diff options
author | Andy Lutomirski <luto@kernel.org> | 2016-02-03 00:46:37 -0500 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-03-02 10:01:57 -0500 |
commit | 2a2d1382fe9dccfce6f9c60a9c9fd2f0fe5bcf2b (patch) | |
tree | ab3783be11369f689e3e7aebe0c438ab6746375f | |
parent | 780bc7903a32edb63be138487fd981694d993610 (diff) |
virtio: Add improved queue allocation API
This leaves vring_new_virtqueue alone for compatbility, but it
adds two new improved APIs:
vring_create_virtqueue: Creates a virtqueue backed by automatically
allocated coherent memory. (Some day it this could be extended to
support non-coherent memory, too, if there ends up being a platform
on which it's worthwhile.)
__vring_new_virtqueue: Creates a virtqueue with a manually-specified
layout. This should allow mic_virtio to work much more cleanly.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | drivers/virtio/virtio_ring.c | 209 | ||||
-rw-r--r-- | include/linux/virtio.h | 23 | ||||
-rw-r--r-- | include/linux/virtio_ring.h | 35 |
3 files changed, 235 insertions, 32 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 9abc008ff7ea..e46d08107a50 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c | |||
@@ -95,6 +95,11 @@ struct vring_virtqueue { | |||
95 | /* How to notify other side. FIXME: commonalize hcalls! */ | 95 | /* How to notify other side. FIXME: commonalize hcalls! */ |
96 | bool (*notify)(struct virtqueue *vq); | 96 | bool (*notify)(struct virtqueue *vq); |
97 | 97 | ||
98 | /* DMA, allocation, and size information */ | ||
99 | bool we_own_ring; | ||
100 | size_t queue_size_in_bytes; | ||
101 | dma_addr_t queue_dma_addr; | ||
102 | |||
98 | #ifdef DEBUG | 103 | #ifdef DEBUG |
99 | /* They're supposed to lock for us. */ | 104 | /* They're supposed to lock for us. */ |
100 | unsigned int in_use; | 105 | unsigned int in_use; |
@@ -878,36 +883,31 @@ irqreturn_t vring_interrupt(int irq, void *_vq) | |||
878 | } | 883 | } |
879 | EXPORT_SYMBOL_GPL(vring_interrupt); | 884 | EXPORT_SYMBOL_GPL(vring_interrupt); |
880 | 885 | ||
881 | struct virtqueue *vring_new_virtqueue(unsigned int index, | 886 | struct virtqueue *__vring_new_virtqueue(unsigned int index, |
882 | unsigned int num, | 887 | struct vring vring, |
883 | unsigned int vring_align, | 888 | struct virtio_device *vdev, |
884 | struct virtio_device *vdev, | 889 | bool weak_barriers, |
885 | bool weak_barriers, | 890 | bool (*notify)(struct virtqueue *), |
886 | void *pages, | 891 | void (*callback)(struct virtqueue *), |
887 | bool (*notify)(struct virtqueue *), | 892 | const char *name) |
888 | void (*callback)(struct virtqueue *), | ||
889 | const char *name) | ||
890 | { | 893 | { |
891 | struct vring_virtqueue *vq; | ||
892 | unsigned int i; | 894 | unsigned int i; |
895 | struct vring_virtqueue *vq; | ||
893 | 896 | ||
894 | /* We assume num is a power of 2. */ | 897 | vq = kmalloc(sizeof(*vq) + vring.num * sizeof(struct vring_desc_state), |
895 | if (num & (num - 1)) { | ||
896 | dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num); | ||
897 | return NULL; | ||
898 | } | ||
899 | |||
900 | vq = kmalloc(sizeof(*vq) + num * sizeof(struct vring_desc_state), | ||
901 | GFP_KERNEL); | 898 | GFP_KERNEL); |
902 | if (!vq) | 899 | if (!vq) |
903 | return NULL; | 900 | return NULL; |
904 | 901 | ||
905 | vring_init(&vq->vring, num, pages, vring_align); | 902 | vq->vring = vring; |
906 | vq->vq.callback = callback; | 903 | vq->vq.callback = callback; |
907 | vq->vq.vdev = vdev; | 904 | vq->vq.vdev = vdev; |
908 | vq->vq.name = name; | 905 | vq->vq.name = name; |
909 | vq->vq.num_free = num; | 906 | vq->vq.num_free = vring.num; |
910 | vq->vq.index = index; | 907 | vq->vq.index = index; |
908 | vq->we_own_ring = false; | ||
909 | vq->queue_dma_addr = 0; | ||
910 | vq->queue_size_in_bytes = 0; | ||
911 | vq->notify = notify; | 911 | vq->notify = notify; |
912 | vq->weak_barriers = weak_barriers; | 912 | vq->weak_barriers = weak_barriers; |
913 | vq->broken = false; | 913 | vq->broken = false; |
@@ -932,18 +932,145 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, | |||
932 | 932 | ||
933 | /* Put everything in free lists. */ | 933 | /* Put everything in free lists. */ |
934 | vq->free_head = 0; | 934 | vq->free_head = 0; |
935 | for (i = 0; i < num-1; i++) | 935 | for (i = 0; i < vring.num-1; i++) |
936 | vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); | 936 | vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); |
937 | memset(vq->desc_state, 0, num * sizeof(struct vring_desc_state)); | 937 | memset(vq->desc_state, 0, vring.num * sizeof(struct vring_desc_state)); |
938 | 938 | ||
939 | return &vq->vq; | 939 | return &vq->vq; |
940 | } | 940 | } |
941 | EXPORT_SYMBOL_GPL(__vring_new_virtqueue); | ||
942 | |||
943 | static void *vring_alloc_queue(struct virtio_device *vdev, size_t size, | ||
944 | dma_addr_t *dma_handle, gfp_t flag) | ||
945 | { | ||
946 | if (vring_use_dma_api(vdev)) { | ||
947 | return dma_alloc_coherent(vdev->dev.parent, size, | ||
948 | dma_handle, flag); | ||
949 | } else { | ||
950 | void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag); | ||
951 | if (queue) { | ||
952 | phys_addr_t phys_addr = virt_to_phys(queue); | ||
953 | *dma_handle = (dma_addr_t)phys_addr; | ||
954 | |||
955 | /* | ||
956 | * Sanity check: make sure we dind't truncate | ||
957 | * the address. The only arches I can find that | ||
958 | * have 64-bit phys_addr_t but 32-bit dma_addr_t | ||
959 | * are certain non-highmem MIPS and x86 | ||
960 | * configurations, but these configurations | ||
961 | * should never allocate physical pages above 32 | ||
962 | * bits, so this is fine. Just in case, throw a | ||
963 | * warning and abort if we end up with an | ||
964 | * unrepresentable address. | ||
965 | */ | ||
966 | if (WARN_ON_ONCE(*dma_handle != phys_addr)) { | ||
967 | free_pages_exact(queue, PAGE_ALIGN(size)); | ||
968 | return NULL; | ||
969 | } | ||
970 | } | ||
971 | return queue; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | static void vring_free_queue(struct virtio_device *vdev, size_t size, | ||
976 | void *queue, dma_addr_t dma_handle) | ||
977 | { | ||
978 | if (vring_use_dma_api(vdev)) { | ||
979 | dma_free_coherent(vdev->dev.parent, size, queue, dma_handle); | ||
980 | } else { | ||
981 | free_pages_exact(queue, PAGE_ALIGN(size)); | ||
982 | } | ||
983 | } | ||
984 | |||
985 | struct virtqueue *vring_create_virtqueue( | ||
986 | unsigned int index, | ||
987 | unsigned int num, | ||
988 | unsigned int vring_align, | ||
989 | struct virtio_device *vdev, | ||
990 | bool weak_barriers, | ||
991 | bool may_reduce_num, | ||
992 | bool (*notify)(struct virtqueue *), | ||
993 | void (*callback)(struct virtqueue *), | ||
994 | const char *name) | ||
995 | { | ||
996 | struct virtqueue *vq; | ||
997 | void *queue; | ||
998 | dma_addr_t dma_addr; | ||
999 | size_t queue_size_in_bytes; | ||
1000 | struct vring vring; | ||
1001 | |||
1002 | /* We assume num is a power of 2. */ | ||
1003 | if (num & (num - 1)) { | ||
1004 | dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num); | ||
1005 | return NULL; | ||
1006 | } | ||
1007 | |||
1008 | /* TODO: allocate each queue chunk individually */ | ||
1009 | for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) { | ||
1010 | queue = vring_alloc_queue(vdev, vring_size(num, vring_align), | ||
1011 | &dma_addr, | ||
1012 | GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); | ||
1013 | if (queue) | ||
1014 | break; | ||
1015 | } | ||
1016 | |||
1017 | if (!num) | ||
1018 | return NULL; | ||
1019 | |||
1020 | if (!queue) { | ||
1021 | /* Try to get a single page. You are my only hope! */ | ||
1022 | queue = vring_alloc_queue(vdev, vring_size(num, vring_align), | ||
1023 | &dma_addr, GFP_KERNEL|__GFP_ZERO); | ||
1024 | } | ||
1025 | if (!queue) | ||
1026 | return NULL; | ||
1027 | |||
1028 | queue_size_in_bytes = vring_size(num, vring_align); | ||
1029 | vring_init(&vring, num, queue, vring_align); | ||
1030 | |||
1031 | vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, | ||
1032 | notify, callback, name); | ||
1033 | if (!vq) { | ||
1034 | vring_free_queue(vdev, queue_size_in_bytes, queue, | ||
1035 | dma_addr); | ||
1036 | return NULL; | ||
1037 | } | ||
1038 | |||
1039 | to_vvq(vq)->queue_dma_addr = dma_addr; | ||
1040 | to_vvq(vq)->queue_size_in_bytes = queue_size_in_bytes; | ||
1041 | to_vvq(vq)->we_own_ring = true; | ||
1042 | |||
1043 | return vq; | ||
1044 | } | ||
1045 | EXPORT_SYMBOL_GPL(vring_create_virtqueue); | ||
1046 | |||
1047 | struct virtqueue *vring_new_virtqueue(unsigned int index, | ||
1048 | unsigned int num, | ||
1049 | unsigned int vring_align, | ||
1050 | struct virtio_device *vdev, | ||
1051 | bool weak_barriers, | ||
1052 | void *pages, | ||
1053 | bool (*notify)(struct virtqueue *vq), | ||
1054 | void (*callback)(struct virtqueue *vq), | ||
1055 | const char *name) | ||
1056 | { | ||
1057 | struct vring vring; | ||
1058 | vring_init(&vring, num, pages, vring_align); | ||
1059 | return __vring_new_virtqueue(index, vring, vdev, weak_barriers, | ||
1060 | notify, callback, name); | ||
1061 | } | ||
941 | EXPORT_SYMBOL_GPL(vring_new_virtqueue); | 1062 | EXPORT_SYMBOL_GPL(vring_new_virtqueue); |
942 | 1063 | ||
943 | void vring_del_virtqueue(struct virtqueue *vq) | 1064 | void vring_del_virtqueue(struct virtqueue *_vq) |
944 | { | 1065 | { |
945 | list_del(&vq->list); | 1066 | struct vring_virtqueue *vq = to_vvq(_vq); |
946 | kfree(to_vvq(vq)); | 1067 | |
1068 | if (vq->we_own_ring) { | ||
1069 | vring_free_queue(vq->vq.vdev, vq->queue_size_in_bytes, | ||
1070 | vq->vring.desc, vq->queue_dma_addr); | ||
1071 | } | ||
1072 | list_del(&_vq->list); | ||
1073 | kfree(vq); | ||
947 | } | 1074 | } |
948 | EXPORT_SYMBOL_GPL(vring_del_virtqueue); | 1075 | EXPORT_SYMBOL_GPL(vring_del_virtqueue); |
949 | 1076 | ||
@@ -1007,20 +1134,42 @@ void virtio_break_device(struct virtio_device *dev) | |||
1007 | } | 1134 | } |
1008 | EXPORT_SYMBOL_GPL(virtio_break_device); | 1135 | EXPORT_SYMBOL_GPL(virtio_break_device); |
1009 | 1136 | ||
1010 | void *virtqueue_get_avail(struct virtqueue *_vq) | 1137 | dma_addr_t virtqueue_get_desc_addr(struct virtqueue *_vq) |
1011 | { | 1138 | { |
1012 | struct vring_virtqueue *vq = to_vvq(_vq); | 1139 | struct vring_virtqueue *vq = to_vvq(_vq); |
1013 | 1140 | ||
1014 | return vq->vring.avail; | 1141 | BUG_ON(!vq->we_own_ring); |
1142 | |||
1143 | return vq->queue_dma_addr; | ||
1015 | } | 1144 | } |
1016 | EXPORT_SYMBOL_GPL(virtqueue_get_avail); | 1145 | EXPORT_SYMBOL_GPL(virtqueue_get_desc_addr); |
1017 | 1146 | ||
1018 | void *virtqueue_get_used(struct virtqueue *_vq) | 1147 | dma_addr_t virtqueue_get_avail_addr(struct virtqueue *_vq) |
1019 | { | 1148 | { |
1020 | struct vring_virtqueue *vq = to_vvq(_vq); | 1149 | struct vring_virtqueue *vq = to_vvq(_vq); |
1021 | 1150 | ||
1022 | return vq->vring.used; | 1151 | BUG_ON(!vq->we_own_ring); |
1152 | |||
1153 | return vq->queue_dma_addr + | ||
1154 | ((char *)vq->vring.avail - (char *)vq->vring.desc); | ||
1155 | } | ||
1156 | EXPORT_SYMBOL_GPL(virtqueue_get_avail_addr); | ||
1157 | |||
1158 | dma_addr_t virtqueue_get_used_addr(struct virtqueue *_vq) | ||
1159 | { | ||
1160 | struct vring_virtqueue *vq = to_vvq(_vq); | ||
1161 | |||
1162 | BUG_ON(!vq->we_own_ring); | ||
1163 | |||
1164 | return vq->queue_dma_addr + | ||
1165 | ((char *)vq->vring.used - (char *)vq->vring.desc); | ||
1166 | } | ||
1167 | EXPORT_SYMBOL_GPL(virtqueue_get_used_addr); | ||
1168 | |||
1169 | const struct vring *virtqueue_get_vring(struct virtqueue *vq) | ||
1170 | { | ||
1171 | return &to_vvq(vq)->vring; | ||
1023 | } | 1172 | } |
1024 | EXPORT_SYMBOL_GPL(virtqueue_get_used); | 1173 | EXPORT_SYMBOL_GPL(virtqueue_get_vring); |
1025 | 1174 | ||
1026 | MODULE_LICENSE("GPL"); | 1175 | MODULE_LICENSE("GPL"); |
diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 8f4d4bfa6d46..d5eb5479a425 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h | |||
@@ -75,8 +75,27 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *vq); | |||
75 | 75 | ||
76 | bool virtqueue_is_broken(struct virtqueue *vq); | 76 | bool virtqueue_is_broken(struct virtqueue *vq); |
77 | 77 | ||
78 | void *virtqueue_get_avail(struct virtqueue *vq); | 78 | const struct vring *virtqueue_get_vring(struct virtqueue *vq); |
79 | void *virtqueue_get_used(struct virtqueue *vq); | 79 | dma_addr_t virtqueue_get_desc_addr(struct virtqueue *vq); |
80 | dma_addr_t virtqueue_get_avail_addr(struct virtqueue *vq); | ||
81 | dma_addr_t virtqueue_get_used_addr(struct virtqueue *vq); | ||
82 | |||
83 | /* | ||
84 | * Legacy accessors -- in almost all cases, these are the wrong functions | ||
85 | * to use. | ||
86 | */ | ||
87 | static inline void *virtqueue_get_desc(struct virtqueue *vq) | ||
88 | { | ||
89 | return virtqueue_get_vring(vq)->desc; | ||
90 | } | ||
91 | static inline void *virtqueue_get_avail(struct virtqueue *vq) | ||
92 | { | ||
93 | return virtqueue_get_vring(vq)->avail; | ||
94 | } | ||
95 | static inline void *virtqueue_get_used(struct virtqueue *vq) | ||
96 | { | ||
97 | return virtqueue_get_vring(vq)->used; | ||
98 | } | ||
80 | 99 | ||
81 | /** | 100 | /** |
82 | * virtio_device - representation of a device using virtio | 101 | * virtio_device - representation of a device using virtio |
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index a156e2b6ccfe..e8d36938f09a 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h | |||
@@ -59,6 +59,35 @@ static inline void virtio_store_mb(bool weak_barriers, | |||
59 | struct virtio_device; | 59 | struct virtio_device; |
60 | struct virtqueue; | 60 | struct virtqueue; |
61 | 61 | ||
62 | /* | ||
63 | * Creates a virtqueue and allocates the descriptor ring. If | ||
64 | * may_reduce_num is set, then this may allocate a smaller ring than | ||
65 | * expected. The caller should query virtqueue_get_ring_size to learn | ||
66 | * the actual size of the ring. | ||
67 | */ | ||
68 | struct virtqueue *vring_create_virtqueue(unsigned int index, | ||
69 | unsigned int num, | ||
70 | unsigned int vring_align, | ||
71 | struct virtio_device *vdev, | ||
72 | bool weak_barriers, | ||
73 | bool may_reduce_num, | ||
74 | bool (*notify)(struct virtqueue *vq), | ||
75 | void (*callback)(struct virtqueue *vq), | ||
76 | const char *name); | ||
77 | |||
78 | /* Creates a virtqueue with a custom layout. */ | ||
79 | struct virtqueue *__vring_new_virtqueue(unsigned int index, | ||
80 | struct vring vring, | ||
81 | struct virtio_device *vdev, | ||
82 | bool weak_barriers, | ||
83 | bool (*notify)(struct virtqueue *), | ||
84 | void (*callback)(struct virtqueue *), | ||
85 | const char *name); | ||
86 | |||
87 | /* | ||
88 | * Creates a virtqueue with a standard layout but a caller-allocated | ||
89 | * ring. | ||
90 | */ | ||
62 | struct virtqueue *vring_new_virtqueue(unsigned int index, | 91 | struct virtqueue *vring_new_virtqueue(unsigned int index, |
63 | unsigned int num, | 92 | unsigned int num, |
64 | unsigned int vring_align, | 93 | unsigned int vring_align, |
@@ -68,7 +97,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, | |||
68 | bool (*notify)(struct virtqueue *vq), | 97 | bool (*notify)(struct virtqueue *vq), |
69 | void (*callback)(struct virtqueue *vq), | 98 | void (*callback)(struct virtqueue *vq), |
70 | const char *name); | 99 | const char *name); |
100 | |||
101 | /* | ||
102 | * Destroys a virtqueue. If created with vring_create_virtqueue, this | ||
103 | * also frees the ring. | ||
104 | */ | ||
71 | void vring_del_virtqueue(struct virtqueue *vq); | 105 | void vring_del_virtqueue(struct virtqueue *vq); |
106 | |||
72 | /* Filter out transport-specific feature bits. */ | 107 | /* Filter out transport-specific feature bits. */ |
73 | void vring_transport_features(struct virtio_device *vdev); | 108 | void vring_transport_features(struct virtio_device *vdev); |
74 | 109 | ||