Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Aug 2002 17:50:32 -0700
From:      Terry Lambert <tlambert2@mindspring.com>
To:        hackers@freebsd.org
Subject:   Re: How the kernel add the devices when the kernel start
Message-ID:  <3D5857D8.8CB8D051@mindspring.com>

next in thread | raw e-mail | index | archive | help
Sent with permission; the original to which this was a response
was supposed to go to -hackers.

(Captured for the next person with the same questions).

ouyang kai wrote:
>
>    Part 1.1.1    Type: Plain Text (text/plain)
>              Encoding: quoted-printable
>
>                                Name: kernel_init_problem3.txt
>    kernel_init_problem3.txt    Type: Plain Text (text/plain)
>                            Encoding: quoted-printable

| If I have two 'fxp' devices in my box, then, the system should have
| the same vars, Why don't they conflict ? How do they register?

PCI devices are enumerated by the PCI bus enumerator.  The
enumerator goes through the IDs of all the cards that exist,
and calls the driver probe routine if it matches the Vendor
and product ID reported on the PCI bus.  The enumerator lives
in /usr/src/sys/pci/pci.c.

Each matching instance has a device instance structure allocated,
which is unique to the device.  PCI also guarantees that two
identical devices get slot-based memory ranges and other resources
assigned, so they are not conflicting (cards are all in different
slots, by definition).

Thus the per device instance structure keeps them seperate, and
the bus ensures there are no conflicts.

For PCI cards that map memory to well known locations, there can
be conflicts (this is especially true of vide cards).  Most do
not map at a fixed location, but instead map wherever the POST
initialization of the BIOS tells them is available.

So:
1)      Machine powers on
2)      Machine POSTs (Power On Self Tests)
3)      BIOS POST code assigns card specific resources
4)      Kernel enumerates PCI devices
5)      Driver matches vendor/device ID
6)      Per device instance structure is allocated
7)      Per device instance structure is filled out from
        values set up by BIOS POST
8)      Card is attached and interrupt handler is registered
        with address of per device instance structure
9)      Interrupts come in
10)     Interrupt sharing code uses PCI command to ask which
        card(s) cause the interrupt
11)     Device driver entry point is called for card that
        cause the interrupt with address of per device
        context structure
12)     Per device context structure address is converted from
        void pointer to device specific structure pointer

        static void
        fxp_intr(void *xsc)
        {
                struct fxp_softc *sc = xsc;

13)     And interrupt processing proceeds to completion


| PS: I can get the device name from the link-level sockaddr(struct
| sockaddr_dl's member sdl_data:"fxp0" and "fxp1"), right?

Yes, but there's really no reason to want it.  It's only for
displaying to the user.


| >This *eventually* calls the probe, and, if it finds a device,
| >the attach, so yes, many function calls deep.   
| I think I did not ask the question clearly.
| Now, I know in the mi_startup(), the kernel complete the function of
|'module_register_init'.
| But, When and How the kernel 'eventually' calls the probe and attach?

The bus enumerator enumerates the PCI devices.  The SYSINIT() code
(via DRIVER_MODULE) only registers the device hierarchy data
structure.

The actual top level driver in the hierarchy does the work; on
i386, this is the "nexus" driver.  See: /usr/src/sys/i386/i386/nexus.c.

This is done in configure():

        /* nexus0 is the top of the i386 device tree */
        device_add_child(root_bus, "nexus", 0);

        /* initialize new bus architecture */
        root_bus_configure();

located in: /usr/src/sys/i386/i386/autoconf.c.  The declaration
for this call is:

SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);

If you look in /usr/src/sys/sys/kernel.h, you see:

[...]
        SI_SUB_CREATE_INIT      = 0x2500000,    /* create the init process */
        SI_SUB_DRIVERS          = 0x3100000,    /* Let Drivers initialize */
        SI_SUB_CONFIGURE        = 0x3800000,    /* Configure devices */
        SI_SUB_VFS              = 0x4000000,    /* virtual file system*/
[...]

...in other words, all the drivers get registered into the device
hierarchy under the root ("nexus") in the SI_SUB_DRIVERS phase,
and then they are initialized in the SI_SUB_CONFIGURE phase.


Note that when you load a device driver as a module, the device
hierarchy is already present.  Therefore the device registers
into an existing hierarchy.  The probe is called (in the PCI case)
only on "unclaimed" devices.  For ISA and other devices, there is
bus-specific behaviour.  In the ISA case, it can actively probe
(most ISA devices require active probing), so it can destabilize
your system (by poking things that aren't ISA cards, and which do
not like it when they are poked); non-legacy drivers "just work".

-- Terry

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3D5857D8.8CB8D051>