Allow recording of TX and RX errors to aid in end-user debugging.
authorMichael Brown <mcb30@etherboot.org>
Thu, 5 Jul 2007 16:18:27 +0000 (17:18 +0100)
committerMichael Brown <mcb30@etherboot.org>
Thu, 5 Jul 2007 16:18:27 +0000 (17:18 +0100)
src/include/gpxe/netdevice.h
src/interface/pxe/pxe_undi.c
src/net/netdevice.c
src/usr/ifmgmt.c

index 0bc5311..d6b9a1b 100644 (file)
@@ -134,9 +134,13 @@ struct ll_protocol {
  */
 struct net_device_stats {
        /** Count of successfully completed transmissions */
-       unsigned int tx_count;
+       unsigned int tx_ok;
+       /** Count of transmission errors */
+       unsigned int tx_err;
        /** Count of successfully received packets */
-       unsigned int rx_count;
+       unsigned int rx_ok;
+       /** Count of reception errors */
+       unsigned int rx_err;
 };
 
 /**
@@ -189,7 +193,8 @@ struct net_device {
         * owned by the net device's TX queue, and the net device must
         * eventually call netdev_tx_complete() to free the buffer.
         * If this method returns failure, the I/O buffer is
-        * immediately released.
+        * immediately released; the failure is interpreted as
+        * "failure to enqueue buffer".
         *
         * This method is guaranteed to be called only when the device
         * is open.
@@ -289,10 +294,12 @@ netdev_put ( struct net_device *netdev ) {
 }
 
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
-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_tx_complete_err ( struct net_device *netdev,
+                                struct io_buffer *iobuf, int rc );
+extern void netdev_tx_complete_next_err ( struct net_device *netdev, int rc );
 extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf );
+extern void netdev_rx_err ( struct net_device *netdev,
+                           struct io_buffer *iobuf, int rc );
 extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota );
 extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
 extern struct net_device * alloc_netdev ( size_t priv_size );
@@ -308,4 +315,28 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
 extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                    uint16_t net_proto, const void *ll_source );
 
+/**
+ * Complete network transmission
+ *
+ * @v netdev           Network device
+ * @v iobuf            I/O buffer
+ *
+ * The packet must currently be in the network device's TX queue.
+ */
+static inline void netdev_tx_complete ( struct net_device *netdev,
+                                       struct io_buffer *iobuf ) {
+       netdev_tx_complete_err ( netdev, iobuf, 0 );
+}
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev           Network device
+ *
+ * Completes the oldest outstanding packet in the TX queue.
+ */
+static inline void netdev_tx_complete_next ( struct net_device *netdev ) {
+       netdev_tx_complete_next_err ( netdev, 0 );
+}
+
 #endif /* _GPXE_NETDEVICE_H */
index 98c4cb1..cc23de7 100644 (file)
@@ -371,10 +371,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
                                         *undi_get_statistics ) {
        DBG ( "PXENV_UNDI_GET_STATISTICS" );
 
-       undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_count;
-       undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_count;
-       undi_get_statistics->RcvCRCErrors = 0;
-       undi_get_statistics->RcvResourceErrors = 0;
+       undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
+       undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
+       undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
+       undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
 
        undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
index fb4612b..a5c8890 100644 (file)
@@ -74,9 +74,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
        return 0;
 
  err:
-       DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
-              netdev, iobuf, strerror ( rc ) );
-       netdev_tx_complete ( netdev, iobuf );
+       netdev_tx_complete_err ( netdev, iobuf, rc );
        return rc;
 }
 
@@ -85,11 +83,23 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
  *
  * @v netdev           Network device
  * @v iobuf            I/O buffer
+ * @v rc               Packet status code
  *
  * The packet must currently be in the network device's TX queue.
  */
