diff options
| author | Petr Machata <petrm@mellanox.com> | 2018-11-23 02:28:51 +0300 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2018-11-24 05:02:23 +0300 | 
| commit | c6fa35b2370aeed280fccbc02ff24b94ab48fcf9 (patch) | |
| tree | a1f51d23f63ad23133d3664bbc517e06101f5e7a | |
| parent | aa4efe21393f5c39a72c132d6e0d777d7405b885 (diff) | |
| download | linux-c6fa35b2370aeed280fccbc02ff24b94ab48fcf9.tar.xz | |
rocker: Handle SWITCHDEV_PORT_OBJ_ADD/_DEL
Following patches will change the way of distributing port object
changes from a switchdev operation to a switchdev notifier. The
switchdev code currently recursively descends through layers of lower
devices, eventually calling the op on a front-panel port device. The
notifier will instead be sent referencing the bridge port device, which
may be a stacking device that's one of front-panel ports uppers, or a
completely unrelated device.
rocker currently doesn't support any uppers other than bridge. Thus the
only case that a stacked device could be validly referenced by port
object notifications are bridge notifications for VLAN objects added to
the bridge itself. But the driver explicitly rejects such notifications
in rocker_world_port_obj_vlan_add(). It is therefore safe to assume that
the only interesting case is that the notification is on a front-panel
port netdevice.
Subscribe to the blocking notifier chain. In the handler, filter out
notifications on any foreign netdevices. Dispatch the new notifiers to
rocker_port_obj_add() resp. _del() to maintain the behavior that the
switchdev operation based code currently has.
Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/rocker/rocker_main.c | 55 | 
1 files changed, 55 insertions, 0 deletions
| diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index beb06628f22d..806ffe1d906e 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2812,12 +2812,54 @@ static int rocker_switchdev_event(struct notifier_block *unused,  	return NOTIFY_DONE;  } +static int +rocker_switchdev_port_obj_event(unsigned long event, struct net_device *netdev, +			struct switchdev_notifier_port_obj_info *port_obj_info) +{ +	int err = -EOPNOTSUPP; + +	switch (event) { +	case SWITCHDEV_PORT_OBJ_ADD: +		err = rocker_port_obj_add(netdev, port_obj_info->obj, +					  port_obj_info->trans); +		break; +	case SWITCHDEV_PORT_OBJ_DEL: +		err = rocker_port_obj_del(netdev, port_obj_info->obj); +		break; +	} + +	port_obj_info->handled = true; +	return notifier_from_errno(err); +} + +static int rocker_switchdev_blocking_event(struct notifier_block *unused, +					   unsigned long event, void *ptr) +{ +	struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + +	if (!rocker_port_dev_check(dev)) +		return NOTIFY_DONE; + +	switch (event) { +	case SWITCHDEV_PORT_OBJ_ADD: +	case SWITCHDEV_PORT_OBJ_DEL: +		return rocker_switchdev_port_obj_event(event, dev, ptr); +	} + +	return NOTIFY_DONE; +} +  static struct notifier_block rocker_switchdev_notifier = {  	.notifier_call = rocker_switchdev_event,  }; +static struct notifier_block rocker_switchdev_blocking_notifier = { +	.notifier_call = rocker_switchdev_blocking_event, +}; +  static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)  { +	struct notifier_block *nb;  	struct rocker *rocker;  	int err; @@ -2933,6 +2975,13 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		goto err_register_switchdev_notifier;  	} +	nb = &rocker_switchdev_blocking_notifier; +	err = register_switchdev_blocking_notifier(nb); +	if (err) { +		dev_err(&pdev->dev, "Failed to register switchdev blocking notifier\n"); +		goto err_register_switchdev_blocking_notifier; +	} +  	rocker->hw.id = rocker_read64(rocker, SWITCH_ID);  	dev_info(&pdev->dev, "Rocker switch with id %*phN\n", @@ -2940,6 +2989,8 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	return 0; +err_register_switchdev_blocking_notifier: +	unregister_switchdev_notifier(&rocker_switchdev_notifier);  err_register_switchdev_notifier:  	unregister_fib_notifier(&rocker->fib_nb);  err_register_fib_notifier: @@ -2971,6 +3022,10 @@ err_pci_enable_device:  static void rocker_remove(struct pci_dev *pdev)  {  	struct rocker *rocker = pci_get_drvdata(pdev); +	struct notifier_block *nb; + +	nb = &rocker_switchdev_blocking_notifier; +	unregister_switchdev_blocking_notifier(nb);  	unregister_switchdev_notifier(&rocker_switchdev_notifier);  	unregister_fib_notifier(&rocker->fib_nb); | 
