4.16-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Fainelli f.fainelli@gmail.com
[ Upstream commit 1f3ccc3c3fc26468be00392ef0b2c215f9c9d054 ]
While adding the DSA notifier, we will be sending DSA notifications with info->master that is going to point to a particular net_device instance.
Our logic in bcm_sysport_map_queues() correctly disambiguates net_device instances that are not covered by our own driver, but it will not make sure that info->master points to a particular driver instance that we are interested in. In a system where e.g: two or more SYSTEMPORT instances are registered, this would lead in programming two or more times the queue mapping, completely messing with the logic which does the queue/port allocation and tracking.
Fix this by looking at the notifier_block pointer which is unique per instance and allows us to go back to our driver private structure, and in turn to the backing net_device instance.
Fixes: d156576362c0 ("net: systemport: Establish lower/upper queue mapping") Signed-off-by: Florian Fainelli f.fainelli@gmail.com Reviewed-by: Vivien Didelot vivien.didelot@savoirfairelinux.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/broadcom/bcmsysport.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2052,14 +2052,21 @@ static const struct net_device_ops bcm_s .ndo_select_queue = bcm_sysport_select_queue, };
-static int bcm_sysport_map_queues(struct net_device *dev, +static int bcm_sysport_map_queues(struct notifier_block *nb, struct dsa_notifier_register_info *info) { - struct bcm_sysport_priv *priv = netdev_priv(dev); struct bcm_sysport_tx_ring *ring; + struct bcm_sysport_priv *priv; struct net_device *slave_dev; unsigned int num_tx_queues; unsigned int q, start, port; + struct net_device *dev; + + priv = container_of(nb, struct bcm_sysport_priv, dsa_notifier); + if (priv->netdev != info->master) + return 0; + + dev = info->master;
/* We can't be setting up queue inspection for non directly attached * switches @@ -2082,6 +2089,7 @@ static int bcm_sysport_map_queues(struct if (priv->is_lite) netif_set_real_num_tx_queues(slave_dev, slave_dev->num_tx_queues / 2); + num_tx_queues = slave_dev->real_num_tx_queues;
if (priv->per_port_num_tx_queues && @@ -2109,7 +2117,7 @@ static int bcm_sysport_map_queues(struct return 0; }
-static int bcm_sysport_dsa_notifier(struct notifier_block *unused, +static int bcm_sysport_dsa_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { struct dsa_notifier_register_info *info; @@ -2119,7 +2127,7 @@ static int bcm_sysport_dsa_notifier(stru
info = ptr;
- return notifier_from_errno(bcm_sysport_map_queues(info->master, info)); + return notifier_from_errno(bcm_sysport_map_queues(nb, info)); }
#define REV_FMT "v%2x.%02x"