Implemented (untested) PXENV_START_UNDI.
authorMichael Brown <mcb30@etherboot.org>
Tue, 3 Jul 2007 17:17:14 +0000 (18:17 +0100)
committerMichael Brown <mcb30@etherboot.org>
Tue, 3 Jul 2007 17:17:14 +0000 (18:17 +0100)
src/drivers/bus/isapnp.c
src/include/gpxe/isapnp.h
src/include/gpxe/netdevice.h
src/interface/pxe/pxe_preboot.c
src/net/netdevice.c

index 79268d4..b34108c 100644 (file)
@@ -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
index 72ce0a6..07797a9 100644 (file)
@@ -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
                                         * 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
index c0df7c9..0bc5311 100644 (file)
@@ -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,
index 15752b2..a74e58a 100644 (file)
@@ -28,6 +28,9 @@
 #include <stdlib.h>
 #include <gpxe/uaccess.h>
 #include <gpxe/dhcp.h>
+#include <gpxe/device.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/isapnp.h>
 #include <basemem_packet.h>
 #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 %04x:%04x:%04x",
+             start_undi->AX, start_undi->BX, start_undi->DX );
+
+       /* Determine bus type and location */
+       isapnp_read_port = start_undi->DX;
+       isapnp_csn = start_undi->BX;
+       pci_busdevfn = start_undi->AX;
+
+       /* 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;
+       }
 
-       DBG ( "PXENV_START_UNDI" );
-
-#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;
-
-#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;
+       /* 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;
        }
-#endif
+       DBG ( " using netdev %s", netdev->name );
 
-#endif
+       /* 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;
index 8a09910..971830d 100644 (file)
@@ -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;
        }