Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-Remove-switchdev_ops'

Florian Fainelli says:

====================
net: Remove switchdev_ops

This patch series completes the removal of the switchdev_ops by
converting switchdev_port_attr_set() to use either the blocking
(process) or non-blocking (atomic) notifier since we typically need to
deal with both depending on where in the bridge code we get called from.

This was tested with the forwarding selftests and DSA hardware.

Ido, hopefully this captures your comments done on v1, if not, can you
illustrate with some pseudo-code what you had in mind if that's okay?

Changes in v3:

- added Reviewed-by tags from Ido where relevant
- added missing notifier_to_errno() in net/bridge/br_switchdev.c when
calling the atomic notifier for PRE_BRIDGE_FLAGS
- kept mlxsw_sp_switchdev_init() in mlxsw/

Changes in v2:

- do not check for SWITCHDEV_F_DEFER when calling the blocking notifier
and instead directly call the atomic notifier from the single location
where this is required
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+205 -84
-3
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
··· 3660 3660 } 3661 3661 mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan; 3662 3662 3663 - mlxsw_sp_port_switchdev_init(mlxsw_sp_port); 3664 3663 mlxsw_sp->ports[local_port] = mlxsw_sp_port; 3665 3664 err = register_netdev(dev); 3666 3665 if (err) { ··· 3676 3677 3677 3678 err_register_netdev: 3678 3679 mlxsw_sp->ports[local_port] = NULL; 3679 - mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); 3680 3680 mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 3681 3681 err_port_vlan_create: 3682 3682 err_port_pvid_set: ··· 3718 3720 mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp); 3719 3721 unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ 3720 3722 mlxsw_sp->ports[local_port] = NULL; 3721 - mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); 3722 3723 mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true); 3723 3724 mlxsw_sp_port_nve_fini(mlxsw_sp_port); 3724 3725 mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
-2
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
··· 407 407 /* spectrum_switchdev.c */ 408 408 int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); 409 409 void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); 410 - void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); 411 - void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); 412 410 int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, 413 411 bool adding); 414 412 void
+12 -12
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
··· 1938 1938 return NULL; 1939 1939 } 1940 1940 1941 - static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = { 1942 - .switchdev_port_attr_set = mlxsw_sp_port_attr_set, 1943 - }; 1944 - 1945 1941 static int 1946 1942 mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device, 1947 1943 struct mlxsw_sp_bridge_port *bridge_port, ··· 3119 3123 struct net_device *br_dev; 3120 3124 int err; 3121 3125 3126 + if (event == SWITCHDEV_PORT_ATTR_SET) { 3127 + err = switchdev_handle_port_attr_set(dev, ptr, 3128 + mlxsw_sp_port_dev_check, 3129 + mlxsw_sp_port_attr_set); 3130 + return notifier_from_errno(err); 3131 + } 3132 + 3122 3133 /* Tunnel devices are not our uppers, so check their master instead */ 3123 3134 br_dev = netdev_master_upper_dev_get_rcu(dev); 3124 3135 if (!br_dev) ··· 3449 3446 mlxsw_sp_port_dev_check, 3450 3447 mlxsw_sp_port_obj_del); 3451 3448 return notifier_from_errno(err); 3449 + case SWITCHDEV_PORT_ATTR_SET: 3450 + err = switchdev_handle_port_attr_set(dev, ptr, 3451 + mlxsw_sp_port_dev_check, 3452 + mlxsw_sp_port_attr_set); 3453 + return notifier_from_errno(err); 3452 3454 } 3453 3455 3454 3456 return NOTIFY_DONE; ··· 3541 3533 kfree(mlxsw_sp->bridge); 3542 3534 } 3543 3535 3544 - void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port) 3545 - { 3546 - mlxsw_sp_port->dev->switchdev_ops = &mlxsw_sp_port_switchdev_ops; 3547 - } 3548 - 3549 - void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port) 3550 - { 3551 - }
+27 -5
drivers/net/ethernet/mscc/ocelot.c
··· 1324 1324 return ret; 1325 1325 } 1326 1326 1327 - static const struct switchdev_ops ocelot_port_switchdev_ops = { 1328 - .switchdev_port_attr_set = ocelot_port_attr_set, 1329 - }; 1330 - 1331 1327 static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port, 1332 1328 struct net_device *bridge) 1333 1329 { ··· 1578 1582 }; 1579 1583 EXPORT_SYMBOL(ocelot_netdevice_nb); 1580 1584 1585 + static int ocelot_switchdev_event(struct notifier_block *unused, 1586 + unsigned long event, void *ptr) 1587 + { 1588 + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 1589 + int err; 1590 + 1591 + switch (event) { 1592 + case SWITCHDEV_PORT_ATTR_SET: 1593 + err = switchdev_handle_port_attr_set(dev, ptr, 1594 + ocelot_netdevice_dev_check, 1595 + ocelot_port_attr_set); 1596 + return notifier_from_errno(err); 1597 + } 1598 + 1599 + return NOTIFY_DONE; 1600 + } 1601 + 1602 + struct notifier_block ocelot_switchdev_nb __read_mostly = { 1603 + .notifier_call = ocelot_switchdev_event, 1604 + }; 1605 + EXPORT_SYMBOL(ocelot_switchdev_nb); 1606 + 1581 1607 static int ocelot_switchdev_blocking_event(struct notifier_block *unused, 1582 1608 unsigned long event, void *ptr) 1583 1609 { ··· 1617 1599 err = switchdev_handle_port_obj_del(dev, ptr, 1618 1600 ocelot_netdevice_dev_check, 1619 1601 ocelot_port_obj_del); 1602 + return notifier_from_errno(err); 1603 + case SWITCHDEV_PORT_ATTR_SET: 1604 + err = switchdev_handle_port_attr_set(dev, ptr, 1605 + ocelot_netdevice_dev_check, 1606 + ocelot_port_attr_set); 1620 1607 return notifier_from_errno(err); 1621 1608 } 1622 1609 ··· 1656 1633 1657 1634 dev->netdev_ops = &ocelot_port_netdev_ops; 1658 1635 dev->ethtool_ops = &ocelot_ethtool_ops; 1659 - dev->switchdev_ops = &ocelot_port_switchdev_ops; 1660 1636 1661 1637 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS; 1662 1638 dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+1
drivers/net/ethernet/mscc/ocelot.h
··· 499 499 struct phy_device *phy); 500 500 501 501 extern struct notifier_block ocelot_netdevice_nb; 502 + extern struct notifier_block ocelot_switchdev_nb; 502 503 extern struct notifier_block ocelot_switchdev_blocking_nb; 503 504 504 505 #endif
+2
drivers/net/ethernet/mscc/ocelot_board.c
··· 329 329 } 330 330 331 331 register_netdevice_notifier(&ocelot_netdevice_nb); 332 + register_switchdev_notifier(&ocelot_switchdev_nb); 332 333 register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); 333 334 334 335 dev_info(&pdev->dev, "Ocelot switch probed\n"); ··· 346 345 347 346 ocelot_deinit(ocelot); 348 347 unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); 348 + unregister_switchdev_notifier(&ocelot_switchdev_nb); 349 349 unregister_netdevice_notifier(&ocelot_netdevice_nb); 350 350 351 351 return 0;
+18 -5
drivers/net/ethernet/rocker/rocker_main.c
··· 2142 2142 return err; 2143 2143 } 2144 2144 2145 - static const struct switchdev_ops rocker_port_switchdev_ops = { 2146 - .switchdev_port_attr_set = rocker_port_attr_set, 2147 - }; 2148 - 2149 2145 struct rocker_fib_event_work { 2150 2146 struct work_struct work; 2151 2147 union { ··· 2595 2599 rocker_port_dev_addr_init(rocker_port); 2596 2600 dev->netdev_ops = &rocker_port_netdev_ops; 2597 2601 dev->ethtool_ops = &rocker_port_ethtool_ops; 2598 - dev->switchdev_ops = &rocker_port_switchdev_ops; 2599 2602 netif_tx_napi_add(dev, &rocker_port->napi_tx, rocker_port_poll_tx, 2600 2603 NAPI_POLL_WEIGHT); 2601 2604 netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx, ··· 2705 2710 return dev->netdev_ops == &rocker_port_netdev_ops; 2706 2711 } 2707 2712 2713 + static int 2714 + rocker_switchdev_port_attr_set_event(struct net_device *netdev, 2715 + struct switchdev_notifier_port_attr_info *port_attr_info) 2716 + { 2717 + int err; 2718 + 2719 + err = rocker_port_attr_set(netdev, port_attr_info->attr, 2720 + port_attr_info->trans); 2721 + 2722 + port_attr_info->handled = true; 2723 + return notifier_from_errno(err); 2724 + } 2725 + 2708 2726 struct rocker_switchdev_event_work { 2709 2727 struct work_struct work; 2710 2728 struct switchdev_notifier_fdb_info fdb_info; ··· 2787 2779 if (!rocker_port_dev_check(dev)) 2788 2780 return NOTIFY_DONE; 2789 2781 2782 + if (event == SWITCHDEV_PORT_ATTR_SET) 2783 + return rocker_switchdev_port_attr_set_event(dev, ptr); 2784 + 2790 2785 rocker_port = netdev_priv(dev); 2791 2786 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 2792 2787 if (WARN_ON(!switchdev_work)) ··· 2852 2841 case SWITCHDEV_PORT_OBJ_ADD: 2853 2842 case SWITCHDEV_PORT_OBJ_DEL: 2854 2843 return rocker_switchdev_port_obj_event(event, dev, ptr); 2844 + case SWITCHDEV_PORT_ATTR_SET: 2845 + return rocker_switchdev_port_attr_set_event(dev, ptr); 2855 2846 } 2856 2847 2857 2848 return NOTIFY_DONE;
+20 -4
drivers/staging/fsl-dpaa2/ethsw/ethsw.c
··· 925 925 return err; 926 926 } 927 927 928 - static const struct switchdev_ops ethsw_port_switchdev_ops = { 929 - .switchdev_port_attr_set = swdev_port_attr_set, 930 - }; 928 + static int 929 + ethsw_switchdev_port_attr_set_event(struct net_device *netdev, 930 + struct switchdev_notifier_port_attr_info *port_attr_info) 931 + { 932 + int err; 933 + 934 + err = swdev_port_attr_set(netdev, port_attr_info->attr, 935 + port_attr_info->trans); 936 + 937 + port_attr_info->handled = true; 938 + return notifier_from_errno(err); 939 + } 931 940 932 941 /* For the moment, only flood setting needs to be updated */ 933 942 static int port_bridge_join(struct net_device *netdev, ··· 1056 1047 struct ethsw_switchdev_event_work *switchdev_work; 1057 1048 struct switchdev_notifier_fdb_info *fdb_info = ptr; 1058 1049 1050 + if (!ethsw_port_dev_check(dev)) 1051 + return NOTIFY_DONE; 1052 + 1053 + if (event == SWITCHDEV_PORT_ATTR_SET) 1054 + return ethsw_switchdev_port_attr_set_event(dev, ptr); 1055 + 1059 1056 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 1060 1057 if (!switchdev_work) 1061 1058 return NOTIFY_BAD; ··· 1130 1115 case SWITCHDEV_PORT_OBJ_ADD: /* fall through */ 1131 1116 case SWITCHDEV_PORT_OBJ_DEL: 1132 1117 return ethsw_switchdev_port_obj_event(event, dev, ptr); 1118 + case SWITCHDEV_PORT_ATTR_SET: 1119 + return ethsw_switchdev_port_attr_set_event(dev, ptr); 1133 1120 } 1134 1121 1135 1122 return NOTIFY_DONE; ··· 1451 1434 SET_NETDEV_DEV(port_netdev, dev); 1452 1435 port_netdev->netdev_ops = &ethsw_port_ops; 1453 1436 port_netdev->ethtool_ops = &ethsw_port_ethtool_ops; 1454 - port_netdev->switchdev_ops = &ethsw_port_switchdev_ops; 1455 1437 1456 1438 /* Set MTU limits */ 1457 1439 port_netdev->min_mtu = ETH_MIN_MTU;
-3
include/linux/netdevice.h
··· 1843 1843 #endif 1844 1844 const struct net_device_ops *netdev_ops; 1845 1845 const struct ethtool_ops *ethtool_ops; 1846 - #ifdef CONFIG_NET_SWITCHDEV 1847 - const struct switchdev_ops *switchdev_ops; 1848 - #endif 1849 1846 #ifdef CONFIG_NET_L3_MASTER_DEV 1850 1847 const struct l3mdev_ops *l3mdev_ops; 1851 1848 #endif
+24 -14
include/net/switchdev.h
··· 112 112 113 113 typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); 114 114 115 - /** 116 - * struct switchdev_ops - switchdev operations 117 - * 118 - * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). 119 - */ 120 - struct switchdev_ops { 121 - int (*switchdev_port_attr_set)(struct net_device *dev, 122 - const struct switchdev_attr *attr, 123 - struct switchdev_trans *trans); 124 - }; 125 - 126 115 enum switchdev_notifier_type { 127 116 SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, 128 117 SWITCHDEV_FDB_DEL_TO_BRIDGE, ··· 121 132 122 133 SWITCHDEV_PORT_OBJ_ADD, /* Blocking. */ 123 134 SWITCHDEV_PORT_OBJ_DEL, /* Blocking. */ 135 + SWITCHDEV_PORT_ATTR_SET, /* May be blocking . */ 124 136 125 137 SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE, 126 138 SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE, ··· 146 156 struct switchdev_notifier_port_obj_info { 147 157 struct switchdev_notifier_info info; /* must be first */ 148 158 const struct switchdev_obj *obj; 159 + struct switchdev_trans *trans; 160 + bool handled; 161 + }; 162 + 163 + struct switchdev_notifier_port_attr_info { 164 + struct switchdev_notifier_info info; /* must be first */ 165 + const struct switchdev_attr *attr; 149 166 struct switchdev_trans *trans; 150 167 bool handled; 151 168 }; ··· 209 212 int (*del_cb)(struct net_device *dev, 210 213 const struct switchdev_obj *obj)); 211 214 212 - #define SWITCHDEV_SET_OPS(netdev, ops) ((netdev)->switchdev_ops = (ops)) 215 + int switchdev_handle_port_attr_set(struct net_device *dev, 216 + struct switchdev_notifier_port_attr_info *port_attr_info, 217 + bool (*check_cb)(const struct net_device *dev), 218 + int (*set_cb)(struct net_device *dev, 219 + const struct switchdev_attr *attr, 220 + struct switchdev_trans *trans)); 213 221 #else 214 222 215 223 static inline void switchdev_deferred_process(void) ··· 301 299 return 0; 302 300 } 303 301 304 - #define SWITCHDEV_SET_OPS(netdev, ops) do {} while (0) 305 - 302 + static inline int 303 + switchdev_handle_port_attr_set(struct net_device *dev, 304 + struct switchdev_notifier_port_attr_info *port_attr_info, 305 + bool (*check_cb)(const struct net_device *dev), 306 + int (*set_cb)(struct net_device *dev, 307 + const struct switchdev_attr *attr, 308 + struct switchdev_trans *trans)) 309 + { 310 + return 0; 311 + } 306 312 #endif 307 313 308 314 #endif /* _LINUX_SWITCHDEV_H_ */
+7 -1
net/bridge/br_switchdev.c
··· 67 67 .id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, 68 68 .u.brport_flags = mask, 69 69 }; 70 + struct switchdev_notifier_port_attr_info info = { 71 + .attr = &attr, 72 + }; 70 73 int err; 71 74 72 75 if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD) 73 76 return 0; 74 77 75 - err = switchdev_port_attr_set(p->dev, &attr); 78 + /* We run from atomic context here */ 79 + err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, 80 + &info.info, NULL); 81 + err = notifier_to_errno(err); 76 82 if (err == -EOPNOTSUPP) 77 83 return 0; 78 84
+18 -5
net/dsa/slave.c
··· 1118 1118 .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, 1119 1119 }; 1120 1120 1121 - static const struct switchdev_ops dsa_slave_switchdev_ops = { 1122 - .switchdev_port_attr_set = dsa_slave_port_attr_set, 1123 - }; 1124 - 1125 1121 static struct device_type dsa_type = { 1126 1122 .name = "dsa", 1127 1123 }; ··· 1378 1382 eth_hw_addr_inherit(slave_dev, master); 1379 1383 slave_dev->priv_flags |= IFF_NO_QUEUE; 1380 1384 slave_dev->netdev_ops = &dsa_slave_netdev_ops; 1381 - slave_dev->switchdev_ops = &dsa_slave_switchdev_ops; 1382 1385 slave_dev->min_mtu = 0; 1383 1386 slave_dev->max_mtu = ETH_MAX_MTU; 1384 1387 SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); ··· 1519 1524 return NOTIFY_DONE; 1520 1525 } 1521 1526 1527 + static int 1528 + dsa_slave_switchdev_port_attr_set_event(struct net_device *netdev, 1529 + struct switchdev_notifier_port_attr_info *port_attr_info) 1530 + { 1531 + int err; 1532 + 1533 + err = dsa_slave_port_attr_set(netdev, port_attr_info->attr, 1534 + port_attr_info->trans); 1535 + 1536 + port_attr_info->handled = true; 1537 + return notifier_from_errno(err); 1538 + } 1539 + 1522 1540 struct dsa_switchdev_event_work { 1523 1541 struct work_struct work; 1524 1542 struct switchdev_notifier_fdb_info fdb_info; ··· 1610 1602 if (!dsa_slave_dev_check(dev)) 1611 1603 return NOTIFY_DONE; 1612 1604 1605 + if (event == SWITCHDEV_PORT_ATTR_SET) 1606 + return dsa_slave_switchdev_port_attr_set_event(dev, ptr); 1607 + 1613 1608 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 1614 1609 if (!switchdev_work) 1615 1610 return NOTIFY_BAD; ··· 1675 1664 case SWITCHDEV_PORT_OBJ_ADD: /* fall through */ 1676 1665 case SWITCHDEV_PORT_OBJ_DEL: 1677 1666 return dsa_slave_switchdev_port_obj_event(event, dev, ptr); 1667 + case SWITCHDEV_PORT_ATTR_SET: 1668 + return dsa_slave_switchdev_port_attr_set_event(dev, ptr); 1678 1669 } 1679 1670 1680 1671 return NOTIFY_DONE;
+76 -30
net/switchdev/switchdev.c
··· 174 174 return 0; 175 175 } 176 176 177 - static int __switchdev_port_attr_set(struct net_device *dev, 178 - const struct switchdev_attr *attr, 179 - struct switchdev_trans *trans) 177 + static int switchdev_port_attr_notify(enum switchdev_notifier_type nt, 178 + struct net_device *dev, 179 + const struct switchdev_attr *attr, 180 + struct switchdev_trans *trans) 180 181 { 181 - const struct switchdev_ops *ops = dev->switchdev_ops; 182 - struct net_device *lower_dev; 183 - struct list_head *iter; 184 - int err = -EOPNOTSUPP; 182 + int err; 183 + int rc; 185 184 186 - if (ops && ops->switchdev_port_attr_set) { 187 - err = ops->switchdev_port_attr_set(dev, attr, trans); 188 - goto done; 185 + struct switchdev_notifier_port_attr_info attr_info = { 186 + .attr = attr, 187 + .trans = trans, 188 + .handled = false, 189 + }; 190 + 191 + rc = call_switchdev_blocking_notifiers(nt, dev, 192 + &attr_info.info, NULL); 193 + err = notifier_to_errno(rc); 194 + if (err) { 195 + WARN_ON(!attr_info.handled); 196 + return err; 189 197 } 190 198 191 - if (attr->flags & SWITCHDEV_F_NO_RECURSE) 192 - goto done; 199 + if (!attr_info.handled) 200 + return -EOPNOTSUPP; 193 201 194 - /* Switch device port(s) may be stacked under 195 - * bond/team/vlan dev, so recurse down to set attr on 196 - * each port. 197 - */ 198 - 199 - netdev_for_each_lower_dev(dev, lower_dev, iter) { 200 - err = __switchdev_port_attr_set(lower_dev, attr, trans); 201 - if (err) 202 - break; 203 - } 204 - 205 - done: 206 - if (err == -EOPNOTSUPP && attr->flags & SWITCHDEV_F_SKIP_EOPNOTSUPP) 207 - err = 0; 208 - 209 - return err; 202 + return 0; 210 203 } 211 204 212 205 static int switchdev_port_attr_set_now(struct net_device *dev, ··· 218 225 */ 219 226 220 227 trans.ph_prepare = true; 221 - err = __switchdev_port_attr_set(dev, attr, &trans); 228 + err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr, 229 + &trans); 222 230 if (err) { 223 231 /* Prepare phase failed: abort the transaction. Any 224 232 * resources reserved in the prepare phase are ··· 238 244 */ 239 245 240 246 trans.ph_prepare = false; 241 - err = __switchdev_port_attr_set(dev, attr, &trans); 247 + err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr, 248 + &trans); 242 249 WARN(err, "%s: Commit of attribute (id=%d) failed.\n", 243 250 dev->name, attr->id); 244 251 switchdev_trans_items_warn_destroy(dev, &trans); ··· 650 655 return err; 651 656 } 652 657 EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del); 658 + 659 + static int __switchdev_handle_port_attr_set(struct net_device *dev, 660 + struct switchdev_notifier_port_attr_info *port_attr_info, 661 + bool (*check_cb)(const struct net_device *dev), 662 + int (*set_cb)(struct net_device *dev, 663 + const struct switchdev_attr *attr, 664 + struct switchdev_trans *trans)) 665 + { 666 + struct net_device *lower_dev; 667 + struct list_head *iter; 668 + int err = -EOPNOTSUPP; 669 + 670 + if (check_cb(dev)) { 671 + port_attr_info->handled = true; 672 + return set_cb(dev, port_attr_info->attr, 673 + port_attr_info->trans); 674 + } 675 + 676 + /* Switch ports might be stacked under e.g. a LAG. Ignore the 677 + * unsupported devices, another driver might be able to handle them. But 678 + * propagate to the callers any hard errors. 679 + * 680 + * If the driver does its own bookkeeping of stacked ports, it's not 681 + * necessary to go through this helper. 682 + */ 683 + netdev_for_each_lower_dev(dev, lower_dev, iter) { 684 + err = __switchdev_handle_port_attr_set(lower_dev, port_attr_info, 685 + check_cb, set_cb); 686 + if (err && err != -EOPNOTSUPP) 687 + return err; 688 + } 689 + 690 + return err; 691 + } 692 + 693 + int switchdev_handle_port_attr_set(struct net_device *dev, 694 + struct switchdev_notifier_port_attr_info *port_attr_info, 695 + bool (*check_cb)(const struct net_device *dev), 696 + int (*set_cb)(struct net_device *dev, 697 + const struct switchdev_attr *attr, 698 + struct switchdev_trans *trans)) 699 + { 700 + int err; 701 + 702 + err = __switchdev_handle_port_attr_set(dev, port_attr_info, check_cb, 703 + set_cb); 704 + if (err == -EOPNOTSUPP) 705 + err = 0; 706 + return err; 707 + } 708 + EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set);