From 4576c2da587eeb884fbf848021d06d1a7d280e3f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 20 Nov 2010 04:56:25 +0000 Subject: [PATCH] [netdevice] Allow per-device receive queue processing to be frozen Several use cases (e.g. the UNDI API and the EFI SNP API) require access to the raw network device receive queue, and so currently use manual calls to netdev_poll() on a specific network device in order to prevent received packets from being processed by the network stack. As an alternative, provide a flag that allows receive queue processing to be frozen on a per-device basis. When receive queue processing is frozen, packets will be enqueued as normal, but will not be automatically dequeued and passed up the network stack. Signed-off-by: Michael Brown --- src/include/ipxe/netdevice.h | 39 ++++++++++++++++++++++++++++++++++-- src/net/netdevice.c | 24 ++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 4649377a..26e2ab89 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -343,6 +343,9 @@ struct net_device { /** Network device interrupts are enabled */ #define NETDEV_IRQ_ENABLED 0x0002 +/** Network device receive queue processing is frozen */ +#define NETDEV_RX_FROZEN 0x0004 + /** Link-layer protocol table */ #define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" ) @@ -505,7 +508,7 @@ netdev_link_ok ( struct net_device *netdev ) { * Check whether or not network device is open * * @v netdev Network device - * @v is_open Network device is open + * @ret is_open Network device is open */ static inline __attribute__ (( always_inline )) int netdev_is_open ( struct net_device *netdev ) { @@ -516,13 +519,24 @@ netdev_is_open ( struct net_device *netdev ) { * Check whether or not network device interrupts are currently enabled * * @v netdev Network device - * @v irq_enabled Network device interrupts are enabled + * @ret irq_enabled Network device interrupts are enabled */ static inline __attribute__ (( always_inline )) int netdev_irq_enabled ( struct net_device *netdev ) { return ( netdev->state & NETDEV_IRQ_ENABLED ); } +/** + * Check whether or not network device receive queue processing is frozen + * + * @v netdev Network device + * @ret rx_frozen Network device receive queue processing is frozen + */ +static inline __attribute__ (( always_inline )) int +netdev_rx_frozen ( struct net_device *netdev ) { + return ( netdev->state & NETDEV_RX_FROZEN ); +} + extern void netdev_link_err ( struct net_device *netdev, int rc ); extern void netdev_link_down ( struct net_device *netdev ); extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -550,6 +564,7 @@ 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_dest, const void *ll_source ); +extern void net_poll ( void ); /** * Complete network transmission @@ -585,4 +600,24 @@ netdev_link_up ( struct net_device *netdev ) { netdev_link_err ( netdev, 0 ); } +/** + * Freeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_freeze ( struct net_device *netdev ) { + netdev->state |= NETDEV_RX_FROZEN; +} + +/** + * Unfreeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_unfreeze ( struct net_device *netdev ) { + netdev->state &= ~NETDEV_RX_FROZEN; +} + #endif /* _IPXE_NETDEVICE_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index c6c377b5..90dab8fb 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -669,14 +669,12 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, } /** - * Single-step the network stack - * - * @v process Network stack process + * Poll the network stack * * This polls all interfaces for received packets, and processes * packets from the RX queue. */ -static void net_step ( struct process *process __unused ) { +void net_poll ( void ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; @@ -691,6 +689,15 @@ static void net_step ( struct process *process __unused ) { /* Poll for new packets */ netdev_poll ( netdev ); + /* Leave received packets on the queue if receive + * queue processing is currently frozen. This will + * happen when the raw packets are to be manually + * dequeued using netdev_rx_dequeue(), rather than + * processed via the usual networking stack. + */ + if ( netdev_rx_frozen ( netdev ) ) + continue; + /* Process at most one received packet. Give priority * to getting packets out of the NIC over processing * the received packets, because we advertise a window @@ -723,6 +730,15 @@ static void net_step ( struct process *process __unused ) { } } +/** + * Single-step the network stack + * + * @v process Network stack process + */ +static void net_step ( struct process *process __unused ) { + net_poll(); +} + /** Networking stack process */ struct process net_process __permanent_process = { .list = LIST_HEAD_INIT ( net_process.list ),