]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
virtio: create admin queues alongside other virtqueues
authorJiri Pirko <jiri@nvidia.com>
Tue, 16 Jul 2024 11:35:48 +0000 (13:35 +0200)
committerMichael S. Tsirkin <mst@redhat.com>
Wed, 17 Jul 2024 09:43:21 +0000 (05:43 -0400)
Admin virtqueue is just another virtqueue nothing that special about it.
The current implementation treats it somehow separate though in terms
of creation and deletion. Unify the admin virtqueue creation and
deletion flows to be aligned with the rest of virtqueues, creating
it from vp_find_vqs_*() helpers. Let the admin virtqueue to be deleted
by vp_del_vqs() as the rest.

Call vp_find_one_vq_msix() with slow_path argument being "true" to make
sure that in case of limited interrupt vectors the config vector is used
for admin queue.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Message-Id: <20240716113552.80599-10-jiri@resnulli.us>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/virtio/virtio.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_common.h
drivers/virtio/virtio_pci_modern.c
include/linux/virtio_config.h

index 396d3cd49a1b61156578d92ce824b64ca40cb689..835cfbcb59c87dd777a1868ed4b339521cf06a69 100644 (file)
@@ -305,15 +305,9 @@ static int virtio_dev_probe(struct device *_d)
        if (err)
                goto err;
 
-       if (dev->config->create_avq) {
-               err = dev->config->create_avq(dev);
-               if (err)
-                       goto err;
-       }
-
        err = drv->probe(dev);
        if (err)
-               goto err_probe;
+               goto err;
 
        /* If probe didn't do it, mark device DRIVER_OK ourselves. */
        if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
@@ -326,9 +320,6 @@ static int virtio_dev_probe(struct device *_d)
 
        return 0;
 
-err_probe:
-       if (dev->config->destroy_avq)
-               dev->config->destroy_avq(dev);
 err:
        virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
        return err;
@@ -344,9 +335,6 @@ static void virtio_dev_remove(struct device *_d)
 
        drv->remove(dev);
 
-       if (dev->config->destroy_avq)
-               dev->config->destroy_avq(dev);
-
        /* Driver should have reset device. */
        WARN_ON_ONCE(dev->config->get_status(dev));
 
@@ -524,9 +512,6 @@ int virtio_device_freeze(struct virtio_device *dev)
                }
        }
 
-       if (dev->config->destroy_avq)
-               dev->config->destroy_avq(dev);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(virtio_device_freeze);
@@ -562,16 +547,10 @@ int virtio_device_restore(struct virtio_device *dev)
        if (ret)
                goto err;
 
-       if (dev->config->create_avq) {
-               ret = dev->config->create_avq(dev);
-               if (ret)
-                       goto err;
-       }
-
        if (drv->restore) {
                ret = drv->restore(dev);
                if (ret)
-                       goto err_restore;
+                       goto err;
        }
 
        /* If restore didn't do it, mark device DRIVER_OK ourselves. */
@@ -582,9 +561,6 @@ int virtio_device_restore(struct virtio_device *dev)
 
        return 0;
 
-err_restore:
-       if (dev->config->destroy_avq)
-               dev->config->destroy_avq(dev);
 err:
        virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
        return ret;
index 7c5516ae1f8a8384f21d2b2acd59d0b64313158d..267643bb1cd5335397a7d81276cd4fbb45a7c22d 100644 (file)
@@ -262,9 +262,6 @@ void vp_del_vqs(struct virtio_device *vdev)
        int i;
 
        list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
-               if (vp_dev->is_avq && vp_dev->is_avq(vdev, vq->index))
-                       continue;
-
                if (vp_dev->per_vq_vectors) {
                        int v = vp_dev->vqs[vq->index]->msix_vector;
 
@@ -371,14 +368,23 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                            struct irq_affinity *desc)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       struct virtio_pci_admin_vq *avq = &vp_dev->admin_vq;
        struct virtqueue_info *vqi;
        int i, err, nvectors, allocated_vectors, queue_idx = 0;
+       struct virtqueue *vq;
        bool per_vq_vectors;
+       u16 avq_num = 0;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
                return -ENOMEM;
 
