Date: Tue, 1 Jun 1999 08:32:04 +0100 (BST) From: Doug Rabson <dfr@nlsystems.com> To: Bill Paul <wpaul@skynet.ctr.columbia.edu> Cc: hackers@freebsd.org, dfr@freebsd.org Subject: Re: Using newbus to hang a custom bus off a device Message-ID: <Pine.BSF.4.05.9906010819070.411-100000@herring.nlsystems.com> In-Reply-To: <199905312309.TAA04790@skynet.ctr.columbia.edu>
next in thread | previous in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.05.9906010819070.411-100000>
