diff options
author | Mark McLoughlin <markmc@redhat.com> | 2009-01-19 20:09:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-21 17:34:53 -0500 |
commit | 9f4d26d0f3016cf8813977d624751b94465fa317 (patch) | |
tree | ac17805553ff3b3bc570ed73027b150e7ba3b88b /drivers | |
parent | 357fe2c6d2b12482abd1c3f24a086a2f507f03fc (diff) |
virtio_net: add link status handling
Allow the host to inform us that the link is down by adding
a VIRTIO_NET_F_STATUS which indicates that device status is
available in virtio_net config.
This is currently useful for simulating link down conditions
(e.g. using proposed qemu 'set_link' monitor command) but
would also be needed if we were to support device assignment
via virtio.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (added future masking)
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/virtio_net.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 30ae6d9a12af..9b33d6ebf542 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -42,6 +42,7 @@ struct virtnet_info | |||
42 | struct virtqueue *rvq, *svq; | 42 | struct virtqueue *rvq, *svq; |
43 | struct net_device *dev; | 43 | struct net_device *dev; |
44 | struct napi_struct napi; | 44 | struct napi_struct napi; |
45 | unsigned int status; | ||
45 | 46 | ||
46 | /* The skb we couldn't send because buffers were full. */ | 47 | /* The skb we couldn't send because buffers were full. */ |
47 | struct sk_buff *last_xmit_skb; | 48 | struct sk_buff *last_xmit_skb; |
@@ -611,6 +612,7 @@ static struct ethtool_ops virtnet_ethtool_ops = { | |||
611 | .set_tx_csum = virtnet_set_tx_csum, | 612 | .set_tx_csum = virtnet_set_tx_csum, |
612 | .set_sg = ethtool_op_set_sg, | 613 | .set_sg = ethtool_op_set_sg, |
613 | .set_tso = ethtool_op_set_tso, | 614 | .set_tso = ethtool_op_set_tso, |
615 | .get_link = ethtool_op_get_link, | ||
614 | }; | 616 | }; |
615 | 617 | ||
616 | #define MIN_MTU 68 | 618 | #define MIN_MTU 68 |
@@ -636,6 +638,41 @@ static const struct net_device_ops virtnet_netdev = { | |||
636 | #endif | 638 | #endif |
637 | }; | 639 | }; |
638 | 640 | ||
641 | static void virtnet_update_status(struct virtnet_info *vi) | ||
642 | { | ||
643 | u16 v; | ||
644 | |||
645 | if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) | ||
646 | return; | ||
647 | |||
648 | vi->vdev->config->get(vi->vdev, | ||
649 | offsetof(struct virtio_net_config, status), | ||
650 | &v, sizeof(v)); | ||
651 | |||
652 | /* Ignore unknown (future) status bits */ | ||
653 | v &= VIRTIO_NET_S_LINK_UP; | ||
654 | |||
655 | if (vi->status == v) | ||
656 | return; | ||
657 | |||
658 | vi->status = v; | ||
659 | |||
660 | if (vi->status & VIRTIO_NET_S_LINK_UP) { | ||
661 | netif_carrier_on(vi->dev); | ||
662 | netif_wake_queue(vi->dev); | ||
663 | } else { | ||
664 | netif_carrier_off(vi->dev); | ||
665 | netif_stop_queue(vi->dev); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | static void virtnet_config_changed(struct virtio_device *vdev) | ||
670 | { | ||
671 | struct virtnet_info *vi = vdev->priv; | ||
672 | |||
673 | virtnet_update_status(vi); | ||
674 | } | ||
675 | |||
639 | static int virtnet_probe(struct virtio_device *vdev) | 676 | static int virtnet_probe(struct virtio_device *vdev) |
640 | { | 677 | { |
641 | int err; | 678 | int err; |
@@ -738,6 +775,9 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
738 | goto unregister; | 775 | goto unregister; |
739 | } | 776 | } |
740 | 777 | ||
778 | vi->status = VIRTIO_NET_S_LINK_UP; | ||
779 | virtnet_update_status(vi); | ||
780 | |||
741 | pr_debug("virtnet: registered device %s\n", dev->name); | 781 | pr_debug("virtnet: registered device %s\n", dev->name); |
742 | return 0; | 782 | return 0; |
743 | 783 | ||
@@ -793,7 +833,7 @@ static unsigned int features[] = { | |||
793 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, | 833 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, |
794 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, | 834 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, |
795 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ | 835 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ |
796 | VIRTIO_NET_F_MRG_RXBUF, | 836 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, |
797 | VIRTIO_F_NOTIFY_ON_EMPTY, | 837 | VIRTIO_F_NOTIFY_ON_EMPTY, |
798 | }; | 838 | }; |
799 | 839 | ||
@@ -805,6 +845,7 @@ static struct virtio_driver virtio_net = { | |||
805 | .id_table = id_table, | 845 | .id_table = id_table, |
806 | .probe = virtnet_probe, | 846 | .probe = virtnet_probe, |
807 | .remove = __devexit_p(virtnet_remove), | 847 | .remove = __devexit_p(virtnet_remove), |
848 | .config_changed = virtnet_config_changed, | ||
808 | }; | 849 | }; |
809 | 850 | ||
810 | static int __init init(void) | 851 | static int __init init(void) |