]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/core/dev.c
rps: fixed missed rps_unlock
[net-next-2.6.git] / net / core / dev.c
index c0e260870c0a1c81ec5e150b64b0b35a9bf58ea5..74f77ca033497604bce3985ad44bef2ec8f8ed29 100644 (file)
 #include <linux/jhash.h>
 #include <linux/random.h>
 #include <trace/events/napi.h>
+#include <linux/pci.h>
 
 #include "net-sysfs.h"
 
@@ -206,6 +207,20 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
        return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
 }
 
+static inline void rps_lock(struct softnet_data *queue)
+{
+#ifdef CONFIG_RPS
+       spin_lock(&queue->input_pkt_queue.lock);
+#endif
+}
+
+static inline void rps_unlock(struct softnet_data *queue)
+{
+#ifdef CONFIG_RPS
+       spin_unlock(&queue->input_pkt_queue.lock);
+#endif
+}
+
 /* Device list insertion */
 static int list_netdevice(struct net_device *dev)
 {
@@ -772,14 +787,17 @@ EXPORT_SYMBOL(__dev_getfirstbyhwtype);
 
 struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
 {
-       struct net_device *dev;
+       struct net_device *dev, *ret = NULL;
 
-       rtnl_lock();
-       dev = __dev_getfirstbyhwtype(net, type);
-       if (dev)
-               dev_hold(dev);
-       rtnl_unlock();
-       return dev;
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev)
+               if (dev->type == type) {
+                       dev_hold(dev);
+                       ret = dev;
+                       break;
+               }
+       rcu_read_unlock();
+       return ret;
 }
 EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
@@ -1783,18 +1801,27 @@ EXPORT_SYMBOL(netdev_rx_csum_fault);
  * 2. No high memory really exists on this machine.
  */
 
-static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_HIGHMEM
        int i;
+       if (!(dev->features & NETIF_F_HIGHDMA)) {
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+                       if (PageHighMem(skb_shinfo(skb)->frags[i].page))
+                               return 1;
+       }
 
-       if (dev->features & NETIF_F_HIGHDMA)
-               return 0;
-
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               if (PageHighMem(skb_shinfo(skb)->frags[i].page))
-                       return 1;
+       if (PCI_DMA_BUS_IS_PHYS) {
+               struct device *pdev = dev->dev.parent;
 
+               if (!pdev)
+                       return 0;
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       dma_addr_t addr = page_to_phys(skb_shinfo(skb)->frags[i].page);
+                       if (!pdev->dma_mask || addr + PAGE_SIZE - 1 > *pdev->dma_mask)
+                               return 1;
+               }
+       }
 #endif
        return 0;
 }
@@ -2174,7 +2201,7 @@ int weight_p __read_mostly = 64;            /* old backlog weight */
 
 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
 /*
  * get_rps_cpu is called from netif_receive_skb and returns the target
  * CPU from the RPS map of the receiving queue for a given skb.
@@ -2310,19 +2337,19 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu)
        local_irq_save(flags);
        __get_cpu_var(netdev_rx_stat).total++;
 
-       spin_lock(&queue->input_pkt_queue.lock);
+       rps_lock(queue);
        if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
                if (queue->input_pkt_queue.qlen) {
 enqueue:
                        __skb_queue_tail(&queue->input_pkt_queue, skb);
-                       spin_unlock_irqrestore(&queue->input_pkt_queue.lock,
-                           flags);
+                       rps_unlock(queue);
+                       local_irq_restore(flags);
                        return NET_RX_SUCCESS;
                }
 
                /* Schedule NAPI for backlog device */
                if (napi_schedule_prep(&queue->backlog)) {
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
                        if (cpu != smp_processor_id()) {
                                struct rps_remote_softirq_cpus *rcpus =
                                    &__get_cpu_var(rps_remote_softirq_cpus);
@@ -2338,7 +2365,7 @@ enqueue:
                goto enqueue;
        }
 
-       spin_unlock(&queue->input_pkt_queue.lock);
+       rps_unlock(queue);
 
        __get_cpu_var(netdev_rx_stat).dropped++;
        local_irq_restore(flags);
@@ -2373,7 +2400,7 @@ int netif_rx(struct sk_buff *skb)
        if (!skb->tstamp.tv64)
                net_timestamp(skb);
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
        cpu = get_rps_cpu(skb->dev, skb);
        if (cpu < 0)
                cpu = smp_processor_id();
@@ -2618,7 +2645,7 @@ void netif_nit_deliver(struct sk_buff *skb)
        rcu_read_unlock();
 }
 
