To read PCI Configuration space, i need to write BDF and offset to 0xCF8h and then read the data register 0xCFCh
I am looking into linux kernel source, where the below logic is used.
In file arch/x86/pci/early.c
u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
{
u32 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inl(0xcfc);
return v;
}
u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
{
u8 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inb(0xcfc + (offset&3));
return v;
}
u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
{
u16 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inw(0xcfc + (offset&2));
return v;
}
Why is the bitwise AND operation performed in case of read_pci_config_8 and read_pci_config_16
v = inw(0xcfc + (offset&2));
Think of I/O port CFC as a 32-bit “window” into the 32-bit PCI config register addressed by the value in port CF8. PCI allows reading 1, 2, or 4 bytes within this window. If the low two bits of the register offset are not 0, then the byte or bytes to be read are not at the base of the window, but instead require using an offset within the window to access the desired bytes. The AND operation you’re asking about adjusts the port address being read from, to select the desired bytes. Since a 16-bit read must be aligned to a multiple of 2 bytes, the adjustment must be either 0 or 2.
That code is misguided.
You should only ever read and 32-bit dwords from IO port 0xCFC (chipset might ignore anything that isn't a 32-bit IO port read or write from this IO port); and they are IO ports and not RAM - e.g. IO port 0xCFD (or "IO port 0xCFC+1") is a completely unrelated IO port that has nothing to do with IO port 0xCFC at all.
For reference (and example code showing how to read a word correctly) see: https://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
Note: If you read the PCI Local Bus spec/s carefully; technically the chipset is supposed to also support reads/writes of bytes and words from IO port 0xCFC, and IO ports 0xCFD, 0xCFE and 0xCFF; and maybe one day someone will manage to implement a chip that doesn't need many pages of errata and the risk of assuming the chipset actually complies with every tiny detail of every relevant specification will be low enough to justify the "near zero benefits" of Linux' approach.
User contributions licensed under CC BY-SA 3.0