]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[pci] Add pci_find_next() to iterate over existent PCI devices
authorMichael Brown <mcb30@ipxe.org>
Thu, 1 Aug 2013 15:52:28 +0000 (16:52 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 5 Aug 2013 12:51:16 +0000 (13:51 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/bus/pci.c
src/include/ipxe/pci.h

index 7bd353d8be05a30f1ffd0f1e167c7e6d2411c085..4a8d00b54fefef1e8df13d43c919e2e04336abaa 100644 (file)
@@ -171,8 +171,20 @@ void adjust_pci_device ( struct pci_device *pci ) {
  * @ret rc             Return status code
  */
 int pci_read_config ( struct pci_device *pci ) {
+       uint16_t busdevfn;
+       uint8_t hdrtype;
        uint32_t tmp;
 
+       /* Ignore all but the first function on non-multifunction devices */
+       if ( PCI_FUNC ( pci->busdevfn ) != 0 ) {
+               busdevfn = pci->busdevfn;
+               pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn );
+               pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
+               pci->busdevfn = busdevfn;
+               if ( ! ( hdrtype & 0x80 ) )
+                       return -ENODEV;
+       }
+
        /* Check for physical device presence */
        pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
        if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
@@ -203,6 +215,32 @@ int pci_read_config ( struct pci_device *pci ) {
        return 0;
 }
 
+/**
+ * Find next device on PCI bus
+ *
+ * @v pci              PCI device to fill in
+ * @v busdevfn         Starting bus:dev.fn address
+ * @ret busdevfn       Bus:dev.fn address of next PCI device, or negative error
+ */
+int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
+       static unsigned int end;
+       int rc;
+
+       /* Determine number of PCI buses */
+       if ( ! end )
+               end = PCI_BUSDEVFN ( pci_num_bus(), 0, 0 );
+
+       /* Find next PCI device, if any */
+       for ( ; busdevfn < end ; busdevfn++ ) {
+               memset ( pci, 0, sizeof ( *pci ) );
+               pci_init ( pci, busdevfn );
+               if ( ( rc = pci_read_config ( pci ) ) == 0 )
+                       return busdevfn;
+       }
+
+       return -ENODEV;
+}
+
 /**
  * Find driver for PCI device
  *
@@ -276,14 +314,10 @@ void pci_remove ( struct pci_device *pci ) {
  */
 static int pcibus_probe ( struct root_device *rootdev ) {
        struct pci_device *pci = NULL;
-       unsigned int num_bus;
-       unsigned int busdevfn;
-       uint8_t hdrtype = 0;
+       int busdevfn = 0;
        int rc;
 
-       num_bus = pci_num_bus();
-       for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ;
-             busdevfn++ ) {
+       for ( busdevfn = 0 ; 1 ; busdevfn++ ) {
 
                /* Allocate struct pci_device */
                if ( ! pci )
@@ -292,22 +326,11 @@ static int pcibus_probe ( struct root_device *rootdev ) {
                        rc = -ENOMEM;
                        goto err;
                }
-               memset ( pci, 0, sizeof ( *pci ) );
-               pci_init ( pci, busdevfn );
-                       
-               /* Skip all but the first function on
-                * non-multifunction cards
-                */
-               if ( PCI_FUNC ( busdevfn ) == 0 ) {
-                       pci_read_config_byte ( pci, PCI_HEADER_TYPE,
-                                              &hdrtype );
-               } else if ( ! ( hdrtype & 0x80 ) ) {
-                       continue;
-               }
 
-               /* Read device configuration */
-               if ( ( rc = pci_read_config ( pci ) ) != 0 )
-                       continue;
+               /* Find next PCI device, if any */
+               busdevfn = pci_find_next ( pci, busdevfn );
+               if ( busdevfn < 0 )
+                       break;
 
                /* Look for a driver */
                if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
index a6ed484f1c803d4141bbad45d269c80a7982560b..692771ebefb7a8d0a7552995bc90b45c57cdfcb1 100644 (file)
@@ -351,6 +351,7 @@ struct pci_driver {
 #define PCI_FUNC( busdevfn )           ( ( (busdevfn) >> 0 ) & 0x07 )
 #define PCI_BUSDEVFN( bus, slot, func )        \
        ( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) )
+#define PCI_FIRST_FUNC( busdevfn )     ( (busdevfn) & ~0x07 )
 
 #define PCI_BASE_CLASS( class )                ( (class) >> 16 )
 #define PCI_SUB_CLASS( class )         ( ( (class) >> 8 ) & 0xff )
@@ -385,6 +386,7 @@ extern void adjust_pci_device ( struct pci_device *pci );
 extern unsigned long pci_bar_start ( struct pci_device *pci,
                                     unsigned int reg );
 extern int pci_read_config ( struct pci_device *pci );
+extern int pci_find_next ( struct pci_device *pci, unsigned int busdevfn );
 extern int pci_find_driver ( struct pci_device *pci );
 extern int pci_probe ( struct pci_device *pci );
 extern void pci_remove ( struct pci_device *pci );