diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4e0cbbcd60a7..d75256bd1a6a 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -540,8 +540,8 @@ static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp) skb_put(skb, GOOD_PACKET_LEN); hdr = skb_vnet_hdr(skb); + sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); sg_set_buf(rq->sg, &hdr->hdr, sizeof hdr->hdr); - skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp); @@ -557,6 +557,8 @@ static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp) char *p; int i, err, offset; + sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); + /* page in rq->sg[MAX_SKB_FRAGS + 1] is list tail */ for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { first = get_a_page(rq, gfp); @@ -893,6 +895,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (vi->mergeable_rx_bufs) hdr->mhdr.num_buffers = 0; + sg_init_table(sq->sg, MAX_SKB_FRAGS + 2); if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); @@ -911,6 +914,8 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) int qnum = skb_get_queue_mapping(skb); struct send_queue *sq = &vi->sq[qnum]; int err; + struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum); + bool kick = !skb->xmit_more; /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(sq); @@ -928,7 +933,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); return NETDEV_TX_OK; } - virtqueue_kick(sq->vq); /* Don't wait up for transmitted skbs to be freed. */ skb_orphan(skb); @@ -948,6 +952,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) } } + if (kick || netif_xmit_stopped(txq)) + virtqueue_kick(sq->vq); + return NETDEV_TX_OK; } |