diff options
-rw-r--r-- | drivers/block/virtio_blk.c | 6 | ||||
-rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 6 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 26 | ||||
-rw-r--r-- | drivers/lguest/lguest_device.c | 36 | ||||
-rw-r--r-- | drivers/net/virtio_net.c | 45 | ||||
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 36 | ||||
-rw-r--r-- | drivers/virtio/virtio_balloon.c | 27 | ||||
-rw-r--r-- | drivers/virtio/virtio_pci.c | 37 | ||||
-rw-r--r-- | include/linux/virtio_config.h | 47 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 6 |
10 files changed, 183 insertions, 89 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index db55a50d9f6a..07d8e595e51f 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -288,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev) | |||
288 | sg_init_table(vblk->sg, vblk->sg_elems); | 288 | sg_init_table(vblk->sg, vblk->sg_elems); |
289 | 289 | ||
290 | /* We expect one virtqueue, for output. */ | 290 | /* We expect one virtqueue, for output. */ |
291 | vblk->vq = vdev->config->find_vq(vdev, 0, blk_done, "requests"); | 291 | vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests"); |
292 | if (IS_ERR(vblk->vq)) { | 292 | if (IS_ERR(vblk->vq)) { |
293 | err = PTR_ERR(vblk->vq); | 293 | err = PTR_ERR(vblk->vq); |
294 | goto out_free_vblk; | 294 | goto out_free_vblk; |
@@ -388,7 +388,7 @@ out_put_disk: | |||
388 | out_mempool: | 388 | out_mempool: |
389 | mempool_destroy(vblk->pool); | 389 | mempool_destroy(vblk->pool); |
390 | out_free_vq: | 390 | out_free_vq: |
391 | vdev->config->del_vq(vblk->vq); | 391 | vdev->config->del_vqs(vdev); |
392 | out_free_vblk: | 392 | out_free_vblk: |
393 | kfree(vblk); | 393 | kfree(vblk); |
394 | out: | 394 | out: |
@@ -409,7 +409,7 @@ static void virtblk_remove(struct virtio_device *vdev) | |||
409 | blk_cleanup_queue(vblk->disk->queue); | 409 | blk_cleanup_queue(vblk->disk->queue); |
410 | put_disk(vblk->disk); | 410 | put_disk(vblk->disk); |
411 | mempool_destroy(vblk->pool); | 411 | mempool_destroy(vblk->pool); |
412 | vdev->config->del_vq(vblk->vq); | 412 | vdev->config->del_vqs(vdev); |
413 | kfree(vblk); | 413 | kfree(vblk); |
414 | } | 414 | } |
415 | 415 | ||
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 2aeafcea95fe..f2041fede822 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
@@ -94,13 +94,13 @@ static int virtrng_probe(struct virtio_device *vdev) | |||
94 | int err; | 94 | int err; |
95 | 95 | ||
96 | /* We expect a single virtqueue. */ | 96 | /* We expect a single virtqueue. */ |
97 | vq = vdev->config->find_vq(vdev, 0, random_recv_done, "input"); | 97 | vq = virtio_find_single_vq(vdev, random_recv_done, "input"); |
98 | if (IS_ERR(vq)) | 98 | if (IS_ERR(vq)) |
99 | return PTR_ERR(vq); | 99 | return PTR_ERR(vq); |
100 | 100 | ||
101 | err = hwrng_register(&virtio_hwrng); | 101 | err = hwrng_register(&virtio_hwrng); |
102 | if (err) { | 102 | if (err) { |
103 | vdev->config->del_vq(vq); | 103 | vdev->config->del_vqs(vdev); |
104 | return err; | 104 | return err; |
105 | } | 105 | } |
106 | 106 | ||
@@ -112,7 +112,7 @@ static void virtrng_remove(struct virtio_device *vdev) | |||
112 | { | 112 | { |
113 | vdev->config->reset(vdev); | 113 | vdev->config->reset(vdev); |
114 | hwrng_unregister(&virtio_hwrng); | 114 | hwrng_unregister(&virtio_hwrng); |
115 | vdev->config->del_vq(vq); | 115 | vdev->config->del_vqs(vdev); |
116 | } | 116 | } |
117 | 117 | ||
118 | static struct virtio_device_id id_table[] = { | 118 | static struct virtio_device_id id_table[] = { |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 58684e4a0814..c74dacfa6795 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -188,6 +188,9 @@ static void hvc_handle_input(struct virtqueue *vq) | |||
188 | * Finally we put our input buffer in the input queue, ready to receive. */ | 188 | * Finally we put our input buffer in the input queue, ready to receive. */ |
189 | static int __devinit virtcons_probe(struct virtio_device *dev) | 189 | static int __devinit virtcons_probe(struct virtio_device *dev) |
190 | { | 190 | { |
191 | vq_callback_t *callbacks[] = { hvc_handle_input, NULL}; | ||
192 | const char *names[] = { "input", "output" }; | ||
193 | struct virtqueue *vqs[2]; | ||
191 | int err; | 194 | int err; |
192 | 195 | ||
193 | vdev = dev; | 196 | vdev = dev; |
@@ -199,20 +202,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) | |||
199 | goto fail; | 202 | goto fail; |
200 | } | 203 | } |
201 | 204 | ||
202 | /* Find the input queue. */ | 205 | /* Find the queues. */ |
203 | /* FIXME: This is why we want to wean off hvc: we do nothing | 206 | /* FIXME: This is why we want to wean off hvc: we do nothing |
204 | * when input comes in. */ | 207 | * when input comes in. */ |
205 | in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input, "input"); | 208 | err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); |
206 | if (IS_ERR(in_vq)) { | 209 | if (err) |
207 | err = PTR_ERR(in_vq); | ||
208 | goto free; | 210 | goto free; |
209 | } | ||
210 | 211 | ||
211 | out_vq = vdev->config->find_vq(vdev, 1, NULL, "output"); | 212 | in_vq = vqs[0]; |
212 | if (IS_ERR(out_vq)) { | 213 | out_vq = vqs[1]; |
213 | err = PTR_ERR(out_vq); | ||
214 | goto free_in_vq; | ||
215 | } | ||
216 | 214 | ||
217 | /* Start using the new console output. */ | 215 | /* Start using the new console output. */ |
218 | virtio_cons.get_chars = get_chars; | 216 | virtio_cons.get_chars = get_chars; |
@@ -233,17 +231,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) | |||
233 | hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); | 231 | hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); |
234 | if (IS_ERR(hvc)) { | 232 | if (IS_ERR(hvc)) { |
235 | err = PTR_ERR(hvc); | 233 | err = PTR_ERR(hvc); |
236 | goto free_out_vq; | 234 | goto free_vqs; |
237 | } | 235 | } |
238 | 236 | ||
239 | /* Register the input buffer the first time. */ | 237 | /* Register the input buffer the first time. */ |
240 | add_inbuf(); | 238 | add_inbuf(); |
241 | return 0; | 239 | return 0; |
242 | 240 | ||
243 | free_out_vq: | 241 | free_vqs: |
244 | vdev->config->del_vq(out_vq); | 242 | vdev->config->del_vqs(vdev); |
245 | free_in_vq: | ||
246 | vdev->config->del_vq(in_vq); | ||
247 | free: | 243 | free: |
248 | kfree(inbuf); | 244 | kfree(inbuf); |
249 | fail: | 245 | fail: |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 4babed899d59..e082cdac88b4 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
@@ -313,6 +313,38 @@ static void lg_del_vq(struct virtqueue *vq) | |||
313 | kfree(lvq); | 313 | kfree(lvq); |
314 | } | 314 | } |
315 | 315 | ||
316 | static void lg_del_vqs(struct virtio_device *vdev) | ||
317 | { | ||
318 | struct virtqueue *vq, *n; | ||
319 | |||
320 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
321 | lg_del_vq(vq); | ||
322 | } | ||
323 | |||
324 | static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
325 | struct virtqueue *vqs[], | ||
326 | vq_callback_t *callbacks[], | ||
327 | const char *names[]) | ||
328 | { | ||
329 | struct lguest_device *ldev = to_lgdev(vdev); | ||
330 | int i; | ||
331 | |||
332 | /* We must have this many virtqueues. */ | ||
333 | if (nvqs > ldev->desc->num_vq) | ||
334 | return -ENOENT; | ||
335 | |||
336 | for (i = 0; i < nvqs; ++i) { | ||
337 | vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]); | ||
338 | if (IS_ERR(vqs[i])) | ||
339 | goto error; | ||
340 | } | ||
341 | return 0; | ||
342 | |||
343 | error: | ||
344 | lg_del_vqs(vdev); | ||
345 | return PTR_ERR(vqs[i]); | ||
346 | } | ||
347 | |||
316 | /* The ops structure which hooks everything together. */ | 348 | /* The ops structure which hooks everything together. */ |
317 | static struct virtio_config_ops lguest_config_ops = { | 349 | static struct virtio_config_ops lguest_config_ops = { |
318 | .get_features = lg_get_features, | 350 | .get_features = lg_get_features, |
@@ -322,8 +354,8 @@ static struct virtio_config_ops lguest_config_ops = { | |||
322 | .get_status = lg_get_status, | 354 | .get_status = lg_get_status, |
323 | .set_status = lg_set_status, | 355 | .set_status = lg_set_status, |
324 | .reset = lg_reset, | 356 | .reset = lg_reset, |
325 | .find_vq = lg_find_vq, | 357 | .find_vqs = lg_find_vqs, |
326 | .del_vq = lg_del_vq, | 358 | .del_vqs = lg_del_vqs, |
327 | }; | 359 | }; |
328 | 360 | ||
329 | /* The root device for the lguest virtio devices. This makes them appear as | 361 | /* The root device for the lguest virtio devices. This makes them appear as |
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index be3b734ff5a1..7fa620ddeb21 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -845,6 +845,10 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
845 | int err; | 845 | int err; |
846 | struct net_device *dev; | 846 | struct net_device *dev; |
847 | struct virtnet_info *vi; | 847 | struct virtnet_info *vi; |
848 | struct virtqueue *vqs[3]; | ||
849 | vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL}; | ||
850 | const char *names[] = { "input", "output", "control" }; | ||
851 | int nvqs; | ||
848 | 852 | ||
849 | /* Allocate ourselves a network device with room for our info */ | 853 | /* Allocate ourselves a network device with room for our info */ |
850 | dev = alloc_etherdev(sizeof(struct virtnet_info)); | 854 | dev = alloc_etherdev(sizeof(struct virtnet_info)); |
@@ -905,25 +909,19 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
905 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) | 909 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) |
906 | vi->mergeable_rx_bufs = true; | 910 | vi->mergeable_rx_bufs = true; |
907 | 911 | ||
908 | /* We expect two virtqueues, receive then send. */ | 912 | /* We expect two virtqueues, receive then send, |
909 | vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done, "input"); | 913 | * and optionally control. */ |
910 | if (IS_ERR(vi->rvq)) { | 914 | nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; |
911 | err = PTR_ERR(vi->rvq); | 915 | |
916 | err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names); | ||
917 | if (err) | ||
912 | goto free; | 918 | goto free; |
913 | } | ||
914 | 919 | ||
915 | vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done, "output"); | 920 | vi->rvq = vqs[0]; |
916 | if (IS_ERR(vi->svq)) { | 921 | vi->svq = vqs[1]; |
917 | err = PTR_ERR(vi->svq); | ||
918 | goto free_recv; | ||
919 | } | ||
920 | 922 | ||
921 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { | 923 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { |
922 | vi->cvq = vdev->config->find_vq(vdev, 2, NULL, "control"); | 924 | vi->cvq = vqs[2]; |
923 | if (IS_ERR(vi->cvq)) { | ||
924 | err = PTR_ERR(vi->svq); | ||
925 | goto free_send; | ||
926 | } | ||
927 | 925 | ||
928 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) | 926 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) |
929 | dev->features |= NETIF_F_HW_VLAN_FILTER; | 927 | dev->features |= NETIF_F_HW_VLAN_FILTER; |
@@ -941,7 +939,7 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
941 | err = register_netdev(dev); | 939 | err = register_netdev(dev); |
942 | if (err) { | 940 | if (err) { |
943 | pr_debug("virtio_net: registering device failed\n"); | 941 | pr_debug("virtio_net: registering device failed\n"); |
944 | goto free_ctrl; | 942 | goto free_vqs; |
945 | } | 943 | } |
946 | 944 | ||
947 | /* Last of all, set up some receive buffers. */ | 945 | /* Last of all, set up some receive buffers. */ |
@@ -962,13 +960,8 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
962 | 960 | ||
963 | unregister: | 961 | unregister: |
964 | unregister_netdev(dev); | 962 | unregister_netdev(dev); |
965 | free_ctrl: | 963 | free_vqs: |
966 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | 964 | vdev->config->del_vqs(vdev); |
967 | vdev->config->del_vq(vi->cvq); | ||
968 | free_send: | ||
969 | vdev->config->del_vq(vi->svq); | ||
970 | free_recv: | ||
971 | vdev->config->del_vq(vi->rvq); | ||
972 | free: | 965 | free: |
973 | free_netdev(dev); | 966 | free_netdev(dev); |
974 | return err; | 967 | return err; |
@@ -994,12 +987,10 @@ static void virtnet_remove(struct virtio_device *vdev) | |||
994 | 987 | ||
995 | BUG_ON(vi->num != 0); | 988 | BUG_ON(vi->num != 0); |
996 | 989 | ||
997 | vdev->config->del_vq(vi->svq); | ||
998 | vdev->config->del_vq(vi->rvq); | ||
999 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | ||
1000 | vdev->config->del_vq(vi->cvq); | ||
1001 | unregister_netdev(vi->dev); | 990 | unregister_netdev(vi->dev); |
1002 | 991 | ||
992 | vdev->config->del_vqs(vi->vdev); | ||
993 | |||
1003 | while (vi->pages) | 994 | while (vi->pages) |
1004 | __free_pages(get_a_page(vi, GFP_KERNEL), 0); | 995 | __free_pages(get_a_page(vi, GFP_KERNEL), 0); |
1005 | 996 | ||
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index ba8995fbf041..e38e5d306faf 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -227,6 +227,38 @@ static void kvm_del_vq(struct virtqueue *vq) | |||
227 | KVM_S390_VIRTIO_RING_ALIGN)); | 227 | KVM_S390_VIRTIO_RING_ALIGN)); |
228 | } | 228 | } |
229 | 229 | ||
230 | static void kvm_del_vqs(struct virtio_device *vdev) | ||
231 | { | ||
232 | struct virtqueue *vq, *n; | ||
233 | |||
234 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
235 | kvm_del_vq(vq); | ||
236 | } | ||
237 | |||
238 | static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
239 | struct virtqueue *vqs[], | ||
240 | vq_callback_t *callbacks[], | ||
241 | const char *names[]) | ||
242 | { | ||
243 | struct kvm_device *kdev = to_kvmdev(vdev); | ||
244 | int i; | ||
245 | |||
246 | /* We must have this many virtqueues. */ | ||
247 | if (nvqs > kdev->desc->num_vq) | ||
248 | return -ENOENT; | ||
249 | |||
250 | for (i = 0; i < nvqs; ++i) { | ||
251 | vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); | ||
252 | if (IS_ERR(vqs[i])) | ||
253 | goto error; | ||
254 | } | ||
255 | return 0; | ||
256 | |||
257 | error: | ||
258 | kvm_del_vqs(vdev); | ||
259 | return PTR_ERR(vqs[i]); | ||
260 | } | ||
261 | |||
230 | /* | 262 | /* |
231 | * The config ops structure as defined by virtio config | 263 | * The config ops structure as defined by virtio config |
232 | */ | 264 | */ |
@@ -238,8 +270,8 @@ static struct virtio_config_ops kvm_vq_configspace_ops = { | |||
238 | .get_status = kvm_get_status, | 270 | .get_status = kvm_get_status, |
239 | .set_status = kvm_set_status, | 271 | .set_status = kvm_set_status, |
240 | .reset = kvm_reset, | 272 | .reset = kvm_reset, |
241 | .find_vq = kvm_find_vq, | 273 | .find_vqs = kvm_find_vqs, |
242 | .del_vq = kvm_del_vq, | 274 | .del_vqs = kvm_del_vqs, |
243 | }; | 275 | }; |
244 | 276 | ||
245 | /* | 277 | /* |
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 0fa73b4d18b0..26b278264796 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c | |||
@@ -204,6 +204,9 @@ static int balloon(void *_vballoon) | |||
204 | static int virtballoon_probe(struct virtio_device *vdev) | 204 | static int virtballoon_probe(struct virtio_device *vdev) |
205 | { | 205 | { |
206 | struct virtio_balloon *vb; | 206 | struct virtio_balloon *vb; |
207 | struct virtqueue *vqs[2]; | ||
208 | vq_callback_t *callbacks[] = { balloon_ack, balloon_ack }; | ||
209 | const char *names[] = { "inflate", "deflate" }; | ||
207 | int err; | 210 | int err; |
208 | 211 | ||
209 | vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); | 212 | vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); |
@@ -218,22 +221,17 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
218 | vb->vdev = vdev; | 221 | vb->vdev = vdev; |
219 | 222 | ||
220 | /* We expect two virtqueues. */ | 223 | /* We expect two virtqueues. */ |
221 | vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack, "inflate"); | 224 | err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); |
222 | if (IS_ERR(vb->inflate_vq)) { | 225 | if (err) |
223 | err = PTR_ERR(vb->inflate_vq); | ||
224 | goto out_free_vb; | 226 | goto out_free_vb; |
225 | } | ||
226 | 227 | ||
227 | vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack, "deflate"); | 228 | vb->inflate_vq = vqs[0]; |
228 | if (IS_ERR(vb->deflate_vq)) { | 229 | vb->deflate_vq = vqs[1]; |
229 | err = PTR_ERR(vb->deflate_vq); | ||
230 | goto out_del_inflate_vq; | ||
231 | } | ||
232 | 230 | ||
233 | vb->thread = kthread_run(balloon, vb, "vballoon"); | 231 | vb->thread = kthread_run(balloon, vb, "vballoon"); |
234 | if (IS_ERR(vb->thread)) { | 232 | if (IS_ERR(vb->thread)) { |
235 | err = PTR_ERR(vb->thread); | 233 | err = PTR_ERR(vb->thread); |
236 | goto out_del_deflate_vq; | 234 | goto out_del_vqs; |
237 | } | 235 | } |
238 | 236 | ||
239 | vb->tell_host_first | 237 | vb->tell_host_first |
@@ -241,10 +239,8 @@ static int virtballoon_probe(struct virtio_device *vdev) | |||
241 | 239 | ||
242 | return 0; | 240 | return 0; |
243 | 241 | ||
244 | out_del_deflate_vq: | 242 | out_del_vqs: |
245 | vdev->config->del_vq(vb->deflate_vq); | 243 | vdev->config->del_vqs(vdev); |
246 | out_del_inflate_vq: | ||
247 | vdev->config->del_vq(vb->inflate_vq); | ||
248 | out_free_vb: | 244 | out_free_vb: |
249 | kfree(vb); | 245 | kfree(vb); |
250 | out: | 246 | out: |
@@ -264,8 +260,7 @@ static void virtballoon_remove(struct virtio_device *vdev) | |||
264 | /* Now we reset the device so we can clean up the queues. */ | 260 | /* Now we reset the device so we can clean up the queues. */ |
265 | vdev->config->reset(vdev); | 261 | vdev->config->reset(vdev); |
266 | 262 | ||
267 | vdev->config->del_vq(vb->deflate_vq); | 263 | vdev->config->del_vqs(vdev); |
268 | vdev->config->del_vq(vb->inflate_vq); | ||
269 | kfree(vb); | 264 | kfree(vb); |
270 | } | 265 | } |
271 | 266 | ||
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index be4047abd5ba..027f13fbe493 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c | |||
@@ -276,11 +276,7 @@ static void vp_del_vq(struct virtqueue *vq) | |||
276 | { | 276 | { |
277 | struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); | 277 | struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); |
278 | struct virtio_pci_vq_info *info = vq->priv; | 278 | struct virtio_pci_vq_info *info = vq->priv; |
279 | unsigned long flags, size; | 279 | unsigned long size; |
280 | |||
281 | spin_lock_irqsave(&vp_dev->lock, flags); | ||
282 | list_del(&info->node); | ||
283 | spin_unlock_irqrestore(&vp_dev->lock, flags); | ||
284 | 280 | ||
285 | vring_del_virtqueue(vq); | 281 | vring_del_virtqueue(vq); |
286 | 282 | ||
@@ -293,14 +289,41 @@ static void vp_del_vq(struct virtqueue *vq) | |||
293 | kfree(info); | 289 | kfree(info); |
294 | } | 290 | } |
295 | 291 | ||
292 | static void vp_del_vqs(struct virtio_device *vdev) | ||
293 | { | ||
294 | struct virtqueue *vq, *n; | ||
295 | |||
296 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
297 | vp_del_vq(vq); | ||
298 | } | ||
299 | |||
300 | static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
301 | struct virtqueue *vqs[], | ||
302 | vq_callback_t *callbacks[], | ||
303 | const char *names[]) | ||
304 | { | ||
305 | int i; | ||
306 | |||
307 | for (i = 0; i < nvqs; ++i) { | ||
308 | vqs[i] = vp_find_vq(vdev, i, callbacks[i], names[i]); | ||
309 | if (IS_ERR(vqs[i])) | ||
310 | goto error; | ||
311 | } | ||
312 | return 0; | ||
313 | |||
314 | error: | ||
315 | vp_del_vqs(vdev); | ||
316 | return PTR_ERR(vqs[i]); | ||
317 | } | ||
318 | |||
296 | static struct virtio_config_ops virtio_pci_config_ops = { | 319 | static struct virtio_config_ops virtio_pci_config_ops = { |
297 | .get = vp_get, | 320 | .get = vp_get, |
298 | .set = vp_set, | 321 | .set = vp_set, |
299 | .get_status = vp_get_status, | 322 | .get_status = vp_get_status, |
300 | .set_status = vp_set_status, | 323 | .set_status = vp_set_status, |
301 | .reset = vp_reset, | 324 | .reset = vp_reset, |
302 | .find_vq = vp_find_vq, | 325 | .find_vqs = vp_find_vqs, |
303 | .del_vq = vp_del_vq, | 326 | .del_vqs = vp_del_vqs, |
304 | .get_features = vp_get_features, | 327 | .get_features = vp_get_features, |
305 | .finalize_features = vp_finalize_features, | 328 | .finalize_features = vp_finalize_features, |
306 | }; | 329 | }; |
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 9fae274751e0..4cd290c06a88 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #define VIRTIO_F_NOTIFY_ON_EMPTY 24 | 29 | #define VIRTIO_F_NOTIFY_ON_EMPTY 24 |
30 | 30 | ||
31 | #ifdef __KERNEL__ | 31 | #ifdef __KERNEL__ |
32 | #include <linux/err.h> | ||
32 | #include <linux/virtio.h> | 33 | #include <linux/virtio.h> |
33 | 34 | ||
34 | /** | 35 | /** |
@@ -49,16 +50,26 @@ | |||
49 | * @set_status: write the status byte | 50 | * @set_status: write the status byte |
50 | * vdev: the virtio_device | 51 | * vdev: the virtio_device |
51 | * status: the new status byte | 52 | * status: the new status byte |
53 | * @request_vqs: request the specified number of virtqueues | ||
54 | * vdev: the virtio_device | ||
55 | * max_vqs: the max number of virtqueues we want | ||
56 | * If supplied, must call before any virtqueues are instantiated. | ||
57 | * To modify the max number of virtqueues after request_vqs has been | ||
58 | * called, call free_vqs and then request_vqs with a new value. | ||
59 | * @free_vqs: cleanup resources allocated by request_vqs | ||
60 | * vdev: the virtio_device | ||
61 | * If supplied, must call after all virtqueues have been deleted. | ||
52 | * @reset: reset the device | 62 | * @reset: reset the device |
53 | * vdev: the virtio device | 63 | * vdev: the virtio device |
54 | * After this, status and feature negotiation must be done again | 64 | * After this, status and feature negotiation must be done again |
55 | * @find_vq: find a virtqueue and instantiate it. | 65 | * @find_vqs: find virtqueues and instantiate them. |
56 | * vdev: the virtio_device | 66 | * vdev: the virtio_device |
57 | * index: the 0-based virtqueue number in case there's more than one. | 67 | * nvqs: the number of virtqueues to find |
58 | * callback: the virtqueue callback | 68 | * vqs: on success, includes new virtqueues |
59 | * name: the virtqueue name (mainly for debugging) | 69 | * callbacks: array of callbacks, for each virtqueue |
60 | * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). | 70 | * names: array of virtqueue names (mainly for debugging) |
61 | * @del_vq: free a virtqueue found by find_vq(). | 71 | * Returns 0 on success or error status |
72 | * @del_vqs: free virtqueues found by find_vqs(). | ||
62 | * @get_features: get the array of feature bits for this device. | 73 | * @get_features: get the array of feature bits for this device. |
63 | * vdev: the virtio_device | 74 | * vdev: the virtio_device |
64 | * Returns the first 32 feature bits (all we currently need). | 75 | * Returns the first 32 feature bits (all we currently need). |
@@ -67,6 +78,7 @@ | |||
67 | * This gives the final feature bits for the device: it can change | 78 | * This gives the final feature bits for the device: it can change |
68 | * the dev->feature bits if it wants. | 79 | * the dev->feature bits if it wants. |
69 | */ | 80 | */ |
81 | typedef void vq_callback_t(struct virtqueue *); | ||
70 | struct virtio_config_ops | 82 | struct virtio_config_ops |
71 | { | 83 | { |
72 | void (*get)(struct virtio_device *vdev, unsigned offset, | 84 | void (*get)(struct virtio_device *vdev, unsigned offset, |
@@ -76,11 +88,11 @@ struct virtio_config_ops | |||
76 | u8 (*get_status)(struct virtio_device *vdev); | 88 | u8 (*get_status)(struct virtio_device *vdev); |
77 | void (*set_status)(struct virtio_device *vdev, u8 status); | 89 | void (*set_status)(struct virtio_device *vdev, u8 status); |
78 | void (*reset)(struct virtio_device *vdev); | 90 | void (*reset)(struct virtio_device *vdev); |
79 | struct virtqueue *(*find_vq)(struct virtio_device *vdev, | 91 | int (*find_vqs)(struct virtio_device *, unsigned nvqs, |
80 | unsigned index, | 92 | struct virtqueue *vqs[], |
81 | void (*callback)(struct virtqueue *), | 93 | vq_callback_t *callbacks[], |
82 | const char *name); | 94 | const char *names[]); |
83 | void (*del_vq)(struct virtqueue *vq); | 95 | void (*del_vqs)(struct virtio_device *); |
84 | u32 (*get_features)(struct virtio_device *vdev); | 96 | u32 (*get_features)(struct virtio_device *vdev); |
85 | void (*finalize_features)(struct virtio_device *vdev); | 97 | void (*finalize_features)(struct virtio_device *vdev); |
86 | }; | 98 | }; |
@@ -128,5 +140,18 @@ static inline int virtio_config_buf(struct virtio_device *vdev, | |||
128 | vdev->config->get(vdev, offset, buf, len); | 140 | vdev->config->get(vdev, offset, buf, len); |
129 | return 0; | 141 | return 0; |
130 | } | 142 | } |
143 | |||
144 | static inline | ||
145 | struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, | ||
146 | vq_callback_t *c, const char *n) | ||
147 | { | ||
148 | vq_callback_t *callbacks[] = { c }; | ||
149 | const char *names[] = { n }; | ||
150 | struct virtqueue *vq; | ||
151 | int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names); | ||
152 | if (err < 0) | ||
153 | return ERR_PTR(err); | ||
154 | return vq; | ||
155 | } | ||
131 | #endif /* __KERNEL__ */ | 156 | #endif /* __KERNEL__ */ |
132 | #endif /* _LINUX_VIRTIO_CONFIG_H */ | 157 | #endif /* _LINUX_VIRTIO_CONFIG_H */ |
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index ab8791f9aba8..a49484e67e1d 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -246,7 +246,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) | |||
246 | chan->vdev = vdev; | 246 | chan->vdev = vdev; |
247 | 247 | ||
248 | /* We expect one virtqueue, for requests. */ | 248 | /* We expect one virtqueue, for requests. */ |
249 | chan->vq = vdev->config->find_vq(vdev, 0, req_done, "requests"); | 249 | chan->vq = virtio_find_single_vq(vdev, req_done, "requests"); |
250 | if (IS_ERR(chan->vq)) { | 250 | if (IS_ERR(chan->vq)) { |
251 | err = PTR_ERR(chan->vq); | 251 | err = PTR_ERR(chan->vq); |
252 | goto out_free_vq; | 252 | goto out_free_vq; |
@@ -261,7 +261,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) | |||
261 | return 0; | 261 | return 0; |
262 | 262 | ||
263 | out_free_vq: | 263 | out_free_vq: |
264 | vdev->config->del_vq(chan->vq); | 264 | vdev->config->del_vqs(vdev); |
265 | fail: | 265 | fail: |
266 | mutex_lock(&virtio_9p_lock); | 266 | mutex_lock(&virtio_9p_lock); |
267 | chan_index--; | 267 | chan_index--; |
@@ -332,7 +332,7 @@ static void p9_virtio_remove(struct virtio_device *vdev) | |||
332 | BUG_ON(chan->inuse); | 332 | BUG_ON(chan->inuse); |
333 | 333 | ||
334 | if (chan->initialized) { | 334 | if (chan->initialized) { |
335 | vdev->config->del_vq(chan->vq); | 335 | vdev->config->del_vqs(vdev); |
336 | chan->initialized = false; | 336 | chan->initialized = false; |
337 | } | 337 | } |
338 | } | 338 | } |