Merge tag 'mt76-for-kvalo-2021-01-29' of https://github.com/nbd168/wireless
[linux-2.6-microblaze.git] / net / dsa / slave.c
index f2fb433..431bdbd 100644 (file)
@@ -68,8 +68,11 @@ static int dsa_slave_open(struct net_device *dev)
        struct dsa_port *dp = dsa_slave_to_port(dev);
        int err;
 
-       if (!(master->flags & IFF_UP))
-               return -ENETDOWN;
+       err = dev_open(master, NULL);
+       if (err < 0) {
+               netdev_err(dev, "failed to open master %s\n", master->name);
+               goto out;
+       }
 
        if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
                err = dev_uc_add(master, dev->dev_addr);
@@ -1430,7 +1433,7 @@ out:
        dsa_hw_port_list_free(&hw_port_list);
 }
 
-static int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
+int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct net_device *master = dsa_slave_to_master(dev);
        struct dsa_port *dp = dsa_slave_to_port(dev);
@@ -1708,6 +1711,27 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
        return ret;
 }
 
+void dsa_slave_setup_tagger(struct net_device *slave)
+{
+       struct dsa_port *dp = dsa_slave_to_port(slave);
+       struct dsa_slave_priv *p = netdev_priv(slave);
+       const struct dsa_port *cpu_dp = dp->cpu_dp;
+       struct net_device *master = cpu_dp->master;
+
+       if (cpu_dp->tag_ops->tail_tag)
+               slave->needed_tailroom = cpu_dp->tag_ops->overhead;
+       else
+               slave->needed_headroom = cpu_dp->tag_ops->overhead;
+       /* Try to save one extra realloc later in the TX path (in the master)
+        * by also inheriting the master's needed headroom and tailroom.
+        * The 8021q driver also does this.
+        */
+       slave->needed_headroom += master->needed_headroom;
+       slave->needed_tailroom += master->needed_tailroom;
+
+       p->xmit = cpu_dp->tag_ops->xmit;
+}
+
 static struct lock_class_key dsa_slave_netdev_xmit_lock_key;
 static void dsa_slave_set_lockdep_class_one(struct net_device *dev,
                                            struct netdev_queue *txq,
@@ -1782,16 +1806,6 @@ int dsa_slave_create(struct dsa_port *port)
        slave_dev->netdev_ops = &dsa_slave_netdev_ops;
        if (ds->ops->port_max_mtu)
                slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index);
-       if (cpu_dp->tag_ops->tail_tag)
-               slave_dev->needed_tailroom = cpu_dp->tag_ops->overhead;
-       else
-               slave_dev->needed_headroom = cpu_dp->tag_ops->overhead;
-       /* Try to save one extra realloc later in the TX path (in the master)
-        * by also inheriting the master's needed headroom and tailroom.
-        * The 8021q driver also does this.
-        */
-       slave_dev->needed_headroom += master->needed_headroom;
-       slave_dev->needed_tailroom += master->needed_tailroom;
        SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
 
        netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
@@ -1814,8 +1828,8 @@ int dsa_slave_create(struct dsa_port *port)
 
        p->dp = port;
        INIT_LIST_HEAD(&p->mall_tc_list);
-       p->xmit = cpu_dp->tag_ops->xmit;
        port->slave = slave_dev;
+       dsa_slave_setup_tagger(slave_dev);
 
        rtnl_lock();
        ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
@@ -2067,6 +2081,30 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
                err = dsa_port_lag_change(dp, info->lower_state_info);
                return notifier_from_errno(err);
        }
+       case NETDEV_GOING_DOWN: {
+               struct dsa_port *dp, *cpu_dp;
+               struct dsa_switch_tree *dst;
+               LIST_HEAD(close_list);
+
+               if (!netdev_uses_dsa(dev))
+                       return NOTIFY_DONE;
+
+               cpu_dp = dev->dsa_ptr;
+               dst = cpu_dp->ds->dst;
+
+               list_for_each_entry(dp, &dst->ports, list) {
+                       if (!dsa_is_user_port(dp->ds, dp->index))
+                               continue;
+
+                       list_add(&dp->slave->close_list, &close_list);
+               }
+
+               dev_close_many(&close_list, true);
+
+               return NOTIFY_OK;
+       }
+       default:
+               break;
        }
 
        return NOTIFY_DONE;
@@ -2204,6 +2242,14 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
 
                        if (!dp->ds->assisted_learning_on_cpu_port)
                                return NOTIFY_DONE;
+
+                       /* When the bridge learns an address on an offloaded
+                        * LAG we don't want to send traffic to the CPU, the
+                        * other ports bridged with the LAG should be able to
+                        * autonomously forward towards it.
+                        */
+                       if (dsa_tree_offloads_netdev(dp->ds->dst, dev))
+                               return NOTIFY_DONE;
                }
 
                if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)