Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / net / virtio_net.c
index 4e0cbbc..d75256b 100644 (file)
@@ -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;
 }