The dpaa2_switch_port_set_fdb() function is responsible with determining what FDB should be used by a port as a consequence of changing its upper device. This patch extends the function to also cover the circumstances in which a DPAA2 switch port offloads a bond device. This will allow us, for example, to setup the same FDB on all DPAA2 switch ports which are under the same bridge, even though not directly but rather through an upper bond device which is bridged. How the function does this is by first determining a DPAA2 port is already under the same bridge and if so, choosing its FDB. To cover the entire hierarchy in depth, we add an extra walk through all the lowers of a bridged bond device. When leaving an upper device, the DPAA2 switch port must find a new FDB to use. If before it just searched for an unused FDB to go along with its new standalone status, now it first checks if the port is still part of a LAG and then uses the FDB of any port that already left the same bridge. Signed-off-by: Ioana Ciornei --- Changes in v2: - none --- .../ethernet/freescale/dpaa2/dpaa2-switch.c | 102 +++++++++++++----- 1 file changed, 78 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index 91be5a12a006..8af8b1f769d4 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@ -66,28 +66,59 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, struct net_device *upper_dev, bool linking) { + struct ethsw_core *ethsw = port_priv->ethsw_data; struct ethsw_port_priv *other_port_priv = NULL; - struct dpaa2_switch_fdb *fdb; - struct net_device *other_dev; - struct list_head *iter; + struct net_device *other_dev, *other_dev2; + u16 fdb_id_old = port_priv->fdb->fdb_id; + struct dpaa2_switch_fdb *fdb = NULL; + struct list_head *iter, *iter2; + int i; - /* If we leave a bridge, find an unused FDB and use that. */ + /* If we leave a an upper device, be it a bond or a bridge, find an + * unused FDB and use that. + */ if (!linking) { - fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data); - - /* If there is no unused FDB, we must be the last port that - * leaves the last bridge, all the others are standalone. We - * can just keep the FDB that we already have. + /* This port leaves a bridge, but it's still under a bond. + * Search for the first port under the same bond which already + * left the bridge. */ + if (netif_is_bridge_master(upper_dev) && port_priv->lag) { + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + other_port_priv = ethsw->ports[i]; + if (!other_port_priv) + continue; + + if (other_port_priv == port_priv) + continue; + + /* Found a port which is under the same bond + * device but already left the bridge. Use + * this port's FDB. + */ + if (other_port_priv->lag == port_priv->lag && + other_port_priv->fdb->fdb_id != fdb_id_old) { + fdb = other_port_priv->fdb; + break; + } + } + } - if (!fdb) { - port_priv->fdb->bridge_dev = NULL; - return; + /* Try to get hold of an unused FDB to use */ + if (!fdb) + fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data); + + if (fdb) { + port_priv->fdb = fdb; + port_priv->fdb->in_use = true; } - port_priv->fdb = fdb; - port_priv->fdb->in_use = true; - port_priv->fdb->bridge_dev = NULL; + if (netif_is_bridge_master(upper_dev)) + port_priv->fdb->bridge_dev = NULL; + + /* In case all FDBs are already in use, we must be the last + * port that becomes standalone. We can just keep the FDB that + * we already have. Nothing more to do in this case. + */ return; } @@ -97,18 +128,40 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, */ ASSERT_RTNL(); - /* If part of a bridge, use the FDB of the first dpaa2 switch interface - * to be present in that bridge + /* In case we are joining an upper device, be it a bridge device or a + * bond device, we will use the FDB of the first DPAA2 switch interface + * that is already present under the same upper device. For this to + * happen we have to extend our search so that we can find any DPAA2 + * interface that is a lower of a bond bridged port */ + other_port_priv = NULL; netdev_for_each_lower_dev(upper_dev, other_dev, iter) { - if (!dpaa2_switch_port_dev_check(other_dev)) - continue; + if (netif_is_lag_master(other_dev)) { + /* Search through all the lowers of the bridged lag */ + netdev_for_each_lower_dev(other_dev, other_dev2, iter2) { + if (!dpaa2_switch_port_dev_check(other_dev2)) + continue; + if (other_dev2 == port_priv->netdev) + continue; + + /* Skip the port if it's the same upper */ + other_port_priv = netdev_priv(other_dev2); + if (other_port_priv->lag == port_priv->lag) { + other_port_priv = NULL; + continue; + } + break; + } - if (other_dev == port_priv->netdev) - continue; + if (other_port_priv) + break; + } else if (dpaa2_switch_port_dev_check(other_dev)) { + if (other_dev == port_priv->netdev) + continue; - other_port_priv = netdev_priv(other_dev); - break; + other_port_priv = netdev_priv(other_dev); + break; + } } /* The current port is about to change its FDB to the one used by the @@ -126,7 +179,8 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, } /* Keep track of the new upper bridge device */ - port_priv->fdb->bridge_dev = upper_dev; + if (netif_is_bridge_master(upper_dev)) + port_priv->fdb->bridge_dev = upper_dev; } static void dpaa2_switch_fdb_get_flood_cfg(struct ethsw_core *ethsw, u16 fdb_id, -- 2.25.1