I have a Realtek nic in a Lenovo netbook which is not working with ipxe
in git as of about a week ago. It looks like there was some substantial
consolidation of the Realtek code, so I backed up to commit:
d27e6d6efdfb0d40e83a8c297b9eae9ca84a7638
and things started working again. I can _also_ get things working again
if I compile out the realtek.c support altogether and just use undi.
I hacked together the attached patch which also works around the issue,
but might have wider applicability. If a pci_probe() fails, this patch
attempts to look for other drivers. This lets my system try the
realtek.c driver, fail to probe, then fall back to the UNDI Driver.
Detailed information about my nic:
> 05:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
> RTL8101E/RTL8102E PCI Express Fast Ethernet controller (rev 02)
> Subsystem: Realtek Semiconductor Co., Ltd. Device 0123
Even more, including lspci -vvv -n:
http://sr71.net/~dave/ipxe/
and output from ipxe after "make DEBUG=realtek"
http://sr71.net/~dave/foo/ipxe.debug.0.JPG
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 3ae17e5..8ecfe5c 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -208,12 +208,14 @@ int pci_read_config ( struct pci_device *pci ) {
* @v pci PCI device
* @ret rc Return status code
*/
-int pci_find_driver ( struct pci_device *pci ) {
- struct pci_driver *driver;
+struct pci_driver *pci_find_driver ( struct pci_device *pci,
+ struct pci_driver *driver ) {
struct pci_device_id *id;
unsigned int i;
- for_each_table_entry ( driver, PCI_DRIVERS ) {
+ if (driver == NULL)
+ driver = table_start ( PCI_DRIVERS );
+ for_each_table_entry_continue ( driver, PCI_DRIVERS ) {
for ( i = 0 ; i < driver->id_count ; i++ ) {
id = &driver->ids[i];
if ( ( id->vendor != PCI_ANY_ID ) &&
@@ -223,10 +225,10 @@ int pci_find_driver ( struct pci_device *pci ) {
( id->device != pci->device ) )
continue;
pci_set_driver ( pci, driver, id );
- return 0;
+ return driver;
}
}
- return -ENOENT;
+ return NULL;
}
/**
@@ -283,6 +285,7 @@ static int pcibus_probe ( struct root_device *rootdev ) {
num_bus = pci_num_bus();
for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ;
busdevfn++ ) {
+ struct pci_driver *driver = NULL;
/* Allocate struct pci_device */
if ( ! pci )
@@ -308,9 +311,10 @@ static int pcibus_probe ( struct root_device *rootdev ) {
if ( ( rc = pci_read_config ( pci ) ) != 0 )
continue;
+look_again:
/* Look for a driver */
- if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
- DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
+ if ( ( driver = pci_find_driver ( pci, driver ) ) == NULL ) {
+ DBGC ( pci, PCI_FMT " (%04x:%04x) no more drivers\n",
PCI_ARGS ( pci ), pci->vendor, pci->device );
continue;
}
@@ -324,8 +328,10 @@ static int pcibus_probe ( struct root_device *rootdev ) {
/* pcidev registered, we can drop our ref */
pci = NULL;
} else {
+ pci_clear_driver( pci );
/* Not registered; re-use struct pci_device */
list_del ( &pci->dev.siblings );
+ goto look_again;
}
}
diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h
index 520c8a0..776fca1 100644
--- a/src/include/ipxe/pci.h
+++ b/src/include/ipxe/pci.h
@@ -385,7 +385,8 @@ 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_driver ( struct pci_device *pci );
+extern struct pci_driver *pci_find_driver ( struct pci_device *pci,
+ struct pci_driver *driver );
extern int pci_probe ( struct pci_device *pci );
extern void pci_remove ( struct pci_device *pci );
extern int pci_find_capability ( struct pci_device *pci, int capability );
@@ -417,6 +418,19 @@ static inline void pci_set_driver ( struct pci_device *pci,
}
/**
+ * Clear PCI driver
+ *
+ * @v pci PCI device
+ * @v driver PCI driver
+ * @v id PCI device ID
+ */
+static inline void pci_clear_driver ( struct pci_device *pci ) {
+ pci->driver = NULL;
+ pci->id = NULL;
+ pci->dev.driver_name = NULL;
+}
+
+/**
* Set PCI driver-private data
*
* @v pci PCI device
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index 0a2da2e..33605e1 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -355,7 +355,6 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
container_of ( driver, struct efi_driver, driver );
struct efi_pci_device *efipci;
EFI_STATUS efirc;
- int rc;
DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child );
@@ -368,7 +367,7 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
}
/* Look for a driver */
- if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
+ if ( pci_find_driver ( &efipci->pci, NULL ) == NULL ) {
DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
PCI_ARGS ( &efipci->pci ) );
efirc = EFI_UNSUPPORTED;
@@ -416,10 +415,10 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
}
/* Find driver */
- if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
+ if ( pci_find_driver ( &efipci->pci, NULL ) == NULL ) {
DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
PCI_ARGS ( &efipci->pci ) );
- efirc = RC_TO_EFIRC ( rc );
+ efirc = RC_TO_EFIRC ( -ENOENT );
goto err_find_driver;
}
_______________________________________________
ipxe-devel mailing list
[email protected]
https://lists.ipxe.org/mailman/listinfo.cgi/ipxe-devel