ALSA: sound/usb: add preliminary support for UAC2 interrupts
[safe/jmp/linux-2.6] / net / 8021q / vlan.c
index f0e335a..4535122 100644 (file)
 
 /* Global VLAN variables */
 
-int vlan_net_id;
+int vlan_net_id __read_mostly;
 
 /* Our listing of VLAN group(s) */
 static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
 
-static char vlan_fullname[] = "802.1Q VLAN Support";
-static char vlan_version[] = DRV_VERSION;
-static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
-static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
+const char vlan_fullname[] = "802.1Q VLAN Support";
+const char vlan_version[] = DRV_VERSION;
+static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
+static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
-static struct packet_type vlan_packet_type = {
-       .type = __constant_htons(ETH_P_8021Q),
+static struct packet_type vlan_packet_type __read_mostly = {
+       .type = cpu_to_be16(ETH_P_8021Q),
        .func = vlan_skb_recv, /* VLAN receive method */
 };
 
@@ -140,10 +140,11 @@ static void vlan_rcu_free(struct rcu_head *rcu)
        vlan_group_free(container_of(rcu, struct vlan_group, rcu));
 }
 
-void unregister_vlan_dev(struct net_device *dev)
+void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
 {
        struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct net_device *real_dev = vlan->real_dev;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
        struct vlan_group *grp;
        u16 vlan_id = vlan->vlan_id;
 
@@ -156,21 +157,22 @@ void unregister_vlan_dev(struct net_device *dev)
         * HW accelerating devices or SW vlan input packet processing.
         */
        if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
-               real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
+               ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
 
-       vlan_group_set_device(grp, vlan_id, NULL);
        grp->nr_vlans--;
 
-       synchronize_net();
+       vlan_group_set_device(grp, vlan_id, NULL);
+       if (!grp->killall)
+               synchronize_net();
 
-       unregister_netdevice(dev);
+       unregister_netdevice_queue(dev, head);
 
        /* If the group is now empty, kill off the group. */
        if (grp->nr_vlans == 0) {
                vlan_gvrp_uninit_applicant(real_dev);
 
                if (real_dev->features & NETIF_F_HW_VLAN_RX)
-                       real_dev->vlan_rx_register(real_dev, NULL);
+                       ops->ndo_vlan_rx_register(real_dev, NULL);
 
                hlist_del_rcu(&grp->hlist);
 
@@ -182,54 +184,27 @@ void unregister_vlan_dev(struct net_device *dev)
        dev_put(real_dev);
 }
 
-static void vlan_transfer_operstate(const struct net_device *dev,
-                                   struct net_device *vlandev)
-{
-       /* Have to respect userspace enforced dormant state
-        * of real device, also must allow supplicant running
-        * on VLAN device
-        */
-       if (dev->operstate == IF_OPER_DORMANT)
-               netif_dormant_on(vlandev);
-       else
-               netif_dormant_off(vlandev);
-
-       if (netif_carrier_ok(dev)) {
-               if (!netif_carrier_ok(vlandev))
-                       netif_carrier_on(vlandev);
-       } else {
-               if (netif_carrier_ok(vlandev))
-                       netif_carrier_off(vlandev);
-       }
-}
-
 int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
 {
-       char *name = real_dev->name;
+       const char *name = real_dev->name;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
 
        if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
                pr_info("8021q: VLANs not supported on %s\n", name);
                return -EOPNOTSUPP;
        }
 
-       if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
-           !real_dev->vlan_rx_register) {
+       if ((real_dev->features & NETIF_F_HW_VLAN_RX) && !ops->ndo_vlan_rx_register) {
                pr_info("8021q: device %s has buggy VLAN hw accel\n", name);
                return -EOPNOTSUPP;
        }
 
        if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-           (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {
+           (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
                pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
                return -EOPNOTSUPP;
        }
 
-       /* The real device must be up and operating in order to
-        * assosciate a VLAN device with it.
-        */
-       if (!(real_dev->flags & IFF_UP))
-               return -ENETDOWN;
-
        if (__find_vlan_dev(real_dev, vlan_id) != NULL)
                return -EEXIST;
 
@@ -240,6 +215,7 @@ int register_vlan_dev(struct net_device *dev)
 {
        struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct net_device *real_dev = vlan->real_dev;
+       const struct net_device_ops *ops = real_dev->netdev_ops;
        u16 vlan_id = vlan->vlan_id;
        struct vlan_group *grp, *ngrp = NULL;
        int err;
@@ -265,7 +241,7 @@ int register_vlan_dev(struct net_device *dev)
        /* Account for reference in struct vlan_dev_info */
        dev_hold(real_dev);
 
-       vlan_transfer_operstate(real_dev, dev);
+       netif_stacked_transfer_operstate(real_dev, dev);
        linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
 
        /* So, got the sucker initialized, now lets place
@@ -275,9 +251,9 @@ int register_vlan_dev(struct net_device *dev)
        grp->nr_vlans++;
 
        if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
-               real_dev->vlan_rx_register(real_dev, ngrp);
+               ops->ndo_vlan_rx_register(real_dev, ngrp);
        if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
-               real_dev->vlan_rx_add_vid(real_dev, vlan_id);
+               ops->ndo_vlan_rx_add_vid(real_dev, vlan_id);
 
        return 0;
 
@@ -285,8 +261,11 @@ out_uninit_applicant:
        if (ngrp)
                vlan_gvrp_uninit_applicant(real_dev);
 out_free_group:
-       if (ngrp)
-               vlan_group_free(ngrp);
+       if (ngrp) {
+               hlist_del_rcu(&ngrp->hlist);
+               /* Free the group, after all cpu's are done. */
+               call_rcu(&ngrp->rcu, vlan_rcu_free);
+       }
        return err;
 }
 
@@ -334,12 +313,13 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
                snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id);
        }
 
