diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index c68808336c8c..fe576e75a538 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -43,6 +43,7 @@ struct virtnet_info | |||
43 | struct virtqueue *rvq, *svq; | 43 | struct virtqueue *rvq, *svq; |
44 | struct net_device *dev; | 44 | struct net_device *dev; |
45 | struct napi_struct napi; | 45 | struct napi_struct napi; |
46 | unsigned int status; | ||
46 | 47 | ||
47 | /* The skb we couldn't send because buffers were full. */ | 48 | /* The skb we couldn't send because buffers were full. */ |
48 | struct sk_buff *last_xmit_skb; | 49 | struct sk_buff *last_xmit_skb; |
@@ -375,9 +376,9 @@ static void skb_recv_done(struct virtqueue *rvq) | |||
375 | { | 376 | { |
376 | struct virtnet_info *vi = rvq->vdev->priv; | 377 | struct virtnet_info *vi = rvq->vdev->priv; |
377 | /* Schedule NAPI, Suppress further interrupts if successful. */ | 378 | /* Schedule NAPI, Suppress further interrupts if successful. */ |
378 | if (netif_rx_schedule_prep(&vi->napi)) { | 379 | if (napi_schedule_prep(&vi->napi)) { |
379 | rvq->vq_ops->disable_cb(rvq); | 380 | rvq->vq_ops->disable_cb(rvq); |
380 | __netif_rx_schedule(&vi->napi); | 381 | __napi_schedule(&vi->napi); |
381 | } | 382 | } |
382 | } | 383 | } |
383 | 384 | ||
@@ -403,11 +404,11 @@ again: | |||
403 | 404 | ||
404 | /* Out of packets? */ | 405 | /* Out of packets? */ |
405 | if (received < budget) { | 406 | if (received < budget) { |
406 | netif_rx_complete(napi); | 407 | napi_complete(napi); |
407 | if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) | 408 | if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) |
408 | && napi_schedule_prep(napi)) { | 409 | && napi_schedule_prep(napi)) { |
409 | vi->rvq->vq_ops->disable_cb(vi->rvq); | 410 | vi->rvq->vq_ops->disable_cb(vi->rvq); |
410 | __netif_rx_schedule(napi); | 411 | __napi_schedule(napi); |
411 | goto again; | 412 | goto again; |
412 | } | 413 | } |
413 | } | 414 | } |
@@ -581,9 +582,9 @@ static int virtnet_open(struct net_device *dev) | |||
581 | * won't get another interrupt, so process any outstanding packets | 582 | * won't get another interrupt, so process any outstanding packets |
582 | * now. virtnet_poll wants re-enable the queue, so we disable here. | 583 | * now. virtnet_poll wants re-enable the queue, so we disable here. |
583 | * We synchronize against interrupts via NAPI_STATE_SCHED */ | 584 | * We synchronize against interrupts via NAPI_STATE_SCHED */ |
584 | if (netif_rx_schedule_prep(&vi->napi)) { | 585 | if (napi_schedule_prep(&vi->napi)) { |
585 | vi->rvq->vq_ops->disable_cb(vi->rvq); | 586 | vi->rvq->vq_ops->disable_cb(vi->rvq); |
586 | __netif_rx_schedule(&vi->napi); | 587 | __napi_schedule(&vi->napi); |
587 | } | 588 | } |
588 | return 0; | 589 | return 0; |
589 | } | 590 | } |
@@ -612,6 +613,7 @@ static struct ethtool_ops virtnet_ethtool_ops = { | |||
612 | .set_tx_csum = virtnet_set_tx_csum, | 613 | .set_tx_csum = virtnet_set_tx_csum, |
613 | .set_sg = ethtool_op_set_sg, | 614 | .set_sg = ethtool_op_set_sg, |
614 | .set_tso = ethtool_op_set_tso, | 615 | .set_tso = ethtool_op_set_tso, |
616 | .get_link = ethtool_op_get_link, | ||
615 | }; | 617 | }; |
616 | 618 | ||
617 | #define MIN_MTU 68 | 619 | #define MIN_MTU 68 |
@@ -637,6 +639,41 @@ static const struct net_device_ops virtnet_netdev = { | |||
637 | #endif | 639 | #endif |
638 | }; | 640 | }; |
639 | 641 | ||
642 | static void virtnet_update_status(struct virtnet_info *vi) | ||
643 | { | ||
644 | u16 v; | ||
645 | |||
646 | if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) | ||
647 | return; | ||
648 | |||
649 | vi->vdev->config->get(vi->vdev, | ||
650 | offsetof(struct virtio_net_config, status), | ||
651 | &v, sizeof(v)); | ||
652 | |||
653 | /* Ignore unknown (future) status bits */ | ||
654 | v &= VIRTIO_NET_S_LINK_UP; | ||
655 | |||
656 | if (vi->status == v) | ||
657 | return; | ||
658 | |||
659 | vi->status = v; | ||
660 | |||
661 | if (vi->status & VIRTIO_NET_S_LINK_UP) { | ||
662 | netif_carrier_on(vi->dev); | ||
663 | netif_wake_queue(vi->dev); | ||
664 | } else { | ||
665 | netif_carrier_off(vi->dev); | ||
666 | netif_stop_queue(vi->dev); | ||
667 | } | ||
668 | } | ||
669 | |||
670 | static void virtnet_config_changed(struct virtio_device *vdev) | ||
671 | { | ||
672 | struct virtnet_info *vi = vdev->priv; | ||
673 | |||
674 | virtnet_update_status(vi); | ||
675 | } | ||
676 | |||
640 | static int virtnet_probe(struct virtio_device *vdev) | 677 | static int virtnet_probe(struct virtio_device *vdev) |
641 | { | 678 | { |
642 | int err; | 679 | int err; |
@@ -739,6 +776,9 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
739 | goto unregister; | 776 | goto unregister; |
740 | } | 777 | } |
741 | 778 | ||
779 | vi->status = VIRTIO_NET_S_LINK_UP; | ||
780 | virtnet_update_status(vi); | ||
781 | |||
742 | pr_debug("virtnet: registered device %s\n", dev->name); | 782 | pr_debug("virtnet: registered device %s\n", dev->name); |
743 | return 0; | 783 | return 0; |
744 | 784 | ||
@@ -794,7 +834,7 @@ static unsigned int features[] = { | |||
794 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, | 834 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, |
795 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, | 835 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, |
796 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ | 836 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ |
797 | VIRTIO_NET_F_MRG_RXBUF, | 837 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, |
798 | VIRTIO_F_NOTIFY_ON_EMPTY, | 838 | VIRTIO_F_NOTIFY_ON_EMPTY, |
799 | }; | 839 | }; |
800 | 840 | ||
@@ -806,6 +846,7 @@ static struct virtio_driver virtio_net = { | |||
806 | .id_table = id_table, | 846 | .id_table = id_table, |
807 | .probe = virtnet_probe, | 847 | .probe = virtnet_probe, |
808 | .remove = __devexit_p(virtnet_remove), | 848 | .remove = __devexit_p(virtnet_remove), |
849 | .config_changed = virtnet_config_changed, | ||
809 | }; | 850 | }; |
810 | 851 | ||
811 | static int __init init(void) | 852 | static int __init init(void) |