aboutsummaryrefslogtreecommitdiffstats
path: root/src/drivers/bus
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2011-02-10 13:43:58 +0000
committerMichael Brown <mcb30@ipxe.org>2011-02-17 01:59:24 +0000
commit4f4c21462114cb4e397377d8ea59c4204a4e33f7 (patch)
tree7c4db0f186c4df0dd4ce18169e3c79783d2ce8f3 /src/drivers/bus
parent5bde349e55640b2d21fbe0f4f53edabe6878eb91 (diff)
downloadipxe-4f4c21462114cb4e397377d8ea59c4204a4e33f7.tar.gz
[pci] Modularise PCI device support
Some operating environments require (or at least prefer) that we do not perform our own PCI bus scan, but deal only with specified devices. Modularise the PCI core to allow for this. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/bus')
-rw-r--r--src/drivers/bus/pci.c126
1 files changed, 79 insertions, 47 deletions
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 4d77dfe56..3ae17e5cf 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -164,23 +164,54 @@ void adjust_pci_device ( struct pci_device *pci ) {
}
/**
- * Probe a PCI device
+ * Read PCI device configuration
*
* @v pci PCI device
* @ret rc Return status code
+ */
+int pci_read_config ( struct pci_device *pci ) {
+ uint32_t tmp;
+
+ /* Check for physical device presence */
+ pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
+ if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
+ return -ENODEV;
+
+ /* Populate struct pci_device */
+ pci->vendor = ( tmp & 0xffff );
+ pci->device = ( tmp >> 16 );
+ pci_read_config_dword ( pci, PCI_REVISION, &tmp );
+ pci->class = ( tmp >> 8 );
+ pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
+ pci_read_bases ( pci );
+
+ /* Initialise generic device component */
+ snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
+ "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ),
+ PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) );
+ pci->dev.desc.bus_type = BUS_TYPE_PCI;
+ pci->dev.desc.location = pci->busdevfn;
+ pci->dev.desc.vendor = pci->vendor;
+ pci->dev.desc.device = pci->device;
+ pci->dev.desc.class = pci->class;
+ pci->dev.desc.ioaddr = pci->ioaddr;
+ pci->dev.desc.irq = pci->irq;
+ INIT_LIST_HEAD ( &pci->dev.siblings );
+ INIT_LIST_HEAD ( &pci->dev.children );
+
+ return 0;
+}
+
+/**
+ * Find driver for PCI device
*
- * Searches for a driver for the PCI device. If a driver is found,
- * its probe() routine is called.
+ * @v pci PCI device
+ * @ret rc Return status code
*/
-static int pci_probe ( struct pci_device *pci ) {
+int pci_find_driver ( struct pci_device *pci ) {
struct pci_driver *driver;
struct pci_device_id *id;
unsigned int i;
- int rc;
-
- DBGC ( pci, PCI_FMT " is %04x:%04x mem %lx io %lx irq %d\n",
- PCI_ARGS ( pci ), pci->vendor, pci->device, pci->membase,
- pci->ioaddr, pci->irq );
for_each_table_entry ( driver, PCI_DRIVERS ) {
for ( i = 0 ; i < driver->id_count ; i++ ) {
@@ -191,21 +222,37 @@ static int pci_probe ( struct pci_device *pci ) {
if ( ( id->device != PCI_ANY_ID ) &&
( id->device != pci->device ) )
continue;
- pci->driver = driver;
- pci->id = id;
- DBGC ( pci, "...using driver %s\n", pci->id->name );
- if ( ( rc = driver->probe ( pci ) ) != 0 ) {
- DBGC ( pci, "......probe failed: %s\n",
- strerror ( rc ) );
- continue;
- }
- DBGC ( pci, PCI_FMT " added\n", PCI_ARGS ( pci ) );
+ pci_set_driver ( pci, driver, id );
return 0;
}
}
+ return -ENOENT;
+}
- DBGC ( pci, "...no driver found\n" );
- return -ENOTTY;
+/**
+ * Probe a PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ *
+ * Searches for a driver for the PCI device. If a driver is found,
+ * its probe() routine is called.
+ */
+int pci_probe ( struct pci_device *pci ) {
+ int rc;
+
+ DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n",
+ PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name );
+ DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n",
+ PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq );
+
+ if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) {
+ DBGC ( pci, PCI_FMT " probe failed: %s\n",
+ PCI_ARGS ( pci ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
/**
@@ -213,7 +260,7 @@ static int pci_probe ( struct pci_device *pci ) {
*
* @v pci PCI device
*/
-static void pci_remove ( struct pci_device *pci ) {
+void pci_remove ( struct pci_device *pci ) {
pci->driver->remove ( pci );
DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) );
}
@@ -231,7 +278,6 @@ static int pcibus_probe ( struct root_device *rootdev ) {
unsigned int num_bus;
unsigned int busdevfn;
uint8_t hdrtype = 0;
- uint32_t tmp;
int rc;
num_bus = pci_num_bus();
@@ -246,7 +292,7 @@ static int pcibus_probe ( struct root_device *rootdev ) {
goto err;
}
memset ( pci, 0, sizeof ( *pci ) );
- pci->busdevfn = busdevfn;
+ pci_init ( pci, busdevfn );
/* Skip all but the first function on
* non-multifunction cards
@@ -258,37 +304,23 @@ static int pcibus_probe ( struct root_device *rootdev ) {
continue;
}
- /* Check for physical device presence */
- pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp );
- if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) )
+ /* Read device configuration */
+ if ( ( rc = pci_read_config ( pci ) ) != 0 )
continue;
-
- /* Populate struct pci_device */
- pci->vendor = ( tmp & 0xffff );
- pci->device = ( tmp >> 16 );
- pci_read_config_dword ( pci, PCI_REVISION, &tmp );
- pci->class = ( tmp >> 8 );
- pci_read_config_byte ( pci, PCI_INTERRUPT_LINE,
- &pci->irq );
- pci_read_bases ( pci );
+
+ /* Look for a driver */
+ if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
+ DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
+ PCI_ARGS ( pci ), pci->vendor, pci->device );
+ continue;
+ }
/* Add to device hierarchy */
- snprintf ( pci->dev.name, sizeof ( pci->dev.name ),
- "PCI%02x:%02x.%x", PCI_BUS ( busdevfn ),
- PCI_SLOT ( busdevfn ), PCI_FUNC ( busdevfn ) );
- pci->dev.desc.bus_type = BUS_TYPE_PCI;
- pci->dev.desc.location = pci->busdevfn;
- pci->dev.desc.vendor = pci->vendor;
- pci->dev.desc.device = pci->device;
- pci->dev.desc.class = pci->class;
- pci->dev.desc.ioaddr = pci->ioaddr;
- pci->dev.desc.irq = pci->irq;
pci->dev.parent = &rootdev->dev;
list_add ( &pci->dev.siblings, &rootdev->dev.children);
- INIT_LIST_HEAD ( &pci->dev.children );
/* Look for a driver */
- if ( pci_probe ( pci ) == 0 ) {
+ if ( ( rc = pci_probe ( pci ) ) == 0 ) {
/* pcidev registered, we can drop our ref */
pci = NULL;
} else {