summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-17 20:19:44 +0100
committerMark Brown <broonie@kernel.org>2026-09-17 20:19:44 +0100
commit15900ab8061d2442f36b00cec8170c62fd45c0d4 (patch)
treeeee4e1778f822000e45382675a4f7afe13915f9c
parentc1e061d79661b1866165de2b6e4316d6d97cd7e0 (diff)
parentef071c4906eb45d16b60f09154cf0bc6ec8f5435 (diff)
downloadlinux-next-15900ab8061d2442f36b00cec8170c62fd45c0d4.tar.gz
linux-next-15900ab8061d2442f36b00cec8170c62fd45c0d4.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/srini/fastrpc.git
-rw-r--r--drivers/misc/fastrpc.c200
1 files changed, 107 insertions, 93 deletions
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index d4fac2caca86..af18ff1992ee 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -70,8 +70,6 @@
#define ADSP_MMAP_HEAP_ADDR 4
/* MAP static DMA buffer on DSP User PD */
#define ADSP_MMAP_DMA_BUFFER 6
-/* Add memory to static PD pool protection thru hypervisor */
-#define ADSP_MMAP_REMOTE_HEAP_ADDR 8
/* Add memory to userPD pool, for user heap */
#define ADSP_MMAP_ADD_PAGES 0x1000
/* Add memory to userPD pool, for LLC heap */
@@ -314,10 +312,14 @@ struct fastrpc_channel_ctx {
struct kref refcount;
/* Flag if dsp attributes are cached */
bool valid_attributes;
+ /* Flag if audio PD init mem was allocated */
+ bool audio_init_mem;
+ /* Audio PD reserved remote heap region */
+ phys_addr_t remote_heap_addr;
+ u64 remote_heap_size;
u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
struct fastrpc_device *secure_fdevice;
struct fastrpc_device *fdevice;
- struct fastrpc_buf *remote_heap;
struct list_head invoke_interrupted_mmaps;
bool secure;
bool unsigned_support;
@@ -927,7 +929,7 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
dev_dbg(sess->dev, "Bad size passed len 0x%llx map size 0x%llx\n",
len, map->size);
err = -EINVAL;
- goto map_err;
+ goto get_err;
}
map->va = sg_virt(map->table->sgl);
map->len = len;
@@ -950,7 +952,7 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
dev_err(sess->dev,
"Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
&map->dma_addr, map->len, err);
- goto map_err;
+ goto get_err;
}
}
spin_lock(&fl->lock);
@@ -1454,15 +1456,24 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
struct fastrpc_init_create_static init;
struct fastrpc_invoke_args *args;
struct fastrpc_phy_page pages[1];
+ struct fastrpc_channel_ctx *cctx = fl->cctx;
char *name;
int err;
- bool scm_done = false;
struct {
int client_id;
u32 namelen;
u32 pageslen;
} inbuf;
u32 sc;
+ unsigned long flags;
+ bool sent_heap = false;
+
+ if (!cctx->remote_heap_addr || !cctx->remote_heap_size) {
+ err = -ENOMEM;
+ dev_err(fl->sctx->dev,
+ "remote heap memory region is not added\n");
+ return err;
+ }
args = kzalloc_objs(*args, FASTRPC_CREATE_STATIC_PROCESS_NARGS);
if (!args)
@@ -1486,31 +1497,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
inbuf.client_id = fl->client_id;
inbuf.namelen = init.namelen;
inbuf.pageslen = 0;
- if (!fl->cctx->remote_heap) {
- err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
- &fl->cctx->remote_heap);
- if (err)
- goto err_name;
-
- /* Map if we have any heap VMIDs associated with this ADSP Static Process. */
- if (fl->cctx->vmcount) {
- u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
-
- err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
- (u64)fl->cctx->remote_heap->size,
- &src_perms,
- fl->cctx->vmperms, fl->cctx->vmcount);
- if (err) {
- dev_err(fl->sctx->dev,
- "Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
- &fl->cctx->remote_heap->dma_addr,
- fl->cctx->remote_heap->size, err);
- goto err_map;
- }
- scm_done = true;
- inbuf.pageslen = 1;
- }
- }
fl->pd = USER_PD;
@@ -1522,8 +1508,25 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
args[1].length = inbuf.namelen;
args[1].fd = -1;
- pages[0].addr = fl->cctx->remote_heap->dma_addr;
- pages[0].size = fl->cctx->remote_heap->size;
+ /*
+ * Audio PD is a static PD and retains the remote heap
+ * information across daemon restarts. Therefore only
+ * the first attach should provide heap information to
+ * DSP. Subsequent attaches reuse the previously
+ * initialized memory pool.
+ */
+ spin_lock_irqsave(&cctx->lock, flags);
+ if (!cctx->audio_init_mem) {
+ pages[0].addr = cctx->remote_heap_addr;
+ pages[0].size = cctx->remote_heap_size;
+ cctx->audio_init_mem = true;
+ inbuf.pageslen = 1;
+ sent_heap = true;
+ } else {
+ pages[0].addr = 0;
+ pages[0].size = 0;
+ }
+ spin_unlock_irqrestore(&cctx->lock, flags);
args[2].ptr = (u64)(uintptr_t) pages;
args[2].length = sizeof(*pages);
@@ -1541,27 +1544,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
return 0;
err_invoke:
- if (fl->cctx->vmcount && scm_done) {
- u64 src_perms = 0;
- struct qcom_scm_vmperm dst_perms;
- u32 i;
-
- for (i = 0; i < fl->cctx->vmcount; i++)
- src_perms |= BIT(fl->cctx->vmperms[i].vmid);
-
- dst_perms.vmid = QCOM_SCM_VMID_HLOS;
- dst_perms.perm = QCOM_SCM_PERM_RWX;
- err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
- (u64)fl->cctx->remote_heap->size,
- &src_perms, &dst_perms, 1);
- if (err)
- dev_err(fl->sctx->dev, "Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
- &fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err);
+ if (sent_heap) {
+ spin_lock_irqsave(&cctx->lock, flags);
+ cctx->audio_init_mem = false;
+ spin_unlock_irqrestore(&cctx->lock, flags);
}
-err_map:
- fastrpc_buf_free(fl->cctx->remote_heap);
- fl->cctx->remote_heap = NULL;
-err_name:
kfree(name);
err:
kfree(args);
@@ -1783,7 +1770,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
fl->sctx = fastrpc_session_alloc(fl);
if (!fl->sctx) {
- dev_err(&cctx->rpdev->dev, "No session available\n");
+ dev_err_ratelimited(&cctx->rpdev->dev, "No session available\n");
mutex_destroy(&fl->mutex);
kfree(fl);
fastrpc_channel_ctx_put(cctx);
@@ -1937,7 +1924,7 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap,
kfree(dsp_attributes);
return -EOPNOTSUPP;
} else if (err) {
- dev_err(&cctx->rpdev->dev, "Error: dsp information is incorrect err: %d\n", err);
+ dev_dbg(&cctx->rpdev->dev, "Error: dsp information is incorrect err: %d\n", err);
kfree(dsp_attributes);
return err;
}
@@ -2086,7 +2073,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;
- if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR) {
+ if (req.flags != ADSP_MMAP_ADD_PAGES) {
dev_err(dev, "flag not supported 0x%x\n", req.flags);
return -EINVAL;
@@ -2097,10 +2084,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
return -EINVAL;
}
- if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
- err = fastrpc_remote_heap_alloc(fl, dev, req.size, &buf);
- else
- err = fastrpc_buf_alloc(fl, dev, req.size, &buf);
+ err = fastrpc_buf_alloc(fl, dev, req.size, &buf);
if (err) {
dev_err(dev, "failed to allocate buffer\n");
@@ -2139,20 +2123,6 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
/* let the client know the address to use */
req.vaddrout = rsp_msg.vaddr;
- /* Add memory to static PD pool, protection thru hypervisor */
- if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
- u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
-
- err = qcom_scm_assign_mem(buf->dma_addr, (u64)buf->size,
- &src_perms, fl->cctx->vmperms, fl->cctx->vmcount);
- if (err) {
- dev_err(fl->sctx->dev,
- "Failed to assign memory dma_addr %pad size 0x%llx err %d",
- &buf->dma_addr, buf->size, err);
- goto err_assign;
- }
- }
-
spin_lock(&fl->lock);
list_add_tail(&buf->node, &fl->mmaps);
spin_unlock(&fl->lock);
@@ -2533,6 +2503,45 @@ static const struct of_device_id fastrpc_poll_supported_machines[] __maybe_unuse
{},
};
+static int fastrpc_init_reserved_mem(struct fastrpc_channel_ctx *cctx,
+ struct device *rdev, u32 domain_id)
+{
+ struct resource res;
+ u64 src_perms;
+ int err;
+
+ /* Only SDSP and ADSP domains use a reserved remote heap region */
+ if (domain_id != SDSP_DOMAIN_ID && domain_id != ADSP_DOMAIN_ID)
+ return 0;
+
+ err = of_reserved_mem_region_to_resource(rdev->of_node, 0, &res);
+ if (err) {
+ /*
+ * The reserved-memory region is optional at probe time. For
+ * the Audio PD (ADSP) domain its absence is validated later in
+ * fastrpc_init_create_static_process(), so keep probing here.
+ */
+ return 0;
+ }
+
+ /*
+ * Audio PD (ADSP) is a static PD: cache the region so its lifetime
+ * is tied to the rpmsg channel instead of being controlled by
+ * userspace.
+ */
+ if (domain_id == ADSP_DOMAIN_ID) {
+ cctx->remote_heap_addr = res.start;
+ cctx->remote_heap_size = resource_size(&res);
+ }
+
+ if (!cctx->vmcount)
+ return 0;
+
+ src_perms = BIT(QCOM_SCM_VMID_HLOS);
+ return qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
+ cctx->vmperms, cctx->vmcount);
+}
+
static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
{
struct device *rdev = &rpdev->dev;
@@ -2558,8 +2567,8 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
return -EINVAL;
}
- if (of_reserved_mem_device_init_by_idx(rdev, rdev->of_node, 0))
- dev_info(rdev, "no reserved DMA memory for FASTRPC\n");
+ if (devm_of_reserved_mem_device_init(rdev))
+ dev_dbg(rdev, "no reserved DMA memory for FASTRPC\n");
vmcount = of_property_read_variable_u32_array(rdev->of_node,
"qcom,vmids", &vmids[0], 0, FASTRPC_MAX_VMIDS);
@@ -2580,21 +2589,9 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
}
}
- if (domain_id == SDSP_DOMAIN_ID) {
- struct resource res;
- u64 src_perms;
-
- err = of_reserved_mem_region_to_resource(rdev->of_node, 0, &res);
- if (!err) {
- src_perms = BIT(QCOM_SCM_VMID_HLOS);
-
- err = qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
- data->vmperms, data->vmcount);
- if (err)
- goto err_free_data;
- }
-
- }
+ err = fastrpc_init_reserved_mem(data, rdev, domain_id);
+ if (err)
+ goto err_free_data;
secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain"));
data->secure = secure_dsp;
@@ -2694,8 +2691,25 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
list_del(&buf->node);
- if (cctx->remote_heap)
- fastrpc_buf_free(cctx->remote_heap);
+ if (cctx->remote_heap_size && cctx->vmcount) {
+ u64 src_perms = 0;
+ int err, i;
+ struct qcom_scm_vmperm dst_perms;
+
+ for (i = 0; i < cctx->vmcount; i++)
+ src_perms |= BIT(cctx->vmperms[i].vmid);
+
+ dst_perms.vmid = QCOM_SCM_VMID_HLOS;
+ dst_perms.perm = QCOM_SCM_PERM_RWX;
+
+ err = qcom_scm_assign_mem(cctx->remote_heap_addr,
+ cctx->remote_heap_size, &src_perms,
+ &dst_perms, 1);
+ if (err)
+ dev_err(&rpdev->dev,
+ "Failed to assign memory back to HLOS: addr %pa size %#llx err %d\n",
+ &cctx->remote_heap_addr, cctx->remote_heap_size, err);
+ }
of_platform_depopulate(&rpdev->dev);