arm64: dts: rockchip: enable pcie_phy for Sapphire board
[firefly-linux-kernel-4.4.55.git] / net / core / dev.c
index 9efbdb3ff78a0098b83f60e0c626da933035e983..08215a85c742a9999bf4cb2cd2b6b11e4a6fade0 100644 (file)
@@ -1676,24 +1676,19 @@ EXPORT_SYMBOL_GPL(net_dec_ingress_queue);
 
 static struct static_key netstamp_needed __read_mostly;
 #ifdef HAVE_JUMP_LABEL
-/* We are not allowed to call static_key_slow_dec() from irq context
- * If net_disable_timestamp() is called from irq context, defer the
- * static_key_slow_dec() calls.
- */
 static atomic_t netstamp_needed_deferred;
-#endif
-
-void net_enable_timestamp(void)
+static void netstamp_clear(struct work_struct *work)
 {
-#ifdef HAVE_JUMP_LABEL
        int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
 
-       if (deferred) {
-               while (--deferred)
-                       static_key_slow_dec(&netstamp_needed);
-               return;
-       }
+       while (deferred--)
+               static_key_slow_dec(&netstamp_needed);
+}
+static DECLARE_WORK(netstamp_work, netstamp_clear);
 #endif
+
+void net_enable_timestamp(void)
+{
        static_key_slow_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
@@ -1701,12 +1696,12 @@ EXPORT_SYMBOL(net_enable_timestamp);
 void net_disable_timestamp(void)
 {
 #ifdef HAVE_JUMP_LABEL
-       if (in_interrupt()) {
-               atomic_inc(&netstamp_needed_deferred);
-               return;
-       }
-#endif
+       /* net_disable_timestamp() can be called from non process context */
+       atomic_inc(&netstamp_needed_deferred);
+       schedule_work(&netstamp_work);
+#else
        static_key_slow_dec(&netstamp_needed);
+#endif
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
@@ -2462,7 +2457,7 @@ int skb_checksum_help(struct sk_buff *skb)
                        goto out;
        }
 
-       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0;
 out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -2650,9 +2645,9 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
        if (skb->ip_summed != CHECKSUM_NONE &&
            !can_checksum_protocol(features, type)) {
                features &= ~NETIF_F_ALL_CSUM;
-       } else if (illegal_highdma(skb->dev, skb)) {
-               features &= ~NETIF_F_SG;
        }
+       if (illegal_highdma(skb->dev, skb))
+               features &= ~NETIF_F_SG;
 
        return features;
 }
@@ -2836,6 +2831,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
        }
        return head;
 }
+EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
 
 static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
@@ -3721,6 +3717,22 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
        return skb;
 }
 
+/**
+ *     netdev_is_rx_handler_busy - check if receive handler is registered
+ *     @dev: device to check
+ *
+ *     Check if a receive handler is already registered for a given device.
+ *     Return true if there one.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+bool netdev_is_rx_handler_busy(struct net_device *dev)
+{
+       ASSERT_RTNL();
+       return dev && rtnl_dereference(dev->rx_handler);
+}
+EXPORT_SYMBOL_GPL(netdev_is_rx_handler_busy);
+
 /**
  *     netdev_rx_handler_register - register receive handler
  *     @dev: device to register a handler for
@@ -4170,7 +4182,9 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
            pinfo->nr_frags &&
            !PageHighMem(skb_frag_page(frag0))) {
                NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
-               NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
+               NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
+                                                   skb_frag_size(frag0),
+                                                   skb->end - skb->tail);
        }
 }
 
@@ -4223,7 +4237,8 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
-               NAPI_GRO_CB(skb)->udp_mark = 0;
+               NAPI_GRO_CB(skb)->encap_mark = 0;
+               NAPI_GRO_CB(skb)->recursion_counter = 0;
                NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
 
                /* Setup for GRO checksum validation */
@@ -5188,6 +5203,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev,
 
 static int __netdev_adjacent_dev_insert(struct net_device *dev,
                                        struct net_device *adj_dev,
+                                       u16 ref_nr,
                                        struct list_head *dev_list,
                                        void *private, bool master)
 {
@@ -5197,7 +5213,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
        adj = __netdev_find_adj(adj_dev, dev_list);
 
        if (adj) {
-               adj->ref_nr++;
+               adj->ref_nr += ref_nr;
                return 0;
        }
 
@@ -5207,7 +5223,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
 
        adj->dev = adj_dev;
        adj->master = master;
-       adj->ref_nr = 1;
+       adj->ref_nr = ref_nr;
        adj->private = private;
        dev_hold(adj_dev);
 
@@ -5246,6 +5262,7 @@ free_adj:
 
 static void __netdev_adjacent_dev_remove(struct net_device *dev,
                                         struct net_device *adj_dev,
+                                        u16 ref_nr,
                                         struct list_head *dev_list)
 {
        struct netdev_adjacent *adj;
@@ -5258,10 +5275,10 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
                BUG();
        }
 
-       if (adj->ref_nr > 1) {
-               pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name,
-                        adj->ref_nr-1);
-               adj->ref_nr--;
+       if (adj->ref_nr > ref_nr) {
+               pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name,
+                        ref_nr, adj->ref_nr-ref_nr);
+               adj->ref_nr -= ref_nr;
                return;
        }
 
