On Tue, May 19, 2026 at 11:45:56AM +0530, Ekansh Gupta via B4 Relay wrote:
> From: Ekansh Gupta <[email protected]>
> 
> Introduce the CB (compute context bank) device management layer for the
> QDA driver. Each DSP domain node in the device tree may contain child
> nodes with compatible "qcom,fastrpc-compute-cb", each representing one
> IOMMU context bank. The driver enumerates those child nodes during
> RPMsg probe and creates a corresponding device on the qda-compute-cb
> bus for each one.
> 
> The CB devices are created via create_qda_cb_device(), which registers
> them on the qda-compute-cb bus so that the IOMMU subsystem assigns each
> device its own IOMMU domain, enabling per-session address space
> isolation for DSP buffer mapping.
> 
> The new qda_cb.c file provides two functions:
> 
>   qda_create_cb_device()
>     Reads the "reg" property from the DT child node to obtain the
>     stream ID, constructs a unique device name of the form
>     "qda-cb-<dsp>-<sid>", and registers the device on the compute bus.
>     A qda_cb_dev entry is allocated and appended to qdev->cb_devs so
>     that the list can be walked during teardown.
> 
>   qda_destroy_cb_device()
>     Removes the device from its IOMMU group before calling
>     device_unregister(), ensuring the IOMMU domain is released cleanly.
> 
> CB devices are populated before the DRM device is registered and
> destroyed before it is unplugged, so no DRM operation can race with
> CB teardown. On probe failure after population, qda_cb_unpopulate()
> is called to clean up any CBs that were successfully created before
> the error.
> 
> Assisted-by: Claude:claude-4-6-sonnet
> Signed-off-by: Ekansh Gupta <[email protected]>
> ---
>  drivers/accel/qda/Makefile    |  1 +
>  drivers/accel/qda/qda_cb.c    | 99 
> +++++++++++++++++++++++++++++++++++++++++++
>  drivers/accel/qda/qda_cb.h    | 32 ++++++++++++++
>  drivers/accel/qda/qda_drv.c   |  1 +
>  drivers/accel/qda/qda_drv.h   |  3 ++
>  drivers/accel/qda/qda_rpmsg.c | 12 +++++-
>  6 files changed, 147 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/accel/qda/Makefile b/drivers/accel/qda/Makefile
> index 424176f652a5..143c9e4e789e 100644
> --- a/drivers/accel/qda/Makefile
> +++ b/drivers/accel/qda/Makefile
> @@ -6,6 +6,7 @@
>  obj-$(CONFIG_DRM_ACCEL_QDA)  := qda.o
>  
>  qda-y := \
> +     qda_cb.o \
>       qda_drv.o \
>       qda_rpmsg.o
>  
> diff --git a/drivers/accel/qda/qda_cb.c b/drivers/accel/qda/qda_cb.c
> new file mode 100644
> index 000000000000..77caf8438c67
> --- /dev/null
> +++ b/drivers/accel/qda/qda_cb.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> +#include <linux/dma-mapping.h>
> +#include <linux/device.h>
> +#include <linux/of.h>
> +#include <linux/iommu.h>
> +#include <linux/qda_compute_bus.h>
> +#include <linux/slab.h>
> +#include <drm/drm_print.h>
> +#include "qda_drv.h"
> +#include "qda_cb.h"
> +
> +int qda_create_cb_device(struct qda_dev *qdev, struct device_node *cb_node)
> +{
> +     struct device *cb_dev;
> +     u32 sid = 0;
> +     char name[64];
> +     struct qda_cb_dev *entry;
> +
> +     drm_dbg_driver(&qdev->drm_dev, "Creating CB device for node: %s\n", 
> cb_node->name);
> +
> +     of_property_read_u32(cb_node, "reg", &sid);
> +
> +     snprintf(name, sizeof(name), "qda-cb-%s-%u", qdev->dsp_name, sid);
> +
> +     cb_dev = create_qda_cb_device(qdev->dev, name, DMA_BIT_MASK(32), 
> cb_node);

Wrong prefix. Pass the name format and the params to this function. Use
kasprintf in it.

> +     if (IS_ERR(cb_dev)) {
> +             drm_err(&qdev->drm_dev, "Failed to create CB device for SID %u: 
> %ld\n",
> +                     sid, PTR_ERR(cb_dev));
> +             return PTR_ERR(cb_dev);
> +     }
> +
> +     entry = kzalloc_obj(*entry);
> +     if (!entry) {
> +             device_unregister(cb_dev);
> +             return -ENOMEM;
> +     }
> +
> +     entry->dev = cb_dev;
> +     list_add_tail(&entry->node, &qdev->cb_devs);
> +
> +     drm_dbg_driver(&qdev->drm_dev, "Successfully created CB device for SID 
> %u\n", sid);
> +     return 0;
> +}
> +
> +void qda_cb_unpopulate(struct qda_dev *qdev)
> +{
> +     struct qda_cb_dev *entry, *tmp;
> +
> +     list_for_each_entry_safe(entry, tmp, &qdev->cb_devs, node) {
> +             list_del(&entry->node);
> +             qda_destroy_cb_device(entry->dev);
> +             kfree(entry);
> +     }
> +}
> +
> +int qda_cb_populate(struct qda_dev *qdev, struct device_node *parent_node)
> +{
> +     struct device_node *child;
> +     int count = 0, success = 0;
> +
> +     for_each_child_of_node(parent_node, child) {
> +             if (of_device_is_compatible(child, "qcom,fastrpc-compute-cb")) {
> +                     count++;
> +                     if (qda_create_cb_device(qdev, child) == 0) {
> +                             success++;
> +                             dev_dbg(qdev->dev, "Created CB device for node: 
> %s\n",
> +                                     child->name);

Stop counting successes.

> +                     } else {
> +                             dev_err(qdev->dev, "Failed to create CB device 
> for: %s\n",
> +                                     child->name);

Unwind, return error.

> +                     }
> +             }
> +     }
> +     if (count == 0)
> +             return 0;
> +     return success > 0 ? 0 : -ENODEV;
> +}
> +
> +void qda_destroy_cb_device(struct device *cb_dev)
> +{
> +     struct iommu_group *group;
> +
> +     if (!cb_dev) {

How can it be?

> +             pr_debug("qda: NULL CB device passed to destroy\n");
> +             return;
> +     }
> +
> +     dev_dbg(cb_dev, "Destroying CB device %s\n", dev_name(cb_dev));
> +
> +     group = iommu_group_get(cb_dev);
> +     if (group) {
> +             dev_dbg(cb_dev, "Removing %s from IOMMU group\n", 
> dev_name(cb_dev));

Be uniform. It's either drm_dbg_foo() or dev_dbg() all over the place.
Don't mix them.

> +             iommu_group_remove_device(cb_dev);
> +             iommu_group_put(group);
> +     }
> +
> +     device_unregister(cb_dev);
> +}
> @@ -59,9 +61,17 @@ static int qda_rpmsg_probe(struct rpmsg_device *rpdev)
>       }
>       qdev->dsp_name = label;
>  
> +     ret = qda_cb_populate(qdev, rpdev->dev.of_node);
> +     if (ret) {
> +             dev_err(qdev->dev, "Failed to populate child devices: %d\n", 
> ret);
> +             return ret;
> +     }
> +
>       ret = qda_register_device(qdev);
> -     if (ret)
> +     if (ret) {
> +             qda_cb_unpopulate(qdev);
>               return ret;

Unwinding registration?

> +     }
>  
>       drm_info(&qdev->drm_dev, "QDA RPMsg probe complete for %s\n", 
> qdev->dsp_name);
>       return 0;
> 
> -- 
> 2.34.1
> 
> 

-- 
With best wishes
Dmitry

Reply via email to