Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 71 additions & 62 deletions drivers/misc/fastrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ struct fastrpc_buf {
/* mmap support */
struct list_head node; /* list of user requested mmaps */
uintptr_t raddr;
/* Lock for buf->node */
spinlock_t *list_lock;
};

struct fastrpc_dma_buf_attachment {
Expand Down Expand Up @@ -287,6 +289,8 @@ 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;
u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
struct fastrpc_device *secure_fdevice;
struct fastrpc_device *fdevice;
Expand Down Expand Up @@ -407,6 +411,9 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,

static void fastrpc_buf_free(struct fastrpc_buf *buf)
{
if (!buf)
return;

dma_free_coherent(buf->dev, buf->size, buf->virt,
FASTRPC_PHYS(buf->phys));
kfree(buf);
Expand All @@ -431,6 +438,7 @@ static int __fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
buf->size = size;
buf->dev = dev;
buf->raddr = 0;
buf->list_lock = &fl->lock;

buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys,
GFP_KERNEL);
Expand Down Expand Up @@ -503,8 +511,7 @@ static void fastrpc_context_free(struct kref *ref)
for (i = 0; i < ctx->nbufs; i++)
fastrpc_map_put(ctx->maps[i]);

if (ctx->buf)
fastrpc_buf_free(ctx->buf);
fastrpc_buf_free(ctx->buf);

spin_lock_irqsave(&cctx->lock, flags);
idr_remove(&cctx->ctx_idr, FIELD_GET(FASTRPC_CTXID_MASK, ctx->ctxid));
Expand Down Expand Up @@ -1360,7 +1367,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
struct fastrpc_phy_page pages[1];
char *name;
int err;
bool scm_done = false;
struct {
int client_id;
u32 namelen;
Expand All @@ -1387,33 +1393,10 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
err = PTR_ERR(name);
goto err;
}

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->phys,
(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 phys 0x%llx size 0x%llx err %d\n",
fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
goto err_map;
}
scm_done = true;
}
}

inbuf.client_id = fl->client_id;
inbuf.namelen = init.namelen;
inbuf.pageslen = 0;

fl->pd = USER_PD;

args[0].ptr = (u64)(uintptr_t)&inbuf;
Expand All @@ -1424,8 +1407,15 @@ 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->phys;
pages[0].size = fl->cctx->remote_heap->size;
if (!fl->cctx->audio_init_mem) {
pages[0].addr = fl->cctx->remote_heap->phys;
pages[0].size = fl->cctx->remote_heap->size;
fl->cctx->audio_init_mem = true;
inbuf.pageslen = 1;
} else {
pages[0].addr = 0;
pages[0].size = 0;
}

args[2].ptr = (u64)(uintptr_t) pages;
args[2].length = sizeof(*pages);
Expand All @@ -1443,26 +1433,7 @@ 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->phys,
(u64)fl->cctx->remote_heap->size,
&src_perms, &dst_perms, 1);
if (err)
dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
}
err_map:
fastrpc_buf_free(fl->cctx->remote_heap);
err_name:
fl->cctx->audio_init_mem = false;
kfree(name);
err:
kfree(args);
Expand Down Expand Up @@ -1650,8 +1621,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
list_del(&fl->user);
spin_unlock_irqrestore(&cctx->lock, flags);

if (fl->init_mem)
fastrpc_buf_free(fl->init_mem);
fastrpc_buf_free(fl->init_mem);

list_for_each_entry_safe(ctx, n, &fl->pending, node) {
list_del(&ctx->node);
Expand Down Expand Up @@ -1947,9 +1917,6 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
&args[0]);
if (!err) {
dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr);
spin_lock(&fl->lock);
list_del(&buf->node);
spin_unlock(&fl->lock);
fastrpc_buf_free(buf);
} else {
dev_err(dev, "unmmap\tpt 0x%09lx ERROR\n", buf->raddr);
Expand All @@ -1963,13 +1930,15 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_buf *buf = NULL, *iter, *b;
struct fastrpc_req_munmap req;
struct device *dev = fl->sctx->dev;
int err;

if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;

spin_lock(&fl->lock);
list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
list_del(&iter->node);
buf = iter;
break;
}
Expand All @@ -1982,7 +1951,14 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
return -EINVAL;
}

return fastrpc_req_munmap_impl(fl, buf);
err = fastrpc_req_munmap_impl(fl, buf);
if (err) {
spin_lock(buf->list_lock);
list_add_tail(&buf->node, &fl->mmaps);
spin_unlock(buf->list_lock);
}

return err;
}

static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
Expand Down Expand Up @@ -2066,20 +2042,23 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
}
}

spin_lock(&fl->lock);
spin_lock(buf->list_lock);
list_add_tail(&buf->node, &fl->mmaps);
spin_unlock(&fl->lock);
spin_unlock(buf->list_lock);

if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
err = -EFAULT;
goto err_assign;
goto err_copy;
}

dev_dbg(dev, "mmap\t\tpt 0x%09lx OK [len 0x%08llx]\n",
buf->raddr, buf->size);

return 0;

err_copy:
spin_lock(buf->list_lock);
list_del(&buf->node);
spin_unlock(buf->list_lock);
err_assign:
fastrpc_req_munmap_impl(fl, buf);

Expand Down Expand Up @@ -2448,7 +2427,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
}
}

if (domain_id == SDSP_DOMAIN_ID) {
if (domain_id == SDSP_DOMAIN_ID || domain_id == ADSP_DOMAIN_ID) {
struct resource res;
u64 src_perms;

Expand All @@ -2459,6 +2438,15 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
data->vmperms, data->vmcount);
}
if (domain_id == ADSP_DOMAIN_ID) {
data->remote_heap =
kzalloc(sizeof(*data->remote_heap), GFP_KERNEL);
if (!data->remote_heap)
return -ENOMEM;

data->remote_heap->phys = res.start;
data->remote_heap->size = resource_size(&res);
}

}

Expand Down Expand Up @@ -2539,10 +2527,13 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
struct fastrpc_buf *buf, *b;
struct fastrpc_user *user;
unsigned long flags;
bool skip_free = false;
int err;

/* No invocations past this point */
spin_lock_irqsave(&cctx->lock, flags);
cctx->rpdev = NULL;
cctx->audio_init_mem = false;
list_for_each_entry(user, &cctx->users, user)
fastrpc_notify_users(user);
spin_unlock_irqrestore(&cctx->lock, flags);
Expand All @@ -2556,8 +2547,26 @@ 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) {
if (cctx->vmcount) {
u64 src_perms = 0;
struct qcom_scm_vmperm dst_perms;

for (u32 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->phys,
cctx->remote_heap->size,
&src_perms, &dst_perms, 1);
if (err)
skip_free = true;
}
if (!skip_free)
fastrpc_buf_free(cctx->remote_heap);
}

of_platform_depopulate(&rpdev->dev);

Expand Down