12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 291da11f8SLennert Buytenhek /* 391da11f8SLennert Buytenhek * net/dsa/slave.c - Slave device handling 4e84665c9SLennert Buytenhek * Copyright (c) 2008-2009 Marvell Semiconductor 591da11f8SLennert Buytenhek */ 691da11f8SLennert Buytenhek 791da11f8SLennert Buytenhek #include <linux/list.h> 8df02c6ffSLennert Buytenhek #include <linux/etherdevice.h> 9b73adef6SFlorian Fainelli #include <linux/netdevice.h> 1091da11f8SLennert Buytenhek #include <linux/phy.h> 11a2820543SFlorian Fainelli #include <linux/phy_fixed.h> 12aab9c406SFlorian Fainelli #include <linux/phylink.h> 130d8bcdd3SFlorian Fainelli #include <linux/of_net.h> 140d8bcdd3SFlorian Fainelli #include <linux/of_mdio.h> 157f854420SAndrew Lunn #include <linux/mdio.h> 16b73adef6SFlorian Fainelli #include <net/rtnetlink.h> 17f50f2127SFlorian Fainelli #include <net/pkt_cls.h> 18a71acad9SOleksij Rempel #include <net/selftests.h> 19f50f2127SFlorian Fainelli #include <net/tc_act/tc_mirred.h> 20b73adef6SFlorian Fainelli #include <linux/if_bridge.h> 2118596f50SGeorge McCollister #include <linux/if_hsr.h> 22d538eca8SVladimir Oltean #include <net/dcbnl.h> 2304ff53f9SFlorian Fainelli #include <linux/netpoll.h> 24ea5dd34bSVivien Didelot 2547d2ce03SVladimir Oltean #include "dsa.h" 26022bba63SVladimir Oltean #include "port.h" 2794ef6fadSVladimir Oltean #include "master.h" 285917bfe6SVladimir Oltean #include "netlink.h" 2909f92341SVladimir Oltean #include "slave.h" 30bd954b82SVladimir Oltean #include "tag.h" 3191da11f8SLennert Buytenhek 328e396fecSVladimir Oltean struct dsa_switchdev_event_work { 338e396fecSVladimir Oltean struct net_device *dev; 348e396fecSVladimir Oltean struct net_device *orig_dev; 358e396fecSVladimir Oltean struct work_struct work; 368e396fecSVladimir Oltean unsigned long event; 378e396fecSVladimir Oltean /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and 388e396fecSVladimir Oltean * SWITCHDEV_FDB_DEL_TO_DEVICE 398e396fecSVladimir Oltean */ 408e396fecSVladimir Oltean unsigned char addr[ETH_ALEN]; 418e396fecSVladimir Oltean u16 vid; 428e396fecSVladimir Oltean bool host_addr; 438e396fecSVladimir Oltean }; 448e396fecSVladimir Oltean 458e396fecSVladimir Oltean enum dsa_standalone_event { 468e396fecSVladimir Oltean DSA_UC_ADD, 478e396fecSVladimir Oltean DSA_UC_DEL, 488e396fecSVladimir Oltean DSA_MC_ADD, 498e396fecSVladimir Oltean DSA_MC_DEL, 508e396fecSVladimir Oltean }; 518e396fecSVladimir Oltean 528e396fecSVladimir Oltean struct dsa_standalone_event_work { 538e396fecSVladimir Oltean struct work_struct work; 548e396fecSVladimir Oltean struct net_device *dev; 558e396fecSVladimir Oltean enum dsa_standalone_event event; 568e396fecSVladimir Oltean unsigned char addr[ETH_ALEN]; 578e396fecSVladimir Oltean u16 vid; 588e396fecSVladimir Oltean }; 598e396fecSVladimir Oltean 608e396fecSVladimir Oltean static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds) 618e396fecSVladimir Oltean { 628e396fecSVladimir Oltean return ds->ops->port_fdb_add && ds->ops->port_fdb_del && 638e396fecSVladimir Oltean ds->fdb_isolation && !ds->vlan_filtering_is_global && 648e396fecSVladimir Oltean !ds->needs_standalone_vlan_filtering; 658e396fecSVladimir Oltean } 668e396fecSVladimir Oltean 678e396fecSVladimir Oltean static bool dsa_switch_supports_mc_filtering(struct dsa_switch *ds) 688e396fecSVladimir Oltean { 698e396fecSVladimir Oltean return ds->ops->port_mdb_add && ds->ops->port_mdb_del && 708e396fecSVladimir Oltean ds->fdb_isolation && !ds->vlan_filtering_is_global && 718e396fecSVladimir Oltean !ds->needs_standalone_vlan_filtering; 728e396fecSVladimir Oltean } 738e396fecSVladimir Oltean 745e8a1e03SVladimir Oltean static void dsa_slave_standalone_event_work(struct work_struct *work) 755e8a1e03SVladimir Oltean { 765e8a1e03SVladimir Oltean struct dsa_standalone_event_work *standalone_work = 775e8a1e03SVladimir Oltean container_of(work, struct dsa_standalone_event_work, work); 785e8a1e03SVladimir Oltean const unsigned char *addr = standalone_work->addr; 795e8a1e03SVladimir Oltean struct net_device *dev = standalone_work->dev; 805e8a1e03SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 815e8a1e03SVladimir Oltean struct switchdev_obj_port_mdb mdb; 825e8a1e03SVladimir Oltean struct dsa_switch *ds = dp->ds; 835e8a1e03SVladimir Oltean u16 vid = standalone_work->vid; 845e8a1e03SVladimir Oltean int err; 855e8a1e03SVladimir Oltean 865e8a1e03SVladimir Oltean switch (standalone_work->event) { 875e8a1e03SVladimir Oltean case DSA_UC_ADD: 885e8a1e03SVladimir Oltean err = dsa_port_standalone_host_fdb_add(dp, addr, vid); 895e8a1e03SVladimir Oltean if (err) { 905e8a1e03SVladimir Oltean dev_err(ds->dev, 915e8a1e03SVladimir Oltean "port %d failed to add %pM vid %d to fdb: %d\n", 925e8a1e03SVladimir Oltean dp->index, addr, vid, err); 935e8a1e03SVladimir Oltean break; 945e8a1e03SVladimir Oltean } 955e8a1e03SVladimir Oltean break; 965e8a1e03SVladimir Oltean 975e8a1e03SVladimir Oltean case DSA_UC_DEL: 985e8a1e03SVladimir Oltean err = dsa_port_standalone_host_fdb_del(dp, addr, vid); 995e8a1e03SVladimir Oltean if (err) { 1005e8a1e03SVladimir Oltean dev_err(ds->dev, 1015e8a1e03SVladimir Oltean "port %d failed to delete %pM vid %d from fdb: %d\n", 1025e8a1e03SVladimir Oltean dp->index, addr, vid, err); 1035e8a1e03SVladimir Oltean } 1045e8a1e03SVladimir Oltean 1055e8a1e03SVladimir Oltean break; 1065e8a1e03SVladimir Oltean case DSA_MC_ADD: 1075e8a1e03SVladimir Oltean ether_addr_copy(mdb.addr, addr); 1085e8a1e03SVladimir Oltean mdb.vid = vid; 1095e8a1e03SVladimir Oltean 1105e8a1e03SVladimir Oltean err = dsa_port_standalone_host_mdb_add(dp, &mdb); 1115e8a1e03SVladimir Oltean if (err) { 1125e8a1e03SVladimir Oltean dev_err(ds->dev, 1135e8a1e03SVladimir Oltean "port %d failed to add %pM vid %d to mdb: %d\n", 1145e8a1e03SVladimir Oltean dp->index, addr, vid, err); 1155e8a1e03SVladimir Oltean break; 1165e8a1e03SVladimir Oltean } 1175e8a1e03SVladimir Oltean break; 1185e8a1e03SVladimir Oltean case DSA_MC_DEL: 1195e8a1e03SVladimir Oltean ether_addr_copy(mdb.addr, addr); 1205e8a1e03SVladimir Oltean mdb.vid = vid; 1215e8a1e03SVladimir Oltean 1225e8a1e03SVladimir Oltean err = dsa_port_standalone_host_mdb_del(dp, &mdb); 1235e8a1e03SVladimir Oltean if (err) { 1245e8a1e03SVladimir Oltean dev_err(ds->dev, 1255e8a1e03SVladimir Oltean "port %d failed to delete %pM vid %d from mdb: %d\n", 1265e8a1e03SVladimir Oltean dp->index, addr, vid, err); 1275e8a1e03SVladimir Oltean } 1285e8a1e03SVladimir Oltean 1295e8a1e03SVladimir Oltean break; 1305e8a1e03SVladimir Oltean } 1315e8a1e03SVladimir Oltean 1325e8a1e03SVladimir Oltean kfree(standalone_work); 1335e8a1e03SVladimir Oltean } 1345e8a1e03SVladimir Oltean 1355e8a1e03SVladimir Oltean static int dsa_slave_schedule_standalone_work(struct net_device *dev, 1365e8a1e03SVladimir Oltean enum dsa_standalone_event event, 1375e8a1e03SVladimir Oltean const unsigned char *addr, 1385e8a1e03SVladimir Oltean u16 vid) 1395e8a1e03SVladimir Oltean { 1405e8a1e03SVladimir Oltean struct dsa_standalone_event_work *standalone_work; 1415e8a1e03SVladimir Oltean 1425e8a1e03SVladimir Oltean standalone_work = kzalloc(sizeof(*standalone_work), GFP_ATOMIC); 1435e8a1e03SVladimir Oltean if (!standalone_work) 1445e8a1e03SVladimir Oltean return -ENOMEM; 1455e8a1e03SVladimir Oltean 1465e8a1e03SVladimir Oltean INIT_WORK(&standalone_work->work, dsa_slave_standalone_event_work); 1475e8a1e03SVladimir Oltean standalone_work->event = event; 1485e8a1e03SVladimir Oltean standalone_work->dev = dev; 1495e8a1e03SVladimir Oltean 1505e8a1e03SVladimir Oltean ether_addr_copy(standalone_work->addr, addr); 1515e8a1e03SVladimir Oltean standalone_work->vid = vid; 1525e8a1e03SVladimir Oltean 1535e8a1e03SVladimir Oltean dsa_schedule_work(&standalone_work->work); 1545e8a1e03SVladimir Oltean 1555e8a1e03SVladimir Oltean return 0; 1565e8a1e03SVladimir Oltean } 1575e8a1e03SVladimir Oltean 1585e8a1e03SVladimir Oltean static int dsa_slave_sync_uc(struct net_device *dev, 1595e8a1e03SVladimir Oltean const unsigned char *addr) 1605e8a1e03SVladimir Oltean { 1615077e2c8SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 1625077e2c8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1635077e2c8SVladimir Oltean 1645077e2c8SVladimir Oltean dev_uc_add(master, addr); 1655077e2c8SVladimir Oltean 1665077e2c8SVladimir Oltean if (!dsa_switch_supports_uc_filtering(dp->ds)) 1675077e2c8SVladimir Oltean return 0; 1685077e2c8SVladimir Oltean 1695e8a1e03SVladimir Oltean return dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD, addr, 0); 1705e8a1e03SVladimir Oltean } 1715e8a1e03SVladimir Oltean 1725e8a1e03SVladimir Oltean static int dsa_slave_unsync_uc(struct net_device *dev, 1735e8a1e03SVladimir Oltean const unsigned char *addr) 1745e8a1e03SVladimir Oltean { 1755077e2c8SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 1765077e2c8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1775077e2c8SVladimir Oltean 1785077e2c8SVladimir Oltean dev_uc_del(master, addr); 1795077e2c8SVladimir Oltean 1805077e2c8SVladimir Oltean if (!dsa_switch_supports_uc_filtering(dp->ds)) 1815077e2c8SVladimir Oltean return 0; 1825077e2c8SVladimir Oltean 1835e8a1e03SVladimir Oltean return dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL, addr, 0); 1845e8a1e03SVladimir Oltean } 1855e8a1e03SVladimir Oltean 1865e8a1e03SVladimir Oltean static int dsa_slave_sync_mc(struct net_device *dev, 1875e8a1e03SVladimir Oltean const unsigned char *addr) 1885e8a1e03SVladimir Oltean { 1895077e2c8SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 1905077e2c8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1915077e2c8SVladimir Oltean 1925077e2c8SVladimir Oltean dev_mc_add(master, addr); 1935077e2c8SVladimir Oltean 1945077e2c8SVladimir Oltean if (!dsa_switch_supports_mc_filtering(dp->ds)) 1955077e2c8SVladimir Oltean return 0; 1965077e2c8SVladimir Oltean 1975e8a1e03SVladimir Oltean return dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, addr, 0); 1985e8a1e03SVladimir Oltean } 1995e8a1e03SVladimir Oltean 2005e8a1e03SVladimir Oltean static int dsa_slave_unsync_mc(struct net_device *dev, 2015e8a1e03SVladimir Oltean const unsigned char *addr) 2025e8a1e03SVladimir Oltean { 2035077e2c8SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 2045077e2c8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2055077e2c8SVladimir Oltean 2065077e2c8SVladimir Oltean dev_mc_del(master, addr); 2075077e2c8SVladimir Oltean 2085077e2c8SVladimir Oltean if (!dsa_switch_supports_mc_filtering(dp->ds)) 2095077e2c8SVladimir Oltean return 0; 2105077e2c8SVladimir Oltean 2115e8a1e03SVladimir Oltean return dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, addr, 0); 2125e8a1e03SVladimir Oltean } 2135e8a1e03SVladimir Oltean 21495f510d0SVladimir Oltean void dsa_slave_sync_ha(struct net_device *dev) 21595f510d0SVladimir Oltean { 21695f510d0SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 21795f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 21895f510d0SVladimir Oltean struct netdev_hw_addr *ha; 21995f510d0SVladimir Oltean 22095f510d0SVladimir Oltean netif_addr_lock_bh(dev); 22195f510d0SVladimir Oltean 22295f510d0SVladimir Oltean netdev_for_each_synced_mc_addr(ha, dev) 22395f510d0SVladimir Oltean dsa_slave_sync_mc(dev, ha->addr); 22495f510d0SVladimir Oltean 22595f510d0SVladimir Oltean netdev_for_each_synced_uc_addr(ha, dev) 22695f510d0SVladimir Oltean dsa_slave_sync_uc(dev, ha->addr); 22795f510d0SVladimir Oltean 22895f510d0SVladimir Oltean netif_addr_unlock_bh(dev); 22995f510d0SVladimir Oltean 23095f510d0SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds) || 23195f510d0SVladimir Oltean dsa_switch_supports_mc_filtering(ds)) 23295f510d0SVladimir Oltean dsa_flush_workqueue(); 23395f510d0SVladimir Oltean } 23495f510d0SVladimir Oltean 23595f510d0SVladimir Oltean void dsa_slave_unsync_ha(struct net_device *dev) 23695f510d0SVladimir Oltean { 23795f510d0SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 23895f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 23995f510d0SVladimir Oltean struct netdev_hw_addr *ha; 24095f510d0SVladimir Oltean 24195f510d0SVladimir Oltean netif_addr_lock_bh(dev); 24295f510d0SVladimir Oltean 24395f510d0SVladimir Oltean netdev_for_each_synced_uc_addr(ha, dev) 24495f510d0SVladimir Oltean dsa_slave_unsync_uc(dev, ha->addr); 24595f510d0SVladimir Oltean 24695f510d0SVladimir Oltean netdev_for_each_synced_mc_addr(ha, dev) 24795f510d0SVladimir Oltean dsa_slave_unsync_mc(dev, ha->addr); 24895f510d0SVladimir Oltean 24995f510d0SVladimir Oltean netif_addr_unlock_bh(dev); 25095f510d0SVladimir Oltean 25195f510d0SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds) || 25295f510d0SVladimir Oltean dsa_switch_supports_mc_filtering(ds)) 25395f510d0SVladimir Oltean dsa_flush_workqueue(); 25495f510d0SVladimir Oltean } 25595f510d0SVladimir Oltean 25691da11f8SLennert Buytenhek /* slave mii_bus handling ***************************************************/ 25791da11f8SLennert Buytenhek static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) 25891da11f8SLennert Buytenhek { 25991da11f8SLennert Buytenhek struct dsa_switch *ds = bus->priv; 26091da11f8SLennert Buytenhek 2610d8bcdd3SFlorian Fainelli if (ds->phys_mii_mask & (1 << addr)) 2629d490b4eSVivien Didelot return ds->ops->phy_read(ds, addr, reg); 26391da11f8SLennert Buytenhek 26491da11f8SLennert Buytenhek return 0xffff; 26591da11f8SLennert Buytenhek } 26691da11f8SLennert Buytenhek 26791da11f8SLennert Buytenhek static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) 26891da11f8SLennert Buytenhek { 26991da11f8SLennert Buytenhek struct dsa_switch *ds = bus->priv; 27091da11f8SLennert Buytenhek 2710d8bcdd3SFlorian Fainelli if (ds->phys_mii_mask & (1 << addr)) 2729d490b4eSVivien Didelot return ds->ops->phy_write(ds, addr, reg, val); 27391da11f8SLennert Buytenhek 27491da11f8SLennert Buytenhek return 0; 27591da11f8SLennert Buytenhek } 27691da11f8SLennert Buytenhek 27791da11f8SLennert Buytenhek void dsa_slave_mii_bus_init(struct dsa_switch *ds) 27891da11f8SLennert Buytenhek { 27991da11f8SLennert Buytenhek ds->slave_mii_bus->priv = (void *)ds; 28091da11f8SLennert Buytenhek ds->slave_mii_bus->name = "dsa slave smi"; 28191da11f8SLennert Buytenhek ds->slave_mii_bus->read = dsa_slave_phy_read; 28291da11f8SLennert Buytenhek ds->slave_mii_bus->write = dsa_slave_phy_write; 2830b7b498dSFlorian Fainelli snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", 28449463b7fSVivien Didelot ds->dst->index, ds->index); 285c33063d6SAndrew Lunn ds->slave_mii_bus->parent = ds->dev; 28624df8986SVivien Didelot ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; 28791da11f8SLennert Buytenhek } 28891da11f8SLennert Buytenhek 28991da11f8SLennert Buytenhek 29091da11f8SLennert Buytenhek /* slave device handling ****************************************************/ 291abd2be00SNicolas Dichtel static int dsa_slave_get_iflink(const struct net_device *dev) 292c0840801SLennert Buytenhek { 293d0006b00SVivien Didelot return dsa_slave_to_master(dev)->ifindex; 294c0840801SLennert Buytenhek } 295c0840801SLennert Buytenhek 29691da11f8SLennert Buytenhek static int dsa_slave_open(struct net_device *dev) 29791da11f8SLennert Buytenhek { 298d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 299d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 300499aa9e1SVladimir Oltean struct dsa_switch *ds = dp->ds; 301df02c6ffSLennert Buytenhek int err; 302df02c6ffSLennert Buytenhek 3039d5ef190SVladimir Oltean err = dev_open(master, NULL); 3049d5ef190SVladimir Oltean if (err < 0) { 3059d5ef190SVladimir Oltean netdev_err(dev, "failed to open master %s\n", master->name); 3069d5ef190SVladimir Oltean goto out; 3079d5ef190SVladimir Oltean } 308df02c6ffSLennert Buytenhek 309499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) { 310499aa9e1SVladimir Oltean err = dsa_port_standalone_host_fdb_add(dp, dev->dev_addr, 0); 311499aa9e1SVladimir Oltean if (err) 312499aa9e1SVladimir Oltean goto out; 313499aa9e1SVladimir Oltean } 314499aa9e1SVladimir Oltean 3158feedbb4SJoe Perches if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { 316a748ee24SJiri Pirko err = dev_uc_add(master, dev->dev_addr); 317df02c6ffSLennert Buytenhek if (err < 0) 318499aa9e1SVladimir Oltean goto del_host_addr; 319df02c6ffSLennert Buytenhek } 320df02c6ffSLennert Buytenhek 3218640f8dcSRussell King err = dsa_port_enable_rt(dp, dev->phydev); 322b2f2af21SFlorian Fainelli if (err) 32335aae5abSVladimir Oltean goto del_unicast; 324b73adef6SFlorian Fainelli 32591da11f8SLennert Buytenhek return 0; 326df02c6ffSLennert Buytenhek 327df02c6ffSLennert Buytenhek del_unicast: 3288feedbb4SJoe Perches if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) 329a748ee24SJiri Pirko dev_uc_del(master, dev->dev_addr); 330499aa9e1SVladimir Oltean del_host_addr: 331499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 332499aa9e1SVladimir Oltean dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 333df02c6ffSLennert Buytenhek out: 334df02c6ffSLennert Buytenhek return err; 33591da11f8SLennert Buytenhek } 33691da11f8SLennert Buytenhek 33791da11f8SLennert Buytenhek static int dsa_slave_close(struct net_device *dev) 33891da11f8SLennert Buytenhek { 339d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 340d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 341499aa9e1SVladimir Oltean struct dsa_switch *ds = dp->ds; 342df02c6ffSLennert Buytenhek 3438640f8dcSRussell King dsa_port_disable_rt(dp); 3446457edfeSVivien Didelot 3458feedbb4SJoe Perches if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) 346a748ee24SJiri Pirko dev_uc_del(master, dev->dev_addr); 347df02c6ffSLennert Buytenhek 348499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 349499aa9e1SVladimir Oltean dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 350499aa9e1SVladimir Oltean 35191da11f8SLennert Buytenhek return 0; 35291da11f8SLennert Buytenhek } 35391da11f8SLennert Buytenhek 35472c3b0c7SVladimir Oltean static void dsa_slave_manage_host_flood(struct net_device *dev) 3557569459aSVladimir Oltean { 35672c3b0c7SVladimir Oltean bool mc = dev->flags & (IFF_PROMISC | IFF_ALLMULTI); 35772c3b0c7SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 35872c3b0c7SVladimir Oltean bool uc = dev->flags & IFF_PROMISC; 3597569459aSVladimir Oltean 36072c3b0c7SVladimir Oltean dsa_port_set_host_flood(dp, uc, mc); 3617569459aSVladimir Oltean } 3627569459aSVladimir Oltean 36391da11f8SLennert Buytenhek static void dsa_slave_change_rx_flags(struct net_device *dev, int change) 36491da11f8SLennert Buytenhek { 365d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 3667569459aSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 3677569459aSVladimir Oltean struct dsa_switch *ds = dp->ds; 36835aae5abSVladimir Oltean 36991da11f8SLennert Buytenhek if (change & IFF_ALLMULTI) 37017ab4f61SRundong Ge dev_set_allmulti(master, 37117ab4f61SRundong Ge dev->flags & IFF_ALLMULTI ? 1 : -1); 37291da11f8SLennert Buytenhek if (change & IFF_PROMISC) 37317ab4f61SRundong Ge dev_set_promiscuity(master, 37417ab4f61SRundong Ge dev->flags & IFF_PROMISC ? 1 : -1); 3757569459aSVladimir Oltean 3767569459aSVladimir Oltean if (dsa_switch_supports_uc_filtering(ds) && 3777569459aSVladimir Oltean dsa_switch_supports_mc_filtering(ds)) 37872c3b0c7SVladimir Oltean dsa_slave_manage_host_flood(dev); 37917ab4f61SRundong Ge } 38091da11f8SLennert Buytenhek 38191da11f8SLennert Buytenhek static void dsa_slave_set_rx_mode(struct net_device *dev) 38291da11f8SLennert Buytenhek { 3835e8a1e03SVladimir Oltean __dev_mc_sync(dev, dsa_slave_sync_mc, dsa_slave_unsync_mc); 3845e8a1e03SVladimir Oltean __dev_uc_sync(dev, dsa_slave_sync_uc, dsa_slave_unsync_uc); 38591da11f8SLennert Buytenhek } 38691da11f8SLennert Buytenhek 387df02c6ffSLennert Buytenhek static int dsa_slave_set_mac_address(struct net_device *dev, void *a) 38891da11f8SLennert Buytenhek { 389d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 390499aa9e1SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 391499aa9e1SVladimir Oltean struct dsa_switch *ds = dp->ds; 392df02c6ffSLennert Buytenhek struct sockaddr *addr = a; 393df02c6ffSLennert Buytenhek int err; 394df02c6ffSLennert Buytenhek 395df02c6ffSLennert Buytenhek if (!is_valid_ether_addr(addr->sa_data)) 396df02c6ffSLennert Buytenhek return -EADDRNOTAVAIL; 397df02c6ffSLennert Buytenhek 398e2d0576fSVladimir Oltean /* If the port is down, the address isn't synced yet to hardware or 399e2d0576fSVladimir Oltean * to the DSA master, so there is nothing to change. 400e2d0576fSVladimir Oltean */ 401e2d0576fSVladimir Oltean if (!(dev->flags & IFF_UP)) 402e2d0576fSVladimir Oltean goto out_change_dev_addr; 403e2d0576fSVladimir Oltean 404499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) { 405499aa9e1SVladimir Oltean err = dsa_port_standalone_host_fdb_add(dp, addr->sa_data, 0); 406499aa9e1SVladimir Oltean if (err) 407499aa9e1SVladimir Oltean return err; 408499aa9e1SVladimir Oltean } 409499aa9e1SVladimir Oltean 4108feedbb4SJoe Perches if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { 411a748ee24SJiri Pirko err = dev_uc_add(master, addr->sa_data); 412df02c6ffSLennert Buytenhek if (err < 0) 413499aa9e1SVladimir Oltean goto del_unicast; 414df02c6ffSLennert Buytenhek } 415df02c6ffSLennert Buytenhek 4168feedbb4SJoe Perches if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) 417a748ee24SJiri Pirko dev_uc_del(master, dev->dev_addr); 418df02c6ffSLennert Buytenhek 419499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 420499aa9e1SVladimir Oltean dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); 421499aa9e1SVladimir Oltean 422e2d0576fSVladimir Oltean out_change_dev_addr: 423e35b8d7dSJakub Kicinski eth_hw_addr_set(dev, addr->sa_data); 42491da11f8SLennert Buytenhek 42591da11f8SLennert Buytenhek return 0; 426499aa9e1SVladimir Oltean 427499aa9e1SVladimir Oltean del_unicast: 428499aa9e1SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 429499aa9e1SVladimir Oltean dsa_port_standalone_host_fdb_del(dp, addr->sa_data, 0); 430499aa9e1SVladimir Oltean 431499aa9e1SVladimir Oltean return err; 43291da11f8SLennert Buytenhek } 43391da11f8SLennert Buytenhek 4342bedde1aSArkadi Sharshevsky struct dsa_slave_dump_ctx { 4352bedde1aSArkadi Sharshevsky struct net_device *dev; 4362bedde1aSArkadi Sharshevsky struct sk_buff *skb; 4372bedde1aSArkadi Sharshevsky struct netlink_callback *cb; 4382bedde1aSArkadi Sharshevsky int idx; 4392bedde1aSArkadi Sharshevsky }; 4402bedde1aSArkadi Sharshevsky 4412bedde1aSArkadi Sharshevsky static int 4422bedde1aSArkadi Sharshevsky dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid, 4432bedde1aSArkadi Sharshevsky bool is_static, void *data) 4442bedde1aSArkadi Sharshevsky { 4452bedde1aSArkadi Sharshevsky struct dsa_slave_dump_ctx *dump = data; 4462bedde1aSArkadi Sharshevsky u32 portid = NETLINK_CB(dump->cb->skb).portid; 4472bedde1aSArkadi Sharshevsky u32 seq = dump->cb->nlh->nlmsg_seq; 4482bedde1aSArkadi Sharshevsky struct nlmsghdr *nlh; 4492bedde1aSArkadi Sharshevsky struct ndmsg *ndm; 4502bedde1aSArkadi Sharshevsky 4512bedde1aSArkadi Sharshevsky if (dump->idx < dump->cb->args[2]) 4522bedde1aSArkadi Sharshevsky goto skip; 4532bedde1aSArkadi Sharshevsky 4542bedde1aSArkadi Sharshevsky nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, 4552bedde1aSArkadi Sharshevsky sizeof(*ndm), NLM_F_MULTI); 4562bedde1aSArkadi Sharshevsky if (!nlh) 4572bedde1aSArkadi Sharshevsky return -EMSGSIZE; 4582bedde1aSArkadi Sharshevsky 4592bedde1aSArkadi Sharshevsky ndm = nlmsg_data(nlh); 4602bedde1aSArkadi Sharshevsky ndm->ndm_family = AF_BRIDGE; 4612bedde1aSArkadi Sharshevsky ndm->ndm_pad1 = 0; 4622bedde1aSArkadi Sharshevsky ndm->ndm_pad2 = 0; 4632bedde1aSArkadi Sharshevsky ndm->ndm_flags = NTF_SELF; 4642bedde1aSArkadi Sharshevsky ndm->ndm_type = 0; 4652bedde1aSArkadi Sharshevsky ndm->ndm_ifindex = dump->dev->ifindex; 4662bedde1aSArkadi Sharshevsky ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; 4672bedde1aSArkadi Sharshevsky 4682bedde1aSArkadi Sharshevsky if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) 4692bedde1aSArkadi Sharshevsky goto nla_put_failure; 4702bedde1aSArkadi Sharshevsky 4712bedde1aSArkadi Sharshevsky if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) 4722bedde1aSArkadi Sharshevsky goto nla_put_failure; 4732bedde1aSArkadi Sharshevsky 4742bedde1aSArkadi Sharshevsky nlmsg_end(dump->skb, nlh); 4752bedde1aSArkadi Sharshevsky 4762bedde1aSArkadi Sharshevsky skip: 4772bedde1aSArkadi Sharshevsky dump->idx++; 4782bedde1aSArkadi Sharshevsky return 0; 4792bedde1aSArkadi Sharshevsky 4802bedde1aSArkadi Sharshevsky nla_put_failure: 4812bedde1aSArkadi Sharshevsky nlmsg_cancel(dump->skb, nlh); 4822bedde1aSArkadi Sharshevsky return -EMSGSIZE; 4832bedde1aSArkadi Sharshevsky } 4842bedde1aSArkadi Sharshevsky 4852bedde1aSArkadi Sharshevsky static int 4862bedde1aSArkadi Sharshevsky dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, 4872bedde1aSArkadi Sharshevsky struct net_device *dev, struct net_device *filter_dev, 4882bedde1aSArkadi Sharshevsky int *idx) 4892bedde1aSArkadi Sharshevsky { 490d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 4912bedde1aSArkadi Sharshevsky struct dsa_slave_dump_ctx dump = { 4922bedde1aSArkadi Sharshevsky .dev = dev, 4932bedde1aSArkadi Sharshevsky .skb = skb, 4942bedde1aSArkadi Sharshevsky .cb = cb, 4952bedde1aSArkadi Sharshevsky .idx = *idx, 4962bedde1aSArkadi Sharshevsky }; 4972bedde1aSArkadi Sharshevsky int err; 4982bedde1aSArkadi Sharshevsky 499de40fc5dSVivien Didelot err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump); 5002bedde1aSArkadi Sharshevsky *idx = dump.idx; 501de40fc5dSVivien Didelot 5022bedde1aSArkadi Sharshevsky return err; 5032bedde1aSArkadi Sharshevsky } 5042bedde1aSArkadi Sharshevsky 50591da11f8SLennert Buytenhek static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 50691da11f8SLennert Buytenhek { 5070336369dSBrandon Streiff struct dsa_slave_priv *p = netdev_priv(dev); 5080336369dSBrandon Streiff struct dsa_switch *ds = p->dp->ds; 5090336369dSBrandon Streiff int port = p->dp->index; 5100336369dSBrandon Streiff 5110336369dSBrandon Streiff /* Pass through to switch driver if it supports timestamping */ 5120336369dSBrandon Streiff switch (cmd) { 5130336369dSBrandon Streiff case SIOCGHWTSTAMP: 5140336369dSBrandon Streiff if (ds->ops->port_hwtstamp_get) 5150336369dSBrandon Streiff return ds->ops->port_hwtstamp_get(ds, port, ifr); 5160336369dSBrandon Streiff break; 5170336369dSBrandon Streiff case SIOCSHWTSTAMP: 5180336369dSBrandon Streiff if (ds->ops->port_hwtstamp_set) 5190336369dSBrandon Streiff return ds->ops->port_hwtstamp_set(ds, port, ifr); 5200336369dSBrandon Streiff break; 5210336369dSBrandon Streiff } 5220336369dSBrandon Streiff 523aab9c406SFlorian Fainelli return phylink_mii_ioctl(p->dp->pl, ifr, cmd); 52491da11f8SLennert Buytenhek } 52591da11f8SLennert Buytenhek 52669bfac96SVladimir Oltean static int dsa_slave_port_attr_set(struct net_device *dev, const void *ctx, 5274c08c586SVladimir Oltean const struct switchdev_attr *attr, 5284c08c586SVladimir Oltean struct netlink_ext_ack *extack) 52935636062SScott Feldman { 530d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 531b8d866acSVivien Didelot int ret; 53235636062SScott Feldman 5330d2cfbd4SVladimir Oltean if (ctx && ctx != dp) 5340d2cfbd4SVladimir Oltean return 0; 5350d2cfbd4SVladimir Oltean 53635636062SScott Feldman switch (attr->id) { 5371f868398SJiri Pirko case SWITCHDEV_ATTR_ID_PORT_STP_STATE: 53803cbb870SVladimir Oltean if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) 53903cbb870SVladimir Oltean return -EOPNOTSUPP; 54003cbb870SVladimir Oltean 54139f32101SVladimir Oltean ret = dsa_port_set_state(dp, attr->u.stp_state, true); 54235636062SScott Feldman break; 5437414af30STobias Waldekranz case SWITCHDEV_ATTR_ID_PORT_MST_STATE: 5447414af30STobias Waldekranz if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) 5457414af30STobias Waldekranz return -EOPNOTSUPP; 5467414af30STobias Waldekranz 5477414af30STobias Waldekranz ret = dsa_port_set_mst_state(dp, &attr->u.mst_state, extack); 5487414af30STobias Waldekranz break; 549fb2dabadSVivien Didelot case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: 550936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) 55103cbb870SVladimir Oltean return -EOPNOTSUPP; 55203cbb870SVladimir Oltean 55389153ed6SVladimir Oltean ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, 55489153ed6SVladimir Oltean extack); 555fb2dabadSVivien Didelot break; 55634a79f63SVivien Didelot case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: 557936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) 55803cbb870SVladimir Oltean return -EOPNOTSUPP; 55903cbb870SVladimir Oltean 560bae33f2bSVladimir Oltean ret = dsa_port_ageing_time(dp, attr->u.ageing_time); 56134a79f63SVivien Didelot break; 562332afc4cSTobias Waldekranz case SWITCHDEV_ATTR_ID_BRIDGE_MST: 563332afc4cSTobias Waldekranz if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) 564332afc4cSTobias Waldekranz return -EOPNOTSUPP; 565332afc4cSTobias Waldekranz 566332afc4cSTobias Waldekranz ret = dsa_port_mst_enable(dp, attr->u.mst, extack); 567332afc4cSTobias Waldekranz break; 568ea87005aSFlorian Fainelli case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: 56903cbb870SVladimir Oltean if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) 57003cbb870SVladimir Oltean return -EOPNOTSUPP; 57103cbb870SVladimir Oltean 572a8b659e7SVladimir Oltean ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, 573a8b659e7SVladimir Oltean extack); 574ea87005aSFlorian Fainelli break; 57557652796SRussell King case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: 57603cbb870SVladimir Oltean if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) 57703cbb870SVladimir Oltean return -EOPNOTSUPP; 57803cbb870SVladimir Oltean 579a8b659e7SVladimir Oltean ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); 58057652796SRussell King break; 5818e6598a7STobias Waldekranz case SWITCHDEV_ATTR_ID_VLAN_MSTI: 5828e6598a7STobias Waldekranz if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) 5838e6598a7STobias Waldekranz return -EOPNOTSUPP; 5848e6598a7STobias Waldekranz 5858e6598a7STobias Waldekranz ret = dsa_port_vlan_msti(dp, &attr->u.vlan_msti); 5868e6598a7STobias Waldekranz break; 58735636062SScott Feldman default: 58835636062SScott Feldman ret = -EOPNOTSUPP; 58935636062SScott Feldman break; 59035636062SScott Feldman } 59135636062SScott Feldman 59235636062SScott Feldman return ret; 59335636062SScott Feldman } 59435636062SScott Feldman 5951ce39f0eSVladimir Oltean /* Must be called under rcu_read_lock() */ 5961ce39f0eSVladimir Oltean static int 5971ce39f0eSVladimir Oltean dsa_slave_vlan_check_for_8021q_uppers(struct net_device *slave, 5981ce39f0eSVladimir Oltean const struct switchdev_obj_port_vlan *vlan) 5991ce39f0eSVladimir Oltean { 6001ce39f0eSVladimir Oltean struct net_device *upper_dev; 6011ce39f0eSVladimir Oltean struct list_head *iter; 6021ce39f0eSVladimir Oltean 6031ce39f0eSVladimir Oltean netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { 6041ce39f0eSVladimir Oltean u16 vid; 6051ce39f0eSVladimir Oltean 6061ce39f0eSVladimir Oltean if (!is_vlan_dev(upper_dev)) 6071ce39f0eSVladimir Oltean continue; 6081ce39f0eSVladimir Oltean 6091ce39f0eSVladimir Oltean vid = vlan_dev_vlan_id(upper_dev); 610b7a9e0daSVladimir Oltean if (vid == vlan->vid) 6111ce39f0eSVladimir Oltean return -EBUSY; 6121ce39f0eSVladimir Oltean } 6131ce39f0eSVladimir Oltean 6141ce39f0eSVladimir Oltean return 0; 6151ce39f0eSVladimir Oltean } 6161ce39f0eSVladimir Oltean 617bdcff080SVivien Didelot static int dsa_slave_vlan_add(struct net_device *dev, 6180ee2af4eSVladimir Oltean const struct switchdev_obj *obj, 6190ee2af4eSVladimir Oltean struct netlink_ext_ack *extack) 620bdcff080SVivien Didelot { 621bdcff080SVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 622134ef238SVladimir Oltean struct switchdev_obj_port_vlan *vlan; 623b7a9e0daSVladimir Oltean int err; 624bdcff080SVivien Didelot 6250ee2af4eSVladimir Oltean if (dsa_port_skip_vlan_configuration(dp)) { 6260ee2af4eSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); 627c5335d73SVivien Didelot return 0; 6280ee2af4eSVladimir Oltean } 629c5335d73SVivien Didelot 630134ef238SVladimir Oltean vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 631bdcff080SVivien Didelot 6321ce39f0eSVladimir Oltean /* Deny adding a bridge VLAN when there is already an 802.1Q upper with 6331ce39f0eSVladimir Oltean * the same VID. 6341ce39f0eSVladimir Oltean */ 63536cbf39bSVladimir Oltean if (br_vlan_enabled(dsa_port_bridge_dev_get(dp))) { 6361ce39f0eSVladimir Oltean rcu_read_lock(); 637134ef238SVladimir Oltean err = dsa_slave_vlan_check_for_8021q_uppers(dev, vlan); 6381ce39f0eSVladimir Oltean rcu_read_unlock(); 63931046a5fSVladimir Oltean if (err) { 64031046a5fSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 64131046a5fSVladimir Oltean "Port already has a VLAN upper with this VID"); 6421ce39f0eSVladimir Oltean return err; 6431ce39f0eSVladimir Oltean } 64431046a5fSVladimir Oltean } 6451ce39f0eSVladimir Oltean 646134ef238SVladimir Oltean return dsa_port_vlan_add(dp, vlan, extack); 647134ef238SVladimir Oltean } 648bdcff080SVivien Didelot 649164f861bSVladimir Oltean /* Offload a VLAN installed on the bridge or on a foreign interface by 650164f861bSVladimir Oltean * installing it as a VLAN towards the CPU port. 651164f861bSVladimir Oltean */ 652134ef238SVladimir Oltean static int dsa_slave_host_vlan_add(struct net_device *dev, 653134ef238SVladimir Oltean const struct switchdev_obj *obj, 654134ef238SVladimir Oltean struct netlink_ext_ack *extack) 655134ef238SVladimir Oltean { 656134ef238SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 657134ef238SVladimir Oltean struct switchdev_obj_port_vlan vlan; 658134ef238SVladimir Oltean 659164f861bSVladimir Oltean /* Do nothing if this is a software bridge */ 660164f861bSVladimir Oltean if (!dp->bridge) 661164f861bSVladimir Oltean return -EOPNOTSUPP; 662164f861bSVladimir Oltean 663134ef238SVladimir Oltean if (dsa_port_skip_vlan_configuration(dp)) { 664134ef238SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); 665134ef238SVladimir Oltean return 0; 666134ef238SVladimir Oltean } 667134ef238SVladimir Oltean 668134ef238SVladimir Oltean vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); 669134ef238SVladimir Oltean 670134ef238SVladimir Oltean /* Even though drivers often handle CPU membership in special ways, 671b9499904SVivien Didelot * it doesn't make sense to program a PVID, so clear this flag. 672b9499904SVivien Didelot */ 673b9499904SVivien Didelot vlan.flags &= ~BRIDGE_VLAN_INFO_PVID; 674b9499904SVivien Didelot 675134ef238SVladimir Oltean return dsa_port_host_vlan_add(dp, &vlan, extack); 676bdcff080SVivien Didelot } 677bdcff080SVivien Didelot 67869bfac96SVladimir Oltean static int dsa_slave_port_obj_add(struct net_device *dev, const void *ctx, 679648b4a99SJiri Pirko const struct switchdev_obj *obj, 68079b139f4SVivien Didelot struct netlink_ext_ack *extack) 681ba14d9ebSVivien Didelot { 682d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 683ba14d9ebSVivien Didelot int err; 684ba14d9ebSVivien Didelot 6850d2cfbd4SVladimir Oltean if (ctx && ctx != dp) 6860d2cfbd4SVladimir Oltean return 0; 6870d2cfbd4SVladimir Oltean 6889e8f4a54SJiri Pirko switch (obj->id) { 6898df30255SVivien Didelot case SWITCHDEV_OBJ_ID_PORT_MDB: 69003cbb870SVladimir Oltean if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) 69179b139f4SVivien Didelot return -EOPNOTSUPP; 69203cbb870SVladimir Oltean 693ffb68fc5SVladimir Oltean err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); 6948df30255SVivien Didelot break; 6955f4dbc50SAndrew Lunn case SWITCHDEV_OBJ_ID_HOST_MDB: 696936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 69703cbb870SVladimir Oltean return -EOPNOTSUPP; 69803cbb870SVladimir Oltean 69968d6d71eSVladimir Oltean err = dsa_port_bridge_host_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); 7005f4dbc50SAndrew Lunn break; 70157d80838SJiri Pirko case SWITCHDEV_OBJ_ID_PORT_VLAN: 702164f861bSVladimir Oltean if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) 7030ee2af4eSVladimir Oltean err = dsa_slave_vlan_add(dev, obj, extack); 704164f861bSVladimir Oltean else 705164f861bSVladimir Oltean err = dsa_slave_host_vlan_add(dev, obj, extack); 70611149536SVivien Didelot break; 707c595c433SHoratiu Vultur case SWITCHDEV_OBJ_ID_MRP: 708936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 709c595c433SHoratiu Vultur return -EOPNOTSUPP; 71003cbb870SVladimir Oltean 711c595c433SHoratiu Vultur err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj)); 712c595c433SHoratiu Vultur break; 713c595c433SHoratiu Vultur case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: 714936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 715c595c433SHoratiu Vultur return -EOPNOTSUPP; 71603cbb870SVladimir Oltean 717c595c433SHoratiu Vultur err = dsa_port_mrp_add_ring_role(dp, 718c595c433SHoratiu Vultur SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); 719c595c433SHoratiu Vultur break; 720ba14d9ebSVivien Didelot default: 721ba14d9ebSVivien Didelot err = -EOPNOTSUPP; 722ba14d9ebSVivien Didelot break; 723ba14d9ebSVivien Didelot } 724ba14d9ebSVivien Didelot 725ba14d9ebSVivien Didelot return err; 726ba14d9ebSVivien Didelot } 727ba14d9ebSVivien Didelot 728bdcff080SVivien Didelot static int dsa_slave_vlan_del(struct net_device *dev, 729bdcff080SVivien Didelot const struct switchdev_obj *obj) 730bdcff080SVivien Didelot { 731bdcff080SVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 7322209158cSVladimir Oltean struct switchdev_obj_port_vlan *vlan; 733bdcff080SVivien Didelot 73454a0ed0dSRussell King if (dsa_port_skip_vlan_configuration(dp)) 735c5335d73SVivien Didelot return 0; 736c5335d73SVivien Didelot 7372209158cSVladimir Oltean vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 7382209158cSVladimir Oltean 739134ef238SVladimir Oltean return dsa_port_vlan_del(dp, vlan); 740134ef238SVladimir Oltean } 7412209158cSVladimir Oltean 742134ef238SVladimir Oltean static int dsa_slave_host_vlan_del(struct net_device *dev, 743134ef238SVladimir Oltean const struct switchdev_obj *obj) 744134ef238SVladimir Oltean { 745134ef238SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 746134ef238SVladimir Oltean struct switchdev_obj_port_vlan *vlan; 7472209158cSVladimir Oltean 748164f861bSVladimir Oltean /* Do nothing if this is a software bridge */ 749164f861bSVladimir Oltean if (!dp->bridge) 750164f861bSVladimir Oltean return -EOPNOTSUPP; 751164f861bSVladimir Oltean 752134ef238SVladimir Oltean if (dsa_port_skip_vlan_configuration(dp)) 7532209158cSVladimir Oltean return 0; 754134ef238SVladimir Oltean 755134ef238SVladimir Oltean vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 756134ef238SVladimir Oltean 757134ef238SVladimir Oltean return dsa_port_host_vlan_del(dp, vlan); 758bdcff080SVivien Didelot } 759bdcff080SVivien Didelot 76069bfac96SVladimir Oltean static int dsa_slave_port_obj_del(struct net_device *dev, const void *ctx, 761648b4a99SJiri Pirko const struct switchdev_obj *obj) 762ba14d9ebSVivien Didelot { 763d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 764ba14d9ebSVivien Didelot int err; 765ba14d9ebSVivien Didelot 7660d2cfbd4SVladimir Oltean if (ctx && ctx != dp) 7670d2cfbd4SVladimir Oltean return 0; 7680d2cfbd4SVladimir Oltean 7699e8f4a54SJiri Pirko switch (obj->id) { 7708df30255SVivien Didelot case SWITCHDEV_OBJ_ID_PORT_MDB: 77103cbb870SVladimir Oltean if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) 77279b139f4SVivien Didelot return -EOPNOTSUPP; 77303cbb870SVladimir Oltean 774bcebb976SVivien Didelot err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); 7758df30255SVivien Didelot break; 7765f4dbc50SAndrew Lunn case SWITCHDEV_OBJ_ID_HOST_MDB: 777936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 77803cbb870SVladimir Oltean return -EOPNOTSUPP; 77903cbb870SVladimir Oltean 78068d6d71eSVladimir Oltean err = dsa_port_bridge_host_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); 7815f4dbc50SAndrew Lunn break; 78257d80838SJiri Pirko case SWITCHDEV_OBJ_ID_PORT_VLAN: 783164f861bSVladimir Oltean if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) 784bdcff080SVivien Didelot err = dsa_slave_vlan_del(dev, obj); 785164f861bSVladimir Oltean else 786164f861bSVladimir Oltean err = dsa_slave_host_vlan_del(dev, obj); 78711149536SVivien Didelot break; 788c595c433SHoratiu Vultur case SWITCHDEV_OBJ_ID_MRP: 789936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 790c595c433SHoratiu Vultur return -EOPNOTSUPP; 79103cbb870SVladimir Oltean 792c595c433SHoratiu Vultur err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj)); 793c595c433SHoratiu Vultur break; 794c595c433SHoratiu Vultur case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: 795936db8a2SVladimir Oltean if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) 796c595c433SHoratiu Vultur return -EOPNOTSUPP; 79703cbb870SVladimir Oltean 798c595c433SHoratiu Vultur err = dsa_port_mrp_del_ring_role(dp, 799c595c433SHoratiu Vultur SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); 800c595c433SHoratiu Vultur break; 801ba14d9ebSVivien Didelot default: 802ba14d9ebSVivien Didelot err = -EOPNOTSUPP; 803ba14d9ebSVivien Didelot break; 804ba14d9ebSVivien Didelot } 805ba14d9ebSVivien Didelot 806ba14d9ebSVivien Didelot return err; 807ba14d9ebSVivien Didelot } 808ba14d9ebSVivien Didelot 8094fa7b718SVivien Didelot static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev, 81004ff53f9SFlorian Fainelli struct sk_buff *skb) 81104ff53f9SFlorian Fainelli { 81204ff53f9SFlorian Fainelli #ifdef CONFIG_NET_POLL_CONTROLLER 8134fa7b718SVivien Didelot struct dsa_slave_priv *p = netdev_priv(dev); 8144fa7b718SVivien Didelot 815f78ed220SEric Dumazet return netpoll_send_skb(p->netpoll, skb); 81604ff53f9SFlorian Fainelli #else 81704ff53f9SFlorian Fainelli BUG(); 81804ff53f9SFlorian Fainelli return NETDEV_TX_OK; 819f78ed220SEric Dumazet #endif 82004ff53f9SFlorian Fainelli } 82104ff53f9SFlorian Fainelli 82290af1059SBrandon Streiff static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, 82390af1059SBrandon Streiff struct sk_buff *skb) 82490af1059SBrandon Streiff { 82590af1059SBrandon Streiff struct dsa_switch *ds = p->dp->ds; 82690af1059SBrandon Streiff 827cfd12c06SYangbo Lu if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 828cfd12c06SYangbo Lu return; 829cfd12c06SYangbo Lu 83090af1059SBrandon Streiff if (!ds->ops->port_txtstamp) 83190af1059SBrandon Streiff return; 83290af1059SBrandon Streiff 8335c5416f5SYangbo Lu ds->ops->port_txtstamp(ds, p->dp->index, skb); 83490af1059SBrandon Streiff } 83590af1059SBrandon Streiff 83697a69a0dSVladimir Oltean netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev) 83797a69a0dSVladimir Oltean { 83897a69a0dSVladimir Oltean /* SKB for netpoll still need to be mangled with the protocol-specific 83997a69a0dSVladimir Oltean * tag to be successfully transmitted 84097a69a0dSVladimir Oltean */ 84197a69a0dSVladimir Oltean if (unlikely(netpoll_tx_running(dev))) 84297a69a0dSVladimir Oltean return dsa_slave_netpoll_send_skb(dev, skb); 84397a69a0dSVladimir Oltean 84497a69a0dSVladimir Oltean /* Queue the SKB for transmission on the parent interface, but 84597a69a0dSVladimir Oltean * do not modify its EtherType 84697a69a0dSVladimir Oltean */ 84797a69a0dSVladimir Oltean skb->dev = dsa_slave_to_master(dev); 84897a69a0dSVladimir Oltean dev_queue_xmit(skb); 84997a69a0dSVladimir Oltean 85097a69a0dSVladimir Oltean return NETDEV_TX_OK; 85197a69a0dSVladimir Oltean } 85297a69a0dSVladimir Oltean EXPORT_SYMBOL_GPL(dsa_enqueue_skb); 85397a69a0dSVladimir Oltean 854a3b0b647SVladimir Oltean static int dsa_realloc_skb(struct sk_buff *skb, struct net_device *dev) 855a3b0b647SVladimir Oltean { 856a3b0b647SVladimir Oltean int needed_headroom = dev->needed_headroom; 857a3b0b647SVladimir Oltean int needed_tailroom = dev->needed_tailroom; 858a3b0b647SVladimir Oltean 859a3b0b647SVladimir Oltean /* For tail taggers, we need to pad short frames ourselves, to ensure 860a3b0b647SVladimir Oltean * that the tail tag does not fail at its role of being at the end of 861a3b0b647SVladimir Oltean * the packet, once the master interface pads the frame. Account for 862a3b0b647SVladimir Oltean * that pad length here, and pad later. 863a3b0b647SVladimir Oltean */ 864a3b0b647SVladimir Oltean if (unlikely(needed_tailroom && skb->len < ETH_ZLEN)) 865a3b0b647SVladimir Oltean needed_tailroom += ETH_ZLEN - skb->len; 866a3b0b647SVladimir Oltean /* skb_headroom() returns unsigned int... */ 867a3b0b647SVladimir Oltean needed_headroom = max_t(int, needed_headroom - skb_headroom(skb), 0); 868a3b0b647SVladimir Oltean needed_tailroom = max_t(int, needed_tailroom - skb_tailroom(skb), 0); 869a3b0b647SVladimir Oltean 870a3b0b647SVladimir Oltean if (likely(!needed_headroom && !needed_tailroom && !skb_cloned(skb))) 871a3b0b647SVladimir Oltean /* No reallocation needed, yay! */ 872a3b0b647SVladimir Oltean return 0; 873a3b0b647SVladimir Oltean 874a3b0b647SVladimir Oltean return pskb_expand_head(skb, needed_headroom, needed_tailroom, 875a3b0b647SVladimir Oltean GFP_ATOMIC); 876a3b0b647SVladimir Oltean } 877a3b0b647SVladimir Oltean 8783e8a72d1SFlorian Fainelli static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) 8793e8a72d1SFlorian Fainelli { 8803e8a72d1SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 8814ed70ce9SFlorian Fainelli struct sk_buff *nskb; 8823e8a72d1SFlorian Fainelli 8836a900628SHeiner Kallweit dev_sw_netstats_tx_add(dev, 1, skb->len); 8843e8a72d1SFlorian Fainelli 885c4b364ceSYangbo Lu memset(skb->cb, 0, sizeof(skb->cb)); 88687671375SVladimir Oltean 887cf536ea3SYangbo Lu /* Handle tx timestamp if any */ 88890af1059SBrandon Streiff dsa_skb_tx_timestamp(p, skb); 88990af1059SBrandon Streiff 890a3b0b647SVladimir Oltean if (dsa_realloc_skb(skb, dev)) { 891a3b0b647SVladimir Oltean dev_kfree_skb_any(skb); 892a3b0b647SVladimir Oltean return NETDEV_TX_OK; 893a3b0b647SVladimir Oltean } 894a3b0b647SVladimir Oltean 895a3b0b647SVladimir Oltean /* needed_tailroom should still be 'warm' in the cache line from 896a3b0b647SVladimir Oltean * dsa_realloc_skb(), which has also ensured that padding is safe. 897a3b0b647SVladimir Oltean */ 898a3b0b647SVladimir Oltean if (dev->needed_tailroom) 899a3b0b647SVladimir Oltean eth_skb_pad(skb); 900a3b0b647SVladimir Oltean 901fe47d563SVivien Didelot /* Transmit function may have to reallocate the original SKB, 902fe47d563SVivien Didelot * in which case it must have freed it. Only free it here on error. 903fe47d563SVivien Didelot */ 9044ed70ce9SFlorian Fainelli nskb = p->xmit(skb, dev); 905fe47d563SVivien Didelot if (!nskb) { 906fe47d563SVivien Didelot kfree_skb(skb); 9074ed70ce9SFlorian Fainelli return NETDEV_TX_OK; 908fe47d563SVivien Didelot } 9095aed85ceSFlorian Fainelli 91097a69a0dSVladimir Oltean return dsa_enqueue_skb(nskb, dev); 91197a69a0dSVladimir Oltean } 91204ff53f9SFlorian Fainelli 91391da11f8SLennert Buytenhek /* ethtool operations *******************************************************/ 91491da11f8SLennert Buytenhek 91591da11f8SLennert Buytenhek static void dsa_slave_get_drvinfo(struct net_device *dev, 91691da11f8SLennert Buytenhek struct ethtool_drvinfo *drvinfo) 91791da11f8SLennert Buytenhek { 918e4d44b3dSWolfram Sang strscpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); 919e4d44b3dSWolfram Sang strscpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); 920e4d44b3dSWolfram Sang strscpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); 92191da11f8SLennert Buytenhek } 92291da11f8SLennert Buytenhek 9233d762a0fSGuenter Roeck static int dsa_slave_get_regs_len(struct net_device *dev) 9243d762a0fSGuenter Roeck { 925d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 926d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 9273d762a0fSGuenter Roeck 9289d490b4eSVivien Didelot if (ds->ops->get_regs_len) 929d945097bSVivien Didelot return ds->ops->get_regs_len(ds, dp->index); 9303d762a0fSGuenter Roeck 9313d762a0fSGuenter Roeck return -EOPNOTSUPP; 9323d762a0fSGuenter Roeck } 9333d762a0fSGuenter Roeck 9343d762a0fSGuenter Roeck static void 9353d762a0fSGuenter Roeck dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) 9363d762a0fSGuenter Roeck { 937d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 938d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 9393d762a0fSGuenter Roeck 9409d490b4eSVivien Didelot if (ds->ops->get_regs) 941d945097bSVivien Didelot ds->ops->get_regs(ds, dp->index, regs, _p); 9423d762a0fSGuenter Roeck } 9433d762a0fSGuenter Roeck 944aab9c406SFlorian Fainelli static int dsa_slave_nway_reset(struct net_device *dev) 945aab9c406SFlorian Fainelli { 946aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 947aab9c406SFlorian Fainelli 948aab9c406SFlorian Fainelli return phylink_ethtool_nway_reset(dp->pl); 949aab9c406SFlorian Fainelli } 950aab9c406SFlorian Fainelli 9516793abb4SGuenter Roeck static int dsa_slave_get_eeprom_len(struct net_device *dev) 9526793abb4SGuenter Roeck { 953d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 954d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 9556793abb4SGuenter Roeck 9560e576044SAndrew Lunn if (ds->cd && ds->cd->eeprom_len) 957ff04955cSAndrew Lunn return ds->cd->eeprom_len; 9586793abb4SGuenter Roeck 9599d490b4eSVivien Didelot if (ds->ops->get_eeprom_len) 9609d490b4eSVivien Didelot return ds->ops->get_eeprom_len(ds); 9616793abb4SGuenter Roeck 9626793abb4SGuenter Roeck return 0; 9636793abb4SGuenter Roeck } 9646793abb4SGuenter Roeck 9656793abb4SGuenter Roeck static int dsa_slave_get_eeprom(struct net_device *dev, 9666793abb4SGuenter Roeck struct ethtool_eeprom *eeprom, u8 *data) 9676793abb4SGuenter Roeck { 968d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 969d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 9706793abb4SGuenter Roeck 9719d490b4eSVivien Didelot if (ds->ops->get_eeprom) 9729d490b4eSVivien Didelot return ds->ops->get_eeprom(ds, eeprom, data); 9736793abb4SGuenter Roeck 9746793abb4SGuenter Roeck return -EOPNOTSUPP; 9756793abb4SGuenter Roeck } 9766793abb4SGuenter Roeck 9776793abb4SGuenter Roeck static int dsa_slave_set_eeprom(struct net_device *dev, 9786793abb4SGuenter Roeck struct ethtool_eeprom *eeprom, u8 *data) 9796793abb4SGuenter Roeck { 980d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 981d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 9826793abb4SGuenter Roeck 9839d490b4eSVivien Didelot if (ds->ops->set_eeprom) 9849d490b4eSVivien Didelot return ds->ops->set_eeprom(ds, eeprom, data); 9856793abb4SGuenter Roeck 9866793abb4SGuenter Roeck return -EOPNOTSUPP; 9876793abb4SGuenter Roeck } 9886793abb4SGuenter Roeck 98991da11f8SLennert Buytenhek static void dsa_slave_get_strings(struct net_device *dev, 99091da11f8SLennert Buytenhek uint32_t stringset, uint8_t *data) 99191da11f8SLennert Buytenhek { 992d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 993d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 99491da11f8SLennert Buytenhek 99591da11f8SLennert Buytenhek if (stringset == ETH_SS_STATS) { 99691da11f8SLennert Buytenhek int len = ETH_GSTRING_LEN; 99791da11f8SLennert Buytenhek 99891da11f8SLennert Buytenhek strncpy(data, "tx_packets", len); 99991da11f8SLennert Buytenhek strncpy(data + len, "tx_bytes", len); 100091da11f8SLennert Buytenhek strncpy(data + 2 * len, "rx_packets", len); 100191da11f8SLennert Buytenhek strncpy(data + 3 * len, "rx_bytes", len); 10029d490b4eSVivien Didelot if (ds->ops->get_strings) 100389f09048SFlorian Fainelli ds->ops->get_strings(ds, dp->index, stringset, 100489f09048SFlorian Fainelli data + 4 * len); 1005a71acad9SOleksij Rempel } else if (stringset == ETH_SS_TEST) { 1006a71acad9SOleksij Rempel net_selftest_get_strings(data); 100791da11f8SLennert Buytenhek } 1008a71acad9SOleksij Rempel 100991da11f8SLennert Buytenhek } 101091da11f8SLennert Buytenhek 101191da11f8SLennert Buytenhek static void dsa_slave_get_ethtool_stats(struct net_device *dev, 101291da11f8SLennert Buytenhek struct ethtool_stats *stats, 101391da11f8SLennert Buytenhek uint64_t *data) 101491da11f8SLennert Buytenhek { 1015d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1016d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 10175f6b4e14SFlorian Fainelli struct pcpu_sw_netstats *s; 1018f613ed66SFlorian Fainelli unsigned int start; 10195f6b4e14SFlorian Fainelli int i; 102091da11f8SLennert Buytenhek 10215f6b4e14SFlorian Fainelli for_each_possible_cpu(i) { 10225f6b4e14SFlorian Fainelli u64 tx_packets, tx_bytes, rx_packets, rx_bytes; 10235f6b4e14SFlorian Fainelli 10246a900628SHeiner Kallweit s = per_cpu_ptr(dev->tstats, i); 1025f613ed66SFlorian Fainelli do { 1026d120d1a6SThomas Gleixner start = u64_stats_fetch_begin(&s->syncp); 10279962acefSEric Dumazet tx_packets = u64_stats_read(&s->tx_packets); 10289962acefSEric Dumazet tx_bytes = u64_stats_read(&s->tx_bytes); 10299962acefSEric Dumazet rx_packets = u64_stats_read(&s->rx_packets); 10309962acefSEric Dumazet rx_bytes = u64_stats_read(&s->rx_bytes); 1031d120d1a6SThomas Gleixner } while (u64_stats_fetch_retry(&s->syncp, start)); 10325f6b4e14SFlorian Fainelli data[0] += tx_packets; 10335f6b4e14SFlorian Fainelli data[1] += tx_bytes; 10345f6b4e14SFlorian Fainelli data[2] += rx_packets; 10355f6b4e14SFlorian Fainelli data[3] += rx_bytes; 10365f6b4e14SFlorian Fainelli } 10379d490b4eSVivien Didelot if (ds->ops->get_ethtool_stats) 1038d945097bSVivien Didelot ds->ops->get_ethtool_stats(ds, dp->index, data + 4); 103991da11f8SLennert Buytenhek } 104091da11f8SLennert Buytenhek 104191da11f8SLennert Buytenhek static int dsa_slave_get_sset_count(struct net_device *dev, int sset) 104291da11f8SLennert Buytenhek { 1043d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1044d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 104591da11f8SLennert Buytenhek 104691da11f8SLennert Buytenhek if (sset == ETH_SS_STATS) { 1047b94cbc90SVladimir Oltean int count = 0; 104891da11f8SLennert Buytenhek 1049b94cbc90SVladimir Oltean if (ds->ops->get_sset_count) { 1050b94cbc90SVladimir Oltean count = ds->ops->get_sset_count(ds, dp->index, sset); 1051b94cbc90SVladimir Oltean if (count < 0) 105291da11f8SLennert Buytenhek return count; 1053b94cbc90SVladimir Oltean } 1054b94cbc90SVladimir Oltean 1055b94cbc90SVladimir Oltean return count + 4; 1056a71acad9SOleksij Rempel } else if (sset == ETH_SS_TEST) { 1057a71acad9SOleksij Rempel return net_selftest_get_count(); 105891da11f8SLennert Buytenhek } 105991da11f8SLennert Buytenhek 106091da11f8SLennert Buytenhek return -EOPNOTSUPP; 106191da11f8SLennert Buytenhek } 106291da11f8SLennert Buytenhek 1063487d3855SAlvin Šipraga static void dsa_slave_get_eth_phy_stats(struct net_device *dev, 1064487d3855SAlvin Šipraga struct ethtool_eth_phy_stats *phy_stats) 1065487d3855SAlvin Šipraga { 1066487d3855SAlvin Šipraga struct dsa_port *dp = dsa_slave_to_port(dev); 1067487d3855SAlvin Šipraga struct dsa_switch *ds = dp->ds; 1068487d3855SAlvin Šipraga 1069487d3855SAlvin Šipraga if (ds->ops->get_eth_phy_stats) 1070487d3855SAlvin Šipraga ds->ops->get_eth_phy_stats(ds, dp->index, phy_stats); 1071487d3855SAlvin Šipraga } 1072487d3855SAlvin Šipraga 1073487d3855SAlvin Šipraga static void dsa_slave_get_eth_mac_stats(struct net_device *dev, 1074487d3855SAlvin Šipraga struct ethtool_eth_mac_stats *mac_stats) 1075487d3855SAlvin Šipraga { 1076487d3855SAlvin Šipraga struct dsa_port *dp = dsa_slave_to_port(dev); 1077487d3855SAlvin Šipraga struct dsa_switch *ds = dp->ds; 1078487d3855SAlvin Šipraga 1079487d3855SAlvin Šipraga if (ds->ops->get_eth_mac_stats) 1080487d3855SAlvin Šipraga ds->ops->get_eth_mac_stats(ds, dp->index, mac_stats); 1081487d3855SAlvin Šipraga } 1082487d3855SAlvin Šipraga 1083487d3855SAlvin Šipraga static void 1084487d3855SAlvin Šipraga dsa_slave_get_eth_ctrl_stats(struct net_device *dev, 1085487d3855SAlvin Šipraga struct ethtool_eth_ctrl_stats *ctrl_stats) 1086487d3855SAlvin Šipraga { 1087487d3855SAlvin Šipraga struct dsa_port *dp = dsa_slave_to_port(dev); 1088487d3855SAlvin Šipraga struct dsa_switch *ds = dp->ds; 1089487d3855SAlvin Šipraga 1090487d3855SAlvin Šipraga if (ds->ops->get_eth_ctrl_stats) 1091487d3855SAlvin Šipraga ds->ops->get_eth_ctrl_stats(ds, dp->index, ctrl_stats); 1092487d3855SAlvin Šipraga } 1093487d3855SAlvin Šipraga 109467f38b1cSClément Léger static void 109567f38b1cSClément Léger dsa_slave_get_rmon_stats(struct net_device *dev, 109667f38b1cSClément Léger struct ethtool_rmon_stats *rmon_stats, 109767f38b1cSClément Léger const struct ethtool_rmon_hist_range **ranges) 109867f38b1cSClément Léger { 109967f38b1cSClément Léger struct dsa_port *dp = dsa_slave_to_port(dev); 110067f38b1cSClément Léger struct dsa_switch *ds = dp->ds; 110167f38b1cSClément Léger 110267f38b1cSClément Léger if (ds->ops->get_rmon_stats) 110367f38b1cSClément Léger ds->ops->get_rmon_stats(ds, dp->index, rmon_stats, ranges); 110467f38b1cSClément Léger } 110567f38b1cSClément Léger 1106a71acad9SOleksij Rempel static void dsa_slave_net_selftest(struct net_device *ndev, 1107a71acad9SOleksij Rempel struct ethtool_test *etest, u64 *buf) 1108a71acad9SOleksij Rempel { 1109a71acad9SOleksij Rempel struct dsa_port *dp = dsa_slave_to_port(ndev); 1110a71acad9SOleksij Rempel struct dsa_switch *ds = dp->ds; 1111a71acad9SOleksij Rempel 1112a71acad9SOleksij Rempel if (ds->ops->self_test) { 1113a71acad9SOleksij Rempel ds->ops->self_test(ds, dp->index, etest, buf); 1114a71acad9SOleksij Rempel return; 1115a71acad9SOleksij Rempel } 1116a71acad9SOleksij Rempel 1117a71acad9SOleksij Rempel net_selftest(ndev, etest, buf); 1118a71acad9SOleksij Rempel } 1119a71acad9SOleksij Rempel 11205f6c2d49SVladimir Oltean static int dsa_slave_get_mm(struct net_device *dev, 11215f6c2d49SVladimir Oltean struct ethtool_mm_state *state) 11225f6c2d49SVladimir Oltean { 11235f6c2d49SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 11245f6c2d49SVladimir Oltean struct dsa_switch *ds = dp->ds; 11255f6c2d49SVladimir Oltean 11265f6c2d49SVladimir Oltean if (!ds->ops->get_mm) 11275f6c2d49SVladimir Oltean return -EOPNOTSUPP; 11285f6c2d49SVladimir Oltean 11295f6c2d49SVladimir Oltean return ds->ops->get_mm(ds, dp->index, state); 11305f6c2d49SVladimir Oltean } 11315f6c2d49SVladimir Oltean 11325f6c2d49SVladimir Oltean static int dsa_slave_set_mm(struct net_device *dev, struct ethtool_mm_cfg *cfg, 11335f6c2d49SVladimir Oltean struct netlink_ext_ack *extack) 11345f6c2d49SVladimir Oltean { 11355f6c2d49SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 11365f6c2d49SVladimir Oltean struct dsa_switch *ds = dp->ds; 11375f6c2d49SVladimir Oltean 11385f6c2d49SVladimir Oltean if (!ds->ops->set_mm) 11395f6c2d49SVladimir Oltean return -EOPNOTSUPP; 11405f6c2d49SVladimir Oltean 11415f6c2d49SVladimir Oltean return ds->ops->set_mm(ds, dp->index, cfg, extack); 11425f6c2d49SVladimir Oltean } 11435f6c2d49SVladimir Oltean 11445f6c2d49SVladimir Oltean static void dsa_slave_get_mm_stats(struct net_device *dev, 11455f6c2d49SVladimir Oltean struct ethtool_mm_stats *stats) 11465f6c2d49SVladimir Oltean { 11475f6c2d49SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 11485f6c2d49SVladimir Oltean struct dsa_switch *ds = dp->ds; 11495f6c2d49SVladimir Oltean 11505f6c2d49SVladimir Oltean if (ds->ops->get_mm_stats) 11515f6c2d49SVladimir Oltean ds->ops->get_mm_stats(ds, dp->index, stats); 11525f6c2d49SVladimir Oltean } 11535f6c2d49SVladimir Oltean 115419e57c4eSFlorian Fainelli static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) 115519e57c4eSFlorian Fainelli { 1156d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1157d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 115819e57c4eSFlorian Fainelli 1159aab9c406SFlorian Fainelli phylink_ethtool_get_wol(dp->pl, w); 1160aab9c406SFlorian Fainelli 11619d490b4eSVivien Didelot if (ds->ops->get_wol) 1162d945097bSVivien Didelot ds->ops->get_wol(ds, dp->index, w); 116319e57c4eSFlorian Fainelli } 116419e57c4eSFlorian Fainelli 116519e57c4eSFlorian Fainelli static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) 116619e57c4eSFlorian Fainelli { 1167d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1168d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 116919e57c4eSFlorian Fainelli int ret = -EOPNOTSUPP; 117019e57c4eSFlorian Fainelli 1171aab9c406SFlorian Fainelli phylink_ethtool_set_wol(dp->pl, w); 1172aab9c406SFlorian Fainelli 11739d490b4eSVivien Didelot if (ds->ops->set_wol) 1174d945097bSVivien Didelot ret = ds->ops->set_wol(ds, dp->index, w); 117519e57c4eSFlorian Fainelli 117619e57c4eSFlorian Fainelli return ret; 117719e57c4eSFlorian Fainelli } 117819e57c4eSFlorian Fainelli 11797905288fSFlorian Fainelli static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) 11807905288fSFlorian Fainelli { 1181d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1182d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 11837905288fSFlorian Fainelli int ret; 11847905288fSFlorian Fainelli 11857b9cc738SVivien Didelot /* Port's PHY and MAC both need to be EEE capable */ 118600670cb8SDan Carpenter if (!dev->phydev || !dp->pl) 11877b9cc738SVivien Didelot return -ENODEV; 11887b9cc738SVivien Didelot 118908f50061SVivien Didelot if (!ds->ops->set_mac_eee) 11907905288fSFlorian Fainelli return -EOPNOTSUPP; 11917905288fSFlorian Fainelli 1192d945097bSVivien Didelot ret = ds->ops->set_mac_eee(ds, dp->index, e); 11937905288fSFlorian Fainelli if (ret) 11947905288fSFlorian Fainelli return ret; 11957905288fSFlorian Fainelli 1196aab9c406SFlorian Fainelli return phylink_ethtool_set_eee(dp->pl, e); 11977905288fSFlorian Fainelli } 11987905288fSFlorian Fainelli 11997905288fSFlorian Fainelli static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) 12007905288fSFlorian Fainelli { 1201d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1202d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 12037905288fSFlorian Fainelli int ret; 12047905288fSFlorian Fainelli 12057b9cc738SVivien Didelot /* Port's PHY and MAC both need to be EEE capable */ 120600670cb8SDan Carpenter if (!dev->phydev || !dp->pl) 12077b9cc738SVivien Didelot return -ENODEV; 12087b9cc738SVivien Didelot 120908f50061SVivien Didelot if (!ds->ops->get_mac_eee) 12107905288fSFlorian Fainelli return -EOPNOTSUPP; 12117905288fSFlorian Fainelli 1212d945097bSVivien Didelot ret = ds->ops->get_mac_eee(ds, dp->index, e); 12137905288fSFlorian Fainelli if (ret) 12147905288fSFlorian Fainelli return ret; 12157905288fSFlorian Fainelli 1216aab9c406SFlorian Fainelli return phylink_ethtool_get_eee(dp->pl, e); 1217aab9c406SFlorian Fainelli } 1218aab9c406SFlorian Fainelli 1219aab9c406SFlorian Fainelli static int dsa_slave_get_link_ksettings(struct net_device *dev, 1220aab9c406SFlorian Fainelli struct ethtool_link_ksettings *cmd) 1221aab9c406SFlorian Fainelli { 1222aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 1223aab9c406SFlorian Fainelli 1224aab9c406SFlorian Fainelli return phylink_ethtool_ksettings_get(dp->pl, cmd); 1225aab9c406SFlorian Fainelli } 1226aab9c406SFlorian Fainelli 1227aab9c406SFlorian Fainelli static int dsa_slave_set_link_ksettings(struct net_device *dev, 1228aab9c406SFlorian Fainelli const struct ethtool_link_ksettings *cmd) 1229aab9c406SFlorian Fainelli { 1230aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 1231aab9c406SFlorian Fainelli 1232aab9c406SFlorian Fainelli return phylink_ethtool_ksettings_set(dp->pl, cmd); 12337905288fSFlorian Fainelli } 12347905288fSFlorian Fainelli 12353d410403SOleksij Rempel static void dsa_slave_get_pause_stats(struct net_device *dev, 12363d410403SOleksij Rempel struct ethtool_pause_stats *pause_stats) 12373d410403SOleksij Rempel { 12383d410403SOleksij Rempel struct dsa_port *dp = dsa_slave_to_port(dev); 12393d410403SOleksij Rempel struct dsa_switch *ds = dp->ds; 12403d410403SOleksij Rempel 12413d410403SOleksij Rempel if (ds->ops->get_pause_stats) 12423d410403SOleksij Rempel ds->ops->get_pause_stats(ds, dp->index, pause_stats); 12433d410403SOleksij Rempel } 12443d410403SOleksij Rempel 1245a2a1a13bSHeiner Kallweit static void dsa_slave_get_pauseparam(struct net_device *dev, 1246a2a1a13bSHeiner Kallweit struct ethtool_pauseparam *pause) 1247a2a1a13bSHeiner Kallweit { 1248a2a1a13bSHeiner Kallweit struct dsa_port *dp = dsa_slave_to_port(dev); 1249a2a1a13bSHeiner Kallweit 1250a2a1a13bSHeiner Kallweit phylink_ethtool_get_pauseparam(dp->pl, pause); 1251a2a1a13bSHeiner Kallweit } 1252a2a1a13bSHeiner Kallweit 1253a2a1a13bSHeiner Kallweit static int dsa_slave_set_pauseparam(struct net_device *dev, 1254a2a1a13bSHeiner Kallweit struct ethtool_pauseparam *pause) 1255a2a1a13bSHeiner Kallweit { 1256a2a1a13bSHeiner Kallweit struct dsa_port *dp = dsa_slave_to_port(dev); 1257a2a1a13bSHeiner Kallweit 1258a2a1a13bSHeiner Kallweit return phylink_ethtool_set_pauseparam(dp->pl, pause); 1259a2a1a13bSHeiner Kallweit } 1260a2a1a13bSHeiner Kallweit 126104ff53f9SFlorian Fainelli #ifdef CONFIG_NET_POLL_CONTROLLER 126204ff53f9SFlorian Fainelli static int dsa_slave_netpoll_setup(struct net_device *dev, 126304ff53f9SFlorian Fainelli struct netpoll_info *ni) 126404ff53f9SFlorian Fainelli { 1265d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 126604ff53f9SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 126704ff53f9SFlorian Fainelli struct netpoll *netpoll; 126804ff53f9SFlorian Fainelli int err = 0; 126904ff53f9SFlorian Fainelli 127004ff53f9SFlorian Fainelli netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); 127104ff53f9SFlorian Fainelli if (!netpoll) 127204ff53f9SFlorian Fainelli return -ENOMEM; 127304ff53f9SFlorian Fainelli 127404ff53f9SFlorian Fainelli err = __netpoll_setup(netpoll, master); 127504ff53f9SFlorian Fainelli if (err) { 127604ff53f9SFlorian Fainelli kfree(netpoll); 127704ff53f9SFlorian Fainelli goto out; 127804ff53f9SFlorian Fainelli } 127904ff53f9SFlorian Fainelli 128004ff53f9SFlorian Fainelli p->netpoll = netpoll; 128104ff53f9SFlorian Fainelli out: 128204ff53f9SFlorian Fainelli return err; 128304ff53f9SFlorian Fainelli } 128404ff53f9SFlorian Fainelli 128504ff53f9SFlorian Fainelli static void dsa_slave_netpoll_cleanup(struct net_device *dev) 128604ff53f9SFlorian Fainelli { 128704ff53f9SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 128804ff53f9SFlorian Fainelli struct netpoll *netpoll = p->netpoll; 128904ff53f9SFlorian Fainelli 129004ff53f9SFlorian Fainelli if (!netpoll) 129104ff53f9SFlorian Fainelli return; 129204ff53f9SFlorian Fainelli 129304ff53f9SFlorian Fainelli p->netpoll = NULL; 129404ff53f9SFlorian Fainelli 1295c9fbd71fSDebabrata Banerjee __netpoll_free(netpoll); 129604ff53f9SFlorian Fainelli } 129704ff53f9SFlorian Fainelli 129804ff53f9SFlorian Fainelli static void dsa_slave_poll_controller(struct net_device *dev) 129904ff53f9SFlorian Fainelli { 130004ff53f9SFlorian Fainelli } 130104ff53f9SFlorian Fainelli #endif 130204ff53f9SFlorian Fainelli 1303f50f2127SFlorian Fainelli static struct dsa_mall_tc_entry * 13044fa7b718SVivien Didelot dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie) 1305f50f2127SFlorian Fainelli { 13064fa7b718SVivien Didelot struct dsa_slave_priv *p = netdev_priv(dev); 1307f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1308f50f2127SFlorian Fainelli 1309f50f2127SFlorian Fainelli list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) 1310f50f2127SFlorian Fainelli if (mall_tc_entry->cookie == cookie) 1311f50f2127SFlorian Fainelli return mall_tc_entry; 1312f50f2127SFlorian Fainelli 1313f50f2127SFlorian Fainelli return NULL; 1314f50f2127SFlorian Fainelli } 1315f50f2127SFlorian Fainelli 1316e13c2075SVladimir Oltean static int 1317e13c2075SVladimir Oltean dsa_slave_add_cls_matchall_mirred(struct net_device *dev, 1318f50f2127SFlorian Fainelli struct tc_cls_matchall_offload *cls, 1319f50f2127SFlorian Fainelli bool ingress) 1320f50f2127SFlorian Fainelli { 13210148bb50SVladimir Oltean struct netlink_ext_ack *extack = cls->common.extack; 1322d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1323f50f2127SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 1324e13c2075SVladimir Oltean struct dsa_mall_mirror_tc_entry *mirror; 1325f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1326d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 13279681e8b3SPieter Jansen van Vuuren struct flow_action_entry *act; 1328d945097bSVivien Didelot struct dsa_port *to_dp; 1329e13c2075SVladimir Oltean int err; 1330e13c2075SVladimir Oltean 1331f50f2127SFlorian Fainelli if (!ds->ops->port_mirror_add) 133234297176SVladimir Oltean return -EOPNOTSUPP; 1333f50f2127SFlorian Fainelli 133453eca1f3SJakub Kicinski if (!flow_action_basic_hw_stats_check(&cls->rule->action, 1335319a1d19SJiri Pirko cls->common.extack)) 133634297176SVladimir Oltean return -EOPNOTSUPP; 1337319a1d19SJiri Pirko 13389681e8b3SPieter Jansen van Vuuren act = &cls->rule->action.entries[0]; 1339f50f2127SFlorian Fainelli 134065722159SVladimir Oltean if (!act->dev) 134165722159SVladimir Oltean return -EINVAL; 134265722159SVladimir Oltean 13439681e8b3SPieter Jansen van Vuuren if (!dsa_slave_dev_check(act->dev)) 1344f50f2127SFlorian Fainelli return -EOPNOTSUPP; 1345f50f2127SFlorian Fainelli 1346f50f2127SFlorian Fainelli mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); 1347f50f2127SFlorian Fainelli if (!mall_tc_entry) 1348f50f2127SFlorian Fainelli return -ENOMEM; 1349f50f2127SFlorian Fainelli 1350f50f2127SFlorian Fainelli mall_tc_entry->cookie = cls->cookie; 1351f50f2127SFlorian Fainelli mall_tc_entry->type = DSA_PORT_MALL_MIRROR; 1352f50f2127SFlorian Fainelli mirror = &mall_tc_entry->mirror; 1353f50f2127SFlorian Fainelli 13549681e8b3SPieter Jansen van Vuuren to_dp = dsa_slave_to_port(act->dev); 1355f50f2127SFlorian Fainelli 1356d945097bSVivien Didelot mirror->to_local_port = to_dp->index; 1357f50f2127SFlorian Fainelli mirror->ingress = ingress; 1358f50f2127SFlorian Fainelli 13590148bb50SVladimir Oltean err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack); 1360f50f2127SFlorian Fainelli if (err) { 1361f50f2127SFlorian Fainelli kfree(mall_tc_entry); 1362f50f2127SFlorian Fainelli return err; 1363f50f2127SFlorian Fainelli } 1364f50f2127SFlorian Fainelli 1365f50f2127SFlorian Fainelli list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); 1366e13c2075SVladimir Oltean 1367e13c2075SVladimir Oltean return err; 1368f50f2127SFlorian Fainelli } 1369f50f2127SFlorian Fainelli 137034297176SVladimir Oltean static int 137134297176SVladimir Oltean dsa_slave_add_cls_matchall_police(struct net_device *dev, 137234297176SVladimir Oltean struct tc_cls_matchall_offload *cls, 137334297176SVladimir Oltean bool ingress) 137434297176SVladimir Oltean { 137534297176SVladimir Oltean struct netlink_ext_ack *extack = cls->common.extack; 137634297176SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 137734297176SVladimir Oltean struct dsa_slave_priv *p = netdev_priv(dev); 137834297176SVladimir Oltean struct dsa_mall_policer_tc_entry *policer; 137934297176SVladimir Oltean struct dsa_mall_tc_entry *mall_tc_entry; 138034297176SVladimir Oltean struct dsa_switch *ds = dp->ds; 138134297176SVladimir Oltean struct flow_action_entry *act; 138234297176SVladimir Oltean int err; 138334297176SVladimir Oltean 138434297176SVladimir Oltean if (!ds->ops->port_policer_add) { 138534297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1386c75a33c8SJacob Keller "Policing offload not implemented"); 138734297176SVladimir Oltean return -EOPNOTSUPP; 138834297176SVladimir Oltean } 138934297176SVladimir Oltean 139034297176SVladimir Oltean if (!ingress) { 139134297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1392c75a33c8SJacob Keller "Only supported on ingress qdisc"); 139334297176SVladimir Oltean return -EOPNOTSUPP; 139434297176SVladimir Oltean } 139534297176SVladimir Oltean 139634297176SVladimir Oltean if (!flow_action_basic_hw_stats_check(&cls->rule->action, 139734297176SVladimir Oltean cls->common.extack)) 139834297176SVladimir Oltean return -EOPNOTSUPP; 139934297176SVladimir Oltean 140034297176SVladimir Oltean list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) { 140134297176SVladimir Oltean if (mall_tc_entry->type == DSA_PORT_MALL_POLICER) { 140234297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1403c75a33c8SJacob Keller "Only one port policer allowed"); 140434297176SVladimir Oltean return -EEXIST; 140534297176SVladimir Oltean } 140634297176SVladimir Oltean } 140734297176SVladimir Oltean 140834297176SVladimir Oltean act = &cls->rule->action.entries[0]; 140934297176SVladimir Oltean 141034297176SVladimir Oltean mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); 141134297176SVladimir Oltean if (!mall_tc_entry) 141234297176SVladimir Oltean return -ENOMEM; 141334297176SVladimir Oltean 141434297176SVladimir Oltean mall_tc_entry->cookie = cls->cookie; 141534297176SVladimir Oltean mall_tc_entry->type = DSA_PORT_MALL_POLICER; 141634297176SVladimir Oltean policer = &mall_tc_entry->policer; 141734297176SVladimir Oltean policer->rate_bytes_per_sec = act->police.rate_bytes_ps; 141834297176SVladimir Oltean policer->burst = act->police.burst; 141934297176SVladimir Oltean 142034297176SVladimir Oltean err = ds->ops->port_policer_add(ds, dp->index, policer); 142134297176SVladimir Oltean if (err) { 142234297176SVladimir Oltean kfree(mall_tc_entry); 142334297176SVladimir Oltean return err; 142434297176SVladimir Oltean } 142534297176SVladimir Oltean 142634297176SVladimir Oltean list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); 142734297176SVladimir Oltean 142834297176SVladimir Oltean return err; 142934297176SVladimir Oltean } 143034297176SVladimir Oltean 1431e13c2075SVladimir Oltean static int dsa_slave_add_cls_matchall(struct net_device *dev, 1432e13c2075SVladimir Oltean struct tc_cls_matchall_offload *cls, 1433e13c2075SVladimir Oltean bool ingress) 1434e13c2075SVladimir Oltean { 1435e13c2075SVladimir Oltean int err = -EOPNOTSUPP; 1436e13c2075SVladimir Oltean 1437e13c2075SVladimir Oltean if (cls->common.protocol == htons(ETH_P_ALL) && 1438e13c2075SVladimir Oltean flow_offload_has_one_action(&cls->rule->action) && 1439e13c2075SVladimir Oltean cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED) 1440e13c2075SVladimir Oltean err = dsa_slave_add_cls_matchall_mirred(dev, cls, ingress); 144134297176SVladimir Oltean else if (flow_offload_has_one_action(&cls->rule->action) && 144234297176SVladimir Oltean cls->rule->action.entries[0].id == FLOW_ACTION_POLICE) 144334297176SVladimir Oltean err = dsa_slave_add_cls_matchall_police(dev, cls, ingress); 1444e13c2075SVladimir Oltean 1445e13c2075SVladimir Oltean return err; 1446f50f2127SFlorian Fainelli } 1447f50f2127SFlorian Fainelli 1448f50f2127SFlorian Fainelli static void dsa_slave_del_cls_matchall(struct net_device *dev, 1449f50f2127SFlorian Fainelli struct tc_cls_matchall_offload *cls) 1450f50f2127SFlorian Fainelli { 1451d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1452f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1453d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1454f50f2127SFlorian Fainelli 14554fa7b718SVivien Didelot mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie); 1456f50f2127SFlorian Fainelli if (!mall_tc_entry) 1457f50f2127SFlorian Fainelli return; 1458f50f2127SFlorian Fainelli 1459f50f2127SFlorian Fainelli list_del(&mall_tc_entry->list); 1460f50f2127SFlorian Fainelli 1461f50f2127SFlorian Fainelli switch (mall_tc_entry->type) { 1462f50f2127SFlorian Fainelli case DSA_PORT_MALL_MIRROR: 146334297176SVladimir Oltean if (ds->ops->port_mirror_del) 146434297176SVladimir Oltean ds->ops->port_mirror_del(ds, dp->index, 146534297176SVladimir Oltean &mall_tc_entry->mirror); 146634297176SVladimir Oltean break; 146734297176SVladimir Oltean case DSA_PORT_MALL_POLICER: 146834297176SVladimir Oltean if (ds->ops->port_policer_del) 146934297176SVladimir Oltean ds->ops->port_policer_del(ds, dp->index); 1470f50f2127SFlorian Fainelli break; 1471f50f2127SFlorian Fainelli default: 1472f50f2127SFlorian Fainelli WARN_ON(1); 1473f50f2127SFlorian Fainelli } 1474f50f2127SFlorian Fainelli 1475f50f2127SFlorian Fainelli kfree(mall_tc_entry); 1476f50f2127SFlorian Fainelli } 1477f50f2127SFlorian Fainelli 14783fbae382SJiri Pirko static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev, 14796b3eb752SJiri Pirko struct tc_cls_matchall_offload *cls, 14806b3eb752SJiri Pirko bool ingress) 1481f50f2127SFlorian Fainelli { 14825fd9fc4eSJiri Pirko if (cls->common.chain_index) 1483a5fcf8a6SJiri Pirko return -EOPNOTSUPP; 1484f50f2127SFlorian Fainelli 14853fbae382SJiri Pirko switch (cls->command) { 14863fbae382SJiri Pirko case TC_CLSMATCHALL_REPLACE: 14875fd9fc4eSJiri Pirko return dsa_slave_add_cls_matchall(dev, cls, ingress); 14883fbae382SJiri Pirko case TC_CLSMATCHALL_DESTROY: 14893fbae382SJiri Pirko dsa_slave_del_cls_matchall(dev, cls); 14903fbae382SJiri Pirko return 0; 14913fbae382SJiri Pirko default: 14923fbae382SJiri Pirko return -EOPNOTSUPP; 14933fbae382SJiri Pirko } 14943fbae382SJiri Pirko } 14953fbae382SJiri Pirko 1496ed11bb1fSVladimir Oltean static int dsa_slave_add_cls_flower(struct net_device *dev, 1497ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1498ed11bb1fSVladimir Oltean bool ingress) 1499ed11bb1fSVladimir Oltean { 1500ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1501ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1502ed11bb1fSVladimir Oltean int port = dp->index; 1503ed11bb1fSVladimir Oltean 1504ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_add) 1505ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1506ed11bb1fSVladimir Oltean 1507ed11bb1fSVladimir Oltean return ds->ops->cls_flower_add(ds, port, cls, ingress); 1508ed11bb1fSVladimir Oltean } 1509ed11bb1fSVladimir Oltean 1510ed11bb1fSVladimir Oltean static int dsa_slave_del_cls_flower(struct net_device *dev, 1511ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1512ed11bb1fSVladimir Oltean bool ingress) 1513ed11bb1fSVladimir Oltean { 1514ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1515ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1516ed11bb1fSVladimir Oltean int port = dp->index; 1517ed11bb1fSVladimir Oltean 1518ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_del) 1519ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1520ed11bb1fSVladimir Oltean 1521ed11bb1fSVladimir Oltean return ds->ops->cls_flower_del(ds, port, cls, ingress); 1522ed11bb1fSVladimir Oltean } 1523ed11bb1fSVladimir Oltean 1524ed11bb1fSVladimir Oltean static int dsa_slave_stats_cls_flower(struct net_device *dev, 1525ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1526ed11bb1fSVladimir Oltean bool ingress) 1527ed11bb1fSVladimir Oltean { 1528ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1529ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1530ed11bb1fSVladimir Oltean int port = dp->index; 1531ed11bb1fSVladimir Oltean 1532ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_stats) 1533ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1534ed11bb1fSVladimir Oltean 1535ed11bb1fSVladimir Oltean return ds->ops->cls_flower_stats(ds, port, cls, ingress); 1536ed11bb1fSVladimir Oltean } 1537ed11bb1fSVladimir Oltean 1538ed11bb1fSVladimir Oltean static int dsa_slave_setup_tc_cls_flower(struct net_device *dev, 1539ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1540ed11bb1fSVladimir Oltean bool ingress) 1541ed11bb1fSVladimir Oltean { 1542ed11bb1fSVladimir Oltean switch (cls->command) { 1543ed11bb1fSVladimir Oltean case FLOW_CLS_REPLACE: 1544ed11bb1fSVladimir Oltean return dsa_slave_add_cls_flower(dev, cls, ingress); 1545ed11bb1fSVladimir Oltean case FLOW_CLS_DESTROY: 1546ed11bb1fSVladimir Oltean return dsa_slave_del_cls_flower(dev, cls, ingress); 1547ed11bb1fSVladimir Oltean case FLOW_CLS_STATS: 1548ed11bb1fSVladimir Oltean return dsa_slave_stats_cls_flower(dev, cls, ingress); 1549ed11bb1fSVladimir Oltean default: 1550ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1551ed11bb1fSVladimir Oltean } 1552ed11bb1fSVladimir Oltean } 1553ed11bb1fSVladimir Oltean 15546b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data, 15556b3eb752SJiri Pirko void *cb_priv, bool ingress) 15566b3eb752SJiri Pirko { 15576b3eb752SJiri Pirko struct net_device *dev = cb_priv; 15586b3eb752SJiri Pirko 155944ae12a7SJiri Pirko if (!tc_can_offload(dev)) 156044ae12a7SJiri Pirko return -EOPNOTSUPP; 156144ae12a7SJiri Pirko 15626b3eb752SJiri Pirko switch (type) { 15636b3eb752SJiri Pirko case TC_SETUP_CLSMATCHALL: 15646b3eb752SJiri Pirko return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress); 1565ed11bb1fSVladimir Oltean case TC_SETUP_CLSFLOWER: 1566ed11bb1fSVladimir Oltean return dsa_slave_setup_tc_cls_flower(dev, type_data, ingress); 15676b3eb752SJiri Pirko default: 15686b3eb752SJiri Pirko return -EOPNOTSUPP; 15696b3eb752SJiri Pirko } 15706b3eb752SJiri Pirko } 15716b3eb752SJiri Pirko 15726b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb_ig(enum tc_setup_type type, 15736b3eb752SJiri Pirko void *type_data, void *cb_priv) 15746b3eb752SJiri Pirko { 15756b3eb752SJiri Pirko return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, true); 15766b3eb752SJiri Pirko } 15776b3eb752SJiri Pirko 15786b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type, 15796b3eb752SJiri Pirko void *type_data, void *cb_priv) 15806b3eb752SJiri Pirko { 15816b3eb752SJiri Pirko return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false); 15826b3eb752SJiri Pirko } 15836b3eb752SJiri Pirko 1584955bcb6eSPablo Neira Ayuso static LIST_HEAD(dsa_slave_block_cb_list); 1585955bcb6eSPablo Neira Ayuso 15866b3eb752SJiri Pirko static int dsa_slave_setup_tc_block(struct net_device *dev, 1587955bcb6eSPablo Neira Ayuso struct flow_block_offload *f) 15886b3eb752SJiri Pirko { 1589955bcb6eSPablo Neira Ayuso struct flow_block_cb *block_cb; 1590a7323311SPablo Neira Ayuso flow_setup_cb_t *cb; 15916b3eb752SJiri Pirko 159232f8c409SPablo Neira Ayuso if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 15936b3eb752SJiri Pirko cb = dsa_slave_setup_tc_block_cb_ig; 159432f8c409SPablo Neira Ayuso else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) 15956b3eb752SJiri Pirko cb = dsa_slave_setup_tc_block_cb_eg; 15966b3eb752SJiri Pirko else 15976b3eb752SJiri Pirko return -EOPNOTSUPP; 15986b3eb752SJiri Pirko 1599955bcb6eSPablo Neira Ayuso f->driver_block_list = &dsa_slave_block_cb_list; 1600955bcb6eSPablo Neira Ayuso 16016b3eb752SJiri Pirko switch (f->command) { 16029c0e189eSPablo Neira Ayuso case FLOW_BLOCK_BIND: 16030d4fd02eSPablo Neira Ayuso if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list)) 16040d4fd02eSPablo Neira Ayuso return -EBUSY; 16050d4fd02eSPablo Neira Ayuso 16060c7294ddSPablo Neira Ayuso block_cb = flow_block_cb_alloc(cb, dev, dev, NULL); 1607955bcb6eSPablo Neira Ayuso if (IS_ERR(block_cb)) 1608955bcb6eSPablo Neira Ayuso return PTR_ERR(block_cb); 1609955bcb6eSPablo Neira Ayuso 1610955bcb6eSPablo Neira Ayuso flow_block_cb_add(block_cb, f); 1611955bcb6eSPablo Neira Ayuso list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list); 1612955bcb6eSPablo Neira Ayuso return 0; 16139c0e189eSPablo Neira Ayuso case FLOW_BLOCK_UNBIND: 161414bfb13fSPablo Neira Ayuso block_cb = flow_block_cb_lookup(f->block, cb, dev); 1615955bcb6eSPablo Neira Ayuso if (!block_cb) 1616955bcb6eSPablo Neira Ayuso return -ENOENT; 1617955bcb6eSPablo Neira Ayuso 1618955bcb6eSPablo Neira Ayuso flow_block_cb_remove(block_cb, f); 1619955bcb6eSPablo Neira Ayuso list_del(&block_cb->driver_list); 16206b3eb752SJiri Pirko return 0; 16216b3eb752SJiri Pirko default: 16226b3eb752SJiri Pirko return -EOPNOTSUPP; 16236b3eb752SJiri Pirko } 16246b3eb752SJiri Pirko } 16256b3eb752SJiri Pirko 16263fb24a43SPablo Neira Ayuso static int dsa_slave_setup_ft_block(struct dsa_switch *ds, int port, 16273fb24a43SPablo Neira Ayuso void *type_data) 16283fb24a43SPablo Neira Ayuso { 16298f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dsa_to_port(ds, port)); 16303fb24a43SPablo Neira Ayuso 16313fb24a43SPablo Neira Ayuso if (!master->netdev_ops->ndo_setup_tc) 16323fb24a43SPablo Neira Ayuso return -EOPNOTSUPP; 16333fb24a43SPablo Neira Ayuso 16343fb24a43SPablo Neira Ayuso return master->netdev_ops->ndo_setup_tc(master, TC_SETUP_FT, type_data); 16353fb24a43SPablo Neira Ayuso } 16363fb24a43SPablo Neira Ayuso 16373fbae382SJiri Pirko static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type, 1638de4784caSJiri Pirko void *type_data) 16393fbae382SJiri Pirko { 164047d23af2SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 164147d23af2SVladimir Oltean struct dsa_switch *ds = dp->ds; 164247d23af2SVladimir Oltean 16433fb24a43SPablo Neira Ayuso switch (type) { 16443fb24a43SPablo Neira Ayuso case TC_SETUP_BLOCK: 16456b3eb752SJiri Pirko return dsa_slave_setup_tc_block(dev, type_data); 16463fb24a43SPablo Neira Ayuso case TC_SETUP_FT: 16473fb24a43SPablo Neira Ayuso return dsa_slave_setup_ft_block(ds, dp->index, type_data); 16483fb24a43SPablo Neira Ayuso default: 16493fb24a43SPablo Neira Ayuso break; 16503fb24a43SPablo Neira Ayuso } 165147d23af2SVladimir Oltean 165247d23af2SVladimir Oltean if (!ds->ops->port_setup_tc) 1653a5fcf8a6SJiri Pirko return -EOPNOTSUPP; 165447d23af2SVladimir Oltean 165547d23af2SVladimir Oltean return ds->ops->port_setup_tc(ds, dp->index, type, type_data); 1656f50f2127SFlorian Fainelli } 1657f50f2127SFlorian Fainelli 1658bf9f2648SFlorian Fainelli static int dsa_slave_get_rxnfc(struct net_device *dev, 1659bf9f2648SFlorian Fainelli struct ethtool_rxnfc *nfc, u32 *rule_locs) 1660bf9f2648SFlorian Fainelli { 1661d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1662d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1663bf9f2648SFlorian Fainelli 1664bf9f2648SFlorian Fainelli if (!ds->ops->get_rxnfc) 1665bf9f2648SFlorian Fainelli return -EOPNOTSUPP; 1666bf9f2648SFlorian Fainelli 1667d945097bSVivien Didelot return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs); 1668bf9f2648SFlorian Fainelli } 1669bf9f2648SFlorian Fainelli 1670bf9f2648SFlorian Fainelli static int dsa_slave_set_rxnfc(struct net_device *dev, 1671bf9f2648SFlorian Fainelli struct ethtool_rxnfc *nfc) 1672bf9f2648SFlorian Fainelli { 1673d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1674d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1675bf9f2648SFlorian Fainelli 1676bf9f2648SFlorian Fainelli if (!ds->ops->set_rxnfc) 1677bf9f2648SFlorian Fainelli return -EOPNOTSUPP; 1678bf9f2648SFlorian Fainelli 1679d945097bSVivien Didelot return ds->ops->set_rxnfc(ds, dp->index, nfc); 1680bf9f2648SFlorian Fainelli } 1681bf9f2648SFlorian Fainelli 16820336369dSBrandon Streiff static int dsa_slave_get_ts_info(struct net_device *dev, 16830336369dSBrandon Streiff struct ethtool_ts_info *ts) 16840336369dSBrandon Streiff { 16850336369dSBrandon Streiff struct dsa_slave_priv *p = netdev_priv(dev); 16860336369dSBrandon Streiff struct dsa_switch *ds = p->dp->ds; 16870336369dSBrandon Streiff 16880336369dSBrandon Streiff if (!ds->ops->get_ts_info) 16890336369dSBrandon Streiff return -EOPNOTSUPP; 16900336369dSBrandon Streiff 16910336369dSBrandon Streiff return ds->ops->get_ts_info(ds, p->dp->index, ts); 16920336369dSBrandon Streiff } 16930336369dSBrandon Streiff 1694061f6a50SFlorian Fainelli static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, 1695061f6a50SFlorian Fainelli u16 vid) 1696061f6a50SFlorian Fainelli { 1697061f6a50SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 169888236591SVladimir Oltean struct switchdev_obj_port_vlan vlan = { 169988236591SVladimir Oltean .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 1700b7a9e0daSVladimir Oltean .vid = vid, 170188236591SVladimir Oltean /* This API only allows programming tagged, non-PVID VIDs */ 170288236591SVladimir Oltean .flags = 0, 170388236591SVladimir Oltean }; 170431046a5fSVladimir Oltean struct netlink_ext_ack extack = {0}; 1705061f6a50SFlorian Fainelli int ret; 1706061f6a50SFlorian Fainelli 170788236591SVladimir Oltean /* User port... */ 170831046a5fSVladimir Oltean ret = dsa_port_vlan_add(dp, &vlan, &extack); 170931046a5fSVladimir Oltean if (ret) { 171031046a5fSVladimir Oltean if (extack._msg) 171131046a5fSVladimir Oltean netdev_err(dev, "%s\n", extack._msg); 171288236591SVladimir Oltean return ret; 171331046a5fSVladimir Oltean } 171488236591SVladimir Oltean 171588236591SVladimir Oltean /* And CPU port... */ 1716134ef238SVladimir Oltean ret = dsa_port_host_vlan_add(dp, &vlan, &extack); 171731046a5fSVladimir Oltean if (ret) { 171831046a5fSVladimir Oltean if (extack._msg) 171931046a5fSVladimir Oltean netdev_err(dev, "CPU port %d: %s\n", dp->cpu_dp->index, 172031046a5fSVladimir Oltean extack._msg); 17217e1741b4SVivien Didelot return ret; 172231046a5fSVladimir Oltean } 17237e1741b4SVivien Didelot 1724134ef238SVladimir Oltean return 0; 1725061f6a50SFlorian Fainelli } 1726061f6a50SFlorian Fainelli 1727061f6a50SFlorian Fainelli static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, 1728061f6a50SFlorian Fainelli u16 vid) 1729061f6a50SFlorian Fainelli { 1730061f6a50SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 173188236591SVladimir Oltean struct switchdev_obj_port_vlan vlan = { 1732b7a9e0daSVladimir Oltean .vid = vid, 173388236591SVladimir Oltean /* This API only allows programming tagged, non-PVID VIDs */ 173488236591SVladimir Oltean .flags = 0, 173588236591SVladimir Oltean }; 17362209158cSVladimir Oltean int err; 1737061f6a50SFlorian Fainelli 17382209158cSVladimir Oltean err = dsa_port_vlan_del(dp, &vlan); 17392209158cSVladimir Oltean if (err) 17402209158cSVladimir Oltean return err; 17412209158cSVladimir Oltean 1742134ef238SVladimir Oltean return dsa_port_host_vlan_del(dp, &vlan); 1743061f6a50SFlorian Fainelli } 1744061f6a50SFlorian Fainelli 174506cfb2dfSVladimir Oltean static int dsa_slave_restore_vlan(struct net_device *vdev, int vid, void *arg) 174606cfb2dfSVladimir Oltean { 174706cfb2dfSVladimir Oltean __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); 174806cfb2dfSVladimir Oltean 174906cfb2dfSVladimir Oltean return dsa_slave_vlan_rx_add_vid(arg, proto, vid); 175006cfb2dfSVladimir Oltean } 175106cfb2dfSVladimir Oltean 175206cfb2dfSVladimir Oltean static int dsa_slave_clear_vlan(struct net_device *vdev, int vid, void *arg) 175306cfb2dfSVladimir Oltean { 175406cfb2dfSVladimir Oltean __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); 175506cfb2dfSVladimir Oltean 175606cfb2dfSVladimir Oltean return dsa_slave_vlan_rx_kill_vid(arg, proto, vid); 175706cfb2dfSVladimir Oltean } 175806cfb2dfSVladimir Oltean 175906cfb2dfSVladimir Oltean /* Keep the VLAN RX filtering list in sync with the hardware only if VLAN 176006cfb2dfSVladimir Oltean * filtering is enabled. The baseline is that only ports that offload a 176106cfb2dfSVladimir Oltean * VLAN-aware bridge are VLAN-aware, and standalone ports are VLAN-unaware, 176206cfb2dfSVladimir Oltean * but there are exceptions for quirky hardware. 176306cfb2dfSVladimir Oltean * 176406cfb2dfSVladimir Oltean * If ds->vlan_filtering_is_global = true, then standalone ports which share 176506cfb2dfSVladimir Oltean * the same switch with other ports that offload a VLAN-aware bridge are also 176606cfb2dfSVladimir Oltean * inevitably VLAN-aware. 176706cfb2dfSVladimir Oltean * 176806cfb2dfSVladimir Oltean * To summarize, a DSA switch port offloads: 176906cfb2dfSVladimir Oltean * 177006cfb2dfSVladimir Oltean * - If standalone (this includes software bridge, software LAG): 177158adf9dcSVladimir Oltean * - if ds->needs_standalone_vlan_filtering = true, OR if 177258adf9dcSVladimir Oltean * (ds->vlan_filtering_is_global = true AND there are bridges spanning 177358adf9dcSVladimir Oltean * this switch chip which have vlan_filtering=1) 177406cfb2dfSVladimir Oltean * - the 8021q upper VLANs 177558adf9dcSVladimir Oltean * - else (standalone VLAN filtering is not needed, VLAN filtering is not 177658adf9dcSVladimir Oltean * global, or it is, but no port is under a VLAN-aware bridge): 177706cfb2dfSVladimir Oltean * - no VLAN (any 8021q upper is a software VLAN) 177806cfb2dfSVladimir Oltean * 177906cfb2dfSVladimir Oltean * - If under a vlan_filtering=0 bridge which it offload: 178006cfb2dfSVladimir Oltean * - if ds->configure_vlan_while_not_filtering = true (default): 178106cfb2dfSVladimir Oltean * - the bridge VLANs. These VLANs are committed to hardware but inactive. 178206cfb2dfSVladimir Oltean * - else (deprecated): 178306cfb2dfSVladimir Oltean * - no VLAN. The bridge VLANs are not restored when VLAN awareness is 178406cfb2dfSVladimir Oltean * enabled, so this behavior is broken and discouraged. 178506cfb2dfSVladimir Oltean * 178606cfb2dfSVladimir Oltean * - If under a vlan_filtering=1 bridge which it offload: 178706cfb2dfSVladimir Oltean * - the bridge VLANs 178806cfb2dfSVladimir Oltean * - the 8021q upper VLANs 178906cfb2dfSVladimir Oltean */ 179006cfb2dfSVladimir Oltean int dsa_slave_manage_vlan_filtering(struct net_device *slave, 179106cfb2dfSVladimir Oltean bool vlan_filtering) 179206cfb2dfSVladimir Oltean { 179306cfb2dfSVladimir Oltean int err; 179406cfb2dfSVladimir Oltean 179506cfb2dfSVladimir Oltean if (vlan_filtering) { 179606cfb2dfSVladimir Oltean slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 179706cfb2dfSVladimir Oltean 179806cfb2dfSVladimir Oltean err = vlan_for_each(slave, dsa_slave_restore_vlan, slave); 179906cfb2dfSVladimir Oltean if (err) { 180006cfb2dfSVladimir Oltean vlan_for_each(slave, dsa_slave_clear_vlan, slave); 180106cfb2dfSVladimir Oltean slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 180206cfb2dfSVladimir Oltean return err; 180306cfb2dfSVladimir Oltean } 180406cfb2dfSVladimir Oltean } else { 180506cfb2dfSVladimir Oltean err = vlan_for_each(slave, dsa_slave_clear_vlan, slave); 180606cfb2dfSVladimir Oltean if (err) 180706cfb2dfSVladimir Oltean return err; 180806cfb2dfSVladimir Oltean 180906cfb2dfSVladimir Oltean slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 181006cfb2dfSVladimir Oltean } 181106cfb2dfSVladimir Oltean 181206cfb2dfSVladimir Oltean return 0; 181306cfb2dfSVladimir Oltean } 181406cfb2dfSVladimir Oltean 1815bff33f7eSVladimir Oltean struct dsa_hw_port { 1816bff33f7eSVladimir Oltean struct list_head list; 1817bff33f7eSVladimir Oltean struct net_device *dev; 1818bff33f7eSVladimir Oltean int old_mtu; 1819bff33f7eSVladimir Oltean }; 1820bff33f7eSVladimir Oltean 1821bff33f7eSVladimir Oltean static int dsa_hw_port_list_set_mtu(struct list_head *hw_port_list, int mtu) 1822bff33f7eSVladimir Oltean { 1823bff33f7eSVladimir Oltean const struct dsa_hw_port *p; 1824bff33f7eSVladimir Oltean int err; 1825bff33f7eSVladimir Oltean 1826bff33f7eSVladimir Oltean list_for_each_entry(p, hw_port_list, list) { 1827bff33f7eSVladimir Oltean if (p->dev->mtu == mtu) 1828bff33f7eSVladimir Oltean continue; 1829bff33f7eSVladimir Oltean 1830bff33f7eSVladimir Oltean err = dev_set_mtu(p->dev, mtu); 1831bff33f7eSVladimir Oltean if (err) 1832bff33f7eSVladimir Oltean goto rollback; 1833bff33f7eSVladimir Oltean } 1834bff33f7eSVladimir Oltean 1835bff33f7eSVladimir Oltean return 0; 1836bff33f7eSVladimir Oltean 1837bff33f7eSVladimir Oltean rollback: 1838bff33f7eSVladimir Oltean list_for_each_entry_continue_reverse(p, hw_port_list, list) { 1839bff33f7eSVladimir Oltean if (p->dev->mtu == p->old_mtu) 1840bff33f7eSVladimir Oltean continue; 1841bff33f7eSVladimir Oltean 1842bff33f7eSVladimir Oltean if (dev_set_mtu(p->dev, p->old_mtu)) 1843bff33f7eSVladimir Oltean netdev_err(p->dev, "Failed to restore MTU\n"); 1844bff33f7eSVladimir Oltean } 1845bff33f7eSVladimir Oltean 1846bff33f7eSVladimir Oltean return err; 1847bff33f7eSVladimir Oltean } 1848bff33f7eSVladimir Oltean 1849bff33f7eSVladimir Oltean static void dsa_hw_port_list_free(struct list_head *hw_port_list) 1850bff33f7eSVladimir Oltean { 1851bff33f7eSVladimir Oltean struct dsa_hw_port *p, *n; 1852bff33f7eSVladimir Oltean 1853bff33f7eSVladimir Oltean list_for_each_entry_safe(p, n, hw_port_list, list) 1854bff33f7eSVladimir Oltean kfree(p); 1855bff33f7eSVladimir Oltean } 1856bff33f7eSVladimir Oltean 1857bff33f7eSVladimir Oltean /* Make the hardware datapath to/from @dev limited to a common MTU */ 1858bf88dc32Skbuild test robot static void dsa_bridge_mtu_normalization(struct dsa_port *dp) 1859bff33f7eSVladimir Oltean { 1860bff33f7eSVladimir Oltean struct list_head hw_port_list; 1861bff33f7eSVladimir Oltean struct dsa_switch_tree *dst; 1862bff33f7eSVladimir Oltean int min_mtu = ETH_MAX_MTU; 1863bff33f7eSVladimir Oltean struct dsa_port *other_dp; 1864bff33f7eSVladimir Oltean int err; 1865bff33f7eSVladimir Oltean 1866bff33f7eSVladimir Oltean if (!dp->ds->mtu_enforcement_ingress) 1867bff33f7eSVladimir Oltean return; 1868bff33f7eSVladimir Oltean 1869d3eed0e5SVladimir Oltean if (!dp->bridge) 1870bff33f7eSVladimir Oltean return; 1871bff33f7eSVladimir Oltean 1872bff33f7eSVladimir Oltean INIT_LIST_HEAD(&hw_port_list); 1873bff33f7eSVladimir Oltean 1874bff33f7eSVladimir Oltean /* Populate the list of ports that are part of the same bridge 1875bff33f7eSVladimir Oltean * as the newly added/modified port 1876bff33f7eSVladimir Oltean */ 1877bff33f7eSVladimir Oltean list_for_each_entry(dst, &dsa_tree_list, list) { 1878bff33f7eSVladimir Oltean list_for_each_entry(other_dp, &dst->ports, list) { 1879bff33f7eSVladimir Oltean struct dsa_hw_port *hw_port; 1880bff33f7eSVladimir Oltean struct net_device *slave; 1881bff33f7eSVladimir Oltean 1882bff33f7eSVladimir Oltean if (other_dp->type != DSA_PORT_TYPE_USER) 1883bff33f7eSVladimir Oltean continue; 1884bff33f7eSVladimir Oltean 188536cbf39bSVladimir Oltean if (!dsa_port_bridge_same(dp, other_dp)) 1886bff33f7eSVladimir Oltean continue; 1887bff33f7eSVladimir Oltean 1888bff33f7eSVladimir Oltean if (!other_dp->ds->mtu_enforcement_ingress) 1889bff33f7eSVladimir Oltean continue; 1890bff33f7eSVladimir Oltean 1891bff33f7eSVladimir Oltean slave = other_dp->slave; 1892bff33f7eSVladimir Oltean 1893bff33f7eSVladimir Oltean if (min_mtu > slave->mtu) 1894bff33f7eSVladimir Oltean min_mtu = slave->mtu; 1895bff33f7eSVladimir Oltean 1896bff33f7eSVladimir Oltean hw_port = kzalloc(sizeof(*hw_port), GFP_KERNEL); 1897bff33f7eSVladimir Oltean if (!hw_port) 1898bff33f7eSVladimir Oltean goto out; 1899bff33f7eSVladimir Oltean 1900bff33f7eSVladimir Oltean hw_port->dev = slave; 1901bff33f7eSVladimir Oltean hw_port->old_mtu = slave->mtu; 1902bff33f7eSVladimir Oltean 1903bff33f7eSVladimir Oltean list_add(&hw_port->list, &hw_port_list); 1904bff33f7eSVladimir Oltean } 1905bff33f7eSVladimir Oltean } 1906bff33f7eSVladimir Oltean 1907bff33f7eSVladimir Oltean /* Attempt to configure the entire hardware bridge to the newly added 1908bff33f7eSVladimir Oltean * interface's MTU first, regardless of whether the intention of the 1909bff33f7eSVladimir Oltean * user was to raise or lower it. 1910bff33f7eSVladimir Oltean */ 1911bff33f7eSVladimir Oltean err = dsa_hw_port_list_set_mtu(&hw_port_list, dp->slave->mtu); 1912bff33f7eSVladimir Oltean if (!err) 1913bff33f7eSVladimir Oltean goto out; 1914bff33f7eSVladimir Oltean 1915bff33f7eSVladimir Oltean /* Clearly that didn't work out so well, so just set the minimum MTU on 1916bff33f7eSVladimir Oltean * all hardware bridge ports now. If this fails too, then all ports will 1917bff33f7eSVladimir Oltean * still have their old MTU rolled back anyway. 1918bff33f7eSVladimir Oltean */ 1919bff33f7eSVladimir Oltean dsa_hw_port_list_set_mtu(&hw_port_list, min_mtu); 1920bff33f7eSVladimir Oltean 1921bff33f7eSVladimir Oltean out: 1922bff33f7eSVladimir Oltean dsa_hw_port_list_free(&hw_port_list); 1923bff33f7eSVladimir Oltean } 1924bff33f7eSVladimir Oltean 192553da0ebaSVladimir Oltean int dsa_slave_change_mtu(struct net_device *dev, int new_mtu) 1926bfcb8132SVladimir Oltean { 1927bfcb8132SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 1928bfcb8132SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1929cf1c39d3SVladimir Oltean struct dsa_port *cpu_dp = dp->cpu_dp; 19304715029fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1931b2033a05SVladimir Oltean struct dsa_port *other_dp; 1932bfcb8132SVladimir Oltean int largest_mtu = 0; 1933bfcb8132SVladimir Oltean int new_master_mtu; 1934bfcb8132SVladimir Oltean int old_master_mtu; 1935bfcb8132SVladimir Oltean int mtu_limit; 1936*636e8adfSVladimir Oltean int overhead; 1937bfcb8132SVladimir Oltean int cpu_mtu; 19384e4ab795SVladimir Oltean int err; 1939bfcb8132SVladimir Oltean 1940bfcb8132SVladimir Oltean if (!ds->ops->port_change_mtu) 1941bfcb8132SVladimir Oltean return -EOPNOTSUPP; 1942bfcb8132SVladimir Oltean 1943b2033a05SVladimir Oltean dsa_tree_for_each_user_port(other_dp, ds->dst) { 1944bfcb8132SVladimir Oltean int slave_mtu; 1945bfcb8132SVladimir Oltean 1946bfcb8132SVladimir Oltean /* During probe, this function will be called for each slave 1947bfcb8132SVladimir Oltean * device, while not all of them have been allocated. That's 1948bfcb8132SVladimir Oltean * ok, it doesn't change what the maximum is, so ignore it. 1949bfcb8132SVladimir Oltean */ 1950b2033a05SVladimir Oltean if (!other_dp->slave) 1951bfcb8132SVladimir Oltean continue; 1952bfcb8132SVladimir Oltean 1953bfcb8132SVladimir Oltean /* Pretend that we already applied the setting, which we 1954bfcb8132SVladimir Oltean * actually haven't (still haven't done all integrity checks) 1955bfcb8132SVladimir Oltean */ 1956b2033a05SVladimir Oltean if (dp == other_dp) 1957bfcb8132SVladimir Oltean slave_mtu = new_mtu; 1958bfcb8132SVladimir Oltean else 1959b2033a05SVladimir Oltean slave_mtu = other_dp->slave->mtu; 1960bfcb8132SVladimir Oltean 1961bfcb8132SVladimir Oltean if (largest_mtu < slave_mtu) 1962bfcb8132SVladimir Oltean largest_mtu = slave_mtu; 1963bfcb8132SVladimir Oltean } 1964bfcb8132SVladimir Oltean 1965*636e8adfSVladimir Oltean overhead = dsa_tag_protocol_overhead(cpu_dp->tag_ops); 1966*636e8adfSVladimir Oltean mtu_limit = min_t(int, master->max_mtu, dev->max_mtu + overhead); 1967bfcb8132SVladimir Oltean old_master_mtu = master->mtu; 1968*636e8adfSVladimir Oltean new_master_mtu = largest_mtu + overhead; 1969bfcb8132SVladimir Oltean if (new_master_mtu > mtu_limit) 1970bfcb8132SVladimir Oltean return -ERANGE; 1971bfcb8132SVladimir Oltean 1972bfcb8132SVladimir Oltean /* If the master MTU isn't over limit, there's no need to check the CPU 1973bfcb8132SVladimir Oltean * MTU, since that surely isn't either. 1974bfcb8132SVladimir Oltean */ 1975bfcb8132SVladimir Oltean cpu_mtu = largest_mtu; 1976bfcb8132SVladimir Oltean 1977bfcb8132SVladimir Oltean /* Start applying stuff */ 1978bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) { 1979bfcb8132SVladimir Oltean err = dev_set_mtu(master, new_master_mtu); 1980bfcb8132SVladimir Oltean if (err < 0) 1981bfcb8132SVladimir Oltean goto out_master_failed; 1982bfcb8132SVladimir Oltean 1983bfcb8132SVladimir Oltean /* We only need to propagate the MTU of the CPU port to 1984be6ff966SVladimir Oltean * upstream switches, so emit a notifier which updates them. 1985bfcb8132SVladimir Oltean */ 1986be6ff966SVladimir Oltean err = dsa_port_mtu_change(cpu_dp, cpu_mtu); 1987bfcb8132SVladimir Oltean if (err) 1988bfcb8132SVladimir Oltean goto out_cpu_failed; 1989bfcb8132SVladimir Oltean } 1990bfcb8132SVladimir Oltean 1991be6ff966SVladimir Oltean err = ds->ops->port_change_mtu(ds, dp->index, new_mtu); 1992bfcb8132SVladimir Oltean if (err) 1993bfcb8132SVladimir Oltean goto out_port_failed; 1994bfcb8132SVladimir Oltean 1995bfcb8132SVladimir Oltean dev->mtu = new_mtu; 1996bfcb8132SVladimir Oltean 1997bff33f7eSVladimir Oltean dsa_bridge_mtu_normalization(dp); 1998bff33f7eSVladimir Oltean 1999bfcb8132SVladimir Oltean return 0; 2000bfcb8132SVladimir Oltean 2001bfcb8132SVladimir Oltean out_port_failed: 2002bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) 2003*636e8adfSVladimir Oltean dsa_port_mtu_change(cpu_dp, old_master_mtu - overhead); 2004bfcb8132SVladimir Oltean out_cpu_failed: 2005bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) 2006bfcb8132SVladimir Oltean dev_set_mtu(master, old_master_mtu); 2007bfcb8132SVladimir Oltean out_master_failed: 2008bfcb8132SVladimir Oltean return err; 2009bfcb8132SVladimir Oltean } 2010bfcb8132SVladimir Oltean 2011d538eca8SVladimir Oltean static int __maybe_unused 2012d538eca8SVladimir Oltean dsa_slave_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app) 2013d538eca8SVladimir Oltean { 2014d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2015d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 2016d538eca8SVladimir Oltean unsigned long mask, new_prio; 2017d538eca8SVladimir Oltean int err, port = dp->index; 2018d538eca8SVladimir Oltean 2019d538eca8SVladimir Oltean if (!ds->ops->port_set_default_prio) 2020d538eca8SVladimir Oltean return -EOPNOTSUPP; 2021d538eca8SVladimir Oltean 2022d538eca8SVladimir Oltean err = dcb_ieee_setapp(dev, app); 2023d538eca8SVladimir Oltean if (err) 2024d538eca8SVladimir Oltean return err; 2025d538eca8SVladimir Oltean 2026d538eca8SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 2027d538eca8SVladimir Oltean new_prio = __fls(mask); 2028d538eca8SVladimir Oltean 2029d538eca8SVladimir Oltean err = ds->ops->port_set_default_prio(ds, port, new_prio); 2030d538eca8SVladimir Oltean if (err) { 2031d538eca8SVladimir Oltean dcb_ieee_delapp(dev, app); 2032d538eca8SVladimir Oltean return err; 2033d538eca8SVladimir Oltean } 2034d538eca8SVladimir Oltean 2035d538eca8SVladimir Oltean return 0; 2036d538eca8SVladimir Oltean } 2037d538eca8SVladimir Oltean 203847d75f78SVladimir Oltean static int __maybe_unused 203947d75f78SVladimir Oltean dsa_slave_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) 204047d75f78SVladimir Oltean { 204147d75f78SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 204247d75f78SVladimir Oltean struct dsa_switch *ds = dp->ds; 204347d75f78SVladimir Oltean unsigned long mask, new_prio; 204447d75f78SVladimir Oltean int err, port = dp->index; 204547d75f78SVladimir Oltean u8 dscp = app->protocol; 204647d75f78SVladimir Oltean 204747d75f78SVladimir Oltean if (!ds->ops->port_add_dscp_prio) 204847d75f78SVladimir Oltean return -EOPNOTSUPP; 204947d75f78SVladimir Oltean 205047d75f78SVladimir Oltean if (dscp >= 64) { 205147d75f78SVladimir Oltean netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n", 205247d75f78SVladimir Oltean dscp); 205347d75f78SVladimir Oltean return -EINVAL; 205447d75f78SVladimir Oltean } 205547d75f78SVladimir Oltean 205647d75f78SVladimir Oltean err = dcb_ieee_setapp(dev, app); 205747d75f78SVladimir Oltean if (err) 205847d75f78SVladimir Oltean return err; 205947d75f78SVladimir Oltean 206047d75f78SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 206147d75f78SVladimir Oltean new_prio = __fls(mask); 206247d75f78SVladimir Oltean 206347d75f78SVladimir Oltean err = ds->ops->port_add_dscp_prio(ds, port, dscp, new_prio); 206447d75f78SVladimir Oltean if (err) { 206547d75f78SVladimir Oltean dcb_ieee_delapp(dev, app); 206647d75f78SVladimir Oltean return err; 206747d75f78SVladimir Oltean } 206847d75f78SVladimir Oltean 206947d75f78SVladimir Oltean return 0; 207047d75f78SVladimir Oltean } 207147d75f78SVladimir Oltean 2072d538eca8SVladimir Oltean static int __maybe_unused dsa_slave_dcbnl_ieee_setapp(struct net_device *dev, 2073d538eca8SVladimir Oltean struct dcb_app *app) 2074d538eca8SVladimir Oltean { 2075d538eca8SVladimir Oltean switch (app->selector) { 2076d538eca8SVladimir Oltean case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 2077d538eca8SVladimir Oltean switch (app->protocol) { 2078d538eca8SVladimir Oltean case 0: 2079d538eca8SVladimir Oltean return dsa_slave_dcbnl_set_default_prio(dev, app); 2080d538eca8SVladimir Oltean default: 2081d538eca8SVladimir Oltean return -EOPNOTSUPP; 2082d538eca8SVladimir Oltean } 2083d538eca8SVladimir Oltean break; 208447d75f78SVladimir Oltean case IEEE_8021QAZ_APP_SEL_DSCP: 208547d75f78SVladimir Oltean return dsa_slave_dcbnl_add_dscp_prio(dev, app); 2086d538eca8SVladimir Oltean default: 2087d538eca8SVladimir Oltean return -EOPNOTSUPP; 2088d538eca8SVladimir Oltean } 2089d538eca8SVladimir Oltean } 2090d538eca8SVladimir Oltean 2091d538eca8SVladimir Oltean static int __maybe_unused 2092d538eca8SVladimir Oltean dsa_slave_dcbnl_del_default_prio(struct net_device *dev, struct dcb_app *app) 2093d538eca8SVladimir Oltean { 2094d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2095d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 2096d538eca8SVladimir Oltean unsigned long mask, new_prio; 2097d538eca8SVladimir Oltean int err, port = dp->index; 2098d538eca8SVladimir Oltean 2099d538eca8SVladimir Oltean if (!ds->ops->port_set_default_prio) 2100d538eca8SVladimir Oltean return -EOPNOTSUPP; 2101d538eca8SVladimir Oltean 2102d538eca8SVladimir Oltean err = dcb_ieee_delapp(dev, app); 2103d538eca8SVladimir Oltean if (err) 2104d538eca8SVladimir Oltean return err; 2105d538eca8SVladimir Oltean 2106d538eca8SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 2107d538eca8SVladimir Oltean new_prio = mask ? __fls(mask) : 0; 2108d538eca8SVladimir Oltean 2109d538eca8SVladimir Oltean err = ds->ops->port_set_default_prio(ds, port, new_prio); 2110d538eca8SVladimir Oltean if (err) { 2111d538eca8SVladimir Oltean dcb_ieee_setapp(dev, app); 2112d538eca8SVladimir Oltean return err; 2113d538eca8SVladimir Oltean } 2114d538eca8SVladimir Oltean 2115d538eca8SVladimir Oltean return 0; 2116d538eca8SVladimir Oltean } 2117d538eca8SVladimir Oltean 211847d75f78SVladimir Oltean static int __maybe_unused 211947d75f78SVladimir Oltean dsa_slave_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) 212047d75f78SVladimir Oltean { 212147d75f78SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 212247d75f78SVladimir Oltean struct dsa_switch *ds = dp->ds; 212347d75f78SVladimir Oltean int err, port = dp->index; 212447d75f78SVladimir Oltean u8 dscp = app->protocol; 212547d75f78SVladimir Oltean 212647d75f78SVladimir Oltean if (!ds->ops->port_del_dscp_prio) 212747d75f78SVladimir Oltean return -EOPNOTSUPP; 212847d75f78SVladimir Oltean 212947d75f78SVladimir Oltean err = dcb_ieee_delapp(dev, app); 213047d75f78SVladimir Oltean if (err) 213147d75f78SVladimir Oltean return err; 213247d75f78SVladimir Oltean 213347d75f78SVladimir Oltean err = ds->ops->port_del_dscp_prio(ds, port, dscp, app->priority); 213447d75f78SVladimir Oltean if (err) { 213547d75f78SVladimir Oltean dcb_ieee_setapp(dev, app); 213647d75f78SVladimir Oltean return err; 213747d75f78SVladimir Oltean } 213847d75f78SVladimir Oltean 213947d75f78SVladimir Oltean return 0; 214047d75f78SVladimir Oltean } 214147d75f78SVladimir Oltean 2142d538eca8SVladimir Oltean static int __maybe_unused dsa_slave_dcbnl_ieee_delapp(struct net_device *dev, 2143d538eca8SVladimir Oltean struct dcb_app *app) 2144d538eca8SVladimir Oltean { 2145d538eca8SVladimir Oltean switch (app->selector) { 2146d538eca8SVladimir Oltean case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 2147d538eca8SVladimir Oltean switch (app->protocol) { 2148d538eca8SVladimir Oltean case 0: 2149d538eca8SVladimir Oltean return dsa_slave_dcbnl_del_default_prio(dev, app); 2150d538eca8SVladimir Oltean default: 2151d538eca8SVladimir Oltean return -EOPNOTSUPP; 2152d538eca8SVladimir Oltean } 2153d538eca8SVladimir Oltean break; 215447d75f78SVladimir Oltean case IEEE_8021QAZ_APP_SEL_DSCP: 215547d75f78SVladimir Oltean return dsa_slave_dcbnl_del_dscp_prio(dev, app); 2156d538eca8SVladimir Oltean default: 2157d538eca8SVladimir Oltean return -EOPNOTSUPP; 2158d538eca8SVladimir Oltean } 2159d538eca8SVladimir Oltean } 2160d538eca8SVladimir Oltean 2161d538eca8SVladimir Oltean /* Pre-populate the DCB application priority table with the priorities 2162d538eca8SVladimir Oltean * configured during switch setup, which we read from hardware here. 2163d538eca8SVladimir Oltean */ 2164d538eca8SVladimir Oltean static int dsa_slave_dcbnl_init(struct net_device *dev) 2165d538eca8SVladimir Oltean { 2166d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2167d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 2168d538eca8SVladimir Oltean int port = dp->index; 2169d538eca8SVladimir Oltean int err; 2170d538eca8SVladimir Oltean 2171d538eca8SVladimir Oltean if (ds->ops->port_get_default_prio) { 2172d538eca8SVladimir Oltean int prio = ds->ops->port_get_default_prio(ds, port); 2173d538eca8SVladimir Oltean struct dcb_app app = { 2174d538eca8SVladimir Oltean .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE, 2175d538eca8SVladimir Oltean .protocol = 0, 2176d538eca8SVladimir Oltean .priority = prio, 2177d538eca8SVladimir Oltean }; 2178d538eca8SVladimir Oltean 2179d538eca8SVladimir Oltean if (prio < 0) 2180d538eca8SVladimir Oltean return prio; 2181d538eca8SVladimir Oltean 2182d538eca8SVladimir Oltean err = dcb_ieee_setapp(dev, &app); 2183d538eca8SVladimir Oltean if (err) 2184d538eca8SVladimir Oltean return err; 2185d538eca8SVladimir Oltean } 2186d538eca8SVladimir Oltean 218747d75f78SVladimir Oltean if (ds->ops->port_get_dscp_prio) { 218847d75f78SVladimir Oltean int protocol; 218947d75f78SVladimir Oltean 219047d75f78SVladimir Oltean for (protocol = 0; protocol < 64; protocol++) { 219147d75f78SVladimir Oltean struct dcb_app app = { 219247d75f78SVladimir Oltean .selector = IEEE_8021QAZ_APP_SEL_DSCP, 219347d75f78SVladimir Oltean .protocol = protocol, 219447d75f78SVladimir Oltean }; 219547d75f78SVladimir Oltean int prio; 219647d75f78SVladimir Oltean 219747d75f78SVladimir Oltean prio = ds->ops->port_get_dscp_prio(ds, port, protocol); 219847d75f78SVladimir Oltean if (prio == -EOPNOTSUPP) 219947d75f78SVladimir Oltean continue; 220047d75f78SVladimir Oltean if (prio < 0) 220147d75f78SVladimir Oltean return prio; 220247d75f78SVladimir Oltean 220347d75f78SVladimir Oltean app.priority = prio; 220447d75f78SVladimir Oltean 220547d75f78SVladimir Oltean err = dcb_ieee_setapp(dev, &app); 220647d75f78SVladimir Oltean if (err) 220747d75f78SVladimir Oltean return err; 220847d75f78SVladimir Oltean } 220947d75f78SVladimir Oltean } 221047d75f78SVladimir Oltean 2211d538eca8SVladimir Oltean return 0; 2212d538eca8SVladimir Oltean } 2213d538eca8SVladimir Oltean 221491da11f8SLennert Buytenhek static const struct ethtool_ops dsa_slave_ethtool_ops = { 221591da11f8SLennert Buytenhek .get_drvinfo = dsa_slave_get_drvinfo, 22163d762a0fSGuenter Roeck .get_regs_len = dsa_slave_get_regs_len, 22173d762a0fSGuenter Roeck .get_regs = dsa_slave_get_regs, 2218aab9c406SFlorian Fainelli .nway_reset = dsa_slave_nway_reset, 2219c4aef9fcSFlorian Fainelli .get_link = ethtool_op_get_link, 22206793abb4SGuenter Roeck .get_eeprom_len = dsa_slave_get_eeprom_len, 22216793abb4SGuenter Roeck .get_eeprom = dsa_slave_get_eeprom, 22226793abb4SGuenter Roeck .set_eeprom = dsa_slave_set_eeprom, 222391da11f8SLennert Buytenhek .get_strings = dsa_slave_get_strings, 222491da11f8SLennert Buytenhek .get_ethtool_stats = dsa_slave_get_ethtool_stats, 222591da11f8SLennert Buytenhek .get_sset_count = dsa_slave_get_sset_count, 2226487d3855SAlvin Šipraga .get_eth_phy_stats = dsa_slave_get_eth_phy_stats, 2227487d3855SAlvin Šipraga .get_eth_mac_stats = dsa_slave_get_eth_mac_stats, 2228487d3855SAlvin Šipraga .get_eth_ctrl_stats = dsa_slave_get_eth_ctrl_stats, 222967f38b1cSClément Léger .get_rmon_stats = dsa_slave_get_rmon_stats, 223019e57c4eSFlorian Fainelli .set_wol = dsa_slave_set_wol, 223119e57c4eSFlorian Fainelli .get_wol = dsa_slave_get_wol, 22327905288fSFlorian Fainelli .set_eee = dsa_slave_set_eee, 22337905288fSFlorian Fainelli .get_eee = dsa_slave_get_eee, 2234aab9c406SFlorian Fainelli .get_link_ksettings = dsa_slave_get_link_ksettings, 2235aab9c406SFlorian Fainelli .set_link_ksettings = dsa_slave_set_link_ksettings, 22363d410403SOleksij Rempel .get_pause_stats = dsa_slave_get_pause_stats, 2237a2a1a13bSHeiner Kallweit .get_pauseparam = dsa_slave_get_pauseparam, 2238a2a1a13bSHeiner Kallweit .set_pauseparam = dsa_slave_set_pauseparam, 2239bf9f2648SFlorian Fainelli .get_rxnfc = dsa_slave_get_rxnfc, 2240bf9f2648SFlorian Fainelli .set_rxnfc = dsa_slave_set_rxnfc, 22410336369dSBrandon Streiff .get_ts_info = dsa_slave_get_ts_info, 2242a71acad9SOleksij Rempel .self_test = dsa_slave_net_selftest, 22435f6c2d49SVladimir Oltean .get_mm = dsa_slave_get_mm, 22445f6c2d49SVladimir Oltean .set_mm = dsa_slave_set_mm, 22455f6c2d49SVladimir Oltean .get_mm_stats = dsa_slave_get_mm_stats, 224691da11f8SLennert Buytenhek }; 224791da11f8SLennert Buytenhek 2248d538eca8SVladimir Oltean static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = { 2249d538eca8SVladimir Oltean .ieee_setapp = dsa_slave_dcbnl_ieee_setapp, 2250d538eca8SVladimir Oltean .ieee_delapp = dsa_slave_dcbnl_ieee_delapp, 2251d538eca8SVladimir Oltean }; 2252d538eca8SVladimir Oltean 2253c2ec5f2eSOleksij Rempel static void dsa_slave_get_stats64(struct net_device *dev, 2254c2ec5f2eSOleksij Rempel struct rtnl_link_stats64 *s) 2255c2ec5f2eSOleksij Rempel { 2256c2ec5f2eSOleksij Rempel struct dsa_port *dp = dsa_slave_to_port(dev); 2257c2ec5f2eSOleksij Rempel struct dsa_switch *ds = dp->ds; 2258c2ec5f2eSOleksij Rempel 2259c2ec5f2eSOleksij Rempel if (ds->ops->get_stats64) 2260c2ec5f2eSOleksij Rempel ds->ops->get_stats64(ds, dp->index, s); 2261c2ec5f2eSOleksij Rempel else 2262c2ec5f2eSOleksij Rempel dev_get_tstats64(dev, s); 2263c2ec5f2eSOleksij Rempel } 2264c2ec5f2eSOleksij Rempel 22650994d492SFelix Fietkau static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx, 22660994d492SFelix Fietkau struct net_device_path *path) 22670994d492SFelix Fietkau { 22680994d492SFelix Fietkau struct dsa_port *dp = dsa_slave_to_port(ctx->dev); 22698f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 22700994d492SFelix Fietkau struct dsa_port *cpu_dp = dp->cpu_dp; 22710994d492SFelix Fietkau 22720994d492SFelix Fietkau path->dev = ctx->dev; 22730994d492SFelix Fietkau path->type = DEV_PATH_DSA; 22740994d492SFelix Fietkau path->dsa.proto = cpu_dp->tag_ops->proto; 22750994d492SFelix Fietkau path->dsa.port = dp->index; 22768f6a19c0SVladimir Oltean ctx->dev = master; 22770994d492SFelix Fietkau 22780994d492SFelix Fietkau return 0; 22790994d492SFelix Fietkau } 22800994d492SFelix Fietkau 22813e8a72d1SFlorian Fainelli static const struct net_device_ops dsa_slave_netdev_ops = { 2282d442ad4aSStephen Hemminger .ndo_open = dsa_slave_open, 2283d442ad4aSStephen Hemminger .ndo_stop = dsa_slave_close, 22843e8a72d1SFlorian Fainelli .ndo_start_xmit = dsa_slave_xmit, 2285d442ad4aSStephen Hemminger .ndo_change_rx_flags = dsa_slave_change_rx_flags, 2286d442ad4aSStephen Hemminger .ndo_set_rx_mode = dsa_slave_set_rx_mode, 2287d442ad4aSStephen Hemminger .ndo_set_mac_address = dsa_slave_set_mac_address, 22882bedde1aSArkadi Sharshevsky .ndo_fdb_dump = dsa_slave_fdb_dump, 2289a7605370SArnd Bergmann .ndo_eth_ioctl = dsa_slave_ioctl, 2290abd2be00SNicolas Dichtel .ndo_get_iflink = dsa_slave_get_iflink, 229104ff53f9SFlorian Fainelli #ifdef CONFIG_NET_POLL_CONTROLLER 229204ff53f9SFlorian Fainelli .ndo_netpoll_setup = dsa_slave_netpoll_setup, 229304ff53f9SFlorian Fainelli .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup, 229404ff53f9SFlorian Fainelli .ndo_poll_controller = dsa_slave_poll_controller, 229504ff53f9SFlorian Fainelli #endif 2296f50f2127SFlorian Fainelli .ndo_setup_tc = dsa_slave_setup_tc, 2297c2ec5f2eSOleksij Rempel .ndo_get_stats64 = dsa_slave_get_stats64, 2298061f6a50SFlorian Fainelli .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, 2299061f6a50SFlorian Fainelli .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, 2300bfcb8132SVladimir Oltean .ndo_change_mtu = dsa_slave_change_mtu, 23010994d492SFelix Fietkau .ndo_fill_forward_path = dsa_slave_fill_forward_path, 230298237d43SScott Feldman }; 230398237d43SScott Feldman 2304f37db85dSFlorian Fainelli static struct device_type dsa_type = { 2305f37db85dSFlorian Fainelli .name = "dsa", 2306f37db85dSFlorian Fainelli }; 2307f37db85dSFlorian Fainelli 2308aab9c406SFlorian Fainelli void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up) 2309aab9c406SFlorian Fainelli { 2310aab9c406SFlorian Fainelli const struct dsa_port *dp = dsa_to_port(ds, port); 2311aab9c406SFlorian Fainelli 2312765bda93SRussell King if (dp->pl) 2313aab9c406SFlorian Fainelli phylink_mac_change(dp->pl, up); 2314aab9c406SFlorian Fainelli } 2315aab9c406SFlorian Fainelli EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); 2316aab9c406SFlorian Fainelli 23175c05c1dbSRussell King static void dsa_slave_phylink_fixed_state(struct phylink_config *config, 2318aab9c406SFlorian Fainelli struct phylink_link_state *state) 2319aab9c406SFlorian Fainelli { 23205c05c1dbSRussell King struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 2321aab9c406SFlorian Fainelli struct dsa_switch *ds = dp->ds; 2322aab9c406SFlorian Fainelli 2323aab9c406SFlorian Fainelli /* No need to check that this operation is valid, the callback would 2324aab9c406SFlorian Fainelli * not be called if it was not. 2325aab9c406SFlorian Fainelli */ 2326aab9c406SFlorian Fainelli ds->ops->phylink_fixed_state(ds, dp->index, state); 2327ce31b31cSFlorian Fainelli } 2328ce31b31cSFlorian Fainelli 232991da11f8SLennert Buytenhek /* slave device setup *******************************************************/ 2330c916e8e1SOleksij Rempel static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr, 2331c916e8e1SOleksij Rempel u32 flags) 2332c305c165SFlorian Fainelli { 2333d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2334d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 2335c305c165SFlorian Fainelli 23360115dcd1SVivien Didelot slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr); 23370115dcd1SVivien Didelot if (!slave_dev->phydev) { 2338d25b8e74SRussell King netdev_err(slave_dev, "no phy at %d\n", addr); 2339c305c165SFlorian Fainelli return -ENODEV; 2340d25b8e74SRussell King } 2341c305c165SFlorian Fainelli 2342c916e8e1SOleksij Rempel slave_dev->phydev->dev_flags |= flags; 2343c916e8e1SOleksij Rempel 2344aab9c406SFlorian Fainelli return phylink_connect_phy(dp->pl, slave_dev->phydev); 2345c305c165SFlorian Fainelli } 2346c305c165SFlorian Fainelli 23474fa7b718SVivien Didelot static int dsa_slave_phy_setup(struct net_device *slave_dev) 23480d8bcdd3SFlorian Fainelli { 2349d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2350d945097bSVivien Didelot struct device_node *port_dn = dp->dn; 2351d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 23526819563eSFlorian Fainelli u32 phy_flags = 0; 23530c65b2b9SAndrew Lunn int ret; 23540d8bcdd3SFlorian Fainelli 235544cc27e4SIoana Ciornei dp->pl_config.dev = &slave_dev->dev; 235644cc27e4SIoana Ciornei dp->pl_config.type = PHYLINK_NETDEV; 235744cc27e4SIoana Ciornei 23585c05c1dbSRussell King /* The get_fixed_state callback takes precedence over polling the 23595c05c1dbSRussell King * link GPIO in PHYLINK (see phylink_get_fixed_state). Only set 23605c05c1dbSRussell King * this if the switch provides such a callback. 23615c05c1dbSRussell King */ 23625c05c1dbSRussell King if (ds->ops->phylink_fixed_state) { 23635c05c1dbSRussell King dp->pl_config.get_fixed_state = dsa_slave_phylink_fixed_state; 23645c05c1dbSRussell King dp->pl_config.poll_fixed_state = true; 23655c05c1dbSRussell King } 23665c05c1dbSRussell King 236721bd64bdSRussell King (Oracle) ret = dsa_port_phylink_create(dp); 236821bd64bdSRussell King (Oracle) if (ret) 236921bd64bdSRussell King (Oracle) return ret; 2370aab9c406SFlorian Fainelli 23719d490b4eSVivien Didelot if (ds->ops->get_phy_flags) 2372d945097bSVivien Didelot phy_flags = ds->ops->get_phy_flags(ds, dp->index); 23736819563eSFlorian Fainelli 2374aab9c406SFlorian Fainelli ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); 23756146dd45SVladimir Oltean if (ret == -ENODEV && ds->slave_mii_bus) { 23766146dd45SVladimir Oltean /* We could not connect to a designated PHY or SFP, so try to 23776146dd45SVladimir Oltean * use the switch internal MDIO bus instead 23780d8bcdd3SFlorian Fainelli */ 2379c916e8e1SOleksij Rempel ret = dsa_slave_phy_connect(slave_dev, dp->index, phy_flags); 2380d25b8e74SRussell King } 23816a52e733SVladimir Oltean if (ret) { 23826a52e733SVladimir Oltean netdev_err(slave_dev, "failed to connect to PHY: %pe\n", 23836a52e733SVladimir Oltean ERR_PTR(ret)); 2384cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(dp); 23850d8bcdd3SFlorian Fainelli } 23869697f1cdSFlorian Fainelli 23876146dd45SVladimir Oltean return ret; 2388b31f65fbSAndrew Lunn } 23890d8bcdd3SFlorian Fainelli 239053da0ebaSVladimir Oltean void dsa_slave_setup_tagger(struct net_device *slave) 239153da0ebaSVladimir Oltean { 239253da0ebaSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(slave); 23938f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 239453da0ebaSVladimir Oltean struct dsa_slave_priv *p = netdev_priv(slave); 239553da0ebaSVladimir Oltean const struct dsa_port *cpu_dp = dp->cpu_dp; 239658adf9dcSVladimir Oltean const struct dsa_switch *ds = dp->ds; 239753da0ebaSVladimir Oltean 23984e500251SVladimir Oltean slave->needed_headroom = cpu_dp->tag_ops->needed_headroom; 23994e500251SVladimir Oltean slave->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; 240053da0ebaSVladimir Oltean /* Try to save one extra realloc later in the TX path (in the master) 240153da0ebaSVladimir Oltean * by also inheriting the master's needed headroom and tailroom. 240253da0ebaSVladimir Oltean * The 8021q driver also does this. 240353da0ebaSVladimir Oltean */ 240453da0ebaSVladimir Oltean slave->needed_headroom += master->needed_headroom; 240553da0ebaSVladimir Oltean slave->needed_tailroom += master->needed_tailroom; 240653da0ebaSVladimir Oltean 240753da0ebaSVladimir Oltean p->xmit = cpu_dp->tag_ops->xmit; 240821cf377aSLino Sanfilippo 240921cf377aSLino Sanfilippo slave->features = master->vlan_features | NETIF_F_HW_TC; 241021cf377aSLino Sanfilippo slave->hw_features |= NETIF_F_HW_TC; 241121cf377aSLino Sanfilippo slave->features |= NETIF_F_LLTX; 241221cf377aSLino Sanfilippo if (slave->needed_tailroom) 241321cf377aSLino Sanfilippo slave->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); 241458adf9dcSVladimir Oltean if (ds->needs_standalone_vlan_filtering) 241558adf9dcSVladimir Oltean slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 241653da0ebaSVladimir Oltean } 241753da0ebaSVladimir Oltean 241824462549SFlorian Fainelli int dsa_slave_suspend(struct net_device *slave_dev) 241924462549SFlorian Fainelli { 2420aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(slave_dev); 242124462549SFlorian Fainelli 2422a94c689eSFlorian Fainelli if (!netif_running(slave_dev)) 2423a94c689eSFlorian Fainelli return 0; 2424a94c689eSFlorian Fainelli 2425f154be24SFlorian Fainelli netif_device_detach(slave_dev); 2426f154be24SFlorian Fainelli 2427aab9c406SFlorian Fainelli rtnl_lock(); 2428aab9c406SFlorian Fainelli phylink_stop(dp->pl); 2429aab9c406SFlorian Fainelli rtnl_unlock(); 243024462549SFlorian Fainelli 243124462549SFlorian Fainelli return 0; 243224462549SFlorian Fainelli } 243324462549SFlorian Fainelli 243424462549SFlorian Fainelli int dsa_slave_resume(struct net_device *slave_dev) 243524462549SFlorian Fainelli { 2436aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2437aab9c406SFlorian Fainelli 2438a94c689eSFlorian Fainelli if (!netif_running(slave_dev)) 2439a94c689eSFlorian Fainelli return 0; 2440a94c689eSFlorian Fainelli 244124462549SFlorian Fainelli netif_device_attach(slave_dev); 244224462549SFlorian Fainelli 2443aab9c406SFlorian Fainelli rtnl_lock(); 2444aab9c406SFlorian Fainelli phylink_start(dp->pl); 2445aab9c406SFlorian Fainelli rtnl_unlock(); 244624462549SFlorian Fainelli 244724462549SFlorian Fainelli return 0; 244824462549SFlorian Fainelli } 244924462549SFlorian Fainelli 2450951259aaSVivien Didelot int dsa_slave_create(struct dsa_port *port) 245191da11f8SLennert Buytenhek { 24528f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(port); 24534cfbf09cSVivien Didelot struct dsa_switch *ds = port->ds; 245491da11f8SLennert Buytenhek struct net_device *slave_dev; 245591da11f8SLennert Buytenhek struct dsa_slave_priv *p; 24560171a1d2SRasmus Villemoes const char *name; 24570171a1d2SRasmus Villemoes int assign_type; 245891da11f8SLennert Buytenhek int ret; 245991da11f8SLennert Buytenhek 246055199df6SFlorian Fainelli if (!ds->num_tx_queues) 246155199df6SFlorian Fainelli ds->num_tx_queues = 1; 246255199df6SFlorian Fainelli 24630171a1d2SRasmus Villemoes if (port->name) { 24640171a1d2SRasmus Villemoes name = port->name; 24656fdb0384SRasmus Villemoes assign_type = NET_NAME_PREDICTABLE; 24660171a1d2SRasmus Villemoes } else { 24670171a1d2SRasmus Villemoes name = "eth%d"; 2468b8790661SRasmus Villemoes assign_type = NET_NAME_ENUM; 24690171a1d2SRasmus Villemoes } 24700171a1d2SRasmus Villemoes 247155199df6SFlorian Fainelli slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name, 24720171a1d2SRasmus Villemoes assign_type, ether_setup, 247355199df6SFlorian Fainelli ds->num_tx_queues, 1); 247491da11f8SLennert Buytenhek if (slave_dev == NULL) 2475d87d6f44SGuenter Roeck return -ENOMEM; 247691da11f8SLennert Buytenhek 247795f510d0SVladimir Oltean slave_dev->rtnl_link_ops = &dsa_link_ops; 24787ad24ea4SWilfried Klaebe slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 2479d538eca8SVladimir Oltean #if IS_ENABLED(CONFIG_DCB) 2480d538eca8SVladimir Oltean slave_dev->dcbnl_ops = &dsa_slave_dcbnl_ops; 2481d538eca8SVladimir Oltean #endif 248283216e39SMichael Walle if (!is_zero_ether_addr(port->mac)) 2483e35b8d7dSJakub Kicinski eth_hw_addr_set(slave_dev, port->mac); 2484a2c7023fSXiaofei Shen else 24852fcc8005SBjørn Mork eth_hw_addr_inherit(slave_dev, master); 24860a5f107bSPhil Sutter slave_dev->priv_flags |= IFF_NO_QUEUE; 24875e8a1e03SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 24885e8a1e03SVladimir Oltean slave_dev->priv_flags |= IFF_UNICAST_FLT; 24893e8a72d1SFlorian Fainelli slave_dev->netdev_ops = &dsa_slave_netdev_ops; 2490bfcb8132SVladimir Oltean if (ds->ops->port_max_mtu) 2491bfcb8132SVladimir Oltean slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index); 2492f37db85dSFlorian Fainelli SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); 2493d442ad4aSStephen Hemminger 24944cfbf09cSVivien Didelot SET_NETDEV_DEV(slave_dev, port->ds->dev); 2495ac73d4bfSJiri Pirko SET_NETDEV_DEVLINK_PORT(slave_dev, &port->devlink_port); 24964cfbf09cSVivien Didelot slave_dev->dev.of_node = port->dn; 249791da11f8SLennert Buytenhek slave_dev->vlan_features = master->vlan_features; 249891da11f8SLennert Buytenhek 249991da11f8SLennert Buytenhek p = netdev_priv(slave_dev); 25006a900628SHeiner Kallweit slave_dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 25016a900628SHeiner Kallweit if (!slave_dev->tstats) { 25025f6b4e14SFlorian Fainelli free_netdev(slave_dev); 25035f6b4e14SFlorian Fainelli return -ENOMEM; 25045f6b4e14SFlorian Fainelli } 2505e131a563SAlexander Lobakin 2506e131a563SAlexander Lobakin ret = gro_cells_init(&p->gcells, slave_dev); 2507e131a563SAlexander Lobakin if (ret) 2508e131a563SAlexander Lobakin goto out_free; 2509e131a563SAlexander Lobakin 25104cfbf09cSVivien Didelot p->dp = port; 2511f50f2127SFlorian Fainelli INIT_LIST_HEAD(&p->mall_tc_list); 2512f8b8b1cdSVivien Didelot port->slave = slave_dev; 251353da0ebaSVladimir Oltean dsa_slave_setup_tagger(slave_dev); 251491da11f8SLennert Buytenhek 251591da11f8SLennert Buytenhek netif_carrier_off(slave_dev); 251691da11f8SLennert Buytenhek 25174fa7b718SVivien Didelot ret = dsa_slave_phy_setup(slave_dev); 25180071f56eSAndrew Lunn if (ret) { 2519c9ebf126SVladimir Oltean netdev_err(slave_dev, 2520c9ebf126SVladimir Oltean "error %d setting up PHY for tree %d, switch %d, port %d\n", 2521c9ebf126SVladimir Oltean ret, ds->dst->index, ds->index, port->index); 2522e131a563SAlexander Lobakin goto out_gcells; 2523e804441cSFlorian Fainelli } 2524e804441cSFlorian Fainelli 25252f1e8ea7SVladimir Oltean rtnl_lock(); 2526e31dbd3bSVladimir Oltean 2527904e112aSVladimir Oltean ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); 2528904e112aSVladimir Oltean if (ret && ret != -EOPNOTSUPP) 2529904e112aSVladimir Oltean dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", 2530904e112aSVladimir Oltean ret, ETH_DATA_LEN, port->index); 2531904e112aSVladimir Oltean 25322f1e8ea7SVladimir Oltean ret = register_netdevice(slave_dev); 2533e804441cSFlorian Fainelli if (ret) { 2534e804441cSFlorian Fainelli netdev_err(master, "error %d registering interface %s\n", 2535e804441cSFlorian Fainelli ret, slave_dev->name); 25362f1e8ea7SVladimir Oltean rtnl_unlock(); 2537e804441cSFlorian Fainelli goto out_phy; 25380071f56eSAndrew Lunn } 25390071f56eSAndrew Lunn 2540d538eca8SVladimir Oltean if (IS_ENABLED(CONFIG_DCB)) { 2541d538eca8SVladimir Oltean ret = dsa_slave_dcbnl_init(slave_dev); 2542d538eca8SVladimir Oltean if (ret) { 2543d538eca8SVladimir Oltean netdev_err(slave_dev, 2544d538eca8SVladimir Oltean "failed to initialize DCB: %pe\n", 2545d538eca8SVladimir Oltean ERR_PTR(ret)); 2546d538eca8SVladimir Oltean rtnl_unlock(); 2547d538eca8SVladimir Oltean goto out_unregister; 2548d538eca8SVladimir Oltean } 2549d538eca8SVladimir Oltean } 2550d538eca8SVladimir Oltean 25512f1e8ea7SVladimir Oltean ret = netdev_upper_dev_link(master, slave_dev, NULL); 25522f1e8ea7SVladimir Oltean 25532f1e8ea7SVladimir Oltean rtnl_unlock(); 25542f1e8ea7SVladimir Oltean 25552f1e8ea7SVladimir Oltean if (ret) 25562f1e8ea7SVladimir Oltean goto out_unregister; 25572f1e8ea7SVladimir Oltean 2558d87d6f44SGuenter Roeck return 0; 2559e804441cSFlorian Fainelli 25602f1e8ea7SVladimir Oltean out_unregister: 25612f1e8ea7SVladimir Oltean unregister_netdev(slave_dev); 2562e804441cSFlorian Fainelli out_phy: 2563aab9c406SFlorian Fainelli rtnl_lock(); 2564aab9c406SFlorian Fainelli phylink_disconnect_phy(p->dp->pl); 2565aab9c406SFlorian Fainelli rtnl_unlock(); 2566cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(p->dp); 2567e131a563SAlexander Lobakin out_gcells: 2568e131a563SAlexander Lobakin gro_cells_destroy(&p->gcells); 2569e804441cSFlorian Fainelli out_free: 25706a900628SHeiner Kallweit free_percpu(slave_dev->tstats); 2571e804441cSFlorian Fainelli free_netdev(slave_dev); 2572f8b8b1cdSVivien Didelot port->slave = NULL; 2573e804441cSFlorian Fainelli return ret; 257491da11f8SLennert Buytenhek } 2575b73adef6SFlorian Fainelli 2576cda5c15bSNeil Armstrong void dsa_slave_destroy(struct net_device *slave_dev) 2577cda5c15bSNeil Armstrong { 25782f1e8ea7SVladimir Oltean struct net_device *master = dsa_slave_to_master(slave_dev); 2579d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2580cda5c15bSNeil Armstrong struct dsa_slave_priv *p = netdev_priv(slave_dev); 2581cda5c15bSNeil Armstrong 2582cda5c15bSNeil Armstrong netif_carrier_off(slave_dev); 2583aab9c406SFlorian Fainelli rtnl_lock(); 25842f1e8ea7SVladimir Oltean netdev_upper_dev_unlink(master, slave_dev); 25852f1e8ea7SVladimir Oltean unregister_netdevice(slave_dev); 2586aab9c406SFlorian Fainelli phylink_disconnect_phy(dp->pl); 2587aab9c406SFlorian Fainelli rtnl_unlock(); 2588881eadabSJohan Hovold 2589cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(dp); 2590e131a563SAlexander Lobakin gro_cells_destroy(&p->gcells); 25916a900628SHeiner Kallweit free_percpu(slave_dev->tstats); 2592cda5c15bSNeil Armstrong free_netdev(slave_dev); 2593cda5c15bSNeil Armstrong } 2594cda5c15bSNeil Armstrong 259595f510d0SVladimir Oltean int dsa_slave_change_master(struct net_device *dev, struct net_device *master, 259695f510d0SVladimir Oltean struct netlink_ext_ack *extack) 259795f510d0SVladimir Oltean { 259895f510d0SVladimir Oltean struct net_device *old_master = dsa_slave_to_master(dev); 259995f510d0SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 260095f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 260195f510d0SVladimir Oltean struct net_device *upper; 260295f510d0SVladimir Oltean struct list_head *iter; 260395f510d0SVladimir Oltean int err; 260495f510d0SVladimir Oltean 260595f510d0SVladimir Oltean if (master == old_master) 260695f510d0SVladimir Oltean return 0; 260795f510d0SVladimir Oltean 260895f510d0SVladimir Oltean if (!ds->ops->port_change_master) { 260995f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 261095f510d0SVladimir Oltean "Driver does not support changing DSA master"); 261195f510d0SVladimir Oltean return -EOPNOTSUPP; 261295f510d0SVladimir Oltean } 261395f510d0SVladimir Oltean 261495f510d0SVladimir Oltean if (!netdev_uses_dsa(master)) { 261595f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 261695f510d0SVladimir Oltean "Interface not eligible as DSA master"); 261795f510d0SVladimir Oltean return -EOPNOTSUPP; 261895f510d0SVladimir Oltean } 261995f510d0SVladimir Oltean 262095f510d0SVladimir Oltean netdev_for_each_upper_dev_rcu(master, upper, iter) { 262195f510d0SVladimir Oltean if (dsa_slave_dev_check(upper)) 262295f510d0SVladimir Oltean continue; 262395f510d0SVladimir Oltean if (netif_is_bridge_master(upper)) 262495f510d0SVladimir Oltean continue; 262595f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, "Cannot join master with unknown uppers"); 262695f510d0SVladimir Oltean return -EOPNOTSUPP; 262795f510d0SVladimir Oltean } 262895f510d0SVladimir Oltean 262995f510d0SVladimir Oltean /* Since we allow live-changing the DSA master, plus we auto-open the 263095f510d0SVladimir Oltean * DSA master when the user port opens => we need to ensure that the 263195f510d0SVladimir Oltean * new DSA master is open too. 263295f510d0SVladimir Oltean */ 263395f510d0SVladimir Oltean if (dev->flags & IFF_UP) { 263495f510d0SVladimir Oltean err = dev_open(master, extack); 263595f510d0SVladimir Oltean if (err) 263695f510d0SVladimir Oltean return err; 263795f510d0SVladimir Oltean } 263895f510d0SVladimir Oltean 263995f510d0SVladimir Oltean netdev_upper_dev_unlink(old_master, dev); 264095f510d0SVladimir Oltean 264195f510d0SVladimir Oltean err = netdev_upper_dev_link(master, dev, extack); 264295f510d0SVladimir Oltean if (err) 264395f510d0SVladimir Oltean goto out_revert_old_master_unlink; 264495f510d0SVladimir Oltean 264595f510d0SVladimir Oltean err = dsa_port_change_master(dp, master, extack); 264695f510d0SVladimir Oltean if (err) 264795f510d0SVladimir Oltean goto out_revert_master_link; 264895f510d0SVladimir Oltean 264995f510d0SVladimir Oltean /* Update the MTU of the new CPU port through cross-chip notifiers */ 265095f510d0SVladimir Oltean err = dsa_slave_change_mtu(dev, dev->mtu); 265195f510d0SVladimir Oltean if (err && err != -EOPNOTSUPP) { 265295f510d0SVladimir Oltean netdev_warn(dev, 265395f510d0SVladimir Oltean "nonfatal error updating MTU with new master: %pe\n", 265495f510d0SVladimir Oltean ERR_PTR(err)); 265595f510d0SVladimir Oltean } 265695f510d0SVladimir Oltean 265795f510d0SVladimir Oltean /* If the port doesn't have its own MAC address and relies on the DSA 265895f510d0SVladimir Oltean * master's one, inherit it again from the new DSA master. 265995f510d0SVladimir Oltean */ 266095f510d0SVladimir Oltean if (is_zero_ether_addr(dp->mac)) 266195f510d0SVladimir Oltean eth_hw_addr_inherit(dev, master); 266295f510d0SVladimir Oltean 266395f510d0SVladimir Oltean return 0; 266495f510d0SVladimir Oltean 266595f510d0SVladimir Oltean out_revert_master_link: 266695f510d0SVladimir Oltean netdev_upper_dev_unlink(master, dev); 266795f510d0SVladimir Oltean out_revert_old_master_unlink: 266895f510d0SVladimir Oltean netdev_upper_dev_link(old_master, dev, NULL); 266995f510d0SVladimir Oltean return err; 267095f510d0SVladimir Oltean } 267195f510d0SVladimir Oltean 26724d776482SFlorian Fainelli bool dsa_slave_dev_check(const struct net_device *dev) 2673b73adef6SFlorian Fainelli { 2674b73adef6SFlorian Fainelli return dev->netdev_ops == &dsa_slave_netdev_ops; 2675b73adef6SFlorian Fainelli } 2676a5e3c9baSVladimir Oltean EXPORT_SYMBOL_GPL(dsa_slave_dev_check); 2677b73adef6SFlorian Fainelli 26788e92ab3aSVivien Didelot static int dsa_slave_changeupper(struct net_device *dev, 26798e92ab3aSVivien Didelot struct netdev_notifier_changeupper_info *info) 2680b73adef6SFlorian Fainelli { 2681d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 26822afc526aSVladimir Oltean struct netlink_ext_ack *extack; 26838e92ab3aSVivien Didelot int err = NOTIFY_DONE; 2684b73adef6SFlorian Fainelli 26854c3f80d2SVladimir Oltean if (!dsa_slave_dev_check(dev)) 26864c3f80d2SVladimir Oltean return err; 26874c3f80d2SVladimir Oltean 26882afc526aSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 26892afc526aSVladimir Oltean 26908e92ab3aSVivien Didelot if (netif_is_bridge_master(info->upper_dev)) { 26918e92ab3aSVivien Didelot if (info->linking) { 26922afc526aSVladimir Oltean err = dsa_port_bridge_join(dp, info->upper_dev, extack); 2693bff33f7eSVladimir Oltean if (!err) 2694bff33f7eSVladimir Oltean dsa_bridge_mtu_normalization(dp); 269567b5fb5dSVladimir Oltean if (err == -EOPNOTSUPP) { 2696d795527dSVladimir Oltean NL_SET_ERR_MSG_WEAK_MOD(extack, 2697d795527dSVladimir Oltean "Offloading not supported"); 269867b5fb5dSVladimir Oltean err = 0; 269967b5fb5dSVladimir Oltean } 27008e92ab3aSVivien Didelot err = notifier_from_errno(err); 27018e92ab3aSVivien Didelot } else { 270217d7802bSVivien Didelot dsa_port_bridge_leave(dp, info->upper_dev); 27038e92ab3aSVivien Didelot err = NOTIFY_OK; 27048e92ab3aSVivien Didelot } 2705058102a6STobias Waldekranz } else if (netif_is_lag_master(info->upper_dev)) { 2706058102a6STobias Waldekranz if (info->linking) { 2707058102a6STobias Waldekranz err = dsa_port_lag_join(dp, info->upper_dev, 27082afc526aSVladimir Oltean info->upper_info, extack); 2709058102a6STobias Waldekranz if (err == -EOPNOTSUPP) { 2710d795527dSVladimir Oltean NL_SET_ERR_MSG_WEAK_MOD(extack, 2711058102a6STobias Waldekranz "Offloading not supported"); 2712058102a6STobias Waldekranz err = 0; 2713058102a6STobias Waldekranz } 2714058102a6STobias Waldekranz err = notifier_from_errno(err); 2715058102a6STobias Waldekranz } else { 2716058102a6STobias Waldekranz dsa_port_lag_leave(dp, info->upper_dev); 2717058102a6STobias Waldekranz err = NOTIFY_OK; 2718058102a6STobias Waldekranz } 271918596f50SGeorge McCollister } else if (is_hsr_master(info->upper_dev)) { 272018596f50SGeorge McCollister if (info->linking) { 272118596f50SGeorge McCollister err = dsa_port_hsr_join(dp, info->upper_dev); 272218596f50SGeorge McCollister if (err == -EOPNOTSUPP) { 2723d795527dSVladimir Oltean NL_SET_ERR_MSG_WEAK_MOD(extack, 272418596f50SGeorge McCollister "Offloading not supported"); 272518596f50SGeorge McCollister err = 0; 272618596f50SGeorge McCollister } 272718596f50SGeorge McCollister err = notifier_from_errno(err); 272818596f50SGeorge McCollister } else { 272918596f50SGeorge McCollister dsa_port_hsr_leave(dp, info->upper_dev); 273018596f50SGeorge McCollister err = NOTIFY_OK; 273118596f50SGeorge McCollister } 2732058102a6STobias Waldekranz } 2733058102a6STobias Waldekranz 2734058102a6STobias Waldekranz return err; 2735058102a6STobias Waldekranz } 2736058102a6STobias Waldekranz 273774918945SVladimir Oltean static int dsa_slave_prechangeupper(struct net_device *dev, 273874918945SVladimir Oltean struct netdev_notifier_changeupper_info *info) 273974918945SVladimir Oltean { 274074918945SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 274174918945SVladimir Oltean 27424c3f80d2SVladimir Oltean if (!dsa_slave_dev_check(dev)) 27434c3f80d2SVladimir Oltean return NOTIFY_DONE; 27444c3f80d2SVladimir Oltean 274574918945SVladimir Oltean if (netif_is_bridge_master(info->upper_dev) && !info->linking) 27464e51bf44SVladimir Oltean dsa_port_pre_bridge_leave(dp, info->upper_dev); 274774918945SVladimir Oltean else if (netif_is_lag_master(info->upper_dev) && !info->linking) 27484e51bf44SVladimir Oltean dsa_port_pre_lag_leave(dp, info->upper_dev); 274974918945SVladimir Oltean /* dsa_port_pre_hsr_leave is not yet necessary since hsr cannot be 275074918945SVladimir Oltean * meaningfully enslaved to a bridge yet 275174918945SVladimir Oltean */ 275274918945SVladimir Oltean 27534e51bf44SVladimir Oltean return NOTIFY_DONE; 275474918945SVladimir Oltean } 275574918945SVladimir Oltean 2756058102a6STobias Waldekranz static int 2757058102a6STobias Waldekranz dsa_slave_lag_changeupper(struct net_device *dev, 2758058102a6STobias Waldekranz struct netdev_notifier_changeupper_info *info) 2759058102a6STobias Waldekranz { 2760058102a6STobias Waldekranz struct net_device *lower; 2761058102a6STobias Waldekranz struct list_head *iter; 2762058102a6STobias Waldekranz int err = NOTIFY_DONE; 2763058102a6STobias Waldekranz struct dsa_port *dp; 2764058102a6STobias Waldekranz 27654c3f80d2SVladimir Oltean if (!netif_is_lag_master(dev)) 27664c3f80d2SVladimir Oltean return err; 27674c3f80d2SVladimir Oltean 2768058102a6STobias Waldekranz netdev_for_each_lower_dev(dev, lower, iter) { 2769058102a6STobias Waldekranz if (!dsa_slave_dev_check(lower)) 2770058102a6STobias Waldekranz continue; 2771058102a6STobias Waldekranz 2772058102a6STobias Waldekranz dp = dsa_slave_to_port(lower); 2773dedd6a00SVladimir Oltean if (!dp->lag) 2774058102a6STobias Waldekranz /* Software LAG */ 2775058102a6STobias Waldekranz continue; 2776058102a6STobias Waldekranz 2777058102a6STobias Waldekranz err = dsa_slave_changeupper(lower, info); 2778058102a6STobias Waldekranz if (notifier_to_errno(err)) 2779058102a6STobias Waldekranz break; 27806debb68aSVivien Didelot } 2781b73adef6SFlorian Fainelli 27828e92ab3aSVivien Didelot return err; 2783b73adef6SFlorian Fainelli } 2784b73adef6SFlorian Fainelli 278574918945SVladimir Oltean /* Same as dsa_slave_lag_changeupper() except that it calls 278674918945SVladimir Oltean * dsa_slave_prechangeupper() 278774918945SVladimir Oltean */ 278874918945SVladimir Oltean static int 278974918945SVladimir Oltean dsa_slave_lag_prechangeupper(struct net_device *dev, 279074918945SVladimir Oltean struct netdev_notifier_changeupper_info *info) 279174918945SVladimir Oltean { 279274918945SVladimir Oltean struct net_device *lower; 279374918945SVladimir Oltean struct list_head *iter; 279474918945SVladimir Oltean int err = NOTIFY_DONE; 279574918945SVladimir Oltean struct dsa_port *dp; 279674918945SVladimir Oltean 27974c3f80d2SVladimir Oltean if (!netif_is_lag_master(dev)) 27984c3f80d2SVladimir Oltean return err; 27994c3f80d2SVladimir Oltean 280074918945SVladimir Oltean netdev_for_each_lower_dev(dev, lower, iter) { 280174918945SVladimir Oltean if (!dsa_slave_dev_check(lower)) 280274918945SVladimir Oltean continue; 280374918945SVladimir Oltean 280474918945SVladimir Oltean dp = dsa_slave_to_port(lower); 2805dedd6a00SVladimir Oltean if (!dp->lag) 280674918945SVladimir Oltean /* Software LAG */ 280774918945SVladimir Oltean continue; 280874918945SVladimir Oltean 280974918945SVladimir Oltean err = dsa_slave_prechangeupper(lower, info); 281074918945SVladimir Oltean if (notifier_to_errno(err)) 281174918945SVladimir Oltean break; 281274918945SVladimir Oltean } 281374918945SVladimir Oltean 281474918945SVladimir Oltean return err; 281574918945SVladimir Oltean } 281674918945SVladimir Oltean 2817eb46e8daSVladimir Oltean static int 2818eb46e8daSVladimir Oltean dsa_prevent_bridging_8021q_upper(struct net_device *dev, 2819eb46e8daSVladimir Oltean struct netdev_notifier_changeupper_info *info) 2820cc1d5bdaSFlorian Fainelli { 2821cc1d5bdaSFlorian Fainelli struct netlink_ext_ack *ext_ack; 282236cbf39bSVladimir Oltean struct net_device *slave, *br; 2823cc1d5bdaSFlorian Fainelli struct dsa_port *dp; 2824cc1d5bdaSFlorian Fainelli 2825cc1d5bdaSFlorian Fainelli ext_ack = netdev_notifier_info_to_extack(&info->info); 2826cc1d5bdaSFlorian Fainelli 2827cc1d5bdaSFlorian Fainelli if (!is_vlan_dev(dev)) 2828cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2829cc1d5bdaSFlorian Fainelli 2830cc1d5bdaSFlorian Fainelli slave = vlan_dev_real_dev(dev); 2831cc1d5bdaSFlorian Fainelli if (!dsa_slave_dev_check(slave)) 2832cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2833cc1d5bdaSFlorian Fainelli 2834cc1d5bdaSFlorian Fainelli dp = dsa_slave_to_port(slave); 283536cbf39bSVladimir Oltean br = dsa_port_bridge_dev_get(dp); 283636cbf39bSVladimir Oltean if (!br) 2837cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2838cc1d5bdaSFlorian Fainelli 2839cc1d5bdaSFlorian Fainelli /* Deny enslaving a VLAN device into a VLAN-aware bridge */ 284036cbf39bSVladimir Oltean if (br_vlan_enabled(br) && 2841cc1d5bdaSFlorian Fainelli netif_is_bridge_master(info->upper_dev) && info->linking) { 2842cc1d5bdaSFlorian Fainelli NL_SET_ERR_MSG_MOD(ext_ack, 2843cc1d5bdaSFlorian Fainelli "Cannot enslave VLAN device into VLAN aware bridge"); 2844cc1d5bdaSFlorian Fainelli return notifier_from_errno(-EINVAL); 2845cc1d5bdaSFlorian Fainelli } 2846cc1d5bdaSFlorian Fainelli 2847cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2848cc1d5bdaSFlorian Fainelli } 2849cc1d5bdaSFlorian Fainelli 28502b138406SVladimir Oltean static int 28512b138406SVladimir Oltean dsa_slave_check_8021q_upper(struct net_device *dev, 28522b138406SVladimir Oltean struct netdev_notifier_changeupper_info *info) 28532b138406SVladimir Oltean { 28542b138406SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 285536cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 28562b138406SVladimir Oltean struct bridge_vlan_info br_info; 28572b138406SVladimir Oltean struct netlink_ext_ack *extack; 28582b138406SVladimir Oltean int err = NOTIFY_DONE; 28592b138406SVladimir Oltean u16 vid; 28602b138406SVladimir Oltean 2861adb256ebSVladimir Oltean if (!br || !br_vlan_enabled(br)) 28622b138406SVladimir Oltean return NOTIFY_DONE; 28632b138406SVladimir Oltean 28642b138406SVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 28652b138406SVladimir Oltean vid = vlan_dev_vlan_id(info->upper_dev); 28662b138406SVladimir Oltean 28672b138406SVladimir Oltean /* br_vlan_get_info() returns -EINVAL or -ENOENT if the 28682b138406SVladimir Oltean * device, respectively the VID is not found, returning 28692b138406SVladimir Oltean * 0 means success, which is a failure for us here. 28702b138406SVladimir Oltean */ 28712b138406SVladimir Oltean err = br_vlan_get_info(br, vid, &br_info); 28722b138406SVladimir Oltean if (err == 0) { 28732b138406SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 28742b138406SVladimir Oltean "This VLAN is already configured by the bridge"); 28752b138406SVladimir Oltean return notifier_from_errno(-EBUSY); 28762b138406SVladimir Oltean } 28772b138406SVladimir Oltean 28782b138406SVladimir Oltean return NOTIFY_DONE; 28792b138406SVladimir Oltean } 28802b138406SVladimir Oltean 28814ede74e7SVladimir Oltean static int 28824ede74e7SVladimir Oltean dsa_slave_prechangeupper_sanity_check(struct net_device *dev, 28834ede74e7SVladimir Oltean struct netdev_notifier_changeupper_info *info) 2884b73adef6SFlorian Fainelli { 2885e358bef7SVladimir Oltean struct dsa_switch *ds; 2886e358bef7SVladimir Oltean struct dsa_port *dp; 2887e358bef7SVladimir Oltean int err; 28882b138406SVladimir Oltean 288953bade8aSFlorian Fainelli if (!dsa_slave_dev_check(dev)) 28904ede74e7SVladimir Oltean return dsa_prevent_bridging_8021q_upper(dev, info); 28912b138406SVladimir Oltean 2892e358bef7SVladimir Oltean dp = dsa_slave_to_port(dev); 2893e358bef7SVladimir Oltean ds = dp->ds; 2894e358bef7SVladimir Oltean 2895e358bef7SVladimir Oltean if (ds->ops->port_prechangeupper) { 2896e358bef7SVladimir Oltean err = ds->ops->port_prechangeupper(ds, dp->index, info); 2897e358bef7SVladimir Oltean if (err) 2898e358bef7SVladimir Oltean return notifier_from_errno(err); 2899e358bef7SVladimir Oltean } 2900e358bef7SVladimir Oltean 29012b138406SVladimir Oltean if (is_vlan_dev(info->upper_dev)) 29024ede74e7SVladimir Oltean return dsa_slave_check_8021q_upper(dev, info); 29034ede74e7SVladimir Oltean 29044ede74e7SVladimir Oltean return NOTIFY_DONE; 29054ede74e7SVladimir Oltean } 29064ede74e7SVladimir Oltean 2907acc43b7bSVladimir Oltean /* To be eligible as a DSA master, a LAG must have all lower interfaces be 2908acc43b7bSVladimir Oltean * eligible DSA masters. Additionally, all LAG slaves must be DSA masters of 2909acc43b7bSVladimir Oltean * switches in the same switch tree. 2910acc43b7bSVladimir Oltean */ 2911acc43b7bSVladimir Oltean static int dsa_lag_master_validate(struct net_device *lag_dev, 2912acc43b7bSVladimir Oltean struct netlink_ext_ack *extack) 2913acc43b7bSVladimir Oltean { 2914acc43b7bSVladimir Oltean struct net_device *lower1, *lower2; 2915acc43b7bSVladimir Oltean struct list_head *iter1, *iter2; 2916acc43b7bSVladimir Oltean 2917acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower1, iter1) { 2918acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower2, iter2) { 2919acc43b7bSVladimir Oltean if (!netdev_uses_dsa(lower1) || 2920acc43b7bSVladimir Oltean !netdev_uses_dsa(lower2)) { 2921acc43b7bSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 2922acc43b7bSVladimir Oltean "All LAG ports must be eligible as DSA masters"); 2923acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2924acc43b7bSVladimir Oltean } 2925acc43b7bSVladimir Oltean 2926acc43b7bSVladimir Oltean if (lower1 == lower2) 2927acc43b7bSVladimir Oltean continue; 2928acc43b7bSVladimir Oltean 2929acc43b7bSVladimir Oltean if (!dsa_port_tree_same(lower1->dsa_ptr, 2930acc43b7bSVladimir Oltean lower2->dsa_ptr)) { 2931acc43b7bSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 2932acc43b7bSVladimir Oltean "LAG contains DSA masters of disjoint switch trees"); 2933acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2934acc43b7bSVladimir Oltean } 2935acc43b7bSVladimir Oltean } 2936acc43b7bSVladimir Oltean } 2937acc43b7bSVladimir Oltean 2938acc43b7bSVladimir Oltean return NOTIFY_DONE; 2939acc43b7bSVladimir Oltean } 2940acc43b7bSVladimir Oltean 29414f03dcc6SVladimir Oltean static int 29424f03dcc6SVladimir Oltean dsa_master_prechangeupper_sanity_check(struct net_device *master, 29434f03dcc6SVladimir Oltean struct netdev_notifier_changeupper_info *info) 29444f03dcc6SVladimir Oltean { 2945acc43b7bSVladimir Oltean struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); 29464f03dcc6SVladimir Oltean 29474f03dcc6SVladimir Oltean if (!netdev_uses_dsa(master)) 29484f03dcc6SVladimir Oltean return NOTIFY_DONE; 29494f03dcc6SVladimir Oltean 29504f03dcc6SVladimir Oltean if (!info->linking) 29514f03dcc6SVladimir Oltean return NOTIFY_DONE; 29524f03dcc6SVladimir Oltean 29534f03dcc6SVladimir Oltean /* Allow DSA switch uppers */ 29544f03dcc6SVladimir Oltean if (dsa_slave_dev_check(info->upper_dev)) 29554f03dcc6SVladimir Oltean return NOTIFY_DONE; 29564f03dcc6SVladimir Oltean 29574f03dcc6SVladimir Oltean /* Allow bridge uppers of DSA masters, subject to further 29584f03dcc6SVladimir Oltean * restrictions in dsa_bridge_prechangelower_sanity_check() 29594f03dcc6SVladimir Oltean */ 29604f03dcc6SVladimir Oltean if (netif_is_bridge_master(info->upper_dev)) 29614f03dcc6SVladimir Oltean return NOTIFY_DONE; 29624f03dcc6SVladimir Oltean 2963acc43b7bSVladimir Oltean /* Allow LAG uppers, subject to further restrictions in 2964acc43b7bSVladimir Oltean * dsa_lag_master_prechangelower_sanity_check() 2965acc43b7bSVladimir Oltean */ 2966acc43b7bSVladimir Oltean if (netif_is_lag_master(info->upper_dev)) 2967acc43b7bSVladimir Oltean return dsa_lag_master_validate(info->upper_dev, extack); 29684f03dcc6SVladimir Oltean 29694f03dcc6SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 29704f03dcc6SVladimir Oltean "DSA master cannot join unknown upper interfaces"); 29714f03dcc6SVladimir Oltean return notifier_from_errno(-EBUSY); 29724f03dcc6SVladimir Oltean } 29734f03dcc6SVladimir Oltean 2974acc43b7bSVladimir Oltean static int 2975acc43b7bSVladimir Oltean dsa_lag_master_prechangelower_sanity_check(struct net_device *dev, 2976acc43b7bSVladimir Oltean struct netdev_notifier_changeupper_info *info) 2977acc43b7bSVladimir Oltean { 2978acc43b7bSVladimir Oltean struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); 2979acc43b7bSVladimir Oltean struct net_device *lag_dev = info->upper_dev; 2980acc43b7bSVladimir Oltean struct net_device *lower; 2981acc43b7bSVladimir Oltean struct list_head *iter; 2982acc43b7bSVladimir Oltean 2983acc43b7bSVladimir Oltean if (!netdev_uses_dsa(lag_dev) || !netif_is_lag_master(lag_dev)) 2984acc43b7bSVladimir Oltean return NOTIFY_DONE; 2985acc43b7bSVladimir Oltean 2986acc43b7bSVladimir Oltean if (!info->linking) 2987acc43b7bSVladimir Oltean return NOTIFY_DONE; 2988acc43b7bSVladimir Oltean 2989acc43b7bSVladimir Oltean if (!netdev_uses_dsa(dev)) { 2990acc43b7bSVladimir Oltean NL_SET_ERR_MSG(extack, 2991acc43b7bSVladimir Oltean "Only DSA masters can join a LAG DSA master"); 2992acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2993acc43b7bSVladimir Oltean } 2994acc43b7bSVladimir Oltean 2995acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower, iter) { 2996acc43b7bSVladimir Oltean if (!dsa_port_tree_same(dev->dsa_ptr, lower->dsa_ptr)) { 2997acc43b7bSVladimir Oltean NL_SET_ERR_MSG(extack, 2998acc43b7bSVladimir Oltean "Interface is DSA master for a different switch tree than this LAG"); 2999acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 3000acc43b7bSVladimir Oltean } 3001acc43b7bSVladimir Oltean 3002acc43b7bSVladimir Oltean break; 3003acc43b7bSVladimir Oltean } 3004acc43b7bSVladimir Oltean 3005acc43b7bSVladimir Oltean return NOTIFY_DONE; 3006acc43b7bSVladimir Oltean } 3007acc43b7bSVladimir Oltean 3008920a33cdSVladimir Oltean /* Don't allow bridging of DSA masters, since the bridge layer rx_handler 3009920a33cdSVladimir Oltean * prevents the DSA fake ethertype handler to be invoked, so we don't get the 3010920a33cdSVladimir Oltean * chance to strip off and parse the DSA switch tag protocol header (the bridge 3011920a33cdSVladimir Oltean * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these 3012920a33cdSVladimir Oltean * frames). 3013920a33cdSVladimir Oltean * The only case where that would not be an issue is when bridging can already 3014920a33cdSVladimir Oltean * be offloaded, such as when the DSA master is itself a DSA or plain switchdev 3015920a33cdSVladimir Oltean * port, and is bridged only with other ports from the same hardware device. 3016920a33cdSVladimir Oltean */ 3017920a33cdSVladimir Oltean static int 3018920a33cdSVladimir Oltean dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower, 3019920a33cdSVladimir Oltean struct netdev_notifier_changeupper_info *info) 3020920a33cdSVladimir Oltean { 3021920a33cdSVladimir Oltean struct net_device *br = info->upper_dev; 3022920a33cdSVladimir Oltean struct netlink_ext_ack *extack; 3023920a33cdSVladimir Oltean struct net_device *lower; 3024920a33cdSVladimir Oltean struct list_head *iter; 3025920a33cdSVladimir Oltean 3026920a33cdSVladimir Oltean if (!netif_is_bridge_master(br)) 3027920a33cdSVladimir Oltean return NOTIFY_DONE; 3028920a33cdSVladimir Oltean 3029920a33cdSVladimir Oltean if (!info->linking) 3030920a33cdSVladimir Oltean return NOTIFY_DONE; 3031920a33cdSVladimir Oltean 3032920a33cdSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 3033920a33cdSVladimir Oltean 3034920a33cdSVladimir Oltean netdev_for_each_lower_dev(br, lower, iter) { 3035920a33cdSVladimir Oltean if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower)) 3036920a33cdSVladimir Oltean continue; 3037920a33cdSVladimir Oltean 3038920a33cdSVladimir Oltean if (!netdev_port_same_parent_id(lower, new_lower)) { 3039920a33cdSVladimir Oltean NL_SET_ERR_MSG(extack, 3040920a33cdSVladimir Oltean "Cannot do software bridging with a DSA master"); 3041920a33cdSVladimir Oltean return notifier_from_errno(-EINVAL); 3042920a33cdSVladimir Oltean } 3043920a33cdSVladimir Oltean } 3044920a33cdSVladimir Oltean 3045920a33cdSVladimir Oltean return NOTIFY_DONE; 3046920a33cdSVladimir Oltean } 3047920a33cdSVladimir Oltean 3048acc43b7bSVladimir Oltean static void dsa_tree_migrate_ports_from_lag_master(struct dsa_switch_tree *dst, 3049acc43b7bSVladimir Oltean struct net_device *lag_dev) 3050acc43b7bSVladimir Oltean { 3051acc43b7bSVladimir Oltean struct net_device *new_master = dsa_tree_find_first_master(dst); 3052acc43b7bSVladimir Oltean struct dsa_port *dp; 3053acc43b7bSVladimir Oltean int err; 3054acc43b7bSVladimir Oltean 3055acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) { 3056acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != lag_dev) 3057acc43b7bSVladimir Oltean continue; 3058acc43b7bSVladimir Oltean 3059acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, new_master, NULL); 3060acc43b7bSVladimir Oltean if (err) { 3061acc43b7bSVladimir Oltean netdev_err(dp->slave, 3062acc43b7bSVladimir Oltean "failed to restore master to %s: %pe\n", 3063acc43b7bSVladimir Oltean new_master->name, ERR_PTR(err)); 3064acc43b7bSVladimir Oltean } 3065acc43b7bSVladimir Oltean } 3066acc43b7bSVladimir Oltean } 3067acc43b7bSVladimir Oltean 3068acc43b7bSVladimir Oltean static int dsa_master_lag_join(struct net_device *master, 3069acc43b7bSVladimir Oltean struct net_device *lag_dev, 3070acc43b7bSVladimir Oltean struct netdev_lag_upper_info *uinfo, 3071acc43b7bSVladimir Oltean struct netlink_ext_ack *extack) 3072acc43b7bSVladimir Oltean { 3073acc43b7bSVladimir Oltean struct dsa_port *cpu_dp = master->dsa_ptr; 3074acc43b7bSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->dst; 3075acc43b7bSVladimir Oltean struct dsa_port *dp; 3076acc43b7bSVladimir Oltean int err; 3077acc43b7bSVladimir Oltean 3078acc43b7bSVladimir Oltean err = dsa_master_lag_setup(lag_dev, cpu_dp, uinfo, extack); 3079acc43b7bSVladimir Oltean if (err) 3080acc43b7bSVladimir Oltean return err; 3081acc43b7bSVladimir Oltean 3082acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) { 3083acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != master) 3084acc43b7bSVladimir Oltean continue; 3085acc43b7bSVladimir Oltean 3086acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, lag_dev, extack); 3087acc43b7bSVladimir Oltean if (err) 3088acc43b7bSVladimir Oltean goto restore; 3089acc43b7bSVladimir Oltean } 3090acc43b7bSVladimir Oltean 3091acc43b7bSVladimir Oltean return 0; 3092acc43b7bSVladimir Oltean 3093acc43b7bSVladimir Oltean restore: 3094acc43b7bSVladimir Oltean dsa_tree_for_each_user_port_continue_reverse(dp, dst) { 3095acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != lag_dev) 3096acc43b7bSVladimir Oltean continue; 3097acc43b7bSVladimir Oltean 3098acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, master, NULL); 3099acc43b7bSVladimir Oltean if (err) { 3100acc43b7bSVladimir Oltean netdev_err(dp->slave, 3101acc43b7bSVladimir Oltean "failed to restore master to %s: %pe\n", 3102acc43b7bSVladimir Oltean master->name, ERR_PTR(err)); 3103acc43b7bSVladimir Oltean } 3104acc43b7bSVladimir Oltean } 3105acc43b7bSVladimir Oltean 3106acc43b7bSVladimir Oltean dsa_master_lag_teardown(lag_dev, master->dsa_ptr); 3107acc43b7bSVladimir Oltean 3108acc43b7bSVladimir Oltean return err; 3109acc43b7bSVladimir Oltean } 3110acc43b7bSVladimir Oltean 3111acc43b7bSVladimir Oltean static void dsa_master_lag_leave(struct net_device *master, 3112acc43b7bSVladimir Oltean struct net_device *lag_dev) 3113acc43b7bSVladimir Oltean { 3114acc43b7bSVladimir Oltean struct dsa_port *dp, *cpu_dp = lag_dev->dsa_ptr; 3115acc43b7bSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->dst; 3116acc43b7bSVladimir Oltean struct dsa_port *new_cpu_dp = NULL; 3117acc43b7bSVladimir Oltean struct net_device *lower; 3118acc43b7bSVladimir Oltean struct list_head *iter; 3119acc43b7bSVladimir Oltean 3120acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower, iter) { 3121acc43b7bSVladimir Oltean if (netdev_uses_dsa(lower)) { 3122acc43b7bSVladimir Oltean new_cpu_dp = lower->dsa_ptr; 3123acc43b7bSVladimir Oltean break; 3124acc43b7bSVladimir Oltean } 3125acc43b7bSVladimir Oltean } 3126acc43b7bSVladimir Oltean 3127acc43b7bSVladimir Oltean if (new_cpu_dp) { 3128acc43b7bSVladimir Oltean /* Update the CPU port of the user ports still under the LAG 3129acc43b7bSVladimir Oltean * so that dsa_port_to_master() continues to work properly 3130acc43b7bSVladimir Oltean */ 3131acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) 3132acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) == lag_dev) 3133acc43b7bSVladimir Oltean dp->cpu_dp = new_cpu_dp; 3134acc43b7bSVladimir Oltean 3135acc43b7bSVladimir Oltean /* Update the index of the virtual CPU port to match the lowest 3136acc43b7bSVladimir Oltean * physical CPU port 3137acc43b7bSVladimir Oltean */ 3138acc43b7bSVladimir Oltean lag_dev->dsa_ptr = new_cpu_dp; 3139acc43b7bSVladimir Oltean wmb(); 3140acc43b7bSVladimir Oltean } else { 3141acc43b7bSVladimir Oltean /* If the LAG DSA master has no ports left, migrate back all 3142acc43b7bSVladimir Oltean * user ports to the first physical CPU port 3143acc43b7bSVladimir Oltean */ 3144acc43b7bSVladimir Oltean dsa_tree_migrate_ports_from_lag_master(dst, lag_dev); 3145acc43b7bSVladimir Oltean } 3146acc43b7bSVladimir Oltean 3147acc43b7bSVladimir Oltean /* This DSA master has left its LAG in any case, so let 3148acc43b7bSVladimir Oltean * the CPU port leave the hardware LAG as well 3149acc43b7bSVladimir Oltean */ 3150acc43b7bSVladimir Oltean dsa_master_lag_teardown(lag_dev, master->dsa_ptr); 3151acc43b7bSVladimir Oltean } 3152acc43b7bSVladimir Oltean 3153acc43b7bSVladimir Oltean static int dsa_master_changeupper(struct net_device *dev, 3154acc43b7bSVladimir Oltean struct netdev_notifier_changeupper_info *info) 3155acc43b7bSVladimir Oltean { 3156acc43b7bSVladimir Oltean struct netlink_ext_ack *extack; 3157acc43b7bSVladimir Oltean int err = NOTIFY_DONE; 3158acc43b7bSVladimir Oltean 3159acc43b7bSVladimir Oltean if (!netdev_uses_dsa(dev)) 3160acc43b7bSVladimir Oltean return err; 3161acc43b7bSVladimir Oltean 3162acc43b7bSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 3163acc43b7bSVladimir Oltean 3164acc43b7bSVladimir Oltean if (netif_is_lag_master(info->upper_dev)) { 3165acc43b7bSVladimir Oltean if (info->linking) { 3166acc43b7bSVladimir Oltean err = dsa_master_lag_join(dev, info->upper_dev, 3167acc43b7bSVladimir Oltean info->upper_info, extack); 3168acc43b7bSVladimir Oltean err = notifier_from_errno(err); 3169acc43b7bSVladimir Oltean } else { 3170acc43b7bSVladimir Oltean dsa_master_lag_leave(dev, info->upper_dev); 3171acc43b7bSVladimir Oltean err = NOTIFY_OK; 3172acc43b7bSVladimir Oltean } 3173acc43b7bSVladimir Oltean } 3174acc43b7bSVladimir Oltean 3175acc43b7bSVladimir Oltean return err; 3176acc43b7bSVladimir Oltean } 3177acc43b7bSVladimir Oltean 31784ede74e7SVladimir Oltean static int dsa_slave_netdevice_event(struct notifier_block *nb, 31794ede74e7SVladimir Oltean unsigned long event, void *ptr) 31804ede74e7SVladimir Oltean { 31814ede74e7SVladimir Oltean struct net_device *dev = netdev_notifier_info_to_dev(ptr); 31824ede74e7SVladimir Oltean 31834ede74e7SVladimir Oltean switch (event) { 31844ede74e7SVladimir Oltean case NETDEV_PRECHANGEUPPER: { 31854ede74e7SVladimir Oltean struct netdev_notifier_changeupper_info *info = ptr; 31864ede74e7SVladimir Oltean int err; 31874ede74e7SVladimir Oltean 31884ede74e7SVladimir Oltean err = dsa_slave_prechangeupper_sanity_check(dev, info); 31890498277eSVladimir Oltean if (notifier_to_errno(err)) 31904ede74e7SVladimir Oltean return err; 31914ede74e7SVladimir Oltean 31924f03dcc6SVladimir Oltean err = dsa_master_prechangeupper_sanity_check(dev, info); 31934f03dcc6SVladimir Oltean if (notifier_to_errno(err)) 31944f03dcc6SVladimir Oltean return err; 31954f03dcc6SVladimir Oltean 3196acc43b7bSVladimir Oltean err = dsa_lag_master_prechangelower_sanity_check(dev, info); 3197acc43b7bSVladimir Oltean if (notifier_to_errno(err)) 3198acc43b7bSVladimir Oltean return err; 3199acc43b7bSVladimir Oltean 3200920a33cdSVladimir Oltean err = dsa_bridge_prechangelower_sanity_check(dev, info); 3201920a33cdSVladimir Oltean if (notifier_to_errno(err)) 3202920a33cdSVladimir Oltean return err; 3203920a33cdSVladimir Oltean 32044c3f80d2SVladimir Oltean err = dsa_slave_prechangeupper(dev, ptr); 32054c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 32064c3f80d2SVladimir Oltean return err; 320774918945SVladimir Oltean 32084c3f80d2SVladimir Oltean err = dsa_slave_lag_prechangeupper(dev, ptr); 32094c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 32104c3f80d2SVladimir Oltean return err; 321174918945SVladimir Oltean 321283501299SVladimir Oltean break; 32132b138406SVladimir Oltean } 32144c3f80d2SVladimir Oltean case NETDEV_CHANGEUPPER: { 32154c3f80d2SVladimir Oltean int err; 3216058102a6STobias Waldekranz 32174c3f80d2SVladimir Oltean err = dsa_slave_changeupper(dev, ptr); 32184c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 32194c3f80d2SVladimir Oltean return err; 32204c3f80d2SVladimir Oltean 32214c3f80d2SVladimir Oltean err = dsa_slave_lag_changeupper(dev, ptr); 32224c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 32234c3f80d2SVladimir Oltean return err; 3224058102a6STobias Waldekranz 3225acc43b7bSVladimir Oltean err = dsa_master_changeupper(dev, ptr); 3226acc43b7bSVladimir Oltean if (notifier_to_errno(err)) 3227acc43b7bSVladimir Oltean return err; 3228acc43b7bSVladimir Oltean 3229058102a6STobias Waldekranz break; 32304c3f80d2SVladimir Oltean } 3231058102a6STobias Waldekranz case NETDEV_CHANGELOWERSTATE: { 3232058102a6STobias Waldekranz struct netdev_notifier_changelowerstate_info *info = ptr; 3233058102a6STobias Waldekranz struct dsa_port *dp; 32340a6d58a7SDan Carpenter int err = 0; 3235058102a6STobias Waldekranz 3236acc43b7bSVladimir Oltean if (dsa_slave_dev_check(dev)) { 3237058102a6STobias Waldekranz dp = dsa_slave_to_port(dev); 3238058102a6STobias Waldekranz 3239058102a6STobias Waldekranz err = dsa_port_lag_change(dp, info->lower_state_info); 3240acc43b7bSVladimir Oltean } 3241acc43b7bSVladimir Oltean 3242acc43b7bSVladimir Oltean /* Mirror LAG port events on DSA masters that are in 3243acc43b7bSVladimir Oltean * a LAG towards their respective switch CPU ports 3244acc43b7bSVladimir Oltean */ 3245acc43b7bSVladimir Oltean if (netdev_uses_dsa(dev)) { 3246acc43b7bSVladimir Oltean dp = dev->dsa_ptr; 3247acc43b7bSVladimir Oltean 3248acc43b7bSVladimir Oltean err = dsa_port_lag_change(dp, info->lower_state_info); 3249acc43b7bSVladimir Oltean } 3250acc43b7bSVladimir Oltean 3251058102a6STobias Waldekranz return notifier_from_errno(err); 3252058102a6STobias Waldekranz } 3253295ab96fSVladimir Oltean case NETDEV_CHANGE: 3254295ab96fSVladimir Oltean case NETDEV_UP: { 3255295ab96fSVladimir Oltean /* Track state of master port. 3256295ab96fSVladimir Oltean * DSA driver may require the master port (and indirectly 3257295ab96fSVladimir Oltean * the tagger) to be available for some special operation. 3258295ab96fSVladimir Oltean */ 3259295ab96fSVladimir Oltean if (netdev_uses_dsa(dev)) { 3260295ab96fSVladimir Oltean struct dsa_port *cpu_dp = dev->dsa_ptr; 3261295ab96fSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->ds->dst; 3262295ab96fSVladimir Oltean 3263295ab96fSVladimir Oltean /* Track when the master port is UP */ 3264295ab96fSVladimir Oltean dsa_tree_master_oper_state_change(dst, dev, 3265295ab96fSVladimir Oltean netif_oper_up(dev)); 3266295ab96fSVladimir Oltean 3267295ab96fSVladimir Oltean /* Track when the master port is ready and can accept 3268295ab96fSVladimir Oltean * packet. 3269295ab96fSVladimir Oltean * NETDEV_UP event is not enough to flag a port as ready. 3270295ab96fSVladimir Oltean * We also have to wait for linkwatch_do_dev to dev_activate 3271295ab96fSVladimir Oltean * and emit a NETDEV_CHANGE event. 3272295ab96fSVladimir Oltean * We check if a master port is ready by checking if the dev 3273295ab96fSVladimir Oltean * have a qdisc assigned and is not noop. 3274295ab96fSVladimir Oltean */ 3275295ab96fSVladimir Oltean dsa_tree_master_admin_state_change(dst, dev, 3276295ab96fSVladimir Oltean !qdisc_tx_is_noop(dev)); 3277295ab96fSVladimir Oltean 3278295ab96fSVladimir Oltean return NOTIFY_OK; 3279295ab96fSVladimir Oltean } 3280295ab96fSVladimir Oltean 3281295ab96fSVladimir Oltean return NOTIFY_DONE; 3282295ab96fSVladimir Oltean } 3283c0a8a9c2SVladimir Oltean case NETDEV_GOING_DOWN: { 3284c0a8a9c2SVladimir Oltean struct dsa_port *dp, *cpu_dp; 3285c0a8a9c2SVladimir Oltean struct dsa_switch_tree *dst; 3286c0a8a9c2SVladimir Oltean LIST_HEAD(close_list); 3287c0a8a9c2SVladimir Oltean 3288c0a8a9c2SVladimir Oltean if (!netdev_uses_dsa(dev)) 3289c0a8a9c2SVladimir Oltean return NOTIFY_DONE; 3290c0a8a9c2SVladimir Oltean 3291c0a8a9c2SVladimir Oltean cpu_dp = dev->dsa_ptr; 3292c0a8a9c2SVladimir Oltean dst = cpu_dp->ds->dst; 3293c0a8a9c2SVladimir Oltean 3294295ab96fSVladimir Oltean dsa_tree_master_admin_state_change(dst, dev, false); 3295295ab96fSVladimir Oltean 3296c0a8a9c2SVladimir Oltean list_for_each_entry(dp, &dst->ports, list) { 3297d0004a02SVladimir Oltean if (!dsa_port_is_user(dp)) 3298c0a8a9c2SVladimir Oltean continue; 3299c0a8a9c2SVladimir Oltean 33007136097eSVladimir Oltean if (dp->cpu_dp != cpu_dp) 33017136097eSVladimir Oltean continue; 33027136097eSVladimir Oltean 3303c0a8a9c2SVladimir Oltean list_add(&dp->slave->close_list, &close_list); 3304c0a8a9c2SVladimir Oltean } 3305c0a8a9c2SVladimir Oltean 3306c0a8a9c2SVladimir Oltean dev_close_many(&close_list, true); 3307c0a8a9c2SVladimir Oltean 3308c0a8a9c2SVladimir Oltean return NOTIFY_OK; 3309c0a8a9c2SVladimir Oltean } 3310c0a8a9c2SVladimir Oltean default: 3311c0a8a9c2SVladimir Oltean break; 3312cc1d5bdaSFlorian Fainelli } 3313b73adef6SFlorian Fainelli 3314b73adef6SFlorian Fainelli return NOTIFY_DONE; 3315b73adef6SFlorian Fainelli } 331688e4f0caSVivien Didelot 3317c4bb76a9SVladimir Oltean static void 3318c4bb76a9SVladimir Oltean dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) 3319c4bb76a9SVladimir Oltean { 3320c35b57ceSVladimir Oltean struct switchdev_notifier_fdb_info info = {}; 3321c4bb76a9SVladimir Oltean 3322c4bb76a9SVladimir Oltean info.addr = switchdev_work->addr; 3323c4bb76a9SVladimir Oltean info.vid = switchdev_work->vid; 3324c4bb76a9SVladimir Oltean info.offloaded = true; 3325c4bb76a9SVladimir Oltean call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, 332693c79823SVladimir Oltean switchdev_work->orig_dev, &info.info, NULL); 3327c4bb76a9SVladimir Oltean } 3328c9eb3e0fSArkadi Sharshevsky 3329c9eb3e0fSArkadi Sharshevsky static void dsa_slave_switchdev_event_work(struct work_struct *work) 3330c9eb3e0fSArkadi Sharshevsky { 3331c9eb3e0fSArkadi Sharshevsky struct dsa_switchdev_event_work *switchdev_work = 3332c9eb3e0fSArkadi Sharshevsky container_of(work, struct dsa_switchdev_event_work, work); 333368d6d71eSVladimir Oltean const unsigned char *addr = switchdev_work->addr; 3334e35f12e9SVladimir Oltean struct net_device *dev = switchdev_work->dev; 333568d6d71eSVladimir Oltean u16 vid = switchdev_work->vid; 3336e35f12e9SVladimir Oltean struct dsa_switch *ds; 3337c4bb76a9SVladimir Oltean struct dsa_port *dp; 3338c9eb3e0fSArkadi Sharshevsky int err; 3339c9eb3e0fSArkadi Sharshevsky 3340e35f12e9SVladimir Oltean dp = dsa_slave_to_port(dev); 3341e35f12e9SVladimir Oltean ds = dp->ds; 3342c4bb76a9SVladimir Oltean 3343c9eb3e0fSArkadi Sharshevsky switch (switchdev_work->event) { 3344c9eb3e0fSArkadi Sharshevsky case SWITCHDEV_FDB_ADD_TO_DEVICE: 33453dc80afcSVladimir Oltean if (switchdev_work->host_addr) 334668d6d71eSVladimir Oltean err = dsa_port_bridge_host_fdb_add(dp, addr, vid); 3347e212fa7cSVladimir Oltean else if (dp->lag) 334868d6d71eSVladimir Oltean err = dsa_port_lag_fdb_add(dp, addr, vid); 33493dc80afcSVladimir Oltean else 335068d6d71eSVladimir Oltean err = dsa_port_fdb_add(dp, addr, vid); 3351c9eb3e0fSArkadi Sharshevsky if (err) { 3352c4bb76a9SVladimir Oltean dev_err(ds->dev, 3353c4bb76a9SVladimir Oltean "port %d failed to add %pM vid %d to fdb: %d\n", 335468d6d71eSVladimir Oltean dp->index, addr, vid, err); 3355c9eb3e0fSArkadi Sharshevsky break; 3356c9eb3e0fSArkadi Sharshevsky } 3357c4bb76a9SVladimir Oltean dsa_fdb_offload_notify(switchdev_work); 3358c9eb3e0fSArkadi Sharshevsky break; 3359c9eb3e0fSArkadi Sharshevsky 3360c9eb3e0fSArkadi Sharshevsky case SWITCHDEV_FDB_DEL_TO_DEVICE: 33613dc80afcSVladimir Oltean if (switchdev_work->host_addr) 336268d6d71eSVladimir Oltean err = dsa_port_bridge_host_fdb_del(dp, addr, vid); 3363e212fa7cSVladimir Oltean else if (dp->lag) 336468d6d71eSVladimir Oltean err = dsa_port_lag_fdb_del(dp, addr, vid); 33653dc80afcSVladimir Oltean else 336668d6d71eSVladimir Oltean err = dsa_port_fdb_del(dp, addr, vid); 3367c9eb3e0fSArkadi Sharshevsky if (err) { 3368c4bb76a9SVladimir Oltean dev_err(ds->dev, 3369c4bb76a9SVladimir Oltean "port %d failed to delete %pM vid %d from fdb: %d\n", 337068d6d71eSVladimir Oltean dp->index, addr, vid, err); 3371c9eb3e0fSArkadi Sharshevsky } 33722fd18650SVladimir Oltean 3373c9eb3e0fSArkadi Sharshevsky break; 3374c9eb3e0fSArkadi Sharshevsky } 3375c9eb3e0fSArkadi Sharshevsky 3376c9eb3e0fSArkadi Sharshevsky kfree(switchdev_work); 3377c9eb3e0fSArkadi Sharshevsky } 3378c9eb3e0fSArkadi Sharshevsky 3379b94dc99cSVladimir Oltean static bool dsa_foreign_dev_check(const struct net_device *dev, 3380b94dc99cSVladimir Oltean const struct net_device *foreign_dev) 3381d5f19486SVladimir Oltean { 3382b94dc99cSVladimir Oltean const struct dsa_port *dp = dsa_slave_to_port(dev); 3383b94dc99cSVladimir Oltean struct dsa_switch_tree *dst = dp->ds->dst; 3384b94dc99cSVladimir Oltean 3385b94dc99cSVladimir Oltean if (netif_is_bridge_master(foreign_dev)) 3386936db8a2SVladimir Oltean return !dsa_tree_offloads_bridge_dev(dst, foreign_dev); 3387b94dc99cSVladimir Oltean 3388b94dc99cSVladimir Oltean if (netif_is_bridge_port(foreign_dev)) 3389b94dc99cSVladimir Oltean return !dsa_tree_offloads_bridge_port(dst, foreign_dev); 3390b94dc99cSVladimir Oltean 3391b94dc99cSVladimir Oltean /* Everything else is foreign */ 3392b94dc99cSVladimir Oltean return true; 3393d5f19486SVladimir Oltean } 3394d5f19486SVladimir Oltean 3395b94dc99cSVladimir Oltean static int dsa_slave_fdb_event(struct net_device *dev, 3396716a30a9SVladimir Oltean struct net_device *orig_dev, 3397716a30a9SVladimir Oltean unsigned long event, const void *ctx, 3398716a30a9SVladimir Oltean const struct switchdev_notifier_fdb_info *fdb_info) 3399b94dc99cSVladimir Oltean { 3400b94dc99cSVladimir Oltean struct dsa_switchdev_event_work *switchdev_work; 3401b94dc99cSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 3402b94dc99cSVladimir Oltean bool host_addr = fdb_info->is_local; 3403b94dc99cSVladimir Oltean struct dsa_switch *ds = dp->ds; 3404b94dc99cSVladimir Oltean 3405b94dc99cSVladimir Oltean if (ctx && ctx != dp) 3406b94dc99cSVladimir Oltean return 0; 3407b94dc99cSVladimir Oltean 3408a860352eSTobias Waldekranz if (!dp->bridge) 3409a860352eSTobias Waldekranz return 0; 3410a860352eSTobias Waldekranz 3411e212fa7cSVladimir Oltean if (switchdev_fdb_is_dynamically_learned(fdb_info)) { 3412e212fa7cSVladimir Oltean if (dsa_port_offloads_bridge_port(dp, orig_dev)) 3413b94dc99cSVladimir Oltean return 0; 3414b94dc99cSVladimir Oltean 3415e212fa7cSVladimir Oltean /* FDB entries learned by the software bridge or by foreign 3416e212fa7cSVladimir Oltean * bridge ports should be installed as host addresses only if 3417e212fa7cSVladimir Oltean * the driver requests assisted learning. 3418b94dc99cSVladimir Oltean */ 3419e212fa7cSVladimir Oltean if (!ds->assisted_learning_on_cpu_port) 3420b94dc99cSVladimir Oltean return 0; 3421e212fa7cSVladimir Oltean } 3422b94dc99cSVladimir Oltean 3423b94dc99cSVladimir Oltean /* Also treat FDB entries on foreign interfaces bridged with us as host 3424b94dc99cSVladimir Oltean * addresses. 3425b94dc99cSVladimir Oltean */ 3426b94dc99cSVladimir Oltean if (dsa_foreign_dev_check(dev, orig_dev)) 3427b94dc99cSVladimir Oltean host_addr = true; 3428b94dc99cSVladimir Oltean 3429e212fa7cSVladimir Oltean /* Check early that we're not doing work in vain. 3430e212fa7cSVladimir Oltean * Host addresses on LAG ports still require regular FDB ops, 3431e212fa7cSVladimir Oltean * since the CPU port isn't in a LAG. 3432e212fa7cSVladimir Oltean */ 3433e212fa7cSVladimir Oltean if (dp->lag && !host_addr) { 3434e212fa7cSVladimir Oltean if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del) 3435e212fa7cSVladimir Oltean return -EOPNOTSUPP; 3436e212fa7cSVladimir Oltean } else { 3437e212fa7cSVladimir Oltean if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del) 3438e212fa7cSVladimir Oltean return -EOPNOTSUPP; 3439e212fa7cSVladimir Oltean } 3440e212fa7cSVladimir Oltean 3441b94dc99cSVladimir Oltean switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 3442b94dc99cSVladimir Oltean if (!switchdev_work) 3443b94dc99cSVladimir Oltean return -ENOMEM; 3444b94dc99cSVladimir Oltean 3445b94dc99cSVladimir Oltean netdev_dbg(dev, "%s FDB entry towards %s, addr %pM vid %d%s\n", 3446b94dc99cSVladimir Oltean event == SWITCHDEV_FDB_ADD_TO_DEVICE ? "Adding" : "Deleting", 3447b94dc99cSVladimir Oltean orig_dev->name, fdb_info->addr, fdb_info->vid, 3448b94dc99cSVladimir Oltean host_addr ? " as host address" : ""); 3449b94dc99cSVladimir Oltean 3450b94dc99cSVladimir Oltean INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work); 3451b94dc99cSVladimir Oltean switchdev_work->event = event; 3452b94dc99cSVladimir Oltean switchdev_work->dev = dev; 345393c79823SVladimir Oltean switchdev_work->orig_dev = orig_dev; 3454b94dc99cSVladimir Oltean 3455b94dc99cSVladimir Oltean ether_addr_copy(switchdev_work->addr, fdb_info->addr); 3456b94dc99cSVladimir Oltean switchdev_work->vid = fdb_info->vid; 3457b94dc99cSVladimir Oltean switchdev_work->host_addr = host_addr; 3458b94dc99cSVladimir Oltean 3459b94dc99cSVladimir Oltean dsa_schedule_work(&switchdev_work->work); 3460b94dc99cSVladimir Oltean 3461d5f19486SVladimir Oltean return 0; 3462d5f19486SVladimir Oltean } 3463d5f19486SVladimir Oltean 3464c9eb3e0fSArkadi Sharshevsky /* Called under rcu_read_lock() */ 3465c9eb3e0fSArkadi Sharshevsky static int dsa_slave_switchdev_event(struct notifier_block *unused, 3466c9eb3e0fSArkadi Sharshevsky unsigned long event, void *ptr) 3467c9eb3e0fSArkadi Sharshevsky { 3468c9eb3e0fSArkadi Sharshevsky struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 346979b139f4SVivien Didelot int err; 347079b139f4SVivien Didelot 3471447d290aSVladimir Oltean switch (event) { 3472447d290aSVladimir Oltean case SWITCHDEV_PORT_ATTR_SET: 347379b139f4SVivien Didelot err = switchdev_handle_port_attr_set(dev, ptr, 347479b139f4SVivien Didelot dsa_slave_dev_check, 347579b139f4SVivien Didelot dsa_slave_port_attr_set); 347679b139f4SVivien Didelot return notifier_from_errno(err); 3477447d290aSVladimir Oltean case SWITCHDEV_FDB_ADD_TO_DEVICE: 3478447d290aSVladimir Oltean case SWITCHDEV_FDB_DEL_TO_DEVICE: 3479716a30a9SVladimir Oltean err = switchdev_handle_fdb_event_to_device(dev, event, ptr, 3480b94dc99cSVladimir Oltean dsa_slave_dev_check, 3481b94dc99cSVladimir Oltean dsa_foreign_dev_check, 3482ec638740SVladimir Oltean dsa_slave_fdb_event); 3483b94dc99cSVladimir Oltean return notifier_from_errno(err); 3484c9eb3e0fSArkadi Sharshevsky default: 3485c9eb3e0fSArkadi Sharshevsky return NOTIFY_DONE; 3486c9eb3e0fSArkadi Sharshevsky } 3487c9eb3e0fSArkadi Sharshevsky 3488c9eb3e0fSArkadi Sharshevsky return NOTIFY_OK; 3489c9eb3e0fSArkadi Sharshevsky } 3490c9eb3e0fSArkadi Sharshevsky 34912b239f67SPetr Machata static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, 34922b239f67SPetr Machata unsigned long event, void *ptr) 34932b239f67SPetr Machata { 34942b239f67SPetr Machata struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 349579b139f4SVivien Didelot int err; 34962b239f67SPetr Machata 34972b239f67SPetr Machata switch (event) { 349879b139f4SVivien Didelot case SWITCHDEV_PORT_OBJ_ADD: 3499164f861bSVladimir Oltean err = switchdev_handle_port_obj_add_foreign(dev, ptr, 350079b139f4SVivien Didelot dsa_slave_dev_check, 3501164f861bSVladimir Oltean dsa_foreign_dev_check, 350279b139f4SVivien Didelot dsa_slave_port_obj_add); 350379b139f4SVivien Didelot return notifier_from_errno(err); 35042b239f67SPetr Machata case SWITCHDEV_PORT_OBJ_DEL: 3505164f861bSVladimir Oltean err = switchdev_handle_port_obj_del_foreign(dev, ptr, 350679b139f4SVivien Didelot dsa_slave_dev_check, 3507164f861bSVladimir Oltean dsa_foreign_dev_check, 350879b139f4SVivien Didelot dsa_slave_port_obj_del); 350979b139f4SVivien Didelot return notifier_from_errno(err); 35109ed1ecedSFlorian Fainelli case SWITCHDEV_PORT_ATTR_SET: 351179b139f4SVivien Didelot err = switchdev_handle_port_attr_set(dev, ptr, 351279b139f4SVivien Didelot dsa_slave_dev_check, 351379b139f4SVivien Didelot dsa_slave_port_attr_set); 351479b139f4SVivien Didelot return notifier_from_errno(err); 35152b239f67SPetr Machata } 35162b239f67SPetr Machata 35172b239f67SPetr Machata return NOTIFY_DONE; 35182b239f67SPetr Machata } 35192b239f67SPetr Machata 352088e4f0caSVivien Didelot static struct notifier_block dsa_slave_nb __read_mostly = { 352188e4f0caSVivien Didelot .notifier_call = dsa_slave_netdevice_event, 352288e4f0caSVivien Didelot }; 352388e4f0caSVivien Didelot 3524010e269fSVladimir Oltean struct notifier_block dsa_slave_switchdev_notifier = { 3525c9eb3e0fSArkadi Sharshevsky .notifier_call = dsa_slave_switchdev_event, 3526c9eb3e0fSArkadi Sharshevsky }; 3527c9eb3e0fSArkadi Sharshevsky 3528010e269fSVladimir Oltean struct notifier_block dsa_slave_switchdev_blocking_notifier = { 35292b239f67SPetr Machata .notifier_call = dsa_slave_switchdev_blocking_event, 35302b239f67SPetr Machata }; 35312b239f67SPetr Machata 353288e4f0caSVivien Didelot int dsa_slave_register_notifier(void) 353388e4f0caSVivien Didelot { 35342b239f67SPetr Machata struct notifier_block *nb; 3535c9eb3e0fSArkadi Sharshevsky int err; 3536c9eb3e0fSArkadi Sharshevsky 3537c9eb3e0fSArkadi Sharshevsky err = register_netdevice_notifier(&dsa_slave_nb); 3538c9eb3e0fSArkadi Sharshevsky if (err) 3539c9eb3e0fSArkadi Sharshevsky return err; 3540c9eb3e0fSArkadi Sharshevsky 3541c9eb3e0fSArkadi Sharshevsky err = register_switchdev_notifier(&dsa_slave_switchdev_notifier); 3542c9eb3e0fSArkadi Sharshevsky if (err) 3543c9eb3e0fSArkadi Sharshevsky goto err_switchdev_nb; 3544c9eb3e0fSArkadi Sharshevsky 35452b239f67SPetr Machata nb = &dsa_slave_switchdev_blocking_notifier; 35462b239f67SPetr Machata err = register_switchdev_blocking_notifier(nb); 35472b239f67SPetr Machata if (err) 35482b239f67SPetr Machata goto err_switchdev_blocking_nb; 35492b239f67SPetr Machata 3550c9eb3e0fSArkadi Sharshevsky return 0; 3551c9eb3e0fSArkadi Sharshevsky 35522b239f67SPetr Machata err_switchdev_blocking_nb: 35532b239f67SPetr Machata unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); 3554c9eb3e0fSArkadi Sharshevsky err_switchdev_nb: 3555c9eb3e0fSArkadi Sharshevsky unregister_netdevice_notifier(&dsa_slave_nb); 3556c9eb3e0fSArkadi Sharshevsky return err; 355788e4f0caSVivien Didelot } 355888e4f0caSVivien Didelot 355988e4f0caSVivien Didelot void dsa_slave_unregister_notifier(void) 356088e4f0caSVivien Didelot { 35612b239f67SPetr Machata struct notifier_block *nb; 356288e4f0caSVivien Didelot int err; 356388e4f0caSVivien Didelot 35642b239f67SPetr Machata nb = &dsa_slave_switchdev_blocking_notifier; 35652b239f67SPetr Machata err = unregister_switchdev_blocking_notifier(nb); 35662b239f67SPetr Machata if (err) 35672b239f67SPetr Machata pr_err("DSA: failed to unregister switchdev blocking notifier (%d)\n", err); 35682b239f67SPetr Machata 3569c9eb3e0fSArkadi Sharshevsky err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); 3570c9eb3e0fSArkadi Sharshevsky if (err) 3571c9eb3e0fSArkadi Sharshevsky pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err); 3572c9eb3e0fSArkadi Sharshevsky 357388e4f0caSVivien Didelot err = unregister_netdevice_notifier(&dsa_slave_nb); 357488e4f0caSVivien Didelot if (err) 357588e4f0caSVivien Didelot pr_err("DSA: failed to unregister slave notifier (%d)\n", err); 357688e4f0caSVivien Didelot } 3577