diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 64 |
1 files changed, 40 insertions, 24 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 420388a4c5e8..effe8c685f77 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* A simple network driver using virtio. | 1 | /* A network driver using virtio. |
2 | * | 2 | * |
3 | * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation | 3 | * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation |
4 | * | 4 | * |
@@ -73,6 +73,7 @@ struct skb_vnet_hdr { | |||
73 | struct virtio_net_hdr hdr; | 73 | struct virtio_net_hdr hdr; |
74 | struct virtio_net_hdr_mrg_rxbuf mhdr; | 74 | struct virtio_net_hdr_mrg_rxbuf mhdr; |
75 | }; | 75 | }; |
76 | unsigned int num_sg; | ||
76 | }; | 77 | }; |
77 | 78 | ||
78 | static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb) | 79 | static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb) |
@@ -442,23 +443,24 @@ again: | |||
442 | return received; | 443 | return received; |
443 | } | 444 | } |
444 | 445 | ||
445 | static void free_old_xmit_skbs(struct virtnet_info *vi) | 446 | static unsigned int free_old_xmit_skbs(struct virtnet_info *vi) |
446 | { | 447 | { |
447 | struct sk_buff *skb; | 448 | struct sk_buff *skb; |
448 | unsigned int len; | 449 | unsigned int len, tot_sgs = 0; |
449 | 450 | ||
450 | while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { | 451 | while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) { |
451 | pr_debug("Sent skb %p\n", skb); | 452 | pr_debug("Sent skb %p\n", skb); |
452 | __skb_unlink(skb, &vi->send); | 453 | __skb_unlink(skb, &vi->send); |
453 | vi->dev->stats.tx_bytes += skb->len; | 454 | vi->dev->stats.tx_bytes += skb->len; |
454 | vi->dev->stats.tx_packets++; | 455 | vi->dev->stats.tx_packets++; |
456 | tot_sgs += skb_vnet_hdr(skb)->num_sg; | ||
455 | kfree_skb(skb); | 457 | kfree_skb(skb); |
456 | } | 458 | } |
459 | return tot_sgs; | ||
457 | } | 460 | } |
458 | 461 | ||
459 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | 462 | static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) |
460 | { | 463 | { |
461 | int num; | ||
462 | struct scatterlist sg[2+MAX_SKB_FRAGS]; | 464 | struct scatterlist sg[2+MAX_SKB_FRAGS]; |
463 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); | 465 | struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb); |
464 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; | 466 | const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; |
@@ -502,13 +504,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) | |||
502 | else | 504 | else |
503 | sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); | 505 | sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr)); |
504 | 506 | ||
505 | num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; | 507 | hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; |
506 | return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); | 508 | return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb); |
507 | } | 509 | } |
508 | 510 | ||
509 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) | 511 | static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) |
510 | { | 512 | { |
511 | struct virtnet_info *vi = netdev_priv(dev); | 513 | struct virtnet_info *vi = netdev_priv(dev); |
514 | int capacity; | ||
512 | 515 | ||
513 | again: | 516 | again: |
514 | /* Free up any pending old buffers before queueing new ones. */ | 517 | /* Free up any pending old buffers before queueing new ones. */ |
@@ -516,27 +519,40 @@ again: | |||
516 | 519 | ||
517 | /* Put new one in send queue and do transmit */ | 520 | /* Put new one in send queue and do transmit */ |
518 | __skb_queue_head(&vi->send, skb); | 521 | __skb_queue_head(&vi->send, skb); |
519 | if (likely(xmit_skb(vi, skb) >= 0)) { | 522 | capacity = xmit_skb(vi, skb); |
520 | vi->svq->vq_ops->kick(vi->svq); | 523 | |
521 | /* Don't wait up for transmitted skbs to be freed. */ | 524 | /* This can happen with OOM and indirect buffers. */ |
522 | skb_orphan(skb); | 525 | if (unlikely(capacity < 0)) { |
523 | nf_reset(skb); | 526 | netif_stop_queue(dev); |
524 | return NETDEV_TX_OK; | 527 | dev_warn(&dev->dev, "Unexpected full queue\n"); |
528 | if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { | ||
529 | vi->svq->vq_ops->disable_cb(vi->svq); | ||
530 | netif_start_queue(dev); | ||
531 | goto again; | ||
532 | } | ||
533 | return NETDEV_TX_BUSY; | ||
525 | } | 534 | } |
526 | 535 | ||
527 | /* Ring too full for this packet, remove it from queue again. */ | 536 | vi->svq->vq_ops->kick(vi->svq); |
528 | pr_debug("%s: virtio not prepared to send\n", dev->name); | 537 | /* Don't wait up for transmitted skbs to be freed. */ |
529 | __skb_unlink(skb, &vi->send); | 538 | skb_orphan(skb); |
530 | netif_stop_queue(dev); | 539 | nf_reset(skb); |
531 | 540 | ||
532 | /* Activate callback for using skbs: if this returns false it | 541 | /* Apparently nice girls don't return TX_BUSY; stop the queue |
533 | * means some were used in the meantime. */ | 542 | * before it gets out of hand. Naturally, this wastes entries. */ |
534 | if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { | 543 | if (capacity < 2+MAX_SKB_FRAGS) { |
535 | vi->svq->vq_ops->disable_cb(vi->svq); | 544 | netif_stop_queue(dev); |
536 | netif_start_queue(dev); | 545 | if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) { |
537 | goto again; | 546 | /* More just got used, free them then recheck. */ |
547 | capacity += free_old_xmit_skbs(vi); | ||
548 | if (capacity >= 2+MAX_SKB_FRAGS) { | ||
549 | netif_start_queue(dev); | ||
550 | vi->svq->vq_ops->disable_cb(vi->svq); | ||
551 | } | ||
552 | } | ||
538 | } | 553 | } |
539 | return NETDEV_TX_BUSY; | 554 | |
555 | return NETDEV_TX_OK; | ||
540 | } | 556 | } |
541 | 557 | ||
542 | static int virtnet_set_mac_address(struct net_device *dev, void *p) | 558 | static int virtnet_set_mac_address(struct net_device *dev, void *p) |