Hi,
The first problem is that "pci_read()" will always return a 32 bit value that is always aligned to the nearest 32 bits. When you try to read the "pci_device_id" you will actually get a 32 bit value where the Device ID is in bits 16 to 31.
The PCI BIOS solves this by providing functions to return a dword, word or byte (and doing the necessary bit shifting to make it work). You could do the same, but to be honest this is lame - the first thing you're doing is getting the Device ID and the Vendor ID which are in the same dword. Rather than reading the same dword from configuration space twice, it's better to read it once and do the bit shifting stuff afterwards.
For example:
Code: Select all
temp = pci_read(bus, device, 0, 0);
vendor_id = temp & 0xFFFF;
device_id = (temp >> 16) & 0xFFFF;
Secondly, I'm not sure why your "pci_read()" function saves and restores the original value (I can't see why you'd need to). If you're worried about re-entrancy then use a re-entrancy lock (or for single CPU only, just disable interrupts).
None of this explains why
"if (!vendor_id || vendor_id == 0xFFFF) continue;" doesn't work correctly, as vendor_id should still be correct (as it's truncated to 16 bit). Also, theoretically "vendor ID = 0x0000" is possible (but hasn't been assigned to a vendor yet). In any case you should be able to simplify this test.
This leaves something like:
Code: Select all
unsigned int pci_list_count;
void pci_detect() {
unsigned short bus, device;
unsigned int functions_count;
u32 temp;
u8 header_type;
u16 vendor_id;
pci_list_count = 0;
for (bus = 0; bus < 0x10; ++bus) {
for (device = 0; device < 0x40; ++device) {
temp = pci_read_dword(bus, device, 0, 0);
vendor_id = temp & 0xFFFF;
device_id = (temp >> 16) & 0xFFFF;
vendor_id =pci_read_dword(bus, device, 0, pci_vendor_id);
if (vendor_id != 0xFFFF) {
++pci_list_count;
// here is not finished...
}
}
}
}
unsigned int pci_read_dword(unsigned short bus, unsigned short device, unsigned short function, unsigned short reg) {
U32 result;
u32 msg = 0x80000000 | ((bus & 0xFF) << 16) | ((device & 0x1F) << 11) | ((function & 0x07) << 8) | (reg & 0xFC);
// Re-entrancy lock or "CLI" needed here
outd(0xCF8, msg);
result = ind(0xCFC);
// Unlock re-entrancy lock or "STI" needed here
return result;
}
This is a start. The next step is to see if works (fingers crossed), and then implement more.
[continued]