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 );
/* 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 );
+ }
}
/**
#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 {
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
*
*/
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 );
}
/**
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 */