* [PATCH net-next 0/2] net: dsa: motorcomm: Add devlink info and resources @ 2026-11-06 18:48 David Yang 2026-11-06 18:48 ` [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add David Yang 2026-11-06 18:48 ` [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources David Yang 0 siblings, 2 replies; 5+ messages in thread From: David Yang @ 2026-11-06 18:48 UTC (permalink / raw) To: netdev Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel Add basic devlink support: expose the ASIC id through .devlink_info_get, and register devlink resources for the hardware blocks, reporting ACL, FDB (with unicast/mcast/static occupancy) and meter usage. David Yang (2): net: dsa: motorcomm: Report error when FDB fails to add net: dsa: motorcomm: Add devlink info and resources drivers/net/dsa/motorcomm/Makefile | 1 + drivers/net/dsa/motorcomm/chip.c | 45 +++++- drivers/net/dsa/motorcomm/chip.h | 3 + drivers/net/dsa/motorcomm/devlink.c | 208 ++++++++++++++++++++++++++++ drivers/net/dsa/motorcomm/devlink.h | 16 +++ 5 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 drivers/net/dsa/motorcomm/devlink.c create mode 100644 drivers/net/dsa/motorcomm/devlink.h -- 2.53.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add 2026-11-06 18:48 [PATCH net-next 0/2] net: dsa: motorcomm: Add devlink info and resources David Yang @ 2026-11-06 18:48 ` David Yang 2026-11-07 19:39 ` netdev-bot+sashiko 2026-11-06 18:48 ` [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources David Yang 1 sibling, 1 reply; 5+ messages in thread From: David Yang @ 2026-11-06 18:48 UTC (permalink / raw) To: netdev Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel fdb_add() ignored any errors returned by the hardware (for example, table is full). Return error for that case. Note that this does not affect userspace tools: .port_fdb_add() is asynchronous and DSA core always returns 0 for that. Signed-off-by: David Yang <mmyangfl@gmail.com> --- drivers/net/dsa/motorcomm/chip.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c index 33e5fc127244..a7a9a7439304 100644 --- a/drivers/net/dsa/motorcomm/chip.c +++ b/drivers/net/dsa/motorcomm/chip.c @@ -725,7 +725,13 @@ yt921x_fdb_add(struct yt921x_priv *priv, const unsigned char *addr, u16 vid, if (res) return res; - return yt921x_fdb_wait(priv, &val); + res = yt921x_fdb_wait(priv, &val); + if (res) + return res; + if (val & YT921X_FDB_RESULT_NOTFOUND) + return -ENOSPC; + + return 0; } static int -- 2.53.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add 2026-11-06 18:48 ` [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add David Yang @ 2026-11-07 19:39 ` netdev-bot+sashiko 0 siblings, 0 replies; 5+ messages in thread From: netdev-bot+sashiko @ 2026-11-07 19:39 UTC (permalink / raw) To: mmyangfl Cc: netdev, andrew, olteanv, davem, edumazet, kuba, pabeni, linux-kernel Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 2 · Low: 1 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] The commit message says the change "does not affect userspace tools: .port_fdb_add() is asynchronous and DSA core always returns 0… - [Medium] The patch reads YT921X_FDB_RESULT_NOTFOUND (BIT(14), chip.h:284) after an OP_ADD as "table full" and returns -ENOSPC from… - [Low] The patch fixes a real bug, but it has no Fixes: tag. -- net: dsa: motorcomm: Report error when FDB fails to add This patch makes yt921x_fdb_add() return -ENOSPC when the FDB result register reports YT921X_FDB_RESULT_NOTFOUND after an add operation. Before the patch, the hardware status was ignored. The commit message says userspace is not affected because .port_fdb_add() is asynchronous. > Note that this does not affect userspace tools: .port_fdb_add() is > asynchronous and DSA core always returns 0 for that. [Severity: Medium] Is this accurate? yt921x_fdb_add() is also reached from the MDB path, and DSA returns .port_mdb_add() errors synchronously: yt921x_dsa_port_mdb_add() yt921x_fdb_join() yt921x_fdb_add() return -ENOSPC; When a port joins a bridge, host-joined MDB groups are replayed as SWITCHDEV_OBJ_ID_HOST_MDB. nbp_switchdev_sync_objs() then returns the error unchanged: net/bridge/br_switchdev.c:nbp_switchdev_sync_objs() { ... err = br_switchdev_mdb_replay(br_dev, dev, ctx, true, blocking_nb, extack); if (err) { /* -EOPNOTSUPP not propagated from MDB replay. */ return err; } ... } If the hardware table is full, will "ip link set lanX master br0" now fail with -ENOSPC? Before this patch it succeeded. For deferred MDB adds, br_switchdev_mdb_complete() now calls br_multicast_set_pg_offload_flags(p, !err) with an error. Userspace then gets an RTM_NEWMDB notification and sees offload_failed in "bridge mdb show". On the FDB path, dsa_user_switchdev_event_work() now logs the error and skips dsa_fdb_offload_notify(): net/dsa/user.c:dsa_user_switchdev_event_work() { ... if (err) { dev_err(ds->dev, "port %d failed to add %pM vid %d to fdb: %d\n", dp->index, addr, vid, err); break; } dsa_fdb_offload_notify(switchdev_work); ... } As a result, "bridge fdb show" no longer marks these entries as offloaded. The driver sets ds->assisted_learning_on_cpu_port = true, so every learned station MAC takes this path. A full table would then log one dev_err() per address, with no rate limit. The new behavior looks more correct. Could the commit message describe these changes that userspace can see, especially that bridge join can now fail? > Signed-off-by: David Yang <mmyangfl@gmail.com> [Severity: Low] Should this have a Fixes: tag? Before this patch, a static FDB or MDB add that the hardware rejected still returned 0. DSA then called dsa_fdb_offload_notify(), and the bridge set MDB offload flags for entries the switch never installed. Traffic to those addresses could be flooded or forwarded wrongly. The ignored result goes back to the original driver submission: Fixes: 186623f4aa72 ("net: dsa: yt921x: Add support for Motorcomm YT921x") Could this also go to net instead of being bundled with net-next feature work? > diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c > index 33e5fc127244d..a7a9a74393045 100644 > --- a/drivers/net/dsa/motorcomm/chip.c > +++ b/drivers/net/dsa/motorcomm/chip.c > @@ -725,7 +725,13 @@ yt921x_fdb_add(struct yt921x_priv *priv, const unsigned char *addr, u16 vid, > if (res) > return res; > > - return yt921x_fdb_wait(priv, &val); > + res = yt921x_fdb_wait(priv, &val); > + if (res) > + return res; > + if (val & YT921X_FDB_RESULT_NOTFOUND) > + return -ENOSPC; [Severity: Medium] Does the hardware set YT921X_FDB_RESULT_NOTFOUND when an OP_ADD finds no free slot? Everywhere else in the driver this bit means a lookup miss. For example, yt921x_fdb_has() checks it after OP_GET_ONE: if (val & YT921X_FDB_RESULT_NOTFOUND) { *indexp = YT921X_FDB_NUM; return 0; } The neighbouring bit is defined in chip.h but never checked: #define YT921X_FDB_RESULT_OVERWRITED BIT(13) If the hardware reports a full table some other way, this check would miss the case the commit message describes. Static FDB and MDB entries could then still be lost silently while being marked as offloaded. If OVERWRITED means the ADD evicted another entry from a full bucket, would that other entry also be lost silently? Could the datasheet meaning of these bits for OP_ADD be confirmed? Separately, yt921x_fdb_add_index_in12() still ignores every result bit. It is used by the join and leave update paths. Should it check them too? > + > + return 0; > } > > static int -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261106184811.350700-1-mmyangfl%40gmail.com ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources 2026-11-06 18:48 [PATCH net-next 0/2] net: dsa: motorcomm: Add devlink info and resources David Yang 2026-11-06 18:48 ` [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add David Yang @ 2026-11-06 18:48 ` David Yang 2026-11-07 19:39 ` netdev-bot+sashiko 1 sibling, 1 reply; 5+ messages in thread From: David Yang @ 2026-11-06 18:48 UTC (permalink / raw) To: netdev Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel Expose the ASIC model via devlink info (ASIC_ID), and register devlink resources for ACLs, FDB and meters. Resource occupancy is read back from the hardware counters for learned FDB entries; static FDB entries are counted in software. Signed-off-by: David Yang <mmyangfl@gmail.com> --- drivers/net/dsa/motorcomm/Makefile | 1 + drivers/net/dsa/motorcomm/chip.c | 37 ++++- drivers/net/dsa/motorcomm/chip.h | 3 + drivers/net/dsa/motorcomm/devlink.c | 208 ++++++++++++++++++++++++++++ drivers/net/dsa/motorcomm/devlink.h | 16 +++ 5 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 drivers/net/dsa/motorcomm/devlink.c create mode 100644 drivers/net/dsa/motorcomm/devlink.h diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile index 9eaa59f699e8..0b31d815ce43 100644 --- a/drivers/net/dsa/motorcomm/Makefile +++ b/drivers/net/dsa/motorcomm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o yt921x-objs := chip.o yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o +yt921x-objs += devlink.o yt921x-objs += mdio_bus.o yt921x-objs += mib.o yt921x-objs += pcs-921x.o diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c index a7a9a7439304..c3c555cb8941 100644 --- a/drivers/net/dsa/motorcomm/chip.c +++ b/drivers/net/dsa/motorcomm/chip.c @@ -26,6 +26,7 @@ #include <net/ieee8021q.h> #include "chip.h" +#include "devlink.h" #include "leds.h" #include "mdio_bus.h" #include "mib.h" @@ -731,6 +732,7 @@ yt921x_fdb_add(struct yt921x_priv *priv, const unsigned char *addr, u16 vid, if (val & YT921X_FDB_RESULT_NOTFOUND) return -ENOSPC; + priv->fdb_static_cnt++; return 0; } @@ -761,18 +763,27 @@ yt921x_fdb_leave(struct yt921x_priv *priv, const unsigned char *addr, ctrl2 = val2 & ~YT921X_FDB_IO2_EGR_PORTS(ports_mask); if (ctrl2 == val2) return 0; + + res = yt921x_reg_read(priv, YT921X_FDB_OUT1, &ctrl1); + if (res) + return res; + if (!(ctrl2 & YT921X_FDB_IO2_EGR_PORTS_M)) { ctrl = YT921X_FDB_OP_OP_DEL | YT921X_FDB_OP_START; res = yt921x_reg_write(priv, YT921X_FDB_OP, ctrl); if (res) return res; - return yt921x_fdb_wait(priv, &val); - } + res = yt921x_fdb_wait(priv, &val); + if (res) + return res; - res = yt921x_reg_read(priv, YT921X_FDB_OUT1, &ctrl1); - if (res) - return res; + if ((ctrl1 & YT921X_FDB_IO1_STATUS_M) == + YT921X_FDB_IO1_STATUS_STATIC && + !WARN_ON(!priv->fdb_static_cnt)) + priv->fdb_static_cnt--; + return 0; + } return yt921x_fdb_add_index_in12(priv, index, ctrl1, ctrl2); } @@ -809,7 +820,14 @@ yt921x_fdb_join(struct yt921x_priv *priv, const unsigned char *addr, u16 vid, if (ctrl1 == val1 && ctrl2 == val2) return 0; - return yt921x_fdb_add_index_in12(priv, index, ctrl1, ctrl2); + res = yt921x_fdb_add_index_in12(priv, index, ctrl1, ctrl2); + if (res) + return res; + + if ((val1 & YT921X_FDB_IO1_STATUS_M) != + YT921X_FDB_IO1_STATUS_STATIC) + priv->fdb_static_cnt++; + return 0; } static int @@ -2154,6 +2172,8 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds) yt921x_leds_remove(priv); #endif + + dsa_devlink_resources_unregister(ds); } static int yt921x_chip_detect(struct yt921x_priv *priv) @@ -2488,6 +2508,10 @@ static int yt921x_dsa_setup(struct dsa_switch *ds) if (res) return res; + res = yt921x_devlink_setup(priv); + if (res) + return res; + #if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS) res = yt921x_leds_setup(priv); if (res) @@ -2576,6 +2600,7 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = { .port_add_dscp_prio = yt921x_dsa_port_add_dscp_prio, #endif /* chip */ + .devlink_info_get = yt921x_dsa_devlink_info_get, .teardown = yt921x_dsa_teardown, .setup = yt921x_dsa_setup, }; diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h index fc315f1d8f87..5408ec268ba0 100644 --- a/drivers/net/dsa/motorcomm/chip.h +++ b/drivers/net/dsa/motorcomm/chip.h @@ -248,6 +248,7 @@ enum yt921x_app_selector { #define YT921X_PORT_LEARN_MODE_AUTO YT921X_PORT_LEARN_MODE(0) #define YT921X_PORT_LEARN_MODE_AUTO_AND_COPY YT921X_PORT_LEARN_MODE(1) #define YT921X_PORT_LEARN_MODE_CPU_CONTROL YT921X_PORT_LEARN_MODE(2) +#define YT921X_LEARN_UCAST_CNT 0x18043c #define YT921X_AGEING 0x180440 #define YT921X_AGEING_INTERVAL_M GENMASK(15, 0) #define YT921X_FDB_IN0 0x180454 @@ -312,6 +313,7 @@ enum yt921x_app_selector { #define YT921X_FDB_IO2_PRIO(x) FIELD_PREP(YT921X_FDB_IO2_PRIO_M, (x)) #define YT921X_FDB_IO2_NEW_VID_M GENMASK(11, 0) #define YT921X_FDB_IO2_NEW_VID(x) FIELD_PREP(YT921X_FDB_IO2_NEW_VID_M, (x)) +#define YT921X_LEARN_MCAST_CNT 0x180504 #define YT921X_FILTER_UNK_UCAST 0x180508 #define YT921X_FILTER_UNK_MCAST 0x18050c #define YT921X_FILTER_MCAST 0x180510 @@ -525,6 +527,7 @@ struct yt921x_priv { struct yt921x_port ports[YT921X_PORT_NUM]; u16 eee_ports_mask; + unsigned short fdb_static_cnt; DECLARE_BITMAP(meters_map, YT921X_METER_NUM); diff --git a/drivers/net/dsa/motorcomm/devlink.c b/drivers/net/dsa/motorcomm/devlink.c new file mode 100644 index 000000000000..cddc77a6fd11 --- /dev/null +++ b/drivers/net/dsa/motorcomm/devlink.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2026 David Yang + */ + +#include "chip.h" +#include "devlink.h" +#include "smi.h" +#include "tc.h" + +#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds) + +int +yt921x_dsa_devlink_info_get(struct dsa_switch *ds, struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct yt921x_priv *priv = to_yt921x_priv(ds); + int res; + + if (!priv->info) + return -ENODEV; + + res = devlink_info_version_fixed_put(req, + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, + priv->info->name); + if (res) + return res; + + return 0; +} + +static u64 yt921x_devlink_occ_get_acl(void *ctx) +{ + struct yt921x_priv *priv = ctx; + u64 count = 0; + + mutex_lock(&priv->reg_lock); + for (unsigned int i = 0; i < YT921X_ACL_BLK_NUM; i++) + count += hweight8(priv->acl_masks[i]); + mutex_unlock(&priv->reg_lock); + + return count; +} + +static u64 yt921x_devlink_occ_get_fdb_ucast(void *ctx) +{ + struct yt921x_priv *priv = ctx; + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_read(priv, YT921X_LEARN_UCAST_CNT, &val); + mutex_unlock(&priv->reg_lock); + + if (res) + return 0; + return val; +} + +static u64 yt921x_devlink_occ_get_fdb_mcast(void *ctx) +{ + struct yt921x_priv *priv = ctx; + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + res = yt921x_reg_read(priv, YT921X_LEARN_MCAST_CNT, &val); + mutex_unlock(&priv->reg_lock); + + if (res) + return 0; + return val; +} + +static u64 yt921x_devlink_occ_get_fdb_static(void *ctx) +{ + struct yt921x_priv *priv = ctx; + + return READ_ONCE(priv->fdb_static_cnt); +} + +static u64 yt921x_devlink_occ_get_fdb(void *ctx) +{ + struct yt921x_priv *priv = ctx; + u64 count = 0; + u32 val; + int res; + + mutex_lock(&priv->reg_lock); + + res = yt921x_reg_read(priv, YT921X_LEARN_UCAST_CNT, &val); + if (res) + goto end; + count += val; + + res = yt921x_reg_read(priv, YT921X_LEARN_MCAST_CNT, &val); + if (res) + goto end; + count += val; + + count += priv->fdb_static_cnt; + +end: + mutex_unlock(&priv->reg_lock); + + if (res) + return 0; + return count; +} + +static u64 yt921x_devlink_occ_get_meter(void *ctx) +{ + struct yt921x_priv *priv = ctx; + u64 count; + + mutex_lock(&priv->reg_lock); + count = bitmap_weight(priv->meters_map, YT921X_METER_NUM); + mutex_unlock(&priv->reg_lock); + + return count; +} + +enum yt921x_devlink_resource_id { + YT921X_DEVLINK_RESOURCE_ID_NONE, /* DEVLINK_RESOURCE_ID_PARENT_TOP */ + YT921X_DEVLINK_RESOURCE_ID_ACL, + YT921X_DEVLINK_RESOURCE_ID_FDB, + YT921X_DEVLINK_RESOURCE_ID_FDB_UCAST, + YT921X_DEVLINK_RESOURCE_ID_FDB_MCAST, + YT921X_DEVLINK_RESOURCE_ID_FDB_STATIC, + YT921X_DEVLINK_RESOURCE_ID_METER, +}; + +struct yt921x_devlink_resource { + const char *name; + devlink_resource_occ_get_t *occ_get; + unsigned short size; + unsigned char id; + unsigned char parent_id; +}; + +static const struct yt921x_devlink_resource yt921x_devlink_resources[] = { + { + "ACLs", yt921x_devlink_occ_get_acl, + YT921X_ACL_NUM, + YT921X_DEVLINK_RESOURCE_ID_ACL, + DEVLINK_RESOURCE_ID_PARENT_TOP, + }, + { + "FDBs", yt921x_devlink_occ_get_fdb, + YT921X_FDB_NUM, + YT921X_DEVLINK_RESOURCE_ID_FDB, + DEVLINK_RESOURCE_ID_PARENT_TOP, + }, + { + "ucast", yt921x_devlink_occ_get_fdb_ucast, + YT921X_FDB_NUM, + YT921X_DEVLINK_RESOURCE_ID_FDB_UCAST, + YT921X_DEVLINK_RESOURCE_ID_FDB, + }, + { + "mcast", yt921x_devlink_occ_get_fdb_mcast, + YT921X_FDB_NUM, + YT921X_DEVLINK_RESOURCE_ID_FDB_MCAST, + YT921X_DEVLINK_RESOURCE_ID_FDB, + }, + { + "static", yt921x_devlink_occ_get_fdb_static, + YT921X_FDB_NUM, + YT921X_DEVLINK_RESOURCE_ID_FDB_STATIC, + YT921X_DEVLINK_RESOURCE_ID_FDB, + }, + { + "meters", yt921x_devlink_occ_get_meter, + YT921X_METER_NUM, + YT921X_DEVLINK_RESOURCE_ID_METER, + DEVLINK_RESOURCE_ID_PARENT_TOP, + }, +}; + +int yt921x_devlink_setup(struct yt921x_priv *priv) +{ + struct dsa_switch *ds = &priv->ds; + int res; + + for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_devlink_resources); + i++) { + struct devlink_resource_size_params size_params; + const struct yt921x_devlink_resource *r; + + r = &yt921x_devlink_resources[i]; + + devlink_resource_size_params_init(&size_params, r->size, + r->size, 1, + DEVLINK_RESOURCE_UNIT_ENTRY); + + res = dsa_devlink_resource_register(ds, r->name, r->size, r->id, + r->parent_id, &size_params); + if (res) { + dsa_devlink_resources_unregister(ds); + return res; + } + + dsa_devlink_resource_occ_get_register(ds, r->id, r->occ_get, + priv); + } + + return 0; +} diff --git a/drivers/net/dsa/motorcomm/devlink.h b/drivers/net/dsa/motorcomm/devlink.h new file mode 100644 index 000000000000..e13fbe320bca --- /dev/null +++ b/drivers/net/dsa/motorcomm/devlink.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2026 David Yang + */ + +#ifndef _YT_DEVLINK_H +#define _YT_DEVLINK_H + +#include <net/dsa.h> + +int +yt921x_dsa_devlink_info_get(struct dsa_switch *ds, struct devlink_info_req *req, + struct netlink_ext_ack *extack); +int yt921x_devlink_setup(struct yt921x_priv *priv); + +#endif -- 2.53.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources 2026-11-06 18:48 ` [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources David Yang @ 2026-11-07 19:39 ` netdev-bot+sashiko 0 siblings, 0 replies; 5+ messages in thread From: netdev-bot+sashiko @ 2026-11-07 19:39 UTC (permalink / raw) To: mmyangfl Cc: netdev, andrew, olteanv, davem, edumazet, kuba, pabeni, linux-kernel Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 4 · Low: 4 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] The devlink FDB resource tree breaks devlink's rule for parent and child sizes. - [Medium] yt921x_devlink_occ_get_fdb() computes FDB occupancy as LEARN_UCAST_CNT + LEARN_MCAST_CNT + priv->fdb_static_cnt. - [Medium] priv->fdb_static_cnt is changed only after the whole FDB sequence reports success, so it can drift from the hardware when the… - [Medium] yt921x_dsa_setup() calls yt921x_chip_reset(), which writes YT921X_RST_HW (chip.c:2258), described in a comment as 'almost same as… - [Low] The uAPI resource names "ucast" and "mcast" under /FDBs do not describe what they report. - [Low] devlink.h declares `int yt921x_devlink_setup(struct yt921x_priv *priv);` but includes only <net/dsa.h>. - [Low] devlink.c defines its own macro `#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds)` at line 11. - [Low] priv->fdb_static_cnt is accessed in two inconsistent ways. -- net: dsa: motorcomm: Add devlink info and resources This commit reports the ASIC model through devlink info. It also registers devlink resources for ACLs, FDB entries (with ucast, mcast and static children) and meters. FDB occupancy adds the hardware learn counters to a software count of static entries, which is updated in the FDB add, join and leave paths. > diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c > index a7a9a74393045..c3c555cb8941c 100644 > --- a/drivers/net/dsa/motorcomm/chip.c > +++ b/drivers/net/dsa/motorcomm/chip.c [ ... ] > @@ -731,6 +732,7 @@ yt921x_fdb_add(struct yt921x_priv *priv, const unsigned char *addr, u16 vid, > if (val & YT921X_FDB_RESULT_NOTFOUND) > return -ENOSPC; > > + priv->fdb_static_cnt++; > return 0; > } > > @@ -761,18 +763,27 @@ yt921x_fdb_leave(struct yt921x_priv *priv, const unsigned char *addr, > ctrl2 = val2 & ~YT921X_FDB_IO2_EGR_PORTS(ports_mask); > if (ctrl2 == val2) > return 0; > + > + res = yt921x_reg_read(priv, YT921X_FDB_OUT1, &ctrl1); > + if (res) > + return res; > + > if (!(ctrl2 & YT921X_FDB_IO2_EGR_PORTS_M)) { > ctrl = YT921X_FDB_OP_OP_DEL | YT921X_FDB_OP_START; > res = yt921x_reg_write(priv, YT921X_FDB_OP, ctrl); > if (res) > return res; > > - return yt921x_fdb_wait(priv, &val); > - } > + res = yt921x_fdb_wait(priv, &val); > + if (res) > + return res; > > - res = yt921x_reg_read(priv, YT921X_FDB_OUT1, &ctrl1); > - if (res) > - return res; > + if ((ctrl1 & YT921X_FDB_IO1_STATUS_M) == > + YT921X_FDB_IO1_STATUS_STATIC && > + !WARN_ON(!priv->fdb_static_cnt)) > + priv->fdb_static_cnt--; > + return 0; > + } [Severity: Medium] Can fdb_static_cnt drift from the hardware table when an FDB command takes effect but a later step reports an error? In yt921x_fdb_add(), OP_ADD|START is written to YT921X_FDB_OP before yt921x_fdb_wait() runs. Two failures can happen after that write: - the wait times out ("FDB probably stuck") - the MDIO write was applied but still returned an error In either case the function returns before fdb_static_cnt++, but the entry may already be static in hardware. yt921x_fdb_join() has the same problem through yt921x_fdb_add_index_in12(). If the same {addr, vid, port} is added again later, yt921x_fdb_join() sees STATUS_STATIC with identical ctrl1/ctrl2 and returns 0 without counting it. When the entry is finally removed, yt921x_fdb_leave() reaches this check: if ((ctrl1 & YT921X_FDB_IO1_STATUS_M) == YT921X_FDB_IO1_STATUS_STATIC && !WARN_ON(!priv->fdb_static_cnt)) If there are no other static entries, the WARN_ON fires. The opposite can happen here as well. If yt921x_fdb_wait() fails after the DEL has completed, the decrement is skipped. The count then stays too high for as long as the device exists, because nothing re-syncs the counter with the hardware table. > > return yt921x_fdb_add_index_in12(priv, index, ctrl1, ctrl2); > } [ ... ] > @@ -2154,6 +2172,8 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds) > > yt921x_leds_remove(priv); > #endif > + > + dsa_devlink_resources_unregister(ds); > } [Severity: Medium] Should fdb_static_cnt be reset somewhere in the setup or teardown path? yt921x_dsa_setup() calls yt921x_chip_reset(), which does: /* Reset */ res = yt921x_reg_write(priv, YT921X_RST, YT921X_RST_HW); ... /* RST_HW is almost same as GPIO hard reset, so we need this delay. */ That reset clears the hardware FDB, static entries included. However, fdb_static_cnt is only zeroed once, when priv is allocated with devm_kzalloc() at probe time. Setup can run again on the same priv if the DSA tree is torn down and set up again while this switch stays probed. Examples are another member of a multi-switch tree unbinding and rebinding, or a failed tree setup being retried. If the counter was non-zero at teardown, the re-registered "static" and "FDBs" resources would then count entries that no longer exist. Entries can still be present at teardown in two cases: - entries installed through ndo_dflt_fdb_add() that upper layers never remove; dsa_switch_release_ports() cleans these up, but it only runs at switch removal - entries left behind by the error-path drift described above When those addresses are deleted later, yt921x_fdb_leave() finds no hardware entry and returns early: if (index >= YT921X_FDB_NUM) return 0; So the inflated count is never corrected. [ ... ] > diff --git a/drivers/net/dsa/motorcomm/devlink.c b/drivers/net/dsa/motorcomm/devlink.c > new file mode 100644 > index 0000000000000..cddc77a6fd111 > --- /dev/null > +++ b/drivers/net/dsa/motorcomm/devlink.c > @@ -0,0 +1,208 @@ [ ... ] > +#include "chip.h" > +#include "devlink.h" > +#include "smi.h" > +#include "tc.h" > + > +#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds) [Severity: Low] This isn't a bug, but this macro duplicates dsa_to_yt921x_priv() in chip.h, which is already included here: #define dsa_to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds) Could yt921x_dsa_devlink_info_get() use the existing helper instead? [ ... ] > +static u64 yt921x_devlink_occ_get_fdb_static(void *ctx) > +{ > + struct yt921x_priv *priv = ctx; > + > + return READ_ONCE(priv->fdb_static_cnt); > +} [Severity: Low] Is this read meant to be lockless? It is the only occ_get callback in this file that does not take priv->reg_lock. The writers in yt921x_fdb_add(), yt921x_fdb_leave() and yt921x_fdb_join() use plain ++/-- under reg_lock, without WRITE_ONCE(). Also, yt921x_devlink_occ_get_fdb() reads the same field plainly under reg_lock. This callback runs under devl_lock only, which does not exclude the FDB writers, so the READ_ONCE() here is paired with unmarked writes. Would it be simpler to take reg_lock like the other callbacks do, or else to use WRITE_ONCE() in every writer? > + > +static u64 yt921x_devlink_occ_get_fdb(void *ctx) > +{ > + struct yt921x_priv *priv = ctx; > + u64 count = 0; > + u32 val; > + int res; > + > + mutex_lock(&priv->reg_lock); > + > + res = yt921x_reg_read(priv, YT921X_LEARN_UCAST_CNT, &val); > + if (res) > + goto end; > + count += val; > + > + res = yt921x_reg_read(priv, YT921X_LEARN_MCAST_CNT, &val); > + if (res) > + goto end; > + count += val; > + > + count += priv->fdb_static_cnt; [Severity: Medium] Can this sum count the same FDB entry twice? The total is LEARN_UCAST_CNT + LEARN_MCAST_CNT + fdb_static_cnt. That is only correct if neither hardware counter includes static entries that the CPU installed or converted. For multicast: SA learning cannot create multicast entries, and the driver does not configure hardware IGMP/MLD snooping. So every multicast entry comes from this path: yt921x_dsa_port_mdb_add()->yt921x_fdb_join()->yt921x_fdb_add() That path writes STATUS_STATIC and does fdb_static_cnt++. If YT921X_LEARN_MCAST_CNT counts these entries, every MDB entry is counted twice in "FDBs". If it does not, the "mcast" resource always reads 0. For unicast: yt921x_fdb_join() rewrites an existing hardware-learned entry as static through an index-mode ADD, and then does: if ((val1 & YT921X_FDB_IO1_STATUS_M) != YT921X_FDB_IO1_STATUS_STATIC) priv->fdb_static_cnt++; Does YT921X_LEARN_UCAST_CNT drop by one when the CPU rewrites the entry, or only on age-out or flush? If only on age-out or flush, then a "bridge fdb add ... static" for a MAC that was already learned is counted under both ucast and static. The commit message describes these as hardware counters for "learned FDB entries". Nothing in the code shows how they treat entries the CPU wrote. The answer depends on hardware behaviour that can't be confirmed from the code. > + > +end: > + mutex_unlock(&priv->reg_lock); [ ... ] > +static const struct yt921x_devlink_resource yt921x_devlink_resources[] = { [ ... ] > + { > + "FDBs", yt921x_devlink_occ_get_fdb, > + YT921X_FDB_NUM, > + YT921X_DEVLINK_RESOURCE_ID_FDB, > + DEVLINK_RESOURCE_ID_PARENT_TOP, > + }, > + { > + "ucast", yt921x_devlink_occ_get_fdb_ucast, > + YT921X_FDB_NUM, > + YT921X_DEVLINK_RESOURCE_ID_FDB_UCAST, > + YT921X_DEVLINK_RESOURCE_ID_FDB, > + }, [Severity: Low] Do the names "ucast" and "mcast" match what these resources report? yt921x_devlink_occ_get_fdb_ucast() and yt921x_devlink_occ_get_fdb_mcast() return only the hardware learn counters (YT921X_LEARN_UCAST_CNT and YT921X_LEARN_MCAST_CNT). Static entries from yt921x_dsa_port_fdb_add() and yt921x_dsa_port_mdb_add() only increment fdb_static_cnt. So a "bridge fdb add ... static" or an MDB entry never shows up under "ucast" or "mcast". These names become uAPI once they are released. Would names like "learned-ucast" and "learned-mcast" be clearer? > + { > + "mcast", yt921x_devlink_occ_get_fdb_mcast, > + YT921X_FDB_NUM, > + YT921X_DEVLINK_RESOURCE_ID_FDB_MCAST, > + YT921X_DEVLINK_RESOURCE_ID_FDB, > + }, > + { > + "static", yt921x_devlink_occ_get_fdb_static, > + YT921X_FDB_NUM, > + YT921X_DEVLINK_RESOURCE_ID_FDB_STATIC, > + YT921X_DEVLINK_RESOURCE_ID_FDB, > + }, [Severity: Medium] Does this hierarchy follow devlink's rule for parent and child sizes? "FDBs" is registered with YT921X_FDB_NUM entries. Each of its three children, "ucast", "mcast" and "static", is also registered with YT921X_FDB_NUM. devlink treats children as parts of the parent: net/devlink/resource.c:devlink_resource_validate_children() { ... list_for_each_entry(child_resource, &resource->resource_list, list) parts_size += child_resource->size_new; if (parts_size > resource->size_new) size_valid = false; ... } Registration does not catch this, because devl_resource_register() sets size_valid = true. However, devlink_nl_resource_set_doit() re-validates the parent: resource->size_new = size; devlink_resource_validate_children(resource); if (resource->parent) devlink_resource_validate_children(resource->parent); Since size_min == size_max, the only value a set can use is 4096. Even that no-op, "devlink resource set ... path /FDBs/ucast size 4096", leaves "FDBs" permanently reported with size_valid false, because 3 * 4096 > 4096. The children also overlap. ucast and mcast split entries by address type, while static splits them by entry type, so a static unicast entry belongs to two siblings. Would it work better to register these counters as top-level resources? mv88e6xxx does this: its ATU_bin_* resources are registered with DEVLINK_RESOURCE_ID_PARENT_TOP, as siblings of "ATU". Another option is to give the children non-overlapping sizes that add up to the parent. [ ... ] > diff --git a/drivers/net/dsa/motorcomm/devlink.h b/drivers/net/dsa/motorcomm/devlink.h > new file mode 100644 > index 0000000000000..e13fbe320bcaa > --- /dev/null > +++ b/drivers/net/dsa/motorcomm/devlink.h > @@ -0,0 +1,16 @@ [ ... ] > +#include <net/dsa.h> > + > +int > +yt921x_dsa_devlink_info_get(struct dsa_switch *ds, struct devlink_info_req *req, > + struct netlink_ext_ack *extack); > +int yt921x_devlink_setup(struct yt921x_priv *priv); [Severity: Low] This isn't a bug, but devlink.h uses struct yt921x_priv without including chip.h or forward-declaring the struct. leds.h, mdio_bus.h and smi.h all have: struct yt921x_priv; devlink.h only compiles because chip.c and devlink.c include chip.h first. Could a forward declaration be added so the header is self-contained? > + > +#endif -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261106184811.350700-1-mmyangfl%40gmail.com ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-07 19:39 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-11-06 18:48 [PATCH net-next 0/2] net: dsa: motorcomm: Add devlink info and resources David Yang 2026-11-06 18:48 ` [PATCH net-next 1/2] net: dsa: motorcomm: Report error when FDB fails to add David Yang 2026-11-07 19:39 ` netdev-bot+sashiko 2026-11-06 18:48 ` [PATCH net-next 2/2] net: dsa: motorcomm: Add devlink info and resources David Yang 2026-11-07 19:39 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®