All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Christian König" <christian.koenig@amd.com>
To: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>,
	Oded Gabbay <ogabbay@kernel.org>,
	Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	Bill Wendling <morbo@google.com>,
	Justin Stitt <justinstitt@google.com>,
	"Joerg Roedel (AMD)" <joro@8bytes.org>,
	Will Deacon <will@kernel.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Maxime Ripard <mripard@kernel.org>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
	Sumit Semwal <sumit.semwal@linaro.org>
Cc: Bharath Kumar <quic_bkumar@quicinc.com>,
	Chenna Kesava Raju <quic_chennak@quicinc.com>,
	srinivas.kandagatla@oss.qualcomm.com,
	dmitry.baryshkov@oss.qualcomm.com, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, llvm@lists.linux.dev,
	iommu@lists.linux.dev, linux-media@vger.kernel.org,
	linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH v2 09/15] accel/qda: Add DMA-backed GEM objects and memory manager integration
Date: Mon, 24 Aug 2026 16:30:53 +0200	[thread overview]
Message-ID: <7030a8f8-f320-4b09-b2de-2c8e897409f8@amd.com> (raw)
In-Reply-To: <20260817-qda-v2-v2-9-69a02e9090d4@oss.qualcomm.com>

On 8/17/26 06:47, Ekansh Gupta wrote:
> Introduce DMA-coherent buffer management for the QDA driver, wiring
> together the GEM subsystem, the IOMMU memory manager, and a DMA
> allocation backend.
> 
> qda_gem.c / qda_gem.h
>   Implements the GEM object lifecycle for QDA buffers. Each buffer is
>   represented by a qda_gem_obj which embeds a drm_gem_object and
>   carries the kernel virtual address, DMA address, and a pointer to
>   the IOMMU device that performed the allocation. The .free callback
>   delegates to the memory manager, and the .mmap callback uses
>   dma_mmap_coherent() via the DMA backend.
> 
> qda_memory_dma.c / qda_memory_dma.h
>   DMA coherent allocation backend. qda_dma_alloc() calls
>   dma_alloc_coherent() on the CB device and encodes the stream ID
>   (SID) in the upper 32 bits of the returned DMA address, following
>   the Qualcomm FastRPC convention for IOMMU address space tagging.
>   qda_dma_free() strips the SID prefix before calling
>   dma_free_coherent().
> 
> qda_memory_manager.c
>   Adds process-to-device assignment: each DRM file (process) is
>   assigned one IOMMU context bank device for the lifetime of the
>   session. qda_memory_manager_assign_device() first checks whether
>   the process already has a device (reusing it with a refcount
>   increment), then falls back to claiming an unassigned device.
>   qda_memory_manager_alloc() and qda_memory_manager_free() delegate
>   to the DMA backend after resolving the correct CB device for the
>   calling process.

Oh, stuff like that is usually a pretty big NO-GO now.

AMD has made the same mistake with KFD and it resulted in a massive chaos.

The DRM file is the driver context your process uses and even if there are multiple DRM files for the same PID you should absolute *NOT* share anything between them.

The general rule of thumb is to not attach anything to the process using the DRM file descriptor.

Regards,
Christian.

