[PATCH net-next v4 1/4] net: dsa: wire flash_update devlink callback to drivers
From: Daniel Golle <daniel@makrotopia.org>
Date: 2026-07-21 23:58:45
Also in:
lkml
Subsystem:
networking [dsa], networking [general], the rest · Maintainers:
Andrew Lunn, Vladimir Oltean, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Add a devlink_flash_update callback to dsa_switch_ops so that DSA
drivers can support devlink dev flash without open-coding the devlink
plumbing. Unlike the other trampolines in net/dsa/devlink.c, the
flash_update op is only installed for switches whose driver implements
the callback: the devlink core rejects flash requests up front when the
op is absent, before fetching the firmware file from userspace, and an
unconditionally present trampoline would defeat that early check and
let unsupported requests block on request_firmware() only to fail with
-EOPNOTSUPP afterwards.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v4: only install the flash_update op for drivers implementing the
callback so the devlink core keeps rejecting unsupported flash
requests before fetching the firmware file
v3: no changes
v2: align continuation lines with the open parenthesis
include/net/dsa.h | 3 +++
net/dsa/devlink.c | 50 +++++++++++++++++++++++++++++++++++------------
2 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 8c16ef23cc10..c9e19348de61 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h@@ -1170,6 +1170,9 @@ struct dsa_switch_ops { int (*devlink_info_get)(struct dsa_switch *ds, struct devlink_info_req *req, struct netlink_ext_ack *extack); + int (*devlink_flash_update)(struct dsa_switch *ds, + struct devlink_flash_update_params *params, + struct netlink_ext_ack *extack); int (*devlink_sb_pool_get)(struct dsa_switch *ds, unsigned int sb_index, u16 pool_index, struct devlink_sb_pool_info *pool_info);
diff --git a/net/dsa/devlink.c b/net/dsa/devlink.c
index ed342f345692..d6022267a839 100644
--- a/net/dsa/devlink.c
+++ b/net/dsa/devlink.c@@ -20,6 +20,15 @@ static int dsa_devlink_info_get(struct devlink *dl, return -EOPNOTSUPP; } +static int dsa_devlink_flash_update(struct devlink *dl, + struct devlink_flash_update_params *params, + struct netlink_ext_ack *extack) +{ + struct dsa_switch *ds = dsa_devlink_to_ds(dl); + + return ds->ops->devlink_flash_update(ds, params, extack); +} + static int dsa_devlink_sb_pool_get(struct devlink *dl, unsigned int sb_index, u16 pool_index, struct devlink_sb_pool_info *pool_info)
@@ -167,18 +176,31 @@ dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp, p_max); } -static const struct devlink_ops dsa_devlink_ops = { - .info_get = dsa_devlink_info_get, - .sb_pool_get = dsa_devlink_sb_pool_get, - .sb_pool_set = dsa_devlink_sb_pool_set, - .sb_port_pool_get = dsa_devlink_sb_port_pool_get, - .sb_port_pool_set = dsa_devlink_sb_port_pool_set, - .sb_tc_pool_bind_get = dsa_devlink_sb_tc_pool_bind_get, - .sb_tc_pool_bind_set = dsa_devlink_sb_tc_pool_bind_set, - .sb_occ_snapshot = dsa_devlink_sb_occ_snapshot, - .sb_occ_max_clear = dsa_devlink_sb_occ_max_clear, - .sb_occ_port_pool_get = dsa_devlink_sb_occ_port_pool_get, +/* The devlink core rejects flash requests up front when the flash_update + * op is absent, before fetching the firmware file from userspace. Only + * install the op for switches whose driver implements it, so that + * unsupported requests keep failing early. + */ +#define DSA_DEVLINK_OPS \ + .info_get = dsa_devlink_info_get, \ + .sb_pool_get = dsa_devlink_sb_pool_get, \ + .sb_pool_set = dsa_devlink_sb_pool_set, \ + .sb_port_pool_get = dsa_devlink_sb_port_pool_get, \ + .sb_port_pool_set = dsa_devlink_sb_port_pool_set, \ + .sb_tc_pool_bind_get = dsa_devlink_sb_tc_pool_bind_get, \ + .sb_tc_pool_bind_set = dsa_devlink_sb_tc_pool_bind_set, \ + .sb_occ_snapshot = dsa_devlink_sb_occ_snapshot, \ + .sb_occ_max_clear = dsa_devlink_sb_occ_max_clear, \ + .sb_occ_port_pool_get = dsa_devlink_sb_occ_port_pool_get, \ .sb_occ_tc_port_bind_get = dsa_devlink_sb_occ_tc_port_bind_get, + +static const struct devlink_ops dsa_devlink_ops = { + DSA_DEVLINK_OPS +}; + +static const struct devlink_ops dsa_devlink_flash_ops = { + DSA_DEVLINK_OPS + .flash_update = dsa_devlink_flash_update, }; int dsa_devlink_param_get(struct devlink *dl, u32 id,
@@ -378,12 +400,16 @@ void dsa_switch_devlink_unregister(struct dsa_switch *ds) int dsa_switch_devlink_alloc(struct dsa_switch *ds) { struct dsa_devlink_priv *dl_priv; + const struct devlink_ops *ops; struct devlink *dl; + ops = ds->ops->devlink_flash_update ? &dsa_devlink_flash_ops + : &dsa_devlink_ops; + /* Add the switch to devlink before calling setup, so that setup can * add dpipe tables */ - dl = devlink_alloc(&dsa_devlink_ops, sizeof(*dl_priv), ds->dev); + dl = devlink_alloc(ops, sizeof(*dl_priv), ds->dev); if (!dl) return -ENOMEM;
--
2.55.0