From owner-freebsd-hackers Tue Jun 1 0:32:26 1999 Delivered-To: freebsd-hackers@freebsd.org Received: from herring.nlsystems.com (nlsys.demon.co.uk [158.152.125.33]) by hub.freebsd.org (Postfix) with ESMTP id 77A6815277; Tue, 1 Jun 1999 00:32:17 -0700 (PDT) (envelope-from dfr@nlsystems.com) Received: from localhost (dfr@localhost) by herring.nlsystems.com (8.9.3/8.8.8) with ESMTP id IAA23360; Tue, 1 Jun 1999 08:32:04 +0100 (BST) (envelope-from dfr@nlsystems.com) Date: Tue, 1 Jun 1999 08:32:04 +0100 (BST) From: Doug Rabson To: Bill Paul Cc: hackers@freebsd.org, dfr@freebsd.org Subject: Re: Using newbus to hang a custom bus off a device In-Reply-To: <199905312309.TAA04790@skynet.ctr.columbia.edu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG On Mon, 31 May 1999, Bill Paul wrote: > Well, after a bit of head scratching, I finally think I've gotten the > hang of the new bus architecture stuff (in general that is, not just > the new ISA and PCI stuff). I'm trying to create an miibus framework so > that I can have an miibus attached to those PCI ethernet drivers which > support MII-based transceivers, to which I can attach transceiver > drivers. I'm still a little confused by something though, probably > because I'm trying to do the development on 3.2-RELEASE (I don't have > a machine that I can clobber with -current just at the moment). > > Basically what I have is this: > > - An miibus_if.m file which describes the methods implemented by miibus > drivers. There are three methodes: a readreg method, which lets you > read a given register from a given PHY on the MII bus, a writereg > method, which lets you write a value to a given register on a given > PHY on the MII bus, and a status change method, which lets you tell > the driver which implements the miibus support that the status of a > PHY has changed and that the controller needs to update some state to > match it. (This is mainly to deal with controllers that have speed > and duplex settings that operate independently of the PHY: if the > PHY negotiates 100Mbps full duplex, then the controller chip to which > the PHY is attached may also need to be explicitly programmed for > 100Mbps full duplex to match the PHY.) > > - A stub mii PHY driver, which has its own probe and attach functions, > and which uses the following DRIVER_MODULE() macro: > > DRIVER_MODULE(miigeneric, miibus, mii_driver, mii_devclass, 0, 0); > > - Some stub code to be inserted into a NIC driver which implements > the miibus support. The code provides a probe routine (which checks > for MII support on the controller) but uses bus_generic_attach for > its attach routine. This, I believe, allows all of the mii driver > probes to be invoked after the bus is attached. The NIC driver also > uses a DRIVER_MODULE() macro like this: > > DRIVER_MODULE(miibus, ax, miibus_driver, miibus_devclass, 0, 0); > > (Here, "ax" represents the if_ax driver, which is what I used for > testing since the ASIX chipset uses an MII-based transeiver.) Sounds good so far. > > So, here's how I understand this: the MII driver is declared to be > in the 'miibus' devclass. And the if_ax driver declares an miibus device > which is attached to the ax devclass. Since this is 3.2-RELEASE, > I manually attach the ax device to the root_bus devclass using > device_add_child(). Then I do the following: > > miibus = device_add_child(sc->ax_device, "miibus", -1, NULL); > if (device_probe_and_attach(miibus)) { > device_delete_child(sc->ax_device, miibus); > return(ENODEV); > } > > Now, this is where I had to do some looking around: the fact that you > need to use device_add_child() is not clearly spelled out in the man > pages. Basically, the fact that the DRIVER_MODULE() modules declare > the driver hierarchy does not mean than device instances are actually > created. The DRIVER_MODULE() macros basically tell the system to expect > that an miibus could be created as a child of an ax device instance, and > that an miigeneric device could be created as a child of an miibus instance, > but you actually need to use device_add_child() to call the device > instance into existence. Thats right. I needed to make a clear distinction between the device instance and the driver since there can be many (or no) devices using a single driver (e.g. sio[0-3]). It is normally the responsibility of a parent device to decide if it has children and add them using device_add_child() if appropriate. For -current, I have added a mechanism so that drivers can be asked to search for and add devices. I use this mechanism to populate the isa bus through the isahint (and soon the pnp) driver. If a parent device is using this mechanism to add its children, it must call bus_generic_probe() from its probe method which will call the DEVICE_IDENTIFY method (a static method, i.e. not specific to a device instance) of each driver in the class. These drivers may call BUS_ADD_CHILD to add devices to the parent device if any are found. The parent device must implement BUS_ADD_CHILD, mainly to allow it to allocate and initialise the ivars for the new device. I guess I could provide a bus_generic_add_child() which used a NULL ivars. > > Similarly, in the miibus probe routine, you have to check for PHYs > on the miibus and call device_add_child() to create a device node > for each PHY on the bus. (I use device_add_child(dev, NULL, -1, NULL) > for this, because you don't know ahead of time exactly which driver > will be attached.) Then, bus_generic_attach() will call the probe > routines of all the PHY drivers that are declared to be in the miibus > devclass, and whichever driver supports the discovered PHY claims the > device instance. > > Now, given all that, here are the questions that I have: > > - In -current, assuming that a PCI NIC driver has been properly > newbus-ified, is it still necessary for the driver to manually > call device_add_child() to create the miibus device instance and then > call device_probe_and_attach() to get the PHY drivers into the > picture? I think the answer is yes, because I don't see any other > way for it to work. Yes, unless you use DEVICE_IDENTIFY. > > - Suppose that I want to probe for PHYs on the miibus in a particular > order? All MII-compliant PHYs implement a standard set of registers, > so in theory it's possible to write just a single generic PHY driver > which will handle all PHYs. However, sometimes a given PHY will > require some special handling. So, what I want to do is have expliclt > PHY drivers to handle certain PHYs and have a catch-all generic driver > to handle any other device that isn't handled by one of the explicit > PHY drivers. This implies that the probe routine of the generic device > will be invoked last. If the generic device probe is invoked first, > then all PHYs will get the generic driver attached, which is not what > I want. Is there some way to weight the drivers such that the specific > ones will have a higher priority than the generic one, thereby forcing > the specific probes to be called first? I don't have a mechanism for changing the order of the probes but (in current only) a probe method can return a priority value. The highest priority returned from any probe 'wins'. Since the probe methods can return errno values, success is denoted by returning a value <= 0. The driver which returns the highest such value is chosen with a special case that the first driver which returns zero is selected immediately. You could arrange the mii drivers so that the generic driver returns -1 and the specific drivers return 0 and this should select the right driver. To make this work, you must avoid side effects in the probe method (memory allocation, resource allocation etc) since a successful probe doesn't guarantee that attach will be called (unless the probe returned zero). -- Doug Rabson Mail: dfr@nlsystems.com Nonlinear Systems Ltd. Phone: +44 181 442 9037 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message