> 
> qda_drv.c / qda_drv.h
>   qda_file_priv gains an assigned_iommu_dev pointer and a pid field.
>   The .postclose callback decrements the IOMMU device refcount and
>   clears the process assignment when the last reference is dropped.
> 
> Assisted-by: Claude:claude-sonnet-5
> Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> ---
> Changes in v2:
> - Adapt to the dynamically-sized device array introduced in patch 07
>   (kcalloc'd from DT node count, replaces fixed QDA_IOMMU_DEVICES_MAX)
> - Protect register/unregister with the process_assignment_lock mutex so
>   the device-assignment and device-registration paths are serialised
> - No functional changes requested by reviewers on this patch
> ---
>  drivers/accel/qda/Makefile             |   2 +
>  drivers/accel/qda/qda_drv.c            |   4 +
>  drivers/accel/qda/qda_drv.h            |   4 +
>  drivers/accel/qda/qda_gem.c            | 134 ++++++++++++++++++
>  drivers/accel/qda/qda_gem.h            |  52 +++++++
>  drivers/accel/qda/qda_memory_dma.c     |  82 +++++++++++
>  drivers/accel/qda/qda_memory_dma.h     |  17 +++
>  drivers/accel/qda/qda_memory_manager.c | 239 ++++++++++++++++++++++++++++++++-
>  drivers/accel/qda/qda_memory_manager.h |  30 +++++
>  9 files changed, 559 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/accel/qda/Makefile b/drivers/accel/qda/Makefile
> index b658dad35fee..a46ddceecfc5 100644
> --- a/drivers/accel/qda/Makefile
> +++ b/drivers/accel/qda/Makefile
> @@ -8,7 +8,9 @@ obj-$(CONFIG_DRM_ACCEL_QDA)	:= qda.o
>  qda-y := \
>  	qda_cb.o \
>  	qda_drv.o \
> +	qda_gem.o \
>  	qda_ioctl.o \
> +	qda_memory_dma.o \
>  	qda_memory_manager.o \
>  	qda_rpmsg.o
>  
> diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
> index e1fd8bfa12d7..2b14dab95507 100644
> --- a/drivers/accel/qda/qda_drv.c
> +++ b/drivers/accel/qda/qda_drv.c
> @@ -21,6 +21,7 @@ static int qda_open(struct drm_device *dev, struct drm_file *file)
>  	if (!qda_file_priv)
>  		return -ENOMEM;
>  
> +	qda_file_priv->pid = current->pid;
>  	qda_file_priv->qda_dev = qda_dev_from_drm(dev);
>  	file->driver_priv = qda_file_priv;
>  
> @@ -31,6 +32,9 @@ static void qda_postclose(struct drm_device *dev, struct drm_file *file)
>  {
>  	struct qda_file_priv *qda_file_priv = file->driver_priv;
>  
> +	if (qda_file_priv->assigned_iommu_dev)
> +		qda_memory_manager_release_device(qda_file_priv->assigned_iommu_dev);
> +
>  	kfree(qda_file_priv);
>  	file->driver_priv = NULL;
>  }
> diff --git a/drivers/accel/qda/qda_drv.h b/drivers/accel/qda/qda_drv.h
> index 690a833d732b..2fe58f3efec0 100644
> --- a/drivers/accel/qda/qda_drv.h
> +++ b/drivers/accel/qda/qda_drv.h
> @@ -24,6 +24,10 @@
>  struct qda_file_priv {
>  	/** @qda_dev: Back-pointer to device structure */
>  	struct qda_dev *qda_dev;
> +	/** @assigned_iommu_dev: IOMMU device assigned to this process */
> +	struct qda_iommu_device *assigned_iommu_dev;
> +	/** @pid: Process ID for tracking */
> +	pid_t pid;
>  };
>  
>  /**
> diff --git a/drivers/accel/qda/qda_gem.c b/drivers/accel/qda/qda_gem.c
> new file mode 100644
> index 000000000000..66e78013a726
> --- /dev/null
> +++ b/drivers/accel/qda/qda_gem.c
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> +#include <drm/drm_gem.h>
> +#include <drm/drm_prime.h>
> +#include <drm/drm_print.h>
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +#include "qda_drv.h"
> +#include "qda_gem.h"
> +#include "qda_memory_manager.h"
> +#include "qda_memory_dma.h"
> +
> +/**
> + * qda_gem_free_object() - Free a GEM object and its associated resources
> + * @gem_obj: DRM GEM object to free
> + */
> +void qda_gem_free_object(struct drm_gem_object *gem_obj)
> +{
> +	struct qda_gem_obj *qda_gem_obj = to_qda_gem_obj(gem_obj);
> +	struct qda_dev *qdev = qda_dev_from_drm(gem_obj->dev);
> +
> +	if (qda_gem_obj->virt && qdev->iommu_mgr)
> +		qda_memory_manager_free(qdev->iommu_mgr, qda_gem_obj);
> +
> +	drm_gem_object_release(gem_obj);
> +	kfree(qda_gem_obj);
> +}
> +
> +/**
> + * qda_gem_mmap_obj() - Map a GEM object into userspace
> + * @drm_obj: DRM GEM object to map
> + * @vma: Virtual memory area to map into
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int qda_gem_mmap_obj(struct drm_gem_object *drm_obj, struct vm_area_struct *vma)
> +{
> +	struct qda_gem_obj *qda_gem_obj = to_qda_gem_obj(drm_obj);
> +	int ret;
> +
> +	/* The fake offset is only used to find the object, not to index it */
> +	vma->vm_pgoff = 0;
> +
> +	ret = qda_dma_mmap(qda_gem_obj, vma);
> +	if (ret)
> +		return ret;
> +
> +	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
> +
> +	return 0;
> +}
> +
> +static const struct drm_gem_object_funcs qda_gem_object_funcs = {
> +	.free = qda_gem_free_object,
> +	.mmap = qda_gem_mmap_obj,
> +};
> +
> +/**
> + * qda_gem_alloc_object() - Allocate a new QDA GEM object
> + * @drm_dev: DRM device
> + * @aligned_size: Size of the object in bytes (must be page-aligned)
> + *
> + * Return: Pointer to the new GEM object, or ERR_PTR on failure
> + */
> +struct qda_gem_obj *qda_gem_alloc_object(struct drm_device *drm_dev, size_t aligned_size)
> +{
> +	struct qda_gem_obj *qda_gem_obj;
> +	int ret;
> +
> +	qda_gem_obj = kzalloc_obj(*qda_gem_obj);
> +	if (!qda_gem_obj)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = drm_gem_object_init(drm_dev, &qda_gem_obj->base, aligned_size);
> +	if (ret) {
> +		kfree(qda_gem_obj);
> +		return ERR_PTR(ret);
> +	}
> +
> +	qda_gem_obj->base.funcs = &qda_gem_object_funcs;
> +	qda_gem_obj->size = aligned_size;
> +
> +	return qda_gem_obj;
> +}
> +
> +void qda_gem_cleanup_object(struct qda_gem_obj *qda_gem_obj)
> +{
> +	drm_gem_object_release(&qda_gem_obj->base);
> +	kfree(qda_gem_obj);
> +}
> +
> +int qda_gem_create_handle(struct drm_file *file_priv, struct drm_gem_object *gem_obj, u32 *handle)
> +{
> +	int ret;
> +
> +	ret = drm_gem_handle_create(file_priv, gem_obj, handle);
> +	drm_gem_object_put(gem_obj);
> +
> +	return ret;
> +}
> +
> +/**
> + * qda_gem_create_object() - Allocate and initialize a GEM object with DMA backing
> + * @drm_dev: DRM device
> + * @iommu_mgr: Memory manager to use for DMA allocation
> + * @size: Requested size in bytes
> + * @file_priv: DRM file private data for process association
> + *
> + * Return: Pointer to the base DRM GEM object on success, ERR_PTR on failure
> + */
> +struct drm_gem_object *qda_gem_create_object(struct drm_device *drm_dev,
> +					     struct qda_memory_manager *iommu_mgr, size_t size,
> +					     struct drm_file *file_priv)
> +{
> +	struct qda_gem_obj *qda_gem_obj;
> +	size_t aligned_size;
> +	int ret;
> +
> +	aligned_size = PAGE_ALIGN(size);
> +	if (!aligned_size)
> +		return ERR_PTR(-EINVAL);
> +
> +	qda_gem_obj = qda_gem_alloc_object(drm_dev, aligned_size);
> +	if (IS_ERR(qda_gem_obj))
> +		return ERR_CAST(qda_gem_obj);
> +
> +	ret = qda_memory_manager_alloc(iommu_mgr, qda_gem_obj, file_priv);
> +	if (ret) {
> +		qda_gem_cleanup_object(qda_gem_obj);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return &qda_gem_obj->base;
> +}
> diff --git a/drivers/accel/qda/qda_gem.h b/drivers/accel/qda/qda_gem.h
> new file mode 100644
> index 000000000000..afd7c9b49549
> --- /dev/null
> +++ b/drivers/accel/qda/qda_gem.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +#ifndef __QDA_GEM_H__
> +#define __QDA_GEM_H__
> +
> +#include <linux/dma-mapping.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_gem.h>
> +#include "qda_memory_manager.h"
> +
> +/**
> + * struct qda_gem_obj - QDA GEM buffer object
> + *
> + * Represents a GEM buffer object that can be allocated by the driver
> + * or imported from another driver via DMA-BUF.
> + */
> +struct qda_gem_obj {
> +	/** @base: DRM GEM object base — must be first member */
> +	struct drm_gem_object base;
> +	/** @iommu_dev: IOMMU context bank device that performed the allocation */
> +	struct qda_iommu_device *iommu_dev;
> +	/** @virt: Kernel virtual address of the allocated DMA memory */
> +	void *virt;
> +	/** @dma_addr: DMA address (with SID encoded in upper 32 bits) */
> +	dma_addr_t dma_addr;
> +	/** @size: Size of the buffer in bytes */
> +	size_t size;
> +};
> +
> +/**
> + * to_qda_gem_obj - Cast a drm_gem_object pointer to qda_gem_obj
> + * @gem_obj: Pointer to the embedded drm_gem_object
> + */
> +#define to_qda_gem_obj(gem_obj) container_of(gem_obj, struct qda_gem_obj, base)
> +
> +/* GEM object lifecycle */
> +struct drm_gem_object *qda_gem_create_object(struct drm_device *drm_dev,
> +					     struct qda_memory_manager *iommu_mgr,
> +					     size_t size, struct drm_file *file_priv);
> +void qda_gem_free_object(struct drm_gem_object *gem_obj);
> +int qda_gem_mmap_obj(struct drm_gem_object *gem_obj, struct vm_area_struct *vma);
> +
> +/* Internal helpers (also used by PRIME import) */
> +struct qda_gem_obj *qda_gem_alloc_object(struct drm_device *drm_dev, size_t aligned_size);
> +void qda_gem_cleanup_object(struct qda_gem_obj *qda_gem_obj);
> +
> +/* Utility functions */
> +int qda_gem_create_handle(struct drm_file *file_priv, struct drm_gem_object *gem_obj, u32 *handle);
> +
> +#endif /* __QDA_GEM_H__ */
> diff --git a/drivers/accel/qda/qda_memory_dma.c b/drivers/accel/qda/qda_memory_dma.c
> new file mode 100644
> index 000000000000..7072ed8edf0b
> --- /dev/null
> +++ b/drivers/accel/qda/qda_memory_dma.c
> @@ -0,0 +1,82 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +#include "qda_drv.h"
> +#include "qda_gem.h"
> +#include "qda_memory_dma.h"
> +
> +/*
> + * The DSP identifies the IOMMU context bank from the upper bits of the address,
> + * so the stream ID is folded into every address handed to it. The DMA API only
> + * ever sees the plain 32-bit address, which is why the context bank devices are
> + * created with a 32-bit DMA mask.
> + */
> +static dma_addr_t get_actual_dma_addr(struct qda_gem_obj *gem_obj)
> +{
> +	return gem_obj->dma_addr - ((u64)gem_obj->iommu_dev->sid << 32);
> +}
> +
> +static void setup_gem_object(struct qda_gem_obj *gem_obj, void *virt,
> +			     dma_addr_t dma_addr, struct qda_iommu_device *iommu_dev)
> +{
> +	gem_obj->virt = virt;
> +	gem_obj->dma_addr = dma_addr;
> +	gem_obj->iommu_dev = iommu_dev;
> +}
> +
> +static void cleanup_gem_object_fields(struct qda_gem_obj *gem_obj)
> +{
> +	gem_obj->virt = NULL;
> +	gem_obj->dma_addr = 0;
> +	gem_obj->iommu_dev = NULL;
> +}
> +
> +/**
> + * qda_dma_alloc() - Allocate DMA coherent memory for a GEM object
> + * @iommu_dev: Pointer to the QDA IOMMU device structure
> + * @gem_obj: Pointer to GEM object to allocate memory for
> + * @size: Size of memory to allocate in bytes
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int qda_dma_alloc(struct qda_iommu_device *iommu_dev,
> +		  struct qda_gem_obj *gem_obj, size_t size)
> +{
> +	dma_addr_t dma_addr;
> +	void *virt;
> +
> +	virt = dma_alloc_coherent(iommu_dev->dev, size, &dma_addr, GFP_KERNEL);
> +	if (!virt)
> +		return -ENOMEM;
> +
> +	dma_addr += ((u64)iommu_dev->sid << 32);
> +	setup_gem_object(gem_obj, virt, dma_addr, iommu_dev);
> +
> +	return 0;
> +}
> +
> +/**
> + * qda_dma_free() - Free DMA coherent memory for a GEM object
> + * @gem_obj: Pointer to GEM object to free memory for
> + */
> +void qda_dma_free(struct qda_gem_obj *gem_obj)
> +{
> +	dma_free_coherent(gem_obj->iommu_dev->dev, gem_obj->size,
> +			  gem_obj->virt, get_actual_dma_addr(gem_obj));
> +
> +	cleanup_gem_object_fields(gem_obj);
> +}
> +
> +/**
> + * qda_dma_mmap() - Map DMA memory into userspace
> + * @gem_obj: Pointer to GEM object containing DMA memory
> + * @vma: Virtual memory area to map into
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int qda_dma_mmap(struct qda_gem_obj *gem_obj, struct vm_area_struct *vma)
> +{
> +	return dma_mmap_coherent(gem_obj->iommu_dev->dev, vma, gem_obj->virt,
> +				 get_actual_dma_addr(gem_obj), gem_obj->size);
> +}
> diff --git a/drivers/accel/qda/qda_memory_dma.h b/drivers/accel/qda/qda_memory_dma.h
> new file mode 100644
> index 000000000000..99352a99dc33
> --- /dev/null
> +++ b/drivers/accel/qda/qda_memory_dma.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef __QDA_MEMORY_DMA_H__
> +#define __QDA_MEMORY_DMA_H__
> +
> +#include <linux/dma-mapping.h>
> +#include "qda_memory_manager.h"
> +
> +int qda_dma_alloc(struct qda_iommu_device *iommu_dev,
> +		  struct qda_gem_obj *gem_obj, size_t size);
> +void qda_dma_free(struct qda_gem_obj *gem_obj);
> +int qda_dma_mmap(struct qda_gem_obj *gem_obj, struct vm_area_struct *vma);
> +
> +#endif /* __QDA_MEMORY_DMA_H__ */
> diff --git a/drivers/accel/qda/qda_memory_manager.c b/drivers/accel/qda/qda_memory_manager.c
> index b1a80ee77c35..d47c7419e11d 100644
> --- a/drivers/accel/qda/qda_memory_manager.c
> +++ b/drivers/accel/qda/qda_memory_manager.c
> @@ -1,14 +1,26 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>  
> +#include <linux/refcount.h>
>  #include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_print.h>
>  #include "qda_drv.h"
> +#include "qda_gem.h"
>  #include "qda_memory_manager.h"
> +#include "qda_memory_dma.h"
> +
> +static void iommu_device_free(struct kref *ref)
> +{
> +	kfree(container_of(ref, struct qda_iommu_device, ref));
> +}
>  
>  static void cleanup_all_memory_devices(struct qda_memory_manager *mem_mgr)
>  {
>  	int i;
>  
> +	mutex_lock(&mem_mgr->process_assignment_lock);
>  	for (i = 0; i < mem_mgr->num_devices; i++) {
>  		struct qda_iommu_device *iommu_dev = mem_mgr->devices[i];
>  
> @@ -16,9 +28,215 @@ static void cleanup_all_memory_devices(struct qda_memory_manager *mem_mgr)
>  			continue;
>  
>  		mem_mgr->devices[i] = NULL;
> -		kfree(iommu_dev);
> +		kref_put(&iommu_dev->ref, iommu_device_free);
>  	}
>  	mem_mgr->num_devices = 0;
> +	mutex_unlock(&mem_mgr->process_assignment_lock);
> +}
> +
> +static void init_iommu_device_fields(struct qda_iommu_device *iommu_dev)
> +{
> +	spin_lock_init(&iommu_dev->lock);
> +	refcount_set(&iommu_dev->users, 0);
> +	kref_init(&iommu_dev->ref);
> +	iommu_dev->assigned_pid = 0;
> +	iommu_dev->assigned_file_priv = NULL;
> +}
> +
> +static struct qda_iommu_device *find_device_for_pid(struct qda_memory_manager *mem_mgr,
> +						    pid_t pid)
> +{
> +	struct qda_iommu_device *found_dev = NULL;
> +	unsigned long flags;
> +	int i;
> +
> +	for (i = 0; i < mem_mgr->num_devices; i++) {
> +		struct qda_iommu_device *iommu_dev = mem_mgr->devices[i];
> +
> +		if (!iommu_dev)
> +			continue;
> +
> +		spin_lock_irqsave(&iommu_dev->lock, flags);
> +		if (iommu_dev->assigned_pid == pid) {
> +			found_dev = iommu_dev;
> +			refcount_inc(&found_dev->users);
> +			kref_get(&found_dev->ref);
> +			spin_unlock_irqrestore(&iommu_dev->lock, flags);
> +			break;
> +		}
> +		spin_unlock_irqrestore(&iommu_dev->lock, flags);
> +	}
> +
> +	return found_dev;
> +}
> +
> +static struct qda_iommu_device *assign_available_device_to_pid(struct qda_memory_manager *mem_mgr,
> +							       pid_t pid,
> +							       struct drm_file *file_priv)
> +{
> +	struct qda_iommu_device *selected_dev = NULL;
> +	unsigned long flags;
> +	int i;
> +
> +	for (i = 0; i < mem_mgr->num_devices; i++) {
> +		struct qda_iommu_device *iommu_dev = mem_mgr->devices[i];
> +
> +		if (!iommu_dev)
> +			continue;
> +
> +		spin_lock_irqsave(&iommu_dev->lock, flags);
> +		if (iommu_dev->assigned_pid == 0) {
> +			iommu_dev->assigned_pid = pid;
> +			iommu_dev->assigned_file_priv = file_priv;
> +			selected_dev = iommu_dev;
> +			refcount_set(&selected_dev->users, 1);
> +			kref_get(&selected_dev->ref);
> +			spin_unlock_irqrestore(&iommu_dev->lock, flags);
> +			break;
> +		}
> +		spin_unlock_irqrestore(&iommu_dev->lock, flags);
> +	}
> +
> +	return selected_dev;
> +}
> +
> +static struct qda_iommu_device *get_process_iommu_device(struct qda_memory_manager *mem_mgr,
> +							 struct drm_file *file_priv)
> +{
> +	struct qda_file_priv *qda_priv;
> +
> +	if (!file_priv || !file_priv->driver_priv)
> +		return NULL;
> +
> +	qda_priv = (struct qda_file_priv *)file_priv->driver_priv;
> +	return qda_priv->assigned_iommu_dev;
> +}
> +
> +/**
> + * qda_memory_manager_assign_device() - Assign an IOMMU device to a process
> + * @mem_mgr: Pointer to memory manager
> + * @file_priv: DRM file private data for process association
> + *
> + * On success the caller owns a reference on the device and must release it
> + * with qda_memory_manager_release_device().
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int qda_memory_manager_assign_device(struct qda_memory_manager *mem_mgr,
> +				     struct drm_file *file_priv)
> +{
> +	struct qda_file_priv *qda_priv;
> +	struct qda_iommu_device *selected_dev = NULL;
> +	int ret = 0;
> +	pid_t current_pid;
> +
> +	if (!file_priv || !file_priv->driver_priv)
> +		return -EINVAL;
> +
> +	qda_priv = (struct qda_file_priv *)file_priv->driver_priv;
> +	current_pid = qda_priv->pid;
> +
> +	mutex_lock(&mem_mgr->process_assignment_lock);
> +
> +	if (qda_priv->assigned_iommu_dev) {
> +		ret = 0;
> +		goto unlock_and_return;
> +	}
> +
> +	selected_dev = find_device_for_pid(mem_mgr, current_pid);
> +
> +	if (selected_dev) {
> +		qda_priv->assigned_iommu_dev = selected_dev;
> +		goto unlock_and_return;
> +	}
> +
> +	selected_dev = assign_available_device_to_pid(mem_mgr, current_pid, file_priv);
> +
> +	if (!selected_dev) {
> +		drm_dbg_driver(file_priv->minor->dev, "No context bank available for PID %d\n",
> +			       current_pid);
> +		ret = -EBUSY;
> +		goto unlock_and_return;
> +	}
> +
> +	qda_priv->assigned_iommu_dev = selected_dev;
> +
> +unlock_and_return:
> +	mutex_unlock(&mem_mgr->process_assignment_lock);
> +
> +	return ret;
> +}
> +
> +/**
> + * qda_memory_manager_release_device() - Release a process assignment
> + * @iommu_dev: Device previously obtained from qda_memory_manager_assign_device()
> + *
> + * Drops the caller's reference. Once the last process using the device is
> + * gone the assignment is cleared so the device can serve another process.
> + */
> +void qda_memory_manager_release_device(struct qda_iommu_device *iommu_dev)
> +{
> +	unsigned long flags;
> +
> +	if (refcount_dec_and_test(&iommu_dev->users)) {
> +		spin_lock_irqsave(&iommu_dev->lock, flags);
> +		iommu_dev->assigned_pid = 0;
> +		iommu_dev->assigned_file_priv = NULL;
> +		spin_unlock_irqrestore(&iommu_dev->lock, flags);
> +	}
> +
> +	kref_put(&iommu_dev->ref, iommu_device_free);
> +}
> +
> +static struct qda_iommu_device *get_or_assign_iommu_device(struct qda_memory_manager *mem_mgr,
> +							   struct drm_file *file_priv)
> +{
> +	struct qda_iommu_device *iommu_dev;
> +	int ret;
> +
> +	iommu_dev = get_process_iommu_device(mem_mgr, file_priv);
> +	if (iommu_dev)
> +		return iommu_dev;
> +
> +	ret = qda_memory_manager_assign_device(mem_mgr, file_priv);
> +	if (ret)
> +		return NULL;
> +
> +	iommu_dev = get_process_iommu_device(mem_mgr, file_priv);
> +	if (iommu_dev)
> +		return iommu_dev;
> +
> +	return NULL;
> +}
> +
> +/**
> + * qda_memory_manager_alloc() - Allocate memory for a GEM object
> + * @mem_mgr: Pointer to memory manager
> + * @gem_obj: Pointer to GEM object to allocate memory for
> + * @file_priv: DRM file private data for process association
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int qda_memory_manager_alloc(struct qda_memory_manager *mem_mgr, struct qda_gem_obj *gem_obj,
> +			     struct drm_file *file_priv)
> +{
> +	struct qda_iommu_device *selected_dev;
> +
> +	selected_dev = get_or_assign_iommu_device(mem_mgr, file_priv);
> +	if (!selected_dev)
> +		return -EBUSY;
> +
> +	return qda_dma_alloc(selected_dev, gem_obj, gem_obj->size);
> +}
> +
> +/**
> + * qda_memory_manager_free() - Free memory for a GEM object
> + * @mem_mgr: Pointer to memory manager
> + * @gem_obj: Pointer to GEM object to free memory for
> + */
> +void qda_memory_manager_free(struct qda_memory_manager *mem_mgr, struct qda_gem_obj *gem_obj)
> +{
> +	qda_dma_free(gem_obj);
>  }
>  
>  /**
> @@ -31,13 +249,21 @@ static void cleanup_all_memory_devices(struct qda_memory_manager *mem_mgr)
>  int qda_memory_manager_register_device(struct qda_memory_manager *mem_mgr,
>  				       struct qda_iommu_device *iommu_dev)
>  {
> -	if (mem_mgr->num_devices >= mem_mgr->max_devices)
> -		return -ENOSPC;
> +	int ret = 0;
>  
> +	mutex_lock(&mem_mgr->process_assignment_lock);
> +	if (mem_mgr->num_devices >= mem_mgr->max_devices) {
> +		ret = -ENOSPC;
> +		goto out;
> +	}
> +
> +	init_iommu_device_fields(iommu_dev);
>  	iommu_dev->id = mem_mgr->num_devices;
>  	mem_mgr->devices[mem_mgr->num_devices++] = iommu_dev;
>  
> -	return 0;
> +out:
> +	mutex_unlock(&mem_mgr->process_assignment_lock);
> +	return ret;
>  }
>  
>  /**
> @@ -52,14 +278,16 @@ void qda_memory_manager_unregister_device(struct qda_memory_manager *mem_mgr,
>  {
>  	int i;
>  
> +	mutex_lock(&mem_mgr->process_assignment_lock);
>  	for (i = 0; i < mem_mgr->num_devices; i++) {
>  		if (mem_mgr->devices[i] == iommu_dev) {
>  			mem_mgr->devices[i] = NULL;
>  			break;
>  		}
>  	}
> +	mutex_unlock(&mem_mgr->process_assignment_lock);
>  
> -	kfree(iommu_dev);
> +	kref_put(&iommu_dev->ref, iommu_device_free);
>  }
>  
>  /**
> @@ -80,6 +308,7 @@ int qda_memory_manager_init(struct qda_memory_manager *mem_mgr, int max_devices)
>  
>  	mem_mgr->num_devices = 0;
>  	mem_mgr->max_devices = max_devices;
> +	mutex_init(&mem_mgr->process_assignment_lock);
>  
>  	return 0;
>  }
> diff --git a/drivers/accel/qda/qda_memory_manager.h b/drivers/accel/qda/qda_memory_manager.h
> index 7e38c8a18284..0949c0c213f6 100644
> --- a/drivers/accel/qda/qda_memory_manager.h
> +++ b/drivers/accel/qda/qda_memory_manager.h
> @@ -7,25 +7,44 @@
>  #define __QDA_MEMORY_MANAGER_H__
>  
>  #include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/mutex.h>
> +#include <linux/refcount.h>
> +#include <linux/spinlock.h>
> +#include <drm/drm_file.h>
>  
>  /* Forward declarations */
>  struct qda_dev;
> +struct qda_gem_obj;
>  
>  /**
>   * struct qda_iommu_device - IOMMU device instance for memory management
>   *
>   * Represents a single IOMMU-enabled device managed by the memory manager.
>   * Each device can be assigned to a specific process session.
> + *
> + * The object outlives its registration: open files keep a reference through
> + * @ref, so a device can be unregistered while a process still holds it.
>   */
>  struct qda_iommu_device {
>  	/** @dev: Pointer to the underlying device */
>  	struct device *dev;
>  	/** @qdev: Back-pointer to the parent QDA device */
>  	struct qda_dev *qdev;
> +	/** @assigned_file_priv: DRM file private data for the assigned process */
> +	struct drm_file *assigned_file_priv;
>  	/** @id: Unique identifier assigned by the memory manager */
>  	u32 id;
>  	/** @sid: Stream ID for IOMMU transactions */
>  	u32 sid;
> +	/** @assigned_pid: Process ID of the process assigned to this device */
> +	pid_t assigned_pid;
> +	/** @users: Number of open files sharing this device */
> +	refcount_t users;
> +	/** @ref: Reference count controlling when the object is freed */
> +	struct kref ref;
> +	/** @lock: Spinlock protecting concurrent access to device */
> +	spinlock_t lock;
>  };
>  
>  /**
> @@ -42,6 +61,8 @@ struct qda_memory_manager {
>  	int num_devices;
>  	/** @max_devices: Capacity of the @devices array */
>  	int max_devices;
> +	/** @process_assignment_lock: Mutex protecting process-to-device assignments */
> +	struct mutex process_assignment_lock;
>  };
>  
>  int qda_memory_manager_init(struct qda_memory_manager *mem_mgr, int max_devices);
> @@ -51,5 +72,14 @@ int qda_memory_manager_register_device(struct qda_memory_manager *mem_mgr,
>  				       struct qda_iommu_device *iommu_dev);
>  void qda_memory_manager_unregister_device(struct qda_memory_manager *mem_mgr,
>  					  struct qda_iommu_device *iommu_dev);
> +int qda_memory_manager_assign_device(struct qda_memory_manager *mem_mgr,
> +				     struct drm_file *file_priv);
> +void qda_memory_manager_release_device(struct qda_iommu_device *iommu_dev);
> +
> +int qda_memory_manager_alloc(struct qda_memory_manager *mem_mgr,
> +			     struct qda_gem_obj *gem_obj,
> +			     struct drm_file *file_priv);
> +void qda_memory_manager_free(struct qda_memory_manager *mem_mgr,
> +			     struct qda_gem_obj *gem_obj);
>  
>  #endif /* __QDA_MEMORY_MANAGER_H__ */
> 


  parent reply	other threads:[~2026-08-24 14:31 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17  4:47 [PATCH v2 00/15] accel/qda: Qualcomm DSP Accelerator driver Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 01/15] MAINTAINERS: Add entry for Qualcomm DSP Accelerator (QDA) driver Ekansh Gupta
