Skip site navigation (1)Skip section navigation (2)
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>