[PATCH net-next v9 1/5] net: dsa: add devlink flash_update callback to dsa_switch_ops

From: Daniel Golle

Date: Sun Aug 02 2026 - 23:52:26 EST


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. Like the other trampolines in net/dsa/devlink.c, the op
returns -EOPNOTSUPP when the driver does not implement the callback;
the devlink core will then have fetched the firmware file from
userspace before the request fails, which is acceptable for an
operation as infrequent as a firmware update.

The devlink core calls the op with the devlink instance lock held and
without rtnl_lock, whereas DSA serialises its switch and port ops
under rtnl_lock, so a driver has to serialise a flash against its own
ops itself.

Signed-off-by: Daniel Golle <daniel@xxxxxxxxxxxxxx>
---
v9: install the flash_update op unconditionally and return -EOPNOTSUPP
from the trampoline like the other DSA devlink trampolines,
instead of a second devlink_ops permutation (Andrew Lunn)

v8:
- retitled: this patch adds the callback, its first user is patch 3
- describe the op's calling context in the commit message

v7: no changes

v6: no changes

v5: no changes

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 | 13 +++++++++++++
2 files changed, 16 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6f7f5c17b532..58597b14e592 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1172,6 +1172,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..25311a87cbc5 100644
--- a/net/dsa/devlink.c
+++ b/net/dsa/devlink.c
@@ -20,6 +20,18 @@ 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);
+
+ if (!ds->ops->devlink_flash_update)
+ return -EOPNOTSUPP;
+
+ 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)
@@ -169,6 +181,7 @@ dsa_devlink_sb_occ_tc_port_bind_get(struct devlink_port *dlp,

static const struct devlink_ops dsa_devlink_ops = {
.info_get = dsa_devlink_info_get,
+ .flash_update = dsa_devlink_flash_update,
.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,
--
2.55.0