]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[NETDEV] Add notion of link state
authorMichael Brown <mcb30@etherboot.org>
Tue, 22 Apr 2008 16:40:50 +0000 (17:40 +0100)
committerMichael Brown <mcb30@etherboot.org>
Tue, 22 Apr 2008 16:40:50 +0000 (17:40 +0100)
Add ability for network devices to flag link up/down state to the
networking core.

Autobooting code will now wait for link-up before attempting DHCP.

IPoIB reflects the Infiniband link state as the network device link state
(which is not strictly correct; we also need a succesful IPoIB IPv4
broadcast group join), but is probably more informative.

13 files changed:
src/arch/i386/drivers/net/undinet.c
src/drivers/net/e1000/e1000.c
src/drivers/net/ipoib.c
src/drivers/net/legacy.c
src/drivers/net/mtnic.c
src/drivers/net/natsemi.c
src/drivers/net/pnic.c
src/drivers/net/rtl8139.c
src/include/gpxe/errfile.h
src/include/gpxe/netdevice.h
src/include/usr/ifmgmt.h
src/usr/autoboot.c
src/usr/ifmgmt.c

index 07bec560b1218b4096572d1476833cd9ca0d4893..512c60e9d43a5badfaac2d65b7632173e74b929e 100644 (file)
@@ -708,6 +708,9 @@ int undinet_probe ( struct undi_device *undi ) {
                undinic->hacks |= UNDI_HACK_EB54;
        }
 
+       /* Mark as link up; we don't handle link state */
+       netdev_link_up ( netdev );
+
        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err_register;
index 739217cf7b88dee16e79753ee31d65541d746091..a9aa508ace6ede2459e71ec12ad9d192b89408e4 100644 (file)
@@ -876,6 +876,9 @@ e1000_probe ( struct pci_device *pdev,
        
        e1000_get_hw_control ( adapter );
 
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( netdev );
+
        if ( ( err = register_netdev ( netdev ) ) != 0)
                goto err_register;
                
index 3b915bf05698f609c8285365cf1f992678c24433..e3baa14f28d8ea30c5a1fa088594ba1078f5c56c 100644 (file)
@@ -471,6 +471,12 @@ static int ipoib_transmit ( struct net_device *netdev,
        }
        iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) );
 
+       /* Attempting transmission while link is down will put the
+        * queue pair into an error state, so don't try it.
+        */
+       if ( ! ibdev->link_up )
+               return -ENETUNREACH;
+
        /* Construct address vector */
        memset ( &av, 0, sizeof ( av ) );
        av.qkey = IB_GLOBAL_QKEY;
@@ -790,6 +796,10 @@ static int ipoib_join_broadcast_group ( struct ipoib_device *ipoib ) {
                return rc;
        }
 
+       /* We will set link up on the network device when we receive
+        * the broadcast join response.
+        */
+
        return 0;
 }
 
@@ -907,16 +917,24 @@ static struct net_device_operations ipoib_operations = {
  */
 static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) {
        struct ib_device *ibdev = ipoib->ibdev;
+       struct net_device *netdev = ipoib->netdev;
        struct ipoib_mac *mac;
 
        /* Calculate GID portion of MAC address based on port GID */
-       mac = ( ( struct ipoib_mac * ) ipoib->netdev->ll_addr );
+       mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
        memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) );
 
        /* Calculate broadcast GID based on partition key */
        memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid,
                 sizeof ( ipoib->broadcast_gid ) );
        ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey );
+
+       /* Set net device link state to reflect Infiniband link state */
+       if ( ibdev->link_up ) {
+               netdev_link_up ( netdev );
+       } else {
+               netdev_link_down ( netdev );
+       }
 }
 
 /**
index 32460adba5816e8896c666764687fff5dfcac6cb..cbec3cf5ca9c18e86e63557192cd81f4c14e908b 100644 (file)
@@ -112,6 +112,9 @@ int legacy_probe ( void *hwdev,
         */
        dev->desc.irq = nic.irqno;
 
+       /* Mark as link up; legacy devices don't handle link state */
+       netdev_link_up ( netdev );
+
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err_register;
 
