diff --git a/src/drivers/bus/isapnp.c b/src/drivers/bus/isapnp.c index 79268d44..b34108c7 100644 --- a/src/drivers/bus/isapnp.c +++ b/src/drivers/bus/isapnp.c @@ -529,7 +529,7 @@ static int isapnp_try_isolate ( void ) { * */ static void isapnp_isolate ( void ) { - for ( isapnp_read_port = ISAPNP_READ_PORT_MIN ; + for ( isapnp_read_port = ISAPNP_READ_PORT_START ; isapnp_read_port <= ISAPNP_READ_PORT_MAX ; isapnp_read_port += ISAPNP_READ_PORT_STEP ) { /* Avoid problematic locations such as the NE2000 diff --git a/src/include/gpxe/isapnp.h b/src/include/gpxe/isapnp.h index 72ce0a6f..07797a99 100644 --- a/src/include/gpxe/isapnp.h +++ b/src/include/gpxe/isapnp.h @@ -49,7 +49,8 @@ /* Port addresses */ #define ISAPNP_ADDRESS 0x279 #define ISAPNP_WRITE_DATA 0xa79 -#define ISAPNP_READ_PORT_MIN 0x213 /* ISAPnP spec says 0x203, but +#define ISAPNP_READ_PORT_MIN 0x203 +#define ISAPNP_READ_PORT_START 0x213 /* ISAPnP spec says 0x203, but * Linux ISAPnP starts at * 0x213 with no explanatory * comment. 0x203 probably @@ -63,6 +64,10 @@ * any value less than 16. */ +/* Card select numbers */ +#define ISAPNP_CSN_MIN 0x01 +#define ISAPNP_CSN_MAX 0x0f + /* Registers */ #define ISAPNP_READPORT 0x00 #define ISAPNP_SERIALISOLATION 0x01 diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index c0df7c96..0bc5311c 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -289,8 +289,9 @@ netdev_put ( struct net_device *netdev ) { } extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); -void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf ); -void netdev_tx_complete_next ( struct net_device *netdev ); +extern void netdev_tx_complete ( struct net_device *netdev, + struct io_buffer *iobuf ); +extern void netdev_tx_complete_next ( struct net_device *netdev ); extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ); extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota ); extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ); @@ -299,9 +300,9 @@ extern int register_netdev ( struct net_device *netdev ); extern int netdev_open ( struct net_device *netdev ); extern void netdev_close ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev ); -struct net_device * find_netdev ( const char *name ); -struct net_device * find_pci_netdev ( unsigned int busdevfn ); - +extern struct net_device * find_netdev ( const char *name ); +extern struct net_device * find_netdev_by_location ( unsigned int bus_type, + unsigned int location ); extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ); extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, diff --git a/src/interface/pxe/pxe_preboot.c b/src/interface/pxe/pxe_preboot.c index 15752b23..a74e58af 100644 --- a/src/interface/pxe/pxe_preboot.c +++ b/src/interface/pxe/pxe_preboot.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include "pxe.h" #include "pxe_call.h" @@ -196,41 +199,47 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE * Status: working */ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { + unsigned int isapnp_read_port; + unsigned int isapnp_csn; + unsigned int pci_busdevfn; + unsigned int bus_type; + unsigned int location; + struct net_device *netdev; - DBG ( "PXENV_START_UNDI" ); + DBG ( "PXENV_START_UNDI %04x:%04x:%04x", + start_undi->AX, start_undi->BX, start_undi->DX ); -#if 0 - /* Record PCI bus & devfn passed by caller, so we know which - * NIC they want to use. - * - * If they don't match our already-existing NIC structure, set - * values to ensure that the specified NIC is used at the next - * call to pxe_intialise_nic(). - */ - bus = ( start_undi->AX >> 8 ) & 0xff; - devfn = start_undi->AX & 0xff; + /* Determine bus type and location */ + isapnp_read_port = start_undi->DX; + isapnp_csn = start_undi->BX; + pci_busdevfn = start_undi->AX; -#warning "device probing mechanism has completely changed" -#if 0 - if ( ( pci->dev.driver == NULL ) || - ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) { - /* This is quite a bit of a hack and relies on - * knowledge of the internal operation of Etherboot's - * probe mechanism. - */ - DBG ( " set PCI %hhx:%hhx.%hhx", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn) ); - dev->type = BOOT_NIC; - dev->to_probe = PROBE_PCI; - memset ( &dev->state, 0, sizeof(dev->state) ); - pci->advance = 1; - pci->dev.use_specified = 1; - pci->dev.bus = bus; - pci->dev.devfn = devfn; + /* Use a heuristic to decide whether we are PCI or ISAPnP */ + if ( ( isapnp_read_port >= ISAPNP_READ_PORT_MIN ) && + ( isapnp_read_port <= ISAPNP_READ_PORT_MAX ) && + ( isapnp_csn >= ISAPNP_CSN_MIN ) && + ( isapnp_csn <= ISAPNP_CSN_MAX ) ) { + bus_type = BUS_TYPE_ISAPNP; + location = isapnp_csn; + } else { + bus_type = BUS_TYPE_PCI; + location = pci_busdevfn; } -#endif -#endif + /* Look for a matching net device */ + netdev = find_netdev_by_location ( bus_type, location ); + if ( ! netdev ) { + DBG ( " no net device found" ); + start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC; + return PXENV_EXIT_FAILURE; + } + DBG ( " using netdev %s", netdev->name ); + + /* Save as PXE net device */ + pxe_set_netdev ( netdev ); + + /* Hook INT 1A */ + pxe_hook_int1a(); start_undi->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 8a099107..971830d9 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -356,15 +356,17 @@ struct net_device * find_netdev ( const char *name ) { /** * Get network device by PCI bus:dev.fn address * - * @v busdevfn PCI bus:dev.fn address + * @v bus_type Bus type + * @v location Bus location * @ret netdev Network device, or NULL */ -struct net_device * find_pci_netdev ( unsigned int busdevfn ) { +struct net_device * find_netdev_by_location ( unsigned int bus_type, + unsigned int location ) { struct net_device *netdev; list_for_each_entry ( netdev, &net_devices, list ) { - if ( ( netdev->dev->desc.bus_type == BUS_TYPE_PCI ) && - ( netdev->dev->desc.location == busdevfn ) ) + if ( ( netdev->dev->desc.bus_type == bus_type ) && + ( netdev->dev->desc.location == location ) ) return netdev; }