Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[deliverable/linux.git] / drivers / net / virtio_net.c
index 6e0a9fefe6cb7fb126b6d37256be7906bf470e75..555b70c8b8635226a1fa295c7334d5d70c34f939 100644 (file)
@@ -24,6 +24,9 @@
 #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);
@@ -56,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);
 }
 
@@ -198,8 +203,11 @@ again:
        if (received < budget) {
                netif_rx_complete(vi->dev, napi);
                if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
-                   && netif_rx_reschedule(vi->dev, napi))
+                   && napi_schedule_prep(napi)) {
+                       vi->rvq->vq_ops->disable_cb(vi->rvq);
+                       __netif_rx_schedule(vi->dev, napi);
                        goto again;
+               }
        }
 
        return received;
@@ -226,13 +234,12 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct scatterlist sg[1+MAX_SKB_FRAGS];
        struct virtio_net_hdr *hdr;
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
-       DECLARE_MAC_BUF(mac);
 
        sg_init_table(sg, 1+MAX_SKB_FRAGS);
 
-       pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
-
-       free_old_xmit_skbs(vi);
+       pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb,
+                dest[0], dest[1], dest[2],
+                dest[3], dest[4], dest[5]);
 
        /* Encode metadata header at front. */
        hdr = skb_vnet_hdr(skb);
@@ -266,11 +273,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 returns false it
+                * means some were used in the meantime. */
+               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+                       vi->svq->vq_ops->disable_cb(vi->svq);
+                       netif_start_queue(dev);
+                       goto again;
+               }
+               __skb_unlink(skb, &vi->send);
+
                return NETDEV_TX_BUSY;
        }
        vi->svq->vq_ops->kick(vi->svq);
@@ -278,11 +298,29 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void virtnet_netpoll(struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+
+       napi_schedule(&vi->napi);
+}
+#endif
+
 static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
        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;
 }
 
@@ -307,11 +345,13 @@ 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;
        dev->features = NETIF_F_HIGHDMA;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = virtnet_netpoll;
+#endif
        SET_NETDEV_DEV(dev, &vdev->dev);
 
        /* Do we support "hardware" checksums? */
@@ -334,9 +374,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);
@@ -371,7 +412,6 @@ static int virtnet_probe(struct virtio_device *vdev)
        }
 
        pr_debug("virtnet: registered device %s\n", dev->name);
-       vdev->priv = vi;
        return 0;
 
 unregister:
This page took 0.037681 seconds and 5 git commands to generate.