-void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf ) {
-       DBGC ( netdev, "NETDEV %p transmission %p complete\n", netdev, iobuf );
+void netdev_tx_complete_err ( struct net_device *netdev,
+                             struct io_buffer *iobuf, int rc ) {
+
+       /* Update statistics counter */
+       if ( rc == 0 ) {
+               netdev->stats.tx_ok++;
+               DBGC ( netdev, "NETDEV %p transmission %p complete\n",
+                      netdev, iobuf );
+       } else {
+               netdev->stats.tx_err++;
+               DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
+                      netdev, iobuf, strerror ( rc ) );
+       }
 
        /* Catch data corruption as early as possible */
        assert ( iobuf->list.next != NULL );
@@ -98,23 +108,21 @@ void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf ) {
        /* Dequeue and free I/O buffer */
        list_del ( &iobuf->list );
        free_iob ( iobuf );
-
-       /* Update statistics counter */
-       netdev->stats.tx_count++;
 }
 
 /**
  * Complete network transmission
  *
  * @v netdev           Network device
+ * @v rc               Packet status code
  *
  * Completes the oldest outstanding packet in the TX queue.
  */
-void netdev_tx_complete_next ( struct net_device *netdev ) {
+void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) {
        struct io_buffer *iobuf;
 
        list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
-               netdev_tx_complete ( netdev, iobuf );
+               netdev_tx_complete_err ( netdev, iobuf, rc );
                return;
        }
 }
@@ -128,7 +136,7 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
 
        /* Discard any packets in the TX queue */
        while ( ! list_empty ( &netdev->tx_queue ) ) {
-               netdev_tx_complete_next ( netdev );
+               netdev_tx_complete_next_err ( netdev, -ECANCELED );
        }
 }
 
@@ -136,12 +144,13 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
  * Add packet to receive queue
  *
  * @v netdev           Network device
- * @v iobuf            I/O buffer
+ * @v iobuf            I/O buffer, or NULL
  *
  * The packet is added to the network device's RX queue.  This
  * function takes ownership of the I/O buffer.
  */
 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
+
        DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
               netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
 
@@ -149,7 +158,32 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
        list_add_tail ( &iobuf->list, &netdev->rx_queue );
 
        /* Update statistics counter */
-       netdev->stats.rx_count++;
+       netdev->stats.rx_ok++;
+}
+
+/**
+ * Discard received packet
+ *
+ * @v netdev           Network device
+ * @v iobuf            I/O buffer, or NULL
+ * @v rc               Packet status code
+ *
+ * The packet is discarded and an RX error is recorded.  This function
+ * takes ownership of the I/O buffer.  @c iobuf may be NULL if, for
+ * example, the net device wishes to report an error due to being
+ * unable to allocate an I/O buffer.
+ */
+void netdev_rx_err ( struct net_device *netdev,
+                    struct io_buffer *iobuf, int rc ) {
+
+       DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n",
+              netdev, iobuf, strerror ( rc ) );
+
+       /* Discard packet */
+       free_iob ( iobuf );
+
+       /* Update statistics counter */
+       netdev->stats.rx_err++;
 }
 
 /**
@@ -200,9 +234,7 @@ static void netdev_rx_flush ( struct net_device *netdev ) {
 
        /* Discard any packets in the RX queue */
        while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
-               DBGC ( netdev, "NETDEV %p discarding received %p\n",
-                      netdev, iobuf );
-               free_iob ( iobuf );
+               netdev_rx_err ( netdev, iobuf, -ECANCELED );
        }
 }
 
index a43c4ca..5f4323d 100644 (file)
@@ -61,8 +61,9 @@ void ifclose ( struct net_device *netdev ) {
  * @v netdev           Network device
  */
 void ifstat ( struct net_device *netdev ) {
-       printf ( "%s: %s on %s (%s) TX:%d RX:%d\n",
+       printf ( "%s: %s on %s (%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->stats.tx_count, netdev->stats.rx_count );
+                netdev->stats.tx_ok, netdev->stats.tx_err,
+                netdev->stats.rx_ok, netdev->stats.rx_err );
 }