net: Add init_dummy_netdev() and fix EMAC driver using it
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 15 Jan 2009 05:05:05 +0000 (21:05 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Jan 2009 05:05:05 +0000 (21:05 -0800)
This adds an init_dummy_netdev() function that gets a network device
structure (allocation and lifetime entirely under caller's control) and
initialize the minimum amount of fields so it can be used to schedule
NAPI polls without registering a full blown interface. This is to be
used by drivers that need to tie several hardware interfaces to a single
NAPI poll scheduler due to HW limitations.

It also updates the ibm_newemac driver to use that, this fixing the
oops on 2.6.29 due to passing NULL as "dev" to netif_napi_add()

Symbol is exported GPL only a I don't think we want binary drivers doing
that sort of acrobatics (if we want them at all).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Tested-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ibm_newemac/mal.c
drivers/net/ibm_newemac/mal.h
include/linux/netdevice.h
net/core/dev.c

index ecf9798..2a2fc17 100644 (file)
@@ -613,7 +613,9 @@ static int __devinit mal_probe(struct of_device *ofdev,
        INIT_LIST_HEAD(&mal->list);
        spin_lock_init(&mal->lock);
 
-       netif_napi_add(NULL, &mal->napi, mal_poll,
+       init_dummy_netdev(&mal->dummy_dev);
+
+       netif_napi_add(&mal->dummy_dev, &mal->napi, mal_poll,
                       CONFIG_IBM_NEW_EMAC_POLL_WEIGHT);
 
        /* Load power-on reset defaults */
index 2f0a873..9ededfb 100644 (file)
@@ -214,6 +214,8 @@ struct mal_instance {
        int                     index;
        spinlock_t              lock;
 
+       struct net_device       dummy_dev;
+
        unsigned int features;
 };
 
index 4647604..ec54785 100644 (file)
@@ -795,6 +795,7 @@ struct net_device
               NETREG_UNREGISTERING,    /* called unregister_netdevice */
               NETREG_UNREGISTERED,     /* completed unregister todo */
               NETREG_RELEASED,         /* called free_netdev */
+              NETREG_DUMMY,            /* dummy device for NAPI poll */
        } reg_state;
 
        /* Called from unregister, can be used to call free_netdev */
@@ -1077,6 +1078,8 @@ extern void               free_netdev(struct net_device *dev);
 extern void            synchronize_net(void);
 extern int             register_netdevice_notifier(struct notifier_block *nb);
 extern int             unregister_netdevice_notifier(struct notifier_block *nb);
+extern int             init_dummy_netdev(struct net_device *dev);
+
 extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
 extern struct net_device       *dev_get_by_index(struct net *net, int ifindex);
 extern struct net_device       *__dev_get_by_index(struct net *net, int ifindex);
index 60377b6..8d67597 100644 (file)
@@ -4431,6 +4431,45 @@ err_uninit:
 }
 
 /**
+ *     init_dummy_netdev       - init a dummy network device for NAPI
+ *     @dev: device to init
+ *
+ *     This takes a network device structure and initialize the minimum
+ *     amount of fields so it can be used to schedule NAPI polls without
+ *     registering a full blown interface. This is to be used by drivers
+ *     that need to tie several hardware interfaces to a single NAPI
+ *     poll scheduler due to HW limitations.
+ */
+int init_dummy_netdev(struct net_device *dev)
+{
+       /* Clear everything. Note we don't initialize spinlocks
+        * are they aren't supposed to be taken by any of the
+        * NAPI code and this dummy netdev is supposed to be
+        * only ever used for NAPI polls
+        */
+       memset(dev, 0, sizeof(struct net_device));
+
+       /* make sure we BUG if trying to hit standard
+        * register/unregister code path
+        */
+       dev->reg_state = NETREG_DUMMY;
+
+       /* initialize the ref count */
+       atomic_set(&dev->refcnt, 1);
+
+       /* NAPI wants this */
+       INIT_LIST_HEAD(&dev->napi_list);
+
+       /* a dummy interface is started by default */
+       set_bit(__LINK_STATE_PRESENT, &dev->state);
+       set_bit(__LINK_STATE_START, &dev->state);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(init_dummy_netdev);
+
+
+/**
  *     register_netdev - register a network device
  *     @dev: device to register
  *