]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/net/virtio_net.c
virtio: blk: Add freeze, restore handlers to support S4
[mirror_ubuntu-artful-kernel.git] / drivers / net / virtio_net.c
index d1c3dce15dc2b523aa50c7066107173471c3b342..6345a52194f9f5c670892f0f0360bbe6a0c07bf2 100644 (file)
@@ -156,6 +156,7 @@ static void set_skb_frag(struct sk_buff *skb, struct page *page,
        *len -= size;
 }
 
+/* Called from bottom half context */
 static struct sk_buff *page_to_skb(struct virtnet_info *vi,
                                   struct page *page, unsigned int len)
 {
@@ -358,7 +359,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
        struct skb_vnet_hdr *hdr;
        int err;
 
-       skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
+       skb = __netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN, gfp);
        if (unlikely(!skb))
                return -ENOMEM;
 
@@ -369,7 +370,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 
        skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
        if (err < 0)
                dev_kfree_skb(skb);
 
@@ -414,8 +415,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
 
        /* chain first in list head */
        first->private = (unsigned long)list;
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
-                                   first, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
+                               first, gfp);
        if (err < 0)
                give_pages(vi, first);
 
@@ -433,14 +434,20 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
 
        sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
        if (err < 0)
                give_pages(vi, page);
 
        return err;
 }
 
-/* Returns false if we couldn't fill entirely (OOM). */
+/*
+ * Returns false if we couldn't fill entirely (OOM).
+ *
+ * Normally run in the receive path, but can also be run from ndo_open
+ * before we're receiving packets, or from refill_work which is
+ * careful to disable receiving (using napi_disable).
+ */
 static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
 {
        int err;
@@ -502,7 +509,7 @@ static void refill_work(struct work_struct *work)
        /* In theory, this can happen: if we don't get any buffers in
         * we will *never* try to fill again. */
        if (still_empty)
-               schedule_delayed_work(&vi->refill, HZ/2);
+               queue_delayed_work(system_nrt_wq, &vi->refill, HZ/2);
 }
 
 static int virtnet_poll(struct napi_struct *napi, int budget)
@@ -521,7 +528,7 @@ again:
 
        if (vi->num < vi->max / 2) {
                if (!try_fill_recv(vi, GFP_ATOMIC))
-                       schedule_delayed_work(&vi->refill, 0);
+                       queue_delayed_work(system_nrt_wq, &vi->refill, 0);
        }
 
        /* Out of packets? */
@@ -602,7 +609,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 
        hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
        return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
-                                       0, skb);
+                                0, skb, GFP_ATOMIC);
 }
 
 static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -721,6 +728,10 @@ static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
+       /* Make sure we have some buffers: if oom use wq. */
+       if (!try_fill_recv(vi, GFP_KERNEL))
+               queue_delayed_work(system_nrt_wq, &vi->refill, 0);
+
        virtnet_napi_enable(vi);
        return 0;
 }
@@ -756,7 +767,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
                sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
        sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
 
-       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0);
+       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
 
        virtqueue_kick(vi->cvq);
 
@@ -774,6 +785,8 @@ static int virtnet_close(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
+       /* Make sure refill_work doesn't re-enable napi! */
+       cancel_delayed_work_sync(&vi->refill);
        napi_disable(&vi->napi);
 
        return 0;
@@ -1100,7 +1113,6 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 unregister:
        unregister_netdev(dev);
-       cancel_delayed_work_sync(&vi->refill);
 free_vqs:
        vdev->config->del_vqs(vdev);
 free_stats:
@@ -1139,9 +1151,7 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
-
        unregister_netdev(vi->dev);
-       cancel_delayed_work_sync(&vi->refill);
 
        /* Free unused buffers in both send and recv, if any. */
        free_unused_bufs(vi);