Hi,
os64dev wrote:Currently i am trying to enumerate all the pci devices with the following code. It is kind a raw i guess because it scans all the posibble combinations. pci::read_pci returns a pointer to the configuration header of a device or null if there is no device at that location.
For each PCI bridge there's a "primary bus" and a "secondary bus" where the secondary bus is the bus on the other side of the bridge. Because PCI is a hierarchy of buses, you can start at the top (which is always "bus 0") and find all other buses without checking every bus number.
There's also a flag somewhere in a device's PCI configuration space (e.g. bus X, device Y, function 0) that determines if it is a multi-function device or not. If it's not a multi-function device you don't need to check the other functions (e.g. bus X, device Y, function 1 to bus X, device Y, function 7 can be skipped).
PCI bus 0, device 0, function 0 is always the first PCI host controller. If the system has multiple PCI host controllers then PCI bus 0, device 0 will be a multi-function device (with one function per host controller). This means that PCI bus 0, device 0, function 0 should represent a host controller with a secondary bus = 0, and PCI bus 0, device 0, function 1 should be another PCI host controller with a secondary bus = 1. AFAIK the secondary bus number returned in PCI host controllers is hard-wired (regardless of how many PCI host controllers there are).
This is all suited to recursive functions, for either detecting settings (like most OSs) or configuring the PCI bus numbers and other things (like the BIOS does).
os64dev wrote:now my question is because i find a lot of pci bridges how do i detect de devices behind the bridges, do i have to program the bridge device? or does the above code find all the device.
Very roughly, it'd go something like:
Code: Select all
void main(void) {
scanPCIbus(0);
}
void scanPCIbus(int bus) {
int device;
int function;
for(device = 0; device < 32; device ++) {
if( checkIfMultifunction(bus, device) == MULTI_FUNCTION) {
for(function = 0; function < 7; function++) {
scanPCIfunction(bus, device, function);
}
} else {
scanPCIfunction(bus, device, 0);
}
}
}
void scanPCIfunction(int bus, int device, int function) {
int type;
if( (bus == 0) && (device == 0) ) {
handlePCIhostController(bus, device, function);
} else {
type = getPCIdeviceType();
switch(type) {
case PCI_TO_PCI_BRIDGE:
handlePCItoPCIbridge(bus, device, function);
break;
/* More device types here */
}
}
}
void handlePCIhostController(int bus, int device, int function) {
scanPCIbus( getSecondaryBus(bus, device, function) );
}
void handlePCItoPCIbridge(int bus, int device, int function); {
scanPCIbus( getSecondaryBus(bus, device, function) );
}
Note that if you're completely reconfiguring the PCI buses you'd keep track of used bus numbers and set the bus number in the "secondary bus number" field, rather than using a "getSecondaryBus()" function.
You shouldn't have to program the bridge device, as the BIOS should do this correctly. Here I use the word "should" like a lawyer (i.e. "should" isn't necessarily the same as "will"), and there's no guarantee that the BIOS will acheive the best configuration. It's also technically possible (but very unlikely) that someone will plug in a new PCI bridge while the OS is runniing (if the computer supports hot-plug PCI)
BTW the code you had will find everything on the PCI bus, it's just that it's less efficient and harder to get right if you're configuring bridges (including setting which address range/s are forwarded by the bridge from the primary bus to the secondary bus).
Cheers,
Brendan