-       new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
-                              vlan_setup);
+       new_dev = alloc_netdev_mq(sizeof(struct vlan_dev_info), name,
+                                 vlan_setup, real_dev->num_tx_queues);
 
        if (new_dev == NULL)
                return -ENOBUFS;
 
+       new_dev->real_num_tx_queues = real_dev->real_num_tx_queues;
        dev_net_set(new_dev, net);
        /* need 4 bytes for extra VLAN header info,
         * hope the underlying device can handle it.
@@ -376,13 +356,13 @@ static void vlan_sync_address(struct net_device *dev,
         * the new address */
        if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(dev, vlandev->dev_addr);
 
        /* vlan address was equal to the old address and is different from
         * the new address */
        if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN);
+               dev_unicast_add(dev, vlandev->dev_addr);
 
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
@@ -395,6 +375,9 @@ static void vlan_transfer_features(struct net_device *dev,
        vlandev->features &= ~dev->vlan_features;
        vlandev->features |= dev->features & dev->vlan_features;
        vlandev->gso_max_size = dev->gso_max_size;
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+       vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
+#endif
 
        if (old_features != vlandev->features)
                netdev_features_change(vlandev);
@@ -427,6 +410,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        struct vlan_group *grp;
        int i, flgs;
        struct net_device *vlandev;
+       struct vlan_dev_info *vlan;
+       LIST_HEAD(list);
 
        if (is_vlan_dev(dev))
                __vlan_device_event(dev, event);
@@ -447,7 +432,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (!vlandev)
                                continue;
 
-                       vlan_transfer_operstate(dev, vlandev);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
@@ -466,6 +451,19 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                }
                break;
 
+       case NETDEV_CHANGEMTU:
+               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+                       vlandev = vlan_group_get_device(grp, i);
+                       if (!vlandev)
+                               continue;
+
+                       if (vlandev->mtu <= dev->mtu)
+                               continue;
+
+                       dev_set_mtu(vlandev, dev->mtu);
+               }
+               break;
+
        case NETDEV_FEAT_CHANGE:
                /* Propagate device features to underlying device */
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
@@ -489,7 +487,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (!(flgs & IFF_UP))
                                continue;
 
