summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-04-22 18:40:50 +0200
committerMichael Brown2008-04-22 18:40:50 +0200
commit1ba959c6b342b314dfb01ca0a926ed6832c090b3 (patch)
treed977e301ebfe46d76f9def376e9edb173b96eb26
parent[Infiniband] Fix event queue doorbell ringing on Arbel (diff)
downloadipxe-1ba959c6b342b314dfb01ca0a926ed6832c090b3.tar.gz
ipxe-1ba959c6b342b314dfb01ca0a926ed6832c090b3.tar.xz
ipxe-1ba959c6b342b314dfb01ca0a926ed6832c090b3.zip
[NETDEV] Add notion of link state
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.
-rw-r--r--src/arch/i386/drivers/net/undinet.c3
-rw-r--r--src/drivers/net/e1000/e1000.c3
-rw-r--r--src/drivers/net/ipoib.c20
-rw-r--r--src/drivers/net/legacy.c3
-rwxr-xr-xsrc/drivers/net/mtnic.c3
-rw-r--r--src/drivers/net/natsemi.c3
-rw-r--r--src/drivers/net/pnic.c3
-rw-r--r--src/drivers/net/rtl8139.c3
-rw-r--r--src/include/gpxe/errfile.h1
-rw-r--r--src/include/gpxe/netdevice.h34
-rw-r--r--src/include/usr/ifmgmt.h1
-rw-r--r--src/usr/autoboot.c11
-rw-r--r--src/usr/ifmgmt.c24
13 files changed, 110 insertions, 2 deletions
diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c
index 07bec560..512c60e9 100644
--- a/src/arch/i386/drivers/net/undinet.c
+++ b/src/arch/i386/drivers/net/undinet.c
@@ -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;
diff --git a/src/drivers/net/e1000/e1000.c b/src/drivers/net/e1000/e1000.c
index 739217cf..a9aa508a 100644
--- a/src/drivers/net/e1000/e1000.c
+++ b/src/drivers/net/e1000/e1000.c
@@ -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;
diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c
index 3b915bf0..e3baa14f 100644
--- a/src/drivers/net/ipoib.c
+++ b/src/drivers/net/ipoib.c
@@ -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 );
+ }
}
/**
diff --git a/src/drivers/net/legacy.c b/src/drivers/net/legacy.c
index 32460adb..cbec3cf5 100644
--- a/src/drivers/net/legacy.c
+++ b/src/drivers/net/legacy.c
@@ -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;
diff --git a/src/drivers/net/mtnic.c b/src/drivers/net/mtnic.c
index 536fcb8d..57507065 100755
--- a/src/drivers/net/mtnic.c
+++ b/src/drivers/net/mtnic.c
@@ -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;
diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c
index 98a5ff84..028b905c 100644
--- a/src/drivers/net/natsemi.c
+++ b/src/drivers/net/natsemi.c
@@ -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;
diff --git a/src/drivers/net/pnic.c b/src/drivers/net/pnic.c
index b431ec52..c7f08670 100644
--- a/src/drivers/net/pnic.c
+++ b/src/drivers/net/pnic.c
@@ -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;
diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c
index c432884c..509047a9 100644
--- a/src/drivers/net/rtl8139.c
+++ b/src/drivers/net/rtl8139.c
@@ -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 )
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index ae8b1480..011ff1f1 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -151,6 +151,7 @@
#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 )
/** @} */
diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h
index d8cb84d0..1ef648e1 100644
--- a/src/include/gpxe/netdevice.h
+++ b/src/include/gpxe/netdevice.h
@@ -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 );
diff --git a/src/include/usr/ifmgmt.h b/src/include/usr/ifmgmt.h
index c7d35da8..7b49d349 100644
--- a/src/include/usr/ifmgmt.h
+++ b/src/include/usr/ifmgmt.h
@@ -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 */
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index c1a61ec0..cff6e95d 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -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;
diff --git a/src/usr/ifmgmt.c b/src/usr/ifmgmt.c
index 5f4323de..9c88ab53 100644
--- a/src/usr/ifmgmt.c
+++ b/src/usr/ifmgmt.c
@@ -18,8 +18,11 @@
#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 );
+ }
+}