-int __netif_receive_skb(struct sk_buff *skb)
+static int __netif_receive_skb(struct sk_buff *skb)
 {
        struct packet_type *ptype, *pt_prev;
        struct net_device *orig_dev;
@@ -2747,7 +2774,7 @@ out:
  */
 int netif_receive_skb(struct sk_buff *skb)
 {
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
        int cpu;
 
        cpu = get_rps_cpu(skb->dev, skb);
@@ -2769,11 +2796,13 @@ static void flush_backlog(void *arg)
        struct softnet_data *queue = &__get_cpu_var(softnet_data);
        struct sk_buff *skb, *tmp;
 
+       rps_lock(queue);
        skb_queue_walk_safe(&queue->input_pkt_queue, skb, tmp)
                if (skb->dev == dev) {
                        __skb_unlink(skb, &queue->input_pkt_queue);
                        kfree_skb(skb);
                }
+       rps_unlock(queue);
 }
 
 static int napi_gro_complete(struct sk_buff *skb)
@@ -3086,14 +3115,16 @@ static int process_backlog(struct napi_struct *napi, int quota)
        do {
                struct sk_buff *skb;
 
-               spin_lock_irq(&queue->input_pkt_queue.lock);
+               local_irq_disable();
+               rps_lock(queue);
                skb = __skb_dequeue(&queue->input_pkt_queue);
                if (!skb) {
                        __napi_complete(napi);
-                       spin_unlock_irq(&queue->input_pkt_queue.lock);
+                       rps_unlock(queue);
                        break;
                }
-               spin_unlock_irq(&queue->input_pkt_queue.lock);
+               rps_unlock(queue);
+               local_irq_enable();
 
                __netif_receive_skb(skb);
        } while (++work < quota && jiffies == start_time);
@@ -3184,7 +3215,7 @@ void netif_napi_del(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(netif_napi_del);
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
 /*
  * net_rps_action sends any pending IPI's for rps.  This is only called from
  * softirq and interrupts must be enabled.
@@ -3209,7 +3240,7 @@ static void net_rx_action(struct softirq_action *h)
        unsigned long time_limit = jiffies + 2;
        int budget = netdev_budget;
        void *have;
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
        int select;
        struct rps_remote_softirq_cpus *rcpus;
 #endif
@@ -3275,7 +3306,7 @@ static void net_rx_action(struct softirq_action *h)
                netpoll_poll_unlock(have);
        }
 out:
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
        rcpus = &__get_cpu_var(rps_remote_softirq_cpus);
        select = rcpus->select;
        rcpus->select ^= 1;
@@ -3757,11 +3788,10 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
 
        slave->master = master;
 
-       synchronize_net();
-
-       if (old)
+       if (old) {
+               synchronize_net();
                dev_put(old);
-
+       }
        if (master)
                slave->flags |= IFF_SLAVE;
        else
@@ -3938,562 +3968,6 @@ void dev_set_rx_mode(struct net_device *dev)
        netif_addr_unlock_bh(dev);
 }
 
-/* hw addresses list handling functions */
-
-static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
-                        int addr_len, unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-       int alloc_size;
-
-       if (addr_len > MAX_ADDR_LEN)
-               return -EINVAL;
-
-       list_for_each_entry(ha, &list->list, list) {
-               if (!memcmp(ha->addr, addr, addr_len) &&
-                   ha->type == addr_type) {
-                       ha->refcount++;
-                       return 0;
-               }
-       }
-
-
-       alloc_size = sizeof(*ha);
-       if (alloc_size < L1_CACHE_BYTES)
-               alloc_size = L1_CACHE_BYTES;
-       ha = kmalloc(alloc_size, GFP_ATOMIC);
-       if (!ha)
-               return -ENOMEM;
-       memcpy(ha->addr, addr, addr_len);
-       ha->type = addr_type;
-       ha->refcount = 1;
-       ha->synced = false;
-       list_add_tail_rcu(&ha->list, &list->list);
-       list->count++;
-       return 0;
-}
-
-static void ha_rcu_free(struct rcu_head *head)
-{
-       struct netdev_hw_addr *ha;
-
-       ha = container_of(head, struct netdev_hw_addr, rcu_head);
-       kfree(ha);
-}
-
-static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr,
-                        int addr_len, unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-
-       list_for_each_entry(ha, &list->list, list) {
-               if (!memcmp(ha->addr, addr, addr_len) &&
-                   (ha->type == addr_type || !addr_type)) {
-                       if (--ha->refcount)
-                               return 0;
-                       list_del_rcu(&ha->list);
-                       call_rcu(&ha->rcu_head, ha_rcu_free);
-                       list->count--;
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
-                                 struct netdev_hw_addr_list *from_list,
-                                 int addr_len,
-                                 unsigned char addr_type)
-{
-       int err;
-       struct netdev_hw_addr *ha, *ha2;
-       unsigned char type;
-
-       list_for_each_entry(ha, &from_list->list, list) {
-               type = addr_type ? addr_type : ha->type;
-               err = __hw_addr_add(to_list, ha->addr, addr_len, type);
-               if (err)
-                       goto unroll;
-       }
-       return 0;
-
-unroll:
-       list_for_each_entry(ha2, &from_list->list, list) {
-               if (ha2 == ha)
-                       break;
-               type = addr_type ? addr_type : ha2->type;
-               __hw_addr_del(to_list, ha2->addr, addr_len, type);
-       }
-       return err;
-}
-
-static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
-                                  struct netdev_hw_addr_list *from_list,
-                                  int addr_len,
-                                  unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-       unsigned char type;
-
-       list_for_each_entry(ha, &from_list->list, list) {
-               type = addr_type ? addr_type : ha->type;
-               __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
-       }
-}
-
-static int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
-                         struct netdev_hw_addr_list *from_list,
-                         int addr_len)
-{
-       int err = 0;
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
-               if (!ha->synced) {
-                       err = __hw_addr_add(to_list, ha->addr,
-                                           addr_len, ha->type);
-                       if (err)
-                               break;
-                       ha->synced = true;
-                       ha->refcount++;
-               } else if (ha->refcount == 1) {
-                       __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
-                       __hw_addr_del(from_list, ha->addr, addr_len, ha->type);
-               }
-       }
-       return err;
-}
-
-static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
-                            struct netdev_hw_addr_list *from_list,
-                            int addr_len)
-{
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
-               if (ha->synced) {
-                       __hw_addr_del(to_list, ha->addr,
-                                     addr_len, ha->type);
-                       ha->synced = false;
-                       __hw_addr_del(from_list, ha->addr,
-                                     addr_len, ha->type);
-               }
-       }
-}
-
-static void __hw_addr_flush(struct netdev_hw_addr_list *list)
-{
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &list->list, list) {
-               list_del_rcu(&ha->list);
-               call_rcu(&ha->rcu_head, ha_rcu_free);
-       }
-       list->count = 0;
-}
-
-static void __hw_addr_init(struct netdev_hw_addr_list *list)
-{
-       INIT_LIST_HEAD(&list->list);
-       list->count = 0;
-}
-
-/* Device addresses handling functions */
-
-static void dev_addr_flush(struct net_device *dev)
-{
-       /* rtnl_mutex must be held here */
-
-       __hw_addr_flush(&dev->dev_addrs);
-       dev->dev_addr = NULL;
-}
-
-static int dev_addr_init(struct net_device *dev)
-{
-       unsigned char addr[MAX_ADDR_LEN];
-       struct netdev_hw_addr *ha;
-       int err;
-
-       /* rtnl_mutex must be held here */
-
-       __hw_addr_init(&dev->dev_addrs);
-       memset(addr, 0, sizeof(addr));
-       err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
-                           NETDEV_HW_ADDR_T_LAN);
-       if (!err) {
-               /*
-                * Get the first (previously created) address from the list
-                * and set dev_addr pointer to this location.
-                */
-               ha = list_first_entry(&dev->dev_addrs.list,
-                                     struct netdev_hw_addr, list);
-               dev->dev_addr = ha->addr;
-       }
-       return err;
-}
-
-/**
- *     dev_addr_add    - Add a device address
- *     @dev: device
- *     @addr: address to add
- *     @addr_type: address type
- *
- *     Add a device address to the device or increase the reference count if
- *     it already exists.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_add(struct net_device *dev, unsigned char *addr,
-                unsigned char addr_type)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_add);
-
-/**
- *     dev_addr_del    - Release a device address.
- *     @dev: device
- *     @addr: address to delete
- *     @addr_type: address type
- *
- *     Release reference to a device address and remove it from the device
- *     if the reference count drops to zero.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_del(struct net_device *dev, unsigned char *addr,
-                unsigned char addr_type)
-{
-       int err;
-       struct netdev_hw_addr *ha;
-
-       ASSERT_RTNL();
-
-       /*
-        * We can not remove the first address from the list because
-        * dev->dev_addr points to that.
-        */
-       ha = list_first_entry(&dev->dev_addrs.list,
-                             struct netdev_hw_addr, list);
-       if (ha->addr == dev->dev_addr && ha->refcount == 1)
-               return -ENOENT;
-
-       err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
-                           addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_del);
-
-/**
- *     dev_addr_add_multiple   - Add device addresses from another device
- *     @to_dev: device to which addresses will be added
- *     @from_dev: device from which addresses will be added
- *     @addr_type: address type - 0 means type will be used from from_dev
- *
- *     Add device addresses of the one device to another.
- **
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_add_multiple(struct net_device *to_dev,
-                         struct net_device *from_dev,
-                         unsigned char addr_type)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       if (from_dev->addr_len != to_dev->addr_len)
-               return -EINVAL;
-       err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
-                                    to_dev->addr_len, addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_add_multiple);
-
-/**
- *     dev_addr_del_multiple   - Delete device addresses by another device
- *     @to_dev: device where the addresses will be deleted
- *     @from_dev: device by which addresses the addresses will be deleted
- *     @addr_type: address type - 0 means type will used from from_dev
- *
- *     Deletes addresses in to device by the list of addresses in from device.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_del_multiple(struct net_device *to_dev,
-                         struct net_device *from_dev,
-                         unsigned char addr_type)
-{
-       ASSERT_RTNL();
-
-       if (from_dev->addr_len != to_dev->addr_len)
-               return -EINVAL;
-       __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
-                              to_dev->addr_len, addr_type);
-       call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
-       return 0;
-}
-EXPORT_SYMBOL(dev_addr_del_multiple);
-
-/* multicast addresses handling functions */
-
-int __dev_addr_delete(struct dev_addr_list **list, int *count,
-                     void *addr, int alen, int glbl)
-{
-       struct dev_addr_list *da;
-
-       for (; (da = *list) != NULL; list = &da->next) {
-               if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
-                   alen == da->da_addrlen) {
-                       if (glbl) {
-                               int old_glbl = da->da_gusers;
-                               da->da_gusers = 0;
-                               if (old_glbl == 0)
-                                       break;
-                       }
-                       if (--da->da_users)
-                               return 0;
-
-                       *list = da->next;
-                       kfree(da);
-                       (*count)--;
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-int __dev_addr_add(struct dev_addr_list **list, int *count,
-                  void *addr, int alen, int glbl)
-{
-       struct dev_addr_list *da;
-
-       for (da = *list; da != NULL; da = da->next) {
-               if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
-                   da->da_addrlen == alen) {
-                       if (glbl) {
-                               int old_glbl = da->da_gusers;
-                               da->da_gusers = 1;
-                               if (old_glbl)
-                                       return 0;
-                       }
-                       da->da_users++;
-                       return 0;
-               }
-       }
-
-       da = kzalloc(sizeof(*da), GFP_ATOMIC);
-       if (da == NULL)
-               return -ENOMEM;
-       memcpy(da->da_addr, addr, alen);
-       da->da_addrlen = alen;
-       da->da_users = 1;
-       da->da_gusers = glbl ? 1 : 0;
-       da->next = *list;
-       *list = da;
-       (*count)++;
-       return 0;
-}
-
-/**
- *     dev_unicast_delete      - Release secondary unicast address.
- *     @dev: device
- *     @addr: address to delete
- *
- *     Release reference to a secondary unicast address and remove it
- *     from the device if the reference count drops to zero.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_unicast_delete(struct net_device *dev, void *addr)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       netif_addr_lock_bh(dev);
-       err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
-                           NETDEV_HW_ADDR_T_UNICAST);
-       if (!err)
-               __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_delete);
-
-/**
- *     dev_unicast_add         - add a secondary unicast address
- *     @dev: device
- *     @addr: address to add
- *
- *     Add a secondary unicast address to the device or increase
- *     the reference count if it already exists.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_unicast_add(struct net_device *dev, void *addr)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       netif_addr_lock_bh(dev);
-       err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
-                           NETDEV_HW_ADDR_T_UNICAST);
-       if (!err)
-               __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_add);
-
-int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
-                   struct dev_addr_list **from, int *from_count)
-{
-       struct dev_addr_list *da, *next;
-       int err = 0;
-
-       da = *from;
-       while (da != NULL) {
-               next = da->next;
-               if (!da->da_synced) {
-                       err = __dev_addr_add(to, to_count,
-                                            da->da_addr, da->da_addrlen, 0);
-                       if (err < 0)
-                               break;
-                       da->da_synced = 1;
-                       da->da_users++;
-               } else if (da->da_users == 1) {
-                       __dev_addr_delete(to, to_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       __dev_addr_delete(from, from_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
-       return err;
-}
-EXPORT_SYMBOL_GPL(__dev_addr_sync);
-
-void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
-                      struct dev_addr_list **from, int *from_count)
-{
-       struct dev_addr_list *da, *next;
-
-       da = *from;
-       while (da != NULL) {
-               next = da->next;
-               if (da->da_synced) {
-                       __dev_addr_delete(to, to_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       da->da_synced = 0;
-                       __dev_addr_delete(from, from_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
-}
-EXPORT_SYMBOL_GPL(__dev_addr_unsync);
-
-/**
- *     dev_unicast_sync - Synchronize device's unicast list to another device
- *     @to: destination device
- *     @from: source device
- *
- *     Add newly added addresses to the destination device and release
- *     addresses that have no users left. The source device must be
- *     locked by netif_tx_lock_bh.
- *
- *     This function is intended to be called from the dev->set_rx_mode
- *     function of layered software devices.
- */
-int dev_unicast_sync(struct net_device *to, struct net_device *from)
-{
-       int err = 0;
-
-       if (to->addr_len != from->addr_len)
-               return -EINVAL;
-
-       netif_addr_lock_bh(to);
-       err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
-       if (!err)
-               __dev_set_rx_mode(to);
-       netif_addr_unlock_bh(to);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_sync);
-
-/**
- *     dev_unicast_unsync - Remove synchronized addresses from the destination device
- *     @to: destination device
- *     @from: source device
- *
- *     Remove all addresses that were added to the destination device by
- *     dev_unicast_sync(). This function is intended to be called from the
- *     dev->stop function of layered software devices.
- */
-void dev_unicast_unsync(struct net_device *to, struct net_device *from)
-{
-       if (to->addr_len != from->addr_len)
-               return;
-
-       netif_addr_lock_bh(from);
-       netif_addr_lock(to);
-       __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
-       __dev_set_rx_mode(to);
-       netif_addr_unlock(to);
-       netif_addr_unlock_bh(from);
-}
-EXPORT_SYMBOL(dev_unicast_unsync);
-
-static void dev_unicast_flush(struct net_device *dev)
-{
-       netif_addr_lock_bh(dev);
-       __hw_addr_flush(&dev->uc);
-       netif_addr_unlock_bh(dev);
-}
-
-static void dev_unicast_init(struct net_device *dev)
-{
-       __hw_addr_init(&dev->uc);
-}
-
-
-static void __dev_addr_discard(struct dev_addr_list **list)
-{
-       struct dev_addr_list *tmp;
-
-       while (*list != NULL) {
-               tmp = *list;
-               *list = tmp->next;
-               if (tmp->da_users > tmp->da_gusers)
-                       printk("__dev_addr_discard: address leakage! "
-                              "da_users=%d\n", tmp->da_users);
-               kfree(tmp);
-       }
-}
-
-static void dev_addr_discard(struct net_device *dev)
-{
-       netif_addr_lock_bh(dev);
-
-       __dev_addr_discard(&dev->mc_list);
-       netdev_mc_count(dev) = 0;
-
-       netif_addr_unlock_bh(dev);
-}
-
 /**
  *     dev_get_flags - get flags reported to userspace
  *     @dev: device
@@ -4804,8 +4278,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return -EINVAL;
                if (!netif_device_present(dev))
                        return -ENODEV;
-               return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data,
-                                 dev->addr_len, 1);
+               return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
 
        case SIOCDELMULTI:
                if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
@@ -4813,8 +4286,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return -EINVAL;
                if (!netif_device_present(dev))
                        return -ENODEV;
-               return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data,
-                                    dev->addr_len, 1);
+               return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
 
        case SIOCSIFTXQLEN:
                if (ifr->ifr_qlen < 0)
@@ -5121,8 +4593,8 @@ static void rollback_registered_many(struct list_head *head)
                /*
                 *      Flush the unicast and multicast chains
                 */
-               dev_unicast_flush(dev);
-               dev_addr_discard(dev);
+               dev_uc_flush(dev);
+               dev_mc_flush(dev);
 
                if (dev->netdev_ops->ndo_uninit)
                        dev->netdev_ops->ndo_uninit(dev);
@@ -5271,6 +4743,7 @@ int register_netdevice(struct net_device *dev)
 
        dev->iflink = -1;
 
+#ifdef CONFIG_RPS
        if (!dev->num_rx_queues) {
                /*
                 * Allocate a single RX queue if driver never called
@@ -5287,7 +4760,7 @@ int register_netdevice(struct net_device *dev)
                atomic_set(&dev->_rx->count, 1);
                dev->num_rx_queues = 1;
        }
-
+#endif
        /* Init, if this function is available */
        if (dev->netdev_ops->ndo_init) {
                ret = dev->netdev_ops->ndo_init(dev);
@@ -5645,11 +5118,13 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                void (*setup)(struct net_device *), unsigned int queue_count)
 {
        struct netdev_queue *tx;
-       struct netdev_rx_queue *rx;
        struct net_device *dev;
        size_t alloc_size;
        struct net_device *p;
+#ifdef CONFIG_RPS
+       struct netdev_rx_queue *rx;
        int i;
+#endif
 
        BUG_ON(strlen(name) >= sizeof(dev->name));
 
@@ -5675,6 +5150,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                goto free_p;
        }
 
+#ifdef CONFIG_RPS
        rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
        if (!rx) {
                printk(KERN_ERR "alloc_netdev: Unable to allocate "
@@ -5690,6 +5166,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
         */
        for (i = 0; i < queue_count; i++)
                rx[i].first = rx;
+#endif
 
        dev = PTR_ALIGN(p, NETDEV_ALIGN);
        dev->padded = (char *)dev - (char *)p;
@@ -5697,7 +5174,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        if (dev_addr_init(dev))
                goto free_rx;
 
-       dev_unicast_init(dev);
+       dev_mc_init(dev);
+       dev_uc_init(dev);
 
        dev_net_set(dev, &init_net);
 
@@ -5705,8 +5183,10 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        dev->num_tx_queues = queue_count;
        dev->real_num_tx_queues = queue_count;
 
+#ifdef CONFIG_RPS
        dev->_rx = rx;
        dev->num_rx_queues = queue_count;
+#endif
 
        dev->gso_max_size = GSO_MAX_SIZE;
 
@@ -5723,8 +5203,10 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        return dev;
 
 free_rx:
+#ifdef CONFIG_RPS
        kfree(rx);
 free_tx:
+#endif
        kfree(tx);
 free_p:
        kfree(p);
@@ -5927,8 +5409,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        /*
         *      Flush the unicast and multicast chains
         */
-       dev_unicast_flush(dev);
-       dev_addr_discard(dev);
+       dev_uc_flush(dev);
+       dev_mc_flush(dev);
 
        netdev_unregister_kobject(dev);
 
@@ -6228,7 +5710,7 @@ static int __init net_dev_init(void)
                queue->completion_queue = NULL;
                INIT_LIST_HEAD(&queue->poll_list);
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_RPS
                queue->csd.func = trigger_softirq;
                queue->csd.info = queue;
                queue->csd.flags = 0;