summaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/net/netfront.c19
-rw-r--r--src/drivers/net/netfront.h37
2 files changed, 41 insertions, 15 deletions
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 {
@@ -89,6 +102,21 @@ netfront_init_ring ( struct netfront_ring *ring, const char *ref_key,
}
/**
+ * 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
*
* @v ring Descriptor ring
@@ -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 */