Page 1 of 1

Quickly scanning PCI config space

Posted: Thu Jan 28, 2010 9:09 pm
by NickJohnson
I'm trying to write a (originally thought to be) simple function that will run through all of the functions of all of the slots of all of the buses in the PCI configuration space and locate all instances of a class and optionally a subclass, obviously for device detection purposes. Originally, I wrote it to scan through all three dimensions assuming they were contiguous, i.e. if bus 1 does not exist, bus 2 does not exist; same for slots and functions. Of course, I was completely wrong, which I realized after inspecting lspci on my laptop. I know that if function 0 does not exist for a slot, no other functions do, but are there any more rules like that that will save me from looping though (and doing at least two I/O cycles for) all 65536 possible combinations of bus, slot, and function fields? Is there any way to quickly figure out the topology of the buses or slots without actually checking each one?

Thanks!

Re: Quickly scanning PCI config space

Posted: Thu Jan 28, 2010 10:07 pm
by Brendan
Hi,

NickJohnson wrote:I'm trying to write a (originally thought to be) simple function that will run through all of the functions of all of the slots of all of the buses in the PCI configuration space and locate all instances of a class and optionally a subclass, obviously for device detection purposes. Originally, I wrote it to scan through all three dimensions assuming they were contiguous, i.e. if bus 1 does not exist, bus 2 does not exist; same for slots and functions. Of course, I was completely wrong, which I realized after inspecting lspci on my laptop. I know that if function 0 does not exist for a slot, no other functions do, but are there any more rules like that that will save me from looping though (and doing at least two I/O cycles for) all 65536 possible combinations of bus, slot, and function fields? Is there any way to quickly figure out the topology of the buses or slots without actually checking each one?
If bit 7 in the "header type" field (for function 0) is clear then the device is a single-function device (and you don't need to care about functions 1 to 7 as they don't exist). If it's a multi-function device then the function numbers should be sequential (when you've found the first invalid function you can assume that higher number functions aren't present).

For PCI to PCI bridges (anything with 1 in the "header type"), the format of PCI configuration space is different, and there's a "primary bus number" field (which you already knew to access the PCI to PCI bridge), a "secondary bus number" field and a "suboordinate bus number" field. The "secondary bus number" is the number of the bus that is directly behind the bridge. The "suboordinate bus number" is number of the highest bus that is (directly or indirectly) behind the bridge.

You can use this information to avoid checking a lot of things that aren't present anyway (e.g. all "not present" buses and most "not present" functions). For example:

Code: Select all

void main(void) {
  scanDevices(0);
}

scanDevices(int bus) {
  for(device = 0; device < 32; device++) {
    if(vendorID(bus, device, 0) is valid) {
      checkDevice(bus, device, 0);
      if(headerType(bus, 0, 0) has_bit7_set) {
        for(function = 1; function < 8; function++) {
          if(vendorID(bus, device, function) is valid) checkDevice(bus, device, function);
          else break;
        }
      }
    }
  }
}

checkDevice(int bus, int device, int function) {
  if(headerType(bus, device, function) says_device_is_PCI_to_PCI_bridge) {
    printf("Found bridge: <details>\n");
    secondaryBus = get_secondary_bus((bus, device, function);
    scanDevices(secondaryBus);
  } else {
    printf("Found device: <details>\n");
  }
}

Cheers,

Brendan

Re: Quickly scanning PCI config space

Posted: Thu Jan 28, 2010 10:41 pm
by bewing
As I understand it, all motherboards that support PCI are supposed to support BIOS function INT1A AX=B101 -- IIRC CL is the maximum PCI bus number configured on the machine, so you can discount all of them above that.

Note however that bochs & qemu do not support this BIOS function. At least the last time I tested it.

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 12:26 am
by Brendan
Hi,
bewing wrote:As I understand it, all motherboards that support PCI are supposed to support BIOS function INT1A AX=B101 -- IIRC CL is the maximum PCI bus number configured on the machine, so you can discount all of them above that.
It's probably good to do it yourself (e.g. using I/O ports directly), so that it's easier for your OS to support other types of firmware (e.g. EFI/UEFI, coreboot, OpenFirmware) later on; and so that your OS is immune to BIOS/firmware bugs.

Also note that for hot-plug PCI you might (eventually) need code to scan PCI buses after boot (when the PC BIOS may be unusable); and for embedded systems you may need to configure PCI yourself (rather than just assuming that the firmware pre-configured everything). In both of these cases your code would need to be able to (for e.g.) set the "primary bus", "secondary bus" and "subordinate bus" numbers in bridges (rather than reading them), and do some other things (like setting I/O ranges and memory ranges in bridges that the bridge forwards to the secondary bus, configuring BARs in devices, etc).


Cheers,

Brendan

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 9:21 am
by XanClic
bewing wrote:Note however that bochs & qemu do not support this BIOS function. At least the last time I tested it.
At least qemu does. My entry for the fourth 512 byte contest relies on exactly that (see http://forum.osdev.org/viewtopic.php?f=2&t=21042).

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 9:40 am
by Kevin
qemu was using bochsbios until (including) 0.11. It switched to SeaBIOS though for 0.12 (released in December), so that's probably what makes the difference.

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 10:39 am
by XanClic
As for me, I use 0.11.0. :wink:

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 11:25 am
by Kevin
Hm... But it was a nice theory at least. ;)

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 1:16 pm
by NickJohnson
Thanks for the suggestions.

Using the BIOS function is out of the question for me anyway, because this scanning is being done from a userspace driver.

@Brendan: so, you're saying I should recursively run through each bus by following the PCI-PCI bridges? That seems like a good idea, provided I interpreted it right of course.

Re: Quickly scanning PCI config space

Posted: Fri Jan 29, 2010 11:58 pm
by Brendan
Hi,
NickJohnson wrote:@Brendan: so, you're saying I should recursively run through each bus by following the PCI-PCI bridges? That seems like a good idea, provided I interpreted it right of course.
Yes.

You should be able to find & download a document called "PCI-to-PCI Bridge Architecture Specification Revision 1.1" (a PDF file), which includes a description of the format used for the PCI configuration space header used by PCI to PCI bridges. There's also some other interesting stuff in this document..


Cheers,

Brendan