How to register non-modular net drivers?

From: Andrew Morton (andrewm@uow.edu.au)
Date: Thu Mar 02 2000 - 06:48:10 EST


[ kernel 2.3.48 ]

How should a non-modularised network device driver register itself? If
it's a module then its init_module() function can call register_netdev()
but having done a pretty extensive walkthrough I can't see how a
linked-in driver is supposed to do it. I've appended my analysis of
the initialisation sequence here. I'd be interested if it has a hole.
(Is the network layer _really_ initialised via the fs partition
checking??).

I wonder if there should be a walk down the net device list right at the
end of net_dev_init().

Also, is register_netdev() buggy? It calls rtnl_lock() but has two
error return paths which fail to call rtnl_unlock().

Thanks.

Bootup walkthrough from the netdevice POV follows. Might be useful for
someone.

Before anything happens: static storage
---------------------------------------

There is a global list of struct net_device's. The head is pointed to
by the global variable drivers/net/Space.c:dev_base.

dev_base is initialised at load time to point to the head of a linked
list of struct net_devices which describe ethernet devices. These all
have the name "eth%d". They are defined in Space.c:eth[0-7]_dev.
Their init() methods are all initialised to point to
Space.c:ethif_probe().

There is a magic flag in net/core/dev.c:dev_boot_phase which is
initialised to 1. Remember this intteger for later.

When the kernel runs
--------------------

arch/i386/kernel/head.S calls start_kernel()

init/main.c:start_kernel() initialises lots of low-level things then
starts a kernel thread based on the function init/main.c:init().

init/main.c:init() calls init/main.c:do_basic_setup().

do_basic_setup initialises lots of stuff. Partway through it calls
do_initcalls() which walks through all the kernel functions which are
declared as being __initcall's. One of these is
fs/partitions/check.c:partition_setup().

fs/partitions/check.c:partition_setup() is an __initcall function

fs/partitions/check.c:partition_setup() calls device_init()

drivers/block/genhd.c:device_init() calls net_dev_init()

net/core/dev.c:net_dev_init() initialises a bunch of stuff then walks
the net_device_list which is pointed to by dev_base (see previous
section).

For each device in the dev_base list net_dev_init() converts the
device's name from "eth%d" to "eth0", etc. with
dev.c:dev_alloc_name(). It also calls the device's init() method. At
this time, each device's init() method points at Space.c:ethif_probe().

  Space.c:ethif_probe() walks all the compiled-in device drivers,
  calling their probe() routines. If the probe succeeds it returns
  zero and the device's init() method is considered to have succeeded..

    The device driver's probe() routine cannot successfully
    register itself via register_netdev() because the netdevice layer
    is not yet fully initialised and ready for it (dev_boot_phase ==
    1). If the driver attempts to register itself via
    drivers/net/net_init.c:register_netdev() (which calls
    net/core/dev.c:register_netdevice()), register_netdevice() will
    print "early initialization of device %s is deferred" and will
    queue the device on the dev_base queue if it's not already there.
    The initial eight devices _will_ already be there.

Back to net_dev_init(): If the init() method succeeds, net_dev_init()
marks the device as available. If it fails, it is marked as dead and
unlinked from the dev_base list.

At the end of processing, net_dev_init() sets dev_boot_phase to zero
and calls drivers/net/setup.c:net_device_init() - very similar name!

  net_device_init() calls a bunch of probing routines, including
  pci_probe(), which does more device probing. It also causes
  registration of things like the dummy and loopback devices (via
  register_netdev()).

So when we hit the end of net/core/dev.c:net_dev_init() we still
haven't successfully called register_netdevice() for this device. I
tried outting this in right at the end of net_dev_init() but it blew up
mysteriously.

We can't call register_netdev() from within the device driver's init()
method because register_netdev() calls the init() method!

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Mar 07 2000 - 21:00:12 EST