diff options
| author | Mark Brown <broonie@kernel.org> | 2026-09-17 20:19:44 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-09-17 20:19:44 +0100 |
| commit | 15900ab8061d2442f36b00cec8170c62fd45c0d4 (patch) | |
| tree | eee4e1778f822000e45382675a4f7afe13915f9c | |
| parent | c1e061d79661b1866165de2b6e4316d6d97cd7e0 (diff) | |
| parent | ef071c4906eb45d16b60f09154cf0bc6ec8f5435 (diff) | |
| download | linux-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.c | 200 |
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); |
