net: dsa: felix: add port fast age support
authorVladimir Oltean <vladimir.oltean@nxp.com>
Fri, 7 Jan 2022 14:42:29 +0000 (16:42 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 8 Jan 2022 02:58:25 +0000 (18:58 -0800)
Add support for flushing the MAC table on a given port in the ocelot
switch library, and use this functionality in the felix DSA driver.

This operation is needed when a port leaves a bridge to become
standalone, and when the learning is disabled, and when the STP state
changes to a state where no FDB entry should be present.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Link: https://lore.kernel.org/r/20220107144229.244584-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/ocelot/felix.c
drivers/net/ethernet/mscc/ocelot.c
include/soc/mscc/ocelot.h

index bb2a43070ea8bb57f0961536e51af535266b530c..9957772201d58d4fdc59f8b487bf9068bb70c811 100644 (file)
@@ -639,6 +639,17 @@ static int felix_set_ageing_time(struct dsa_switch *ds,
        return 0;
 }
 
+static void felix_port_fast_age(struct dsa_switch *ds, int port)
+{
+       struct ocelot *ocelot = ds->priv;
+       int err;
+
+       err = ocelot_mact_flush(ocelot, port);
+       if (err)
+               dev_err(ds->dev, "Flushing MAC table on port %d returned %pe\n",
+                       port, ERR_PTR(err));
+}
+
 static int felix_fdb_dump(struct dsa_switch *ds, int port,
                          dsa_fdb_dump_cb_t *cb, void *data)
 {
@@ -1622,6 +1633,7 @@ const struct dsa_switch_ops felix_switch_ops = {
        .phylink_mac_config             = felix_phylink_mac_config,
        .phylink_mac_link_down          = felix_phylink_mac_link_down,
        .phylink_mac_link_up            = felix_phylink_mac_link_up,
+       .port_fast_age                  = felix_port_fast_age,
        .port_fdb_dump                  = felix_fdb_dump,
        .port_fdb_add                   = felix_fdb_add,
        .port_fdb_del                   = felix_fdb_del,
index 79e7df837740a51fe1d10c206554bb63df8510a6..b1311b656e17f926ff0df3088343b2a465df7913 100644 (file)
@@ -1341,6 +1341,43 @@ static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
        return 0;
 }
 
+int ocelot_mact_flush(struct ocelot *ocelot, int port)
+{
+       int err;
+
+       mutex_lock(&ocelot->mact_lock);
+
+       /* Program ageing filter for a single port */
+       ocelot_write(ocelot, ANA_ANAGEFIL_PID_EN | ANA_ANAGEFIL_PID_VAL(port),
+                    ANA_ANAGEFIL);
+
+       /* Flushing dynamic FDB entries requires two successive age scans */
+       ocelot_write(ocelot,
+                    ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_AGE),
+                    ANA_TABLES_MACACCESS);
+
+       err = ocelot_mact_wait_for_completion(ocelot);
+       if (err) {
+               mutex_unlock(&ocelot->mact_lock);
+               return err;
+       }
+
+       /* And second... */
+       ocelot_write(ocelot,
+                    ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_AGE),
+                    ANA_TABLES_MACACCESS);
+
+       err = ocelot_mact_wait_for_completion(ocelot);
+
+       /* Restore ageing filter */
+       ocelot_write(ocelot, 0, ANA_ANAGEFIL);
+
+       mutex_unlock(&ocelot->mact_lock);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(ocelot_mact_flush);
+
 int ocelot_fdb_dump(struct ocelot *ocelot, int port,
                    dsa_fdb_dump_cb_t *cb, void *data)
 {
index 3e9454b005622c78a43160db1cdcceb94436db8b..5c3a3597f1d2f8a7cfeb8c7a80e14884c8c42005 100644 (file)
@@ -833,6 +833,7 @@ void ocelot_port_bridge_join(struct ocelot *ocelot, int port,
                             struct net_device *bridge);
 void ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
                              struct net_device *bridge);
+int ocelot_mact_flush(struct ocelot *ocelot, int port);
 int ocelot_fdb_dump(struct ocelot *ocelot, int port,
                    dsa_fdb_dump_cb_t *cb, void *data);
 int ocelot_fdb_add(struct ocelot *ocelot, int port,