diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 68 |
1 files changed, 65 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 | ||