diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 22 |
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. */ | ||
245 | static void xmit_free(unsigned long data) | 249 | static 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[] = { | |||
540 | static unsigned int features[] = { | 552 | static 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 | ||
546 | static struct virtio_driver virtio_net = { | 558 | static struct virtio_driver virtio_net = { |