* [PATCH v2 1/4] remoteproc: virtio: Decouple vdev from the parent pdev
2026-11-14 8:06 [PATCH v2 0/4] remoteproc: virtio: Fixes and cleanups in the vdev<->pdev relationship Francesco Valla
@ 2026-11-14 8:06 ` Francesco Valla
2026-11-14 8:06 ` [PATCH v2 2/4] remoteproc: virtio: Rework memory release Francesco Valla
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Francesco Valla @ 2026-11-14 8:06 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Arnaud Pouliquen, Joakim Zhang
Cc: linux-remoteproc, linux-kernel, Francesco Valla
The rproc-virtio platform device can have a lifetime different from the
virtio_device it registers. During cleanup (e.g.: when a remoteproc is
stopped) the platform device is de-registered by the remoteproc core,
but the related virtio_device might be released later; if this happens,
rproc_virtio_dev_release() will try to de-reference a NULL pointer as
part of vdev_to_rvdev(). This can easily be reproduced with
CONFIG_DEBUG_KOBJECT_RELEASE.
Remove the access to the platform device structure from the cleanup path
and interact instead with its backing device, whose refcount was
explicitly increased during rproc_add_virtio_dev() and will be
decremented as part of rproc_virtio_dev_release(). The same is done for
the pdev de-reference inside vdev_to_rvdev(), even if no more used
during cleanup, to maintain the same access pattern.
While at it, fix the comments on the specific matter.
Fixes: 1d7b61c06dc3 ("remoteproc: virtio: Create platform device for the remoteproc_virtio")
Signed-off-by: Francesco Valla <francesco@valla.it>
---
drivers/remoteproc/remoteproc_virtio.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 29a3a4c18097..b59f4acbb630 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -49,11 +49,7 @@ static int copy_dma_range_map(struct device *to, struct device *from)
static struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
{
- struct platform_device *pdev;
-
- pdev = container_of(vdev->dev.parent, struct platform_device, dev);
-
- return platform_get_drvdata(pdev);
+ return dev_get_drvdata(vdev->dev.parent);
}
static struct rproc *vdev_to_rproc(struct virtio_device *vdev)
@@ -348,7 +344,7 @@ static const struct virtio_config_ops rproc_virtio_config_ops = {
/*
* This function is called whenever vdev is released, and is responsible
- * to decrement the remote processor's refcount which was taken when vdev was
+ * to decrement the platform device's refcount which was taken when vdev was
* added.
*
* Never call this function directly; it will be called by the driver
@@ -357,14 +353,13 @@ static const struct virtio_config_ops rproc_virtio_config_ops = {
static void rproc_virtio_dev_release(struct device *dev)
{
struct virtio_device *vdev = dev_to_virtio(dev);
- struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
- kfree(vdev);
+ of_reserved_mem_device_release(dev->parent);
+ dma_release_coherent_memory(dev->parent);
- of_reserved_mem_device_release(&rvdev->pdev->dev);
- dma_release_coherent_memory(&rvdev->pdev->dev);
+ put_device(dev->parent);
- put_device(&rvdev->pdev->dev);
+ kfree(vdev);
}
/**
@@ -372,8 +367,7 @@ static void rproc_virtio_dev_release(struct device *dev)
* @rvdev: the remote vdev
* @id: the device type identification (used to match it with a driver).
*
- * This function registers a virtio device. This vdev's partent is
- * the rproc device.
+ * This function registers a virtio device with the platform device as parent.
*
* Return: 0 on success or an appropriate error value otherwise
*/
@@ -448,7 +442,7 @@ static int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
vdev->dev.parent = dev;
vdev->dev.release = rproc_virtio_dev_release;
- /* Reference the vdev and vring allocations */
+ /* Reference the parent device, which will be used during teardown. */
get_device(dev);
ret = register_virtio_device(vdev);
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 2/4] remoteproc: virtio: Rework memory release
2026-11-14 8:06 [PATCH v2 0/4] remoteproc: virtio: Fixes and cleanups in the vdev<->pdev relationship Francesco Valla
2026-11-14 8:06 ` [PATCH v2 1/4] remoteproc: virtio: Decouple vdev from the parent pdev Francesco Valla
@ 2026-11-14 8:06 ` Francesco Valla
2026-11-14 8:06 ` [PATCH v2 3/4] remoteproc: virtio: Drop rvdevs list and associated functions Francesco Valla
2026-11-14 8:06 ` [PATCH v2 4/4] remoteproc: virtio: Stop de-referencing pdev from its children Francesco Valla
3 siblings, 0 replies; 5+ messages in thread
From: Francesco Valla @ 2026-11-14 8:06 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Arnaud Pouliquen, Joakim Zhang
Cc: linux-remoteproc, linux-kernel, Francesco Valla
The current memory release setup has two issues, which may happen in
specific corner cases:
- a failure in kzalloc_obj() during subdev.start() would keep alive
the association between the pdev and the memory setups done just
before, leaking them and preventing further start attempts;
- in case of a crash recovery restart, where the pdev is maintained
but subdev.start() is called again, a delayed release of the
previous vdev either makes the start fail with -EBUSY (dedicated
vdev buffer) or, when falling back to the parent's reserved memory,
makes the memory setup disappear underneath the newly created vdev.
Move the memory release calls to subdev.stop(), symmetrically to what
happens in subdev.start(), and add them to the failure path of the
start() itself. The get()/put() actions on the pdev, that are now
useless since no access to it is performed during the vdev release, can
be safely dropped.
Fixes: b327c72753d6 ("remoteproc: virtio: Fix wdg cannot recovery remote processor")
Signed-off-by: Francesco Valla <francesco@valla.it>
---
drivers/remoteproc/remoteproc_virtio.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index b59f4acbb630..6cfdab831185 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -344,8 +344,7 @@ static const struct virtio_config_ops rproc_virtio_config_ops = {
/*
* This function is called whenever vdev is released, and is responsible
- * to decrement the platform device's refcount which was taken when vdev was
- * added.
+ * to free the memory allocated for the vdev.
*
* Never call this function directly; it will be called by the driver
* core when needed.
@@ -354,11 +353,6 @@ static void rproc_virtio_dev_release(struct device *dev)
{
struct virtio_device *vdev = dev_to_virtio(dev);
- of_reserved_mem_device_release(dev->parent);
- dma_release_coherent_memory(dev->parent);
-
- put_device(dev->parent);
-
kfree(vdev);
}
@@ -434,27 +428,32 @@ static int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
/* Allocate virtio device */
vdev = kzalloc_obj(*vdev);
- if (!vdev)
- return -ENOMEM;
+ if (!vdev) {
+ ret = -ENOMEM;
+ goto release_mem;
+ }
vdev->id.device = id;
vdev->config = &rproc_virtio_config_ops;
vdev->dev.parent = dev;
vdev->dev.release = rproc_virtio_dev_release;
- /* Reference the parent device, which will be used during teardown. */
- get_device(dev);
-
ret = register_virtio_device(vdev);
if (ret) {
put_device(&vdev->dev);
dev_err(dev, "failed to register vdev: %d\n", ret);
- return ret;
+ goto release_mem;
}
dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
return 0;
+
+release_mem:
+ of_reserved_mem_device_release(dev);
+ dma_release_coherent_memory(dev);
+
+ return ret;
}
/**
@@ -490,6 +489,9 @@ static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
ret = device_for_each_child(dev, NULL, rproc_remove_virtio_dev);
if (ret)
dev_warn(dev, "can't remove vdev child device: %d\n", ret);
+
+ of_reserved_mem_device_release(dev);
+ dma_release_coherent_memory(dev);
}
static int rproc_virtio_probe(struct platform_device *pdev)
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 3/4] remoteproc: virtio: Drop rvdevs list and associated functions
2026-11-14 8:06 [PATCH v2 0/4] remoteproc: virtio: Fixes and cleanups in the vdev<->pdev relationship Francesco Valla
2026-11-14 8:06 ` [PATCH v2 1/4] remoteproc: virtio: Decouple vdev from the parent pdev Francesco Valla
2026-11-14 8:06 ` [PATCH v2 2/4] remoteproc: virtio: Rework memory release Francesco Valla
@ 2026-11-14 8:06 ` Francesco Valla
2026-11-14 8:06 ` [PATCH v2 4/4] remoteproc: virtio: Stop de-referencing pdev from its children Francesco Valla
3 siblings, 0 replies; 5+ messages in thread
From: Francesco Valla @ 2026-11-14 8:06 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Arnaud Pouliquen, Joakim Zhang
Cc: linux-remoteproc, linux-kernel, Francesco Valla
The rvdevs linked list is kept at rproc side to track the rproc_vdev
devices registered at runtime and de-register them during cleanup, but
the same information can be obtained from the driver core using
parent-child relationships coupled with driver name.
Drop the list and all associated functions and de-register the virtio
children of a remoteproc using device_for_each_child(), with the
following benefits:
- increased separation between the core and virtio parts of remoteproc;
- reduction in code and occupied memory;
- the platform devices whose probe fail are now de-registered correctly
during remoteproc cleanup.
A dedicated macro is used to register rproc-virtio platform devices to
avoid duplication (in code, not in memory) of the same string.
Signed-off-by: Francesco Valla <francesco@valla.it>
---
drivers/remoteproc/remoteproc_core.c | 34 ++++++++++++++++----------------
drivers/remoteproc/remoteproc_internal.h | 4 ++--
drivers/remoteproc/remoteproc_virtio.c | 5 +----
include/linux/remoteproc.h | 6 +-----
4 files changed, 21 insertions(+), 28 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index d5fa9d23bd5c..296b955f415f 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -431,17 +431,6 @@ void rproc_free_vring(struct rproc_vring *rvring)
}
}
-void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev)
-{
- if (rvdev && rproc)
- list_add_tail(&rvdev->node, &rproc->rvdevs);
-}
-
-void rproc_remove_rvdev(struct rproc_vdev *rvdev)
-{
- if (rvdev)
- list_del(&rvdev->node);
-}
/**
* rproc_handle_vdev() - handle a vdev fw resource
* @rproc: the remote processor
@@ -513,7 +502,8 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
* as device id, then we get duplication in sysfs, so need to use
* PLATFORM_DEVID_AUTO to auto select device id.
*/
- pdev = platform_device_register_data(dev, "rproc-virtio", PLATFORM_DEVID_AUTO, &rvdev_data,
+ pdev = platform_device_register_data(dev, RPROC_VIRTIO_DRV_NAME,
+ PLATFORM_DEVID_AUTO, &rvdev_data,
sizeof(rvdev_data));
if (IS_ERR(pdev)) {
dev_err(dev, "failed to create rproc-virtio device\n");
@@ -1212,6 +1202,19 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc)
return 0;
}
+static int rproc_unregister_vdev_pdev(struct device *dev, void *data)
+{
+ struct platform_device *pdev;
+
+ if (!dev_is_platform(dev))
+ return 0;
+
+ pdev = to_platform_device(dev);
+ if (!strcmp(pdev->name, RPROC_VIRTIO_DRV_NAME))
+ platform_device_unregister(pdev);
+
+ return 0;
+}
/**
* rproc_resource_cleanup() - clean up and free all acquired resources
@@ -1224,7 +1227,6 @@ void rproc_resource_cleanup(struct rproc *rproc)
{
struct rproc_mem_entry *entry, *tmp;
struct rproc_debug_trace *trace, *ttmp;
- struct rproc_vdev *rvdev, *rvtmp;
struct device *dev = &rproc->dev;
/* clean up debugfs trace entries */
@@ -1258,9 +1260,8 @@ void rproc_resource_cleanup(struct rproc *rproc)
kfree(entry);
}
- /* clean up remote vdev entries */
- list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
- platform_device_unregister(rvdev->pdev);
+ /* unregister platform devices */
+ device_for_each_child(&rproc->dev, NULL, rproc_unregister_vdev_pdev);
rproc_coredump_cleanup(rproc);
}
@@ -2521,7 +2522,6 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
INIT_LIST_HEAD(&rproc->carveouts);
INIT_LIST_HEAD(&rproc->mappings);
INIT_LIST_HEAD(&rproc->traces);
- INIT_LIST_HEAD(&rproc->rvdevs);
INIT_LIST_HEAD(&rproc->subdevs);
INIT_LIST_HEAD(&rproc->dump_segments);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 3a742ef6ef60..d587a3301811 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -18,6 +18,8 @@
#include <linux/io.h>
#endif
+#define RPROC_VIRTIO_DRV_NAME "rproc-virtio"
+
struct rproc;
struct rproc_debug_trace {
@@ -122,8 +124,6 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
const struct firmware *fw);
struct rproc_mem_entry *
rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
-void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev);
-void rproc_remove_rvdev(struct rproc_vdev *rvdev);
#ifdef CONFIG_HAS_IOMEM
static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 6cfdab831185..403519e78ee3 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -549,8 +549,6 @@ static int rproc_virtio_probe(struct platform_device *pdev)
goto unwind_vring_allocations;
}
- rproc_add_rvdev(rproc, rvdev);
-
rvdev->subdev.start = rproc_vdev_do_start;
rvdev->subdev.stop = rproc_vdev_do_stop;
@@ -588,7 +586,6 @@ static void rproc_virtio_remove(struct platform_device *pdev)
}
rproc_remove_subdev(rproc, &rvdev->subdev);
- rproc_remove_rvdev(rvdev);
put_device(&rproc->dev);
}
@@ -598,7 +595,7 @@ static struct platform_driver rproc_virtio_driver = {
.probe = rproc_virtio_probe,
.remove = rproc_virtio_remove,
.driver = {
- .name = "rproc-virtio",
+ .name = RPROC_VIRTIO_DRV_NAME,
},
};
builtin_platform_driver(rproc_virtio_driver);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 00019b1895e6..77ea0e1067e0 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -228,8 +228,7 @@ enum rproc_features {
* @carveouts: list of physically contiguous memory allocations
* @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
+ * @vq_srcu: SRCU domain for the virtqueue callbacks of the virtio devices
* @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
@@ -275,7 +274,6 @@ struct rproc {
struct list_head carveouts;
struct list_head mappings;
u64 bootaddr;
- struct list_head rvdevs;
struct srcu_struct vq_srcu;
struct list_head subdevs;
struct idr notifyids;
@@ -351,7 +349,6 @@ struct rproc_vring {
* @subdev: handle for registering the vdev as a rproc subdevice
* @pdev: remoteproc virtio platform device
* @id: virtio device id (as in virtio_ids.h)
- * @node: list node
* @rproc: the rproc handle
* @vring: the vrings for this vdev
* @rsc_offset: offset of the vdev's resource entry
@@ -362,7 +359,6 @@ struct rproc_vdev {
struct platform_device *pdev;
unsigned int id;
- struct list_head node;
struct rproc *rproc;
struct rproc_vring vring[RVDEV_NUM_VRINGS];
u32 rsc_offset;
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 4/4] remoteproc: virtio: Stop de-referencing pdev from its children
2026-11-14 8:06 [PATCH v2 0/4] remoteproc: virtio: Fixes and cleanups in the vdev<->pdev relationship Francesco Valla
` (2 preceding siblings ...)
2026-11-14 8:06 ` [PATCH v2 3/4] remoteproc: virtio: Drop rvdevs list and associated functions Francesco Valla
@ 2026-11-14 8:06 ` Francesco Valla
3 siblings, 0 replies; 5+ messages in thread
From: Francesco Valla @ 2026-11-14 8:06 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Arnaud Pouliquen, Joakim Zhang
Cc: linux-remoteproc, linux-kernel, Francesco Valla
The struct device underlying the rproc-virtio platform device is used to
perform some operations during the lifetime of the rproc_vdev. It is
however no longer necessary to keep a pointer to the platform device,
which is not really used but only de-referenced to access its struct
device; a pointer to the struct device itself is sufficient.
Signed-off-by: Francesco Valla <francesco@valla.it>
---
drivers/remoteproc/remoteproc_virtio.c | 6 +++---
include/linux/remoteproc.h | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 403519e78ee3..16c48ed45b48 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -368,7 +368,7 @@ static void rproc_virtio_dev_release(struct device *dev)
static int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
{
struct rproc *rproc = rvdev->rproc;
- struct device *dev = &rvdev->pdev->dev;
+ struct device *dev = rvdev->dev;
struct virtio_device *vdev;
struct rproc_mem_entry *mem;
int ret;
@@ -483,7 +483,7 @@ static int rproc_vdev_do_start(struct rproc_subdev *subdev)
static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
{
struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
- struct device *dev = &rvdev->pdev->dev;
+ struct device *dev = rvdev->dev;
int ret;
ret = device_for_each_child(dev, NULL, rproc_remove_virtio_dev);
@@ -510,6 +510,7 @@ static int rproc_virtio_probe(struct platform_device *pdev)
if (!rvdev)
return -ENOMEM;
+ rvdev->dev = dev;
rvdev->id = rvdev_data->id;
rvdev->rproc = rproc;
rvdev->index = rvdev_data->index;
@@ -528,7 +529,6 @@ static int rproc_virtio_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rvdev);
- rvdev->pdev = pdev;
rsc = rvdev_data->rsc;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 77ea0e1067e0..f3074c69098f 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -347,7 +347,7 @@ struct rproc_vring {
/**
* struct rproc_vdev - remoteproc state for a supported virtio device
* @subdev: handle for registering the vdev as a rproc subdevice
- * @pdev: remoteproc virtio platform device
+ * @dev: parent remoteproc virtio device
* @id: virtio device id (as in virtio_ids.h)
* @rproc: the rproc handle
* @vring: the vrings for this vdev
@@ -356,7 +356,7 @@ struct rproc_vring {
*/
struct rproc_vdev {
struct rproc_subdev subdev;
- struct platform_device *pdev;
+ struct device *dev;
unsigned int id;
struct rproc *rproc;
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread