diff options
| -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 = { |
