diff options
-rw-r--r-- | drivers/net/virtio_net.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9a3b85e55ccc..156d76fee164 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -44,6 +44,8 @@ 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 | struct timer_list xmit_free_timer; | ||
48 | |||
47 | /* Number of input buffers, and max we've ever had. */ | 49 | /* Number of input buffers, and max we've ever had. */ |
48 | unsigned int num, max; | 50 | unsigned int num, max; |
49 | 51 | ||
@@ -240,9 +242,23 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) | |||
240 | } | 242 | } |
241 | } | 243 | } |
242 | 244 | ||
245 | static void xmit_free(unsigned long data) | ||
246 | { | ||
247 | struct virtnet_info *vi = (void *)data; | ||
248 | |||
249 | netif_tx_lock(vi->dev); | ||
250 | |||
251 | free_old_xmit_skbs(vi); | ||
252 | |||
253 | if (!skb_queue_empty(&vi->send)) | ||
254 | mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); | ||
255 | |||
256 | netif_tx_unlock(vi->dev); | ||
257 | } | ||
258 | |||
243 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | 259 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) |
244 | { | 260 | { |
245 | int num; | 261 | int num, err; |
246 | struct scatterlist sg[2+MAX_SKB_FRAGS]; | 262 | struct scatterlist sg[2+MAX_SKB_FRAGS]; |
247 | struct virtio_net_hdr *hdr; | 263 | struct virtio_net_hdr *hdr; |
248 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | 264 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; |
@@ -285,7 +301,11 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
285 | vnet_hdr_to_sg(sg, skb); | 301 | vnet_hdr_to_sg(sg, skb); |
286 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; | 302 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; |
287 | 303 | ||
288 | return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); | 304 | err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); |
305 | if (!err) | ||
306 | mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); | ||
307 | |||
308 | return err; | ||
289 | } | 309 | } |
290 | 310 | ||
291 | static void xmit_tasklet(unsigned long data) | 311 | static void xmit_tasklet(unsigned long data) |
@@ -456,6 +476,8 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
456 | 476 | ||
457 | tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); | 477 | tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); |
458 | 478 | ||
479 | setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi); | ||
480 | |||
459 | err = register_netdev(dev); | 481 | err = register_netdev(dev); |
460 | if (err) { | 482 | if (err) { |
461 | pr_debug("virtio_net: registering device failed\n"); | 483 | pr_debug("virtio_net: registering device failed\n"); |
@@ -493,6 +515,8 @@ static void virtnet_remove(struct virtio_device *vdev) | |||
493 | /* Stop all the virtqueues. */ | 515 | /* Stop all the virtqueues. */ |
494 | vdev->config->reset(vdev); | 516 | vdev->config->reset(vdev); |
495 | 517 | ||
518 | del_timer_sync(&vi->xmit_free_timer); | ||
519 | |||
496 | /* Free our skbs in send and recv queues, if any. */ | 520 | /* Free our skbs in send and recv queues, if any. */ |
497 | while ((skb = __skb_dequeue(&vi->recv)) != NULL) { | 521 | while ((skb = __skb_dequeue(&vi->recv)) != NULL) { |
498 | kfree_skb(skb); | 522 | kfree_skb(skb); |