2026-08-18 19:22   ` Krzysztof Kozlowski
2026-08-19 13:05     ` Ekansh Gupta
2026-08-19 14:16       ` Krzysztof Kozlowski
2026-08-20  4:12         ` Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 02/15] accel/qda: Add QDA driver documentation Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 03/15] accel/qda: Add initial QDA DRM accelerator driver Ekansh Gupta
2026-08-18 19:10   ` Krzysztof Kozlowski
2026-08-19 13:17     ` Ekansh Gupta
2026-08-19 14:18       ` Krzysztof Kozlowski
2026-08-20  8:52         ` Dmitry Baryshkov
2026-08-20  9:07           ` Krzysztof Kozlowski
2026-08-20 10:07             ` Dmitry Baryshkov
2026-08-20 13:31               ` Krzysztof Kozlowski
2026-08-17  4:47 ` [PATCH v2 04/15] accel/qda: Add compute bus for QDA context banks Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 05/15] iommu: Add QDA compute context bank bus to iommu_buses Ekansh Gupta
2026-08-17  7:01   ` Joerg Roedel (AMD)
2026-08-17 13:44   ` Jason Gunthorpe
2026-08-18  5:10     ` Ekansh Gupta
2026-08-18 13:07       ` Jason Gunthorpe
2026-08-20 13:17         ` Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 06/15] accel/qda: Create compute context bank devices on QDA compute bus Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 07/15] accel/qda: Add memory manager for CB devices Ekansh Gupta
2026-08-17  6:52   ` Dmitry Baryshkov
2026-08-18  4:33     ` Ekansh Gupta
2026-08-18  4:44       ` Dmitry Baryshkov
2026-08-17  4:47 ` [PATCH v2 08/15] accel/qda: Add QUERY IOCTL and QDA UAPI header Ekansh Gupta
2026-08-17  6:58   ` Dmitry Baryshkov
2026-08-18  4:40     ` Ekansh Gupta
2026-08-18  4:45       ` Dmitry Baryshkov
2026-08-17  4:47 ` [PATCH v2 09/15] accel/qda: Add DMA-backed GEM objects and memory manager integration Ekansh Gupta
2026-08-18  3:42   ` Dmitry Baryshkov
2026-08-18  5:51     ` Ekansh Gupta
2026-08-18  3:48   ` Dmitry Baryshkov
2026-08-18  5:52     ` Ekansh Gupta
2026-08-24 14:30   ` Christian König [this message]
2026-08-24 15:07     ` Rob Clark
2026-08-17  4:47 ` [PATCH v2 10/15] accel/qda: Add GEM_CREATE and GEM_MMAP_OFFSET IOCTLs Ekansh Gupta
2026-08-18  3:49   ` Dmitry Baryshkov
2026-08-18  5:54     ` Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 11/15] accel/qda: Add PRIME DMA-BUF import support Ekansh Gupta
2026-08-18  3:55   ` Dmitry Baryshkov
2026-08-18  6:25     ` Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 12/15] accel/qda: Add FastRPC invocation support Ekansh Gupta
2026-08-18  4:19   ` Dmitry Baryshkov
2026-08-20  8:35     ` Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 13/15] accel/qda: Add DSP process creation and release Ekansh Gupta
2026-08-17  4:47 ` [PATCH v2 14/15] accel/qda: Add remote memory mapping to DSP address space Ekansh Gupta
2026-08-18 19:13 ` [PATCH v2 00/15] accel/qda: Qualcomm DSP Accelerator driver Krzysztof Kozlowski
2026-08-18 19:21   ` Krzysztof Kozlowski
2026-08-19 13:32     ` Ekansh Gupta
2026-08-19 14:19       ` Krzysztof Kozlowski
2026-08-19 13:26   ` Ekansh Gupta
2026-08-19 14:21     ` Krzysztof Kozlowski
2026-08-19 14:38       ` Rob Clark
2026-08-19 14:40         ` Konrad Dybcio
2026-08-19 14:43         ` Krzysztof Kozlowski
2026-08-19 14:49           ` Rob Clark
2026-08-19 14:53             ` Krzysztof Kozlowski
2026-08-19 15:23               ` Rob Clark
2026-08-19 15:27                 ` Krzysztof Kozlowski
2026-08-19 15:48                   ` Rob Clark
2026-08-20  6:15                     ` Krzysztof Kozlowski
2026-08-20 14:47                       ` Rob Clark
2026-08-18 19:18 ` Krzysztof Kozlowski
2026-08-19 13:23   ` Ekansh Gupta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7030a8f8-f320-4b09-b2de-2c8e897409f8@amd.com \
    --to=christian.koenig@amd.com \
    --cc=airlied@gmail.com \
    --cc=corbet@lwn.net \
    --cc=dmitry.baryshkov@oss.qualcomm.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=ekansh.gupta@oss.qualcomm.com \
    --cc=iommu@lists.linux.dev \
    --cc=joro@8bytes.org \
    --cc=justinstitt@google.com \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=morbo@google.com \
    --cc=mripard@kernel.org \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=ogabbay@kernel.org \
    --cc=quic_bkumar@quicinc.com \
    --cc=quic_chennak@quicinc.com \
    --cc=rdunlap@infradead.org \
    --cc=robin.murphy@arm.com \
    --cc=simona@ffwll.ch \
    --cc=skhan@linuxfoundation.org \
    --cc=srinivas.kandagatla@oss.qualcomm.com \
    --cc=sumit.semwal@linaro.org \
    --cc=tzimmermann@suse.de \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.