[SeaBIOS] [PATCH] pci: capability scanning function'

Michael S. Tsirkin mst at redhat.com
Wed Jul 6 16:57:47 CEST 2011


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 at 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)



More information about the SeaBIOS mailing list