From owner-freebsd-hackers Mon Aug 12 17:51:42 2002 Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A5A9E37B400 for ; Mon, 12 Aug 2002 17:51:37 -0700 (PDT) Received: from hawk.mail.pas.earthlink.net (hawk.mail.pas.earthlink.net [207.217.120.22]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4172743E77 for ; Mon, 12 Aug 2002 17:51:37 -0700 (PDT) (envelope-from tlambert2@mindspring.com) Received: from pool0130.cvx21-bradley.dialup.earthlink.net ([209.179.192.130] helo=mindspring.com) by hawk.mail.pas.earthlink.net with esmtp (Exim 3.33 #1) id 17ePuE-0004vf-00 for hackers@freebsd.org; Mon, 12 Aug 2002 17:51:30 -0700 Message-ID: <3D5857D8.8CB8D051@mindspring.com> Date: Mon, 12 Aug 2002 17:50:32 -0700 From: Terry Lambert X-Mailer: Mozilla 4.79 [en] (Win98; U) X-Accept-Language: en MIME-Version: 1.0 To: hackers@freebsd.org Subject: Re: How the kernel add the devices when the kernel start Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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