*/
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;
};
/**
* 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.
}
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 );
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 */
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;
}
*
* @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 );
/* 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;
}
}
/* 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 );
}
}
* 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 ) );
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++;
}
/**
/* 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 );
}
}