Subject: Re: pci probe
To: M. Warner Losh <imp@bsdimp.com>
From: Nathan J. Williams <nathanw@wasabisystems.com>
List: tech-kern
Date: 08/15/2003 15:36:12
"M. Warner Losh" <imp@bsdimp.com> writes:

> The problem, for those that are new to the discussion, is that reading
> anything but the header type for devices that do not exist is ill
> defined.  For devices that are really there, one can rely on certain
> registers being implemented for all devices.  However, the standard is
> less clear on what happens when on access registers on devices that
> aren't there.

Not at all. It's the Vendor ID that is the place to start.

Section 6.1: "System software may need to scan the PCI bus to
determine what devices are actually present. To do this, the
configuration software must read the Vendor ID in each possible PCI
"slot". The host bus to PCI bridge must unambigously report attempts
to read the Vendor ID of non-existent devices. Since 0FFFFh is an
invalid Vendor ID, it is adequate for the host bus to PCI bridge to
return a value of all 1's on read accesses to Configuration Space
registers of non-existent devices. (Note that these accesses will be
terminated with a Master-Abort).
...
Read accesses to reserved or unimplemented registers must be
completed normally and a data value of 0 returned".

So it should be adequate to check for a valid Vendor ID, and then read
all of configuration space.

> The problem with the geode has to do with looking at the higher order
> functions without properly checking.  The HDRTYPE register has 7 bits
> for type, as well as one bit for 'this is a multi-function device'.
> Prior to the fixes I put into FreeBSD, we'd check all the functions of
> a device whenever this bit was 1, even for bogus header types.
> However, the standard seems to say (I thought I'd found it before, but
> can't find it now) that only the 7-bits that define the header type
> are valid for all header types.  The standard only defines header type
> 0, 1, and 2.  If the header type isn't one of those, you can't count
> on the high bit meaning multifunction.  This is especially true for
> the 0x7f header type.  Since non-existant registers either read as all
> 'f' or cause an exception to happen, a bare minimum of filtering would
> be to completely ignore the slot if HDRTYPE is 0xff.
> 
> Maybe I missed some verbage in the standard that covers what
> guarnatees future version of the standard will make about header types
> other than 0, 1 and 2.  If so, I'd be very grateful for a gentle
> pointer.

The multi-function bit is valid independent of the value encoded in
the lower bits, as described in section 6.2.1, "Device
Identification", subsection "Header Type":

"This byte identifies the layout of the second part of the predefined
header (beginning at byte 10h in Configuration Space) and also whether
or not the device contains multiple functions. Bit 7 in this register
is used to identify a multi-function device. If the bit is 0, then the
device is single-function. If the bit is 0, then the device has
multiple functions. Bits 6 through 0 identify the layout of the second
part of the predefined header. The encoding 00h specifies the layout
shown in figure 6-1. The encoding 01h is defined for PCI-to-PCI
bridges and is defined in the document _PCI to PCI Bridge Architecture
Specification_. The encoding 02h is defined for a CardBus bridge and
is documented in the _PC Card Standard_. All other encodings are
reserved."

I'm willing to believe that FreeBSD's PCI code doesn't happen to
generate the sequence that breaks the Geode's PCI hardware, but it
really sounds like the hardware is buggy and FreeBSD is lucky.

It sounds like checking the header type register *before* validating
the existence of a device with the Vendor ID register is problematic,
though, and leads to seeing the FFh value for the header type that you
describe.

        - Nathan