diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index 52c1cb9cb7e0..782fef26b78e 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@ -54,27 +54,44 @@ dpaa2_switch_filter_block_get_unused(struct ethsw_core *ethsw) static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, struct net_device *bridge_dev) { + 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; + bool last_fdb_user = true; struct list_head *iter; + int i; /* If we leave a bridge (bridge_dev is NULL), find an unused * FDB and use that. */ if (!bridge_dev) { - fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data); + /* First verify if this is the last port to leave this bridge */ + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + if (!ethsw->ports[i] || ethsw->ports[i] == port_priv) + continue; + if (ethsw->ports[i]->fdb == port_priv->fdb) { + last_fdb_user = false; + break; + } + } - /* 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. - */ - - if (!fdb) { + /* If this is the last user of the FDB, just keep using it. */ + if (last_fdb_user) { port_priv->fdb->bridge_dev = NULL; return 0; } + /* Since we are not the last port which leaves a bridge, + * acquire a new FDB and use it. The number of FDBs is sized to + * accommodate all switch ports as standalone, each with its + * private FDB, which means that dpaa2_switch_fdb_get_unused() + * must succeed here. WARN if not. + */ + fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data); + if (WARN_ON(!fdb)) + return 0; + port_priv->fdb = fdb; port_priv->fdb->in_use = true; port_priv->fdb->bridge_dev = NULL;