Re: [PATCH 06/15] accel/qda: Create compute context bank devices on QDA compute bus
From: Dmitry Baryshkov
Date: Wed May 20 2026 - 10:42:46 EST
On Tue, May 19, 2026 at 11:45:56AM +0530, Ekansh Gupta via B4 Relay wrote:
> From: Ekansh Gupta <ekansh.gupta@xxxxxxxxxxxxxxxx>
>
> 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 <ekansh.gupta@xxxxxxxxxxxxxxxx>
> ---
> 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