diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c index 2f4bbf2a..b6205542 100644 --- a/src/drivers/net/netfront.c +++ b/src/drivers/net/netfront.c @@ -511,15 +511,12 @@ static void netfront_refill_rx ( struct net_device *netdev ) { struct xen_device *xendev = netfront->xendev; struct io_buffer *iobuf; struct netif_rx_request *request; + unsigned int refilled = 0; int notify; int rc; - /* Do nothing if ring is already full */ - if ( netfront_ring_is_full ( &netfront->rx ) ) - return; - /* Refill ring */ - do { + while ( netfront_ring_fill ( &netfront->rx ) < NETFRONT_RX_FILL ) { /* Allocate I/O buffer */ iobuf = alloc_iob ( PAGE_SIZE ); @@ -543,13 +540,17 @@ static void netfront_refill_rx ( struct net_device *netdev ) { /* Move to next descriptor */ netfront->rx_fring.req_prod_pvt++; + refilled++; - } while ( ! netfront_ring_is_full ( &netfront->rx ) ); + } /* Push new descriptors and notify backend if applicable */ - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, notify ); - if ( notify ) - netfront_send_event ( netfront ); + if ( refilled ) { + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, + notify ); + if ( notify ) + netfront_send_event ( netfront ); + } } /** diff --git a/src/drivers/net/netfront.h b/src/drivers/net/netfront.h index 38fd0a77..c95ed264 100644 --- a/src/drivers/net/netfront.h +++ b/src/drivers/net/netfront.h @@ -16,7 +16,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define NETFRONT_NUM_TX_DESC 16 /** Number of receive ring entries */ -#define NETFRONT_NUM_RX_DESC 8 +#define NETFRONT_NUM_RX_DESC 32 + +/** Receive ring fill level + * + * The xen-netback driver from kernels 3.18 to 4.2 inclusive have a + * bug (CA-163395) which prevents packet reception if fewer than 18 + * receive descriptors are available. This was fixed in upstream + * kernel commit d5d4852 ("xen-netback: require fewer guest Rx slots + * when not using GSO"). + * + * We provide 18 receive descriptors to avoid unpleasant silent + * failures on these kernel versions. + */ +#define NETFRONT_RX_FILL 18 /** Grant reference indices */ enum netfront_ref_index { @@ -88,6 +101,21 @@ netfront_init_ring ( struct netfront_ring *ring, const char *ref_key, ring->ids = ids; } +/** + * Calculate descriptor ring fill level + * + * @v ring Descriptor ring + * @v fill Fill level + */ +static inline __attribute__ (( always_inline )) unsigned int +netfront_ring_fill ( struct netfront_ring *ring ) { + unsigned int fill_level; + + fill_level = ( ring->id_prod - ring->id_cons ); + assert ( fill_level <= ring->count ); + return fill_level; +} + /** * Check whether or not descriptor ring is full * @@ -96,11 +124,8 @@ netfront_init_ring ( struct netfront_ring *ring, const char *ref_key, */ static inline __attribute__ (( always_inline )) int netfront_ring_is_full ( struct netfront_ring *ring ) { - unsigned int fill_level; - fill_level = ( ring->id_prod - ring->id_cons ); - assert ( fill_level <= ring->count ); - return ( fill_level >= ring->count ); + return ( netfront_ring_fill ( ring ) >= ring->count ); } /** @@ -112,7 +137,7 @@ netfront_ring_is_full ( struct netfront_ring *ring ) { static inline __attribute__ (( always_inline )) int netfront_ring_is_empty ( struct netfront_ring *ring ) { - return ( ring->id_prod == ring->id_cons ); + return ( netfront_ring_fill ( ring ) == 0 ); } /** A netfront NIC */