Add a DRM_QDA_MAP ioctl and supporting FastRPC plumbing to map GEM
backed buffers into the DSP virtual address space. The new
qda_mem_map UAPI structure allows userspace to request legacy MMAP
style mappings or handle-based MEM_MAP mappings with attributes, and
encodes flags, offsets and optional virtual address hints that are
forwarded to the DSP.

On the FastRPC side new method identifiers FASTRPC_RMID_INIT_MMAP
and FASTRPC_RMID_INIT_MEM_MAP are introduced together with message
structures for map requests and responses. The fastrpc_prepare_args
path is extended to build the appropriate request headers, serialize
the physical page information derived from a GEM object into a
fastrpc_phy_page array and pack the arguments into the shared message
buffer used by the existing invoke infrastructure.

The qda_ioctl_mmap() handler dispatches mapping requests based on the
qda_mem_map request type, reusing the generic fastrpc_invoke()
machinery and the RPMsg transport to communicate with the DSP. This
provides the foundation for explicit buffer mapping into the DSP
address space for subsequent FastRPC calls, aligned with the
traditional FastRPC user space model.

Signed-off-by: Ekansh Gupta <[email protected]>
---
 arch/arm64/configs/defconfig    |   2 +
 drivers/accel/qda/qda_drv.c     |   1 +
 drivers/accel/qda/qda_fastrpc.c | 217 ++++++++++++++++++++++++++++++++++++++++
 drivers/accel/qda/qda_fastrpc.h |  64 ++++++++++++
 drivers/accel/qda/qda_ioctl.c   |  24 +++++
 drivers/accel/qda/qda_ioctl.h   |  13 +++
 include/uapi/drm/qda_accel.h    |  44 +++++++-
 7 files changed, 364 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index b67d5b1fc45b..e53a7984c9be 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1046,6 +1046,8 @@ CONFIG_DRM_TIDSS=m
 CONFIG_DRM_ZYNQMP_DPSUB=m
 CONFIG_DRM_ZYNQMP_DPSUB_AUDIO=y
 CONFIG_DRM_POWERVR=m
+CONFIG_DRM_ACCEL=y
+CONFIG_DRM_ACCEL_QDA=m
 CONFIG_FB=y
 CONFIG_FB_EFI=y
 CONFIG_FB_MODE_HELPERS=y
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
index 2b080d5d51c5..5f43c97ebc25 100644
--- a/drivers/accel/qda/qda_drv.c
+++ b/drivers/accel/qda/qda_drv.c
@@ -163,6 +163,7 @@ static const struct drm_ioctl_desc qda_ioctls[] = {
        DRM_IOCTL_DEF_DRV(QDA_GEM_MMAP_OFFSET, qda_ioctl_gem_mmap_offset, 0),
        DRM_IOCTL_DEF_DRV(QDA_INIT_ATTACH, qda_ioctl_attach, 0),
        DRM_IOCTL_DEF_DRV(QDA_INIT_CREATE, qda_ioctl_create, 0),
+       DRM_IOCTL_DEF_DRV(QDA_MAP, qda_ioctl_mmap, 0),
        DRM_IOCTL_DEF_DRV(QDA_INVOKE, qda_ioctl_invoke, 0),
 };
 
diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c
index f03dcf7e21e4..25b5d53ba2d6 100644
--- a/drivers/accel/qda/qda_fastrpc.c
+++ b/drivers/accel/qda/qda_fastrpc.c
@@ -487,6 +487,40 @@ int fastrpc_internal_invoke_unpack(struct 
fastrpc_invoke_context *ctx,
        return err;
 }
 
