diff --git a/dsp/adsprpc.c b/dsp/adsprpc.c index 0f0f90d924..d92bda4a3f 100644 --- a/dsp/adsprpc.c +++ b/dsp/adsprpc.c @@ -957,6 +957,8 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, uintptr_t va, if ((fd < 0 || map->fd == fd) && map->raddr == va && map->raddr + map->len == va + len && map->refs == 1 && + /* Remove map only if it isn't being used in any pending RPC calls */ + !map->ctx_refs && /* Skip unmap if it is fastrpc shell memory */ !map->is_filemap) { match = map; @@ -997,7 +999,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { spin_lock_irqsave(&me->hlock, irq_flags); map->refs--; - if (!map->refs && !map->is_persistent) + if (!map->refs && !map->is_persistent && !map->ctx_refs) hlist_del_init(&map->hn); spin_unlock_irqrestore(&me->hlock, irq_flags); if (map->refs > 0) { @@ -1012,7 +1014,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) spin_unlock_irqrestore(&me->hlock, irq_flags); } else { map->refs--; - if (!map->refs) + if (!map->refs && !map->ctx_refs) hlist_del_init(&map->hn); if (map->refs > 0 && !flags) return; @@ -1953,8 +1955,15 @@ static void context_free(struct smq_invoke_ctx *ctx) spin_unlock(&ctx->fl->hlock); mutex_lock(&ctx->fl->map_mutex); - for (i = 0; i < nbufs; ++i) + for (i = 0; i < nbufs; ++i) { + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (ctx->maps[i] && ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i], 0); + } mutex_unlock(&ctx->fl->map_mutex); fastrpc_buf_free(ctx->buf, 1); @@ -2342,6 +2351,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], NULL, ctx->attrs[i], buf, len, mflags, &ctx->maps[i]); + /* + * Increment ctx refs count for in/out buffer if map created, + * indicate map under use in remote call + */ + if (ctx->maps[i]) + ctx->maps[i]->ctx_refs++; mutex_unlock(&ctx->fl->map_mutex); if (err) goto bail; @@ -2369,10 +2384,23 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) FASTRPC_ATTR_NOVA, 0, 0, dmaflags, &ctx->maps[i]); if (err) { - for (j = bufs; j < i; j++) + for (j = bufs; j < i; j++) { + /* + * Due to error decrement ctx refs count before mmap free + * for each in/out handle, if map created + */ + if (ctx->maps[j] && ctx->maps[j]->ctx_refs) + ctx->maps[j]->ctx_refs--; fastrpc_mmap_free(ctx->maps[j], 0); + } mutex_unlock(&ctx->fl->map_mutex); goto bail; + } else { + /* + * Increment ctx refs count for in/out handle if map created + * and no error, indicate map under use in remote call + */ + ctx->maps[i]->ctx_refs++; } ipage += 1; } @@ -2704,6 +2732,12 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, } } else { mutex_lock(&ctx->fl->map_mutex); + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (ctx->maps[i]->ctx_refs) + ctx->maps[i]->ctx_refs--; fastrpc_mmap_free(ctx->maps[i], 0); mutex_unlock(&ctx->fl->map_mutex); ctx->maps[i] = NULL; @@ -2714,8 +2748,15 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, if (!fdlist[i]) break; if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], NULL, 0, 0, - 0, 0, &mmap)) + 0, 0, &mmap)) { + /* + * Decrement ctx refs count before mmap free, + * indicate remote call no longer using it + */ + if (mmap && mmap->ctx_refs) + mmap->ctx_refs--; fastrpc_mmap_free(mmap, 0); + } } mutex_unlock(&ctx->fl->map_mutex); if (ctx->crc && crclist && rpra) diff --git a/dsp/adsprpc_shared.h b/dsp/adsprpc_shared.h index 7fb2be94df..cea20a7d10 100644 --- a/dsp/adsprpc_shared.h +++ b/dsp/adsprpc_shared.h @@ -1031,6 +1031,8 @@ struct fastrpc_mmap { /* Mapping for fastrpc shell */ bool is_filemap; char *servloc_name; /* Indicate which daemon mapped this */ + /* Indicates map is being used by a pending RPC call */ + unsigned int ctx_refs; }; enum fastrpc_perfkeys {