[PATCH net-next 4/7] net: dsa: netc: use entry ID instead of pointer to track host flood rule

From: wei . fang

Date: Tue Jul 28 2026 - 06:45:34 EST


From: Wei Fang <wei.fang@xxxxxxx>

Replace the struct ipft_entry_data pointer in struct netc_port with a
plain u32 entry ID (ipft_hf_eid), using NTMP_NULL_ENTRY_ID as the
sentinel value. The ipft_entry_data allocation is now freed immediately
inside netc_port_add_host_flood_rule() after the hardware entry is
committed, so no heap memory survives beyond that function. As a result,
netc_free_host_flood_rules() is no longer needed and can be removed.

Signed-off-by: Wei Fang <wei.fang@xxxxxxx>
---
drivers/net/dsa/netc/netc_main.c | 63 ++++++++++++------------------
drivers/net/dsa/netc/netc_switch.h | 2 +-
2 files changed, 25 insertions(+), 40 deletions(-)

diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
index 77077352c1a5..d326a00104e1 100644
--- a/drivers/net/dsa/netc/netc_main.c
+++ b/drivers/net/dsa/netc/netc_main.c
@@ -286,6 +286,12 @@ static int netc_init_all_ports(struct netc_switch *priv)
dev_err(dev, "Failed to create MDIO bus\n");
return err;
}
+
+ /* The ipft_hf_eid is initialized to an invalid entry
+ * ID because the host flood rule (IPFT entry) has not
+ * been created.
+ */
+ np->ipft_hf_eid = NTMP_NULL_ENTRY_ID;
}
}

@@ -938,30 +944,12 @@ static void netc_destroy_all_lists(struct netc_switch *priv)
mutex_destroy(&priv->vft_lock);
}

-static void netc_free_host_flood_rules(struct netc_switch *priv)
-{
- struct dsa_port *dp;
-
- dsa_switch_for_each_user_port(dp, priv->ds) {
- struct netc_port *np = priv->ports[dp->index];
-
- /* No need to clear the hardware IPFT entry. Because PCIe
- * FLR will be performed when the switch is re-registered,
- * it will reset hardware state. So only need to free the
- * memory to avoid memory leak.
- */
- kfree(np->host_flood);
- np->host_flood = NULL;
- }
-}
-
static void netc_teardown(struct dsa_switch *ds)
{
struct netc_switch *priv = ds->priv;

disable_delayed_work_sync(&priv->fdbt_ageing_work);
netc_destroy_all_lists(priv);
- netc_free_host_flood_rules(priv);
netc_free_ntmp_user(priv);
}

@@ -1759,37 +1747,36 @@ static int netc_port_add_host_flood_rule(struct netc_port *np,
cfge->cfg = cpu_to_le32(cfg);

err = ntmp_ipft_add_entry(&priv->ntmp, host_flood);
- if (err) {
- kfree(host_flood);
- return err;
- }
+ if (err)
+ goto free_host_flood;

np->uc = uc;
np->mc = mc;
- np->host_flood = host_flood;
+ np->ipft_hf_eid = host_flood->entry_id;
/* Enable ingress port filter table lookup */
netc_port_wr(np, NETC_PIPFCR, PIPFCR_EN);

- return 0;
+free_host_flood:
+ kfree(host_flood);
+
+ return err;
}

-static void netc_port_remove_host_flood(struct netc_port *np,
- struct ipft_entry_data *host_flood)
+static void netc_port_remove_host_flood(struct netc_port *np, u32 entry_id)
{
struct netc_switch *priv = np->switch_priv;
bool disable_host_flood = false;

- if (!host_flood)
+ if (entry_id == NTMP_NULL_ENTRY_ID)
return;

- if (np->host_flood == host_flood)
+ if (np->ipft_hf_eid == entry_id)
disable_host_flood = true;

- ntmp_ipft_delete_entry(&priv->ntmp, host_flood->entry_id);
- kfree(host_flood);
+ ntmp_ipft_delete_entry(&priv->ntmp, entry_id);

if (disable_host_flood) {
- np->host_flood = NULL;
+ np->ipft_hf_eid = NTMP_NULL_ENTRY_ID;
np->uc = false;
np->mc = false;
netc_port_wr(np, NETC_PIPFCR, 0);
@@ -1800,7 +1787,7 @@ static void netc_port_set_host_flood(struct dsa_switch *ds, int port,
bool uc, bool mc)
{
struct netc_port *np = NETC_PORT(ds, port);
- struct ipft_entry_data *old_host_flood;
+ u32 old_entry_id;

/* Do not add host flood rule to ingress port filter table when
* the port has joined a bridge. Otherwise, the ingress frames
@@ -1808,7 +1795,7 @@ static void netc_port_set_host_flood(struct dsa_switch *ds, int port,
* will be redirected directly to the CPU port.
*/
if (dsa_port_bridge_dev_get(np->dp)) {
- netc_port_remove_host_flood(np, np->host_flood);
+ netc_port_remove_host_flood(np, np->ipft_hf_eid);

return;
}
@@ -1818,20 +1805,18 @@ static void netc_port_set_host_flood(struct dsa_switch *ds, int port,

/* IPFT does not support in-place updates to the KEYE element,
* we need to add a new entry and then delete the old one. So
- * save the old entry first.
+ * save the old entry ID first.
*/
- old_host_flood = np->host_flood;
- np->host_flood = NULL;
+ old_entry_id = np->ipft_hf_eid;

if (netc_port_add_host_flood_rule(np, uc, mc)) {
- np->host_flood = old_host_flood;
dev_err(ds->dev, "Failed to add host flood rule on port %d\n",
port);
return;
}

/* Remove the old host flood entry */
- netc_port_remove_host_flood(np, old_host_flood);
+ netc_port_remove_host_flood(np, old_entry_id);
}

static int netc_single_vlan_aware_bridge(struct dsa_switch *ds,
@@ -2020,7 +2005,7 @@ static int netc_port_bridge_join(struct dsa_switch *ds, int port,
netc_port_set_pvid(np, vlan_unaware_pvid);

out:
- netc_port_remove_host_flood(np, np->host_flood);
+ netc_port_remove_host_flood(np, np->ipft_hf_eid);

if (atomic_inc_return(&priv->br_cnt) == 1)
schedule_delayed_work(&priv->fdbt_ageing_work,
diff --git a/drivers/net/dsa/netc/netc_switch.h b/drivers/net/dsa/netc/netc_switch.h
index 305f2a92e2f9..fd36ec2d0e90 100644
--- a/drivers/net/dsa/netc/netc_switch.h
+++ b/drivers/net/dsa/netc/netc_switch.h
@@ -84,7 +84,7 @@ struct netc_port {
u16 uc:1;
u16 mc:1;
u16 pvid;
- struct ipft_entry_data *host_flood;
+ u32 ipft_hf_eid;
};

struct netc_switch_regs {
--
2.34.1