Commit d2a7ddda9ffb1c8961abff6714b0f1eb925c120f
Committed by
Rusty Russell
1 parent
9499f5e7ed
Exists in
master
and in
20 other branches
virtio: find_vqs/del_vqs virtio operations
This replaces find_vq/del_vq with find_vqs/del_vqs virtio operations, and updates all drivers. This is needed for MSI support, because MSI needs to know the total number of vectors upfront. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (+ lguest/9p compile fixes)
Showing 10 changed files with 183 additions and 89 deletions Side-by-side Diff
drivers/block/virtio_blk.c
| ... | ... | @@ -288,7 +288,7 @@ |
| 288 | 288 | sg_init_table(vblk->sg, vblk->sg_elems); |
| 289 | 289 | |
| 290 | 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 | 292 | if (IS_ERR(vblk->vq)) { |
| 293 | 293 | err = PTR_ERR(vblk->vq); |
| 294 | 294 | goto out_free_vblk; |
| ... | ... | @@ -388,7 +388,7 @@ |
| 388 | 388 | out_mempool: |
| 389 | 389 | mempool_destroy(vblk->pool); |
| 390 | 390 | out_free_vq: |
| 391 | - vdev->config->del_vq(vblk->vq); | |
| 391 | + vdev->config->del_vqs(vdev); | |
| 392 | 392 | out_free_vblk: |
| 393 | 393 | kfree(vblk); |
| 394 | 394 | out: |
| ... | ... | @@ -409,7 +409,7 @@ |
| 409 | 409 | blk_cleanup_queue(vblk->disk->queue); |
| 410 | 410 | put_disk(vblk->disk); |
| 411 | 411 | mempool_destroy(vblk->pool); |
| 412 | - vdev->config->del_vq(vblk->vq); | |
| 412 | + vdev->config->del_vqs(vdev); | |
| 413 | 413 | kfree(vblk); |
| 414 | 414 | } |
| 415 | 415 |
drivers/char/hw_random/virtio-rng.c
| ... | ... | @@ -94,13 +94,13 @@ |
| 94 | 94 | int err; |
| 95 | 95 | |
| 96 | 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 | 98 | if (IS_ERR(vq)) |
| 99 | 99 | return PTR_ERR(vq); |
| 100 | 100 | |
| 101 | 101 | err = hwrng_register(&virtio_hwrng); |
| 102 | 102 | if (err) { |
| 103 | - vdev->config->del_vq(vq); | |
| 103 | + vdev->config->del_vqs(vdev); | |
| 104 | 104 | return err; |
| 105 | 105 | } |
| 106 | 106 | |
| ... | ... | @@ -112,7 +112,7 @@ |
| 112 | 112 | { |
| 113 | 113 | vdev->config->reset(vdev); |
| 114 | 114 | hwrng_unregister(&virtio_hwrng); |
| 115 | - vdev->config->del_vq(vq); | |
| 115 | + vdev->config->del_vqs(vdev); | |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | static struct virtio_device_id id_table[] = { |
drivers/char/virtio_console.c
| ... | ... | @@ -188,6 +188,9 @@ |
| 188 | 188 | * Finally we put our input buffer in the input queue, ready to receive. */ |
| 189 | 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 | 194 | int err; |
| 192 | 195 | |
| 193 | 196 | vdev = dev; |
| 194 | 197 | |
| 195 | 198 | |
| 196 | 199 | |
| ... | ... | @@ -199,20 +202,15 @@ |
| 199 | 202 | goto fail; |
| 200 | 203 | } |
| 201 | 204 | |
| 202 | - /* Find the input queue. */ | |
| 205 | + /* Find the queues. */ | |
| 203 | 206 | /* FIXME: This is why we want to wean off hvc: we do nothing |
| 204 | 207 | * when input comes in. */ |
| 205 | - in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input, "input"); | |
| 206 | - if (IS_ERR(in_vq)) { | |
| 207 | - err = PTR_ERR(in_vq); | |
| 208 | + err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); | |
| 209 | + if (err) | |
| 208 | 210 | goto free; |
| 209 | - } | |
| 210 | 211 | |
| 211 | - out_vq = vdev->config->find_vq(vdev, 1, NULL, "output"); | |
| 212 | - if (IS_ERR(out_vq)) { | |
| 213 | - err = PTR_ERR(out_vq); | |
| 214 | - goto free_in_vq; | |
| 215 | - } | |
| 212 | + in_vq = vqs[0]; | |
| 213 | + out_vq = vqs[1]; | |
| 216 | 214 | |
| 217 | 215 | /* Start using the new console output. */ |
| 218 | 216 | virtio_cons.get_chars = get_chars; |
| 219 | 217 | |
| ... | ... | @@ -233,17 +231,15 @@ |
| 233 | 231 | hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); |
| 234 | 232 | if (IS_ERR(hvc)) { |
| 235 | 233 | err = PTR_ERR(hvc); |
| 236 | - goto free_out_vq; | |
| 234 | + goto free_vqs; | |
| 237 | 235 | } |
| 238 | 236 | |
| 239 | 237 | /* Register the input buffer the first time. */ |
| 240 | 238 | add_inbuf(); |
| 241 | 239 | return 0; |
| 242 | 240 | |
| 243 | -free_out_vq: | |
| 244 | - vdev->config->del_vq(out_vq); | |
| 245 | -free_in_vq: | |
| 246 | - vdev->config->del_vq(in_vq); | |
| 241 | +free_vqs: | |
| 242 | + vdev->config->del_vqs(vdev); | |
| 247 | 243 | free: |
| 248 | 244 | kfree(inbuf); |
| 249 | 245 | fail: |
drivers/lguest/lguest_device.c
| ... | ... | @@ -313,6 +313,38 @@ |
| 313 | 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 | 348 | /* The ops structure which hooks everything together. */ |
| 317 | 349 | static struct virtio_config_ops lguest_config_ops = { |
| 318 | 350 | .get_features = lg_get_features, |
| ... | ... | @@ -322,8 +354,8 @@ |
| 322 | 354 | .get_status = lg_get_status, |
| 323 | 355 | .set_status = lg_set_status, |
| 324 | 356 | .reset = lg_reset, |
| 325 | - .find_vq = lg_find_vq, | |
| 326 | - .del_vq = lg_del_vq, | |
| 357 | + .find_vqs = lg_find_vqs, | |
| 358 | + .del_vqs = lg_del_vqs, | |
| 327 | 359 | }; |
| 328 | 360 | |
| 329 | 361 | /* The root device for the lguest virtio devices. This makes them appear as |
drivers/net/virtio_net.c
| ... | ... | @@ -845,6 +845,10 @@ |
| 845 | 845 | int err; |
| 846 | 846 | struct net_device *dev; |
| 847 | 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 | 853 | /* Allocate ourselves a network device with room for our info */ |
| 850 | 854 | dev = alloc_etherdev(sizeof(struct virtnet_info)); |
| 851 | 855 | |
| 852 | 856 | |
| 853 | 857 | |
| ... | ... | @@ -905,25 +909,19 @@ |
| 905 | 909 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) |
| 906 | 910 | vi->mergeable_rx_bufs = true; |
| 907 | 911 | |
| 908 | - /* We expect two virtqueues, receive then send. */ | |
| 909 | - vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done, "input"); | |
| 910 | - if (IS_ERR(vi->rvq)) { | |
| 911 | - err = PTR_ERR(vi->rvq); | |
| 912 | + /* We expect two virtqueues, receive then send, | |
| 913 | + * and optionally control. */ | |
| 914 | + nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; | |
| 915 | + | |
| 916 | + err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names); | |
| 917 | + if (err) | |
| 912 | 918 | goto free; |
| 913 | - } | |
| 914 | 919 | |
| 915 | - vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done, "output"); | |
| 916 | - if (IS_ERR(vi->svq)) { | |
| 917 | - err = PTR_ERR(vi->svq); | |
| 918 | - goto free_recv; | |
| 919 | - } | |
| 920 | + vi->rvq = vqs[0]; | |
| 921 | + vi->svq = vqs[1]; | |
| 920 | 922 | |
| 921 | 923 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { |
| 922 | - vi->cvq = vdev->config->find_vq(vdev, 2, NULL, "control"); | |
| 923 | - if (IS_ERR(vi->cvq)) { | |
| 924 | - err = PTR_ERR(vi->svq); | |
| 925 | - goto free_send; | |
| 926 | - } | |
| 924 | + vi->cvq = vqs[2]; | |
| 927 | 925 | |
| 928 | 926 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) |
| 929 | 927 | dev->features |= NETIF_F_HW_VLAN_FILTER; |
| ... | ... | @@ -941,7 +939,7 @@ |
| 941 | 939 | err = register_netdev(dev); |
| 942 | 940 | if (err) { |
| 943 | 941 | pr_debug("virtio_net: registering device failed\n"); |
| 944 | - goto free_ctrl; | |
| 942 | + goto free_vqs; | |
| 945 | 943 | } |
| 946 | 944 | |
| 947 | 945 | /* Last of all, set up some receive buffers. */ |
| ... | ... | @@ -962,13 +960,8 @@ |
| 962 | 960 | |
| 963 | 961 | unregister: |
| 964 | 962 | unregister_netdev(dev); |
| 965 | -free_ctrl: | |
| 966 | - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) | |
| 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); | |
| 963 | +free_vqs: | |
| 964 | + vdev->config->del_vqs(vdev); | |
| 972 | 965 | free: |
| 973 | 966 | free_netdev(dev); |
| 974 | 967 | return err; |
| 975 | 968 | |
| ... | ... | @@ -994,11 +987,9 @@ |
| 994 | 987 | |
| 995 | 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 | 990 | unregister_netdev(vi->dev); |
| 991 | + | |
| 992 | + vdev->config->del_vqs(vi->vdev); | |
| 1002 | 993 | |
| 1003 | 994 | while (vi->pages) |
| 1004 | 995 | __free_pages(get_a_page(vi, GFP_KERNEL), 0); |
drivers/s390/kvm/kvm_virtio.c
| ... | ... | @@ -227,6 +227,38 @@ |
| 227 | 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 | 263 | * The config ops structure as defined by virtio config |
| 232 | 264 | */ |
| ... | ... | @@ -238,8 +270,8 @@ |
| 238 | 270 | .get_status = kvm_get_status, |
| 239 | 271 | .set_status = kvm_set_status, |
| 240 | 272 | .reset = kvm_reset, |
| 241 | - .find_vq = kvm_find_vq, | |
| 242 | - .del_vq = kvm_del_vq, | |
| 273 | + .find_vqs = kvm_find_vqs, | |
| 274 | + .del_vqs = kvm_del_vqs, | |
| 243 | 275 | }; |
| 244 | 276 | |
| 245 | 277 | /* |
drivers/virtio/virtio_balloon.c
| ... | ... | @@ -204,6 +204,9 @@ |
| 204 | 204 | static int virtballoon_probe(struct virtio_device *vdev) |
| 205 | 205 | { |
| 206 | 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 | 210 | int err; |
| 208 | 211 | |
| 209 | 212 | vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); |
| 210 | 213 | |
| 211 | 214 | |
| 212 | 215 | |
| ... | ... | @@ -218,22 +221,17 @@ |
| 218 | 221 | vb->vdev = vdev; |
| 219 | 222 | |
| 220 | 223 | /* We expect two virtqueues. */ |
| 221 | - vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack, "inflate"); | |
| 222 | - if (IS_ERR(vb->inflate_vq)) { | |
| 223 | - err = PTR_ERR(vb->inflate_vq); | |
| 224 | + err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); | |
| 225 | + if (err) | |
| 224 | 226 | goto out_free_vb; |
| 225 | - } | |
| 226 | 227 | |
| 227 | - vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack, "deflate"); | |
| 228 | - if (IS_ERR(vb->deflate_vq)) { | |
| 229 | - err = PTR_ERR(vb->deflate_vq); | |
| 230 | - goto out_del_inflate_vq; | |
| 231 | - } | |
| 228 | + vb->inflate_vq = vqs[0]; | |
| 229 | + vb->deflate_vq = vqs[1]; | |
| 232 | 230 | |
| 233 | 231 | vb->thread = kthread_run(balloon, vb, "vballoon"); |
| 234 | 232 | if (IS_ERR(vb->thread)) { |
| 235 | 233 | err = PTR_ERR(vb->thread); |
| 236 | - goto out_del_deflate_vq; | |
| 234 | + goto out_del_vqs; | |
| 237 | 235 | } |
| 238 | 236 | |
| 239 | 237 | vb->tell_host_first |
| ... | ... | @@ -241,10 +239,8 @@ |
| 241 | 239 | |
| 242 | 240 | return 0; |
| 243 | 241 | |
| 244 | -out_del_deflate_vq: | |
| 245 | - vdev->config->del_vq(vb->deflate_vq); | |
| 246 | -out_del_inflate_vq: | |
| 247 | - vdev->config->del_vq(vb->inflate_vq); | |
| 242 | +out_del_vqs: | |
| 243 | + vdev->config->del_vqs(vdev); | |
| 248 | 244 | out_free_vb: |
| 249 | 245 | kfree(vb); |
| 250 | 246 | out: |
| ... | ... | @@ -264,8 +260,7 @@ |
| 264 | 260 | /* Now we reset the device so we can clean up the queues. */ |
| 265 | 261 | vdev->config->reset(vdev); |
| 266 | 262 | |
| 267 | - vdev->config->del_vq(vb->deflate_vq); | |
| 268 | - vdev->config->del_vq(vb->inflate_vq); | |
| 263 | + vdev->config->del_vqs(vdev); | |
| 269 | 264 | kfree(vb); |
| 270 | 265 | } |
| 271 | 266 |
drivers/virtio/virtio_pci.c
| ... | ... | @@ -276,12 +276,8 @@ |
| 276 | 276 | { |
| 277 | 277 | struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); |
| 278 | 278 | struct virtio_pci_vq_info *info = vq->priv; |
| 279 | - unsigned long flags, size; | |
| 279 | + unsigned long size; | |
| 280 | 280 | |
| 281 | - spin_lock_irqsave(&vp_dev->lock, flags); | |
| 282 | - list_del(&info->node); | |
| 283 | - spin_unlock_irqrestore(&vp_dev->lock, flags); | |
| 284 | - | |
| 285 | 281 | vring_del_virtqueue(vq); |
| 286 | 282 | |
| 287 | 283 | /* Select and deactivate the queue */ |
| 288 | 284 | |
| ... | ... | @@ -293,14 +289,41 @@ |
| 293 | 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 | 319 | static struct virtio_config_ops virtio_pci_config_ops = { |
| 297 | 320 | .get = vp_get, |
| 298 | 321 | .set = vp_set, |
| 299 | 322 | .get_status = vp_get_status, |
| 300 | 323 | .set_status = vp_set_status, |
| 301 | 324 | .reset = vp_reset, |
| 302 | - .find_vq = vp_find_vq, | |
| 303 | - .del_vq = vp_del_vq, | |
| 325 | + .find_vqs = vp_find_vqs, | |
| 326 | + .del_vqs = vp_del_vqs, | |
| 304 | 327 | .get_features = vp_get_features, |
| 305 | 328 | .finalize_features = vp_finalize_features, |
| 306 | 329 | }; |
include/linux/virtio_config.h
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | #define VIRTIO_F_NOTIFY_ON_EMPTY 24 |
| 30 | 30 | |
| 31 | 31 | #ifdef __KERNEL__ |
| 32 | +#include <linux/err.h> | |
| 32 | 33 | #include <linux/virtio.h> |
| 33 | 34 | |
| 34 | 35 | /** |
| 35 | 36 | |
| 36 | 37 | |
| ... | ... | @@ -49,16 +50,26 @@ |
| 49 | 50 | * @set_status: write the status byte |
| 50 | 51 | * vdev: the virtio_device |
| 51 | 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 | 62 | * @reset: reset the device |
| 53 | 63 | * vdev: the virtio device |
| 54 | 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 | 66 | * vdev: the virtio_device |
| 57 | - * index: the 0-based virtqueue number in case there's more than one. | |
| 58 | - * callback: the virtqueue callback | |
| 59 | - * name: the virtqueue name (mainly for debugging) | |
| 60 | - * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). | |
| 61 | - * @del_vq: free a virtqueue found by find_vq(). | |
| 67 | + * nvqs: the number of virtqueues to find | |
| 68 | + * vqs: on success, includes new virtqueues | |
| 69 | + * callbacks: array of callbacks, for each virtqueue | |
| 70 | + * names: array of virtqueue names (mainly for debugging) | |
| 71 | + * Returns 0 on success or error status | |
| 72 | + * @del_vqs: free virtqueues found by find_vqs(). | |
| 62 | 73 | * @get_features: get the array of feature bits for this device. |
| 63 | 74 | * vdev: the virtio_device |
| 64 | 75 | * Returns the first 32 feature bits (all we currently need). |
| ... | ... | @@ -67,6 +78,7 @@ |
| 67 | 78 | * This gives the final feature bits for the device: it can change |
| 68 | 79 | * the dev->feature bits if it wants. |
| 69 | 80 | */ |
| 81 | +typedef void vq_callback_t(struct virtqueue *); | |
| 70 | 82 | struct virtio_config_ops |
| 71 | 83 | { |
| 72 | 84 | void (*get)(struct virtio_device *vdev, unsigned offset, |
| ... | ... | @@ -76,11 +88,11 @@ |
| 76 | 88 | u8 (*get_status)(struct virtio_device *vdev); |
| 77 | 89 | void (*set_status)(struct virtio_device *vdev, u8 status); |
| 78 | 90 | void (*reset)(struct virtio_device *vdev); |
| 79 | - struct virtqueue *(*find_vq)(struct virtio_device *vdev, | |
| 80 | - unsigned index, | |
| 81 | - void (*callback)(struct virtqueue *), | |
| 82 | - const char *name); | |
| 83 | - void (*del_vq)(struct virtqueue *vq); | |
| 91 | + int (*find_vqs)(struct virtio_device *, unsigned nvqs, | |
| 92 | + struct virtqueue *vqs[], | |
| 93 | + vq_callback_t *callbacks[], | |
| 94 | + const char *names[]); | |
| 95 | + void (*del_vqs)(struct virtio_device *); | |
| 84 | 96 | u32 (*get_features)(struct virtio_device *vdev); |
| 85 | 97 | void (*finalize_features)(struct virtio_device *vdev); |
| 86 | 98 | }; |
| ... | ... | @@ -127,6 +139,19 @@ |
| 127 | 139 | |
| 128 | 140 | vdev->config->get(vdev, offset, buf, len); |
| 129 | 141 | return 0; |
| 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; | |
| 130 | 155 | } |
| 131 | 156 | #endif /* __KERNEL__ */ |
| 132 | 157 | #endif /* _LINUX_VIRTIO_CONFIG_H */ |
net/9p/trans_virtio.c
| ... | ... | @@ -246,7 +246,7 @@ |
| 246 | 246 | chan->vdev = vdev; |
| 247 | 247 | |
| 248 | 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 | 250 | if (IS_ERR(chan->vq)) { |
| 251 | 251 | err = PTR_ERR(chan->vq); |
| 252 | 252 | goto out_free_vq; |
| ... | ... | @@ -261,7 +261,7 @@ |
| 261 | 261 | return 0; |
| 262 | 262 | |
| 263 | 263 | out_free_vq: |
| 264 | - vdev->config->del_vq(chan->vq); | |
| 264 | + vdev->config->del_vqs(vdev); | |
| 265 | 265 | fail: |
| 266 | 266 | mutex_lock(&virtio_9p_lock); |
| 267 | 267 | chan_index--; |
| ... | ... | @@ -332,7 +332,7 @@ |
| 332 | 332 | BUG_ON(chan->inuse); |
| 333 | 333 | |
| 334 | 334 | if (chan->initialized) { |
| 335 | - vdev->config->del_vq(chan->vq); | |
| 335 | + vdev->config->del_vqs(vdev); | |
| 336 | 336 | chan->initialized = false; |
| 337 | 337 | } |
| 338 | 338 | } |