index 536fcb8d7318a12241f3b89577b6d7a6f8d421af..5750706558e3b84f8904633e3ebe4f7b398e5915 100755 (executable)
@@ -1731,6 +1731,9 @@ mtnic_probe(struct pci_device *pci,
                 mac = mac >> 8;
        }
 
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( dev );
+
        if (register_netdev(dev)) {
                eprintf("Netdev registration failed\n");
                return MTNIC_ERROR;
index 98a5ff84851073789411df2922c385da3024a59a..028b905cea4996994a3aef3b54510272a68494f5 100644 (file)
@@ -205,6 +205,9 @@ static int natsemi_probe (struct pci_device *pci,
                last = last1;
        }
 
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( netdev );
+
        if ((rc = register_netdev (netdev)) != 0)
                goto err_register_netdev;
 
index b431ec52a7e3c41e8860ae00b48123f9e2568e53..c7f08670d43c51a264418eb6e73f1051225fc73f 100644 (file)
@@ -250,6 +250,9 @@ static int pnic_probe ( struct pci_device *pci,
        status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
                                netdev->ll_addr, ETH_ALEN, NULL );
 
+       /* Mark as link up; PNIC has no concept of link state */
+       netdev_link_up ( netdev );
+
        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err;
index c432884cd8c85774c52987c39b8f600b74c46755..509047a931dcc8eb61e2e143d033f8f0ce77de9d 100644 (file)
@@ -518,6 +518,9 @@ static int rtl_probe ( struct pci_device *pci,
        rtl_reset ( netdev );
        rtl_init_eeprom ( netdev );
        nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN );
+
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( netdev );
        
        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
index ae8b14809ee506a2d97c128d6725bccf0d14d85d..011ff1f13db94bfaa4ecf38e889f2c697cb5482c 100644 (file)
 #define ERRFILE_uri_test             ( ERRFILE_OTHER | 0x000b0000 )
 #define ERRFILE_ibft                 ( ERRFILE_OTHER | 0x000c0000 )
 #define ERRFILE_tls                  ( ERRFILE_OTHER | 0x000d0000 )
+#define ERRFILE_ifmgmt               ( ERRFILE_OTHER | 0x000e0000 )
 
 /** @} */
 
index d8cb84d083f87ab4300a80b19c8aae184e6ec676..1ef648e11da0f2a64a7c492e0eafab9339fa8fa2 100644 (file)
@@ -254,6 +254,9 @@ struct net_device {
 /** Network device is open */
 #define NETDEV_OPEN 0x0001
 
+/** Network device has link */
+#define NETDEV_LINK_UP 0x0002
+
 /** Declare a link-layer protocol */
 #define __ll_protocol  __table ( struct ll_protocol, ll_protocols, 01 )
 
@@ -352,6 +355,37 @@ netdev_settings ( struct net_device *netdev ) {
        return &netdev->settings.settings;
 }
 
+/**
+ * Mark network device as having link up
+ *
+ * @v netdev           Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_link_up ( struct net_device *netdev ) {
+       netdev->state |= NETDEV_LINK_UP;
+}
+
+/**
+ * Mark network device as having link down
+ *
+ * @v netdev           Network device
+ */
+static inline __attribute__ (( always_inline )) void
+netdev_link_down ( struct net_device *netdev ) {
+       netdev->state &= ~NETDEV_LINK_UP;
+}
+
+/**
+ * Check link state of network device
+ *
+ * @v netdev           Network device
+ * @ret link_up                Link is up
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_link_ok ( struct net_device *netdev ) {
+       return ( netdev->state & NETDEV_LINK_UP );
+}
+
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
 extern void netdev_tx_complete_err ( struct net_device *netdev,
                                 struct io_buffer *iobuf, int rc );
index c7d35da884ccc10b52f2c73cb7d63b629231f990..7b49d3492d1fa8f03980260d171896dbb1eba3df 100644 (file)
@@ -12,5 +12,6 @@ struct net_device;
 extern int ifopen ( struct net_device *netdev );
 extern void ifclose ( struct net_device *netdev );
 extern void ifstat ( struct net_device *netdev );
+extern int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms );
 
 #endif /* _USR_IFMGMT_H */
index c1a61ec049e8fc7dae23b5a6581667aee017b8d8..cff6e95dd817979fbbba9b5368fa6fc64342d47a 100644 (file)
@@ -38,6 +38,9 @@
  *
  */
 
+/** Time to wait for link-up */
+#define LINK_WAIT_MS 15000
+
 /**
  * Identify the boot network device
  *
@@ -136,6 +139,14 @@ static int netboot ( struct net_device *netdev ) {
                return rc;
        ifstat ( netdev );
 
+       /* Wait for link-up */
+       printf ( "Waiting for link-up on %s...", netdev->name );
+       if ( ( rc = iflinkwait ( netdev, LINK_WAIT_MS ) ) != 0 ) {
+               printf ( " no link detected\n" );
+               return rc;
+       }
+       printf ( " ok\n" );
+
        /* Configure device via DHCP */
        if ( ( rc = dhcp ( netdev ) ) != 0 )
                return rc;
index 5f4323de8402d61d28f985ed50545e443d1727c4..9c88ab53151b3c18b11e6c969b6d42425ace46bd 100644 (file)
 
 #include <string.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/device.h>
+#include <gpxe/process.h>
 #include <usr/ifmgmt.h>
 
 /** @file
@@ -61,9 +64,28 @@ void ifclose ( struct net_device *netdev ) {
  * @v netdev           Network device
  */
 void ifstat ( struct net_device *netdev ) {
-       printf ( "%s: %s on %s (%s) TX:%d TXE:%d RX:%d RXE:%d\n",
+       printf ( "%s: %s on %s (%s)\n"
+                "  [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
                 netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name,
                 ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
+                ( netdev_link_ok ( netdev ) ? "up" : "down" ),
                 netdev->stats.tx_ok, netdev->stats.tx_err,
                 netdev->stats.rx_ok, netdev->stats.rx_err );
 }
+
+/**
+ * Wait for link-up
+ *
+ * @v netdev           Network device
+ * @v max_wait_ms      Maximum time to wait, in ms
+ */
+int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) {
+       while ( 1 ) {
+               if ( netdev_link_ok ( netdev ) )
+                       return 0;
+               if ( max_wait_ms-- == 0 )
+                       return -ETIMEDOUT;
+               step();
+               mdelay ( 1 );
+       }
+}