aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/virtio_net.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-06-08 06:51:55 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-06-10 18:20:32 -0400
commit363f15149cfba67d29f1e6a6103dda079f27f3fa (patch)
treeba1bfb698d5d0ff7590f2dfca3961d40bb2f199c /drivers/net/virtio_net.c
parent14c998f034bdc9a5bfa53bca18fbd0738cbc65e8 (diff)
virtio: use callback on empty in virtio_net
virtio_net uses a timer to free old transmitted packets, rather than leaving callbacks enabled all the time. If the host promises to always notify us when the transmit ring is empty, we can free packets at that point and avoid the timer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r--drivers/net/virtio_net.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 156d76fee164..4452306d5328 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -44,6 +44,7 @@ struct virtnet_info
44 /* The skb we couldn't send because buffers were full. */ 44 /* The skb we couldn't send because buffers were full. */
45 struct sk_buff *last_xmit_skb; 45 struct sk_buff *last_xmit_skb;
46 46
47 /* If we need to free in a timer, this is it. */
47 struct timer_list xmit_free_timer; 48 struct timer_list xmit_free_timer;
48 49
49 /* Number of input buffers, and max we've ever had. */ 50 /* Number of input buffers, and max we've ever had. */
@@ -51,6 +52,7 @@ struct virtnet_info
51 52
52 /* For cleaning up after transmission. */ 53 /* For cleaning up after transmission. */
53 struct tasklet_struct tasklet; 54 struct tasklet_struct tasklet;
55 bool free_in_tasklet;
54 56
55 /* Receive & send queues. */ 57 /* Receive & send queues. */
56 struct sk_buff_head recv; 58 struct sk_buff_head recv;
@@ -74,7 +76,7 @@ static void skb_xmit_done(struct virtqueue *svq)
74 /* Suppress further interrupts. */ 76 /* Suppress further interrupts. */
75 svq->vq_ops->disable_cb(svq); 77 svq->vq_ops->disable_cb(svq);
76 78
77 /* We were waiting for more output buffers. */ 79 /* We were probably waiting for more output buffers. */
78 netif_wake_queue(vi->dev); 80 netif_wake_queue(vi->dev);
79 81
80 /* Make sure we re-xmit last_xmit_skb: if there are no more packets 82 /* Make sure we re-xmit last_xmit_skb: if there are no more packets
@@ -242,6 +244,8 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
242 } 244 }
243} 245}
244 246
247/* If the virtio transport doesn't always notify us when all in-flight packets
248 * are consumed, we fall back to using this function on a timer to free them. */
245static void xmit_free(unsigned long data) 249static void xmit_free(unsigned long data)
246{ 250{
247 struct virtnet_info *vi = (void *)data; 251 struct virtnet_info *vi = (void *)data;
@@ -302,7 +306,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
302 num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; 306 num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
303 307
304 err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); 308 err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
305 if (!err) 309 if (!err && !vi->free_in_tasklet)
306 mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); 310 mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
307 311
308 return err; 312 return err;
@@ -317,6 +321,8 @@ static void xmit_tasklet(unsigned long data)
317 vi->svq->vq_ops->kick(vi->svq); 321 vi->svq->vq_ops->kick(vi->svq);
318 vi->last_xmit_skb = NULL; 322 vi->last_xmit_skb = NULL;
319 } 323 }
324 if (vi->free_in_tasklet)
325 free_old_xmit_skbs(vi);
320 netif_tx_unlock_bh(vi->dev); 326 netif_tx_unlock_bh(vi->dev);
321} 327}
322 328
@@ -457,6 +463,10 @@ static int virtnet_probe(struct virtio_device *vdev)
457 vi->vdev = vdev; 463 vi->vdev = vdev;
458 vdev->priv = vi; 464 vdev->priv = vi;
459 465
466 /* If they give us a callback when all buffers are done, we don't need
467 * the timer. */
468 vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY);
469
460 /* We expect two virtqueues, receive then send. */ 470 /* We expect two virtqueues, receive then send. */
461 vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); 471 vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
462 if (IS_ERR(vi->rvq)) { 472 if (IS_ERR(vi->rvq)) {
@@ -476,7 +486,8 @@ static int virtnet_probe(struct virtio_device *vdev)
476 486
477 tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); 487 tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi);
478 488
479 setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi); 489 if (!vi->free_in_tasklet)
490 setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
480 491
481 err = register_netdev(dev); 492 err = register_netdev(dev);
482 if (err) { 493 if (err) {
@@ -515,7 +526,8 @@ static void virtnet_remove(struct virtio_device *vdev)
515 /* Stop all the virtqueues. */ 526 /* Stop all the virtqueues. */
516 vdev->config->reset(vdev); 527 vdev->config->reset(vdev);
517 528
518 del_timer_sync(&vi->xmit_free_timer); 529 if (!vi->free_in_tasklet)
530 del_timer_sync(&vi->xmit_free_timer);
519 531
520 /* Free our skbs in send and recv queues, if any. */ 532 /* Free our skbs in send and recv queues, if any. */
521 while ((skb = __skb_dequeue(&vi->recv)) != NULL) { 533 while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
@@ -540,7 +552,7 @@ static struct virtio_device_id id_table[] = {
540static unsigned int features[] = { 552static unsigned int features[] = {
541 VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, 553 VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
542 VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, 554 VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
543 VIRTIO_NET_F_HOST_ECN, 555 VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY,
544}; 556};
545 557
546static struct virtio_driver virtio_net = { 558static struct virtio_driver virtio_net = {