-                       dev_change_flags(vlandev, flgs & ~IFF_UP);
+                       vlan = vlan_dev_info(vlandev);
+                       if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
+                               dev_change_flags(vlandev, flgs & ~IFF_UP);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
@@ -504,12 +505,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (flgs & IFF_UP)
                                continue;
 
-                       dev_change_flags(vlandev, flgs | IFF_UP);
+                       vlan = vlan_dev_info(vlandev);
+                       if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
+                               dev_change_flags(vlandev, flgs | IFF_UP);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
        case NETDEV_UNREGISTER:
                /* Delete all VLANs for this dev. */
+               grp->killall = 1;
+
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
                        vlandev = vlan_group_get_device(grp, i);
                        if (!vlandev)
@@ -520,8 +526,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (grp->nr_vlans == 1)
                                i = VLAN_GROUP_ARRAY_LEN;
 
-                       unregister_vlan_dev(vlandev);
+                       unregister_vlan_dev(vlandev, &list);
                }
+               unregister_netdevice_many(&list);
                break;
        }
 
@@ -627,7 +634,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg)
                err = -EPERM;
                if (!capable(CAP_NET_ADMIN))
                        break;
-               unregister_vlan_dev(dev);
+               unregister_vlan_dev(dev, NULL);
                err = 0;
                break;
 
@@ -656,49 +663,28 @@ out:
        return err;
 }
 
-static int vlan_init_net(struct net *net)
+static int __net_init vlan_init_net(struct net *net)
 {
+       struct vlan_net *vn = net_generic(net, vlan_net_id);
        int err;
-       struct vlan_net *vn;
-
-       err = -ENOMEM;
-       vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL);
-       if (vn == NULL)
-               goto err_alloc;
-
-       err = net_assign_generic(net, vlan_net_id, vn);
-       if (err < 0)
-               goto err_assign;
 
        vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
 
        err = vlan_proc_init(net);
-       if (err < 0)
-               goto err_proc;
 
-       return 0;
-
-err_proc:
-       /* nothing */
-err_assign:
-       kfree(vn);
-err_alloc:
        return err;
 }
 
-static void vlan_exit_net(struct net *net)
+static void __net_exit vlan_exit_net(struct net *net)
 {
-       struct vlan_net *vn;
-
-       vn = net_generic(net, vlan_net_id);
-       rtnl_kill_links(net, &vlan_link_ops);
        vlan_proc_cleanup(net);
-       kfree(vn);
 }
 
 static struct pernet_operations vlan_net_ops = {
        .init = vlan_init_net,
        .exit = vlan_exit_net,
+       .id   = &vlan_net_id,
+       .size = sizeof(struct vlan_net),
 };
 
 static int __init vlan_proto_init(void)
@@ -708,7 +694,7 @@ static int __init vlan_proto_init(void)
        pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright);
        pr_info("All bugs added by %s\n", vlan_buggyright);
 
-       err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops);
+       err = register_pernet_subsys(&vlan_net_ops);
        if (err < 0)
                goto err0;
 
@@ -733,7 +719,7 @@ err4:
 err3:
        unregister_netdevice_notifier(&vlan_notifier_block);
 err2:
-       unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops);
+       unregister_pernet_subsys(&vlan_net_ops);
 err0:
        return err;
 }
@@ -753,8 +739,8 @@ static void __exit vlan_cleanup_module(void)
        for (i = 0; i < VLAN_GRP_HASH_SIZE; i++)
                BUG_ON(!hlist_empty(&vlan_group_hash[i]));
 
-       unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops);
-       synchronize_net();
+       unregister_pernet_subsys(&vlan_net_ops);
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
        vlan_gvrp_uninit();
 }