summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown2007-01-09 03:32:06 +0100
committerMichael Brown2007-01-09 03:32:06 +0100
commitf2f492a536f8efd3301414ac769534ecdd834725 (patch)
tree455aff01285d214c9ddae57c0c7021de812782de /src/arch
parentPopulate preloaded_undi device when applicable. (diff)
downloadipxe-f2f492a536f8efd3301414ac769534ecdd834725.tar.gz
ipxe-f2f492a536f8efd3301414ac769534ecdd834725.tar.xz
ipxe-f2f492a536f8efd3301414ac769534ecdd834725.zip
If preloaded device matches, use that rather than going via the UNDI
loader.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/drivers/net/undi.c67
1 files changed, 46 insertions, 21 deletions
diff --git a/src/arch/i386/drivers/net/undi.c b/src/arch/i386/drivers/net/undi.c
index 354a07f7c..a6f1267bc 100644
--- a/src/arch/i386/drivers/net/undi.c
+++ b/src/arch/i386/drivers/net/undi.c
@@ -24,6 +24,7 @@
#include <undirom.h>
#include <undiload.h>
#include <undinet.h>
+#include <undipreload.h>
/** @file
*
@@ -32,34 +33,43 @@
*/
/**
+ * Find UNDI ROM for PCI device
+ *
+ * @v pci PCI device
+ * @ret undirom UNDI ROM, or NULL
+ *
+ * Try to find a driver for this device. Try an exact match on the
+ * ROM address first, then fall back to a vendor/device ID match only
+ */
+static struct undi_rom * undipci_find_rom ( struct pci_device *pci ) {
+ struct undi_rom *undirom;
+ unsigned long rombase;
+
+ rombase = pci_bar_start ( pci, PCI_ROM_ADDRESS );
+ undirom = undirom_find_pci ( pci->vendor, pci->device, rombase );
+ if ( ! undirom )
+ undirom = undirom_find_pci ( pci->vendor, pci->device, 0 );
+ return undirom;
+}
+
+/**
* Probe PCI device
*
- * @v pci PCI device
- * @v id PCI ID
- * @ret rc Return status code
+ * @v pci PCI device
+ * @v id PCI ID
+ * @ret rc Return status code
*/
static int undipci_probe ( struct pci_device *pci,
const struct pci_device_id *id __unused ) {
struct undi_device *undi;
struct undi_rom *undirom;
- unsigned long rombase;
+ unsigned int busdevfn = ( ( pci->bus << 8 ) | pci->devfn );
int rc;
/* Ignore non-network devices */
if ( PCI_BASE_CLASS ( pci->class ) != PCI_BASE_CLASS_NETWORK )
return -ENOTTY;
- /* Try to find a driver for this device. Try an exact match
- * on the ROM address first, then fall back to a vendor/device
- * ID match only
- */
- rombase = pci_bar_start ( pci, PCI_ROM_ADDRESS );
- undirom = undirom_find_pci ( pci->vendor, pci->device, rombase );
- if ( ! undirom )
- undirom = undirom_find_pci ( pci->vendor, pci->device, 0 );
- if ( ! undirom )
- return -ENODEV;
-
/* Allocate UNDI device structure */
undi = malloc ( sizeof ( *undi ) );
if ( ! undi )
@@ -67,16 +77,30 @@ static int undipci_probe ( struct pci_device *pci,
memset ( undi, 0, sizeof ( *undi ) );
pci_set_drvdata ( pci, undi );
+ /* Find/create our pixie */
+ if ( preloaded_undi.pci_busdevfn == busdevfn ) {
+ /* Claim preloaded UNDI device */
+ DBGC ( undi, "UNDI %p using preloaded UNDI device\n", undi );
+ memcpy ( undi, &preloaded_undi, sizeof ( *undi ) );
+ memset ( &preloaded_undi, 0, sizeof ( preloaded_undi ) );
+ } else {
+ /* Find UNDI ROM for PCI device */
+ if ( ! ( undirom = undipci_find_rom ( pci ) ) ) {
+ rc = -ENODEV;
+ goto err_find_rom;
+ }
+
+ /* Call UNDI ROM loader to create pixie */
+ if ( ( rc = undi_load_pci ( undi, undirom, pci->bus,
+ pci->devfn ) ) != 0 )
+ goto err_load_pci;
+ }
+
/* Add to device hierarchy */
undi->dev.parent = &pci->dev;
INIT_LIST_HEAD ( &undi->dev.children );
list_add ( &undi->dev.siblings, &pci->dev.children );
- /* Call UNDI ROM loader to create pixie */
- if ( ( rc = undi_load_pci ( undi, undirom, pci->bus,
- pci->devfn ) ) != 0 )
- goto err_load_pci;
-
/* Create network device */
if ( ( rc = undinet_probe ( undi ) ) != 0 )
goto err_undinet_probe;
@@ -85,8 +109,9 @@ static int undipci_probe ( struct pci_device *pci,
err_undinet_probe:
undi_unload ( undi );
- err_load_pci:
list_del ( &undi->dev.siblings );
+ err_find_rom:
+ err_load_pci:
free ( undi );
pci_set_drvdata ( pci, NULL );
return rc;