From 5f17089b148211dd8667af4efa9302a1f46dbc49 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 2 Jul 2007 17:43:32 +0100 Subject: [PATCH] pxe_netdev now holds a reference to the network device. Use generic fields in struct device_description rather than assuming that the struct device * is contained within a pci_device or isapnp_device; this assumption is broken when using the undionly driver. Add PXENV_UNDI_SET_STATION_ADDRESS. --- src/arch/i386/image/pxe_image.c | 12 ++++- src/drivers/bus/isapnp.c | 2 + src/drivers/bus/pci.c | 3 ++ src/include/gpxe/device.h | 6 +++ src/include/pxe.h | 2 + src/interface/pxe/pxe.c | 16 ++++++- src/interface/pxe/pxe_undi.c | 80 +++++++++++---------------------- 7 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/arch/i386/image/pxe_image.c b/src/arch/i386/image/pxe_image.c index 9cf54691..c6469290 100644 --- a/src/arch/i386/image/pxe_image.c +++ b/src/arch/i386/image/pxe_image.c @@ -40,6 +40,7 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE ); */ static int pxe_exec ( struct image *image __unused ) { struct net_device *netdev; + int rc; /* Ensure that PXE stack is ready to use */ pxe_init_structures(); @@ -47,11 +48,18 @@ static int pxe_exec ( struct image *image __unused ) { /* Arbitrarily pick the first open network device to use for PXE */ for_each_netdev ( netdev ) { - pxe_netdev = netdev; + pxe_set_netdev ( netdev ); break; } - return pxe_start_nbp(); + /* Start PXE NBP */ + rc = pxe_start_nbp(); + + /* Deactivate PXE */ + pxe_set_netdev ( NULL ); + pxe_unhook_int1a(); + + return rc; } /** diff --git a/src/drivers/bus/isapnp.c b/src/drivers/bus/isapnp.c index 96bc60ec..79268d44 100644 --- a/src/drivers/bus/isapnp.c +++ b/src/drivers/bus/isapnp.c @@ -705,6 +705,8 @@ static int isapnpbus_probe ( struct root_device *rootdev ) { isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP; isapnp->dev.desc.vendor = isapnp->vendor_id; isapnp->dev.desc.device = isapnp->prod_id; + isapnp->dev.desc.ioaddr = isapnp->ioaddr; + isapnp->dev.desc.irq = isapnp->irqno; isapnp->dev.parent = &rootdev->dev; list_add ( &isapnp->dev.siblings, &rootdev->dev.children ); diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 577691f5..967441ac 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -286,6 +286,9 @@ static int pcibus_probe ( struct root_device *rootdev ) { pci->dev.desc.location = PCI_BUSDEVFN (bus, devfn); 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 ); diff --git a/src/include/gpxe/device.h b/src/include/gpxe/device.h index f88a2da5..caabdae5 100644 --- a/src/include/gpxe/device.h +++ b/src/include/gpxe/device.h @@ -27,6 +27,12 @@ struct device_description { unsigned int vendor; /** Device ID */ unsigned int device; + /** Device class */ + unsigned long class; + /** I/O address */ + unsigned long ioaddr; + /** IRQ */ + unsigned int irq; }; /** PCI bus type */ diff --git a/src/include/pxe.h b/src/include/pxe.h index aba774ef..301bb10b 100644 --- a/src/include/pxe.h +++ b/src/include/pxe.h @@ -137,4 +137,6 @@ struct pcir_header { extern struct net_device *pxe_netdev; +extern void pxe_set_netdev ( struct net_device *netdev ); + #endif /* PXE_H */ diff --git a/src/interface/pxe/pxe.c b/src/interface/pxe/pxe.c index 8aa7df0d..5e67758b 100644 --- a/src/interface/pxe/pxe.c +++ b/src/interface/pxe/pxe.c @@ -22,12 +22,24 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "dev.h" +#include #include "pxe.h" -#warning "pxe_netdev should hold a persistent reference to the net device" struct net_device *pxe_netdev = NULL; +/** + * Set network device as current PXE network device + * + * @v netdev Network device, or NULL + */ +void pxe_set_netdev ( struct net_device *netdev ) { + if ( pxe_netdev ) + netdev_put ( pxe_netdev ); + pxe_netdev = NULL; + if ( netdev ) + pxe_netdev = netdev_get ( netdev ); +} + #if 0 /* Global pointer to currently installed PXE stack */ diff --git a/src/interface/pxe/pxe_undi.c b/src/interface/pxe/pxe_undi.c index 4a9b3390..e108764c 100644 --- a/src/interface/pxe/pxe_undi.c +++ b/src/interface/pxe/pxe_undi.c @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include #include #include #include "pxe.h" @@ -200,30 +200,30 @@ pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS /* PXENV_UNDI_SET_STATION_ADDRESS * - * Status: working (deliberately incomplete) + * Status: working */ PXENV_EXIT_t pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address ) { + DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" ); -#if 0 - /* We don't offer a facility to set the MAC address; this - * would require adding extra code to all the Etherboot - * drivers, for very little benefit. If we're setting it to - * the current value anyway then return success, otherwise - * return UNSUPPORTED. + /* If adapter is open, the change will have no effect; return + * an error */ - if ( memcmp ( nic.node_addr, - &undi_set_station_address->StationAddress, - ETH_ALEN ) == 0 ) { - undi_set_station_address->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; + if ( pxe_netdev->state & NETDEV_OPEN ) { + undi_set_station_address->Status = + PXENV_STATUS_UNDI_INVALID_STATE; + return PXENV_EXIT_FAILURE; } -#endif - undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + /* Update MAC address */ + memcpy ( pxe_netdev->ll_addr, + &undi_set_station_address->StationAddress, + pxe_netdev->ll_protocol->ll_addr_len ); + + undi_set_station_address = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_SET_PACKET_FILTER @@ -248,33 +248,11 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information ) { struct device *dev = pxe_netdev->dev; struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; - unsigned int ioaddr; - unsigned int irqno; DBG ( "PXENV_UNDI_GET_INFORMATION" ); - switch ( dev->desc.bus_type ) { - case BUS_TYPE_PCI: { - struct pci_device *pci = - container_of ( dev, struct pci_device, dev ); - - ioaddr = pci->ioaddr; - irqno = pci->irq; - break; } - case BUS_TYPE_ISAPNP: { - struct isapnp_device *isapnp = - container_of ( dev, struct isapnp_device, dev ); - - ioaddr = isapnp->ioaddr; - irqno = isapnp->irqno; - break; } - default: - undi_get_information->Status = PXENV_STATUS_FAILURE; - return PXENV_EXIT_FAILURE; - } - - undi_get_information->BaseIo = ioaddr; - undi_get_information->IntNumber = irqno; + undi_get_information->BaseIo = dev->desc.ioaddr; + undi_get_information->IntNumber = dev->desc.irq; /* Cheat: assume all cards can cope with this */ undi_get_information->MaxTranUnit = ETH_MAX_MTU; undi_get_information->HwType = ntohs ( ll_protocol->ll_proto ); @@ -384,17 +362,15 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE switch ( dev->desc.bus_type ) { case BUS_TYPE_PCI: { - struct pci_device *pci = - container_of ( dev, struct pci_device, dev ); struct pci_nic_info *info = &undi_get_nic_type->info.pci; undi_get_nic_type->NicType = PCI_NIC; - info->Vendor_ID = pci->vendor; - info->Dev_ID = pci->device; - info->Base_Class = PCI_BASE_CLASS ( pci->class ); - info->Sub_Class = PCI_SUB_CLASS ( pci->class ); - info->Prog_Intf = PCI_PROG_INTF ( pci->class ); - info->BusDevFunc = PCI_BUSDEVFN ( pci->bus, pci->devfn ); + info->Vendor_ID = dev->desc.vendor; + info->Dev_ID = dev->desc.device; + info->Base_Class = PCI_BASE_CLASS ( dev->desc.class ); + info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class ); + info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class ); + info->BusDevFunc = dev->desc.location; /* Cheat: remaining fields are probably unnecessary, * and would require adding extra code to pci.c. */ @@ -402,14 +378,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type->info.pci.SubDevice_ID = 0xffff; break; } case BUS_TYPE_ISAPNP: { - struct isapnp_device *isapnp = - container_of ( dev, struct isapnp_device, dev ); struct pnp_nic_info *info = &undi_get_nic_type->info.pnp; undi_get_nic_type->NicType = PnP_NIC; - info->EISA_Dev_ID = ( ( isapnp->vendor_id << 16 ) | - isapnp->prod_id ); - info->CardSelNum = isapnp->csn; + info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) | + dev->desc.device ); + info->CardSelNum = dev->desc.location; /* Cheat: remaining fields are probably unnecessary, * and would require adding extra code to isapnp.c. */