Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[sfrench/cifs-2.6.git] / drivers / net / virtio_net.c
index 3492ae0951decca6d714951c3a2e2cdaf911aecd..19fd4cb0ddf8583cbd9235b6085a7ad1100dfa19 100644 (file)
 #include <linux/virtio_net.h>
 #include <linux/scatterlist.h>
 
+static int napi_weight = 128;
+module_param(napi_weight, int, 0444);
+
+static int csum = 1, gso = 1;
+module_param(csum, bool, 0444);
+module_param(gso, bool, 0444);
+
 /* FIXME: MTU in config. */
 #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
 
@@ -52,11 +59,13 @@ static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
        sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
 }
 
-static void skb_xmit_done(struct virtqueue *rvq)
+static void skb_xmit_done(struct virtqueue *svq)
 {
-       struct virtnet_info *vi = rvq->vdev->priv;
+       struct virtnet_info *vi = svq->vdev->priv;
 
-       /* In case we were waiting for output buffers. */
+       /* Suppress further interrupts. */
+       svq->vq_ops->disable_cb(svq);
+       /* We were waiting for more output buffers. */
        netif_wake_queue(vi->dev);
 }
 
@@ -88,13 +97,10 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 
        if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                pr_debug("GSO!\n");
-               switch (hdr->gso_type) {
+               switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
                case VIRTIO_NET_HDR_GSO_TCPV4:
                        skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
                        break;
-               case VIRTIO_NET_HDR_GSO_TCPV4_ECN:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN;
-                       break;
                case VIRTIO_NET_HDR_GSO_UDP:
                        skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
                        break;
@@ -108,6 +114,9 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
                        goto frame_err;
                }
 
+               if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+                       skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+
                skb_shinfo(skb)->gso_size = hdr->gso_size;
                if (skb_shinfo(skb)->gso_size == 0) {
                        if (net_ratelimit())
@@ -228,8 +237,6 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
 
-       free_old_xmit_skbs(vi);
-
        /* Encode metadata header at front. */
        hdr = skb_vnet_hdr(skb);
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -244,9 +251,7 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb_is_gso(skb)) {
                hdr->hdr_len = skb_transport_header(skb) - skb->data;
                hdr->gso_size = skb_shinfo(skb)->gso_size;
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
-                       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
-               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
                else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
@@ -254,6 +259,8 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
                else
                        BUG();
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
+                       hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
        } else {
                hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
                hdr->gso_size = hdr->hdr_len = 0;
@@ -262,11 +269,24 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
        vnet_hdr_to_sg(sg, skb);
        num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
        __skb_queue_head(&vi->send, skb);
+
+again:
+       /* Free up any pending old buffers before queueing new ones. */
+       free_old_xmit_skbs(vi);
        err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
        if (err) {
                pr_debug("%s: virtio not prepared to send\n", dev->name);
-               skb_unlink(skb, &vi->send);
                netif_stop_queue(dev);
+
+               /* Activate callback for using skbs: if this fails it
+                * means some were used in the meantime. */
+               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+                       printk("Unlikely: restart svq failed\n");
+                       netif_start_queue(dev);
+                       goto again;
+               }
+               __skb_unlink(skb, &vi->send);
+
                return NETDEV_TX_BUSY;
        }
        vi->svq->vq_ops->kick(vi->svq);
@@ -278,35 +298,25 @@ static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
-       try_fill_recv(vi);
-
-       /* If we didn't even get one input buffer, we're useless. */
-       if (vi->num == 0)
-               return -ENOMEM;
-
        napi_enable(&vi->napi);
