Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[deliverable/linux.git] / net / core / dev.c
index 56c3e00098c0b3308e1f56ac5fff2567ea4aa97e..95897ff3a76fefd79480c0e3e20264d690893222 100644 (file)
@@ -1454,6 +1454,27 @@ static inline void net_timestamp_check(struct sk_buff *skb)
                __net_timestamp(skb);
 }
 
+static inline bool is_skb_forwardable(struct net_device *dev,
+                                     struct sk_buff *skb)
+{
+       unsigned int len;
+
+       if (!(dev->flags & IFF_UP))
+               return false;
+
+       len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
+       if (skb->len <= len)
+               return true;
+
+       /* if TSO is enabled, we don't care about the length as the packet
+        * could be forwarded without being segmented before
+        */
+       if (skb_is_gso(skb))
+               return true;
+
+       return false;
+}
+
 /**
  * dev_forward_skb - loopback an skb to another netif
  *
@@ -1477,8 +1498,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
        skb_orphan(skb);
        nf_reset(skb);
 
-       if (unlikely(!(dev->flags & IFF_UP) ||
-                    (skb->len > (dev->mtu + dev->hard_header_len + VLAN_HLEN)))) {
+       if (unlikely(!is_skb_forwardable(dev, skb))) {
                atomic_long_inc(&dev->rx_dropped);
                kfree_skb(skb);
                return NET_RX_DROP;
@@ -5216,7 +5236,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features)
 }
 EXPORT_SYMBOL(netdev_fix_features);
 
-void netdev_update_features(struct net_device *dev)
+int __netdev_update_features(struct net_device *dev)
 {
        u32 features;
        int err = 0;
@@ -5230,7 +5250,7 @@ void netdev_update_features(struct net_device *dev)
        features = netdev_fix_features(dev, features);
 
        if (dev->features == features)
-               return;
+               return 0;
 
        netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n",
                dev->features, features);
@@ -5238,12 +5258,23 @@ void netdev_update_features(struct net_device *dev)
        if (dev->netdev_ops->ndo_set_features)
                err = dev->netdev_ops->ndo_set_features(dev, features);
 
-       if (!err)
-               dev->features = features;
-       else if (err < 0)
+       if (unlikely(err < 0)) {
                netdev_err(dev,
                        "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
                        err, features, dev->features);
+               return -1;
+       }
+
+       if (!err)
+               dev->features = features;
+
+       return 1;
+}
+
+void netdev_update_features(struct net_device *dev)
+{
+       if (__netdev_update_features(dev))
+               netdev_features_change(dev);
 }
 EXPORT_SYMBOL(netdev_update_features);
 
@@ -5394,6 +5425,14 @@ int register_netdevice(struct net_device *dev)
                dev->features &= ~NETIF_F_GSO;
        }
 
+       /* Turn on no cache copy if HW is doing checksum */
+       dev->hw_features |= NETIF_F_NOCACHE_COPY;
+       if ((dev->features & NETIF_F_ALL_CSUM) &&
+           !(dev->features & NETIF_F_NO_CSUM)) {
+               dev->wanted_features |= NETIF_F_NOCACHE_COPY;
+               dev->features |= NETIF_F_NOCACHE_COPY;
+       }
+
        /* Enable GRO and NETIF_F_HIGHDMA for vlans by default,
         * vlan_dev_init() will do the dev->features check, so these features
         * are enabled only if supported by underlying device.
@@ -5410,7 +5449,7 @@ int register_netdevice(struct net_device *dev)
                goto err_uninit;
        dev->reg_state = NETREG_REGISTERED;
 
-       netdev_update_features(dev);
+       __netdev_update_features(dev);
 
        /*
         *      Default initial state at registry is that the
@@ -6151,6 +6190,10 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask)
                }
        }
 
+       /* If device can't no cache copy, don't do for all */
+       if (!(one & NETIF_F_NOCACHE_COPY))
+               all &= ~NETIF_F_NOCACHE_COPY;
+
        one |= NETIF_F_ALL_CSUM;
 
        one |= all & NETIF_F_ONE_FOR_ALL;
This page took 0.027262 seconds and 5 git commands to generate.