On Tue, Feb 24, 2026 at 12:39:02AM +0530, Ekansh Gupta wrote:
Introduce per-file and per-user context for the QDA DRM accelerator driver. A new qda_file_priv structure is stored in file->driver_priv for each open file descriptor, and a qda_user object is allocated per client with a unique client_id generated from an atomic counter in qda_dev.
The DRM driver now provides qda_open() and qda_postclose() callbacks. qda_open() resolves the qda_dev from the drm_device, allocates the qda_file_priv and qda_user structures, and attaches them to the DRM file. qda_postclose() tears down the per-file context and frees the qda_user object when the file is closed.
This prepares the QDA driver to track per-process state for future features such as per-client memory mappings, job submission contexts, and access control over DSP compute resources.
Start by describing the problem instead of stuffing it to the end. Can we use something better suited for this task, like IDR?
Signed-off-by: Ekansh Gupta ekansh.gupta@oss.qualcomm.com
drivers/accel/qda/qda_drv.c | 117 ++++++++++++++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_drv.h | 30 ++++++++++++ 2 files changed, 147 insertions(+)
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c index a9113ec78fa2..bf95fc782cf8 100644 --- a/drivers/accel/qda/qda_drv.c +++ b/drivers/accel/qda/qda_drv.c @@ -12,11 +12,127 @@ #include "qda_drv.h" #include "qda_rpmsg.h" +static struct qda_drm_priv *get_drm_priv_from_device(struct drm_device *dev) +{
- if (!dev)
return NULL;- return (struct qda_drm_priv *)dev->dev_private;
+}
+static struct qda_dev *get_qdev_from_drm_device(struct drm_device *dev) +{
- struct qda_drm_priv *drm_priv;
- if (!dev) {
qda_dbg(NULL, "Invalid drm_device\n");return NULL;- }
- drm_priv = get_drm_priv_from_device(dev);
- if (!drm_priv) {
qda_dbg(NULL, "No drm_priv in dev_private\n");return NULL;- }
- return drm_priv->qdev;
+}
+static struct qda_user *alloc_qda_user(struct qda_dev *qdev) +{
- struct qda_user *qda_user;
- qda_user = kzalloc_obj(*qda_user, GFP_KERNEL);
- if (!qda_user)
return NULL;- qda_user->client_id = atomic_inc_return(&qdev->client_id_counter);
- qda_user->qda_dev = qdev;
- qda_dbg(qdev, "Allocated qda_user with client_id=%u\n", qda_user->client_id);
- return qda_user;
+}
+static void free_qda_user(struct qda_user *qda_user) +{
- if (!qda_user)
return;- qda_dbg(qda_user->qda_dev, "Freeing qda_user client_id=%u\n", qda_user->client_id);
- kfree(qda_user);
+}
+static int qda_open(struct drm_device *dev, struct drm_file *file) +{
- struct qda_user *qda_user;
- struct qda_file_priv *qda_file_priv;
- struct qda_dev *qdev;
- if (!file) {
qda_dbg(NULL, "Invalid file pointer\n");return -EINVAL;- }
- qdev = get_qdev_from_drm_device(dev);
- if (!qdev) {
qda_dbg(NULL, "Failed to get qdev from drm_device\n");return -EINVAL;- }
- qda_file_priv = kzalloc(sizeof(*qda_file_priv), GFP_KERNEL);
- if (!qda_file_priv)
return -ENOMEM;- qda_file_priv->pid = current->pid;
- qda_user = alloc_qda_user(qdev);
- if (!qda_user) {
qda_dbg(qdev, "Failed to allocate qda_user\n");kfree(qda_file_priv);return -ENOMEM;- }
- file->driver_priv = qda_file_priv;
- qda_file_priv->qda_user = qda_user;
- qda_dbg(qdev, "Device opened successfully for PID %d\n", current->pid);
- return 0;
+}
+static void qda_postclose(struct drm_device *dev, struct drm_file *file) +{
- struct qda_dev *qdev;
- struct qda_file_priv *qda_file_priv;
- struct qda_user *qda_user;
- qdev = get_qdev_from_drm_device(dev);
- if (!qdev || atomic_read(&qdev->removing)) {
qda_dbg(NULL, "Device unavailable or removing\n");return;
Even if it is being removed, no need to free the memory?
- }
- qda_file_priv = (struct qda_file_priv *)file->driver_priv;
- if (qda_file_priv) {
qda_user = qda_file_priv->qda_user;if (qda_user)free_qda_user(qda_user);kfree(qda_file_priv);file->driver_priv = NULL;- }
- qda_dbg(qdev, "Device closed for PID %d\n", current->pid);
+}
DEFINE_DRM_ACCEL_FOPS(qda_accel_fops); static struct drm_driver qda_drm_driver = { .driver_features = DRIVER_COMPUTE_ACCEL, .fops = &qda_accel_fops,
- .open = qda_open,
- .postclose = qda_postclose, .name = DRIVER_NAME, .desc = "Qualcomm DSP Accelerator Driver",
}; @@ -58,6 +174,7 @@ static void init_device_resources(struct qda_dev *qdev) mutex_init(&qdev->lock); atomic_set(&qdev->removing, 0);
- atomic_set(&qdev->client_id_counter, 0);
} static int init_memory_manager(struct qda_dev *qdev) diff --git a/drivers/accel/qda/qda_drv.h b/drivers/accel/qda/qda_drv.h index 2b80401a3741..e0ba37702a86 100644 --- a/drivers/accel/qda/qda_drv.h +++ b/drivers/accel/qda/qda_drv.h @@ -10,6 +10,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/rpmsg.h> +#include <linux/types.h> #include <linux/xarray.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -20,6 +21,33 @@ /* Driver identification */ #define DRIVER_NAME "qda" +/**
- struct qda_file_priv - Per-process private data for DRM file
- This structure tracks per-process state for each open file descriptor.
- It maintains the IOMMU device assignment and links to the legacy qda_user
- structure for compatibility with existing code.
- */
+struct qda_file_priv {
- /* Process ID for tracking */
- pid_t pid;
- /* Pointer to qda_user structure for backward compatibility */
- struct qda_user *qda_user;
+};
+/**
- struct qda_user - Per-user context for remote processor interaction
- This structure maintains per-user state for interactions with the
- remote processor, including memory mappings and pending operations.
- */
+struct qda_user {
- /* Unique client identifier */
- u32 client_id;
- /* Back-pointer to device structure */
- struct qda_dev *qda_dev;
+};
/**
- struct qda_drm_priv - DRM device private data for QDA device
@@ -52,6 +80,8 @@ struct qda_dev { struct qda_drm_priv *drm_priv; /* Flag indicating device removal in progress */ atomic_t removing;
- /* Atomic counter for generating unique client IDs */
- atomic_t client_id_counter; /* Name of the DSP (e.g., "cdsp", "adsp") */ char dsp_name[16]; /* Compute context-bank (CB) child devices */
-- 2.34.1