diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
index c946a2b2674e..be37e29cd650 100644
--- a/drivers/net/dsa/netc/netc_main.c
+++ b/drivers/net/dsa/netc/netc_main.c
@@ -1820,14 +1820,8 @@ static int netc_port_add_host_flood_rule(struct netc_port *np,
u32 cfg;
int err;
- if (!uc && !mc) {
- /* Disable ingress port filter table lookup */
- netc_port_wr(np, NETC_PIPFCR, 0);
- np->uc = false;
- np->mc = false;
-
+ if (!uc && !mc)
return 0;
- }
host_flood = kzalloc_obj(*host_flood);
if (!host_flood)@@ -1875,32 +1869,37 @@ static int netc_port_add_host_flood_rule(struct netc_port *np,
return err;
}
-static void netc_port_remove_host_flood(struct netc_port *np, u32 entry_id)
+static int netc_port_remove_host_flood(struct netc_port *np)
{
struct netc_switch *priv = np->switch_priv;
- bool disable_host_flood = false;
+ u32 entry_id = np->ipft_hf_eid;
+ int err;
if (entry_id == NTMP_NULL_ENTRY_ID)
- return;
+ return 0;
- if (np->ipft_hf_eid == entry_id)
- disable_host_flood = true;
+ /* The command BD ring is always enabled here, with the ring
+ * enabled, the hardware completes a command well within 1 ms,
+ * so -ETIMEDOUT cannot happen here. Any error therefore means
+ * that the entry has not been deleted, so keep tracking it.
+ */
+ err = ntmp_ipft_delete_entry(&priv->ntmp, entry_id);
+ if (err)
+ return err;
- ntmp_ipft_delete_entry(&priv->ntmp, entry_id);
+ np->ipft_hf_eid = NTMP_NULL_ENTRY_ID;
+ np->uc = false;
+ np->mc = false;
+ netc_port_wr(np, NETC_PIPFCR, 0);
- if (disable_host_flood) {
- np->ipft_hf_eid = NTMP_NULL_ENTRY_ID;
- np->uc = false;
- np->mc = false;
- netc_port_wr(np, NETC_PIPFCR, 0);
- }
+ return 0;
}
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);
- u32 old_entry_id;
+ int retry_num = 0;
/* Do not add host flood rule to ingress port filter table when
* the port has joined a bridge. Otherwise, the ingress frames@@ -1908,7 +1907,12 @@ 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->ipft_hf_eid);
+ if (!netc_port_remove_host_flood(np))
+ return;
+
+ dev_err(ds->dev,
+ "Failed to delete host flood rule on bridge port %d\n",
+ port);
return;
}@@ -1917,19 +1921,33 @@ static void netc_port_set_host_flood(struct dsa_switch *ds, int port,
return;
/* 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 ID first.
+ * we need to delete the old one and then add the new rule. If
+ * the deletion fails, return immediately.
*/
- old_entry_id = np->ipft_hf_eid;
-
- if (netc_port_add_host_flood_rule(np, uc, mc)) {
- dev_err(ds->dev, "Failed to add host flood rule on port %d\n",
+ if (netc_port_remove_host_flood(np)) {
+ dev_err(ds->dev,
+ "Failed to delete old host flood rule on port %d\n",
port);
+
return;
}
- /* Remove the old host flood entry */
- netc_port_remove_host_flood(np, old_entry_id);
+ /* Restoring the previous configuration is pointless because
+ * .port_set_host_flood() returns void, so the upper layer cannot
+ * detect the error and the RX flags have changed. Furthermore, we
+ * cannot guarantee that we can successfully restore the previous
+ * state.
+ */
+retry:
+ if (netc_port_add_host_flood_rule(np, uc, mc)) {
+ if (retry_num++ < 2) {
+ usleep_range(100, 110);
+ goto retry;
+ }
+
+ dev_err(ds->dev,
+ "Failed to add host flood rule on port %d\n", port);
+ }
}
static int netc_single_vlan_aware_bridge(struct dsa_switch *ds,@@ -2094,6 +2112,8 @@ static int netc_port_bridge_join(struct dsa_switch *ds, int port,
struct netc_port *np = NETC_PORT(ds, port);
struct netc_switch *priv = ds->priv;
u16 vlan_unaware_pvid;
+ bool uc = np->uc;
+ bool mc = np->mc;
int err;
if (!bridge.num) {@@ -2105,6 +2125,12 @@ static int netc_port_bridge_join(struct dsa_switch *ds, int port,
if (err)
return err;
+ err = netc_port_remove_host_flood(np);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to delete host flood rule");
+ return err;
+ }
+
netc_port_set_mlo(np, MLO_NOT_OVERRIDE);
if (br_vlan_enabled(bridge.dev))@@ -2118,8 +2144,6 @@ 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->ipft_hf_eid);
-
if (atomic_inc_return(&priv->br_cnt) == 1)
schedule_delayed_work(&priv->fdbt_ageing_work,
READ_ONCE(priv->fdbt_ageing_delay));
@@ -2129,6 +2153,11 @@ static int netc_port_bridge_join(struct dsa_switch *ds, int port,
disable_mlo:
netc_port_set_mlo(np, MLO_DISABLE);
+ if (netc_port_add_host_flood_rule(np, uc, mc))
+ dev_err(ds->dev,
+ "Failed to restore host flood rule on port %d\n",
+ port);
+
return err;
}
--
2.34.1