[netdevice] Add mechanism for reporting detailed link status codes
authorMichael Brown <mcb30@etherboot.org>
Wed, 24 Jun 2009 11:52:38 +0000 (12:52 +0100)
committerMichael Brown <mcb30@etherboot.org>
Wed, 24 Jun 2009 12:04:36 +0000 (13:04 +0100)
Expand the NETDEV_LINK_UP bit into a link_rc status code field,
allowing specific reasons for link failure to be reported via
"ifstat".

Originally-authored-by: Joshua Oreman <oremanj@rwcr.net>
src/hci/strerror.c
src/include/gpxe/netdevice.h
src/net/netdevice.c
src/usr/ifmgmt.c

index 4b16608..216b1e5 100644 (file)
@@ -115,6 +115,7 @@ struct errortab common_errors[] __errortab = {
        { ENOEXEC, "Not an executable image" },
        { ENOMEM, "Out of memory" },
        { ENOSPC, "No space left on device" },
+       { ENOTCONN, "Not connected" },
        { ENOTSUP, "Not supported" },
        { EPERM, "Operation not permitted" },
        { ERANGE, "Out of range" },
index 43c5aa3..70644af 100644 (file)
@@ -267,6 +267,12 @@ struct net_device {
         * This is the bitwise-OR of zero or more NETDEV_XXX constants.
         */
        unsigned int state;
+       /** Link status code
+        *
+        * Zero indicates that the link is up; any other value
+        * indicates the error preventing link-up.
+        */
+       int link_rc;
        /** Maximum packet length
         *
         * This length includes any link-layer headers.
@@ -291,9 +297,6 @@ struct net_device {
 /** Network device is open */
 #define NETDEV_OPEN 0x0001
 
-/** Network device has link */
-#define NETDEV_LINK_UP 0x0002
-
 /** Link-layer protocol table */
 #define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" )
 
@@ -420,17 +423,18 @@ netdev_settings_init ( struct net_device *netdev ) {
  */
 static inline __attribute__ (( always_inline )) void
 netdev_link_up ( struct net_device *netdev ) {
-       netdev->state |= NETDEV_LINK_UP;
+       netdev->link_rc = 0;
 }
 
 /**
- * Mark network device as having link down
+ * Mark network device as having link down due to a specific error
  *
  * @v netdev           Network device
+ * @v rc               Link status code
  */
 static inline __attribute__ (( always_inline )) void
-netdev_link_down ( struct net_device *netdev ) {
-       netdev->state &= ~NETDEV_LINK_UP;
+netdev_link_err ( struct net_device *netdev, int rc ) {
+       netdev->link_rc = rc;
 }
 
 /**
@@ -441,9 +445,10 @@ netdev_link_down ( struct net_device *netdev ) {
  */
 static inline __attribute__ (( always_inline )) int
 netdev_link_ok ( struct net_device *netdev ) {
-       return ( netdev->state & NETDEV_LINK_UP );
+       return ( netdev->link_rc == 0 );
 }
 
+extern void netdev_link_down ( struct net_device *netdev );
 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 c3551ea..e16ebaa 100644 (file)
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <gpxe/process.h>
 #include <gpxe/init.h>
 #include <gpxe/device.h>
+#include <gpxe/errortab.h>
 #include <gpxe/netdevice.h>
 
 /** @file
@@ -44,6 +45,34 @@ struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
 /** List of open network devices, in reverse order of opening */
 struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
 
+/** Default link status code */
+#define EUNKNOWN_LINK_STATUS EINPROGRESS
+
+/** Human-readable message for the default link status */
+struct errortab netdev_errors[] __errortab = {
+       { EUNKNOWN_LINK_STATUS, "Unknown" },
+};
+
+/**
+ * Mark network device as having link down
+ *
+ * @v netdev           Network device
+ */
+void netdev_link_down ( struct net_device *netdev ) {
+
+       switch ( netdev->link_rc ) {
+       case 0:
+       case -EUNKNOWN_LINK_STATUS:
+               netdev->link_rc = -ENOTCONN;
+               break;
+       default:
+               /* Avoid clobbering a more detailed link status code,
+                * if one is already set.
+                */
+               break;
+       }
+}
+
 /**
  * Record network device statistic
  *
@@ -302,6 +331,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
        netdev = zalloc ( total_len );
        if ( netdev ) {
                netdev->refcnt.free = free_netdev;
+               netdev->link_rc = -EUNKNOWN_LINK_STATUS;
                INIT_LIST_HEAD ( &netdev->tx_queue );
                INIT_LIST_HEAD ( &netdev->rx_queue );
                netdev_settings_init ( netdev );
index 9c82503..2c4b3d2 100644 (file)
@@ -94,6 +94,10 @@ void ifstat ( struct net_device *netdev ) {
                 ( netdev_link_ok ( netdev ) ? "up" : "down" ),
                 netdev->tx_stats.good, netdev->tx_stats.bad,
                 netdev->rx_stats.good, netdev->rx_stats.bad );
+       if ( ! netdev_link_ok ( netdev ) ) {
+               printf ( "  [Link status: %s]\n",
+                        strerror ( netdev->link_rc ) );
+       }
        ifstat_errors ( &netdev->tx_stats, "TXE" );
        ifstat_errors ( &netdev->rx_stats, "RXE" );
 }