+static int  fastrpc_return_result_mem_map(struct fastrpc_invoke_context *ctx, 
char __user *argp)
+{
+       struct qda_mem_map margs;
+       struct fastrpc_map_rsp_msg *rsp_msg;
+       int err;
+
+       rsp_msg = ctx->rsp;
+
+       err = copy_from_user_or_kernel(&margs, argp, sizeof(margs));
+       if (err)
+               return err;
+
+       margs.vaddrout = rsp_msg->vaddrout;
+
+       err = copy_to_user_or_kernel(argp, &margs, sizeof(margs));
+       return err;
+}
+
+int fastrpc_return_result(struct fastrpc_invoke_context *ctx, char __user 
*argp)
+{
+       int err = 0;
+
+       switch (ctx->type) {
+       case FASTRPC_RMID_INIT_MMAP:
+       case FASTRPC_RMID_INIT_MEM_MAP:
+               err = fastrpc_return_result_mem_map(ctx, argp);
+               break;
+       default:
+               break;
+       }
+
+       return err;
+}
+
 static void setup_create_process_args(struct fastrpc_invoke_args *args,
                                      struct fastrpc_create_process_inbuf 
*inbuf,
                                      struct qda_init_create *init,
@@ -517,6 +551,29 @@ static void setup_create_process_args(struct 
fastrpc_invoke_args *args,
        args[5].fd = -1;
 }
 
+static int setup_mmap_pages(struct drm_file *file_priv, int fd, struct 
fastrpc_phy_page *pages)
+{
+       struct drm_gem_object *gem_obj;
+       struct qda_gem_obj *qda_gem_obj;
+       int err;
+
+       if (fd <= 0) {
+               pages->addr = 0;
+               pages->size = 0;
+               return 0;
+       }
+
+       err = get_gem_obj_from_handle(file_priv, fd, &gem_obj);
+       if (err)
+               return err;
+
+       qda_gem_obj = to_qda_gem_obj(gem_obj);
+       setup_pages_from_gem_obj(qda_gem_obj, pages);
+
+       drm_gem_object_put(gem_obj);
+       return 0;
+}
+
 static int fastrpc_prepare_args_init_attach(struct fastrpc_invoke_context *ctx)
 {
        struct fastrpc_invoke_args *args;
@@ -658,6 +715,160 @@ static int fastrpc_prepare_args_init_create(struct 
fastrpc_invoke_context *ctx,
        return err;
 }
 
+static int fastrpc_prepare_args_map(struct fastrpc_invoke_context *ctx, char 
__user *argp)
+{
+       struct qda_mem_map margs;
+       struct fastrpc_invoke_args *args;
+       void *req, *rsp;
+       struct fastrpc_map_req_msg *req_msg;
+       struct fastrpc_map_rsp_msg *rsp_msg;
+       int err;
+
+       err = copy_from_user_or_kernel(&margs, argp, sizeof(margs));
+       if (err)
+               return err;
+
+       args = kzalloc_objs(*args, 3, GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+
+       req = kzalloc_obj(*req_msg, GFP_KERNEL);
+       if (!req) {
+               err = -ENOMEM;
+               goto err_free_args;
+       }
+       req_msg = (struct fastrpc_map_req_msg *)req;
+
+       rsp = kzalloc_obj(*rsp_msg, GFP_KERNEL);
+       if (!rsp) {
+               err = -ENOMEM;
+               goto err_free_req;
+       }
+       rsp_msg = (struct fastrpc_map_rsp_msg *)rsp;
+
+       ctx->input_pages = kzalloc_objs(*ctx->input_pages, 1, GFP_KERNEL);
+       if (!ctx->input_pages) {
+               err = -ENOMEM;
+               goto err_free_rsp;
+       }
+
+       req_msg->client_id = ctx->client_id;
+       req_msg->flags = margs.flags;
+       req_msg->vaddr = margs.vaddrin;
+       req_msg->num = sizeof(*ctx->input_pages);
+
+       args[0].ptr = (u64)(uintptr_t)req;
+       args[0].length = sizeof(*req_msg);
+
+       err = setup_mmap_pages(ctx->file_priv, margs.fd, ctx->input_pages);
+       if (err)
+               goto err_free_input_pages;
+
+       args[1].ptr = (u64)(uintptr_t)ctx->input_pages;
+       args[1].length = sizeof(*ctx->input_pages);
+
+       args[2].ptr = (u64)(uintptr_t)rsp;
+       args[2].length = sizeof(*rsp_msg);
+
+       ctx->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+       ctx->args = args;
+       ctx->req = req;
+       ctx->rsp = rsp;
+       ctx->handle = FASTRPC_INIT_HANDLE;
+
+       return 0;
+
+err_free_input_pages:
+       kfree(ctx->input_pages);
+       ctx->input_pages = NULL;
+err_free_rsp:
+       kfree(rsp);
+err_free_req:
+       kfree(req);
+err_free_args:
+       kfree(args);
+       return err;
+}
+
+static int fastrpc_prepare_args_mem_map_attr(struct fastrpc_invoke_context 
*ctx, char __user *argp)
+{
+       struct qda_mem_map margs;
+       struct fastrpc_invoke_args *args;
+       void *req, *rsp;
+       struct fastrpc_mem_map_req_msg *req_msg;
+       struct fastrpc_map_rsp_msg *rsp_msg;
+       int err;
+
+       err = copy_from_user_or_kernel(&margs, argp, sizeof(margs));
+       if (err)
+               return err;
+
+       args = kzalloc_objs(*args, 4, GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+
+       req = kzalloc_obj(*req_msg, GFP_KERNEL);
+       if (!req) {
+               kfree(args);
+               return -ENOMEM;
+       }
+       req_msg = (struct fastrpc_mem_map_req_msg *)req;
+
+       rsp = kzalloc_obj(*rsp_msg, GFP_KERNEL);
+       if (!rsp) {
+               kfree(args);
+               kfree(req);
+               return -ENOMEM;
+       }
+       rsp_msg = (struct fastrpc_map_rsp_msg *)rsp;
+
+       ctx->input_pages = kzalloc_objs(*ctx->input_pages, 1, GFP_KERNEL);
+       if (!ctx->input_pages) {
+               kfree(args);
+               kfree(req);
+               kfree(rsp);
+               return -ENOMEM;
+       }
+
+       req_msg->client_id = ctx->client_id;
+       req_msg->fd = margs.fd;
+       req_msg->offset = margs.offset;
+       req_msg->flags = margs.flags;
+       req_msg->vaddrin = margs.vaddrin;
+       req_msg->num = sizeof(*ctx->input_pages);
+       req_msg->data_len = 0;
+
+       args[0].ptr = (u64)(uintptr_t)req;
+       args[0].length = sizeof(*req_msg);
+
+       err = setup_mmap_pages(ctx->file_priv, margs.fd, ctx->input_pages);
+       if (err) {
+               kfree(args);
+               kfree(req);
+               kfree(rsp);
+               kfree(ctx->input_pages);
+               ctx->input_pages = NULL;
+               return err;
+       }
+
+       args[1].ptr = (u64)(uintptr_t)ctx->input_pages;
+       args[1].length = sizeof(*ctx->input_pages);
+
+       args[2].ptr = (u64)(uintptr_t)ctx->input_pages;
+       args[2].length = 0;
+
+       args[3].ptr = (u64)(uintptr_t)rsp;
+       args[3].length = sizeof(*rsp_msg);
+
+       ctx->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_MAP, 3, 1);
+       ctx->args = args;
+       ctx->req = req;
+       ctx->rsp = rsp;
+       ctx->handle = FASTRPC_INIT_HANDLE;
+
+       return 0;
+}
+
 int fastrpc_prepare_args(struct fastrpc_invoke_context *ctx, char __user *argp)
 {
        int err;
@@ -678,6 +889,12 @@ int fastrpc_prepare_args(struct fastrpc_invoke_context 
*ctx, char __user *argp)
                ctx->pd = USER_PD;
                err = fastrpc_prepare_args_init_create(ctx, argp);
                break;
+       case FASTRPC_RMID_INIT_MMAP:
+               err = fastrpc_prepare_args_map(ctx, argp);
+               break;
+       case FASTRPC_RMID_INIT_MEM_MAP:
+               err = fastrpc_prepare_args_mem_map_attr(ctx, argp);
+               break;
        default:
                return -EINVAL;
        }
diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h
index a8deb7efec86..b45ccc77d9d1 100644
--- a/drivers/accel/qda/qda_fastrpc.h
+++ b/drivers/accel/qda/qda_fastrpc.h
@@ -260,8 +260,10 @@ struct fastrpc_invoke_context {
 /* Remote Method ID table - identifies initialization and control operations */
 #define FASTRPC_RMID_INIT_ATTACH       0       /* Attach to DSP session */
 #define FASTRPC_RMID_INIT_RELEASE      1       /* Release DSP session */
+#define FASTRPC_RMID_INIT_MMAP         4       /* Map memory region to DSP */
 #define FASTRPC_RMID_INIT_CREATE       6       /* Create DSP process */
 #define FASTRPC_RMID_INIT_CREATE_ATTR  7       /* Create DSP process with 
attributes */
+#define FASTRPC_RMID_INIT_MEM_MAP      10      /* Map DMA buffer with 
attributes to DSP */
 #define FASTRPC_RMID_INVOKE_DYNAMIC    0xFFFFFFFF      /* Dynamic method 
invocation */
 
 /* Common handle for initialization operations */
@@ -276,6 +278,59 @@ struct fastrpc_invoke_context {
 /* Maximum initialization file size (4MB) */
 #define INIT_FILELEN_MAX               (4 * 1024 * 1024)
 
+/* Message structures for internal FastRPC calls */
+
+/**
+ * struct fastrpc_mem_map_req_msg - Memory map request message with attributes
+ *
+ * This message structure is sent to the DSP to request mapping
+ * of a DMA buffer with custom attributes (ATTR request).
+ */
+struct fastrpc_mem_map_req_msg {
+       /* Client identifier for the session */
+       s32 client_id;
+       /* Handle of the buffer */
+       s32 fd;
+       /* Offset within the buffer */
+       s32 offset;
+       /* Mapping flags */
+       u32 flags;
+       /* Virtual address hint for mapping */
+       u64 vaddrin;
+       /* Pages in the mapping */
+       s32 num;
+       /* Length of additional data */
+       s32 data_len;
+};
+
+/**
+ * struct fastrpc_map_req_msg - Legacy memory map request message
+ *
+ * This message structure is sent to the DSP to request mapping
+ * of a DMA buffer into the DSP's virtual address space.
+ */
+struct fastrpc_map_req_msg {
+       /* Client identifier for the session */
+       s32 client_id;
+       /* Mapping flags */
+       u32 flags;
+       /* Virtual address hint for mapping */
+       u64 vaddr;
+       /* Pages in the mapping */
+       s32 num;
+};
+
+/**
+ * struct fastrpc_map_rsp_msg - Memory map response message
+ *
+ * This message structure is returned by the DSP after successfully
+ * mapping a buffer, providing the virtual address for future access.
+ */
+struct fastrpc_map_rsp_msg {
+       /* DSP virtual address assigned to the mapped buffer */
+       u64 vaddrout;
+};
+
 /**
  * fastrpc_context_free - Free an invocation context
  * @ref: Reference counter for the context
@@ -332,4 +387,13 @@ int fastrpc_internal_invoke_pack(struct 
fastrpc_invoke_context *ctx, struct qda_
  */
 int fastrpc_internal_invoke_unpack(struct fastrpc_invoke_context *ctx, struct 
qda_msg *msg);
 
+/**
+ * fastrpc_return_result - Return invocation result to user-space
+ * @ctx: FastRPC invocation context
+ * @argp: User-space pointer to return result
+ *
+ * Returns: 0 on success, negative error code on failure
+ */
+int fastrpc_return_result(struct fastrpc_invoke_context *ctx, char __user 
*argp);
+
 #endif /* __QDA_FASTRPC_H__ */
diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
index 477112ad6664..4eb932e2c9ae 100644
--- a/drivers/accel/qda/qda_ioctl.c
+++ b/drivers/accel/qda/qda_ioctl.c
@@ -192,6 +192,10 @@ static int fastrpc_invoke(int type, struct drm_device 
*dev, void *data,
        if (err)
                goto err_context_free;
 
+       err = fastrpc_return_result(ctx, (char __user *)data);
+       if (err)
+               goto err_context_free;
+
 err_context_free:
        if (type == FASTRPC_RMID_INIT_RELEASE && qda_user->init_mem_gem_obj) {
                drm_gem_object_put(&qda_user->init_mem_gem_obj->base);
@@ -223,3 +227,23 @@ int qda_ioctl_create(struct drm_device *dev, void *data, 
struct drm_file *file_p
 {
        return fastrpc_invoke(FASTRPC_RMID_INIT_CREATE, dev, data, file_priv);
 }
+
+int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file 
*file_priv)
+{
+       struct qda_mem_map *map_req;
+
+       if (!data)
+               return -EINVAL;
+
+       map_req = (struct qda_mem_map *)data;
+
+       switch (map_req->request) {
+       case QDA_MAP_REQUEST_LEGACY:
+               return fastrpc_invoke(FASTRPC_RMID_INIT_MMAP, dev, data, 
file_priv);
+       case QDA_MAP_REQUEST_ATTR:
+               return fastrpc_invoke(FASTRPC_RMID_INIT_MEM_MAP, dev, data, 
file_priv);
+       default:
+               qda_err(NULL, "Invalid map request type: %u\n", 
map_req->request);
+               return -EINVAL;
+       }
+}
diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
index 181ed50b19dc..d402d6715b41 100644
--- a/drivers/accel/qda/qda_ioctl.h
+++ b/drivers/accel/qda/qda_ioctl.h
@@ -89,4 +89,17 @@ int qda_ioctl_invoke(struct drm_device *dev, void *data, 
struct drm_file *file_p
  */
 int qda_ioctl_create(struct drm_device *dev, void *data, struct drm_file 
*file_priv);
 
+/**
+ * qda_ioctl_mmap - Map memory to DSP address space
+ * @dev: DRM device structure
+ * @data: User-space data containing memory mapping parameters
+ * @file_priv: DRM file private data
+ *
+ * This IOCTL handler maps a DMA buffer into the DSP's virtual address
+ * space, enabling the DSP to access the buffer during remote calls.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file 
*file_priv);
+
 #endif /* _QDA_IOCTL_H */
diff --git a/include/uapi/drm/qda_accel.h b/include/uapi/drm/qda_accel.h
index 2b7f500db52c..9151ba7adfaf 100644
--- a/include/uapi/drm/qda_accel.h
+++ b/include/uapi/drm/qda_accel.h
@@ -23,7 +23,8 @@ extern "C" {
 #define DRM_QDA_GEM_MMAP_OFFSET        0x02
 #define DRM_QDA_INIT_ATTACH            0x03
 #define DRM_QDA_INIT_CREATE            0x04
-/* Indexes 0x05-0x06 are reserved for other requests */
+#define DRM_QDA_MAP                    0x05
+/* 0x06 is reserved for other request */
 #define DRM_QDA_INVOKE                 0x07
 
 /*
@@ -41,9 +42,14 @@ extern "C" {
 #define DRM_IOCTL_QDA_INIT_ATTACH      DRM_IO(DRM_COMMAND_BASE + 
DRM_QDA_INIT_ATTACH)
 #define DRM_IOCTL_QDA_INIT_CREATE      DRM_IOWR(DRM_COMMAND_BASE + 
DRM_QDA_INIT_CREATE, \
                                                 struct qda_init_create)
+#define DRM_IOCTL_QDA_MAP              DRM_IOWR(DRM_COMMAND_BASE + 
DRM_QDA_MAP, struct qda_mem_map)
 #define DRM_IOCTL_QDA_INVOKE           DRM_IOWR(DRM_COMMAND_BASE + 
DRM_QDA_INVOKE, \
                                                 struct qda_invoke_args)
 
+/* Request type definitions for qda_mem_map */
+#define QDA_MAP_REQUEST_LEGACY    1  /* Legacy MMAP operation */
+#define QDA_MAP_REQUEST_ATTR      2  /* Handle-based MEM_MAP operation with 
attributes */
+
 /**
  * struct drm_qda_query - Device information query structure
  * @dsp_name: Name of DSP (e.g., "adsp", "cdsp", "cdsp1", "gdsp0", "gdsp1")
@@ -143,6 +149,42 @@ struct qda_init_create {
        __u64 file;
 };
 
+/**
+ * struct qda_mem_map - Memory mapping request structure
+ * @request: Request type (QDA_MAP_REQUEST_LEGACY or QDA_MAP_REQUEST_ATTR)
+ * @flags: Mapping flags for DSP (cache attributes, permissions)
+ * @fd: Handle of the buffer to map
+ * @attrs: Mapping attributes (used for ATTR request)
+ * @offset: Offset within buffer (used for ATTR request)
+ * @reserved: Reserved for alignment/future use
+ * @vaddrin: Optional virtual address hint for mapping
+ * @size: Size of the memory region to map in bytes
+ * @vaddrout: Output DSP virtual address after successful mapping
+ *
+ * This structure is used to request mapping of a DMA buffer into the
+ * DSP's virtual address space. The DSP will map the buffer according
+ * to the specified flags and return the virtual address in vaddrout.
+ *
+ * For QDA_MAP_REQUEST_LEGACY (value 1):
+ *   - Uses fields: fd, flags, vaddrin, size, vaddrout
+ *   - Legacy MMAP operation for backward compatibility
+ *
+ * For QDA_MAP_REQUEST_ATTR (value 2):
+ *   - Uses all fields including attrs and offset
+ *   - FD-based MEM_MAP operation with custom SMMU attributes
+ */
+struct qda_mem_map {
+       __u32 request;
+       __u32 flags;
+       __s32 fd;
+       __u32 attrs;
+       __u32 offset;
+       __u32 reserved;
+       __u64 vaddrin;
+       __u64 size;
+       __u64 vaddrout;
+};
+
 #if defined(__cplusplus)
 }
 #endif

-- 
2.34.1

Reply via email to