summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-18 13:53:29 +0100
committerMark Brown <broonie@kernel.org>2026-09-18 13:53:29 +0100
commit45633831fe947f97c2951d0bacb9f5d10f8e47e7 (patch)
tree53c79458c84894a303980e651933f70323fdab73
parent1a6ac810cbf46c3f8f26f38beac78c2035ebcc33 (diff)
parentdd886653d2038a510a21bff476fa1be0422a4fb9 (diff)
downloadlinux-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.c10
-rw-r--r--drivers/platform/mellanox/mlxbf-tmfifo.c15
-rw-r--r--drivers/remoteproc/remoteproc_core.c12
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c37
-rw-r--r--drivers/s390/virtio/virtio_ccw.c6
-rw-r--r--drivers/virtio/virtio_vdpa.c34
-rw-r--r--include/linux/remoteproc.h3
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;