mirror of
https://github.com/ipxe/ipxe
synced 2025-12-20 12:00:19 +03:00
Allow recording of TX and RX errors to aid in end-user debugging.
This commit is contained in:
@@ -134,9 +134,13 @@ struct ll_protocol {
|
|||||||
*/
|
*/
|
||||||
struct net_device_stats {
|
struct net_device_stats {
|
||||||
/** Count of successfully completed transmissions */
|
/** 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 */
|
/** 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
|
* owned by the net device's TX queue, and the net device must
|
||||||
* eventually call netdev_tx_complete() to free the buffer.
|
* eventually call netdev_tx_complete() to free the buffer.
|
||||||
* If this method returns failure, the I/O buffer is
|
* 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
|
* This method is guaranteed to be called only when the device
|
||||||
* is open.
|
* 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 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||||
extern void netdev_tx_complete ( struct net_device *netdev,
|
extern void netdev_tx_complete_err ( struct net_device *netdev,
|
||||||
struct io_buffer *iobuf );
|
struct io_buffer *iobuf, int rc );
|
||||||
extern void netdev_tx_complete_next ( struct net_device *netdev );
|
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 ( 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 int netdev_poll ( struct net_device *netdev, unsigned int rx_quota );
|
||||||
extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
|
extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
|
||||||
extern struct net_device * alloc_netdev ( size_t priv_size );
|
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,
|
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||||
uint16_t net_proto, const void *ll_source );
|
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 */
|
#endif /* _GPXE_NETDEVICE_H */
|
||||||
|
|||||||
@@ -371,10 +371,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
|
|||||||
*undi_get_statistics ) {
|
*undi_get_statistics ) {
|
||||||
DBG ( "PXENV_UNDI_GET_STATISTICS" );
|
DBG ( "PXENV_UNDI_GET_STATISTICS" );
|
||||||
|
|
||||||
undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_count;
|
undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
|
||||||
undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_count;
|
undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
|
||||||
undi_get_statistics->RcvCRCErrors = 0;
|
undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
|
||||||
undi_get_statistics->RcvResourceErrors = 0;
|
undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
|
||||||
|
|
||||||
undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
|
undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
|
||||||
return PXENV_EXIT_SUCCESS;
|
return PXENV_EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -74,9 +74,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
|
netdev_tx_complete_err ( netdev, iobuf, rc );
|
||||||
netdev, iobuf, strerror ( rc ) );
|
|
||||||
netdev_tx_complete ( netdev, iobuf );
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +83,23 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
|||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v iobuf I/O buffer
|
* @v iobuf I/O buffer
|
||||||
|
* @v rc Packet status code
|
||||||
*
|
*
|
||||||
* The packet must currently be in the network device's TX queue.
|
* The packet must currently be in the network device's TX queue.
|
||||||
*/
|
*/
|
||||||
void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
void netdev_tx_complete_err ( struct net_device *netdev,
|
||||||
DBGC ( netdev, "NETDEV %p transmission %p complete\n", netdev, iobuf );
|
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 */
|
/* Catch data corruption as early as possible */
|
||||||
assert ( iobuf->list.next != NULL );
|
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 */
|
/* Dequeue and free I/O buffer */
|
||||||
list_del ( &iobuf->list );
|
list_del ( &iobuf->list );
|
||||||
free_iob ( iobuf );
|
free_iob ( iobuf );
|
||||||
|
|
||||||
/* Update statistics counter */
|
|
||||||
netdev->stats.tx_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete network transmission
|
* Complete network transmission
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
|
* @v rc Packet status code
|
||||||
*
|
*
|
||||||
* Completes the oldest outstanding packet in the TX queue.
|
* 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;
|
struct io_buffer *iobuf;
|
||||||
|
|
||||||
list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
|
list_for_each_entry ( iobuf, &netdev->tx_queue, list ) {
|
||||||
netdev_tx_complete ( netdev, iobuf );
|
netdev_tx_complete_err ( netdev, iobuf, rc );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +136,7 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
|
|||||||
|
|
||||||
/* Discard any packets in the TX queue */
|
/* Discard any packets in the TX queue */
|
||||||
while ( ! list_empty ( &netdev->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
|
* Add packet to receive queue
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @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
|
* The packet is added to the network device's RX queue. This
|
||||||
* function takes ownership of the I/O buffer.
|
* function takes ownership of the I/O buffer.
|
||||||
*/
|
*/
|
||||||
void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
||||||
|
|
||||||
DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
|
DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n",
|
||||||
netdev, iobuf, iobuf->data, iob_len ( iobuf ) );
|
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 );
|
list_add_tail ( &iobuf->list, &netdev->rx_queue );
|
||||||
|
|
||||||
/* Update statistics counter */
|
/* 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 */
|
/* Discard any packets in the RX queue */
|
||||||
while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
|
while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
|
||||||
DBGC ( netdev, "NETDEV %p discarding received %p\n",
|
netdev_rx_err ( netdev, iobuf, -ECANCELED );
|
||||||
netdev, iobuf );
|
|
||||||
free_iob ( iobuf );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,9 @@ void ifclose ( struct net_device *netdev ) {
|
|||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
*/
|
*/
|
||||||
void ifstat ( struct net_device *netdev ) {
|
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->name, netdev_hwaddr ( netdev ), netdev->dev->name,
|
||||||
( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
|
( ( 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 );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user