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
69 changes: 53 additions & 16 deletions drivers/misc/fastrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,6 @@ struct fastrpc_channel_ctx {
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;
u64 dma_mask;
Expand All @@ -316,6 +315,7 @@ struct fastrpc_user {
struct list_head user;
struct list_head maps;
struct list_head pending;
struct list_head interrupted;
struct list_head mmaps;

struct fastrpc_channel_ctx *cctx;
Expand Down Expand Up @@ -519,6 +519,11 @@ static void fastrpc_user_free(struct kref *ref)
fastrpc_context_put(ctx);
}

list_for_each_entry_safe(ctx, n, &fl->interrupted, node) {
list_del(&ctx->node);
fastrpc_context_put(ctx);
}

list_for_each_entry_safe(map, m, &fl->maps, node)
fastrpc_map_put(map);

Expand Down Expand Up @@ -590,6 +595,36 @@ static void fastrpc_context_put_wq(struct work_struct *work)
fastrpc_context_put(ctx);
}

static void fastrpc_context_save_interrupted(struct fastrpc_invoke_ctx *ctx)
{
spin_lock(&ctx->fl->lock);
list_del(&ctx->node);
list_add_tail(&ctx->node, &ctx->fl->interrupted);
spin_unlock(&ctx->fl->lock);
}

static struct fastrpc_invoke_ctx *fastrpc_context_restore_interrupted(
struct fastrpc_user *fl, u32 sc)
{
struct fastrpc_invoke_ctx *ctx = NULL, *ictx, *n;

spin_lock(&fl->lock);
list_for_each_entry_safe(ictx, n, &fl->interrupted, node) {
if (ictx->pid != current->pid)
continue;
if (ictx->sc != sc || ictx->fl != fl) {
spin_unlock(&fl->lock);
return ERR_PTR(-EINVAL);
}
ctx = ictx;
list_del(&ctx->node);
list_add_tail(&ctx->node, &fl->pending);
break;
}
spin_unlock(&fl->lock);
return ctx;
}

#define CMP(aa, bb) ((aa) == (bb) ? 0 : (aa) < (bb) ? -1 : 1)
static int olaps_cmp(const void *a, const void *b)
{
Expand Down Expand Up @@ -1318,8 +1353,6 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
struct fastrpc_invoke_args *args)
{
struct fastrpc_invoke_ctx *ctx = NULL;
struct fastrpc_buf *buf, *b;

int err = 0;

if (!fl->sctx)
Expand All @@ -1333,6 +1366,14 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
return -EPERM;
}

if (!kernel) {
ctx = fastrpc_context_restore_interrupted(fl, sc);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
if (ctx)
goto wait;
}

ctx = fastrpc_context_alloc(fl, kernel, sc, args);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
Expand All @@ -1351,6 +1392,7 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD)
ctx->rsp_flags = POLL_MODE;

wait:
err = fastrpc_wait_for_completion(ctx, kernel);
if (err)
goto bail;
Expand All @@ -1374,21 +1416,16 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
goto bail;

bail:
if (err != -ERESTARTSYS && err != -ETIMEDOUT) {
if (ctx && err == -ERESTARTSYS) {
fastrpc_context_save_interrupted(ctx);
} else if (ctx && err != -ETIMEDOUT) {
/* We are done with this compute context */
spin_lock(&fl->lock);
list_del(&ctx->node);
spin_unlock(&fl->lock);
fastrpc_context_put(ctx);
}

if (err == -ERESTARTSYS) {
list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
list_del(&buf->node);
list_add_tail(&buf->node, &fl->cctx->invoke_interrupted_mmaps);
}
}

if (err)
dev_dbg(fl->sctx->dev, "Error: Invoke Failed %d\n", err);

Expand Down Expand Up @@ -1713,6 +1750,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
spin_lock_init(&fl->lock);
mutex_init(&fl->mutex);
INIT_LIST_HEAD(&fl->pending);
INIT_LIST_HEAD(&fl->interrupted);
INIT_LIST_HEAD(&fl->maps);
INIT_LIST_HEAD(&fl->mmaps);
INIT_LIST_HEAD(&fl->user);
Expand Down Expand Up @@ -2507,7 +2545,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
rdev->dma_mask = &data->dma_mask;
dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
INIT_LIST_HEAD(&data->users);
INIT_LIST_HEAD(&data->invoke_interrupted_mmaps);
spin_lock_init(&data->lock);
idr_init(&data->ctx_idr);
data->domain_id = domain_id;
Expand Down Expand Up @@ -2539,13 +2576,16 @@ static void fastrpc_notify_users(struct fastrpc_user *user)
ctx->retval = -EPIPE;
complete(&ctx->work);
}
list_for_each_entry(ctx, &user->interrupted, node) {
ctx->retval = -EPIPE;
complete(&ctx->work);
}
spin_unlock(&user->lock);
}

static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
{
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
struct fastrpc_buf *buf, *b;
struct fastrpc_user *user;
unsigned long flags;
int err;
Expand All @@ -2563,9 +2603,6 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
if (cctx->secure_fdevice)
misc_deregister(&cctx->secure_fdevice->miscdev);

list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
list_del(&buf->node);

if (cctx->remote_heap && cctx->vmcount) {
u64 src_perms = 0;
struct qcom_scm_vmperm dst_perms;
Expand Down