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" 2691da11f8SLennert Buytenhek #include "dsa_priv.h" 27022bba63SVladimir Oltean #include "port.h" 2894ef6fadSVladimir Oltean #include "master.h" 2909f92341SVladimir Oltean #include "slave.h" 30bd954b82SVladimir Oltean #include "tag.h" 3191da11f8SLennert Buytenhek 32*8e396fecSVladimir Oltean struct dsa_switchdev_event_work { 33*8e396fecSVladimir Oltean struct net_device *dev; 34*8e396fecSVladimir Oltean struct net_device *orig_dev; 35*8e396fecSVladimir Oltean struct work_struct work; 36*8e396fecSVladimir Oltean unsigned long event; 37*8e396fecSVladimir Oltean /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and 38*8e396fecSVladimir Oltean * SWITCHDEV_FDB_DEL_TO_DEVICE 39*8e396fecSVladimir Oltean */ 40*8e396fecSVladimir Oltean unsigned char addr[ETH_ALEN]; 41*8e396fecSVladimir Oltean u16 vid; 42*8e396fecSVladimir Oltean bool host_addr; 43*8e396fecSVladimir Oltean }; 44*8e396fecSVladimir Oltean 45*8e396fecSVladimir Oltean enum dsa_standalone_event { 46*8e396fecSVladimir Oltean DSA_UC_ADD, 47*8e396fecSVladimir Oltean DSA_UC_DEL, 48*8e396fecSVladimir Oltean DSA_MC_ADD, 49*8e396fecSVladimir Oltean DSA_MC_DEL, 50*8e396fecSVladimir Oltean }; 51*8e396fecSVladimir Oltean 52*8e396fecSVladimir Oltean struct dsa_standalone_event_work { 53*8e396fecSVladimir Oltean struct work_struct work; 54*8e396fecSVladimir Oltean struct net_device *dev; 55*8e396fecSVladimir Oltean enum dsa_standalone_event event; 56*8e396fecSVladimir Oltean unsigned char addr[ETH_ALEN]; 57*8e396fecSVladimir Oltean u16 vid; 58*8e396fecSVladimir Oltean }; 59*8e396fecSVladimir Oltean 60*8e396fecSVladimir Oltean static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds) 61*8e396fecSVladimir Oltean { 62*8e396fecSVladimir Oltean return ds->ops->port_fdb_add && ds->ops->port_fdb_del && 63*8e396fecSVladimir Oltean ds->fdb_isolation && !ds->vlan_filtering_is_global && 64*8e396fecSVladimir Oltean !ds->needs_standalone_vlan_filtering; 65*8e396fecSVladimir Oltean } 66*8e396fecSVladimir Oltean 67*8e396fecSVladimir Oltean static bool dsa_switch_supports_mc_filtering(struct dsa_switch *ds) 68*8e396fecSVladimir Oltean { 69*8e396fecSVladimir Oltean return ds->ops->port_mdb_add && ds->ops->port_mdb_del && 70*8e396fecSVladimir Oltean ds->fdb_isolation && !ds->vlan_filtering_is_global && 71*8e396fecSVladimir Oltean !ds->needs_standalone_vlan_filtering; 72*8e396fecSVladimir Oltean } 73*8e396fecSVladimir 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 112019e57c4eSFlorian Fainelli static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) 112119e57c4eSFlorian Fainelli { 1122d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1123d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 112419e57c4eSFlorian Fainelli 1125aab9c406SFlorian Fainelli phylink_ethtool_get_wol(dp->pl, w); 1126aab9c406SFlorian Fainelli 11279d490b4eSVivien Didelot if (ds->ops->get_wol) 1128d945097bSVivien Didelot ds->ops->get_wol(ds, dp->index, w); 112919e57c4eSFlorian Fainelli } 113019e57c4eSFlorian Fainelli 113119e57c4eSFlorian Fainelli static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) 113219e57c4eSFlorian Fainelli { 1133d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1134d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 113519e57c4eSFlorian Fainelli int ret = -EOPNOTSUPP; 113619e57c4eSFlorian Fainelli 1137aab9c406SFlorian Fainelli phylink_ethtool_set_wol(dp->pl, w); 1138aab9c406SFlorian Fainelli 11399d490b4eSVivien Didelot if (ds->ops->set_wol) 1140d945097bSVivien Didelot ret = ds->ops->set_wol(ds, dp->index, w); 114119e57c4eSFlorian Fainelli 114219e57c4eSFlorian Fainelli return ret; 114319e57c4eSFlorian Fainelli } 114419e57c4eSFlorian Fainelli 11457905288fSFlorian Fainelli static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) 11467905288fSFlorian Fainelli { 1147d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1148d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 11497905288fSFlorian Fainelli int ret; 11507905288fSFlorian Fainelli 11517b9cc738SVivien Didelot /* Port's PHY and MAC both need to be EEE capable */ 115200670cb8SDan Carpenter if (!dev->phydev || !dp->pl) 11537b9cc738SVivien Didelot return -ENODEV; 11547b9cc738SVivien Didelot 115508f50061SVivien Didelot if (!ds->ops->set_mac_eee) 11567905288fSFlorian Fainelli return -EOPNOTSUPP; 11577905288fSFlorian Fainelli 1158d945097bSVivien Didelot ret = ds->ops->set_mac_eee(ds, dp->index, e); 11597905288fSFlorian Fainelli if (ret) 11607905288fSFlorian Fainelli return ret; 11617905288fSFlorian Fainelli 1162aab9c406SFlorian Fainelli return phylink_ethtool_set_eee(dp->pl, e); 11637905288fSFlorian Fainelli } 11647905288fSFlorian Fainelli 11657905288fSFlorian Fainelli static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) 11667905288fSFlorian Fainelli { 1167d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1168d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 11697905288fSFlorian Fainelli int ret; 11707905288fSFlorian Fainelli 11717b9cc738SVivien Didelot /* Port's PHY and MAC both need to be EEE capable */ 117200670cb8SDan Carpenter if (!dev->phydev || !dp->pl) 11737b9cc738SVivien Didelot return -ENODEV; 11747b9cc738SVivien Didelot 117508f50061SVivien Didelot if (!ds->ops->get_mac_eee) 11767905288fSFlorian Fainelli return -EOPNOTSUPP; 11777905288fSFlorian Fainelli 1178d945097bSVivien Didelot ret = ds->ops->get_mac_eee(ds, dp->index, e); 11797905288fSFlorian Fainelli if (ret) 11807905288fSFlorian Fainelli return ret; 11817905288fSFlorian Fainelli 1182aab9c406SFlorian Fainelli return phylink_ethtool_get_eee(dp->pl, e); 1183aab9c406SFlorian Fainelli } 1184aab9c406SFlorian Fainelli 1185aab9c406SFlorian Fainelli static int dsa_slave_get_link_ksettings(struct net_device *dev, 1186aab9c406SFlorian Fainelli struct ethtool_link_ksettings *cmd) 1187aab9c406SFlorian Fainelli { 1188aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 1189aab9c406SFlorian Fainelli 1190aab9c406SFlorian Fainelli return phylink_ethtool_ksettings_get(dp->pl, cmd); 1191aab9c406SFlorian Fainelli } 1192aab9c406SFlorian Fainelli 1193aab9c406SFlorian Fainelli static int dsa_slave_set_link_ksettings(struct net_device *dev, 1194aab9c406SFlorian Fainelli const struct ethtool_link_ksettings *cmd) 1195aab9c406SFlorian Fainelli { 1196aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 1197aab9c406SFlorian Fainelli 1198aab9c406SFlorian Fainelli return phylink_ethtool_ksettings_set(dp->pl, cmd); 11997905288fSFlorian Fainelli } 12007905288fSFlorian Fainelli 12013d410403SOleksij Rempel static void dsa_slave_get_pause_stats(struct net_device *dev, 12023d410403SOleksij Rempel struct ethtool_pause_stats *pause_stats) 12033d410403SOleksij Rempel { 12043d410403SOleksij Rempel struct dsa_port *dp = dsa_slave_to_port(dev); 12053d410403SOleksij Rempel struct dsa_switch *ds = dp->ds; 12063d410403SOleksij Rempel 12073d410403SOleksij Rempel if (ds->ops->get_pause_stats) 12083d410403SOleksij Rempel ds->ops->get_pause_stats(ds, dp->index, pause_stats); 12093d410403SOleksij Rempel } 12103d410403SOleksij Rempel 1211a2a1a13bSHeiner Kallweit static void dsa_slave_get_pauseparam(struct net_device *dev, 1212a2a1a13bSHeiner Kallweit struct ethtool_pauseparam *pause) 1213a2a1a13bSHeiner Kallweit { 1214a2a1a13bSHeiner Kallweit struct dsa_port *dp = dsa_slave_to_port(dev); 1215a2a1a13bSHeiner Kallweit 1216a2a1a13bSHeiner Kallweit phylink_ethtool_get_pauseparam(dp->pl, pause); 1217a2a1a13bSHeiner Kallweit } 1218a2a1a13bSHeiner Kallweit 1219a2a1a13bSHeiner Kallweit static int dsa_slave_set_pauseparam(struct net_device *dev, 1220a2a1a13bSHeiner Kallweit struct ethtool_pauseparam *pause) 1221a2a1a13bSHeiner Kallweit { 1222a2a1a13bSHeiner Kallweit struct dsa_port *dp = dsa_slave_to_port(dev); 1223a2a1a13bSHeiner Kallweit 1224a2a1a13bSHeiner Kallweit return phylink_ethtool_set_pauseparam(dp->pl, pause); 1225a2a1a13bSHeiner Kallweit } 1226a2a1a13bSHeiner Kallweit 122704ff53f9SFlorian Fainelli #ifdef CONFIG_NET_POLL_CONTROLLER 122804ff53f9SFlorian Fainelli static int dsa_slave_netpoll_setup(struct net_device *dev, 122904ff53f9SFlorian Fainelli struct netpoll_info *ni) 123004ff53f9SFlorian Fainelli { 1231d0006b00SVivien Didelot struct net_device *master = dsa_slave_to_master(dev); 123204ff53f9SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 123304ff53f9SFlorian Fainelli struct netpoll *netpoll; 123404ff53f9SFlorian Fainelli int err = 0; 123504ff53f9SFlorian Fainelli 123604ff53f9SFlorian Fainelli netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); 123704ff53f9SFlorian Fainelli if (!netpoll) 123804ff53f9SFlorian Fainelli return -ENOMEM; 123904ff53f9SFlorian Fainelli 124004ff53f9SFlorian Fainelli err = __netpoll_setup(netpoll, master); 124104ff53f9SFlorian Fainelli if (err) { 124204ff53f9SFlorian Fainelli kfree(netpoll); 124304ff53f9SFlorian Fainelli goto out; 124404ff53f9SFlorian Fainelli } 124504ff53f9SFlorian Fainelli 124604ff53f9SFlorian Fainelli p->netpoll = netpoll; 124704ff53f9SFlorian Fainelli out: 124804ff53f9SFlorian Fainelli return err; 124904ff53f9SFlorian Fainelli } 125004ff53f9SFlorian Fainelli 125104ff53f9SFlorian Fainelli static void dsa_slave_netpoll_cleanup(struct net_device *dev) 125204ff53f9SFlorian Fainelli { 125304ff53f9SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 125404ff53f9SFlorian Fainelli struct netpoll *netpoll = p->netpoll; 125504ff53f9SFlorian Fainelli 125604ff53f9SFlorian Fainelli if (!netpoll) 125704ff53f9SFlorian Fainelli return; 125804ff53f9SFlorian Fainelli 125904ff53f9SFlorian Fainelli p->netpoll = NULL; 126004ff53f9SFlorian Fainelli 1261c9fbd71fSDebabrata Banerjee __netpoll_free(netpoll); 126204ff53f9SFlorian Fainelli } 126304ff53f9SFlorian Fainelli 126404ff53f9SFlorian Fainelli static void dsa_slave_poll_controller(struct net_device *dev) 126504ff53f9SFlorian Fainelli { 126604ff53f9SFlorian Fainelli } 126704ff53f9SFlorian Fainelli #endif 126804ff53f9SFlorian Fainelli 1269f50f2127SFlorian Fainelli static struct dsa_mall_tc_entry * 12704fa7b718SVivien Didelot dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie) 1271f50f2127SFlorian Fainelli { 12724fa7b718SVivien Didelot struct dsa_slave_priv *p = netdev_priv(dev); 1273f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1274f50f2127SFlorian Fainelli 1275f50f2127SFlorian Fainelli list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) 1276f50f2127SFlorian Fainelli if (mall_tc_entry->cookie == cookie) 1277f50f2127SFlorian Fainelli return mall_tc_entry; 1278f50f2127SFlorian Fainelli 1279f50f2127SFlorian Fainelli return NULL; 1280f50f2127SFlorian Fainelli } 1281f50f2127SFlorian Fainelli 1282e13c2075SVladimir Oltean static int 1283e13c2075SVladimir Oltean dsa_slave_add_cls_matchall_mirred(struct net_device *dev, 1284f50f2127SFlorian Fainelli struct tc_cls_matchall_offload *cls, 1285f50f2127SFlorian Fainelli bool ingress) 1286f50f2127SFlorian Fainelli { 12870148bb50SVladimir Oltean struct netlink_ext_ack *extack = cls->common.extack; 1288d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1289f50f2127SFlorian Fainelli struct dsa_slave_priv *p = netdev_priv(dev); 1290e13c2075SVladimir Oltean struct dsa_mall_mirror_tc_entry *mirror; 1291f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1292d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 12939681e8b3SPieter Jansen van Vuuren struct flow_action_entry *act; 1294d945097bSVivien Didelot struct dsa_port *to_dp; 1295e13c2075SVladimir Oltean int err; 1296e13c2075SVladimir Oltean 1297f50f2127SFlorian Fainelli if (!ds->ops->port_mirror_add) 129834297176SVladimir Oltean return -EOPNOTSUPP; 1299f50f2127SFlorian Fainelli 130053eca1f3SJakub Kicinski if (!flow_action_basic_hw_stats_check(&cls->rule->action, 1301319a1d19SJiri Pirko cls->common.extack)) 130234297176SVladimir Oltean return -EOPNOTSUPP; 1303319a1d19SJiri Pirko 13049681e8b3SPieter Jansen van Vuuren act = &cls->rule->action.entries[0]; 1305f50f2127SFlorian Fainelli 130665722159SVladimir Oltean if (!act->dev) 130765722159SVladimir Oltean return -EINVAL; 130865722159SVladimir Oltean 13099681e8b3SPieter Jansen van Vuuren if (!dsa_slave_dev_check(act->dev)) 1310f50f2127SFlorian Fainelli return -EOPNOTSUPP; 1311f50f2127SFlorian Fainelli 1312f50f2127SFlorian Fainelli mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); 1313f50f2127SFlorian Fainelli if (!mall_tc_entry) 1314f50f2127SFlorian Fainelli return -ENOMEM; 1315f50f2127SFlorian Fainelli 1316f50f2127SFlorian Fainelli mall_tc_entry->cookie = cls->cookie; 1317f50f2127SFlorian Fainelli mall_tc_entry->type = DSA_PORT_MALL_MIRROR; 1318f50f2127SFlorian Fainelli mirror = &mall_tc_entry->mirror; 1319f50f2127SFlorian Fainelli 13209681e8b3SPieter Jansen van Vuuren to_dp = dsa_slave_to_port(act->dev); 1321f50f2127SFlorian Fainelli 1322d945097bSVivien Didelot mirror->to_local_port = to_dp->index; 1323f50f2127SFlorian Fainelli mirror->ingress = ingress; 1324f50f2127SFlorian Fainelli 13250148bb50SVladimir Oltean err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack); 1326f50f2127SFlorian Fainelli if (err) { 1327f50f2127SFlorian Fainelli kfree(mall_tc_entry); 1328f50f2127SFlorian Fainelli return err; 1329f50f2127SFlorian Fainelli } 1330f50f2127SFlorian Fainelli 1331f50f2127SFlorian Fainelli list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); 1332e13c2075SVladimir Oltean 1333e13c2075SVladimir Oltean return err; 1334f50f2127SFlorian Fainelli } 1335f50f2127SFlorian Fainelli 133634297176SVladimir Oltean static int 133734297176SVladimir Oltean dsa_slave_add_cls_matchall_police(struct net_device *dev, 133834297176SVladimir Oltean struct tc_cls_matchall_offload *cls, 133934297176SVladimir Oltean bool ingress) 134034297176SVladimir Oltean { 134134297176SVladimir Oltean struct netlink_ext_ack *extack = cls->common.extack; 134234297176SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 134334297176SVladimir Oltean struct dsa_slave_priv *p = netdev_priv(dev); 134434297176SVladimir Oltean struct dsa_mall_policer_tc_entry *policer; 134534297176SVladimir Oltean struct dsa_mall_tc_entry *mall_tc_entry; 134634297176SVladimir Oltean struct dsa_switch *ds = dp->ds; 134734297176SVladimir Oltean struct flow_action_entry *act; 134834297176SVladimir Oltean int err; 134934297176SVladimir Oltean 135034297176SVladimir Oltean if (!ds->ops->port_policer_add) { 135134297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1352c75a33c8SJacob Keller "Policing offload not implemented"); 135334297176SVladimir Oltean return -EOPNOTSUPP; 135434297176SVladimir Oltean } 135534297176SVladimir Oltean 135634297176SVladimir Oltean if (!ingress) { 135734297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1358c75a33c8SJacob Keller "Only supported on ingress qdisc"); 135934297176SVladimir Oltean return -EOPNOTSUPP; 136034297176SVladimir Oltean } 136134297176SVladimir Oltean 136234297176SVladimir Oltean if (!flow_action_basic_hw_stats_check(&cls->rule->action, 136334297176SVladimir Oltean cls->common.extack)) 136434297176SVladimir Oltean return -EOPNOTSUPP; 136534297176SVladimir Oltean 136634297176SVladimir Oltean list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) { 136734297176SVladimir Oltean if (mall_tc_entry->type == DSA_PORT_MALL_POLICER) { 136834297176SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 1369c75a33c8SJacob Keller "Only one port policer allowed"); 137034297176SVladimir Oltean return -EEXIST; 137134297176SVladimir Oltean } 137234297176SVladimir Oltean } 137334297176SVladimir Oltean 137434297176SVladimir Oltean act = &cls->rule->action.entries[0]; 137534297176SVladimir Oltean 137634297176SVladimir Oltean mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); 137734297176SVladimir Oltean if (!mall_tc_entry) 137834297176SVladimir Oltean return -ENOMEM; 137934297176SVladimir Oltean 138034297176SVladimir Oltean mall_tc_entry->cookie = cls->cookie; 138134297176SVladimir Oltean mall_tc_entry->type = DSA_PORT_MALL_POLICER; 138234297176SVladimir Oltean policer = &mall_tc_entry->policer; 138334297176SVladimir Oltean policer->rate_bytes_per_sec = act->police.rate_bytes_ps; 138434297176SVladimir Oltean policer->burst = act->police.burst; 138534297176SVladimir Oltean 138634297176SVladimir Oltean err = ds->ops->port_policer_add(ds, dp->index, policer); 138734297176SVladimir Oltean if (err) { 138834297176SVladimir Oltean kfree(mall_tc_entry); 138934297176SVladimir Oltean return err; 139034297176SVladimir Oltean } 139134297176SVladimir Oltean 139234297176SVladimir Oltean list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); 139334297176SVladimir Oltean 139434297176SVladimir Oltean return err; 139534297176SVladimir Oltean } 139634297176SVladimir Oltean 1397e13c2075SVladimir Oltean static int dsa_slave_add_cls_matchall(struct net_device *dev, 1398e13c2075SVladimir Oltean struct tc_cls_matchall_offload *cls, 1399e13c2075SVladimir Oltean bool ingress) 1400e13c2075SVladimir Oltean { 1401e13c2075SVladimir Oltean int err = -EOPNOTSUPP; 1402e13c2075SVladimir Oltean 1403e13c2075SVladimir Oltean if (cls->common.protocol == htons(ETH_P_ALL) && 1404e13c2075SVladimir Oltean flow_offload_has_one_action(&cls->rule->action) && 1405e13c2075SVladimir Oltean cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED) 1406e13c2075SVladimir Oltean err = dsa_slave_add_cls_matchall_mirred(dev, cls, ingress); 140734297176SVladimir Oltean else if (flow_offload_has_one_action(&cls->rule->action) && 140834297176SVladimir Oltean cls->rule->action.entries[0].id == FLOW_ACTION_POLICE) 140934297176SVladimir Oltean err = dsa_slave_add_cls_matchall_police(dev, cls, ingress); 1410e13c2075SVladimir Oltean 1411e13c2075SVladimir Oltean return err; 1412f50f2127SFlorian Fainelli } 1413f50f2127SFlorian Fainelli 1414f50f2127SFlorian Fainelli static void dsa_slave_del_cls_matchall(struct net_device *dev, 1415f50f2127SFlorian Fainelli struct tc_cls_matchall_offload *cls) 1416f50f2127SFlorian Fainelli { 1417d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1418f50f2127SFlorian Fainelli struct dsa_mall_tc_entry *mall_tc_entry; 1419d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1420f50f2127SFlorian Fainelli 14214fa7b718SVivien Didelot mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie); 1422f50f2127SFlorian Fainelli if (!mall_tc_entry) 1423f50f2127SFlorian Fainelli return; 1424f50f2127SFlorian Fainelli 1425f50f2127SFlorian Fainelli list_del(&mall_tc_entry->list); 1426f50f2127SFlorian Fainelli 1427f50f2127SFlorian Fainelli switch (mall_tc_entry->type) { 1428f50f2127SFlorian Fainelli case DSA_PORT_MALL_MIRROR: 142934297176SVladimir Oltean if (ds->ops->port_mirror_del) 143034297176SVladimir Oltean ds->ops->port_mirror_del(ds, dp->index, 143134297176SVladimir Oltean &mall_tc_entry->mirror); 143234297176SVladimir Oltean break; 143334297176SVladimir Oltean case DSA_PORT_MALL_POLICER: 143434297176SVladimir Oltean if (ds->ops->port_policer_del) 143534297176SVladimir Oltean ds->ops->port_policer_del(ds, dp->index); 1436f50f2127SFlorian Fainelli break; 1437f50f2127SFlorian Fainelli default: 1438f50f2127SFlorian Fainelli WARN_ON(1); 1439f50f2127SFlorian Fainelli } 1440f50f2127SFlorian Fainelli 1441f50f2127SFlorian Fainelli kfree(mall_tc_entry); 1442f50f2127SFlorian Fainelli } 1443f50f2127SFlorian Fainelli 14443fbae382SJiri Pirko static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev, 14456b3eb752SJiri Pirko struct tc_cls_matchall_offload *cls, 14466b3eb752SJiri Pirko bool ingress) 1447f50f2127SFlorian Fainelli { 14485fd9fc4eSJiri Pirko if (cls->common.chain_index) 1449a5fcf8a6SJiri Pirko return -EOPNOTSUPP; 1450f50f2127SFlorian Fainelli 14513fbae382SJiri Pirko switch (cls->command) { 14523fbae382SJiri Pirko case TC_CLSMATCHALL_REPLACE: 14535fd9fc4eSJiri Pirko return dsa_slave_add_cls_matchall(dev, cls, ingress); 14543fbae382SJiri Pirko case TC_CLSMATCHALL_DESTROY: 14553fbae382SJiri Pirko dsa_slave_del_cls_matchall(dev, cls); 14563fbae382SJiri Pirko return 0; 14573fbae382SJiri Pirko default: 14583fbae382SJiri Pirko return -EOPNOTSUPP; 14593fbae382SJiri Pirko } 14603fbae382SJiri Pirko } 14613fbae382SJiri Pirko 1462ed11bb1fSVladimir Oltean static int dsa_slave_add_cls_flower(struct net_device *dev, 1463ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1464ed11bb1fSVladimir Oltean bool ingress) 1465ed11bb1fSVladimir Oltean { 1466ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1467ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1468ed11bb1fSVladimir Oltean int port = dp->index; 1469ed11bb1fSVladimir Oltean 1470ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_add) 1471ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1472ed11bb1fSVladimir Oltean 1473ed11bb1fSVladimir Oltean return ds->ops->cls_flower_add(ds, port, cls, ingress); 1474ed11bb1fSVladimir Oltean } 1475ed11bb1fSVladimir Oltean 1476ed11bb1fSVladimir Oltean static int dsa_slave_del_cls_flower(struct net_device *dev, 1477ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1478ed11bb1fSVladimir Oltean bool ingress) 1479ed11bb1fSVladimir Oltean { 1480ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1481ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1482ed11bb1fSVladimir Oltean int port = dp->index; 1483ed11bb1fSVladimir Oltean 1484ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_del) 1485ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1486ed11bb1fSVladimir Oltean 1487ed11bb1fSVladimir Oltean return ds->ops->cls_flower_del(ds, port, cls, ingress); 1488ed11bb1fSVladimir Oltean } 1489ed11bb1fSVladimir Oltean 1490ed11bb1fSVladimir Oltean static int dsa_slave_stats_cls_flower(struct net_device *dev, 1491ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1492ed11bb1fSVladimir Oltean bool ingress) 1493ed11bb1fSVladimir Oltean { 1494ed11bb1fSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1495ed11bb1fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1496ed11bb1fSVladimir Oltean int port = dp->index; 1497ed11bb1fSVladimir Oltean 1498ed11bb1fSVladimir Oltean if (!ds->ops->cls_flower_stats) 1499ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1500ed11bb1fSVladimir Oltean 1501ed11bb1fSVladimir Oltean return ds->ops->cls_flower_stats(ds, port, cls, ingress); 1502ed11bb1fSVladimir Oltean } 1503ed11bb1fSVladimir Oltean 1504ed11bb1fSVladimir Oltean static int dsa_slave_setup_tc_cls_flower(struct net_device *dev, 1505ed11bb1fSVladimir Oltean struct flow_cls_offload *cls, 1506ed11bb1fSVladimir Oltean bool ingress) 1507ed11bb1fSVladimir Oltean { 1508ed11bb1fSVladimir Oltean switch (cls->command) { 1509ed11bb1fSVladimir Oltean case FLOW_CLS_REPLACE: 1510ed11bb1fSVladimir Oltean return dsa_slave_add_cls_flower(dev, cls, ingress); 1511ed11bb1fSVladimir Oltean case FLOW_CLS_DESTROY: 1512ed11bb1fSVladimir Oltean return dsa_slave_del_cls_flower(dev, cls, ingress); 1513ed11bb1fSVladimir Oltean case FLOW_CLS_STATS: 1514ed11bb1fSVladimir Oltean return dsa_slave_stats_cls_flower(dev, cls, ingress); 1515ed11bb1fSVladimir Oltean default: 1516ed11bb1fSVladimir Oltean return -EOPNOTSUPP; 1517ed11bb1fSVladimir Oltean } 1518ed11bb1fSVladimir Oltean } 1519ed11bb1fSVladimir Oltean 15206b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data, 15216b3eb752SJiri Pirko void *cb_priv, bool ingress) 15226b3eb752SJiri Pirko { 15236b3eb752SJiri Pirko struct net_device *dev = cb_priv; 15246b3eb752SJiri Pirko 152544ae12a7SJiri Pirko if (!tc_can_offload(dev)) 152644ae12a7SJiri Pirko return -EOPNOTSUPP; 152744ae12a7SJiri Pirko 15286b3eb752SJiri Pirko switch (type) { 15296b3eb752SJiri Pirko case TC_SETUP_CLSMATCHALL: 15306b3eb752SJiri Pirko return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress); 1531ed11bb1fSVladimir Oltean case TC_SETUP_CLSFLOWER: 1532ed11bb1fSVladimir Oltean return dsa_slave_setup_tc_cls_flower(dev, type_data, ingress); 15336b3eb752SJiri Pirko default: 15346b3eb752SJiri Pirko return -EOPNOTSUPP; 15356b3eb752SJiri Pirko } 15366b3eb752SJiri Pirko } 15376b3eb752SJiri Pirko 15386b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb_ig(enum tc_setup_type type, 15396b3eb752SJiri Pirko void *type_data, void *cb_priv) 15406b3eb752SJiri Pirko { 15416b3eb752SJiri Pirko return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, true); 15426b3eb752SJiri Pirko } 15436b3eb752SJiri Pirko 15446b3eb752SJiri Pirko static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type, 15456b3eb752SJiri Pirko void *type_data, void *cb_priv) 15466b3eb752SJiri Pirko { 15476b3eb752SJiri Pirko return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false); 15486b3eb752SJiri Pirko } 15496b3eb752SJiri Pirko 1550955bcb6eSPablo Neira Ayuso static LIST_HEAD(dsa_slave_block_cb_list); 1551955bcb6eSPablo Neira Ayuso 15526b3eb752SJiri Pirko static int dsa_slave_setup_tc_block(struct net_device *dev, 1553955bcb6eSPablo Neira Ayuso struct flow_block_offload *f) 15546b3eb752SJiri Pirko { 1555955bcb6eSPablo Neira Ayuso struct flow_block_cb *block_cb; 1556a7323311SPablo Neira Ayuso flow_setup_cb_t *cb; 15576b3eb752SJiri Pirko 155832f8c409SPablo Neira Ayuso if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 15596b3eb752SJiri Pirko cb = dsa_slave_setup_tc_block_cb_ig; 156032f8c409SPablo Neira Ayuso else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) 15616b3eb752SJiri Pirko cb = dsa_slave_setup_tc_block_cb_eg; 15626b3eb752SJiri Pirko else 15636b3eb752SJiri Pirko return -EOPNOTSUPP; 15646b3eb752SJiri Pirko 1565955bcb6eSPablo Neira Ayuso f->driver_block_list = &dsa_slave_block_cb_list; 1566955bcb6eSPablo Neira Ayuso 15676b3eb752SJiri Pirko switch (f->command) { 15689c0e189eSPablo Neira Ayuso case FLOW_BLOCK_BIND: 15690d4fd02eSPablo Neira Ayuso if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list)) 15700d4fd02eSPablo Neira Ayuso return -EBUSY; 15710d4fd02eSPablo Neira Ayuso 15720c7294ddSPablo Neira Ayuso block_cb = flow_block_cb_alloc(cb, dev, dev, NULL); 1573955bcb6eSPablo Neira Ayuso if (IS_ERR(block_cb)) 1574955bcb6eSPablo Neira Ayuso return PTR_ERR(block_cb); 1575955bcb6eSPablo Neira Ayuso 1576955bcb6eSPablo Neira Ayuso flow_block_cb_add(block_cb, f); 1577955bcb6eSPablo Neira Ayuso list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list); 1578955bcb6eSPablo Neira Ayuso return 0; 15799c0e189eSPablo Neira Ayuso case FLOW_BLOCK_UNBIND: 158014bfb13fSPablo Neira Ayuso block_cb = flow_block_cb_lookup(f->block, cb, dev); 1581955bcb6eSPablo Neira Ayuso if (!block_cb) 1582955bcb6eSPablo Neira Ayuso return -ENOENT; 1583955bcb6eSPablo Neira Ayuso 1584955bcb6eSPablo Neira Ayuso flow_block_cb_remove(block_cb, f); 1585955bcb6eSPablo Neira Ayuso list_del(&block_cb->driver_list); 15866b3eb752SJiri Pirko return 0; 15876b3eb752SJiri Pirko default: 15886b3eb752SJiri Pirko return -EOPNOTSUPP; 15896b3eb752SJiri Pirko } 15906b3eb752SJiri Pirko } 15916b3eb752SJiri Pirko 15923fb24a43SPablo Neira Ayuso static int dsa_slave_setup_ft_block(struct dsa_switch *ds, int port, 15933fb24a43SPablo Neira Ayuso void *type_data) 15943fb24a43SPablo Neira Ayuso { 15958f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dsa_to_port(ds, port)); 15963fb24a43SPablo Neira Ayuso 15973fb24a43SPablo Neira Ayuso if (!master->netdev_ops->ndo_setup_tc) 15983fb24a43SPablo Neira Ayuso return -EOPNOTSUPP; 15993fb24a43SPablo Neira Ayuso 16003fb24a43SPablo Neira Ayuso return master->netdev_ops->ndo_setup_tc(master, TC_SETUP_FT, type_data); 16013fb24a43SPablo Neira Ayuso } 16023fb24a43SPablo Neira Ayuso 16033fbae382SJiri Pirko static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type, 1604de4784caSJiri Pirko void *type_data) 16053fbae382SJiri Pirko { 160647d23af2SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 160747d23af2SVladimir Oltean struct dsa_switch *ds = dp->ds; 160847d23af2SVladimir Oltean 16093fb24a43SPablo Neira Ayuso switch (type) { 16103fb24a43SPablo Neira Ayuso case TC_SETUP_BLOCK: 16116b3eb752SJiri Pirko return dsa_slave_setup_tc_block(dev, type_data); 16123fb24a43SPablo Neira Ayuso case TC_SETUP_FT: 16133fb24a43SPablo Neira Ayuso return dsa_slave_setup_ft_block(ds, dp->index, type_data); 16143fb24a43SPablo Neira Ayuso default: 16153fb24a43SPablo Neira Ayuso break; 16163fb24a43SPablo Neira Ayuso } 161747d23af2SVladimir Oltean 161847d23af2SVladimir Oltean if (!ds->ops->port_setup_tc) 1619a5fcf8a6SJiri Pirko return -EOPNOTSUPP; 162047d23af2SVladimir Oltean 162147d23af2SVladimir Oltean return ds->ops->port_setup_tc(ds, dp->index, type, type_data); 1622f50f2127SFlorian Fainelli } 1623f50f2127SFlorian Fainelli 1624bf9f2648SFlorian Fainelli static int dsa_slave_get_rxnfc(struct net_device *dev, 1625bf9f2648SFlorian Fainelli struct ethtool_rxnfc *nfc, u32 *rule_locs) 1626bf9f2648SFlorian Fainelli { 1627d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1628d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1629bf9f2648SFlorian Fainelli 1630bf9f2648SFlorian Fainelli if (!ds->ops->get_rxnfc) 1631bf9f2648SFlorian Fainelli return -EOPNOTSUPP; 1632bf9f2648SFlorian Fainelli 1633d945097bSVivien Didelot return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs); 1634bf9f2648SFlorian Fainelli } 1635bf9f2648SFlorian Fainelli 1636bf9f2648SFlorian Fainelli static int dsa_slave_set_rxnfc(struct net_device *dev, 1637bf9f2648SFlorian Fainelli struct ethtool_rxnfc *nfc) 1638bf9f2648SFlorian Fainelli { 1639d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 1640d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 1641bf9f2648SFlorian Fainelli 1642bf9f2648SFlorian Fainelli if (!ds->ops->set_rxnfc) 1643bf9f2648SFlorian Fainelli return -EOPNOTSUPP; 1644bf9f2648SFlorian Fainelli 1645d945097bSVivien Didelot return ds->ops->set_rxnfc(ds, dp->index, nfc); 1646bf9f2648SFlorian Fainelli } 1647bf9f2648SFlorian Fainelli 16480336369dSBrandon Streiff static int dsa_slave_get_ts_info(struct net_device *dev, 16490336369dSBrandon Streiff struct ethtool_ts_info *ts) 16500336369dSBrandon Streiff { 16510336369dSBrandon Streiff struct dsa_slave_priv *p = netdev_priv(dev); 16520336369dSBrandon Streiff struct dsa_switch *ds = p->dp->ds; 16530336369dSBrandon Streiff 16540336369dSBrandon Streiff if (!ds->ops->get_ts_info) 16550336369dSBrandon Streiff return -EOPNOTSUPP; 16560336369dSBrandon Streiff 16570336369dSBrandon Streiff return ds->ops->get_ts_info(ds, p->dp->index, ts); 16580336369dSBrandon Streiff } 16590336369dSBrandon Streiff 1660061f6a50SFlorian Fainelli static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, 1661061f6a50SFlorian Fainelli u16 vid) 1662061f6a50SFlorian Fainelli { 1663061f6a50SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 166488236591SVladimir Oltean struct switchdev_obj_port_vlan vlan = { 166588236591SVladimir Oltean .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 1666b7a9e0daSVladimir Oltean .vid = vid, 166788236591SVladimir Oltean /* This API only allows programming tagged, non-PVID VIDs */ 166888236591SVladimir Oltean .flags = 0, 166988236591SVladimir Oltean }; 167031046a5fSVladimir Oltean struct netlink_ext_ack extack = {0}; 1671061f6a50SFlorian Fainelli int ret; 1672061f6a50SFlorian Fainelli 167388236591SVladimir Oltean /* User port... */ 167431046a5fSVladimir Oltean ret = dsa_port_vlan_add(dp, &vlan, &extack); 167531046a5fSVladimir Oltean if (ret) { 167631046a5fSVladimir Oltean if (extack._msg) 167731046a5fSVladimir Oltean netdev_err(dev, "%s\n", extack._msg); 167888236591SVladimir Oltean return ret; 167931046a5fSVladimir Oltean } 168088236591SVladimir Oltean 168188236591SVladimir Oltean /* And CPU port... */ 1682134ef238SVladimir Oltean ret = dsa_port_host_vlan_add(dp, &vlan, &extack); 168331046a5fSVladimir Oltean if (ret) { 168431046a5fSVladimir Oltean if (extack._msg) 168531046a5fSVladimir Oltean netdev_err(dev, "CPU port %d: %s\n", dp->cpu_dp->index, 168631046a5fSVladimir Oltean extack._msg); 16877e1741b4SVivien Didelot return ret; 168831046a5fSVladimir Oltean } 16897e1741b4SVivien Didelot 1690134ef238SVladimir Oltean return 0; 1691061f6a50SFlorian Fainelli } 1692061f6a50SFlorian Fainelli 1693061f6a50SFlorian Fainelli static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, 1694061f6a50SFlorian Fainelli u16 vid) 1695061f6a50SFlorian Fainelli { 1696061f6a50SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(dev); 169788236591SVladimir Oltean struct switchdev_obj_port_vlan vlan = { 1698b7a9e0daSVladimir Oltean .vid = vid, 169988236591SVladimir Oltean /* This API only allows programming tagged, non-PVID VIDs */ 170088236591SVladimir Oltean .flags = 0, 170188236591SVladimir Oltean }; 17022209158cSVladimir Oltean int err; 1703061f6a50SFlorian Fainelli 17042209158cSVladimir Oltean err = dsa_port_vlan_del(dp, &vlan); 17052209158cSVladimir Oltean if (err) 17062209158cSVladimir Oltean return err; 17072209158cSVladimir Oltean 1708134ef238SVladimir Oltean return dsa_port_host_vlan_del(dp, &vlan); 1709061f6a50SFlorian Fainelli } 1710061f6a50SFlorian Fainelli 171106cfb2dfSVladimir Oltean static int dsa_slave_restore_vlan(struct net_device *vdev, int vid, void *arg) 171206cfb2dfSVladimir Oltean { 171306cfb2dfSVladimir Oltean __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); 171406cfb2dfSVladimir Oltean 171506cfb2dfSVladimir Oltean return dsa_slave_vlan_rx_add_vid(arg, proto, vid); 171606cfb2dfSVladimir Oltean } 171706cfb2dfSVladimir Oltean 171806cfb2dfSVladimir Oltean static int dsa_slave_clear_vlan(struct net_device *vdev, int vid, void *arg) 171906cfb2dfSVladimir Oltean { 172006cfb2dfSVladimir Oltean __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); 172106cfb2dfSVladimir Oltean 172206cfb2dfSVladimir Oltean return dsa_slave_vlan_rx_kill_vid(arg, proto, vid); 172306cfb2dfSVladimir Oltean } 172406cfb2dfSVladimir Oltean 172506cfb2dfSVladimir Oltean /* Keep the VLAN RX filtering list in sync with the hardware only if VLAN 172606cfb2dfSVladimir Oltean * filtering is enabled. The baseline is that only ports that offload a 172706cfb2dfSVladimir Oltean * VLAN-aware bridge are VLAN-aware, and standalone ports are VLAN-unaware, 172806cfb2dfSVladimir Oltean * but there are exceptions for quirky hardware. 172906cfb2dfSVladimir Oltean * 173006cfb2dfSVladimir Oltean * If ds->vlan_filtering_is_global = true, then standalone ports which share 173106cfb2dfSVladimir Oltean * the same switch with other ports that offload a VLAN-aware bridge are also 173206cfb2dfSVladimir Oltean * inevitably VLAN-aware. 173306cfb2dfSVladimir Oltean * 173406cfb2dfSVladimir Oltean * To summarize, a DSA switch port offloads: 173506cfb2dfSVladimir Oltean * 173606cfb2dfSVladimir Oltean * - If standalone (this includes software bridge, software LAG): 173758adf9dcSVladimir Oltean * - if ds->needs_standalone_vlan_filtering = true, OR if 173858adf9dcSVladimir Oltean * (ds->vlan_filtering_is_global = true AND there are bridges spanning 173958adf9dcSVladimir Oltean * this switch chip which have vlan_filtering=1) 174006cfb2dfSVladimir Oltean * - the 8021q upper VLANs 174158adf9dcSVladimir Oltean * - else (standalone VLAN filtering is not needed, VLAN filtering is not 174258adf9dcSVladimir Oltean * global, or it is, but no port is under a VLAN-aware bridge): 174306cfb2dfSVladimir Oltean * - no VLAN (any 8021q upper is a software VLAN) 174406cfb2dfSVladimir Oltean * 174506cfb2dfSVladimir Oltean * - If under a vlan_filtering=0 bridge which it offload: 174606cfb2dfSVladimir Oltean * - if ds->configure_vlan_while_not_filtering = true (default): 174706cfb2dfSVladimir Oltean * - the bridge VLANs. These VLANs are committed to hardware but inactive. 174806cfb2dfSVladimir Oltean * - else (deprecated): 174906cfb2dfSVladimir Oltean * - no VLAN. The bridge VLANs are not restored when VLAN awareness is 175006cfb2dfSVladimir Oltean * enabled, so this behavior is broken and discouraged. 175106cfb2dfSVladimir Oltean * 175206cfb2dfSVladimir Oltean * - If under a vlan_filtering=1 bridge which it offload: 175306cfb2dfSVladimir Oltean * - the bridge VLANs 175406cfb2dfSVladimir Oltean * - the 8021q upper VLANs 175506cfb2dfSVladimir Oltean */ 175606cfb2dfSVladimir Oltean int dsa_slave_manage_vlan_filtering(struct net_device *slave, 175706cfb2dfSVladimir Oltean bool vlan_filtering) 175806cfb2dfSVladimir Oltean { 175906cfb2dfSVladimir Oltean int err; 176006cfb2dfSVladimir Oltean 176106cfb2dfSVladimir Oltean if (vlan_filtering) { 176206cfb2dfSVladimir Oltean slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 176306cfb2dfSVladimir Oltean 176406cfb2dfSVladimir Oltean err = vlan_for_each(slave, dsa_slave_restore_vlan, slave); 176506cfb2dfSVladimir Oltean if (err) { 176606cfb2dfSVladimir Oltean vlan_for_each(slave, dsa_slave_clear_vlan, slave); 176706cfb2dfSVladimir Oltean slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 176806cfb2dfSVladimir Oltean return err; 176906cfb2dfSVladimir Oltean } 177006cfb2dfSVladimir Oltean } else { 177106cfb2dfSVladimir Oltean err = vlan_for_each(slave, dsa_slave_clear_vlan, slave); 177206cfb2dfSVladimir Oltean if (err) 177306cfb2dfSVladimir Oltean return err; 177406cfb2dfSVladimir Oltean 177506cfb2dfSVladimir Oltean slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 177606cfb2dfSVladimir Oltean } 177706cfb2dfSVladimir Oltean 177806cfb2dfSVladimir Oltean return 0; 177906cfb2dfSVladimir Oltean } 178006cfb2dfSVladimir Oltean 1781bff33f7eSVladimir Oltean struct dsa_hw_port { 1782bff33f7eSVladimir Oltean struct list_head list; 1783bff33f7eSVladimir Oltean struct net_device *dev; 1784bff33f7eSVladimir Oltean int old_mtu; 1785bff33f7eSVladimir Oltean }; 1786bff33f7eSVladimir Oltean 1787bff33f7eSVladimir Oltean static int dsa_hw_port_list_set_mtu(struct list_head *hw_port_list, int mtu) 1788bff33f7eSVladimir Oltean { 1789bff33f7eSVladimir Oltean const struct dsa_hw_port *p; 1790bff33f7eSVladimir Oltean int err; 1791bff33f7eSVladimir Oltean 1792bff33f7eSVladimir Oltean list_for_each_entry(p, hw_port_list, list) { 1793bff33f7eSVladimir Oltean if (p->dev->mtu == mtu) 1794bff33f7eSVladimir Oltean continue; 1795bff33f7eSVladimir Oltean 1796bff33f7eSVladimir Oltean err = dev_set_mtu(p->dev, mtu); 1797bff33f7eSVladimir Oltean if (err) 1798bff33f7eSVladimir Oltean goto rollback; 1799bff33f7eSVladimir Oltean } 1800bff33f7eSVladimir Oltean 1801bff33f7eSVladimir Oltean return 0; 1802bff33f7eSVladimir Oltean 1803bff33f7eSVladimir Oltean rollback: 1804bff33f7eSVladimir Oltean list_for_each_entry_continue_reverse(p, hw_port_list, list) { 1805bff33f7eSVladimir Oltean if (p->dev->mtu == p->old_mtu) 1806bff33f7eSVladimir Oltean continue; 1807bff33f7eSVladimir Oltean 1808bff33f7eSVladimir Oltean if (dev_set_mtu(p->dev, p->old_mtu)) 1809bff33f7eSVladimir Oltean netdev_err(p->dev, "Failed to restore MTU\n"); 1810bff33f7eSVladimir Oltean } 1811bff33f7eSVladimir Oltean 1812bff33f7eSVladimir Oltean return err; 1813bff33f7eSVladimir Oltean } 1814bff33f7eSVladimir Oltean 1815bff33f7eSVladimir Oltean static void dsa_hw_port_list_free(struct list_head *hw_port_list) 1816bff33f7eSVladimir Oltean { 1817bff33f7eSVladimir Oltean struct dsa_hw_port *p, *n; 1818bff33f7eSVladimir Oltean 1819bff33f7eSVladimir Oltean list_for_each_entry_safe(p, n, hw_port_list, list) 1820bff33f7eSVladimir Oltean kfree(p); 1821bff33f7eSVladimir Oltean } 1822bff33f7eSVladimir Oltean 1823bff33f7eSVladimir Oltean /* Make the hardware datapath to/from @dev limited to a common MTU */ 1824bf88dc32Skbuild test robot static void dsa_bridge_mtu_normalization(struct dsa_port *dp) 1825bff33f7eSVladimir Oltean { 1826bff33f7eSVladimir Oltean struct list_head hw_port_list; 1827bff33f7eSVladimir Oltean struct dsa_switch_tree *dst; 1828bff33f7eSVladimir Oltean int min_mtu = ETH_MAX_MTU; 1829bff33f7eSVladimir Oltean struct dsa_port *other_dp; 1830bff33f7eSVladimir Oltean int err; 1831bff33f7eSVladimir Oltean 1832bff33f7eSVladimir Oltean if (!dp->ds->mtu_enforcement_ingress) 1833bff33f7eSVladimir Oltean return; 1834bff33f7eSVladimir Oltean 1835d3eed0e5SVladimir Oltean if (!dp->bridge) 1836bff33f7eSVladimir Oltean return; 1837bff33f7eSVladimir Oltean 1838bff33f7eSVladimir Oltean INIT_LIST_HEAD(&hw_port_list); 1839bff33f7eSVladimir Oltean 1840bff33f7eSVladimir Oltean /* Populate the list of ports that are part of the same bridge 1841bff33f7eSVladimir Oltean * as the newly added/modified port 1842bff33f7eSVladimir Oltean */ 1843bff33f7eSVladimir Oltean list_for_each_entry(dst, &dsa_tree_list, list) { 1844bff33f7eSVladimir Oltean list_for_each_entry(other_dp, &dst->ports, list) { 1845bff33f7eSVladimir Oltean struct dsa_hw_port *hw_port; 1846bff33f7eSVladimir Oltean struct net_device *slave; 1847bff33f7eSVladimir Oltean 1848bff33f7eSVladimir Oltean if (other_dp->type != DSA_PORT_TYPE_USER) 1849bff33f7eSVladimir Oltean continue; 1850bff33f7eSVladimir Oltean 185136cbf39bSVladimir Oltean if (!dsa_port_bridge_same(dp, other_dp)) 1852bff33f7eSVladimir Oltean continue; 1853bff33f7eSVladimir Oltean 1854bff33f7eSVladimir Oltean if (!other_dp->ds->mtu_enforcement_ingress) 1855bff33f7eSVladimir Oltean continue; 1856bff33f7eSVladimir Oltean 1857bff33f7eSVladimir Oltean slave = other_dp->slave; 1858bff33f7eSVladimir Oltean 1859bff33f7eSVladimir Oltean if (min_mtu > slave->mtu) 1860bff33f7eSVladimir Oltean min_mtu = slave->mtu; 1861bff33f7eSVladimir Oltean 1862bff33f7eSVladimir Oltean hw_port = kzalloc(sizeof(*hw_port), GFP_KERNEL); 1863bff33f7eSVladimir Oltean if (!hw_port) 1864bff33f7eSVladimir Oltean goto out; 1865bff33f7eSVladimir Oltean 1866bff33f7eSVladimir Oltean hw_port->dev = slave; 1867bff33f7eSVladimir Oltean hw_port->old_mtu = slave->mtu; 1868bff33f7eSVladimir Oltean 1869bff33f7eSVladimir Oltean list_add(&hw_port->list, &hw_port_list); 1870bff33f7eSVladimir Oltean } 1871bff33f7eSVladimir Oltean } 1872bff33f7eSVladimir Oltean 1873bff33f7eSVladimir Oltean /* Attempt to configure the entire hardware bridge to the newly added 1874bff33f7eSVladimir Oltean * interface's MTU first, regardless of whether the intention of the 1875bff33f7eSVladimir Oltean * user was to raise or lower it. 1876bff33f7eSVladimir Oltean */ 1877bff33f7eSVladimir Oltean err = dsa_hw_port_list_set_mtu(&hw_port_list, dp->slave->mtu); 1878bff33f7eSVladimir Oltean if (!err) 1879bff33f7eSVladimir Oltean goto out; 1880bff33f7eSVladimir Oltean 1881bff33f7eSVladimir Oltean /* Clearly that didn't work out so well, so just set the minimum MTU on 1882bff33f7eSVladimir Oltean * all hardware bridge ports now. If this fails too, then all ports will 1883bff33f7eSVladimir Oltean * still have their old MTU rolled back anyway. 1884bff33f7eSVladimir Oltean */ 1885bff33f7eSVladimir Oltean dsa_hw_port_list_set_mtu(&hw_port_list, min_mtu); 1886bff33f7eSVladimir Oltean 1887bff33f7eSVladimir Oltean out: 1888bff33f7eSVladimir Oltean dsa_hw_port_list_free(&hw_port_list); 1889bff33f7eSVladimir Oltean } 1890bff33f7eSVladimir Oltean 189153da0ebaSVladimir Oltean int dsa_slave_change_mtu(struct net_device *dev, int new_mtu) 1892bfcb8132SVladimir Oltean { 1893bfcb8132SVladimir Oltean struct net_device *master = dsa_slave_to_master(dev); 1894bfcb8132SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1895cf1c39d3SVladimir Oltean struct dsa_port *cpu_dp = dp->cpu_dp; 18964715029fSVladimir Oltean struct dsa_switch *ds = dp->ds; 1897b2033a05SVladimir Oltean struct dsa_port *other_dp; 1898bfcb8132SVladimir Oltean int largest_mtu = 0; 1899bfcb8132SVladimir Oltean int new_master_mtu; 1900bfcb8132SVladimir Oltean int old_master_mtu; 1901bfcb8132SVladimir Oltean int mtu_limit; 1902bfcb8132SVladimir Oltean int cpu_mtu; 19034e4ab795SVladimir Oltean int err; 1904bfcb8132SVladimir Oltean 1905bfcb8132SVladimir Oltean if (!ds->ops->port_change_mtu) 1906bfcb8132SVladimir Oltean return -EOPNOTSUPP; 1907bfcb8132SVladimir Oltean 1908b2033a05SVladimir Oltean dsa_tree_for_each_user_port(other_dp, ds->dst) { 1909bfcb8132SVladimir Oltean int slave_mtu; 1910bfcb8132SVladimir Oltean 1911bfcb8132SVladimir Oltean /* During probe, this function will be called for each slave 1912bfcb8132SVladimir Oltean * device, while not all of them have been allocated. That's 1913bfcb8132SVladimir Oltean * ok, it doesn't change what the maximum is, so ignore it. 1914bfcb8132SVladimir Oltean */ 1915b2033a05SVladimir Oltean if (!other_dp->slave) 1916bfcb8132SVladimir Oltean continue; 1917bfcb8132SVladimir Oltean 1918bfcb8132SVladimir Oltean /* Pretend that we already applied the setting, which we 1919bfcb8132SVladimir Oltean * actually haven't (still haven't done all integrity checks) 1920bfcb8132SVladimir Oltean */ 1921b2033a05SVladimir Oltean if (dp == other_dp) 1922bfcb8132SVladimir Oltean slave_mtu = new_mtu; 1923bfcb8132SVladimir Oltean else 1924b2033a05SVladimir Oltean slave_mtu = other_dp->slave->mtu; 1925bfcb8132SVladimir Oltean 1926bfcb8132SVladimir Oltean if (largest_mtu < slave_mtu) 1927bfcb8132SVladimir Oltean largest_mtu = slave_mtu; 1928bfcb8132SVladimir Oltean } 1929bfcb8132SVladimir Oltean 1930bfcb8132SVladimir Oltean mtu_limit = min_t(int, master->max_mtu, dev->max_mtu); 1931bfcb8132SVladimir Oltean old_master_mtu = master->mtu; 19324e500251SVladimir Oltean new_master_mtu = largest_mtu + dsa_tag_protocol_overhead(cpu_dp->tag_ops); 1933bfcb8132SVladimir Oltean if (new_master_mtu > mtu_limit) 1934bfcb8132SVladimir Oltean return -ERANGE; 1935bfcb8132SVladimir Oltean 1936bfcb8132SVladimir Oltean /* If the master MTU isn't over limit, there's no need to check the CPU 1937bfcb8132SVladimir Oltean * MTU, since that surely isn't either. 1938bfcb8132SVladimir Oltean */ 1939bfcb8132SVladimir Oltean cpu_mtu = largest_mtu; 1940bfcb8132SVladimir Oltean 1941bfcb8132SVladimir Oltean /* Start applying stuff */ 1942bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) { 1943bfcb8132SVladimir Oltean err = dev_set_mtu(master, new_master_mtu); 1944bfcb8132SVladimir Oltean if (err < 0) 1945bfcb8132SVladimir Oltean goto out_master_failed; 1946bfcb8132SVladimir Oltean 1947bfcb8132SVladimir Oltean /* We only need to propagate the MTU of the CPU port to 1948be6ff966SVladimir Oltean * upstream switches, so emit a notifier which updates them. 1949bfcb8132SVladimir Oltean */ 1950be6ff966SVladimir Oltean err = dsa_port_mtu_change(cpu_dp, cpu_mtu); 1951bfcb8132SVladimir Oltean if (err) 1952bfcb8132SVladimir Oltean goto out_cpu_failed; 1953bfcb8132SVladimir Oltean } 1954bfcb8132SVladimir Oltean 1955be6ff966SVladimir Oltean err = ds->ops->port_change_mtu(ds, dp->index, new_mtu); 1956bfcb8132SVladimir Oltean if (err) 1957bfcb8132SVladimir Oltean goto out_port_failed; 1958bfcb8132SVladimir Oltean 1959bfcb8132SVladimir Oltean dev->mtu = new_mtu; 1960bfcb8132SVladimir Oltean 1961bff33f7eSVladimir Oltean dsa_bridge_mtu_normalization(dp); 1962bff33f7eSVladimir Oltean 1963bfcb8132SVladimir Oltean return 0; 1964bfcb8132SVladimir Oltean 1965bfcb8132SVladimir Oltean out_port_failed: 1966bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) 1967bfcb8132SVladimir Oltean dsa_port_mtu_change(cpu_dp, old_master_mtu - 1968be6ff966SVladimir Oltean dsa_tag_protocol_overhead(cpu_dp->tag_ops)); 1969bfcb8132SVladimir Oltean out_cpu_failed: 1970bfcb8132SVladimir Oltean if (new_master_mtu != old_master_mtu) 1971bfcb8132SVladimir Oltean dev_set_mtu(master, old_master_mtu); 1972bfcb8132SVladimir Oltean out_master_failed: 1973bfcb8132SVladimir Oltean return err; 1974bfcb8132SVladimir Oltean } 1975bfcb8132SVladimir Oltean 1976d538eca8SVladimir Oltean static int __maybe_unused 1977d538eca8SVladimir Oltean dsa_slave_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app) 1978d538eca8SVladimir Oltean { 1979d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 1980d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 1981d538eca8SVladimir Oltean unsigned long mask, new_prio; 1982d538eca8SVladimir Oltean int err, port = dp->index; 1983d538eca8SVladimir Oltean 1984d538eca8SVladimir Oltean if (!ds->ops->port_set_default_prio) 1985d538eca8SVladimir Oltean return -EOPNOTSUPP; 1986d538eca8SVladimir Oltean 1987d538eca8SVladimir Oltean err = dcb_ieee_setapp(dev, app); 1988d538eca8SVladimir Oltean if (err) 1989d538eca8SVladimir Oltean return err; 1990d538eca8SVladimir Oltean 1991d538eca8SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 1992d538eca8SVladimir Oltean new_prio = __fls(mask); 1993d538eca8SVladimir Oltean 1994d538eca8SVladimir Oltean err = ds->ops->port_set_default_prio(ds, port, new_prio); 1995d538eca8SVladimir Oltean if (err) { 1996d538eca8SVladimir Oltean dcb_ieee_delapp(dev, app); 1997d538eca8SVladimir Oltean return err; 1998d538eca8SVladimir Oltean } 1999d538eca8SVladimir Oltean 2000d538eca8SVladimir Oltean return 0; 2001d538eca8SVladimir Oltean } 2002d538eca8SVladimir Oltean 200347d75f78SVladimir Oltean static int __maybe_unused 200447d75f78SVladimir Oltean dsa_slave_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) 200547d75f78SVladimir Oltean { 200647d75f78SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 200747d75f78SVladimir Oltean struct dsa_switch *ds = dp->ds; 200847d75f78SVladimir Oltean unsigned long mask, new_prio; 200947d75f78SVladimir Oltean int err, port = dp->index; 201047d75f78SVladimir Oltean u8 dscp = app->protocol; 201147d75f78SVladimir Oltean 201247d75f78SVladimir Oltean if (!ds->ops->port_add_dscp_prio) 201347d75f78SVladimir Oltean return -EOPNOTSUPP; 201447d75f78SVladimir Oltean 201547d75f78SVladimir Oltean if (dscp >= 64) { 201647d75f78SVladimir Oltean netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n", 201747d75f78SVladimir Oltean dscp); 201847d75f78SVladimir Oltean return -EINVAL; 201947d75f78SVladimir Oltean } 202047d75f78SVladimir Oltean 202147d75f78SVladimir Oltean err = dcb_ieee_setapp(dev, app); 202247d75f78SVladimir Oltean if (err) 202347d75f78SVladimir Oltean return err; 202447d75f78SVladimir Oltean 202547d75f78SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 202647d75f78SVladimir Oltean new_prio = __fls(mask); 202747d75f78SVladimir Oltean 202847d75f78SVladimir Oltean err = ds->ops->port_add_dscp_prio(ds, port, dscp, new_prio); 202947d75f78SVladimir Oltean if (err) { 203047d75f78SVladimir Oltean dcb_ieee_delapp(dev, app); 203147d75f78SVladimir Oltean return err; 203247d75f78SVladimir Oltean } 203347d75f78SVladimir Oltean 203447d75f78SVladimir Oltean return 0; 203547d75f78SVladimir Oltean } 203647d75f78SVladimir Oltean 2037d538eca8SVladimir Oltean static int __maybe_unused dsa_slave_dcbnl_ieee_setapp(struct net_device *dev, 2038d538eca8SVladimir Oltean struct dcb_app *app) 2039d538eca8SVladimir Oltean { 2040d538eca8SVladimir Oltean switch (app->selector) { 2041d538eca8SVladimir Oltean case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 2042d538eca8SVladimir Oltean switch (app->protocol) { 2043d538eca8SVladimir Oltean case 0: 2044d538eca8SVladimir Oltean return dsa_slave_dcbnl_set_default_prio(dev, app); 2045d538eca8SVladimir Oltean default: 2046d538eca8SVladimir Oltean return -EOPNOTSUPP; 2047d538eca8SVladimir Oltean } 2048d538eca8SVladimir Oltean break; 204947d75f78SVladimir Oltean case IEEE_8021QAZ_APP_SEL_DSCP: 205047d75f78SVladimir Oltean return dsa_slave_dcbnl_add_dscp_prio(dev, app); 2051d538eca8SVladimir Oltean default: 2052d538eca8SVladimir Oltean return -EOPNOTSUPP; 2053d538eca8SVladimir Oltean } 2054d538eca8SVladimir Oltean } 2055d538eca8SVladimir Oltean 2056d538eca8SVladimir Oltean static int __maybe_unused 2057d538eca8SVladimir Oltean dsa_slave_dcbnl_del_default_prio(struct net_device *dev, struct dcb_app *app) 2058d538eca8SVladimir Oltean { 2059d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2060d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 2061d538eca8SVladimir Oltean unsigned long mask, new_prio; 2062d538eca8SVladimir Oltean int err, port = dp->index; 2063d538eca8SVladimir Oltean 2064d538eca8SVladimir Oltean if (!ds->ops->port_set_default_prio) 2065d538eca8SVladimir Oltean return -EOPNOTSUPP; 2066d538eca8SVladimir Oltean 2067d538eca8SVladimir Oltean err = dcb_ieee_delapp(dev, app); 2068d538eca8SVladimir Oltean if (err) 2069d538eca8SVladimir Oltean return err; 2070d538eca8SVladimir Oltean 2071d538eca8SVladimir Oltean mask = dcb_ieee_getapp_mask(dev, app); 2072d538eca8SVladimir Oltean new_prio = mask ? __fls(mask) : 0; 2073d538eca8SVladimir Oltean 2074d538eca8SVladimir Oltean err = ds->ops->port_set_default_prio(ds, port, new_prio); 2075d538eca8SVladimir Oltean if (err) { 2076d538eca8SVladimir Oltean dcb_ieee_setapp(dev, app); 2077d538eca8SVladimir Oltean return err; 2078d538eca8SVladimir Oltean } 2079d538eca8SVladimir Oltean 2080d538eca8SVladimir Oltean return 0; 2081d538eca8SVladimir Oltean } 2082d538eca8SVladimir Oltean 208347d75f78SVladimir Oltean static int __maybe_unused 208447d75f78SVladimir Oltean dsa_slave_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) 208547d75f78SVladimir Oltean { 208647d75f78SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 208747d75f78SVladimir Oltean struct dsa_switch *ds = dp->ds; 208847d75f78SVladimir Oltean int err, port = dp->index; 208947d75f78SVladimir Oltean u8 dscp = app->protocol; 209047d75f78SVladimir Oltean 209147d75f78SVladimir Oltean if (!ds->ops->port_del_dscp_prio) 209247d75f78SVladimir Oltean return -EOPNOTSUPP; 209347d75f78SVladimir Oltean 209447d75f78SVladimir Oltean err = dcb_ieee_delapp(dev, app); 209547d75f78SVladimir Oltean if (err) 209647d75f78SVladimir Oltean return err; 209747d75f78SVladimir Oltean 209847d75f78SVladimir Oltean err = ds->ops->port_del_dscp_prio(ds, port, dscp, app->priority); 209947d75f78SVladimir Oltean if (err) { 210047d75f78SVladimir Oltean dcb_ieee_setapp(dev, app); 210147d75f78SVladimir Oltean return err; 210247d75f78SVladimir Oltean } 210347d75f78SVladimir Oltean 210447d75f78SVladimir Oltean return 0; 210547d75f78SVladimir Oltean } 210647d75f78SVladimir Oltean 2107d538eca8SVladimir Oltean static int __maybe_unused dsa_slave_dcbnl_ieee_delapp(struct net_device *dev, 2108d538eca8SVladimir Oltean struct dcb_app *app) 2109d538eca8SVladimir Oltean { 2110d538eca8SVladimir Oltean switch (app->selector) { 2111d538eca8SVladimir Oltean case IEEE_8021QAZ_APP_SEL_ETHERTYPE: 2112d538eca8SVladimir Oltean switch (app->protocol) { 2113d538eca8SVladimir Oltean case 0: 2114d538eca8SVladimir Oltean return dsa_slave_dcbnl_del_default_prio(dev, app); 2115d538eca8SVladimir Oltean default: 2116d538eca8SVladimir Oltean return -EOPNOTSUPP; 2117d538eca8SVladimir Oltean } 2118d538eca8SVladimir Oltean break; 211947d75f78SVladimir Oltean case IEEE_8021QAZ_APP_SEL_DSCP: 212047d75f78SVladimir Oltean return dsa_slave_dcbnl_del_dscp_prio(dev, app); 2121d538eca8SVladimir Oltean default: 2122d538eca8SVladimir Oltean return -EOPNOTSUPP; 2123d538eca8SVladimir Oltean } 2124d538eca8SVladimir Oltean } 2125d538eca8SVladimir Oltean 2126d538eca8SVladimir Oltean /* Pre-populate the DCB application priority table with the priorities 2127d538eca8SVladimir Oltean * configured during switch setup, which we read from hardware here. 2128d538eca8SVladimir Oltean */ 2129d538eca8SVladimir Oltean static int dsa_slave_dcbnl_init(struct net_device *dev) 2130d538eca8SVladimir Oltean { 2131d538eca8SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 2132d538eca8SVladimir Oltean struct dsa_switch *ds = dp->ds; 2133d538eca8SVladimir Oltean int port = dp->index; 2134d538eca8SVladimir Oltean int err; 2135d538eca8SVladimir Oltean 2136d538eca8SVladimir Oltean if (ds->ops->port_get_default_prio) { 2137d538eca8SVladimir Oltean int prio = ds->ops->port_get_default_prio(ds, port); 2138d538eca8SVladimir Oltean struct dcb_app app = { 2139d538eca8SVladimir Oltean .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE, 2140d538eca8SVladimir Oltean .protocol = 0, 2141d538eca8SVladimir Oltean .priority = prio, 2142d538eca8SVladimir Oltean }; 2143d538eca8SVladimir Oltean 2144d538eca8SVladimir Oltean if (prio < 0) 2145d538eca8SVladimir Oltean return prio; 2146d538eca8SVladimir Oltean 2147d538eca8SVladimir Oltean err = dcb_ieee_setapp(dev, &app); 2148d538eca8SVladimir Oltean if (err) 2149d538eca8SVladimir Oltean return err; 2150d538eca8SVladimir Oltean } 2151d538eca8SVladimir Oltean 215247d75f78SVladimir Oltean if (ds->ops->port_get_dscp_prio) { 215347d75f78SVladimir Oltean int protocol; 215447d75f78SVladimir Oltean 215547d75f78SVladimir Oltean for (protocol = 0; protocol < 64; protocol++) { 215647d75f78SVladimir Oltean struct dcb_app app = { 215747d75f78SVladimir Oltean .selector = IEEE_8021QAZ_APP_SEL_DSCP, 215847d75f78SVladimir Oltean .protocol = protocol, 215947d75f78SVladimir Oltean }; 216047d75f78SVladimir Oltean int prio; 216147d75f78SVladimir Oltean 216247d75f78SVladimir Oltean prio = ds->ops->port_get_dscp_prio(ds, port, protocol); 216347d75f78SVladimir Oltean if (prio == -EOPNOTSUPP) 216447d75f78SVladimir Oltean continue; 216547d75f78SVladimir Oltean if (prio < 0) 216647d75f78SVladimir Oltean return prio; 216747d75f78SVladimir Oltean 216847d75f78SVladimir Oltean app.priority = prio; 216947d75f78SVladimir Oltean 217047d75f78SVladimir Oltean err = dcb_ieee_setapp(dev, &app); 217147d75f78SVladimir Oltean if (err) 217247d75f78SVladimir Oltean return err; 217347d75f78SVladimir Oltean } 217447d75f78SVladimir Oltean } 217547d75f78SVladimir Oltean 2176d538eca8SVladimir Oltean return 0; 2177d538eca8SVladimir Oltean } 2178d538eca8SVladimir Oltean 217991da11f8SLennert Buytenhek static const struct ethtool_ops dsa_slave_ethtool_ops = { 218091da11f8SLennert Buytenhek .get_drvinfo = dsa_slave_get_drvinfo, 21813d762a0fSGuenter Roeck .get_regs_len = dsa_slave_get_regs_len, 21823d762a0fSGuenter Roeck .get_regs = dsa_slave_get_regs, 2183aab9c406SFlorian Fainelli .nway_reset = dsa_slave_nway_reset, 2184c4aef9fcSFlorian Fainelli .get_link = ethtool_op_get_link, 21856793abb4SGuenter Roeck .get_eeprom_len = dsa_slave_get_eeprom_len, 21866793abb4SGuenter Roeck .get_eeprom = dsa_slave_get_eeprom, 21876793abb4SGuenter Roeck .set_eeprom = dsa_slave_set_eeprom, 218891da11f8SLennert Buytenhek .get_strings = dsa_slave_get_strings, 218991da11f8SLennert Buytenhek .get_ethtool_stats = dsa_slave_get_ethtool_stats, 219091da11f8SLennert Buytenhek .get_sset_count = dsa_slave_get_sset_count, 2191487d3855SAlvin Šipraga .get_eth_phy_stats = dsa_slave_get_eth_phy_stats, 2192487d3855SAlvin Šipraga .get_eth_mac_stats = dsa_slave_get_eth_mac_stats, 2193487d3855SAlvin Šipraga .get_eth_ctrl_stats = dsa_slave_get_eth_ctrl_stats, 219467f38b1cSClément Léger .get_rmon_stats = dsa_slave_get_rmon_stats, 219519e57c4eSFlorian Fainelli .set_wol = dsa_slave_set_wol, 219619e57c4eSFlorian Fainelli .get_wol = dsa_slave_get_wol, 21977905288fSFlorian Fainelli .set_eee = dsa_slave_set_eee, 21987905288fSFlorian Fainelli .get_eee = dsa_slave_get_eee, 2199aab9c406SFlorian Fainelli .get_link_ksettings = dsa_slave_get_link_ksettings, 2200aab9c406SFlorian Fainelli .set_link_ksettings = dsa_slave_set_link_ksettings, 22013d410403SOleksij Rempel .get_pause_stats = dsa_slave_get_pause_stats, 2202a2a1a13bSHeiner Kallweit .get_pauseparam = dsa_slave_get_pauseparam, 2203a2a1a13bSHeiner Kallweit .set_pauseparam = dsa_slave_set_pauseparam, 2204bf9f2648SFlorian Fainelli .get_rxnfc = dsa_slave_get_rxnfc, 2205bf9f2648SFlorian Fainelli .set_rxnfc = dsa_slave_set_rxnfc, 22060336369dSBrandon Streiff .get_ts_info = dsa_slave_get_ts_info, 2207a71acad9SOleksij Rempel .self_test = dsa_slave_net_selftest, 220891da11f8SLennert Buytenhek }; 220991da11f8SLennert Buytenhek 2210d538eca8SVladimir Oltean static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = { 2211d538eca8SVladimir Oltean .ieee_setapp = dsa_slave_dcbnl_ieee_setapp, 2212d538eca8SVladimir Oltean .ieee_delapp = dsa_slave_dcbnl_ieee_delapp, 2213d538eca8SVladimir Oltean }; 2214d538eca8SVladimir Oltean 2215c2ec5f2eSOleksij Rempel static void dsa_slave_get_stats64(struct net_device *dev, 2216c2ec5f2eSOleksij Rempel struct rtnl_link_stats64 *s) 2217c2ec5f2eSOleksij Rempel { 2218c2ec5f2eSOleksij Rempel struct dsa_port *dp = dsa_slave_to_port(dev); 2219c2ec5f2eSOleksij Rempel struct dsa_switch *ds = dp->ds; 2220c2ec5f2eSOleksij Rempel 2221c2ec5f2eSOleksij Rempel if (ds->ops->get_stats64) 2222c2ec5f2eSOleksij Rempel ds->ops->get_stats64(ds, dp->index, s); 2223c2ec5f2eSOleksij Rempel else 2224c2ec5f2eSOleksij Rempel dev_get_tstats64(dev, s); 2225c2ec5f2eSOleksij Rempel } 2226c2ec5f2eSOleksij Rempel 22270994d492SFelix Fietkau static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx, 22280994d492SFelix Fietkau struct net_device_path *path) 22290994d492SFelix Fietkau { 22300994d492SFelix Fietkau struct dsa_port *dp = dsa_slave_to_port(ctx->dev); 22318f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 22320994d492SFelix Fietkau struct dsa_port *cpu_dp = dp->cpu_dp; 22330994d492SFelix Fietkau 22340994d492SFelix Fietkau path->dev = ctx->dev; 22350994d492SFelix Fietkau path->type = DEV_PATH_DSA; 22360994d492SFelix Fietkau path->dsa.proto = cpu_dp->tag_ops->proto; 22370994d492SFelix Fietkau path->dsa.port = dp->index; 22388f6a19c0SVladimir Oltean ctx->dev = master; 22390994d492SFelix Fietkau 22400994d492SFelix Fietkau return 0; 22410994d492SFelix Fietkau } 22420994d492SFelix Fietkau 22433e8a72d1SFlorian Fainelli static const struct net_device_ops dsa_slave_netdev_ops = { 2244d442ad4aSStephen Hemminger .ndo_open = dsa_slave_open, 2245d442ad4aSStephen Hemminger .ndo_stop = dsa_slave_close, 22463e8a72d1SFlorian Fainelli .ndo_start_xmit = dsa_slave_xmit, 2247d442ad4aSStephen Hemminger .ndo_change_rx_flags = dsa_slave_change_rx_flags, 2248d442ad4aSStephen Hemminger .ndo_set_rx_mode = dsa_slave_set_rx_mode, 2249d442ad4aSStephen Hemminger .ndo_set_mac_address = dsa_slave_set_mac_address, 22502bedde1aSArkadi Sharshevsky .ndo_fdb_dump = dsa_slave_fdb_dump, 2251a7605370SArnd Bergmann .ndo_eth_ioctl = dsa_slave_ioctl, 2252abd2be00SNicolas Dichtel .ndo_get_iflink = dsa_slave_get_iflink, 225304ff53f9SFlorian Fainelli #ifdef CONFIG_NET_POLL_CONTROLLER 225404ff53f9SFlorian Fainelli .ndo_netpoll_setup = dsa_slave_netpoll_setup, 225504ff53f9SFlorian Fainelli .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup, 225604ff53f9SFlorian Fainelli .ndo_poll_controller = dsa_slave_poll_controller, 225704ff53f9SFlorian Fainelli #endif 2258f50f2127SFlorian Fainelli .ndo_setup_tc = dsa_slave_setup_tc, 2259c2ec5f2eSOleksij Rempel .ndo_get_stats64 = dsa_slave_get_stats64, 2260061f6a50SFlorian Fainelli .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, 2261061f6a50SFlorian Fainelli .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, 2262bfcb8132SVladimir Oltean .ndo_change_mtu = dsa_slave_change_mtu, 22630994d492SFelix Fietkau .ndo_fill_forward_path = dsa_slave_fill_forward_path, 226498237d43SScott Feldman }; 226598237d43SScott Feldman 2266f37db85dSFlorian Fainelli static struct device_type dsa_type = { 2267f37db85dSFlorian Fainelli .name = "dsa", 2268f37db85dSFlorian Fainelli }; 2269f37db85dSFlorian Fainelli 2270aab9c406SFlorian Fainelli void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up) 2271aab9c406SFlorian Fainelli { 2272aab9c406SFlorian Fainelli const struct dsa_port *dp = dsa_to_port(ds, port); 2273aab9c406SFlorian Fainelli 2274765bda93SRussell King if (dp->pl) 2275aab9c406SFlorian Fainelli phylink_mac_change(dp->pl, up); 2276aab9c406SFlorian Fainelli } 2277aab9c406SFlorian Fainelli EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); 2278aab9c406SFlorian Fainelli 22795c05c1dbSRussell King static void dsa_slave_phylink_fixed_state(struct phylink_config *config, 2280aab9c406SFlorian Fainelli struct phylink_link_state *state) 2281aab9c406SFlorian Fainelli { 22825c05c1dbSRussell King struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); 2283aab9c406SFlorian Fainelli struct dsa_switch *ds = dp->ds; 2284aab9c406SFlorian Fainelli 2285aab9c406SFlorian Fainelli /* No need to check that this operation is valid, the callback would 2286aab9c406SFlorian Fainelli * not be called if it was not. 2287aab9c406SFlorian Fainelli */ 2288aab9c406SFlorian Fainelli ds->ops->phylink_fixed_state(ds, dp->index, state); 2289ce31b31cSFlorian Fainelli } 2290ce31b31cSFlorian Fainelli 229191da11f8SLennert Buytenhek /* slave device setup *******************************************************/ 2292c916e8e1SOleksij Rempel static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr, 2293c916e8e1SOleksij Rempel u32 flags) 2294c305c165SFlorian Fainelli { 2295d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2296d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 2297c305c165SFlorian Fainelli 22980115dcd1SVivien Didelot slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr); 22990115dcd1SVivien Didelot if (!slave_dev->phydev) { 2300d25b8e74SRussell King netdev_err(slave_dev, "no phy at %d\n", addr); 2301c305c165SFlorian Fainelli return -ENODEV; 2302d25b8e74SRussell King } 2303c305c165SFlorian Fainelli 2304c916e8e1SOleksij Rempel slave_dev->phydev->dev_flags |= flags; 2305c916e8e1SOleksij Rempel 2306aab9c406SFlorian Fainelli return phylink_connect_phy(dp->pl, slave_dev->phydev); 2307c305c165SFlorian Fainelli } 2308c305c165SFlorian Fainelli 23094fa7b718SVivien Didelot static int dsa_slave_phy_setup(struct net_device *slave_dev) 23100d8bcdd3SFlorian Fainelli { 2311d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2312d945097bSVivien Didelot struct device_node *port_dn = dp->dn; 2313d945097bSVivien Didelot struct dsa_switch *ds = dp->ds; 23146819563eSFlorian Fainelli u32 phy_flags = 0; 23150c65b2b9SAndrew Lunn int ret; 23160d8bcdd3SFlorian Fainelli 231744cc27e4SIoana Ciornei dp->pl_config.dev = &slave_dev->dev; 231844cc27e4SIoana Ciornei dp->pl_config.type = PHYLINK_NETDEV; 231944cc27e4SIoana Ciornei 23205c05c1dbSRussell King /* The get_fixed_state callback takes precedence over polling the 23215c05c1dbSRussell King * link GPIO in PHYLINK (see phylink_get_fixed_state). Only set 23225c05c1dbSRussell King * this if the switch provides such a callback. 23235c05c1dbSRussell King */ 23245c05c1dbSRussell King if (ds->ops->phylink_fixed_state) { 23255c05c1dbSRussell King dp->pl_config.get_fixed_state = dsa_slave_phylink_fixed_state; 23265c05c1dbSRussell King dp->pl_config.poll_fixed_state = true; 23275c05c1dbSRussell King } 23285c05c1dbSRussell King 232921bd64bdSRussell King (Oracle) ret = dsa_port_phylink_create(dp); 233021bd64bdSRussell King (Oracle) if (ret) 233121bd64bdSRussell King (Oracle) return ret; 2332aab9c406SFlorian Fainelli 23339d490b4eSVivien Didelot if (ds->ops->get_phy_flags) 2334d945097bSVivien Didelot phy_flags = ds->ops->get_phy_flags(ds, dp->index); 23356819563eSFlorian Fainelli 2336aab9c406SFlorian Fainelli ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); 23376146dd45SVladimir Oltean if (ret == -ENODEV && ds->slave_mii_bus) { 23386146dd45SVladimir Oltean /* We could not connect to a designated PHY or SFP, so try to 23396146dd45SVladimir Oltean * use the switch internal MDIO bus instead 23400d8bcdd3SFlorian Fainelli */ 2341c916e8e1SOleksij Rempel ret = dsa_slave_phy_connect(slave_dev, dp->index, phy_flags); 2342d25b8e74SRussell King } 23436a52e733SVladimir Oltean if (ret) { 23446a52e733SVladimir Oltean netdev_err(slave_dev, "failed to connect to PHY: %pe\n", 23456a52e733SVladimir Oltean ERR_PTR(ret)); 2346cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(dp); 23470d8bcdd3SFlorian Fainelli } 23489697f1cdSFlorian Fainelli 23496146dd45SVladimir Oltean return ret; 2350b31f65fbSAndrew Lunn } 23510d8bcdd3SFlorian Fainelli 235253da0ebaSVladimir Oltean void dsa_slave_setup_tagger(struct net_device *slave) 235353da0ebaSVladimir Oltean { 235453da0ebaSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(slave); 23558f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(dp); 235653da0ebaSVladimir Oltean struct dsa_slave_priv *p = netdev_priv(slave); 235753da0ebaSVladimir Oltean const struct dsa_port *cpu_dp = dp->cpu_dp; 235858adf9dcSVladimir Oltean const struct dsa_switch *ds = dp->ds; 235953da0ebaSVladimir Oltean 23604e500251SVladimir Oltean slave->needed_headroom = cpu_dp->tag_ops->needed_headroom; 23614e500251SVladimir Oltean slave->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; 236253da0ebaSVladimir Oltean /* Try to save one extra realloc later in the TX path (in the master) 236353da0ebaSVladimir Oltean * by also inheriting the master's needed headroom and tailroom. 236453da0ebaSVladimir Oltean * The 8021q driver also does this. 236553da0ebaSVladimir Oltean */ 236653da0ebaSVladimir Oltean slave->needed_headroom += master->needed_headroom; 236753da0ebaSVladimir Oltean slave->needed_tailroom += master->needed_tailroom; 236853da0ebaSVladimir Oltean 236953da0ebaSVladimir Oltean p->xmit = cpu_dp->tag_ops->xmit; 237021cf377aSLino Sanfilippo 237121cf377aSLino Sanfilippo slave->features = master->vlan_features | NETIF_F_HW_TC; 237221cf377aSLino Sanfilippo slave->hw_features |= NETIF_F_HW_TC; 237321cf377aSLino Sanfilippo slave->features |= NETIF_F_LLTX; 237421cf377aSLino Sanfilippo if (slave->needed_tailroom) 237521cf377aSLino Sanfilippo slave->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); 237658adf9dcSVladimir Oltean if (ds->needs_standalone_vlan_filtering) 237758adf9dcSVladimir Oltean slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 237853da0ebaSVladimir Oltean } 237953da0ebaSVladimir Oltean 238024462549SFlorian Fainelli int dsa_slave_suspend(struct net_device *slave_dev) 238124462549SFlorian Fainelli { 2382aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(slave_dev); 238324462549SFlorian Fainelli 2384a94c689eSFlorian Fainelli if (!netif_running(slave_dev)) 2385a94c689eSFlorian Fainelli return 0; 2386a94c689eSFlorian Fainelli 2387f154be24SFlorian Fainelli netif_device_detach(slave_dev); 2388f154be24SFlorian Fainelli 2389aab9c406SFlorian Fainelli rtnl_lock(); 2390aab9c406SFlorian Fainelli phylink_stop(dp->pl); 2391aab9c406SFlorian Fainelli rtnl_unlock(); 239224462549SFlorian Fainelli 239324462549SFlorian Fainelli return 0; 239424462549SFlorian Fainelli } 239524462549SFlorian Fainelli 239624462549SFlorian Fainelli int dsa_slave_resume(struct net_device *slave_dev) 239724462549SFlorian Fainelli { 2398aab9c406SFlorian Fainelli struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2399aab9c406SFlorian Fainelli 2400a94c689eSFlorian Fainelli if (!netif_running(slave_dev)) 2401a94c689eSFlorian Fainelli return 0; 2402a94c689eSFlorian Fainelli 240324462549SFlorian Fainelli netif_device_attach(slave_dev); 240424462549SFlorian Fainelli 2405aab9c406SFlorian Fainelli rtnl_lock(); 2406aab9c406SFlorian Fainelli phylink_start(dp->pl); 2407aab9c406SFlorian Fainelli rtnl_unlock(); 240824462549SFlorian Fainelli 240924462549SFlorian Fainelli return 0; 241024462549SFlorian Fainelli } 241124462549SFlorian Fainelli 2412951259aaSVivien Didelot int dsa_slave_create(struct dsa_port *port) 241391da11f8SLennert Buytenhek { 24148f6a19c0SVladimir Oltean struct net_device *master = dsa_port_to_master(port); 24154cfbf09cSVivien Didelot struct dsa_switch *ds = port->ds; 241691da11f8SLennert Buytenhek struct net_device *slave_dev; 241791da11f8SLennert Buytenhek struct dsa_slave_priv *p; 24180171a1d2SRasmus Villemoes const char *name; 24190171a1d2SRasmus Villemoes int assign_type; 242091da11f8SLennert Buytenhek int ret; 242191da11f8SLennert Buytenhek 242255199df6SFlorian Fainelli if (!ds->num_tx_queues) 242355199df6SFlorian Fainelli ds->num_tx_queues = 1; 242455199df6SFlorian Fainelli 24250171a1d2SRasmus Villemoes if (port->name) { 24260171a1d2SRasmus Villemoes name = port->name; 24276fdb0384SRasmus Villemoes assign_type = NET_NAME_PREDICTABLE; 24280171a1d2SRasmus Villemoes } else { 24290171a1d2SRasmus Villemoes name = "eth%d"; 2430b8790661SRasmus Villemoes assign_type = NET_NAME_ENUM; 24310171a1d2SRasmus Villemoes } 24320171a1d2SRasmus Villemoes 243355199df6SFlorian Fainelli slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name, 24340171a1d2SRasmus Villemoes assign_type, ether_setup, 243555199df6SFlorian Fainelli ds->num_tx_queues, 1); 243691da11f8SLennert Buytenhek if (slave_dev == NULL) 2437d87d6f44SGuenter Roeck return -ENOMEM; 243891da11f8SLennert Buytenhek 243995f510d0SVladimir Oltean slave_dev->rtnl_link_ops = &dsa_link_ops; 24407ad24ea4SWilfried Klaebe slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 2441d538eca8SVladimir Oltean #if IS_ENABLED(CONFIG_DCB) 2442d538eca8SVladimir Oltean slave_dev->dcbnl_ops = &dsa_slave_dcbnl_ops; 2443d538eca8SVladimir Oltean #endif 244483216e39SMichael Walle if (!is_zero_ether_addr(port->mac)) 2445e35b8d7dSJakub Kicinski eth_hw_addr_set(slave_dev, port->mac); 2446a2c7023fSXiaofei Shen else 24472fcc8005SBjørn Mork eth_hw_addr_inherit(slave_dev, master); 24480a5f107bSPhil Sutter slave_dev->priv_flags |= IFF_NO_QUEUE; 24495e8a1e03SVladimir Oltean if (dsa_switch_supports_uc_filtering(ds)) 24505e8a1e03SVladimir Oltean slave_dev->priv_flags |= IFF_UNICAST_FLT; 24513e8a72d1SFlorian Fainelli slave_dev->netdev_ops = &dsa_slave_netdev_ops; 2452bfcb8132SVladimir Oltean if (ds->ops->port_max_mtu) 2453bfcb8132SVladimir Oltean slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index); 2454f37db85dSFlorian Fainelli SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); 2455d442ad4aSStephen Hemminger 24564cfbf09cSVivien Didelot SET_NETDEV_DEV(slave_dev, port->ds->dev); 2457ac73d4bfSJiri Pirko SET_NETDEV_DEVLINK_PORT(slave_dev, &port->devlink_port); 24584cfbf09cSVivien Didelot slave_dev->dev.of_node = port->dn; 245991da11f8SLennert Buytenhek slave_dev->vlan_features = master->vlan_features; 246091da11f8SLennert Buytenhek 246191da11f8SLennert Buytenhek p = netdev_priv(slave_dev); 24626a900628SHeiner Kallweit slave_dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 24636a900628SHeiner Kallweit if (!slave_dev->tstats) { 24645f6b4e14SFlorian Fainelli free_netdev(slave_dev); 24655f6b4e14SFlorian Fainelli return -ENOMEM; 24665f6b4e14SFlorian Fainelli } 2467e131a563SAlexander Lobakin 2468e131a563SAlexander Lobakin ret = gro_cells_init(&p->gcells, slave_dev); 2469e131a563SAlexander Lobakin if (ret) 2470e131a563SAlexander Lobakin goto out_free; 2471e131a563SAlexander Lobakin 24724cfbf09cSVivien Didelot p->dp = port; 2473f50f2127SFlorian Fainelli INIT_LIST_HEAD(&p->mall_tc_list); 2474f8b8b1cdSVivien Didelot port->slave = slave_dev; 247553da0ebaSVladimir Oltean dsa_slave_setup_tagger(slave_dev); 247691da11f8SLennert Buytenhek 247791da11f8SLennert Buytenhek netif_carrier_off(slave_dev); 247891da11f8SLennert Buytenhek 24794fa7b718SVivien Didelot ret = dsa_slave_phy_setup(slave_dev); 24800071f56eSAndrew Lunn if (ret) { 2481c9ebf126SVladimir Oltean netdev_err(slave_dev, 2482c9ebf126SVladimir Oltean "error %d setting up PHY for tree %d, switch %d, port %d\n", 2483c9ebf126SVladimir Oltean ret, ds->dst->index, ds->index, port->index); 2484e131a563SAlexander Lobakin goto out_gcells; 2485e804441cSFlorian Fainelli } 2486e804441cSFlorian Fainelli 24872f1e8ea7SVladimir Oltean rtnl_lock(); 2488e31dbd3bSVladimir Oltean 2489904e112aSVladimir Oltean ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); 2490904e112aSVladimir Oltean if (ret && ret != -EOPNOTSUPP) 2491904e112aSVladimir Oltean dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", 2492904e112aSVladimir Oltean ret, ETH_DATA_LEN, port->index); 2493904e112aSVladimir Oltean 24942f1e8ea7SVladimir Oltean ret = register_netdevice(slave_dev); 2495e804441cSFlorian Fainelli if (ret) { 2496e804441cSFlorian Fainelli netdev_err(master, "error %d registering interface %s\n", 2497e804441cSFlorian Fainelli ret, slave_dev->name); 24982f1e8ea7SVladimir Oltean rtnl_unlock(); 2499e804441cSFlorian Fainelli goto out_phy; 25000071f56eSAndrew Lunn } 25010071f56eSAndrew Lunn 2502d538eca8SVladimir Oltean if (IS_ENABLED(CONFIG_DCB)) { 2503d538eca8SVladimir Oltean ret = dsa_slave_dcbnl_init(slave_dev); 2504d538eca8SVladimir Oltean if (ret) { 2505d538eca8SVladimir Oltean netdev_err(slave_dev, 2506d538eca8SVladimir Oltean "failed to initialize DCB: %pe\n", 2507d538eca8SVladimir Oltean ERR_PTR(ret)); 2508d538eca8SVladimir Oltean rtnl_unlock(); 2509d538eca8SVladimir Oltean goto out_unregister; 2510d538eca8SVladimir Oltean } 2511d538eca8SVladimir Oltean } 2512d538eca8SVladimir Oltean 25132f1e8ea7SVladimir Oltean ret = netdev_upper_dev_link(master, slave_dev, NULL); 25142f1e8ea7SVladimir Oltean 25152f1e8ea7SVladimir Oltean rtnl_unlock(); 25162f1e8ea7SVladimir Oltean 25172f1e8ea7SVladimir Oltean if (ret) 25182f1e8ea7SVladimir Oltean goto out_unregister; 25192f1e8ea7SVladimir Oltean 2520d87d6f44SGuenter Roeck return 0; 2521e804441cSFlorian Fainelli 25222f1e8ea7SVladimir Oltean out_unregister: 25232f1e8ea7SVladimir Oltean unregister_netdev(slave_dev); 2524e804441cSFlorian Fainelli out_phy: 2525aab9c406SFlorian Fainelli rtnl_lock(); 2526aab9c406SFlorian Fainelli phylink_disconnect_phy(p->dp->pl); 2527aab9c406SFlorian Fainelli rtnl_unlock(); 2528cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(p->dp); 2529e131a563SAlexander Lobakin out_gcells: 2530e131a563SAlexander Lobakin gro_cells_destroy(&p->gcells); 2531e804441cSFlorian Fainelli out_free: 25326a900628SHeiner Kallweit free_percpu(slave_dev->tstats); 2533e804441cSFlorian Fainelli free_netdev(slave_dev); 2534f8b8b1cdSVivien Didelot port->slave = NULL; 2535e804441cSFlorian Fainelli return ret; 253691da11f8SLennert Buytenhek } 2537b73adef6SFlorian Fainelli 2538cda5c15bSNeil Armstrong void dsa_slave_destroy(struct net_device *slave_dev) 2539cda5c15bSNeil Armstrong { 25402f1e8ea7SVladimir Oltean struct net_device *master = dsa_slave_to_master(slave_dev); 2541d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(slave_dev); 2542cda5c15bSNeil Armstrong struct dsa_slave_priv *p = netdev_priv(slave_dev); 2543cda5c15bSNeil Armstrong 2544cda5c15bSNeil Armstrong netif_carrier_off(slave_dev); 2545aab9c406SFlorian Fainelli rtnl_lock(); 25462f1e8ea7SVladimir Oltean netdev_upper_dev_unlink(master, slave_dev); 25472f1e8ea7SVladimir Oltean unregister_netdevice(slave_dev); 2548aab9c406SFlorian Fainelli phylink_disconnect_phy(dp->pl); 2549aab9c406SFlorian Fainelli rtnl_unlock(); 2550881eadabSJohan Hovold 2551cf5ca4ddSVladimir Oltean dsa_port_phylink_destroy(dp); 2552e131a563SAlexander Lobakin gro_cells_destroy(&p->gcells); 25536a900628SHeiner Kallweit free_percpu(slave_dev->tstats); 2554cda5c15bSNeil Armstrong free_netdev(slave_dev); 2555cda5c15bSNeil Armstrong } 2556cda5c15bSNeil Armstrong 255795f510d0SVladimir Oltean int dsa_slave_change_master(struct net_device *dev, struct net_device *master, 255895f510d0SVladimir Oltean struct netlink_ext_ack *extack) 255995f510d0SVladimir Oltean { 256095f510d0SVladimir Oltean struct net_device *old_master = dsa_slave_to_master(dev); 256195f510d0SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 256295f510d0SVladimir Oltean struct dsa_switch *ds = dp->ds; 256395f510d0SVladimir Oltean struct net_device *upper; 256495f510d0SVladimir Oltean struct list_head *iter; 256595f510d0SVladimir Oltean int err; 256695f510d0SVladimir Oltean 256795f510d0SVladimir Oltean if (master == old_master) 256895f510d0SVladimir Oltean return 0; 256995f510d0SVladimir Oltean 257095f510d0SVladimir Oltean if (!ds->ops->port_change_master) { 257195f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 257295f510d0SVladimir Oltean "Driver does not support changing DSA master"); 257395f510d0SVladimir Oltean return -EOPNOTSUPP; 257495f510d0SVladimir Oltean } 257595f510d0SVladimir Oltean 257695f510d0SVladimir Oltean if (!netdev_uses_dsa(master)) { 257795f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 257895f510d0SVladimir Oltean "Interface not eligible as DSA master"); 257995f510d0SVladimir Oltean return -EOPNOTSUPP; 258095f510d0SVladimir Oltean } 258195f510d0SVladimir Oltean 258295f510d0SVladimir Oltean netdev_for_each_upper_dev_rcu(master, upper, iter) { 258395f510d0SVladimir Oltean if (dsa_slave_dev_check(upper)) 258495f510d0SVladimir Oltean continue; 258595f510d0SVladimir Oltean if (netif_is_bridge_master(upper)) 258695f510d0SVladimir Oltean continue; 258795f510d0SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, "Cannot join master with unknown uppers"); 258895f510d0SVladimir Oltean return -EOPNOTSUPP; 258995f510d0SVladimir Oltean } 259095f510d0SVladimir Oltean 259195f510d0SVladimir Oltean /* Since we allow live-changing the DSA master, plus we auto-open the 259295f510d0SVladimir Oltean * DSA master when the user port opens => we need to ensure that the 259395f510d0SVladimir Oltean * new DSA master is open too. 259495f510d0SVladimir Oltean */ 259595f510d0SVladimir Oltean if (dev->flags & IFF_UP) { 259695f510d0SVladimir Oltean err = dev_open(master, extack); 259795f510d0SVladimir Oltean if (err) 259895f510d0SVladimir Oltean return err; 259995f510d0SVladimir Oltean } 260095f510d0SVladimir Oltean 260195f510d0SVladimir Oltean netdev_upper_dev_unlink(old_master, dev); 260295f510d0SVladimir Oltean 260395f510d0SVladimir Oltean err = netdev_upper_dev_link(master, dev, extack); 260495f510d0SVladimir Oltean if (err) 260595f510d0SVladimir Oltean goto out_revert_old_master_unlink; 260695f510d0SVladimir Oltean 260795f510d0SVladimir Oltean err = dsa_port_change_master(dp, master, extack); 260895f510d0SVladimir Oltean if (err) 260995f510d0SVladimir Oltean goto out_revert_master_link; 261095f510d0SVladimir Oltean 261195f510d0SVladimir Oltean /* Update the MTU of the new CPU port through cross-chip notifiers */ 261295f510d0SVladimir Oltean err = dsa_slave_change_mtu(dev, dev->mtu); 261395f510d0SVladimir Oltean if (err && err != -EOPNOTSUPP) { 261495f510d0SVladimir Oltean netdev_warn(dev, 261595f510d0SVladimir Oltean "nonfatal error updating MTU with new master: %pe\n", 261695f510d0SVladimir Oltean ERR_PTR(err)); 261795f510d0SVladimir Oltean } 261895f510d0SVladimir Oltean 261995f510d0SVladimir Oltean /* If the port doesn't have its own MAC address and relies on the DSA 262095f510d0SVladimir Oltean * master's one, inherit it again from the new DSA master. 262195f510d0SVladimir Oltean */ 262295f510d0SVladimir Oltean if (is_zero_ether_addr(dp->mac)) 262395f510d0SVladimir Oltean eth_hw_addr_inherit(dev, master); 262495f510d0SVladimir Oltean 262595f510d0SVladimir Oltean return 0; 262695f510d0SVladimir Oltean 262795f510d0SVladimir Oltean out_revert_master_link: 262895f510d0SVladimir Oltean netdev_upper_dev_unlink(master, dev); 262995f510d0SVladimir Oltean out_revert_old_master_unlink: 263095f510d0SVladimir Oltean netdev_upper_dev_link(old_master, dev, NULL); 263195f510d0SVladimir Oltean return err; 263295f510d0SVladimir Oltean } 263395f510d0SVladimir Oltean 26344d776482SFlorian Fainelli bool dsa_slave_dev_check(const struct net_device *dev) 2635b73adef6SFlorian Fainelli { 2636b73adef6SFlorian Fainelli return dev->netdev_ops == &dsa_slave_netdev_ops; 2637b73adef6SFlorian Fainelli } 2638a5e3c9baSVladimir Oltean EXPORT_SYMBOL_GPL(dsa_slave_dev_check); 2639b73adef6SFlorian Fainelli 26408e92ab3aSVivien Didelot static int dsa_slave_changeupper(struct net_device *dev, 26418e92ab3aSVivien Didelot struct netdev_notifier_changeupper_info *info) 2642b73adef6SFlorian Fainelli { 2643d945097bSVivien Didelot struct dsa_port *dp = dsa_slave_to_port(dev); 26442afc526aSVladimir Oltean struct netlink_ext_ack *extack; 26458e92ab3aSVivien Didelot int err = NOTIFY_DONE; 2646b73adef6SFlorian Fainelli 26474c3f80d2SVladimir Oltean if (!dsa_slave_dev_check(dev)) 26484c3f80d2SVladimir Oltean return err; 26494c3f80d2SVladimir Oltean 26502afc526aSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 26512afc526aSVladimir Oltean 26528e92ab3aSVivien Didelot if (netif_is_bridge_master(info->upper_dev)) { 26538e92ab3aSVivien Didelot if (info->linking) { 26542afc526aSVladimir Oltean err = dsa_port_bridge_join(dp, info->upper_dev, extack); 2655bff33f7eSVladimir Oltean if (!err) 2656bff33f7eSVladimir Oltean dsa_bridge_mtu_normalization(dp); 265767b5fb5dSVladimir Oltean if (err == -EOPNOTSUPP) { 2658855a28f9SVladimir Oltean if (extack && !extack->_msg) 265967b5fb5dSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 266067b5fb5dSVladimir Oltean "Offloading not supported"); 266167b5fb5dSVladimir Oltean err = 0; 266267b5fb5dSVladimir Oltean } 26638e92ab3aSVivien Didelot err = notifier_from_errno(err); 26648e92ab3aSVivien Didelot } else { 266517d7802bSVivien Didelot dsa_port_bridge_leave(dp, info->upper_dev); 26668e92ab3aSVivien Didelot err = NOTIFY_OK; 26678e92ab3aSVivien Didelot } 2668058102a6STobias Waldekranz } else if (netif_is_lag_master(info->upper_dev)) { 2669058102a6STobias Waldekranz if (info->linking) { 2670058102a6STobias Waldekranz err = dsa_port_lag_join(dp, info->upper_dev, 26712afc526aSVladimir Oltean info->upper_info, extack); 2672058102a6STobias Waldekranz if (err == -EOPNOTSUPP) { 2673058102a6STobias Waldekranz NL_SET_ERR_MSG_MOD(info->info.extack, 2674058102a6STobias Waldekranz "Offloading not supported"); 2675058102a6STobias Waldekranz err = 0; 2676058102a6STobias Waldekranz } 2677058102a6STobias Waldekranz err = notifier_from_errno(err); 2678058102a6STobias Waldekranz } else { 2679058102a6STobias Waldekranz dsa_port_lag_leave(dp, info->upper_dev); 2680058102a6STobias Waldekranz err = NOTIFY_OK; 2681058102a6STobias Waldekranz } 268218596f50SGeorge McCollister } else if (is_hsr_master(info->upper_dev)) { 268318596f50SGeorge McCollister if (info->linking) { 268418596f50SGeorge McCollister err = dsa_port_hsr_join(dp, info->upper_dev); 268518596f50SGeorge McCollister if (err == -EOPNOTSUPP) { 268618596f50SGeorge McCollister NL_SET_ERR_MSG_MOD(info->info.extack, 268718596f50SGeorge McCollister "Offloading not supported"); 268818596f50SGeorge McCollister err = 0; 268918596f50SGeorge McCollister } 269018596f50SGeorge McCollister err = notifier_from_errno(err); 269118596f50SGeorge McCollister } else { 269218596f50SGeorge McCollister dsa_port_hsr_leave(dp, info->upper_dev); 269318596f50SGeorge McCollister err = NOTIFY_OK; 269418596f50SGeorge McCollister } 2695058102a6STobias Waldekranz } 2696058102a6STobias Waldekranz 2697058102a6STobias Waldekranz return err; 2698058102a6STobias Waldekranz } 2699058102a6STobias Waldekranz 270074918945SVladimir Oltean static int dsa_slave_prechangeupper(struct net_device *dev, 270174918945SVladimir Oltean struct netdev_notifier_changeupper_info *info) 270274918945SVladimir Oltean { 270374918945SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 270474918945SVladimir Oltean 27054c3f80d2SVladimir Oltean if (!dsa_slave_dev_check(dev)) 27064c3f80d2SVladimir Oltean return NOTIFY_DONE; 27074c3f80d2SVladimir Oltean 270874918945SVladimir Oltean if (netif_is_bridge_master(info->upper_dev) && !info->linking) 27094e51bf44SVladimir Oltean dsa_port_pre_bridge_leave(dp, info->upper_dev); 271074918945SVladimir Oltean else if (netif_is_lag_master(info->upper_dev) && !info->linking) 27114e51bf44SVladimir Oltean dsa_port_pre_lag_leave(dp, info->upper_dev); 271274918945SVladimir Oltean /* dsa_port_pre_hsr_leave is not yet necessary since hsr cannot be 271374918945SVladimir Oltean * meaningfully enslaved to a bridge yet 271474918945SVladimir Oltean */ 271574918945SVladimir Oltean 27164e51bf44SVladimir Oltean return NOTIFY_DONE; 271774918945SVladimir Oltean } 271874918945SVladimir Oltean 2719058102a6STobias Waldekranz static int 2720058102a6STobias Waldekranz dsa_slave_lag_changeupper(struct net_device *dev, 2721058102a6STobias Waldekranz struct netdev_notifier_changeupper_info *info) 2722058102a6STobias Waldekranz { 2723058102a6STobias Waldekranz struct net_device *lower; 2724058102a6STobias Waldekranz struct list_head *iter; 2725058102a6STobias Waldekranz int err = NOTIFY_DONE; 2726058102a6STobias Waldekranz struct dsa_port *dp; 2727058102a6STobias Waldekranz 27284c3f80d2SVladimir Oltean if (!netif_is_lag_master(dev)) 27294c3f80d2SVladimir Oltean return err; 27304c3f80d2SVladimir Oltean 2731058102a6STobias Waldekranz netdev_for_each_lower_dev(dev, lower, iter) { 2732058102a6STobias Waldekranz if (!dsa_slave_dev_check(lower)) 2733058102a6STobias Waldekranz continue; 2734058102a6STobias Waldekranz 2735058102a6STobias Waldekranz dp = dsa_slave_to_port(lower); 2736dedd6a00SVladimir Oltean if (!dp->lag) 2737058102a6STobias Waldekranz /* Software LAG */ 2738058102a6STobias Waldekranz continue; 2739058102a6STobias Waldekranz 2740058102a6STobias Waldekranz err = dsa_slave_changeupper(lower, info); 2741058102a6STobias Waldekranz if (notifier_to_errno(err)) 2742058102a6STobias Waldekranz break; 27436debb68aSVivien Didelot } 2744b73adef6SFlorian Fainelli 27458e92ab3aSVivien Didelot return err; 2746b73adef6SFlorian Fainelli } 2747b73adef6SFlorian Fainelli 274874918945SVladimir Oltean /* Same as dsa_slave_lag_changeupper() except that it calls 274974918945SVladimir Oltean * dsa_slave_prechangeupper() 275074918945SVladimir Oltean */ 275174918945SVladimir Oltean static int 275274918945SVladimir Oltean dsa_slave_lag_prechangeupper(struct net_device *dev, 275374918945SVladimir Oltean struct netdev_notifier_changeupper_info *info) 275474918945SVladimir Oltean { 275574918945SVladimir Oltean struct net_device *lower; 275674918945SVladimir Oltean struct list_head *iter; 275774918945SVladimir Oltean int err = NOTIFY_DONE; 275874918945SVladimir Oltean struct dsa_port *dp; 275974918945SVladimir Oltean 27604c3f80d2SVladimir Oltean if (!netif_is_lag_master(dev)) 27614c3f80d2SVladimir Oltean return err; 27624c3f80d2SVladimir Oltean 276374918945SVladimir Oltean netdev_for_each_lower_dev(dev, lower, iter) { 276474918945SVladimir Oltean if (!dsa_slave_dev_check(lower)) 276574918945SVladimir Oltean continue; 276674918945SVladimir Oltean 276774918945SVladimir Oltean dp = dsa_slave_to_port(lower); 2768dedd6a00SVladimir Oltean if (!dp->lag) 276974918945SVladimir Oltean /* Software LAG */ 277074918945SVladimir Oltean continue; 277174918945SVladimir Oltean 277274918945SVladimir Oltean err = dsa_slave_prechangeupper(lower, info); 277374918945SVladimir Oltean if (notifier_to_errno(err)) 277474918945SVladimir Oltean break; 277574918945SVladimir Oltean } 277674918945SVladimir Oltean 277774918945SVladimir Oltean return err; 277874918945SVladimir Oltean } 277974918945SVladimir Oltean 2780eb46e8daSVladimir Oltean static int 2781eb46e8daSVladimir Oltean dsa_prevent_bridging_8021q_upper(struct net_device *dev, 2782eb46e8daSVladimir Oltean struct netdev_notifier_changeupper_info *info) 2783cc1d5bdaSFlorian Fainelli { 2784cc1d5bdaSFlorian Fainelli struct netlink_ext_ack *ext_ack; 278536cbf39bSVladimir Oltean struct net_device *slave, *br; 2786cc1d5bdaSFlorian Fainelli struct dsa_port *dp; 2787cc1d5bdaSFlorian Fainelli 2788cc1d5bdaSFlorian Fainelli ext_ack = netdev_notifier_info_to_extack(&info->info); 2789cc1d5bdaSFlorian Fainelli 2790cc1d5bdaSFlorian Fainelli if (!is_vlan_dev(dev)) 2791cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2792cc1d5bdaSFlorian Fainelli 2793cc1d5bdaSFlorian Fainelli slave = vlan_dev_real_dev(dev); 2794cc1d5bdaSFlorian Fainelli if (!dsa_slave_dev_check(slave)) 2795cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2796cc1d5bdaSFlorian Fainelli 2797cc1d5bdaSFlorian Fainelli dp = dsa_slave_to_port(slave); 279836cbf39bSVladimir Oltean br = dsa_port_bridge_dev_get(dp); 279936cbf39bSVladimir Oltean if (!br) 2800cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2801cc1d5bdaSFlorian Fainelli 2802cc1d5bdaSFlorian Fainelli /* Deny enslaving a VLAN device into a VLAN-aware bridge */ 280336cbf39bSVladimir Oltean if (br_vlan_enabled(br) && 2804cc1d5bdaSFlorian Fainelli netif_is_bridge_master(info->upper_dev) && info->linking) { 2805cc1d5bdaSFlorian Fainelli NL_SET_ERR_MSG_MOD(ext_ack, 2806cc1d5bdaSFlorian Fainelli "Cannot enslave VLAN device into VLAN aware bridge"); 2807cc1d5bdaSFlorian Fainelli return notifier_from_errno(-EINVAL); 2808cc1d5bdaSFlorian Fainelli } 2809cc1d5bdaSFlorian Fainelli 2810cc1d5bdaSFlorian Fainelli return NOTIFY_DONE; 2811cc1d5bdaSFlorian Fainelli } 2812cc1d5bdaSFlorian Fainelli 28132b138406SVladimir Oltean static int 28142b138406SVladimir Oltean dsa_slave_check_8021q_upper(struct net_device *dev, 28152b138406SVladimir Oltean struct netdev_notifier_changeupper_info *info) 28162b138406SVladimir Oltean { 28172b138406SVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 281836cbf39bSVladimir Oltean struct net_device *br = dsa_port_bridge_dev_get(dp); 28192b138406SVladimir Oltean struct bridge_vlan_info br_info; 28202b138406SVladimir Oltean struct netlink_ext_ack *extack; 28212b138406SVladimir Oltean int err = NOTIFY_DONE; 28222b138406SVladimir Oltean u16 vid; 28232b138406SVladimir Oltean 2824adb256ebSVladimir Oltean if (!br || !br_vlan_enabled(br)) 28252b138406SVladimir Oltean return NOTIFY_DONE; 28262b138406SVladimir Oltean 28272b138406SVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 28282b138406SVladimir Oltean vid = vlan_dev_vlan_id(info->upper_dev); 28292b138406SVladimir Oltean 28302b138406SVladimir Oltean /* br_vlan_get_info() returns -EINVAL or -ENOENT if the 28312b138406SVladimir Oltean * device, respectively the VID is not found, returning 28322b138406SVladimir Oltean * 0 means success, which is a failure for us here. 28332b138406SVladimir Oltean */ 28342b138406SVladimir Oltean err = br_vlan_get_info(br, vid, &br_info); 28352b138406SVladimir Oltean if (err == 0) { 28362b138406SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 28372b138406SVladimir Oltean "This VLAN is already configured by the bridge"); 28382b138406SVladimir Oltean return notifier_from_errno(-EBUSY); 28392b138406SVladimir Oltean } 28402b138406SVladimir Oltean 28412b138406SVladimir Oltean return NOTIFY_DONE; 28422b138406SVladimir Oltean } 28432b138406SVladimir Oltean 28444ede74e7SVladimir Oltean static int 28454ede74e7SVladimir Oltean dsa_slave_prechangeupper_sanity_check(struct net_device *dev, 28464ede74e7SVladimir Oltean struct netdev_notifier_changeupper_info *info) 2847b73adef6SFlorian Fainelli { 2848e358bef7SVladimir Oltean struct dsa_switch *ds; 2849e358bef7SVladimir Oltean struct dsa_port *dp; 2850e358bef7SVladimir Oltean int err; 28512b138406SVladimir Oltean 285253bade8aSFlorian Fainelli if (!dsa_slave_dev_check(dev)) 28534ede74e7SVladimir Oltean return dsa_prevent_bridging_8021q_upper(dev, info); 28542b138406SVladimir Oltean 2855e358bef7SVladimir Oltean dp = dsa_slave_to_port(dev); 2856e358bef7SVladimir Oltean ds = dp->ds; 2857e358bef7SVladimir Oltean 2858e358bef7SVladimir Oltean if (ds->ops->port_prechangeupper) { 2859e358bef7SVladimir Oltean err = ds->ops->port_prechangeupper(ds, dp->index, info); 2860e358bef7SVladimir Oltean if (err) 2861e358bef7SVladimir Oltean return notifier_from_errno(err); 2862e358bef7SVladimir Oltean } 2863e358bef7SVladimir Oltean 28642b138406SVladimir Oltean if (is_vlan_dev(info->upper_dev)) 28654ede74e7SVladimir Oltean return dsa_slave_check_8021q_upper(dev, info); 28664ede74e7SVladimir Oltean 28674ede74e7SVladimir Oltean return NOTIFY_DONE; 28684ede74e7SVladimir Oltean } 28694ede74e7SVladimir Oltean 2870acc43b7bSVladimir Oltean /* To be eligible as a DSA master, a LAG must have all lower interfaces be 2871acc43b7bSVladimir Oltean * eligible DSA masters. Additionally, all LAG slaves must be DSA masters of 2872acc43b7bSVladimir Oltean * switches in the same switch tree. 2873acc43b7bSVladimir Oltean */ 2874acc43b7bSVladimir Oltean static int dsa_lag_master_validate(struct net_device *lag_dev, 2875acc43b7bSVladimir Oltean struct netlink_ext_ack *extack) 2876acc43b7bSVladimir Oltean { 2877acc43b7bSVladimir Oltean struct net_device *lower1, *lower2; 2878acc43b7bSVladimir Oltean struct list_head *iter1, *iter2; 2879acc43b7bSVladimir Oltean 2880acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower1, iter1) { 2881acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower2, iter2) { 2882acc43b7bSVladimir Oltean if (!netdev_uses_dsa(lower1) || 2883acc43b7bSVladimir Oltean !netdev_uses_dsa(lower2)) { 2884acc43b7bSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 2885acc43b7bSVladimir Oltean "All LAG ports must be eligible as DSA masters"); 2886acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2887acc43b7bSVladimir Oltean } 2888acc43b7bSVladimir Oltean 2889acc43b7bSVladimir Oltean if (lower1 == lower2) 2890acc43b7bSVladimir Oltean continue; 2891acc43b7bSVladimir Oltean 2892acc43b7bSVladimir Oltean if (!dsa_port_tree_same(lower1->dsa_ptr, 2893acc43b7bSVladimir Oltean lower2->dsa_ptr)) { 2894acc43b7bSVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 2895acc43b7bSVladimir Oltean "LAG contains DSA masters of disjoint switch trees"); 2896acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2897acc43b7bSVladimir Oltean } 2898acc43b7bSVladimir Oltean } 2899acc43b7bSVladimir Oltean } 2900acc43b7bSVladimir Oltean 2901acc43b7bSVladimir Oltean return NOTIFY_DONE; 2902acc43b7bSVladimir Oltean } 2903acc43b7bSVladimir Oltean 29044f03dcc6SVladimir Oltean static int 29054f03dcc6SVladimir Oltean dsa_master_prechangeupper_sanity_check(struct net_device *master, 29064f03dcc6SVladimir Oltean struct netdev_notifier_changeupper_info *info) 29074f03dcc6SVladimir Oltean { 2908acc43b7bSVladimir Oltean struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); 29094f03dcc6SVladimir Oltean 29104f03dcc6SVladimir Oltean if (!netdev_uses_dsa(master)) 29114f03dcc6SVladimir Oltean return NOTIFY_DONE; 29124f03dcc6SVladimir Oltean 29134f03dcc6SVladimir Oltean if (!info->linking) 29144f03dcc6SVladimir Oltean return NOTIFY_DONE; 29154f03dcc6SVladimir Oltean 29164f03dcc6SVladimir Oltean /* Allow DSA switch uppers */ 29174f03dcc6SVladimir Oltean if (dsa_slave_dev_check(info->upper_dev)) 29184f03dcc6SVladimir Oltean return NOTIFY_DONE; 29194f03dcc6SVladimir Oltean 29204f03dcc6SVladimir Oltean /* Allow bridge uppers of DSA masters, subject to further 29214f03dcc6SVladimir Oltean * restrictions in dsa_bridge_prechangelower_sanity_check() 29224f03dcc6SVladimir Oltean */ 29234f03dcc6SVladimir Oltean if (netif_is_bridge_master(info->upper_dev)) 29244f03dcc6SVladimir Oltean return NOTIFY_DONE; 29254f03dcc6SVladimir Oltean 2926acc43b7bSVladimir Oltean /* Allow LAG uppers, subject to further restrictions in 2927acc43b7bSVladimir Oltean * dsa_lag_master_prechangelower_sanity_check() 2928acc43b7bSVladimir Oltean */ 2929acc43b7bSVladimir Oltean if (netif_is_lag_master(info->upper_dev)) 2930acc43b7bSVladimir Oltean return dsa_lag_master_validate(info->upper_dev, extack); 29314f03dcc6SVladimir Oltean 29324f03dcc6SVladimir Oltean NL_SET_ERR_MSG_MOD(extack, 29334f03dcc6SVladimir Oltean "DSA master cannot join unknown upper interfaces"); 29344f03dcc6SVladimir Oltean return notifier_from_errno(-EBUSY); 29354f03dcc6SVladimir Oltean } 29364f03dcc6SVladimir Oltean 2937acc43b7bSVladimir Oltean static int 2938acc43b7bSVladimir Oltean dsa_lag_master_prechangelower_sanity_check(struct net_device *dev, 2939acc43b7bSVladimir Oltean struct netdev_notifier_changeupper_info *info) 2940acc43b7bSVladimir Oltean { 2941acc43b7bSVladimir Oltean struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); 2942acc43b7bSVladimir Oltean struct net_device *lag_dev = info->upper_dev; 2943acc43b7bSVladimir Oltean struct net_device *lower; 2944acc43b7bSVladimir Oltean struct list_head *iter; 2945acc43b7bSVladimir Oltean 2946acc43b7bSVladimir Oltean if (!netdev_uses_dsa(lag_dev) || !netif_is_lag_master(lag_dev)) 2947acc43b7bSVladimir Oltean return NOTIFY_DONE; 2948acc43b7bSVladimir Oltean 2949acc43b7bSVladimir Oltean if (!info->linking) 2950acc43b7bSVladimir Oltean return NOTIFY_DONE; 2951acc43b7bSVladimir Oltean 2952acc43b7bSVladimir Oltean if (!netdev_uses_dsa(dev)) { 2953acc43b7bSVladimir Oltean NL_SET_ERR_MSG(extack, 2954acc43b7bSVladimir Oltean "Only DSA masters can join a LAG DSA master"); 2955acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2956acc43b7bSVladimir Oltean } 2957acc43b7bSVladimir Oltean 2958acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower, iter) { 2959acc43b7bSVladimir Oltean if (!dsa_port_tree_same(dev->dsa_ptr, lower->dsa_ptr)) { 2960acc43b7bSVladimir Oltean NL_SET_ERR_MSG(extack, 2961acc43b7bSVladimir Oltean "Interface is DSA master for a different switch tree than this LAG"); 2962acc43b7bSVladimir Oltean return notifier_from_errno(-EINVAL); 2963acc43b7bSVladimir Oltean } 2964acc43b7bSVladimir Oltean 2965acc43b7bSVladimir Oltean break; 2966acc43b7bSVladimir Oltean } 2967acc43b7bSVladimir Oltean 2968acc43b7bSVladimir Oltean return NOTIFY_DONE; 2969acc43b7bSVladimir Oltean } 2970acc43b7bSVladimir Oltean 2971920a33cdSVladimir Oltean /* Don't allow bridging of DSA masters, since the bridge layer rx_handler 2972920a33cdSVladimir Oltean * prevents the DSA fake ethertype handler to be invoked, so we don't get the 2973920a33cdSVladimir Oltean * chance to strip off and parse the DSA switch tag protocol header (the bridge 2974920a33cdSVladimir Oltean * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these 2975920a33cdSVladimir Oltean * frames). 2976920a33cdSVladimir Oltean * The only case where that would not be an issue is when bridging can already 2977920a33cdSVladimir Oltean * be offloaded, such as when the DSA master is itself a DSA or plain switchdev 2978920a33cdSVladimir Oltean * port, and is bridged only with other ports from the same hardware device. 2979920a33cdSVladimir Oltean */ 2980920a33cdSVladimir Oltean static int 2981920a33cdSVladimir Oltean dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower, 2982920a33cdSVladimir Oltean struct netdev_notifier_changeupper_info *info) 2983920a33cdSVladimir Oltean { 2984920a33cdSVladimir Oltean struct net_device *br = info->upper_dev; 2985920a33cdSVladimir Oltean struct netlink_ext_ack *extack; 2986920a33cdSVladimir Oltean struct net_device *lower; 2987920a33cdSVladimir Oltean struct list_head *iter; 2988920a33cdSVladimir Oltean 2989920a33cdSVladimir Oltean if (!netif_is_bridge_master(br)) 2990920a33cdSVladimir Oltean return NOTIFY_DONE; 2991920a33cdSVladimir Oltean 2992920a33cdSVladimir Oltean if (!info->linking) 2993920a33cdSVladimir Oltean return NOTIFY_DONE; 2994920a33cdSVladimir Oltean 2995920a33cdSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 2996920a33cdSVladimir Oltean 2997920a33cdSVladimir Oltean netdev_for_each_lower_dev(br, lower, iter) { 2998920a33cdSVladimir Oltean if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower)) 2999920a33cdSVladimir Oltean continue; 3000920a33cdSVladimir Oltean 3001920a33cdSVladimir Oltean if (!netdev_port_same_parent_id(lower, new_lower)) { 3002920a33cdSVladimir Oltean NL_SET_ERR_MSG(extack, 3003920a33cdSVladimir Oltean "Cannot do software bridging with a DSA master"); 3004920a33cdSVladimir Oltean return notifier_from_errno(-EINVAL); 3005920a33cdSVladimir Oltean } 3006920a33cdSVladimir Oltean } 3007920a33cdSVladimir Oltean 3008920a33cdSVladimir Oltean return NOTIFY_DONE; 3009920a33cdSVladimir Oltean } 3010920a33cdSVladimir Oltean 3011acc43b7bSVladimir Oltean static void dsa_tree_migrate_ports_from_lag_master(struct dsa_switch_tree *dst, 3012acc43b7bSVladimir Oltean struct net_device *lag_dev) 3013acc43b7bSVladimir Oltean { 3014acc43b7bSVladimir Oltean struct net_device *new_master = dsa_tree_find_first_master(dst); 3015acc43b7bSVladimir Oltean struct dsa_port *dp; 3016acc43b7bSVladimir Oltean int err; 3017acc43b7bSVladimir Oltean 3018acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) { 3019acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != lag_dev) 3020acc43b7bSVladimir Oltean continue; 3021acc43b7bSVladimir Oltean 3022acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, new_master, NULL); 3023acc43b7bSVladimir Oltean if (err) { 3024acc43b7bSVladimir Oltean netdev_err(dp->slave, 3025acc43b7bSVladimir Oltean "failed to restore master to %s: %pe\n", 3026acc43b7bSVladimir Oltean new_master->name, ERR_PTR(err)); 3027acc43b7bSVladimir Oltean } 3028acc43b7bSVladimir Oltean } 3029acc43b7bSVladimir Oltean } 3030acc43b7bSVladimir Oltean 3031acc43b7bSVladimir Oltean static int dsa_master_lag_join(struct net_device *master, 3032acc43b7bSVladimir Oltean struct net_device *lag_dev, 3033acc43b7bSVladimir Oltean struct netdev_lag_upper_info *uinfo, 3034acc43b7bSVladimir Oltean struct netlink_ext_ack *extack) 3035acc43b7bSVladimir Oltean { 3036acc43b7bSVladimir Oltean struct dsa_port *cpu_dp = master->dsa_ptr; 3037acc43b7bSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->dst; 3038acc43b7bSVladimir Oltean struct dsa_port *dp; 3039acc43b7bSVladimir Oltean int err; 3040acc43b7bSVladimir Oltean 3041acc43b7bSVladimir Oltean err = dsa_master_lag_setup(lag_dev, cpu_dp, uinfo, extack); 3042acc43b7bSVladimir Oltean if (err) 3043acc43b7bSVladimir Oltean return err; 3044acc43b7bSVladimir Oltean 3045acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) { 3046acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != master) 3047acc43b7bSVladimir Oltean continue; 3048acc43b7bSVladimir Oltean 3049acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, lag_dev, extack); 3050acc43b7bSVladimir Oltean if (err) 3051acc43b7bSVladimir Oltean goto restore; 3052acc43b7bSVladimir Oltean } 3053acc43b7bSVladimir Oltean 3054acc43b7bSVladimir Oltean return 0; 3055acc43b7bSVladimir Oltean 3056acc43b7bSVladimir Oltean restore: 3057acc43b7bSVladimir Oltean dsa_tree_for_each_user_port_continue_reverse(dp, dst) { 3058acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) != lag_dev) 3059acc43b7bSVladimir Oltean continue; 3060acc43b7bSVladimir Oltean 3061acc43b7bSVladimir Oltean err = dsa_slave_change_master(dp->slave, master, NULL); 3062acc43b7bSVladimir Oltean if (err) { 3063acc43b7bSVladimir Oltean netdev_err(dp->slave, 3064acc43b7bSVladimir Oltean "failed to restore master to %s: %pe\n", 3065acc43b7bSVladimir Oltean master->name, ERR_PTR(err)); 3066acc43b7bSVladimir Oltean } 3067acc43b7bSVladimir Oltean } 3068acc43b7bSVladimir Oltean 3069acc43b7bSVladimir Oltean dsa_master_lag_teardown(lag_dev, master->dsa_ptr); 3070acc43b7bSVladimir Oltean 3071acc43b7bSVladimir Oltean return err; 3072acc43b7bSVladimir Oltean } 3073acc43b7bSVladimir Oltean 3074acc43b7bSVladimir Oltean static void dsa_master_lag_leave(struct net_device *master, 3075acc43b7bSVladimir Oltean struct net_device *lag_dev) 3076acc43b7bSVladimir Oltean { 3077acc43b7bSVladimir Oltean struct dsa_port *dp, *cpu_dp = lag_dev->dsa_ptr; 3078acc43b7bSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->dst; 3079acc43b7bSVladimir Oltean struct dsa_port *new_cpu_dp = NULL; 3080acc43b7bSVladimir Oltean struct net_device *lower; 3081acc43b7bSVladimir Oltean struct list_head *iter; 3082acc43b7bSVladimir Oltean 3083acc43b7bSVladimir Oltean netdev_for_each_lower_dev(lag_dev, lower, iter) { 3084acc43b7bSVladimir Oltean if (netdev_uses_dsa(lower)) { 3085acc43b7bSVladimir Oltean new_cpu_dp = lower->dsa_ptr; 3086acc43b7bSVladimir Oltean break; 3087acc43b7bSVladimir Oltean } 3088acc43b7bSVladimir Oltean } 3089acc43b7bSVladimir Oltean 3090acc43b7bSVladimir Oltean if (new_cpu_dp) { 3091acc43b7bSVladimir Oltean /* Update the CPU port of the user ports still under the LAG 3092acc43b7bSVladimir Oltean * so that dsa_port_to_master() continues to work properly 3093acc43b7bSVladimir Oltean */ 3094acc43b7bSVladimir Oltean dsa_tree_for_each_user_port(dp, dst) 3095acc43b7bSVladimir Oltean if (dsa_port_to_master(dp) == lag_dev) 3096acc43b7bSVladimir Oltean dp->cpu_dp = new_cpu_dp; 3097acc43b7bSVladimir Oltean 3098acc43b7bSVladimir Oltean /* Update the index of the virtual CPU port to match the lowest 3099acc43b7bSVladimir Oltean * physical CPU port 3100acc43b7bSVladimir Oltean */ 3101acc43b7bSVladimir Oltean lag_dev->dsa_ptr = new_cpu_dp; 3102acc43b7bSVladimir Oltean wmb(); 3103acc43b7bSVladimir Oltean } else { 3104acc43b7bSVladimir Oltean /* If the LAG DSA master has no ports left, migrate back all 3105acc43b7bSVladimir Oltean * user ports to the first physical CPU port 3106acc43b7bSVladimir Oltean */ 3107acc43b7bSVladimir Oltean dsa_tree_migrate_ports_from_lag_master(dst, lag_dev); 3108acc43b7bSVladimir Oltean } 3109acc43b7bSVladimir Oltean 3110acc43b7bSVladimir Oltean /* This DSA master has left its LAG in any case, so let 3111acc43b7bSVladimir Oltean * the CPU port leave the hardware LAG as well 3112acc43b7bSVladimir Oltean */ 3113acc43b7bSVladimir Oltean dsa_master_lag_teardown(lag_dev, master->dsa_ptr); 3114acc43b7bSVladimir Oltean } 3115acc43b7bSVladimir Oltean 3116acc43b7bSVladimir Oltean static int dsa_master_changeupper(struct net_device *dev, 3117acc43b7bSVladimir Oltean struct netdev_notifier_changeupper_info *info) 3118acc43b7bSVladimir Oltean { 3119acc43b7bSVladimir Oltean struct netlink_ext_ack *extack; 3120acc43b7bSVladimir Oltean int err = NOTIFY_DONE; 3121acc43b7bSVladimir Oltean 3122acc43b7bSVladimir Oltean if (!netdev_uses_dsa(dev)) 3123acc43b7bSVladimir Oltean return err; 3124acc43b7bSVladimir Oltean 3125acc43b7bSVladimir Oltean extack = netdev_notifier_info_to_extack(&info->info); 3126acc43b7bSVladimir Oltean 3127acc43b7bSVladimir Oltean if (netif_is_lag_master(info->upper_dev)) { 3128acc43b7bSVladimir Oltean if (info->linking) { 3129acc43b7bSVladimir Oltean err = dsa_master_lag_join(dev, info->upper_dev, 3130acc43b7bSVladimir Oltean info->upper_info, extack); 3131acc43b7bSVladimir Oltean err = notifier_from_errno(err); 3132acc43b7bSVladimir Oltean } else { 3133acc43b7bSVladimir Oltean dsa_master_lag_leave(dev, info->upper_dev); 3134acc43b7bSVladimir Oltean err = NOTIFY_OK; 3135acc43b7bSVladimir Oltean } 3136acc43b7bSVladimir Oltean } 3137acc43b7bSVladimir Oltean 3138acc43b7bSVladimir Oltean return err; 3139acc43b7bSVladimir Oltean } 3140acc43b7bSVladimir Oltean 31414ede74e7SVladimir Oltean static int dsa_slave_netdevice_event(struct notifier_block *nb, 31424ede74e7SVladimir Oltean unsigned long event, void *ptr) 31434ede74e7SVladimir Oltean { 31444ede74e7SVladimir Oltean struct net_device *dev = netdev_notifier_info_to_dev(ptr); 31454ede74e7SVladimir Oltean 31464ede74e7SVladimir Oltean switch (event) { 31474ede74e7SVladimir Oltean case NETDEV_PRECHANGEUPPER: { 31484ede74e7SVladimir Oltean struct netdev_notifier_changeupper_info *info = ptr; 31494ede74e7SVladimir Oltean int err; 31504ede74e7SVladimir Oltean 31514ede74e7SVladimir Oltean err = dsa_slave_prechangeupper_sanity_check(dev, info); 31520498277eSVladimir Oltean if (notifier_to_errno(err)) 31534ede74e7SVladimir Oltean return err; 31544ede74e7SVladimir Oltean 31554f03dcc6SVladimir Oltean err = dsa_master_prechangeupper_sanity_check(dev, info); 31564f03dcc6SVladimir Oltean if (notifier_to_errno(err)) 31574f03dcc6SVladimir Oltean return err; 31584f03dcc6SVladimir Oltean 3159acc43b7bSVladimir Oltean err = dsa_lag_master_prechangelower_sanity_check(dev, info); 3160acc43b7bSVladimir Oltean if (notifier_to_errno(err)) 3161acc43b7bSVladimir Oltean return err; 3162acc43b7bSVladimir Oltean 3163920a33cdSVladimir Oltean err = dsa_bridge_prechangelower_sanity_check(dev, info); 3164920a33cdSVladimir Oltean if (notifier_to_errno(err)) 3165920a33cdSVladimir Oltean return err; 3166920a33cdSVladimir Oltean 31674c3f80d2SVladimir Oltean err = dsa_slave_prechangeupper(dev, ptr); 31684c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 31694c3f80d2SVladimir Oltean return err; 317074918945SVladimir Oltean 31714c3f80d2SVladimir Oltean err = dsa_slave_lag_prechangeupper(dev, ptr); 31724c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 31734c3f80d2SVladimir Oltean return err; 317474918945SVladimir Oltean 317583501299SVladimir Oltean break; 31762b138406SVladimir Oltean } 31774c3f80d2SVladimir Oltean case NETDEV_CHANGEUPPER: { 31784c3f80d2SVladimir Oltean int err; 3179058102a6STobias Waldekranz 31804c3f80d2SVladimir Oltean err = dsa_slave_changeupper(dev, ptr); 31814c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 31824c3f80d2SVladimir Oltean return err; 31834c3f80d2SVladimir Oltean 31844c3f80d2SVladimir Oltean err = dsa_slave_lag_changeupper(dev, ptr); 31854c3f80d2SVladimir Oltean if (notifier_to_errno(err)) 31864c3f80d2SVladimir Oltean return err; 3187058102a6STobias Waldekranz 3188acc43b7bSVladimir Oltean err = dsa_master_changeupper(dev, ptr); 3189acc43b7bSVladimir Oltean if (notifier_to_errno(err)) 3190acc43b7bSVladimir Oltean return err; 3191acc43b7bSVladimir Oltean 3192058102a6STobias Waldekranz break; 31934c3f80d2SVladimir Oltean } 3194058102a6STobias Waldekranz case NETDEV_CHANGELOWERSTATE: { 3195058102a6STobias Waldekranz struct netdev_notifier_changelowerstate_info *info = ptr; 3196058102a6STobias Waldekranz struct dsa_port *dp; 31970a6d58a7SDan Carpenter int err = 0; 3198058102a6STobias Waldekranz 3199acc43b7bSVladimir Oltean if (dsa_slave_dev_check(dev)) { 3200058102a6STobias Waldekranz dp = dsa_slave_to_port(dev); 3201058102a6STobias Waldekranz 3202058102a6STobias Waldekranz err = dsa_port_lag_change(dp, info->lower_state_info); 3203acc43b7bSVladimir Oltean } 3204acc43b7bSVladimir Oltean 3205acc43b7bSVladimir Oltean /* Mirror LAG port events on DSA masters that are in 3206acc43b7bSVladimir Oltean * a LAG towards their respective switch CPU ports 3207acc43b7bSVladimir Oltean */ 3208acc43b7bSVladimir Oltean if (netdev_uses_dsa(dev)) { 3209acc43b7bSVladimir Oltean dp = dev->dsa_ptr; 3210acc43b7bSVladimir Oltean 3211acc43b7bSVladimir Oltean err = dsa_port_lag_change(dp, info->lower_state_info); 3212acc43b7bSVladimir Oltean } 3213acc43b7bSVladimir Oltean 3214058102a6STobias Waldekranz return notifier_from_errno(err); 3215058102a6STobias Waldekranz } 3216295ab96fSVladimir Oltean case NETDEV_CHANGE: 3217295ab96fSVladimir Oltean case NETDEV_UP: { 3218295ab96fSVladimir Oltean /* Track state of master port. 3219295ab96fSVladimir Oltean * DSA driver may require the master port (and indirectly 3220295ab96fSVladimir Oltean * the tagger) to be available for some special operation. 3221295ab96fSVladimir Oltean */ 3222295ab96fSVladimir Oltean if (netdev_uses_dsa(dev)) { 3223295ab96fSVladimir Oltean struct dsa_port *cpu_dp = dev->dsa_ptr; 3224295ab96fSVladimir Oltean struct dsa_switch_tree *dst = cpu_dp->ds->dst; 3225295ab96fSVladimir Oltean 3226295ab96fSVladimir Oltean /* Track when the master port is UP */ 3227295ab96fSVladimir Oltean dsa_tree_master_oper_state_change(dst, dev, 3228295ab96fSVladimir Oltean netif_oper_up(dev)); 3229295ab96fSVladimir Oltean 3230295ab96fSVladimir Oltean /* Track when the master port is ready and can accept 3231295ab96fSVladimir Oltean * packet. 3232295ab96fSVladimir Oltean * NETDEV_UP event is not enough to flag a port as ready. 3233295ab96fSVladimir Oltean * We also have to wait for linkwatch_do_dev to dev_activate 3234295ab96fSVladimir Oltean * and emit a NETDEV_CHANGE event. 3235295ab96fSVladimir Oltean * We check if a master port is ready by checking if the dev 3236295ab96fSVladimir Oltean * have a qdisc assigned and is not noop. 3237295ab96fSVladimir Oltean */ 3238295ab96fSVladimir Oltean dsa_tree_master_admin_state_change(dst, dev, 3239295ab96fSVladimir Oltean !qdisc_tx_is_noop(dev)); 3240295ab96fSVladimir Oltean 3241295ab96fSVladimir Oltean return NOTIFY_OK; 3242295ab96fSVladimir Oltean } 3243295ab96fSVladimir Oltean 3244295ab96fSVladimir Oltean return NOTIFY_DONE; 3245295ab96fSVladimir Oltean } 3246c0a8a9c2SVladimir Oltean case NETDEV_GOING_DOWN: { 3247c0a8a9c2SVladimir Oltean struct dsa_port *dp, *cpu_dp; 3248c0a8a9c2SVladimir Oltean struct dsa_switch_tree *dst; 3249c0a8a9c2SVladimir Oltean LIST_HEAD(close_list); 3250c0a8a9c2SVladimir Oltean 3251c0a8a9c2SVladimir Oltean if (!netdev_uses_dsa(dev)) 3252c0a8a9c2SVladimir Oltean return NOTIFY_DONE; 3253c0a8a9c2SVladimir Oltean 3254c0a8a9c2SVladimir Oltean cpu_dp = dev->dsa_ptr; 3255c0a8a9c2SVladimir Oltean dst = cpu_dp->ds->dst; 3256c0a8a9c2SVladimir Oltean 3257295ab96fSVladimir Oltean dsa_tree_master_admin_state_change(dst, dev, false); 3258295ab96fSVladimir Oltean 3259c0a8a9c2SVladimir Oltean list_for_each_entry(dp, &dst->ports, list) { 3260d0004a02SVladimir Oltean if (!dsa_port_is_user(dp)) 3261c0a8a9c2SVladimir Oltean continue; 3262c0a8a9c2SVladimir Oltean 32637136097eSVladimir Oltean if (dp->cpu_dp != cpu_dp) 32647136097eSVladimir Oltean continue; 32657136097eSVladimir Oltean 3266c0a8a9c2SVladimir Oltean list_add(&dp->slave->close_list, &close_list); 3267c0a8a9c2SVladimir Oltean } 3268c0a8a9c2SVladimir Oltean 3269c0a8a9c2SVladimir Oltean dev_close_many(&close_list, true); 3270c0a8a9c2SVladimir Oltean 3271c0a8a9c2SVladimir Oltean return NOTIFY_OK; 3272c0a8a9c2SVladimir Oltean } 3273c0a8a9c2SVladimir Oltean default: 3274c0a8a9c2SVladimir Oltean break; 3275cc1d5bdaSFlorian Fainelli } 3276b73adef6SFlorian Fainelli 3277b73adef6SFlorian Fainelli return NOTIFY_DONE; 3278b73adef6SFlorian Fainelli } 327988e4f0caSVivien Didelot 3280c4bb76a9SVladimir Oltean static void 3281c4bb76a9SVladimir Oltean dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) 3282c4bb76a9SVladimir Oltean { 3283c35b57ceSVladimir Oltean struct switchdev_notifier_fdb_info info = {}; 3284c4bb76a9SVladimir Oltean 3285c4bb76a9SVladimir Oltean info.addr = switchdev_work->addr; 3286c4bb76a9SVladimir Oltean info.vid = switchdev_work->vid; 3287c4bb76a9SVladimir Oltean info.offloaded = true; 3288c4bb76a9SVladimir Oltean call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, 328993c79823SVladimir Oltean switchdev_work->orig_dev, &info.info, NULL); 3290c4bb76a9SVladimir Oltean } 3291c9eb3e0fSArkadi Sharshevsky 3292c9eb3e0fSArkadi Sharshevsky static void dsa_slave_switchdev_event_work(struct work_struct *work) 3293c9eb3e0fSArkadi Sharshevsky { 3294c9eb3e0fSArkadi Sharshevsky struct dsa_switchdev_event_work *switchdev_work = 3295c9eb3e0fSArkadi Sharshevsky container_of(work, struct dsa_switchdev_event_work, work); 329668d6d71eSVladimir Oltean const unsigned char *addr = switchdev_work->addr; 3297e35f12e9SVladimir Oltean struct net_device *dev = switchdev_work->dev; 329868d6d71eSVladimir Oltean u16 vid = switchdev_work->vid; 3299e35f12e9SVladimir Oltean struct dsa_switch *ds; 3300c4bb76a9SVladimir Oltean struct dsa_port *dp; 3301c9eb3e0fSArkadi Sharshevsky int err; 3302c9eb3e0fSArkadi Sharshevsky 3303e35f12e9SVladimir Oltean dp = dsa_slave_to_port(dev); 3304e35f12e9SVladimir Oltean ds = dp->ds; 3305c4bb76a9SVladimir Oltean 3306c9eb3e0fSArkadi Sharshevsky switch (switchdev_work->event) { 3307c9eb3e0fSArkadi Sharshevsky case SWITCHDEV_FDB_ADD_TO_DEVICE: 33083dc80afcSVladimir Oltean if (switchdev_work->host_addr) 330968d6d71eSVladimir Oltean err = dsa_port_bridge_host_fdb_add(dp, addr, vid); 3310e212fa7cSVladimir Oltean else if (dp->lag) 331168d6d71eSVladimir Oltean err = dsa_port_lag_fdb_add(dp, addr, vid); 33123dc80afcSVladimir Oltean else 331368d6d71eSVladimir Oltean err = dsa_port_fdb_add(dp, addr, vid); 3314c9eb3e0fSArkadi Sharshevsky if (err) { 3315c4bb76a9SVladimir Oltean dev_err(ds->dev, 3316c4bb76a9SVladimir Oltean "port %d failed to add %pM vid %d to fdb: %d\n", 331768d6d71eSVladimir Oltean dp->index, addr, vid, err); 3318c9eb3e0fSArkadi Sharshevsky break; 3319c9eb3e0fSArkadi Sharshevsky } 3320c4bb76a9SVladimir Oltean dsa_fdb_offload_notify(switchdev_work); 3321c9eb3e0fSArkadi Sharshevsky break; 3322c9eb3e0fSArkadi Sharshevsky 3323c9eb3e0fSArkadi Sharshevsky case SWITCHDEV_FDB_DEL_TO_DEVICE: 33243dc80afcSVladimir Oltean if (switchdev_work->host_addr) 332568d6d71eSVladimir Oltean err = dsa_port_bridge_host_fdb_del(dp, addr, vid); 3326e212fa7cSVladimir Oltean else if (dp->lag) 332768d6d71eSVladimir Oltean err = dsa_port_lag_fdb_del(dp, addr, vid); 33283dc80afcSVladimir Oltean else 332968d6d71eSVladimir Oltean err = dsa_port_fdb_del(dp, addr, vid); 3330c9eb3e0fSArkadi Sharshevsky if (err) { 3331c4bb76a9SVladimir Oltean dev_err(ds->dev, 3332c4bb76a9SVladimir Oltean "port %d failed to delete %pM vid %d from fdb: %d\n", 333368d6d71eSVladimir Oltean dp->index, addr, vid, err); 3334c9eb3e0fSArkadi Sharshevsky } 33352fd18650SVladimir Oltean 3336c9eb3e0fSArkadi Sharshevsky break; 3337c9eb3e0fSArkadi Sharshevsky } 3338c9eb3e0fSArkadi Sharshevsky 3339c9eb3e0fSArkadi Sharshevsky kfree(switchdev_work); 3340c9eb3e0fSArkadi Sharshevsky } 3341c9eb3e0fSArkadi Sharshevsky 3342b94dc99cSVladimir Oltean static bool dsa_foreign_dev_check(const struct net_device *dev, 3343b94dc99cSVladimir Oltean const struct net_device *foreign_dev) 3344d5f19486SVladimir Oltean { 3345b94dc99cSVladimir Oltean const struct dsa_port *dp = dsa_slave_to_port(dev); 3346b94dc99cSVladimir Oltean struct dsa_switch_tree *dst = dp->ds->dst; 3347b94dc99cSVladimir Oltean 3348b94dc99cSVladimir Oltean if (netif_is_bridge_master(foreign_dev)) 3349936db8a2SVladimir Oltean return !dsa_tree_offloads_bridge_dev(dst, foreign_dev); 3350b94dc99cSVladimir Oltean 3351b94dc99cSVladimir Oltean if (netif_is_bridge_port(foreign_dev)) 3352b94dc99cSVladimir Oltean return !dsa_tree_offloads_bridge_port(dst, foreign_dev); 3353b94dc99cSVladimir Oltean 3354b94dc99cSVladimir Oltean /* Everything else is foreign */ 3355b94dc99cSVladimir Oltean return true; 3356d5f19486SVladimir Oltean } 3357d5f19486SVladimir Oltean 3358b94dc99cSVladimir Oltean static int dsa_slave_fdb_event(struct net_device *dev, 3359716a30a9SVladimir Oltean struct net_device *orig_dev, 3360716a30a9SVladimir Oltean unsigned long event, const void *ctx, 3361716a30a9SVladimir Oltean const struct switchdev_notifier_fdb_info *fdb_info) 3362b94dc99cSVladimir Oltean { 3363b94dc99cSVladimir Oltean struct dsa_switchdev_event_work *switchdev_work; 3364b94dc99cSVladimir Oltean struct dsa_port *dp = dsa_slave_to_port(dev); 3365b94dc99cSVladimir Oltean bool host_addr = fdb_info->is_local; 3366b94dc99cSVladimir Oltean struct dsa_switch *ds = dp->ds; 3367b94dc99cSVladimir Oltean 3368b94dc99cSVladimir Oltean if (ctx && ctx != dp) 3369b94dc99cSVladimir Oltean return 0; 3370b94dc99cSVladimir Oltean 3371a860352eSTobias Waldekranz if (!dp->bridge) 3372a860352eSTobias Waldekranz return 0; 3373a860352eSTobias Waldekranz 3374e212fa7cSVladimir Oltean if (switchdev_fdb_is_dynamically_learned(fdb_info)) { 3375e212fa7cSVladimir Oltean if (dsa_port_offloads_bridge_port(dp, orig_dev)) 3376b94dc99cSVladimir Oltean return 0; 3377b94dc99cSVladimir Oltean 3378e212fa7cSVladimir Oltean /* FDB entries learned by the software bridge or by foreign 3379e212fa7cSVladimir Oltean * bridge ports should be installed as host addresses only if 3380e212fa7cSVladimir Oltean * the driver requests assisted learning. 3381b94dc99cSVladimir Oltean */ 3382e212fa7cSVladimir Oltean if (!ds->assisted_learning_on_cpu_port) 3383b94dc99cSVladimir Oltean return 0; 3384e212fa7cSVladimir Oltean } 3385b94dc99cSVladimir Oltean 3386b94dc99cSVladimir Oltean /* Also treat FDB entries on foreign interfaces bridged with us as host 3387b94dc99cSVladimir Oltean * addresses. 3388b94dc99cSVladimir Oltean */ 3389b94dc99cSVladimir Oltean if (dsa_foreign_dev_check(dev, orig_dev)) 3390b94dc99cSVladimir Oltean host_addr = true; 3391b94dc99cSVladimir Oltean 3392e212fa7cSVladimir Oltean /* Check early that we're not doing work in vain. 3393e212fa7cSVladimir Oltean * Host addresses on LAG ports still require regular FDB ops, 3394e212fa7cSVladimir Oltean * since the CPU port isn't in a LAG. 3395e212fa7cSVladimir Oltean */ 3396e212fa7cSVladimir Oltean if (dp->lag && !host_addr) { 3397e212fa7cSVladimir Oltean if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del) 3398e212fa7cSVladimir Oltean return -EOPNOTSUPP; 3399e212fa7cSVladimir Oltean } else { 3400e212fa7cSVladimir Oltean if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del) 3401e212fa7cSVladimir Oltean return -EOPNOTSUPP; 3402e212fa7cSVladimir Oltean } 3403e212fa7cSVladimir Oltean 3404b94dc99cSVladimir Oltean switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); 3405b94dc99cSVladimir Oltean if (!switchdev_work) 3406b94dc99cSVladimir Oltean return -ENOMEM; 3407b94dc99cSVladimir Oltean 3408b94dc99cSVladimir Oltean netdev_dbg(dev, "%s FDB entry towards %s, addr %pM vid %d%s\n", 3409b94dc99cSVladimir Oltean event == SWITCHDEV_FDB_ADD_TO_DEVICE ? "Adding" : "Deleting", 3410b94dc99cSVladimir Oltean orig_dev->name, fdb_info->addr, fdb_info->vid, 3411b94dc99cSVladimir Oltean host_addr ? " as host address" : ""); 3412b94dc99cSVladimir Oltean 3413b94dc99cSVladimir Oltean INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work); 3414b94dc99cSVladimir Oltean switchdev_work->event = event; 3415b94dc99cSVladimir Oltean switchdev_work->dev = dev; 341693c79823SVladimir Oltean switchdev_work->orig_dev = orig_dev; 3417b94dc99cSVladimir Oltean 3418b94dc99cSVladimir Oltean ether_addr_copy(switchdev_work->addr, fdb_info->addr); 3419b94dc99cSVladimir Oltean switchdev_work->vid = fdb_info->vid; 3420b94dc99cSVladimir Oltean switchdev_work->host_addr = host_addr; 3421b94dc99cSVladimir Oltean 3422b94dc99cSVladimir Oltean dsa_schedule_work(&switchdev_work->work); 3423b94dc99cSVladimir Oltean 3424d5f19486SVladimir Oltean return 0; 3425d5f19486SVladimir Oltean } 3426d5f19486SVladimir Oltean 3427c9eb3e0fSArkadi Sharshevsky /* Called under rcu_read_lock() */ 3428c9eb3e0fSArkadi Sharshevsky static int dsa_slave_switchdev_event(struct notifier_block *unused, 3429c9eb3e0fSArkadi Sharshevsky unsigned long event, void *ptr) 3430c9eb3e0fSArkadi Sharshevsky { 3431c9eb3e0fSArkadi Sharshevsky struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 343279b139f4SVivien Didelot int err; 343379b139f4SVivien Didelot 3434447d290aSVladimir Oltean switch (event) { 3435447d290aSVladimir Oltean case SWITCHDEV_PORT_ATTR_SET: 343679b139f4SVivien Didelot err = switchdev_handle_port_attr_set(dev, ptr, 343779b139f4SVivien Didelot dsa_slave_dev_check, 343879b139f4SVivien Didelot dsa_slave_port_attr_set); 343979b139f4SVivien Didelot return notifier_from_errno(err); 3440447d290aSVladimir Oltean case SWITCHDEV_FDB_ADD_TO_DEVICE: 3441447d290aSVladimir Oltean case SWITCHDEV_FDB_DEL_TO_DEVICE: 3442716a30a9SVladimir Oltean err = switchdev_handle_fdb_event_to_device(dev, event, ptr, 3443b94dc99cSVladimir Oltean dsa_slave_dev_check, 3444b94dc99cSVladimir Oltean dsa_foreign_dev_check, 3445ec638740SVladimir Oltean dsa_slave_fdb_event); 3446b94dc99cSVladimir Oltean return notifier_from_errno(err); 3447c9eb3e0fSArkadi Sharshevsky default: 3448c9eb3e0fSArkadi Sharshevsky return NOTIFY_DONE; 3449c9eb3e0fSArkadi Sharshevsky } 3450c9eb3e0fSArkadi Sharshevsky 3451c9eb3e0fSArkadi Sharshevsky return NOTIFY_OK; 3452c9eb3e0fSArkadi Sharshevsky } 3453c9eb3e0fSArkadi Sharshevsky 34542b239f67SPetr Machata static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, 34552b239f67SPetr Machata unsigned long event, void *ptr) 34562b239f67SPetr Machata { 34572b239f67SPetr Machata struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 345879b139f4SVivien Didelot int err; 34592b239f67SPetr Machata 34602b239f67SPetr Machata switch (event) { 346179b139f4SVivien Didelot case SWITCHDEV_PORT_OBJ_ADD: 3462164f861bSVladimir Oltean err = switchdev_handle_port_obj_add_foreign(dev, ptr, 346379b139f4SVivien Didelot dsa_slave_dev_check, 3464164f861bSVladimir Oltean dsa_foreign_dev_check, 346579b139f4SVivien Didelot dsa_slave_port_obj_add); 346679b139f4SVivien Didelot return notifier_from_errno(err); 34672b239f67SPetr Machata case SWITCHDEV_PORT_OBJ_DEL: 3468164f861bSVladimir Oltean err = switchdev_handle_port_obj_del_foreign(dev, ptr, 346979b139f4SVivien Didelot dsa_slave_dev_check, 3470164f861bSVladimir Oltean dsa_foreign_dev_check, 347179b139f4SVivien Didelot dsa_slave_port_obj_del); 347279b139f4SVivien Didelot return notifier_from_errno(err); 34739ed1ecedSFlorian Fainelli case SWITCHDEV_PORT_ATTR_SET: 347479b139f4SVivien Didelot err = switchdev_handle_port_attr_set(dev, ptr, 347579b139f4SVivien Didelot dsa_slave_dev_check, 347679b139f4SVivien Didelot dsa_slave_port_attr_set); 347779b139f4SVivien Didelot return notifier_from_errno(err); 34782b239f67SPetr Machata } 34792b239f67SPetr Machata 34802b239f67SPetr Machata return NOTIFY_DONE; 34812b239f67SPetr Machata } 34822b239f67SPetr Machata 348388e4f0caSVivien Didelot static struct notifier_block dsa_slave_nb __read_mostly = { 348488e4f0caSVivien Didelot .notifier_call = dsa_slave_netdevice_event, 348588e4f0caSVivien Didelot }; 348688e4f0caSVivien Didelot 3487010e269fSVladimir Oltean struct notifier_block dsa_slave_switchdev_notifier = { 3488c9eb3e0fSArkadi Sharshevsky .notifier_call = dsa_slave_switchdev_event, 3489c9eb3e0fSArkadi Sharshevsky }; 3490c9eb3e0fSArkadi Sharshevsky 3491010e269fSVladimir Oltean struct notifier_block dsa_slave_switchdev_blocking_notifier = { 34922b239f67SPetr Machata .notifier_call = dsa_slave_switchdev_blocking_event, 34932b239f67SPetr Machata }; 34942b239f67SPetr Machata 349588e4f0caSVivien Didelot int dsa_slave_register_notifier(void) 349688e4f0caSVivien Didelot { 34972b239f67SPetr Machata struct notifier_block *nb; 3498c9eb3e0fSArkadi Sharshevsky int err; 3499c9eb3e0fSArkadi Sharshevsky 3500c9eb3e0fSArkadi Sharshevsky err = register_netdevice_notifier(&dsa_slave_nb); 3501c9eb3e0fSArkadi Sharshevsky if (err) 3502c9eb3e0fSArkadi Sharshevsky return err; 3503c9eb3e0fSArkadi Sharshevsky 3504c9eb3e0fSArkadi Sharshevsky err = register_switchdev_notifier(&dsa_slave_switchdev_notifier); 3505c9eb3e0fSArkadi Sharshevsky if (err) 3506c9eb3e0fSArkadi Sharshevsky goto err_switchdev_nb; 3507c9eb3e0fSArkadi Sharshevsky 35082b239f67SPetr Machata nb = &dsa_slave_switchdev_blocking_notifier; 35092b239f67SPetr Machata err = register_switchdev_blocking_notifier(nb); 35102b239f67SPetr Machata if (err) 35112b239f67SPetr Machata goto err_switchdev_blocking_nb; 35122b239f67SPetr Machata 3513c9eb3e0fSArkadi Sharshevsky return 0; 3514c9eb3e0fSArkadi Sharshevsky 35152b239f67SPetr Machata err_switchdev_blocking_nb: 35162b239f67SPetr Machata unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); 3517c9eb3e0fSArkadi Sharshevsky err_switchdev_nb: 3518c9eb3e0fSArkadi Sharshevsky unregister_netdevice_notifier(&dsa_slave_nb); 3519c9eb3e0fSArkadi Sharshevsky return err; 352088e4f0caSVivien Didelot } 352188e4f0caSVivien Didelot 352288e4f0caSVivien Didelot void dsa_slave_unregister_notifier(void) 352388e4f0caSVivien Didelot { 35242b239f67SPetr Machata struct notifier_block *nb; 352588e4f0caSVivien Didelot int err; 352688e4f0caSVivien Didelot 35272b239f67SPetr Machata nb = &dsa_slave_switchdev_blocking_notifier; 35282b239f67SPetr Machata err = unregister_switchdev_blocking_notifier(nb); 35292b239f67SPetr Machata if (err) 35302b239f67SPetr Machata pr_err("DSA: failed to unregister switchdev blocking notifier (%d)\n", err); 35312b239f67SPetr Machata 3532c9eb3e0fSArkadi Sharshevsky err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); 3533c9eb3e0fSArkadi Sharshevsky if (err) 3534c9eb3e0fSArkadi Sharshevsky pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err); 3535c9eb3e0fSArkadi Sharshevsky 353688e4f0caSVivien Didelot err = unregister_netdevice_notifier(&dsa_slave_nb); 353788e4f0caSVivien Didelot if (err) 353888e4f0caSVivien Didelot pr_err("DSA: failed to unregister slave notifier (%d)\n", err); 353988e4f0caSVivien Didelot } 3540