Merge tag 'rtc-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
[linux-2.6-microblaze.git] / net / dsa / slave.c
index 3bc5ca4..4a0498b 100644 (file)
@@ -522,10 +522,10 @@ static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
        if (!clone)
                return;
 
-       DSA_SKB_CB(skb)->clone = clone;
-
-       if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type))
+       if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type)) {
+               DSA_SKB_CB(skb)->clone = clone;
                return;
+       }
 
        kfree_skb(clone);
 }
@@ -548,17 +548,36 @@ netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(dsa_enqueue_skb);
 
+static int dsa_realloc_skb(struct sk_buff *skb, struct net_device *dev)
+{
+       int needed_headroom = dev->needed_headroom;
+       int needed_tailroom = dev->needed_tailroom;
+
+       /* For tail taggers, we need to pad short frames ourselves, to ensure
+        * that the tail tag does not fail at its role of being at the end of
+        * the packet, once the master interface pads the frame. Account for
+        * that pad length here, and pad later.
+        */
+       if (unlikely(needed_tailroom && skb->len < ETH_ZLEN))
+               needed_tailroom += ETH_ZLEN - skb->len;
+       /* skb_headroom() returns unsigned int... */
+       needed_headroom = max_t(int, needed_headroom - skb_headroom(skb), 0);
+       needed_tailroom = max_t(int, needed_tailroom - skb_tailroom(skb), 0);
+
+       if (likely(!needed_headroom && !needed_tailroom && !skb_cloned(skb)))
+               /* No reallocation needed, yay! */
+               return 0;
+
+       return pskb_expand_head(skb, needed_headroom, needed_tailroom,
+                               GFP_ATOMIC);
+}
+
 static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct pcpu_sw_netstats *s;
        struct sk_buff *nskb;
 
-       s = this_cpu_ptr(p->stats64);
-       u64_stats_update_begin(&s->syncp);
-       s->tx_packets++;
-       s->tx_bytes += skb->len;
-       u64_stats_update_end(&s->syncp);
+       dev_sw_netstats_tx_add(dev, 1, skb->len);
 
        DSA_SKB_CB(skb)->clone = NULL;
 
@@ -567,6 +586,17 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        dsa_skb_tx_timestamp(p, skb);
 
+       if (dsa_realloc_skb(skb, dev)) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       /* needed_tailroom should still be 'warm' in the cache line from
+        * dsa_realloc_skb(), which has also ensured that padding is safe.
+        */
+       if (dev->needed_tailroom)
+               eth_skb_pad(skb);
+
        /* Transmit function may have to reallocate the original SKB,
         * in which case it must have freed it. Only free it here on error.
         */
@@ -679,7 +709,6 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
                                        uint64_t *data)
 {
        struct dsa_port *dp = dsa_slave_to_port(dev);
-       struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = dp->ds;
        struct pcpu_sw_netstats *s;
        unsigned int start;
@@ -688,7 +717,7 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
        for_each_possible_cpu(i) {
                u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
 
-               s = per_cpu_ptr(p->stats64, i);
+               s = per_cpu_ptr(dev->tstats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&s->syncp);
                        tx_packets = s->tx_packets;
@@ -1217,15 +1246,6 @@ static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type,
        return ds->ops->port_setup_tc(ds, dp->index, type, type_data);
 }
 
-static void dsa_slave_get_stats64(struct net_device *dev,
-                                 struct rtnl_link_stats64 *stats)
-{
-       struct dsa_slave_priv *p = netdev_priv(dev);
-
-       netdev_stats_to_stats64(stats, &dev->stats);
-       dev_fetch_sw_netstats(stats, p->stats64);
-}
-
 static int dsa_slave_get_rxnfc(struct net_device *dev,
                               struct ethtool_rxnfc *nfc, u32 *rule_locs)
 {
@@ -1601,7 +1621,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
 #endif
        .ndo_get_phys_port_name = dsa_slave_get_phys_port_name,
        .ndo_setup_tc           = dsa_slave_setup_tc,
-       .ndo_get_stats64        = dsa_slave_get_stats64,
+       .ndo_get_stats64        = dev_get_tstats64,
        .ndo_get_port_parent_id = dsa_slave_get_port_parent_id,
        .ndo_vlan_rx_add_vid    = dsa_slave_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = dsa_slave_vlan_rx_kill_vid,
@@ -1791,6 +1811,16 @@ 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,
@@ -1801,8 +1831,8 @@ int dsa_slave_create(struct dsa_port *port)
        slave_dev->vlan_features = master->vlan_features;
 
        p = netdev_priv(slave_dev);
-       p->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
-       if (!p->stats64) {
+       slave_dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!slave_dev->tstats) {
                free_netdev(slave_dev);
                return -ENOMEM;
        }
@@ -1820,8 +1850,8 @@ int dsa_slave_create(struct dsa_port *port)
        ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
        rtnl_unlock();
        if (ret && ret != -EOPNOTSUPP)
-               dev_warn(ds->dev, "nonfatal error %d setting MTU on port %d\n",
-                        ret, port->index);
+               dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n",
+                        ret, ETH_DATA_LEN, port->index);
 
        netif_carrier_off(slave_dev);
 
@@ -1864,7 +1894,7 @@ out_phy:
 out_gcells:
        gro_cells_destroy(&p->gcells);
 out_free:
-       free_percpu(p->stats64);
+       free_percpu(slave_dev->tstats);
        free_netdev(slave_dev);
        port->slave = NULL;
        return ret;
@@ -1886,7 +1916,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
        dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER);
        phylink_destroy(dp->pl);
        gro_cells_destroy(&p->gcells);
-       free_percpu(p->stats64);
+       free_percpu(slave_dev->tstats);
        free_netdev(slave_dev);
 }
 
@@ -1987,10 +2017,22 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
        switch (event) {
        case NETDEV_PRECHANGEUPPER: {
                struct netdev_notifier_changeupper_info *info = ptr;
+               struct dsa_switch *ds;
+               struct dsa_port *dp;
+               int err;
 
                if (!dsa_slave_dev_check(dev))
                        return dsa_prevent_bridging_8021q_upper(dev, ptr);
 
+               dp = dsa_slave_to_port(dev);
+               ds = dp->ds;
+
+               if (ds->ops->port_prechangeupper) {
+                       err = ds->ops->port_prechangeupper(ds, dp->index, info);
+                       if (err)
+                               return notifier_from_errno(err);
+               }
+
                if (is_vlan_dev(info->upper_dev))
                        return dsa_slave_check_8021q_upper(dev, ptr);
                break;