@@ -5280,21 +5297,22 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
 
 static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
                                            struct net_device *upper_dev,
+                                           u16 ref_nr,
                                            struct list_head *up_list,
                                            struct list_head *down_list,
                                            void *private, bool master)
 {
        int ret;
 
-       ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private,
-                                          master);
+       ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list,
+                                          private, master);
        if (ret)
                return ret;
 
-       ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private,
-                                          false);
+       ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list,
+                                          private, false);
        if (ret) {
-               __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
+               __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
                return ret;
        }
 
@@ -5302,9 +5320,10 @@ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
 }
 
 static int __netdev_adjacent_dev_link(struct net_device *dev,
-                                     struct net_device *upper_dev)
+                                     struct net_device *upper_dev,
+                                     u16 ref_nr)
 {
-       return __netdev_adjacent_dev_link_lists(dev, upper_dev,
+       return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr,
                                                &dev->all_adj_list.upper,
                                                &upper_dev->all_adj_list.lower,
                                                NULL, false);
@@ -5312,17 +5331,19 @@ static int __netdev_adjacent_dev_link(struct net_device *dev,
 
 static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
                                               struct net_device *upper_dev,
+                                              u16 ref_nr,
                                               struct list_head *up_list,
                                               struct list_head *down_list)
 {
-       __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
-       __netdev_adjacent_dev_remove(upper_dev, dev, down_list);
+       __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
+       __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
 }
 
 static void __netdev_adjacent_dev_unlink(struct net_device *dev,
-                                        struct net_device *upper_dev)
+                                        struct net_device *upper_dev,
+                                        u16 ref_nr)
 {
-       __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
+       __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
                                           &dev->all_adj_list.upper,
                                           &upper_dev->all_adj_list.lower);
 }
@@ -5331,17 +5352,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
                                                struct net_device *upper_dev,
                                                void *private, bool master)
 {
-       int ret = __netdev_adjacent_dev_link(dev, upper_dev);
+       int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1);
 
        if (ret)
                return ret;
 
-       ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
+       ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1,
                                               &dev->adj_list.upper,
                                               &upper_dev->adj_list.lower,
                                               private, master);
        if (ret) {
-               __netdev_adjacent_dev_unlink(dev, upper_dev);
+               __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
                return ret;
        }
 
@@ -5351,8 +5372,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
 static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
                                                   struct net_device *upper_dev)
 {
-       __netdev_adjacent_dev_unlink(dev, upper_dev);
-       __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
+       __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
+       __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
                                           &dev->adj_list.upper,
                                           &upper_dev->adj_list.lower);
 }
@@ -5404,7 +5425,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
                        pr_debug("Interlinking %s with %s, non-neighbour\n",
                                 i->dev->name, j->dev->name);
-                       ret = __netdev_adjacent_dev_link(i->dev, j->dev);
+                       ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr);
                        if (ret)
                                goto rollback_mesh;
                }
@@ -5414,7 +5435,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
                pr_debug("linking %s's upper device %s with %s\n",
                         upper_dev->name, i->dev->name, dev->name);
-               ret = __netdev_adjacent_dev_link(dev, i->dev);
+               ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
                if (ret)
                        goto rollback_upper_mesh;
        }
@@ -5423,7 +5444,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        list_for_each_entry(i, &dev->all_adj_list.lower, list) {
                pr_debug("linking %s's lower device %s with %s\n", dev->name,
                         i->dev->name, upper_dev->name);
-               ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
+               ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
                if (ret)
                        goto rollback_lower_mesh;
        }
@@ -5437,7 +5458,7 @@ rollback_lower_mesh:
        list_for_each_entry(i, &dev->all_adj_list.lower, list) {
                if (i == to_i)
                        break;
-               __netdev_adjacent_dev_unlink(i->dev, upper_dev);
+               __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
        }
 
        i = NULL;
@@ -5447,7 +5468,7 @@ rollback_upper_mesh:
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
                if (i == to_i)
                        break;
-               __netdev_adjacent_dev_unlink(dev, i->dev);
+               __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
        }
 
        i = j = NULL;
@@ -5459,7 +5480,7 @@ rollback_mesh:
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
                        if (i == to_i && j == to_j)
                                break;
-                       __netdev_adjacent_dev_unlink(i->dev, j->dev);
+                       __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
                }
                if (i == to_i)
                        break;
@@ -5543,16 +5564,16 @@ void netdev_upper_dev_unlink(struct net_device *dev,
         */
        list_for_each_entry(i, &dev->all_adj_list.lower, list)
                list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
-                       __netdev_adjacent_dev_unlink(i->dev, j->dev);
+                       __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
 
        /* remove also the devices itself from lower/upper device
         * list
         */
        list_for_each_entry(i, &dev->all_adj_list.lower, list)
-               __netdev_adjacent_dev_unlink(i->dev, upper_dev);
+               __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
 
        list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
-               __netdev_adjacent_dev_unlink(dev, i->dev);
+               __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
 
        call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
                                      &changeupper_info.info);