+       if (vp_dev->avq_index) {
+               err = vp_dev->avq_index(vdev, &avq->vq_index, &avq_num);
+               if (err)
+                       goto error_find;
+       }
+
        per_vq_vectors = vector_policy != VP_VQ_VECTOR_POLICY_SHARED;
 
        if (per_vq_vectors) {
@@ -415,6 +421,18 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned int nvqs,
                        goto error_find;
                }
        }
+
+       if (!avq_num)
+               return 0;
+       sprintf(avq->name, "avq.%u", avq->vq_index);
+       vq = vp_find_one_vq_msix(vdev, avq->vq_index, NULL, avq->name, false,
+                                true, &allocated_vectors, vector_policy,
+                                &vp_dev->admin_vq.info);
+       if (IS_ERR(vq)) {
+               err = PTR_ERR(vq);
+               goto error_find;
+       }
+
        return 0;
 
 error_find:
@@ -427,12 +445,21 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                            struct virtqueue_info vqs_info[])
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       struct virtio_pci_admin_vq *avq = &vp_dev->admin_vq;
        int i, err, queue_idx = 0;
+       struct virtqueue *vq;
+       u16 avq_num = 0;
 
        vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
        if (!vp_dev->vqs)
                return -ENOMEM;
 
+       if (vp_dev->avq_index) {
+               err = vp_dev->avq_index(vdev, &avq->vq_index, &avq_num);
+               if (err)
+                       goto out_del_vqs;
+       }
+
        err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
                        dev_name(&vdev->dev), vp_dev);
        if (err)
@@ -456,6 +483,16 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,
                }
        }
 
+       if (!avq_num)
+               return 0;
+       sprintf(avq->name, "avq.%u", avq->vq_index);
+       vq = vp_setup_vq(vdev, queue_idx++, NULL, avq->name, false,
+                        VIRTIO_MSI_NO_VECTOR, &vp_dev->admin_vq.info);
+       if (IS_ERR(vq)) {
+               err = PTR_ERR(vq);
+               goto out_del_vqs;
+       }
+
        return 0;
 out_del_vqs:
        vp_del_vqs(vdev);
index aa43875b6353b6514a78a8a2939dba8da38dac65..de59bb06ec3c9e12ed54e73ed0c9e0d1a7eaacee 100644 (file)
@@ -44,7 +44,7 @@ struct virtio_pci_vq_info {
 
 struct virtio_pci_admin_vq {
        /* Virtqueue info associated with this admin queue. */
-       struct virtio_pci_vq_info info;
+       struct virtio_pci_vq_info *info;
        /* serializing admin commands execution. */
        struct mutex cmd_lock;
        u64 supported_cmds;
@@ -105,7 +105,7 @@ struct virtio_pci_device {
        void (*del_vq)(struct virtio_pci_vq_info *info);
 
        u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector);
-       bool (*is_avq)(struct virtio_device *vdev, unsigned int index);
+       int (*avq_index)(struct virtio_device *vdev, u16 *index, u16 *num);
 };
 
 /* Constants for MSI-X */
index d704947b1aecd3f33517b3717fbeb0dcc6b4d247..5ceb4b2c18df317e155136eb1f1a9fbd26d8ed58 100644 (file)
@@ -63,7 +63,7 @@ static int virtqueue_exec_admin_cmd(struct virtio_pci_admin_vq *admin_vq,
        struct virtqueue *vq;
        int ret, len;
 
-       vq = admin_vq->info.vq;
+       vq = admin_vq->info->vq;
        if (!vq)
                return -EIO;
 
@@ -203,27 +203,12 @@ end:
 
 static void vp_modern_avq_activate(struct virtio_device *vdev)
 {
-       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
-
        if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
                return;
 
-       __virtqueue_unbreak(admin_vq->info.vq);
        virtio_pci_admin_cmd_list_init(vdev);
 }
 
-static void vp_modern_avq_deactivate(struct virtio_device *vdev)
-{
-       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
-
-       if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
-               return;
-
-       __virtqueue_break(admin_vq->info.vq);
-}
-
 static void vp_transport_features(struct virtio_device *vdev, u64 features)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
@@ -418,8 +403,6 @@ static void vp_reset(struct virtio_device *vdev)
        while (vp_modern_get_status(mdev))
                msleep(1);
 
-       vp_modern_avq_deactivate(vdev);
-
        /* Flush pending VQ/configuration callbacks. */
        vp_synchronize_vectors(vdev);
 }
@@ -595,9 +578,6 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
                goto err;
        }
 
