diff options
-rw-r--r-- | drivers/net/virtio_net.c | 68 | ||||
-rw-r--r-- | include/linux/virtio_net.h | 18 |
2 files changed, 83 insertions, 3 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fe576e75a538..67bb583b7fc9 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -37,10 +37,12 @@ module_param(gso, bool, 0444); | |||
37 | #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) | 37 | #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) |
38 | #define GOOD_COPY_LEN 128 | 38 | #define GOOD_COPY_LEN 128 |
39 | 39 | ||
40 | #define VIRTNET_SEND_COMMAND_SG_MAX 0 | ||
41 | |||
40 | struct virtnet_info | 42 | struct virtnet_info |
41 | { | 43 | { |
42 | struct virtio_device *vdev; | 44 | struct virtio_device *vdev; |
43 | struct virtqueue *rvq, *svq; | 45 | struct virtqueue *rvq, *svq, *cvq; |
44 | struct net_device *dev; | 46 | struct net_device *dev; |
45 | struct napi_struct napi; | 47 | struct napi_struct napi; |
46 | unsigned int status; | 48 | unsigned int status; |
@@ -589,6 +591,53 @@ static int virtnet_open(struct net_device *dev) | |||
589 | return 0; | 591 | return 0; |
590 | } | 592 | } |
591 | 593 | ||
594 | /* | ||
595 | * Send command via the control virtqueue and check status. Commands | ||
596 | * supported by the hypervisor, as indicated by feature bits, should | ||
597 | * never fail unless improperly formated. | ||
598 | */ | ||
599 | static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, | ||
600 | struct scatterlist *data, int out, int in) | ||
601 | { | ||
602 | struct scatterlist sg[VIRTNET_SEND_COMMAND_SG_MAX + 2]; | ||
603 | struct virtio_net_ctrl_hdr ctrl; | ||
604 | virtio_net_ctrl_ack status = ~0; | ||
605 | unsigned int tmp; | ||
606 | |||
607 | if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { | ||
608 | BUG(); /* Caller should know better */ | ||
609 | return false; | ||
610 | } | ||
611 | |||
612 | BUG_ON(out + in > VIRTNET_SEND_COMMAND_SG_MAX); | ||
613 | |||
614 | out++; /* Add header */ | ||
615 | in++; /* Add return status */ | ||
616 | |||
617 | ctrl.class = class; | ||
618 | ctrl.cmd = cmd; | ||
619 | |||
620 | sg_init_table(sg, out + in); | ||
621 | |||
622 | sg_set_buf(&sg[0], &ctrl, sizeof(ctrl)); | ||
623 | memcpy(&sg[1], data, sizeof(struct scatterlist) * (out + in - 2)); | ||
624 | sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); | ||
625 | |||
626 | if (vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) != 0) | ||
627 | BUG(); | ||
628 | |||
629 | vi->cvq->vq_ops->kick(vi->cvq); | ||
630 | |||
631 | /* | ||
632 | * Spin for a response, the kick causes an ioport write, trapping | ||
633 | * into the hypervisor, so the request should be handled immediately. | ||
634 | */ | ||
635 | while (!vi->cvq->vq_ops->get_buf(vi->cvq, &tmp)) | ||
636 | cpu_relax(); | ||
637 | |||
638 | return status == VIRTIO_NET_OK; | ||
639 | } | ||
640 | |||
592 | static int virtnet_close(struct net_device *dev) | 641 | static int virtnet_close(struct net_device *dev) |
593 | { | 642 | { |
594 | struct virtnet_info *vi = netdev_priv(dev); | 643 | struct virtnet_info *vi = netdev_priv(dev); |
@@ -752,6 +801,14 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
752 | goto free_recv; | 801 | goto free_recv; |
753 | } | 802 | } |
754 | 803 | ||
804 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { | ||
805 | vi->cvq = vdev->config->find_vq(vdev, 2, NULL); | ||
806 | if (IS_ERR(vi->cvq)) { | ||
807 | err = PTR_ERR(vi->svq); | ||
808 | goto free_send; | ||
809 | } | ||
810 | } | ||
811 | |||
755 | /* Initialize our empty receive and send queues. */ | 812 | /* Initialize our empty receive and send queues. */ |
756 | skb_queue_head_init(&vi->recv); | 813 | skb_queue_head_init(&vi->recv); |
757 | skb_queue_head_init(&vi->send); | 814 | skb_queue_head_init(&vi->send); |
@@ -764,7 +821,7 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
764 | err = register_netdev(dev); | 821 | err = register_netdev(dev); |
765 | if (err) { | 822 | if (err) { |
766 | pr_debug("virtio_net: registering device failed\n"); | 823 | pr_debug("virtio_net: registering device failed\n"); |
767 | goto free_send; | 824 | goto free_ctrl; |
768 | } | 825 | } |
769 | 826 | ||
770 | /* Last of all, set up some receive buffers. */ | 827 | /* Last of all, set up some receive buffers. */ |
@@ -784,6 +841,9 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
784 | 841 | ||
785 | unregister: | 842 | unregister: |
786 | unregister_netdev(dev); | 843 | unregister_netdev(dev); |
844 | free_ctrl: | ||
845 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | ||
846 | vdev->config->del_vq(vi->cvq); | ||
787 | free_send: | 847 | free_send: |
788 | vdev->config->del_vq(vi->svq); | 848 | vdev->config->del_vq(vi->svq); |
789 | free_recv: | 849 | free_recv: |
@@ -815,6 +875,8 @@ static void virtnet_remove(struct virtio_device *vdev) | |||
815 | 875 | ||
816 | vdev->config->del_vq(vi->svq); | 876 | vdev->config->del_vq(vi->svq); |
817 | vdev->config->del_vq(vi->rvq); | 877 | vdev->config->del_vq(vi->rvq); |
878 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | ||
879 | vdev->config->del_vq(vi->cvq); | ||
818 | unregister_netdev(vi->dev); | 880 | unregister_netdev(vi->dev); |
819 | 881 | ||
820 | while (vi->pages) | 882 | while (vi->pages) |
@@ -834,7 +896,7 @@ static unsigned int features[] = { | |||
834 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, | 896 | VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, |
835 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, | 897 | VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, |
836 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ | 898 | VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ |
837 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, | 899 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, |
838 | VIRTIO_F_NOTIFY_ON_EMPTY, | 900 | VIRTIO_F_NOTIFY_ON_EMPTY, |
839 | }; | 901 | }; |
840 | 902 | ||
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index d8e362d52fd8..245eda829aa8 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ | 23 | #define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ |
24 | #define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ | 24 | #define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ |
25 | #define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */ | 25 | #define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */ |
26 | #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ | ||
26 | 27 | ||
27 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ | 28 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ |
28 | 29 | ||
@@ -59,4 +60,21 @@ struct virtio_net_hdr_mrg_rxbuf { | |||
59 | __u16 num_buffers; /* Number of merged rx buffers */ | 60 | __u16 num_buffers; /* Number of merged rx buffers */ |
60 | }; | 61 | }; |
61 | 62 | ||
63 | /* | ||
64 | * Control virtqueue data structures | ||
65 | * | ||
66 | * The control virtqueue expects a header in the first sg entry | ||
67 | * and an ack/status response in the last entry. Data for the | ||
68 | * command goes in between. | ||
69 | */ | ||
70 | struct virtio_net_ctrl_hdr { | ||
71 | __u8 class; | ||
72 | __u8 cmd; | ||
73 | } __attribute__((packed)); | ||
74 | |||
75 | typedef __u8 virtio_net_ctrl_ack; | ||
76 | |||
77 | #define VIRTIO_NET_OK 0 | ||
78 | #define VIRTIO_NET_ERR 1 | ||
79 | |||
62 | #endif /* _LINUX_VIRTIO_NET_H */ | 80 | #endif /* _LINUX_VIRTIO_NET_H */ |