diff options
| author | Mark Brown <broonie@kernel.org> | 2026-09-18 13:53:29 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-09-18 13:53:29 +0100 |
| commit | 45633831fe947f97c2951d0bacb9f5d10f8e47e7 (patch) | |
| tree | 53c79458c84894a303980e651933f70323fdab73 | |
| parent | 1a6ac810cbf46c3f8f26f38beac78c2035ebcc33 (diff) | |
| parent | dd886653d2038a510a21bff476fa1be0422a4fb9 (diff) | |
| download | linux-next-45633831fe947f97c2951d0bacb9f5d10f8e47e7.tar.gz linux-next-45633831fe947f97c2951d0bacb9f5d10f8e47e7.zip | |
Merge branch 'linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git
| -rw-r--r-- | arch/um/drivers/virtio_uml.c | 10 | ||||
| -rw-r--r-- | drivers/platform/mellanox/mlxbf-tmfifo.c | 15 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 12 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_virtio.c | 37 | ||||
| -rw-r--r-- | drivers/s390/virtio/virtio_ccw.c | 6 | ||||
| -rw-r--r-- | drivers/virtio/virtio_vdpa.c | 34 | ||||
| -rw-r--r-- | include/linux/remoteproc.h | 3 |
7 files changed, 102 insertions, 15 deletions
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 7425a8548141..1f2e62e29a27 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -20,6 +20,7 @@ * * Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd. */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -869,6 +870,14 @@ static void vu_reset(struct virtio_device *vdev) vu_dev->status = 0; } +static void vu_synchronize_cbs(struct virtio_device *vdev) +{ + struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); + + if (vu_dev->irq != UM_IRQ_ALLOC) + synchronize_irq(vu_dev->irq); +} + static void vu_del_vq(struct virtqueue *vq) { struct virtio_uml_vq_info *info = vq->priv; @@ -1121,6 +1130,7 @@ static const struct virtio_config_ops virtio_uml_config_ops = { .reset = vu_reset, .find_vqs = vu_find_vqs, .del_vqs = vu_del_vqs, + .synchronize_cbs = vu_synchronize_cbs, .get_features = vu_get_features, .finalize_features = vu_finalize_features, .bus_name = vu_bus_name, diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index 3c6408581373..664bec20a7ae 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1135,6 +1135,20 @@ static void mlxbf_tmfifo_virtio_reset(struct virtio_device *vdev) tm_vdev->status = 0; } +/* Synchronize with callbacks running in the FIFO work item. */ +static void mlxbf_tmfifo_virtio_synchronize_cbs(struct virtio_device *vdev) +{ + struct mlxbf_tmfifo_vdev *tm_vdev = mlxbf_vdev_to_tmfifo(vdev); + struct mlxbf_tmfifo *fifo = tm_vdev->vrings[0].fifo; + unsigned long flags; + int i; + + for (i = 0; i < ARRAY_SIZE(fifo->spin_lock); i++) { + spin_lock_irqsave(&fifo->spin_lock[i], flags); + spin_unlock_irqrestore(&fifo->spin_lock[i], flags); + } +} + /* Read the value of a configuration field. */ static void mlxbf_tmfifo_virtio_get(struct virtio_device *vdev, unsigned int offset, @@ -1179,6 +1193,7 @@ static const struct virtio_config_ops mlxbf_tmfifo_virtio_config_ops = { .find_vqs = mlxbf_tmfifo_virtio_find_vqs, .del_vqs = mlxbf_tmfifo_virtio_del_vqs, .reset = mlxbf_tmfifo_virtio_reset, + .synchronize_cbs = mlxbf_tmfifo_virtio_synchronize_cbs, .set_status = mlxbf_tmfifo_virtio_set_status, .get_status = mlxbf_tmfifo_virtio_get_status, .get = mlxbf_tmfifo_virtio_get, diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 1ed406714849..d131b82af320 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2410,6 +2410,7 @@ static void rproc_type_release(struct device *dev) dev_info(&rproc->dev, "releasing %s\n", rproc->name); + cleanup_srcu_struct(&rproc->vq_srcu); idr_destroy(&rproc->notifyids); if (rproc->index >= 0) @@ -2507,6 +2508,11 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, if (!rproc) return NULL; + if (init_srcu_struct(&rproc->vq_srcu)) { + kfree(rproc); + return NULL; + } + rproc->priv = &rproc[1]; rproc->auto_boot = true; rproc->elf_class = ELFCLASSNONE; @@ -2571,6 +2577,9 @@ EXPORT_SYMBOL(rproc_alloc); * * If no one holds any reference to rproc anymore, then its refcount would * now drop to zero, and it would be freed. + * + * Context: Any context, but the last reference must not be dropped from + * atomic context. */ void rproc_free(struct rproc *rproc) { @@ -2586,6 +2595,9 @@ EXPORT_SYMBOL(rproc_free); * * If no one holds any reference to rproc anymore, then its refcount would * now drop to zero, and it would be freed. + * + * Context: Any context, but the last reference must not be dropped from + * atomic context. */ void rproc_put(struct rproc *rproc) { diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index d5e9ff045a28..7fefb4bd7adc 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -23,6 +23,7 @@ #include <linux/err.h> #include <linux/kref.h> #include <linux/slab.h> +#include <linux/srcu.h> #include "remoteproc_internal.h" @@ -88,15 +89,23 @@ static bool rproc_virtio_notify(struct virtqueue *vq) */ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid) { + irqreturn_t ret = IRQ_NONE; struct rproc_vring *rvring; + struct virtqueue *vq; + int idx; dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid); + idx = srcu_read_lock(&rproc->vq_srcu); + rvring = idr_find(&rproc->notifyids, notifyid); - if (!rvring || !rvring->vq) - return IRQ_NONE; + vq = rvring ? READ_ONCE(rvring->vq) : NULL; + if (vq) + ret = vring_interrupt(0, vq); - return vring_interrupt(0, rvring->vq); + srcu_read_unlock(&rproc->vq_srcu, idx); + + return ret; } EXPORT_SYMBOL(rproc_vq_interrupt); @@ -153,7 +162,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, vq->num_max = num; - rvring->vq = vq; + WRITE_ONCE(rvring->vq, vq); vq->priv = rvring; /* Update vring in resource table */ @@ -165,14 +174,20 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, static void __rproc_virtio_del_vqs(struct virtio_device *vdev) { + struct rproc *rproc = vdev_to_rproc(vdev); struct virtqueue *vq, *n; struct rproc_vring *rvring; - list_for_each_entry_safe(vq, n, &vdev->vqs, list) { + list_for_each_entry(vq, &vdev->vqs, list) { rvring = vq->priv; - rvring->vq = NULL; - vring_del_virtqueue(vq); + WRITE_ONCE(rvring->vq, NULL); } + + /* Synchronize with rproc_vq_interrupt() callers that found a queue. */ + synchronize_srcu(&rproc->vq_srcu); + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) + vring_del_virtqueue(vq); } static void rproc_virtio_del_vqs(struct virtio_device *vdev) @@ -242,6 +257,13 @@ static void rproc_virtio_reset(struct virtio_device *vdev) dev_dbg(&vdev->dev, "reset !\n"); } +static void rproc_virtio_synchronize_cbs(struct virtio_device *vdev) +{ + struct rproc *rproc = vdev_to_rproc(vdev); + + synchronize_srcu(&rproc->vq_srcu); +} + /* provide the vdev features as retrieved from the firmware */ static u64 rproc_virtio_get_features(struct virtio_device *vdev) { @@ -330,6 +352,7 @@ static const struct virtio_config_ops rproc_virtio_config_ops = { .find_vqs = rproc_virtio_find_vqs, .del_vqs = rproc_virtio_del_vqs, .reset = rproc_virtio_reset, + .synchronize_cbs = rproc_virtio_synchronize_cbs, .set_status = rproc_virtio_set_status, .get_status = rproc_virtio_get_status, .get = rproc_virtio_get, diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index bab6cad3fd5c..552d77998012 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -1062,7 +1062,7 @@ static void virtio_ccw_synchronize_cbs(struct virtio_device *vdev) struct virtio_ccw_device *vcdev = to_vc_device(vdev); struct airq_info *info = vcdev->airq_info; - if (info) { + if (vcdev->is_thinint && info) { /* * This device uses adapter interrupts: synchronize with * vring_interrupt() called by virtio_airq_handler() @@ -1204,13 +1204,11 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, vcdev->err = -EIO; } virtio_ccw_check_activity(vcdev, activity); -#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION /* * Paired with virtio_ccw_synchronize_cbs() and interrupts are * disabled here. */ read_lock(&vcdev->irq_lock); -#endif for_each_set_bit(i, indicators(vcdev), sizeof(*indicators(vcdev)) * BITS_PER_BYTE) { /* The bit clear must happen before the vring kick. */ @@ -1219,9 +1217,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, vq = virtio_ccw_vq_by_ind(vcdev, i); vring_interrupt(0, vq); } -#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION read_unlock(&vcdev->irq_lock); -#endif if (test_bit(0, indicators2(vcdev))) { virtio_config_changed(&vcdev->vdev); clear_bit(0, indicators2(vcdev)); diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index 6bcf4567a929..f9559b6b2e0b 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -12,6 +12,7 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/srcu.h> #include <linux/uuid.h> #include <linux/group_cpus.h> #include <linux/virtio.h> @@ -27,6 +28,7 @@ struct virtio_vdpa_device { struct virtio_device vdev; struct vdpa_device *vdpa; + struct srcu_struct cb_srcu; u64 features; }; @@ -114,8 +116,11 @@ static bool virtio_vdpa_notify_with_data(struct virtqueue *vq) static irqreturn_t virtio_vdpa_config_cb(void *private) { struct virtio_vdpa_device *vd_dev = private; + int idx; + idx = srcu_read_lock(&vd_dev->cb_srcu); virtio_config_changed(&vd_dev->vdev); + srcu_read_unlock(&vd_dev->cb_srcu, idx); return IRQ_HANDLED; } @@ -123,8 +128,22 @@ static irqreturn_t virtio_vdpa_config_cb(void *private) static irqreturn_t virtio_vdpa_virtqueue_cb(void *private) { struct virtqueue *vq = private; + struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vq->vdev); + irqreturn_t ret; + int idx; + + idx = srcu_read_lock(&vd_dev->cb_srcu); + ret = vring_interrupt(0, vq); + srcu_read_unlock(&vd_dev->cb_srcu, idx); + + return ret; +} + +static void virtio_vdpa_synchronize_cbs(struct virtio_device *vdev) +{ + struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev); - return vring_interrupt(0, vq); + synchronize_srcu(&vd_dev->cb_srcu); } static struct virtqueue * @@ -440,6 +459,7 @@ static const struct virtio_config_ops virtio_vdpa_config_ops = { .reset = virtio_vdpa_reset, .find_vqs = virtio_vdpa_find_vqs, .del_vqs = virtio_vdpa_del_vqs, + .synchronize_cbs = virtio_vdpa_synchronize_cbs, .get_features = virtio_vdpa_get_features, .finalize_features = virtio_vdpa_finalize_features, .bus_name = virtio_vdpa_bus_name, @@ -454,6 +474,7 @@ static void virtio_vdpa_release_dev(struct device *_d) struct virtio_vdpa_device *vd_dev = container_of(vdev, struct virtio_vdpa_device, vdev); + cleanup_srcu_struct(&vd_dev->cb_srcu); kfree(vd_dev); } @@ -467,6 +488,11 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa) if (!vd_dev) return -ENOMEM; + if (init_srcu_struct(&vd_dev->cb_srcu)) { + kfree(vd_dev); + return -ENOMEM; + } + vd_dev->vdev.dev.parent = vdpa->map ? &vdpa->dev : vdpa_get_map(vdpa).dma_dev; vd_dev->vdev.dev.release = virtio_vdpa_release_dev; @@ -489,10 +515,12 @@ static int virtio_vdpa_probe(struct vdpa_device *vdpa) return 0; err: - if (reg_dev) + if (reg_dev) { put_device(&vd_dev->vdev.dev); - else + } else { + cleanup_srcu_struct(&vd_dev->cb_srcu); kfree(vd_dev); + } return ret; } diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index a44368737b39..ff0ad1e12c01 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -15,6 +15,7 @@ #include <linux/cdev.h> #include <linux/completion.h> #include <linux/idr.h> +#include <linux/srcu.h> #include <linux/of.h> #include <linux/rsc_table.h> @@ -228,6 +229,7 @@ enum rproc_features { * @mappings: list of iommu mappings we initiated, needed on shutdown * @bootaddr: address of first instruction to boot rproc with (optional) * @rvdevs: list of remote virtio devices + * @vq_srcu: SRCU domain for the virtqueue callbacks of @rvdevs * @subdevs: list of subdevices, to following the running state * @notifyids: idr for dynamically assigning rproc-wide unique notify ids * @index: index of this rproc device @@ -274,6 +276,7 @@ struct rproc { struct list_head mappings; u64 bootaddr; struct list_head rvdevs; + struct srcu_struct vq_srcu; struct list_head subdevs; struct idr notifyids; int index; |