-       if (is_avq)
-               vp_dev->admin_vq.info.vq = vq;
-
        return vq;
 
 err:
@@ -741,41 +721,6 @@ static bool vp_get_shm_region(struct virtio_device *vdev,
        return true;
 }
 
-static int vp_modern_create_avq(struct virtio_device *vdev)
-{
-       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       struct virtio_pci_admin_vq *avq = &vp_dev->admin_vq;
-       struct virtqueue *vq;
-       u16 num;
-       int err;
-
-       err = vp_avq_index(vdev, &avq->vq_index, &num);
-       if (err || !num)
-               return err;
-
-       sprintf(avq->name, "avq.%u", avq->vq_index);
-       vq = vp_dev->setup_vq(vp_dev, &vp_dev->admin_vq.info, avq->vq_index, NULL,
-                             avq->name, NULL, VIRTIO_MSI_NO_VECTOR);
-       if (IS_ERR(vq)) {
-               dev_err(&vdev->dev, "failed to setup admin virtqueue, err=%ld",
-                       PTR_ERR(vq));
-               return PTR_ERR(vq);
-       }
-
-       vp_modern_set_queue_enable(&vp_dev->mdev, avq->info.vq->index, true);
-       return 0;
-}
-
-static void vp_modern_destroy_avq(struct virtio_device *vdev)
-{
-       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
-       if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
-               return;
-
-       vp_dev->del_vq(&vp_dev->admin_vq.info);
-}
-
 static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
        .get            = NULL,
        .set            = NULL,
@@ -794,8 +739,6 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
        .get_shm_region  = vp_get_shm_region,
        .disable_vq_and_reset = vp_modern_disable_vq_and_reset,
        .enable_vq_after_reset = vp_modern_enable_vq_after_reset,
-       .create_avq = vp_modern_create_avq,
-       .destroy_avq = vp_modern_destroy_avq,
 };
 
 static const struct virtio_config_ops virtio_pci_config_ops = {
@@ -816,8 +759,6 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
        .get_shm_region  = vp_get_shm_region,
        .disable_vq_and_reset = vp_modern_disable_vq_and_reset,
        .enable_vq_after_reset = vp_modern_enable_vq_after_reset,
-       .create_avq = vp_modern_create_avq,
-       .destroy_avq = vp_modern_destroy_avq,
 };
 
 /* the PCI probing function */
@@ -841,7 +782,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
        vp_dev->config_vector = vp_config_vector;
        vp_dev->setup_vq = setup_vq;
        vp_dev->del_vq = del_vq;
-       vp_dev->is_avq = vp_is_avq;
+       vp_dev->avq_index = vp_avq_index;
        vp_dev->isr = mdev->isr;
        vp_dev->vdev.id = mdev->id;
 
index ab4b9a3fef6ba12fecf83cc89f120f4662f2ab9c..169c7d367facb36dcabf9596068580ea8b8516c7 100644 (file)
@@ -104,8 +104,6 @@ struct virtqueue_info {
  *     Returns 0 on success or error status
  *     If disable_vq_and_reset is set, then enable_vq_after_reset must also be
  *     set.
- * @create_avq: create admin virtqueue resource.
- * @destroy_avq: destroy admin virtqueue resource.
  */
 struct virtio_config_ops {
        void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -133,8 +131,6 @@ struct virtio_config_ops {
                               struct virtio_shm_region *region, u8 id);
        int (*disable_vq_and_reset)(struct virtqueue *vq);
        int (*enable_vq_after_reset)(struct virtqueue *vq);
-       int (*create_avq)(struct virtio_device *vdev);
-       void (*destroy_avq)(struct virtio_device *vdev);
 };
 
 /* If driver didn't advertise the feature, it will never appear. */