+
+       /* If all buffers were filled by other side before we napi_enabled, we
+        * won't get another interrupt, so process any outstanding packets
+        * now.  virtnet_poll wants re-enable the queue, so we disable here.
+        * We synchronize against interrupts via NAPI_STATE_SCHED */
+       if (netif_rx_schedule_prep(dev, &vi->napi)) {
+               vi->rvq->vq_ops->disable_cb(vi->rvq);
+               __netif_rx_schedule(dev, &vi->napi);
+       }
        return 0;
 }
 
 static int virtnet_close(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
-       struct sk_buff *skb;
 
        napi_disable(&vi->napi);
 
-       /* networking core has neutered skb_xmit_done/skb_recv_done, so don't
-        * worry about races vs. get(). */
-       vi->rvq->vq_ops->shutdown(vi->rvq);
-       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
-               kfree_skb(skb);
-               vi->num--;
-       }
-       vi->svq->vq_ops->shutdown(vi->svq);
-       while ((skb = __skb_dequeue(&vi->send)) != NULL)
-               kfree_skb(skb);
-
-       BUG_ON(vi->num != 0);
        return 0;
 }
 
@@ -322,7 +332,6 @@ static int virtnet_probe(struct virtio_device *vdev)
                return -ENOMEM;
 
        /* Set up network device as normal. */
-       ether_setup(dev);
        dev->open = virtnet_open;
        dev->stop = virtnet_close;
        dev->hard_start_xmit = start_xmit;
@@ -330,17 +339,13 @@ static int virtnet_probe(struct virtio_device *vdev)
        SET_NETDEV_DEV(dev, &vdev->dev);
 
        /* Do we support "hardware" checksums? */
-       if (vdev->config->feature(vdev, VIRTIO_NET_F_NO_CSUM)) {
+       if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
                /* This opens up the world of extra features. */
                dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
-               if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO4))
-                       dev->features |= NETIF_F_TSO;
-               if (vdev->config->feature(vdev, VIRTIO_NET_F_UFO))
-                       dev->features |= NETIF_F_UFO;
-               if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO4_ECN))
-                       dev->features |= NETIF_F_TSO_ECN;
-               if (vdev->config->feature(vdev, VIRTIO_NET_F_TSO6))
-                       dev->features |= NETIF_F_TSO6;
+               if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+                       dev->features |= NETIF_F_TSO | NETIF_F_UFO
+                               | NETIF_F_TSO_ECN | NETIF_F_TSO6;
+               }
        }
 
        /* Configuration may specify what MAC to use.  Otherwise random. */
@@ -353,9 +358,10 @@ static int virtnet_probe(struct virtio_device *vdev)
 
        /* Set up our device-specific information */
        vi = netdev_priv(dev);
-       netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+       netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
        vi->dev = dev;
        vi->vdev = vdev;
+       vdev->priv = vi;
 
        /* We expect two virtqueues, receive then send. */
        vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
@@ -379,10 +385,21 @@ static int virtnet_probe(struct virtio_device *vdev)
                pr_debug("virtio_net: registering device failed\n");
                goto free_send;
        }
+
+       /* Last of all, set up some receive buffers. */
+       try_fill_recv(vi);
+
+       /* If we didn't even get one input buffer, we're useless. */
+       if (vi->num == 0) {
+               err = -ENOMEM;
+               goto unregister;
+       }
+
        pr_debug("virtnet: registered device %s\n", dev->name);
-       vdev->priv = vi;
        return 0;
 
+unregister:
+       unregister_netdev(dev);
 free_send:
        vdev->config->del_vq(vi->svq);
 free_recv:
@@ -395,6 +412,20 @@ free:
 static void virtnet_remove(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
+       struct sk_buff *skb;
+
+       /* Stop all the virtqueues. */
+       vdev->config->reset(vdev);
+
+       /* Free our skbs in send and recv queues, if any. */
+       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
+               kfree_skb(skb);
+               vi->num--;
+       }
+       while ((skb = __skb_dequeue(&vi->send)) != NULL)
+               kfree_skb(skb);
+
+       BUG_ON(vi->num != 0);
 
        vdev->config->del_vq(vi->svq);
        vdev->config->del_vq(vi->rvq);