On Wed, Jul 06, 2011 at 05:03:21PM +0300, Michael S. Tsirkin wrote:
Add pci_find_capability to scan capability list. Return 0 on error, capability offset if found.
Signed-off-by: Michael S. Tsirkin mst@redhat.com
Not useful by itself, but should be handy if we ever want to look at capabilities such as pci express.
Here's an example using slot register and pci express register to figure out how many expansion slots does a bridge have:
diff --git a/src/pci.c b/src/pci.c index 23a6878..5e72347 100644 --- a/src/pci.c +++ b/src/pci.c @@ -57,30 +57,59 @@ pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on) pci_config_writew(bdf, addr, val); }
unsigned char pci_find_capability(u16 bdf, unsigned char cap_id) { unsigned char next, prev; int loop = 0;
if (!(pci_config_readb(bdf, PCI_STATUS) & PCI_STATUS_CAP_LIST)) return 0;
for (prev = PCI_CAPABILITY_LIST; (next = pci_config_readb(bdf, prev)); prev = next + PCI_CAP_LIST_NEXT) { if (pci_config_readb(bdf, next + PCI_CAP_LIST_ID) == cap_id) break; if (loop++ > 0x100) { dprintf(1, "ERROR: capability loop detected. " "PCI device %02x:%02x.%x\n" , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) , pci_bdf_to_fn(bdf)); return 0; } }
return next; }
+static int pci_bridge_conventional_slots(u16 bdf) +{ + u8 cap = pci_find_capability(bdf, PCI_CAP_ID_SLOTID); + if (!cap) + return 32; + u8 slots = pci_config_readb(bdf, cap + 2); + return slots; +} + +int pci_bridge_get_slots(u16 bdf) +{ + /* No express cap: assume 32 ports. */ + u8 flags, type; + u8 cap = pci_find_capability(bdf, PCI_CAP_ID_EXP); + if (!cap) + return pci_bridge_conventional_slots(bdf); + flags = pci_config_readb(cap + 2); + type = flags >> 4; + switch (type) { + case PCI_EXP_TYPE_UPSTREAM: + return 0; + case PCI_EXP_TYPE_DOWNSTREAM: + return 1; + default: + return pci_bridge_conventional_slots(bdf); + } + +} + // Helper function for foreachbdf() macro - return next device int pci_next(int bdf, int bus)