virtio: find_vqs/del_vqs virtio operations
Subsystems (13)
Michael S. Tsirkin
maintainerPATCH v4 1/1 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 <[email protected]>
---
Untested - Rusty could you pls take a look before I go ahead and rebase the rest on top of this?
drivers/block/virtio_blk.c | 12 ++++---- drivers/char/hw_random/virtio-rng.c | 12 +++++---- drivers/char/virtio_console.c | 26 ++++++++----------- drivers/lguest/lguest_device.c | 36 ++++++++++++++++++++++++++- drivers/net/virtio_net.c | 45 ++++++++++++++--------------------- drivers/s390/kvm/kvm_virtio.c | 37 +++++++++++++++++++++++++++- drivers/virtio/virtio_balloon.c | 27 ++++++++------------ drivers/virtio/virtio_pci.c | 37 +++++++++++++++++++++++----- include/linux/virtio_config.h | 33 +++++++++++++++++-------- net/9p/trans_virtio.c | 8 +++--- 10 files changed, 178 insertions(+), 95 deletions(-)
drivers/block/virtio_blk.c +6 -6
@@ -197,6 +197,8 @@ static int virtblk_probe(struct virtio_device *vdev)u64 cap;u32 v;u32 blk_size, sg_elems; +vq_callback_t *callback[] = { blk_done }; +const char *name[] = {"requests" };if (index_to_minor (index) >=1 <<MINORBITS )return -ENOSPC ;
@@ -224,11 +226,9 @@ static int virtblk_probe(struct virtio_device *vdev)sg_init_table (vblk->sg, vblk->sg_elems);/* We expect one virtqueue, for output. */ - vblk->vq = vdev->config->find_vq (vdev,0 , blk_done,"requests" ); -if (IS_ERR (vblk->vq)) { - err =PTR_ERR (vblk->vq); + err = vdev->config->find_vqs (vdev,1 , &vblk->vq, callback, name); +if (err) goto out_free_vblk; - } vblk->pool =mempool_create_kmalloc_pool (1 ,sizeof (struct virtblk_req ));if (!vblk->pool) {
@@ -323,7 +323,7 @@ out_put_disk: out_mempool:mempool_destroy (vblk->pool); out_free_vq: - vdev->config->del_vq (vblk->vq); + vdev->config->del_vqs (vdev); out_free_vblk:kfree (vblk); out:
@@ -344,7 +344,7 @@ static void virtblk_remove(struct virtio_device *vdev)blk_cleanup_queue (vblk->disk->queue);put_disk (vblk->disk);mempool_destroy (vblk->pool); - vdev->config->del_vq (vblk->vq); + vdev->config->del_vqs (vdev);kfree (vblk); }
drivers/char/hw_random/virtio-rng.c +7 -5
@@ -91,16 +91,18 @@ static struct hwrng virtio_hwrng = {static int virtrng_probe (struct virtio_device *vdev) { +vq_callback_t *callback[] = { random_recv_done }; +const char *name[] = {"input" };int err;/* We expect a single virtqueue. */ - vq = vdev->config->find_vq (vdev,0 , random_recv_done,"input" ); -if (IS_ERR (vq)) -return PTR_ERR (vq); + err = vdev->config->find_vqs (vdev,1 , &vq, callback, name); +if (err) +return err; err =hwrng_register (&virtio_hwrng);if (err) { - vdev->config->del_vq (vq); + vdev->config->del_vqs (vdev);return err; }
@@ -112,7 +114,7 @@ static void virtrng_remove(struct virtio_device *vdev) { vdev->config->reset (vdev);hwrng_unregister (&virtio_hwrng); - vdev->config->del_vq (vq); + vdev->config->del_vqs (vdev); }static struct virtio_device_id id_table[] = {
drivers/char/virtio_console.c +11 -15
@@ -188,6 +188,9 @@ static void hvc_handle_input(struct virtqueue *vq)* Finally we put our input buffer in the input queue, ready to receive. */ static int __devinit virtcons_probe (struct virtio_device *dev) { +vq_callback_t *callbacks[] = { hvc_handle_input,NULL }; +const char *names[] = {"input" ,"output" }; +struct virtqueue *vqs[2 ];int err; vdev = dev;
@@ -199,20 +202,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) goto fail; } -/* Find the input queue. */ +/* Find the queues. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq (vdev,0 , hvc_handle_input,"input" ); -if (IS_ERR (in_vq)) { - err =PTR_ERR (in_vq); + err = vdev->config->find_vqs (vdev,2 , vqs, callbacks, names); +if (err) goto free; - } - out_vq = vdev->config->find_vq (vdev,1 ,NULL ,"output" ); -if (IS_ERR (out_vq)) { - err =PTR_ERR (out_vq); - goto free_in_vq; - } + in_vq = vqs[0 ]; + out_vq = vqs[1 ];/* Start using the new console output. */ virtio_cons.get_chars = get_chars;
@@ -233,17 +231,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) hvc =hvc_alloc (0 ,0 , &virtio_cons,PAGE_SIZE );if (IS_ERR (hvc)) { err =PTR_ERR (hvc); - goto free_out_vq; + goto free_vqs; }/* Register the input buffer the first time. */ add_inbuf ();return 0 ; -free_out_vq: - vdev->config->del_vq (out_vq); -free_in_vq: - vdev->config->del_vq (in_vq); +free_vqs: + vdev->config->del_vqs (vdev); free:kfree (inbuf); fail:
drivers/lguest/lguest_device.c +34 -2
@@ -313,6 +313,38 @@ static void lg_del_vq(struct virtqueue *vq)kfree (lvq); } +static void lg_del_vqs (struct virtio_device *vdev) +{ +struct virtqueue *vq, *n; + +list_for_each_entry_safe (vq, n, &vdev->vqs, list) +kvm_del_vq (vq); +} + +static int lg_find_vqs (struct virtio_device *vdev,unsigned nvqs, +struct virtqueue *vqs[] + void (*callbacks)[](struct virtqueue *), +const char *names[]) +{ +struct lguest_device *ldev =to_lgdev (vdev); +int i; + +/* We must have this many virtqueues. */ +if (nvqs > ldev->desc->num_vq) +return ERR_PTR (-ENOENT ); + +for (i =0 ; i < nvqs; ++i) { + vqs[i] =lg_find_vq (vdev, i, callbacks[i], names[i]); +if (IS_ERR (vqs[i])) + goto error; + } +return 0 ; + +error: +vp_del_vqs (vdev); +return PTR_ERR (vqs[i]); +} +/* The ops structure which hooks everything together. */ static struct virtio_config_ops lguest_config_ops = { .get_features = lg_get_features,
@@ -322,8 +354,8 @@ static struct virtio_config_ops lguest_config_ops = { .get_status = lg_get_status, .set_status = lg_set_status, .reset = lg_reset, - .find_vq = lg_find_vq, - .del_vq = lg_del_vq, + .find_vqs = lg_find_vqs, + .del_vqs = lg_del_vqs, };/* The root device for the lguest virtio devices. This makes them appear as
drivers/net/virtio_net.c +18 -27
81 lines not on this page · raw message
drivers/s390/kvm/kvm_virtio.c +35 -2
@@ -34,6 +34,7 @@ static void *kvm_devices;struct kvm_device {struct virtio_device vdev; +struct kvm_device_desc *desc; };
@@ -227,6 +228,38 @@ static void kvm_del_vq(struct virtqueue *vq) KVM_S390_VIRTIO_RING_ALIGN)); } +static void vp_del_vqs (struct virtio_device *vdev) +{ +struct virtqueue *vq, *n; + +list_for_each_entry_safe (vq, n, &vdev->vqs, list) +kvm_del_vq (vq); +} + +static int kvm_find_vqs (struct virtio_device *vdev,unsigned nvqs, +struct virtqueue *vqs[], +vq_callback_t *callbacks[], +const char *names[]) +{ +struct kvm_device *kdev =to_kvmdev (vdev); +int i; + +/* We must have this many virtqueues. */ +if (nvqs > kdev->desc->num_vq) +return -ENOENT ; + +for (i =0 ; i < nvqs; ++i) { + vqs[i] =kvm_find_vq (vdev, i, callbacks[i], names[i]); +if (IS_ERR (vqs[i])) + goto error; + } +return 0 ; + +error: +kvm_del_vqs (vdev); +return PTR_ERR (vqs[i]); +} +/* * The config ops structure as defined by virtio config */
@@ -238,8 +271,8 @@ static struct virtio_config_ops kvm_vq_configspace_ops = { .get_status = kvm_get_status, .set_status = kvm_set_status, .reset = kvm_reset, - .find_vq = kvm_find_vq, - .del_vq = kvm_del_vq, + .find_vqs = kvm_find_vqs, + .del_vqs = kvm_del_vqs, };/*
drivers/virtio/virtio_balloon.c +11 -16
@@ -204,6 +204,9 @@ static int balloon(void *_vballoon)static int virtballoon_probe (struct virtio_device *vdev) {struct virtio_balloon *vb; +struct virtqueue *vqs[2 ]; +vq_callback_t *callbacks[] = { balloon_ack, balloon_ack }; +const char *names[] = {"inflate" ,"deflate" };int err; vdev->priv = vb =kmalloc (sizeof (*vb),GFP_KERNEL );
@@ -218,22 +221,17 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->vdev = vdev;/* We expect two virtqueues. */ - vb->inflate_vq = vdev->config->find_vq (vdev,0 , balloon_ack,"inflate" ); -if (IS_ERR (vb->inflate_vq)) { - err =PTR_ERR (vb->inflate_vq); + err = vdev->config->find_vqs (vdev,2 , vqs, callbacks, names); +if (err) goto out_free_vb; - } - vb->deflate_vq = vdev->config->find_vq (vdev,1 , balloon_ack,"deflate" ); -if (IS_ERR (vb->deflate_vq)) { - err =PTR_ERR (vb->deflate_vq); - goto out_del_inflate_vq; - } + vb->inflate_vq = vqs[0 ]; + vb->deflate_vq = vqs[1 ]; vb->thread =kthread_run (balloon, vb,"vballoon" );if (IS_ERR (vb->thread)) { err =PTR_ERR (vb->thread); - goto out_del_deflate_vq; + goto out_del_vqs; } vb->tell_host_first
@@ -241,10 +239,8 @@ static int virtballoon_probe(struct virtio_device *vdev)return 0 ; -out_del_deflate_vq: - vdev->config->del_vq (vb->deflate_vq); -out_del_inflate_vq: - vdev->config->del_vq (vb->inflate_vq); +out_del_vqs: + vdev->config->del_vqs (vdev); out_free_vb:kfree (vb); out:
@@ -264,8 +260,7 @@ static void virtballoon_remove(struct virtio_device *vdev)/* Now we reset the device so we can clean up the queues. */ vdev->config->reset (vdev); - vdev->config->del_vq (vb->deflate_vq); - vdev->config->del_vq (vb->inflate_vq); + vdev->config->del_vqs (vdev);kfree (vb); }
drivers/virtio/virtio_pci.c +30 -7
@@ -276,11 +276,7 @@ static void vp_del_vq(struct virtqueue *vq) {struct virtio_pci_device *vp_dev =to_vp_device (vq->vdev);struct virtio_pci_vq_info *info = vq->priv; -unsigned long flags, size; - -spin_lock_irqsave (&vp_dev->lock, flags); -list_del (&info->node); -spin_unlock_irqrestore (&vp_dev->lock, flags); +unsigned long size;vring_del_virtqueue (vq);
@@ -293,14 +289,41 @@ static void vp_del_vq(struct virtqueue *vq)kfree (info); } +static void vp_del_vqs (struct virtio_device *vdev) +{ +struct virtqueue *vq, *n; + +list_for_each_entry_safe (vq, n, &vdev->vqs, list) +vp_del_vq (vq); +} + +static int vp_find_vqs (struct virtio_device *vdev,unsigned nvqs, +struct virtqueue *vqs[], +vq_callback_t *callbacks[], +const char *names[]) +{ +int i; + +for (i =0 ; i < nvqs; ++i) { + vqs[i] =vp_find_vq (vdev, i, callbacks[i], names[i]); +if (IS_ERR (vqs[i])) + goto error; + } +return 0 ; + +error: +vp_del_vqs (vdev); +return PTR_ERR (vqs[i]); +} +static struct virtio_config_ops virtio_pci_config_ops = { .get = vp_get, .set = vp_set, .get_status = vp_get_status, .set_status = vp_set_status, .reset = vp_reset, - .find_vq = vp_find_vq, - .del_vq = vp_del_vq, + .find_vqs = vp_find_vqs, + .del_vqs = vp_del_vqs, .get_features = vp_get_features, .finalize_features = vp_finalize_features, };
include/linux/virtio_config.h +22 -11
@@ -49,16 +49,26 @@* @set_status: write the status byte * vdev: the virtio_device * status: the new status byte +* @request_vqs: request the specified number of virtqueues +* vdev: the virtio_device +* max_vqs: the max number of virtqueues we want +* If supplied, must call before any virtqueues are instantiated. +* To modify the max number of virtqueues after request_vqs has been +* called, call free_vqs and then request_vqs with a new value. +* @free_vqs: cleanup resources allocated by request_vqs +* vdev: the virtio_device +* If supplied, must call after all virtqueues have been deleted. * @reset: reset the device * vdev: the virtio device * After this, status and feature negotiation must be done again -* @find_vq: find a virtqueue and instantiate it. +* @find_vqs: find virtqueues and instantiate them. * vdev: the virtio_device -* index: the 0-based virtqueue number in case there's more than one. -* callback: the virtqueue callback -* name: the virtqueue name (mainly for debugging) -* Returns the new virtqueue or ERR_PTR() (eg. -ENOENT). -* @del_vq: free a virtqueue found by find_vq(). +* nvqs: the number of virtqueues to find +* vqs: on success, includes new virtqueues +* callbacks: array of callbacks, for each virtqueue +* names: array of virtqueue names (mainly for debugging) +* Returns 0 on success or error status +* @del_vqs: free virtqueues found by find_vqs(). * @get_features: get the array of feature bits for this device. * vdev: the virtio_device * Returns the first 32 feature bits (all we currently need).
@@ -67,6 +77,7 @@* This gives the final feature bits for the device: it can change * the dev->feature bits if it wants. */ +typedef void vq_callback_t (struct virtqueue *);struct virtio_config_ops { void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -76,11 +87,11 @@ struct virtio_config_opsu8 (*get_status)(struct virtio_device *vdev);void (*set_status)(struct virtio_device *vdev,u8 status);void (*reset)(struct virtio_device *vdev); -struct virtqueue *(*find_vq)(struct virtio_device *vdev, -unsigned index, -void (*callback)(struct virtqueue *), -const char *name); -void (*del_vq)(struct virtqueue *vq); +int (*find_vqs)(struct virtio_device *,unsigned nvqs, +struct virtqueue *vqs[], +vq_callback_t *callbacks[], +const char *names[]); +void (*del_vqs)(struct virtio_device *);u32 (*get_features)(struct virtio_device *vdev);void (*finalize_features)(struct virtio_device *vdev); };
net/9p/trans_virtio.c +4 -4
@@ -230,6 +230,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)int err;struct virtio_chan *chan;int index; +vq_callback_t *callbacks[] = { req_done }; +const char *names[] = {"requests" };mutex_lock (&virtio_9p_lock); index = chan_index++;
@@ -246,11 +248,9 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->vdev = vdev;/* We expect one virtqueue, for requests. */ - chan->vq = vdev->config->find_vq (vdev,0 , req_done,"requests" ); -if (IS_ERR (chan->vq)) { - err =PTR_ERR (chan->vq); + err = vdev->config->find_vqs (vdev,1 , &chan->vq, callbacks, name); +if (err) goto out_free_vq; - } chan->vq->vdev->priv = chan;spin_lock_init (&chan->lock);
Signature · 1 line
1.6.3.rc3.1.g830204