summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/xen-netback/common.h1
-rw-r--r--drivers/net/xen-netback/rx.c27
2 files changed, 18 insertions, 10 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 7d12a388afc6..cf68149cbb55 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -132,6 +132,7 @@ struct xenvif_copy_state {
struct gnttab_copy op[COPY_BATCH_SIZE];
RING_IDX idx[COPY_BATCH_SIZE];
unsigned int num;
+ struct sk_buff_head *completed;
};
struct xenvif_queue { /* Per-queue data for xenvif */
diff --git a/drivers/net/xen-netback/rx.c b/drivers/net/xen-netback/rx.c
index ae822b8fa76d..8c8c5b5883eb 100644
--- a/drivers/net/xen-netback/rx.c
+++ b/drivers/net/xen-netback/rx.c
@@ -133,6 +133,7 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue)
static void xenvif_rx_copy_flush(struct xenvif_queue *queue)
{
unsigned int i;
+ int notify;
gnttab_batch_copy(queue->rx_copy.op, queue->rx_copy.num);
@@ -154,6 +155,13 @@ static void xenvif_rx_copy_flush(struct xenvif_queue *queue)
}
queue->rx_copy.num = 0;
+
+ /* Push responses for all completed packets. */
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, notify);
+ if (notify)
+ notify_remote_via_irq(queue->rx_irq);
+
+ __skb_queue_purge(queue->rx_copy.completed);
}
static void xenvif_rx_copy_add(struct xenvif_queue *queue,
@@ -279,18 +287,10 @@ static void xenvif_rx_next_skb(struct xenvif_queue *queue,
static void xenvif_rx_complete(struct xenvif_queue *queue,
struct xenvif_pkt_state *pkt)
{
- int notify;
-
- /* Complete any outstanding copy ops for this skb. */
- xenvif_rx_copy_flush(queue);
-
- /* Push responses and notify. */
+ /* All responses are ready to be pushed. */
queue->rx.rsp_prod_pvt = queue->rx.req_cons;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, notify);
- if (notify)
- notify_remote_via_irq(queue->rx_irq);
- dev_kfree_skb(pkt->skb);
+ __skb_queue_tail(queue->rx_copy.completed, pkt->skb);
}
static void xenvif_rx_next_chunk(struct xenvif_queue *queue,
@@ -429,13 +429,20 @@ void xenvif_rx_skb(struct xenvif_queue *queue)
void xenvif_rx_action(struct xenvif_queue *queue)
{
+ struct sk_buff_head completed_skbs;
unsigned int work_done = 0;
+ __skb_queue_head_init(&completed_skbs);
+ queue->rx_copy.completed = &completed_skbs;
+
while (xenvif_rx_ring_slots_available(queue) &&
work_done < RX_BATCH_SIZE) {
xenvif_rx_skb(queue);
work_done++;
}
+
+ /* Flush any pending copies and complete all skbs. */
+ xenvif_rx_copy_flush(queue);
}
static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue)