Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 3212

kernel-2.6.18-238.el5.src.rpm

From: Jason Wang <jasowang@redhat.com>
Date: Tue, 16 Nov 2010 05:01:31 -0500
Subject: [net] virtio_net: add link status handling
Message-id: <20101116050130.3698.51989.stgit@dhcp-91-158.nay.redhat.com>
Patchwork-id: 29451
O-Subject: [RHEL5.6 PATCH] virtio_net: add link status handling
Bugzilla: 649573
RH-Acked-by: David S. Miller <davem@redhat.com>
RH-Acked-by: Thomas Graf <tgraf@redhat.com>

Bugzilla: 649573
Brew Build: https://brewweb.devel.redhat.com/taskinfo?taskID=2894155
Upstream:
This patch backports the following two commits from upstream

commit 9f4d26d0f3016cf8813977d624751b94465fa317
Author: Mark McLoughlin <markmc@redhat.com>
Date:   Mon Jan 19 17:09:49 2009 -0800

    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>

And

commit 167c25e4c5501f8b7e37f949d23652975c5a769c
Author: Jason Wang <jasowang@redhat.com>
Date:   Wed Nov 10 14:45:41 2010 +0000

    virtio-net: init link state correctly

    For device that supports VIRTIO_NET_F_STATUS, there's no need to
    assume the link is up and we need to call nerif_carrier_off() before
    querying device status, otherwise we may get wrong operstate after
    diver was loaded because the link watch event was not fired as
    expected.

    For device that does not support VIRITO_NET_F_STATUS, we could not get
    its status through virtnet_update_status() and what we can only do is
    always assuming the link is up.

    Acked-by: Michael S. Tsirkin <mst@redhat.com>
    Signed-off-by: Jason Wang <jasowang@redhat.com>
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: David S. Miller <davem@davemloft.ne

Test status:
Test with my local machine.

Signed-off-by: Jason Wang <jasowang@redhat.com>

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 89c9835..65cb9fe 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -43,6 +43,7 @@ struct virtnet_info
 	struct virtio_device *vdev;
 	struct virtqueue *rvq, *svq;
 	struct net_device *dev;
+	unsigned int status;
 
 	/* The skb we couldn't send because buffers were full. */
 	struct sk_buff *last_xmit_skb;
@@ -717,6 +718,7 @@ static struct ethtool_ops virtnet_ethtool_ops = {
 	.get_sg = ethtool_op_get_sg,
 	.set_tso = ethtool_op_set_tso,
 	.get_tso = ethtool_op_get_tso,
+	.get_link = ethtool_op_get_link,
 };
 
 #define MIN_MTU 68
@@ -734,6 +736,41 @@ static void virtnet_mclist(struct net_device *dev)
 {
 }
 
+static void virtnet_update_status(struct virtnet_info *vi)
+{
+	u16 v;
+
+	if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS))
+		return;
+
+	vi->vdev->config->get(vi->vdev,
+			      offsetof(struct virtio_net_config, status),
+			      &v, sizeof(v));
+
+	/* Ignore unknown (future) status bits */
+	v &= VIRTIO_NET_S_LINK_UP;
+
+	if (vi->status == v)
+		return;
+
+	vi->status = v;
+
+	if (vi->status & VIRTIO_NET_S_LINK_UP) {
+		netif_carrier_on(vi->dev);
+		netif_wake_queue(vi->dev);
+	} else {
+		netif_carrier_off(vi->dev);
+		netif_stop_queue(vi->dev);
+	}
+}
+
+static void virtnet_config_changed(struct virtio_device *vdev)
+{
+	struct virtnet_info *vi = vdev->priv;
+
+	virtnet_update_status(vi);
+}
+
 static int virtnet_probe(struct virtio_device *vdev)
 {
 	int err;
@@ -843,6 +880,16 @@ static int virtnet_probe(struct virtio_device *vdev)
 		goto unregister;
 	}
 
+	/* Assume link up if device can't report link status,
+	   otherwise get link status from config. */
+	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+		netif_carrier_off(dev);
+		virtnet_update_status(vi);
+	} else {
+		vi->status = VIRTIO_NET_S_LINK_UP;
+		netif_carrier_on(dev);
+	}
+
 	pr_debug("virtnet: registered device %s\n", dev->name);
 	return 0;
 
@@ -913,7 +960,7 @@ static unsigned int features[] = {
 	VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
 	VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
 	VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
-	VIRTIO_NET_F_MRG_RXBUF,
+	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS,
 	VIRTIO_F_NOTIFY_ON_EMPTY,
 };
 
@@ -925,6 +972,7 @@ static struct virtio_driver virtio_net = {
 	.id_table =	id_table,
 	.probe =	virtnet_probe,
 	.remove =	__devexit_p(virtnet_remove),
+	.config_changed = virtnet_config_changed,
 };
 
 static int __init init(void)
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 5cdd0aa..d56f84a 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -21,11 +21,15 @@
 #define VIRTIO_NET_F_HOST_ECN	13	/* Host can handle TSO[6] w/ ECN in. */
 #define VIRTIO_NET_F_HOST_UFO	14	/* Host can handle UFO in. */
 #define VIRTIO_NET_F_MRG_RXBUF	15	/* Host can merge receive buffers. */
+#define VIRTIO_NET_F_STATUS	16	/* virtio_net_config.status available */
+#define VIRTIO_NET_S_LINK_UP	1	/* Link is up */
 
 struct virtio_net_config
 {
 	/* The config defining mac address (if VIRTIO_NET_F_MAC) */
 	__u8 mac[6];
+	/* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
+	__u16 status;
 } __attribute__((packed));
 
 /* This is the first element of the scatter-gather list.  If you don't