tg3: Abort phy init for 5717 serdes devices
[safe/jmp/linux-2.6] / drivers / net / virtio_net.c
index 420388a..c708ecc 100644 (file)
@@ -1,4 +1,4 @@
-/* A simple network driver using virtio.
+/* A network driver using virtio.
  *
  * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
  *
@@ -22,7 +22,6 @@
 #include <linux/ethtool.h>
 #include <linux/module.h>
 #include <linux/virtio.h>
-#include <linux/virtio_ids.h>
 #include <linux/virtio_net.h>
 #include <linux/scatterlist.h>
 #include <linux/if_vlan.h>
@@ -73,6 +72,7 @@ struct skb_vnet_hdr {
                struct virtio_net_hdr hdr;
                struct virtio_net_hdr_mrg_rxbuf mhdr;
        };
+       unsigned int num_sg;
 };
 
 static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
@@ -279,16 +279,15 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
        bool oom = false;
 
        sg_init_table(sg, 2+MAX_SKB_FRAGS);
-       for (;;) {
+       do {
                struct skb_vnet_hdr *hdr;
 
-               skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN);
+               skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
                if (unlikely(!skb)) {
                        oom = true;
                        break;
                }
 
-               skb_reserve(skb, NET_IP_ALIGN);
                skb_put(skb, MAX_PACKET_LEN);
 
                hdr = skb_vnet_hdr(skb);
@@ -322,7 +321,7 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
                        break;
                }
                vi->num++;
-       }
+       } while (err >= num);
        if (unlikely(vi->num > vi->max))
                vi->max = vi->num;
        vi->rvq->vq_ops->kick(vi->rvq);
@@ -340,17 +339,15 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
        if (!vi->mergeable_rx_bufs)
                return try_fill_recv_maxbufs(vi, gfp);
 
-       for (;;) {
+       do {
                skb_frag_t *f;
 
-               skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN);
+               skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
                if (unlikely(!skb)) {
                        oom = true;
                        break;
                }
 
-               skb_reserve(skb, NET_IP_ALIGN);
-
                f = &skb_shinfo(skb)->frags[0];
                f->page = get_a_page(vi, gfp);
                if (!f->page) {
@@ -374,7 +371,7 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
                        break;
                }
                vi->num++;
-       }
+       } while (err > 0);
        if (unlikely(vi->num > vi->max))
                vi->max = vi->num;
        vi->rvq->vq_ops->kick(vi->rvq);
@@ -431,8 +428,8 @@ again:
        /* Out of packets? */
        if (received < budget) {
                napi_complete(napi);
-               if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
-                   && napi_schedule_prep(napi)) {
+               if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) &&
+                   napi_schedule_prep(napi)) {
                        vi->rvq->vq_ops->disable_cb(vi->rvq);
                        __napi_schedule(napi);
                        goto again;
@@ -442,23 +439,24 @@ again:
        return received;
 }
 
-static void free_old_xmit_skbs(struct virtnet_info *vi)
+static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
 {
        struct sk_buff *skb;
-       unsigned int len;
+       unsigned int len, tot_sgs = 0;
 
        while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
                pr_debug("Sent skb %p\n", skb);
                __skb_unlink(skb, &vi->send);
                vi->dev->stats.tx_bytes += skb->len;
                vi->dev->stats.tx_packets++;
-               kfree_skb(skb);
+               tot_sgs += skb_vnet_hdr(skb)->num_sg;
+               dev_kfree_skb_any(skb);
        }
+       return tot_sgs;
 }
 
 static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 {
-       int num;
        struct scatterlist sg[2+MAX_SKB_FRAGS];
        struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
@@ -502,41 +500,63 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
        else
                sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
 
-       num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
-       return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+       hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
+       return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
 }
 
 static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
+       int capacity;
 
 again:
        /* Free up any pending old buffers before queueing new ones. */
        free_old_xmit_skbs(vi);
 
-       /* Put new one in send queue and do transmit */
-       __skb_queue_head(&vi->send, skb);
-       if (likely(xmit_skb(vi, skb) >= 0)) {
-               vi->svq->vq_ops->kick(vi->svq);
-               /* Don't wait up for transmitted skbs to be freed. */
-               skb_orphan(skb);
-               nf_reset(skb);
-               return NETDEV_TX_OK;
+       /* Try to transmit */
+       capacity = xmit_skb(vi, skb);
+
+       /* This can happen with OOM and indirect buffers. */
+       if (unlikely(capacity < 0)) {
+               netif_stop_queue(dev);
+               dev_warn(&dev->dev, "Unexpected full queue\n");
+               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+                       vi->svq->vq_ops->disable_cb(vi->svq);
+                       netif_start_queue(dev);
+                       goto again;
+               }
+               return NETDEV_TX_BUSY;
        }
+       vi->svq->vq_ops->kick(vi->svq);
 
-       /* Ring too full for this packet, remove it from queue again. */
-       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;
+       /*
+        * Put new one in send queue.  You'd expect we'd need this before
+        * xmit_skb calls add_buf(), since the callback can be triggered
+        * immediately after that.  But since the callback just triggers
+        * another call back here, normal network xmit locking prevents the
+        * race.
+        */
+       __skb_queue_head(&vi->send, skb);
+
+       /* Don't wait up for transmitted skbs to be freed. */
+       skb_orphan(skb);
+       nf_reset(skb);
+
+       /* Apparently nice girls don't return TX_BUSY; stop the queue
+        * before it gets out of hand.  Naturally, this wastes entries. */
+       if (capacity < 2+MAX_SKB_FRAGS) {
+               netif_stop_queue(dev);
+               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+                       /* More just got used, free them then recheck. */
+                       capacity += free_old_xmit_skbs(vi);
+                       if (capacity >= 2+MAX_SKB_FRAGS) {
+                               netif_start_queue(dev);
+                               vi->svq->vq_ops->disable_cb(vi->svq);
+                       }
+               }
        }
-       return NETDEV_TX_BUSY;
+
+       return NETDEV_TX_OK;
 }
 
 static int virtnet_set_mac_address(struct net_device *dev, void *p)
@@ -870,9 +890,9 @@ static int virtnet_probe(struct virtio_device *vdev)
        INIT_DELAYED_WORK(&vi->refill, refill_work);
 
        /* If we can receive ANY GSO packets, we must allocate large ones. */
-       if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4)
-           || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6)
-           || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
                vi->big_packets = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
@@ -932,7 +952,7 @@ free:
        return err;
 }
 
-static void virtnet_remove(struct virtio_device *vdev)
+static void __devexit virtnet_remove(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
        struct sk_buff *skb;
@@ -975,7 +995,7 @@ static unsigned int features[] = {
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
 };
 
-static struct virtio_driver virtio_net = {
+static struct virtio_driver virtio_net_driver = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
@@ -988,12 +1008,12 @@ static struct virtio_driver virtio_net = {
 
 static int __init init(void)
 {
-       return register_virtio_driver(&virtio_net);
+       return register_virtio_driver(&virtio_net_driver);
 }
 
 static void __exit fini(void)
 {
-       unregister_virtio_driver(&virtio_net);
+       unregister_virtio_driver(&virtio_net_driver);
 }
 module_init(init);
 module_exit(fini);