1f6f9279fSSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0 2f6f9279fSSrinivas Kandagatla // Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. 3f6f9279fSSrinivas Kandagatla // Copyright (c) 2018, Linaro Limited 4f6f9279fSSrinivas Kandagatla 5*c68cfb71SSrinivas Kandagatla #include <linux/completion.h> 6f6f9279fSSrinivas Kandagatla #include <linux/device.h> 7*c68cfb71SSrinivas Kandagatla #include <linux/dma-buf.h> 8f6f9279fSSrinivas Kandagatla #include <linux/dma-mapping.h> 9f6f9279fSSrinivas Kandagatla #include <linux/idr.h> 10f6f9279fSSrinivas Kandagatla #include <linux/list.h> 11f6f9279fSSrinivas Kandagatla #include <linux/miscdevice.h> 12f6f9279fSSrinivas Kandagatla #include <linux/module.h> 13f6f9279fSSrinivas Kandagatla #include <linux/of_address.h> 14f6f9279fSSrinivas Kandagatla #include <linux/of.h> 15f6f9279fSSrinivas Kandagatla #include <linux/of_platform.h> 16f6f9279fSSrinivas Kandagatla #include <linux/rpmsg.h> 17f6f9279fSSrinivas Kandagatla #include <linux/scatterlist.h> 18f6f9279fSSrinivas Kandagatla #include <linux/slab.h> 19*c68cfb71SSrinivas Kandagatla #include <uapi/misc/fastrpc.h> 20f6f9279fSSrinivas Kandagatla 21f6f9279fSSrinivas Kandagatla #define ADSP_DOMAIN_ID (0) 22f6f9279fSSrinivas Kandagatla #define MDSP_DOMAIN_ID (1) 23f6f9279fSSrinivas Kandagatla #define SDSP_DOMAIN_ID (2) 24f6f9279fSSrinivas Kandagatla #define CDSP_DOMAIN_ID (3) 25f6f9279fSSrinivas Kandagatla #define FASTRPC_DEV_MAX 4 /* adsp, mdsp, slpi, cdsp*/ 26f6f9279fSSrinivas Kandagatla #define FASTRPC_MAX_SESSIONS 9 /*8 compute, 1 cpz*/ 27*c68cfb71SSrinivas Kandagatla #define FASTRPC_ALIGN 128 28*c68cfb71SSrinivas Kandagatla #define FASTRPC_MAX_FDLIST 16 29*c68cfb71SSrinivas Kandagatla #define FASTRPC_MAX_CRCLIST 64 30*c68cfb71SSrinivas Kandagatla #define FASTRPC_PHYS(p) ((p) & 0xffffffff) 31f6f9279fSSrinivas Kandagatla #define FASTRPC_CTX_MAX (256) 32f6f9279fSSrinivas Kandagatla #define FASTRPC_CTXID_MASK (0xFF0) 33f6f9279fSSrinivas Kandagatla #define FASTRPC_DEVICE_NAME "fastrpc" 34f6f9279fSSrinivas Kandagatla 35*c68cfb71SSrinivas Kandagatla /* Retrives number of input buffers from the scalars parameter */ 36*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff) 37*c68cfb71SSrinivas Kandagatla 38*c68cfb71SSrinivas Kandagatla /* Retrives number of output buffers from the scalars parameter */ 39*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0x0ff) 40*c68cfb71SSrinivas Kandagatla 41*c68cfb71SSrinivas Kandagatla /* Retrives number of input handles from the scalars parameter */ 42*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_INHANDLES(sc) (((sc) >> 4) & 0x0f) 43*c68cfb71SSrinivas Kandagatla 44*c68cfb71SSrinivas Kandagatla /* Retrives number of output handles from the scalars parameter */ 45*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_OUTHANDLES(sc) ((sc) & 0x0f) 46*c68cfb71SSrinivas Kandagatla 47*c68cfb71SSrinivas Kandagatla #define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) + \ 48*c68cfb71SSrinivas Kandagatla REMOTE_SCALARS_OUTBUFS(sc) + \ 49*c68cfb71SSrinivas Kandagatla REMOTE_SCALARS_INHANDLES(sc)+ \ 50*c68cfb71SSrinivas Kandagatla REMOTE_SCALARS_OUTHANDLES(sc)) 51*c68cfb71SSrinivas Kandagatla #define FASTRPC_BUILD_SCALARS(attr, method, in, out, oin, oout) \ 52*c68cfb71SSrinivas Kandagatla (((attr & 0x07) << 29) | \ 53*c68cfb71SSrinivas Kandagatla ((method & 0x1f) << 24) | \ 54*c68cfb71SSrinivas Kandagatla ((in & 0xff) << 16) | \ 55*c68cfb71SSrinivas Kandagatla ((out & 0xff) << 8) | \ 56*c68cfb71SSrinivas Kandagatla ((oin & 0x0f) << 4) | \ 57*c68cfb71SSrinivas Kandagatla (oout & 0x0f)) 58*c68cfb71SSrinivas Kandagatla 59*c68cfb71SSrinivas Kandagatla #define FASTRPC_SCALARS(method, in, out) \ 60*c68cfb71SSrinivas Kandagatla FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0) 61*c68cfb71SSrinivas Kandagatla 62f6f9279fSSrinivas Kandagatla #define miscdev_to_cctx(d) container_of(d, struct fastrpc_channel_ctx, miscdev) 63f6f9279fSSrinivas Kandagatla 64f6f9279fSSrinivas Kandagatla static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp", 65f6f9279fSSrinivas Kandagatla "sdsp", "cdsp"}; 66*c68cfb71SSrinivas Kandagatla struct fastrpc_phy_page { 67*c68cfb71SSrinivas Kandagatla u64 addr; /* physical address */ 68*c68cfb71SSrinivas Kandagatla u64 size; /* size of contiguous region */ 69*c68cfb71SSrinivas Kandagatla }; 70*c68cfb71SSrinivas Kandagatla 71*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_buf { 72*c68cfb71SSrinivas Kandagatla u32 num; /* number of contiguous regions */ 73*c68cfb71SSrinivas Kandagatla u32 pgidx; /* index to start of contiguous region */ 74*c68cfb71SSrinivas Kandagatla }; 75*c68cfb71SSrinivas Kandagatla 76*c68cfb71SSrinivas Kandagatla struct fastrpc_remote_arg { 77*c68cfb71SSrinivas Kandagatla u64 pv; 78*c68cfb71SSrinivas Kandagatla u64 len; 79*c68cfb71SSrinivas Kandagatla }; 80*c68cfb71SSrinivas Kandagatla 81*c68cfb71SSrinivas Kandagatla struct fastrpc_msg { 82*c68cfb71SSrinivas Kandagatla int pid; /* process group id */ 83*c68cfb71SSrinivas Kandagatla int tid; /* thread id */ 84*c68cfb71SSrinivas Kandagatla u64 ctx; /* invoke caller context */ 85*c68cfb71SSrinivas Kandagatla u32 handle; /* handle to invoke */ 86*c68cfb71SSrinivas Kandagatla u32 sc; /* scalars structure describing the data */ 87*c68cfb71SSrinivas Kandagatla u64 addr; /* physical address */ 88*c68cfb71SSrinivas Kandagatla u64 size; /* size of contiguous region */ 89*c68cfb71SSrinivas Kandagatla }; 90*c68cfb71SSrinivas Kandagatla 91*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_rsp { 92*c68cfb71SSrinivas Kandagatla u64 ctx; /* invoke caller context */ 93*c68cfb71SSrinivas Kandagatla int retval; /* invoke return value */ 94*c68cfb71SSrinivas Kandagatla }; 95*c68cfb71SSrinivas Kandagatla 96*c68cfb71SSrinivas Kandagatla struct fastrpc_buf { 97*c68cfb71SSrinivas Kandagatla struct fastrpc_user *fl; 98*c68cfb71SSrinivas Kandagatla struct device *dev; 99*c68cfb71SSrinivas Kandagatla void *virt; 100*c68cfb71SSrinivas Kandagatla u64 phys; 101*c68cfb71SSrinivas Kandagatla u64 size; 102*c68cfb71SSrinivas Kandagatla }; 103*c68cfb71SSrinivas Kandagatla 104*c68cfb71SSrinivas Kandagatla struct fastrpc_map { 105*c68cfb71SSrinivas Kandagatla struct list_head node; 106*c68cfb71SSrinivas Kandagatla struct fastrpc_user *fl; 107*c68cfb71SSrinivas Kandagatla int fd; 108*c68cfb71SSrinivas Kandagatla struct dma_buf *buf; 109*c68cfb71SSrinivas Kandagatla struct sg_table *table; 110*c68cfb71SSrinivas Kandagatla struct dma_buf_attachment *attach; 111*c68cfb71SSrinivas Kandagatla u64 phys; 112*c68cfb71SSrinivas Kandagatla u64 size; 113*c68cfb71SSrinivas Kandagatla void *va; 114*c68cfb71SSrinivas Kandagatla u64 len; 115*c68cfb71SSrinivas Kandagatla struct kref refcount; 116*c68cfb71SSrinivas Kandagatla }; 117*c68cfb71SSrinivas Kandagatla 118*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx { 119*c68cfb71SSrinivas Kandagatla int nscalars; 120*c68cfb71SSrinivas Kandagatla int nbufs; 121*c68cfb71SSrinivas Kandagatla int retval; 122*c68cfb71SSrinivas Kandagatla int pid; 123*c68cfb71SSrinivas Kandagatla int tgid; 124*c68cfb71SSrinivas Kandagatla u32 sc; 125*c68cfb71SSrinivas Kandagatla u32 *crc; 126*c68cfb71SSrinivas Kandagatla u64 ctxid; 127*c68cfb71SSrinivas Kandagatla u64 msg_sz; 128*c68cfb71SSrinivas Kandagatla struct kref refcount; 129*c68cfb71SSrinivas Kandagatla struct list_head node; /* list of ctxs */ 130*c68cfb71SSrinivas Kandagatla struct completion work; 131*c68cfb71SSrinivas Kandagatla struct fastrpc_msg msg; 132*c68cfb71SSrinivas Kandagatla struct fastrpc_user *fl; 133*c68cfb71SSrinivas Kandagatla struct fastrpc_remote_arg *rpra; 134*c68cfb71SSrinivas Kandagatla struct fastrpc_map **maps; 135*c68cfb71SSrinivas Kandagatla struct fastrpc_buf *buf; 136*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_args *args; 137*c68cfb71SSrinivas Kandagatla struct fastrpc_channel_ctx *cctx; 138*c68cfb71SSrinivas Kandagatla }; 139f6f9279fSSrinivas Kandagatla 140f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx { 141f6f9279fSSrinivas Kandagatla struct device *dev; 142f6f9279fSSrinivas Kandagatla int sid; 143f6f9279fSSrinivas Kandagatla bool used; 144f6f9279fSSrinivas Kandagatla bool valid; 145f6f9279fSSrinivas Kandagatla }; 146f6f9279fSSrinivas Kandagatla 147f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx { 148f6f9279fSSrinivas Kandagatla int domain_id; 149f6f9279fSSrinivas Kandagatla int sesscount; 150f6f9279fSSrinivas Kandagatla struct rpmsg_device *rpdev; 151f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS]; 152f6f9279fSSrinivas Kandagatla spinlock_t lock; 153f6f9279fSSrinivas Kandagatla struct idr ctx_idr; 154f6f9279fSSrinivas Kandagatla struct list_head users; 155f6f9279fSSrinivas Kandagatla struct miscdevice miscdev; 156f6f9279fSSrinivas Kandagatla }; 157f6f9279fSSrinivas Kandagatla 158f6f9279fSSrinivas Kandagatla struct fastrpc_user { 159f6f9279fSSrinivas Kandagatla struct list_head user; 160f6f9279fSSrinivas Kandagatla struct list_head maps; 161f6f9279fSSrinivas Kandagatla struct list_head pending; 162f6f9279fSSrinivas Kandagatla 163f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx; 164f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *sctx; 165*c68cfb71SSrinivas Kandagatla struct fastrpc_buf *init_mem; 166f6f9279fSSrinivas Kandagatla 167f6f9279fSSrinivas Kandagatla int tgid; 168f6f9279fSSrinivas Kandagatla int pd; 169f6f9279fSSrinivas Kandagatla /* Lock for lists */ 170f6f9279fSSrinivas Kandagatla spinlock_t lock; 171f6f9279fSSrinivas Kandagatla /* lock for allocations */ 172f6f9279fSSrinivas Kandagatla struct mutex mutex; 173f6f9279fSSrinivas Kandagatla }; 174f6f9279fSSrinivas Kandagatla 175*c68cfb71SSrinivas Kandagatla static void fastrpc_free_map(struct kref *ref) 176*c68cfb71SSrinivas Kandagatla { 177*c68cfb71SSrinivas Kandagatla struct fastrpc_map *map; 178*c68cfb71SSrinivas Kandagatla 179*c68cfb71SSrinivas Kandagatla map = container_of(ref, struct fastrpc_map, refcount); 180*c68cfb71SSrinivas Kandagatla 181*c68cfb71SSrinivas Kandagatla if (map->table) { 182*c68cfb71SSrinivas Kandagatla dma_buf_unmap_attachment(map->attach, map->table, 183*c68cfb71SSrinivas Kandagatla DMA_BIDIRECTIONAL); 184*c68cfb71SSrinivas Kandagatla dma_buf_detach(map->buf, map->attach); 185*c68cfb71SSrinivas Kandagatla dma_buf_put(map->buf); 186*c68cfb71SSrinivas Kandagatla } 187*c68cfb71SSrinivas Kandagatla 188*c68cfb71SSrinivas Kandagatla kfree(map); 189*c68cfb71SSrinivas Kandagatla } 190*c68cfb71SSrinivas Kandagatla 191*c68cfb71SSrinivas Kandagatla static void fastrpc_map_put(struct fastrpc_map *map) 192*c68cfb71SSrinivas Kandagatla { 193*c68cfb71SSrinivas Kandagatla if (map) 194*c68cfb71SSrinivas Kandagatla kref_put(&map->refcount, fastrpc_free_map); 195*c68cfb71SSrinivas Kandagatla } 196*c68cfb71SSrinivas Kandagatla 197*c68cfb71SSrinivas Kandagatla static void fastrpc_map_get(struct fastrpc_map *map) 198*c68cfb71SSrinivas Kandagatla { 199*c68cfb71SSrinivas Kandagatla if (map) 200*c68cfb71SSrinivas Kandagatla kref_get(&map->refcount); 201*c68cfb71SSrinivas Kandagatla } 202*c68cfb71SSrinivas Kandagatla 203*c68cfb71SSrinivas Kandagatla static int fastrpc_map_find(struct fastrpc_user *fl, int fd, 204*c68cfb71SSrinivas Kandagatla struct fastrpc_map **ppmap) 205*c68cfb71SSrinivas Kandagatla { 206*c68cfb71SSrinivas Kandagatla struct fastrpc_map *map = NULL; 207*c68cfb71SSrinivas Kandagatla 208*c68cfb71SSrinivas Kandagatla mutex_lock(&fl->mutex); 209*c68cfb71SSrinivas Kandagatla list_for_each_entry(map, &fl->maps, node) { 210*c68cfb71SSrinivas Kandagatla if (map->fd == fd) { 211*c68cfb71SSrinivas Kandagatla fastrpc_map_get(map); 212*c68cfb71SSrinivas Kandagatla *ppmap = map; 213*c68cfb71SSrinivas Kandagatla mutex_unlock(&fl->mutex); 214*c68cfb71SSrinivas Kandagatla return 0; 215*c68cfb71SSrinivas Kandagatla } 216*c68cfb71SSrinivas Kandagatla } 217*c68cfb71SSrinivas Kandagatla mutex_unlock(&fl->mutex); 218*c68cfb71SSrinivas Kandagatla 219*c68cfb71SSrinivas Kandagatla return -ENOENT; 220*c68cfb71SSrinivas Kandagatla } 221*c68cfb71SSrinivas Kandagatla 222*c68cfb71SSrinivas Kandagatla static void fastrpc_buf_free(struct fastrpc_buf *buf) 223*c68cfb71SSrinivas Kandagatla { 224*c68cfb71SSrinivas Kandagatla dma_free_coherent(buf->dev, buf->size, buf->virt, 225*c68cfb71SSrinivas Kandagatla FASTRPC_PHYS(buf->phys)); 226*c68cfb71SSrinivas Kandagatla kfree(buf); 227*c68cfb71SSrinivas Kandagatla } 228*c68cfb71SSrinivas Kandagatla 229*c68cfb71SSrinivas Kandagatla static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev, 230*c68cfb71SSrinivas Kandagatla u64 size, struct fastrpc_buf **obuf) 231*c68cfb71SSrinivas Kandagatla { 232*c68cfb71SSrinivas Kandagatla struct fastrpc_buf *buf; 233*c68cfb71SSrinivas Kandagatla 234*c68cfb71SSrinivas Kandagatla buf = kzalloc(sizeof(*buf), GFP_KERNEL); 235*c68cfb71SSrinivas Kandagatla if (!buf) 236*c68cfb71SSrinivas Kandagatla return -ENOMEM; 237*c68cfb71SSrinivas Kandagatla 238*c68cfb71SSrinivas Kandagatla buf->fl = fl; 239*c68cfb71SSrinivas Kandagatla buf->virt = NULL; 240*c68cfb71SSrinivas Kandagatla buf->phys = 0; 241*c68cfb71SSrinivas Kandagatla buf->size = size; 242*c68cfb71SSrinivas Kandagatla buf->dev = dev; 243*c68cfb71SSrinivas Kandagatla 244*c68cfb71SSrinivas Kandagatla buf->virt = dma_alloc_coherent(dev, buf->size, (dma_addr_t *)&buf->phys, 245*c68cfb71SSrinivas Kandagatla GFP_KERNEL); 246*c68cfb71SSrinivas Kandagatla if (!buf->virt) 247*c68cfb71SSrinivas Kandagatla return -ENOMEM; 248*c68cfb71SSrinivas Kandagatla 249*c68cfb71SSrinivas Kandagatla if (fl->sctx && fl->sctx->sid) 250*c68cfb71SSrinivas Kandagatla buf->phys += ((u64)fl->sctx->sid << 32); 251*c68cfb71SSrinivas Kandagatla 252*c68cfb71SSrinivas Kandagatla *obuf = buf; 253*c68cfb71SSrinivas Kandagatla 254*c68cfb71SSrinivas Kandagatla return 0; 255*c68cfb71SSrinivas Kandagatla } 256*c68cfb71SSrinivas Kandagatla 257*c68cfb71SSrinivas Kandagatla static void fastrpc_context_free(struct kref *ref) 258*c68cfb71SSrinivas Kandagatla { 259*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx; 260*c68cfb71SSrinivas Kandagatla struct fastrpc_channel_ctx *cctx; 261*c68cfb71SSrinivas Kandagatla int i; 262*c68cfb71SSrinivas Kandagatla 263*c68cfb71SSrinivas Kandagatla ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount); 264*c68cfb71SSrinivas Kandagatla cctx = ctx->cctx; 265*c68cfb71SSrinivas Kandagatla 266*c68cfb71SSrinivas Kandagatla for (i = 0; i < ctx->nscalars; i++) 267*c68cfb71SSrinivas Kandagatla fastrpc_map_put(ctx->maps[i]); 268*c68cfb71SSrinivas Kandagatla 269*c68cfb71SSrinivas Kandagatla if (ctx->buf) 270*c68cfb71SSrinivas Kandagatla fastrpc_buf_free(ctx->buf); 271*c68cfb71SSrinivas Kandagatla 272*c68cfb71SSrinivas Kandagatla spin_lock(&cctx->lock); 273*c68cfb71SSrinivas Kandagatla idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4); 274*c68cfb71SSrinivas Kandagatla spin_unlock(&cctx->lock); 275*c68cfb71SSrinivas Kandagatla 276*c68cfb71SSrinivas Kandagatla kfree(ctx->maps); 277*c68cfb71SSrinivas Kandagatla kfree(ctx); 278*c68cfb71SSrinivas Kandagatla } 279*c68cfb71SSrinivas Kandagatla 280*c68cfb71SSrinivas Kandagatla static void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx) 281*c68cfb71SSrinivas Kandagatla { 282*c68cfb71SSrinivas Kandagatla kref_get(&ctx->refcount); 283*c68cfb71SSrinivas Kandagatla } 284*c68cfb71SSrinivas Kandagatla 285*c68cfb71SSrinivas Kandagatla static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx) 286*c68cfb71SSrinivas Kandagatla { 287*c68cfb71SSrinivas Kandagatla kref_put(&ctx->refcount, fastrpc_context_free); 288*c68cfb71SSrinivas Kandagatla } 289*c68cfb71SSrinivas Kandagatla 290*c68cfb71SSrinivas Kandagatla static struct fastrpc_invoke_ctx *fastrpc_context_alloc( 291*c68cfb71SSrinivas Kandagatla struct fastrpc_user *user, u32 kernel, u32 sc, 292*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_args *args) 293*c68cfb71SSrinivas Kandagatla { 294*c68cfb71SSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = user->cctx; 295*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx = NULL; 296*c68cfb71SSrinivas Kandagatla int ret; 297*c68cfb71SSrinivas Kandagatla 298*c68cfb71SSrinivas Kandagatla ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 299*c68cfb71SSrinivas Kandagatla if (!ctx) 300*c68cfb71SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 301*c68cfb71SSrinivas Kandagatla 302*c68cfb71SSrinivas Kandagatla INIT_LIST_HEAD(&ctx->node); 303*c68cfb71SSrinivas Kandagatla ctx->fl = user; 304*c68cfb71SSrinivas Kandagatla ctx->nscalars = REMOTE_SCALARS_LENGTH(sc); 305*c68cfb71SSrinivas Kandagatla ctx->nbufs = REMOTE_SCALARS_INBUFS(sc) + 306*c68cfb71SSrinivas Kandagatla REMOTE_SCALARS_OUTBUFS(sc); 307*c68cfb71SSrinivas Kandagatla 308*c68cfb71SSrinivas Kandagatla if (ctx->nscalars) { 309*c68cfb71SSrinivas Kandagatla ctx->maps = kcalloc(ctx->nscalars, 310*c68cfb71SSrinivas Kandagatla sizeof(*ctx->maps), GFP_KERNEL); 311*c68cfb71SSrinivas Kandagatla if (!ctx->maps) { 312*c68cfb71SSrinivas Kandagatla kfree(ctx); 313*c68cfb71SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 314*c68cfb71SSrinivas Kandagatla } 315*c68cfb71SSrinivas Kandagatla ctx->args = args; 316*c68cfb71SSrinivas Kandagatla } 317*c68cfb71SSrinivas Kandagatla 318*c68cfb71SSrinivas Kandagatla ctx->sc = sc; 319*c68cfb71SSrinivas Kandagatla ctx->retval = -1; 320*c68cfb71SSrinivas Kandagatla ctx->pid = current->pid; 321*c68cfb71SSrinivas Kandagatla ctx->tgid = user->tgid; 322*c68cfb71SSrinivas Kandagatla ctx->cctx = cctx; 323*c68cfb71SSrinivas Kandagatla init_completion(&ctx->work); 324*c68cfb71SSrinivas Kandagatla 325*c68cfb71SSrinivas Kandagatla spin_lock(&user->lock); 326*c68cfb71SSrinivas Kandagatla list_add_tail(&ctx->node, &user->pending); 327*c68cfb71SSrinivas Kandagatla spin_unlock(&user->lock); 328*c68cfb71SSrinivas Kandagatla 329*c68cfb71SSrinivas Kandagatla spin_lock(&cctx->lock); 330*c68cfb71SSrinivas Kandagatla ret = idr_alloc_cyclic(&cctx->ctx_idr, ctx, 1, 331*c68cfb71SSrinivas Kandagatla FASTRPC_CTX_MAX, GFP_ATOMIC); 332*c68cfb71SSrinivas Kandagatla if (ret < 0) { 333*c68cfb71SSrinivas Kandagatla spin_unlock(&cctx->lock); 334*c68cfb71SSrinivas Kandagatla goto err_idr; 335*c68cfb71SSrinivas Kandagatla } 336*c68cfb71SSrinivas Kandagatla ctx->ctxid = ret << 4; 337*c68cfb71SSrinivas Kandagatla spin_unlock(&cctx->lock); 338*c68cfb71SSrinivas Kandagatla 339*c68cfb71SSrinivas Kandagatla kref_init(&ctx->refcount); 340*c68cfb71SSrinivas Kandagatla 341*c68cfb71SSrinivas Kandagatla return ctx; 342*c68cfb71SSrinivas Kandagatla err_idr: 343*c68cfb71SSrinivas Kandagatla spin_lock(&user->lock); 344*c68cfb71SSrinivas Kandagatla list_del(&ctx->node); 345*c68cfb71SSrinivas Kandagatla spin_unlock(&user->lock); 346*c68cfb71SSrinivas Kandagatla kfree(ctx->maps); 347*c68cfb71SSrinivas Kandagatla kfree(ctx); 348*c68cfb71SSrinivas Kandagatla 349*c68cfb71SSrinivas Kandagatla return ERR_PTR(ret); 350*c68cfb71SSrinivas Kandagatla } 351*c68cfb71SSrinivas Kandagatla 352*c68cfb71SSrinivas Kandagatla static int fastrpc_map_create(struct fastrpc_user *fl, int fd, 353*c68cfb71SSrinivas Kandagatla u64 len, struct fastrpc_map **ppmap) 354*c68cfb71SSrinivas Kandagatla { 355*c68cfb71SSrinivas Kandagatla struct fastrpc_session_ctx *sess = fl->sctx; 356*c68cfb71SSrinivas Kandagatla struct fastrpc_map *map = NULL; 357*c68cfb71SSrinivas Kandagatla int err = 0; 358*c68cfb71SSrinivas Kandagatla 359*c68cfb71SSrinivas Kandagatla if (!fastrpc_map_find(fl, fd, ppmap)) 360*c68cfb71SSrinivas Kandagatla return 0; 361*c68cfb71SSrinivas Kandagatla 362*c68cfb71SSrinivas Kandagatla map = kzalloc(sizeof(*map), GFP_KERNEL); 363*c68cfb71SSrinivas Kandagatla if (!map) 364*c68cfb71SSrinivas Kandagatla return -ENOMEM; 365*c68cfb71SSrinivas Kandagatla 366*c68cfb71SSrinivas Kandagatla INIT_LIST_HEAD(&map->node); 367*c68cfb71SSrinivas Kandagatla map->fl = fl; 368*c68cfb71SSrinivas Kandagatla map->fd = fd; 369*c68cfb71SSrinivas Kandagatla map->buf = dma_buf_get(fd); 370*c68cfb71SSrinivas Kandagatla if (!map->buf) { 371*c68cfb71SSrinivas Kandagatla err = -EINVAL; 372*c68cfb71SSrinivas Kandagatla goto get_err; 373*c68cfb71SSrinivas Kandagatla } 374*c68cfb71SSrinivas Kandagatla 375*c68cfb71SSrinivas Kandagatla map->attach = dma_buf_attach(map->buf, sess->dev); 376*c68cfb71SSrinivas Kandagatla if (IS_ERR(map->attach)) { 377*c68cfb71SSrinivas Kandagatla dev_err(sess->dev, "Failed to attach dmabuf\n"); 378*c68cfb71SSrinivas Kandagatla err = PTR_ERR(map->attach); 379*c68cfb71SSrinivas Kandagatla goto attach_err; 380*c68cfb71SSrinivas Kandagatla } 381*c68cfb71SSrinivas Kandagatla 382*c68cfb71SSrinivas Kandagatla map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL); 383*c68cfb71SSrinivas Kandagatla if (IS_ERR(map->table)) { 384*c68cfb71SSrinivas Kandagatla err = PTR_ERR(map->table); 385*c68cfb71SSrinivas Kandagatla goto map_err; 386*c68cfb71SSrinivas Kandagatla } 387*c68cfb71SSrinivas Kandagatla 388*c68cfb71SSrinivas Kandagatla map->phys = sg_dma_address(map->table->sgl); 389*c68cfb71SSrinivas Kandagatla map->phys += ((u64)fl->sctx->sid << 32); 390*c68cfb71SSrinivas Kandagatla map->size = len; 391*c68cfb71SSrinivas Kandagatla map->va = sg_virt(map->table->sgl); 392*c68cfb71SSrinivas Kandagatla map->len = len; 393*c68cfb71SSrinivas Kandagatla kref_init(&map->refcount); 394*c68cfb71SSrinivas Kandagatla 395*c68cfb71SSrinivas Kandagatla spin_lock(&fl->lock); 396*c68cfb71SSrinivas Kandagatla list_add_tail(&map->node, &fl->maps); 397*c68cfb71SSrinivas Kandagatla spin_unlock(&fl->lock); 398*c68cfb71SSrinivas Kandagatla *ppmap = map; 399*c68cfb71SSrinivas Kandagatla 400*c68cfb71SSrinivas Kandagatla return 0; 401*c68cfb71SSrinivas Kandagatla 402*c68cfb71SSrinivas Kandagatla map_err: 403*c68cfb71SSrinivas Kandagatla dma_buf_detach(map->buf, map->attach); 404*c68cfb71SSrinivas Kandagatla attach_err: 405*c68cfb71SSrinivas Kandagatla dma_buf_put(map->buf); 406*c68cfb71SSrinivas Kandagatla get_err: 407*c68cfb71SSrinivas Kandagatla kfree(map); 408*c68cfb71SSrinivas Kandagatla 409*c68cfb71SSrinivas Kandagatla return err; 410*c68cfb71SSrinivas Kandagatla } 411*c68cfb71SSrinivas Kandagatla 412*c68cfb71SSrinivas Kandagatla /* 413*c68cfb71SSrinivas Kandagatla * Fastrpc payload buffer with metadata looks like: 414*c68cfb71SSrinivas Kandagatla * 415*c68cfb71SSrinivas Kandagatla * >>>>>> START of METADATA <<<<<<<<< 416*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 417*c68cfb71SSrinivas Kandagatla * | Arguments | 418*c68cfb71SSrinivas Kandagatla * | type:(struct fastrpc_remote_arg)| 419*c68cfb71SSrinivas Kandagatla * | (0 - N) | 420*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 421*c68cfb71SSrinivas Kandagatla * | Invoke Buffer list | 422*c68cfb71SSrinivas Kandagatla * | type:(struct fastrpc_invoke_buf)| 423*c68cfb71SSrinivas Kandagatla * | (0 - N) | 424*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 425*c68cfb71SSrinivas Kandagatla * | Page info list | 426*c68cfb71SSrinivas Kandagatla * | type:(struct fastrpc_phy_page) | 427*c68cfb71SSrinivas Kandagatla * | (0 - N) | 428*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 429*c68cfb71SSrinivas Kandagatla * | Optional info | 430*c68cfb71SSrinivas Kandagatla * |(can be specific to SoC/Firmware)| 431*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 432*c68cfb71SSrinivas Kandagatla * >>>>>>>> END of METADATA <<<<<<<<< 433*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 434*c68cfb71SSrinivas Kandagatla * | Inline ARGS | 435*c68cfb71SSrinivas Kandagatla * | (0-N) | 436*c68cfb71SSrinivas Kandagatla * +---------------------------------+ 437*c68cfb71SSrinivas Kandagatla */ 438*c68cfb71SSrinivas Kandagatla 439*c68cfb71SSrinivas Kandagatla static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) 440*c68cfb71SSrinivas Kandagatla { 441*c68cfb71SSrinivas Kandagatla int size = 0; 442*c68cfb71SSrinivas Kandagatla 443*c68cfb71SSrinivas Kandagatla size = (sizeof(struct fastrpc_remote_arg) + 444*c68cfb71SSrinivas Kandagatla sizeof(struct fastrpc_invoke_buf) + 445*c68cfb71SSrinivas Kandagatla sizeof(struct fastrpc_phy_page)) * ctx->nscalars + 446*c68cfb71SSrinivas Kandagatla sizeof(u64) * FASTRPC_MAX_FDLIST + 447*c68cfb71SSrinivas Kandagatla sizeof(u32) * FASTRPC_MAX_CRCLIST; 448*c68cfb71SSrinivas Kandagatla 449*c68cfb71SSrinivas Kandagatla return size; 450*c68cfb71SSrinivas Kandagatla } 451*c68cfb71SSrinivas Kandagatla 452*c68cfb71SSrinivas Kandagatla static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen) 453*c68cfb71SSrinivas Kandagatla { 454*c68cfb71SSrinivas Kandagatla u64 size = 0; 455*c68cfb71SSrinivas Kandagatla int i; 456*c68cfb71SSrinivas Kandagatla 457*c68cfb71SSrinivas Kandagatla size = ALIGN(metalen, FASTRPC_ALIGN); 458*c68cfb71SSrinivas Kandagatla for (i = 0; i < ctx->nscalars; i++) { 459*c68cfb71SSrinivas Kandagatla if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) { 460*c68cfb71SSrinivas Kandagatla size = ALIGN(size, FASTRPC_ALIGN); 461*c68cfb71SSrinivas Kandagatla size += ctx->args[i].length; 462*c68cfb71SSrinivas Kandagatla } 463*c68cfb71SSrinivas Kandagatla } 464*c68cfb71SSrinivas Kandagatla 465*c68cfb71SSrinivas Kandagatla return size; 466*c68cfb71SSrinivas Kandagatla } 467*c68cfb71SSrinivas Kandagatla 468*c68cfb71SSrinivas Kandagatla static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx) 469*c68cfb71SSrinivas Kandagatla { 470*c68cfb71SSrinivas Kandagatla struct device *dev = ctx->fl->sctx->dev; 471*c68cfb71SSrinivas Kandagatla int i, err; 472*c68cfb71SSrinivas Kandagatla 473*c68cfb71SSrinivas Kandagatla for (i = 0; i < ctx->nscalars; ++i) { 474*c68cfb71SSrinivas Kandagatla /* Make sure reserved field is set to 0 */ 475*c68cfb71SSrinivas Kandagatla if (ctx->args[i].reserved) 476*c68cfb71SSrinivas Kandagatla return -EINVAL; 477*c68cfb71SSrinivas Kandagatla 478*c68cfb71SSrinivas Kandagatla if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 || 479*c68cfb71SSrinivas Kandagatla ctx->args[i].length == 0) 480*c68cfb71SSrinivas Kandagatla continue; 481*c68cfb71SSrinivas Kandagatla 482*c68cfb71SSrinivas Kandagatla err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, 483*c68cfb71SSrinivas Kandagatla ctx->args[i].length, &ctx->maps[i]); 484*c68cfb71SSrinivas Kandagatla if (err) { 485*c68cfb71SSrinivas Kandagatla dev_err(dev, "Error Creating map %d\n", err); 486*c68cfb71SSrinivas Kandagatla return -EINVAL; 487*c68cfb71SSrinivas Kandagatla } 488*c68cfb71SSrinivas Kandagatla 489*c68cfb71SSrinivas Kandagatla } 490*c68cfb71SSrinivas Kandagatla return 0; 491*c68cfb71SSrinivas Kandagatla } 492*c68cfb71SSrinivas Kandagatla 493*c68cfb71SSrinivas Kandagatla static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) 494*c68cfb71SSrinivas Kandagatla { 495*c68cfb71SSrinivas Kandagatla struct device *dev = ctx->fl->sctx->dev; 496*c68cfb71SSrinivas Kandagatla struct fastrpc_remote_arg *rpra; 497*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_buf *list; 498*c68cfb71SSrinivas Kandagatla struct fastrpc_phy_page *pages; 499*c68cfb71SSrinivas Kandagatla int inbufs, i, err = 0; 500*c68cfb71SSrinivas Kandagatla u64 rlen, pkt_size; 501*c68cfb71SSrinivas Kandagatla uintptr_t args; 502*c68cfb71SSrinivas Kandagatla int metalen; 503*c68cfb71SSrinivas Kandagatla 504*c68cfb71SSrinivas Kandagatla 505*c68cfb71SSrinivas Kandagatla inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); 506*c68cfb71SSrinivas Kandagatla metalen = fastrpc_get_meta_size(ctx); 507*c68cfb71SSrinivas Kandagatla pkt_size = fastrpc_get_payload_size(ctx, metalen); 508*c68cfb71SSrinivas Kandagatla 509*c68cfb71SSrinivas Kandagatla err = fastrpc_create_maps(ctx); 510*c68cfb71SSrinivas Kandagatla if (err) 511*c68cfb71SSrinivas Kandagatla return err; 512*c68cfb71SSrinivas Kandagatla 513*c68cfb71SSrinivas Kandagatla ctx->msg_sz = pkt_size; 514*c68cfb71SSrinivas Kandagatla 515*c68cfb71SSrinivas Kandagatla err = fastrpc_buf_alloc(ctx->fl, dev, pkt_size, &ctx->buf); 516*c68cfb71SSrinivas Kandagatla if (err) 517*c68cfb71SSrinivas Kandagatla return err; 518*c68cfb71SSrinivas Kandagatla 519*c68cfb71SSrinivas Kandagatla rpra = ctx->buf->virt; 520*c68cfb71SSrinivas Kandagatla list = ctx->buf->virt + ctx->nscalars * sizeof(*rpra); 521*c68cfb71SSrinivas Kandagatla pages = ctx->buf->virt + ctx->nscalars * (sizeof(*list) + 522*c68cfb71SSrinivas Kandagatla sizeof(*rpra)); 523*c68cfb71SSrinivas Kandagatla args = (uintptr_t)ctx->buf->virt + metalen; 524*c68cfb71SSrinivas Kandagatla rlen = pkt_size - metalen; 525*c68cfb71SSrinivas Kandagatla ctx->rpra = rpra; 526*c68cfb71SSrinivas Kandagatla 527*c68cfb71SSrinivas Kandagatla for (i = 0; i < ctx->nbufs; ++i) { 528*c68cfb71SSrinivas Kandagatla u64 len = ctx->args[i].length; 529*c68cfb71SSrinivas Kandagatla 530*c68cfb71SSrinivas Kandagatla rpra[i].pv = 0; 531*c68cfb71SSrinivas Kandagatla rpra[i].len = len; 532*c68cfb71SSrinivas Kandagatla list[i].num = len ? 1 : 0; 533*c68cfb71SSrinivas Kandagatla list[i].pgidx = i; 534*c68cfb71SSrinivas Kandagatla 535*c68cfb71SSrinivas Kandagatla if (!len) 536*c68cfb71SSrinivas Kandagatla continue; 537*c68cfb71SSrinivas Kandagatla 538*c68cfb71SSrinivas Kandagatla pages[i].size = roundup(len, PAGE_SIZE); 539*c68cfb71SSrinivas Kandagatla 540*c68cfb71SSrinivas Kandagatla if (ctx->maps[i]) { 541*c68cfb71SSrinivas Kandagatla rpra[i].pv = (u64) ctx->args[i].ptr; 542*c68cfb71SSrinivas Kandagatla pages[i].addr = ctx->maps[i]->phys; 543*c68cfb71SSrinivas Kandagatla } else { 544*c68cfb71SSrinivas Kandagatla rlen -= ALIGN(args, FASTRPC_ALIGN) - args; 545*c68cfb71SSrinivas Kandagatla args = ALIGN(args, FASTRPC_ALIGN); 546*c68cfb71SSrinivas Kandagatla if (rlen < len) 547*c68cfb71SSrinivas Kandagatla goto bail; 548*c68cfb71SSrinivas Kandagatla 549*c68cfb71SSrinivas Kandagatla rpra[i].pv = args; 550*c68cfb71SSrinivas Kandagatla pages[i].addr = ctx->buf->phys + (pkt_size - rlen); 551*c68cfb71SSrinivas Kandagatla pages[i].addr = pages[i].addr & PAGE_MASK; 552*c68cfb71SSrinivas Kandagatla args = args + len; 553*c68cfb71SSrinivas Kandagatla rlen -= len; 554*c68cfb71SSrinivas Kandagatla } 555*c68cfb71SSrinivas Kandagatla 556*c68cfb71SSrinivas Kandagatla if (i < inbufs && !ctx->maps[i]) { 557*c68cfb71SSrinivas Kandagatla void *dst = (void *)(uintptr_t)rpra[i].pv; 558*c68cfb71SSrinivas Kandagatla void *src = (void *)(uintptr_t)ctx->args[i].ptr; 559*c68cfb71SSrinivas Kandagatla 560*c68cfb71SSrinivas Kandagatla if (!kernel) { 561*c68cfb71SSrinivas Kandagatla if (copy_from_user(dst, (void __user *)src, 562*c68cfb71SSrinivas Kandagatla len)) { 563*c68cfb71SSrinivas Kandagatla err = -EFAULT; 564*c68cfb71SSrinivas Kandagatla goto bail; 565*c68cfb71SSrinivas Kandagatla } 566*c68cfb71SSrinivas Kandagatla } else { 567*c68cfb71SSrinivas Kandagatla memcpy(dst, src, len); 568*c68cfb71SSrinivas Kandagatla } 569*c68cfb71SSrinivas Kandagatla } 570*c68cfb71SSrinivas Kandagatla } 571*c68cfb71SSrinivas Kandagatla 572*c68cfb71SSrinivas Kandagatla for (i = ctx->nbufs; i < ctx->nscalars; ++i) { 573*c68cfb71SSrinivas Kandagatla rpra[i].pv = (u64) ctx->args[i].ptr; 574*c68cfb71SSrinivas Kandagatla rpra[i].len = ctx->args[i].length; 575*c68cfb71SSrinivas Kandagatla list[i].num = ctx->args[i].length ? 1 : 0; 576*c68cfb71SSrinivas Kandagatla list[i].pgidx = i; 577*c68cfb71SSrinivas Kandagatla pages[i].addr = ctx->maps[i]->phys; 578*c68cfb71SSrinivas Kandagatla pages[i].size = ctx->maps[i]->size; 579*c68cfb71SSrinivas Kandagatla } 580*c68cfb71SSrinivas Kandagatla 581*c68cfb71SSrinivas Kandagatla bail: 582*c68cfb71SSrinivas Kandagatla if (err) 583*c68cfb71SSrinivas Kandagatla dev_err(dev, "Error: get invoke args failed:%d\n", err); 584*c68cfb71SSrinivas Kandagatla 585*c68cfb71SSrinivas Kandagatla return err; 586*c68cfb71SSrinivas Kandagatla } 587*c68cfb71SSrinivas Kandagatla 588*c68cfb71SSrinivas Kandagatla static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, 589*c68cfb71SSrinivas Kandagatla u32 kernel) 590*c68cfb71SSrinivas Kandagatla { 591*c68cfb71SSrinivas Kandagatla struct fastrpc_remote_arg *rpra = ctx->rpra; 592*c68cfb71SSrinivas Kandagatla int i, inbufs; 593*c68cfb71SSrinivas Kandagatla 594*c68cfb71SSrinivas Kandagatla inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); 595*c68cfb71SSrinivas Kandagatla 596*c68cfb71SSrinivas Kandagatla for (i = inbufs; i < ctx->nbufs; ++i) { 597*c68cfb71SSrinivas Kandagatla void *src = (void *)(uintptr_t)rpra[i].pv; 598*c68cfb71SSrinivas Kandagatla void *dst = (void *)(uintptr_t)ctx->args[i].ptr; 599*c68cfb71SSrinivas Kandagatla u64 len = rpra[i].len; 600*c68cfb71SSrinivas Kandagatla 601*c68cfb71SSrinivas Kandagatla if (!kernel) { 602*c68cfb71SSrinivas Kandagatla if (copy_to_user((void __user *)dst, src, len)) 603*c68cfb71SSrinivas Kandagatla return -EFAULT; 604*c68cfb71SSrinivas Kandagatla } else { 605*c68cfb71SSrinivas Kandagatla memcpy(dst, src, len); 606*c68cfb71SSrinivas Kandagatla } 607*c68cfb71SSrinivas Kandagatla } 608*c68cfb71SSrinivas Kandagatla 609*c68cfb71SSrinivas Kandagatla return 0; 610*c68cfb71SSrinivas Kandagatla } 611*c68cfb71SSrinivas Kandagatla 612*c68cfb71SSrinivas Kandagatla static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx, 613*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx, 614*c68cfb71SSrinivas Kandagatla u32 kernel, uint32_t handle) 615*c68cfb71SSrinivas Kandagatla { 616*c68cfb71SSrinivas Kandagatla struct fastrpc_channel_ctx *cctx; 617*c68cfb71SSrinivas Kandagatla struct fastrpc_user *fl = ctx->fl; 618*c68cfb71SSrinivas Kandagatla struct fastrpc_msg *msg = &ctx->msg; 619*c68cfb71SSrinivas Kandagatla 620*c68cfb71SSrinivas Kandagatla cctx = fl->cctx; 621*c68cfb71SSrinivas Kandagatla msg->pid = fl->tgid; 622*c68cfb71SSrinivas Kandagatla msg->tid = current->pid; 623*c68cfb71SSrinivas Kandagatla 624*c68cfb71SSrinivas Kandagatla if (kernel) 625*c68cfb71SSrinivas Kandagatla msg->pid = 0; 626*c68cfb71SSrinivas Kandagatla 627*c68cfb71SSrinivas Kandagatla msg->ctx = ctx->ctxid | fl->pd; 628*c68cfb71SSrinivas Kandagatla msg->handle = handle; 629*c68cfb71SSrinivas Kandagatla msg->sc = ctx->sc; 630*c68cfb71SSrinivas Kandagatla msg->addr = ctx->buf ? ctx->buf->phys : 0; 631*c68cfb71SSrinivas Kandagatla msg->size = roundup(ctx->msg_sz, PAGE_SIZE); 632*c68cfb71SSrinivas Kandagatla fastrpc_context_get(ctx); 633*c68cfb71SSrinivas Kandagatla 634*c68cfb71SSrinivas Kandagatla return rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg)); 635*c68cfb71SSrinivas Kandagatla } 636*c68cfb71SSrinivas Kandagatla 637*c68cfb71SSrinivas Kandagatla static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, 638*c68cfb71SSrinivas Kandagatla u32 handle, u32 sc, 639*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_args *args) 640*c68cfb71SSrinivas Kandagatla { 641*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx = NULL; 642*c68cfb71SSrinivas Kandagatla int err = 0; 643*c68cfb71SSrinivas Kandagatla 644*c68cfb71SSrinivas Kandagatla if (!fl->sctx) 645*c68cfb71SSrinivas Kandagatla return -EINVAL; 646*c68cfb71SSrinivas Kandagatla 647*c68cfb71SSrinivas Kandagatla ctx = fastrpc_context_alloc(fl, kernel, sc, args); 648*c68cfb71SSrinivas Kandagatla if (IS_ERR(ctx)) 649*c68cfb71SSrinivas Kandagatla return PTR_ERR(ctx); 650*c68cfb71SSrinivas Kandagatla 651*c68cfb71SSrinivas Kandagatla if (ctx->nscalars) { 652*c68cfb71SSrinivas Kandagatla err = fastrpc_get_args(kernel, ctx); 653*c68cfb71SSrinivas Kandagatla if (err) 654*c68cfb71SSrinivas Kandagatla goto bail; 655*c68cfb71SSrinivas Kandagatla } 656*c68cfb71SSrinivas Kandagatla /* Send invoke buffer to remote dsp */ 657*c68cfb71SSrinivas Kandagatla err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle); 658*c68cfb71SSrinivas Kandagatla if (err) 659*c68cfb71SSrinivas Kandagatla goto bail; 660*c68cfb71SSrinivas Kandagatla 661*c68cfb71SSrinivas Kandagatla /* Wait for remote dsp to respond or time out */ 662*c68cfb71SSrinivas Kandagatla err = wait_for_completion_interruptible(&ctx->work); 663*c68cfb71SSrinivas Kandagatla if (err) 664*c68cfb71SSrinivas Kandagatla goto bail; 665*c68cfb71SSrinivas Kandagatla 666*c68cfb71SSrinivas Kandagatla /* Check the response from remote dsp */ 667*c68cfb71SSrinivas Kandagatla err = ctx->retval; 668*c68cfb71SSrinivas Kandagatla if (err) 669*c68cfb71SSrinivas Kandagatla goto bail; 670*c68cfb71SSrinivas Kandagatla 671*c68cfb71SSrinivas Kandagatla if (ctx->nscalars) { 672*c68cfb71SSrinivas Kandagatla /* populate all the output buffers with results */ 673*c68cfb71SSrinivas Kandagatla err = fastrpc_put_args(ctx, kernel); 674*c68cfb71SSrinivas Kandagatla if (err) 675*c68cfb71SSrinivas Kandagatla goto bail; 676*c68cfb71SSrinivas Kandagatla } 677*c68cfb71SSrinivas Kandagatla 678*c68cfb71SSrinivas Kandagatla bail: 679*c68cfb71SSrinivas Kandagatla /* We are done with this compute context, remove it from pending list */ 680*c68cfb71SSrinivas Kandagatla spin_lock(&fl->lock); 681*c68cfb71SSrinivas Kandagatla list_del(&ctx->node); 682*c68cfb71SSrinivas Kandagatla spin_unlock(&fl->lock); 683*c68cfb71SSrinivas Kandagatla fastrpc_context_put(ctx); 684*c68cfb71SSrinivas Kandagatla 685*c68cfb71SSrinivas Kandagatla if (err) 686*c68cfb71SSrinivas Kandagatla dev_dbg(fl->sctx->dev, "Error: Invoke Failed %d\n", err); 687*c68cfb71SSrinivas Kandagatla 688*c68cfb71SSrinivas Kandagatla return err; 689*c68cfb71SSrinivas Kandagatla } 690*c68cfb71SSrinivas Kandagatla 691f6f9279fSSrinivas Kandagatla static struct fastrpc_session_ctx *fastrpc_session_alloc( 692f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx) 693f6f9279fSSrinivas Kandagatla { 694f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *session = NULL; 695f6f9279fSSrinivas Kandagatla int i; 696f6f9279fSSrinivas Kandagatla 697f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 698f6f9279fSSrinivas Kandagatla for (i = 0; i < cctx->sesscount; i++) { 699f6f9279fSSrinivas Kandagatla if (!cctx->session[i].used && cctx->session[i].valid) { 700f6f9279fSSrinivas Kandagatla cctx->session[i].used = true; 701f6f9279fSSrinivas Kandagatla session = &cctx->session[i]; 702f6f9279fSSrinivas Kandagatla break; 703f6f9279fSSrinivas Kandagatla } 704f6f9279fSSrinivas Kandagatla } 705f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 706f6f9279fSSrinivas Kandagatla 707f6f9279fSSrinivas Kandagatla return session; 708f6f9279fSSrinivas Kandagatla } 709f6f9279fSSrinivas Kandagatla 710f6f9279fSSrinivas Kandagatla static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx, 711f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *session) 712f6f9279fSSrinivas Kandagatla { 713f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 714f6f9279fSSrinivas Kandagatla session->used = false; 715f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 716f6f9279fSSrinivas Kandagatla } 717f6f9279fSSrinivas Kandagatla 718f6f9279fSSrinivas Kandagatla static int fastrpc_device_release(struct inode *inode, struct file *file) 719f6f9279fSSrinivas Kandagatla { 720f6f9279fSSrinivas Kandagatla struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data; 721f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = fl->cctx; 722*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx, *n; 723*c68cfb71SSrinivas Kandagatla struct fastrpc_map *map, *m; 724f6f9279fSSrinivas Kandagatla 725f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 726f6f9279fSSrinivas Kandagatla list_del(&fl->user); 727f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 728f6f9279fSSrinivas Kandagatla 729*c68cfb71SSrinivas Kandagatla if (fl->init_mem) 730*c68cfb71SSrinivas Kandagatla fastrpc_buf_free(fl->init_mem); 731*c68cfb71SSrinivas Kandagatla 732*c68cfb71SSrinivas Kandagatla list_for_each_entry_safe(ctx, n, &fl->pending, node) { 733*c68cfb71SSrinivas Kandagatla list_del(&ctx->node); 734*c68cfb71SSrinivas Kandagatla fastrpc_context_put(ctx); 735*c68cfb71SSrinivas Kandagatla } 736*c68cfb71SSrinivas Kandagatla 737*c68cfb71SSrinivas Kandagatla list_for_each_entry_safe(map, m, &fl->maps, node) { 738*c68cfb71SSrinivas Kandagatla list_del(&map->node); 739*c68cfb71SSrinivas Kandagatla fastrpc_map_put(map); 740*c68cfb71SSrinivas Kandagatla } 741*c68cfb71SSrinivas Kandagatla 742f6f9279fSSrinivas Kandagatla fastrpc_session_free(cctx, fl->sctx); 743f6f9279fSSrinivas Kandagatla 744f6f9279fSSrinivas Kandagatla mutex_destroy(&fl->mutex); 745f6f9279fSSrinivas Kandagatla kfree(fl); 746f6f9279fSSrinivas Kandagatla file->private_data = NULL; 747f6f9279fSSrinivas Kandagatla 748f6f9279fSSrinivas Kandagatla return 0; 749f6f9279fSSrinivas Kandagatla } 750f6f9279fSSrinivas Kandagatla 751f6f9279fSSrinivas Kandagatla static int fastrpc_device_open(struct inode *inode, struct file *filp) 752f6f9279fSSrinivas Kandagatla { 753f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = miscdev_to_cctx(filp->private_data); 754f6f9279fSSrinivas Kandagatla struct fastrpc_user *fl = NULL; 755f6f9279fSSrinivas Kandagatla 756f6f9279fSSrinivas Kandagatla fl = kzalloc(sizeof(*fl), GFP_KERNEL); 757f6f9279fSSrinivas Kandagatla if (!fl) 758f6f9279fSSrinivas Kandagatla return -ENOMEM; 759f6f9279fSSrinivas Kandagatla 760f6f9279fSSrinivas Kandagatla filp->private_data = fl; 761f6f9279fSSrinivas Kandagatla spin_lock_init(&fl->lock); 762f6f9279fSSrinivas Kandagatla mutex_init(&fl->mutex); 763f6f9279fSSrinivas Kandagatla INIT_LIST_HEAD(&fl->pending); 764f6f9279fSSrinivas Kandagatla INIT_LIST_HEAD(&fl->maps); 765f6f9279fSSrinivas Kandagatla INIT_LIST_HEAD(&fl->user); 766f6f9279fSSrinivas Kandagatla fl->tgid = current->tgid; 767f6f9279fSSrinivas Kandagatla fl->cctx = cctx; 768f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 769f6f9279fSSrinivas Kandagatla list_add_tail(&fl->user, &cctx->users); 770f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 771f6f9279fSSrinivas Kandagatla fl->sctx = fastrpc_session_alloc(cctx); 772f6f9279fSSrinivas Kandagatla 773f6f9279fSSrinivas Kandagatla return 0; 774f6f9279fSSrinivas Kandagatla } 775f6f9279fSSrinivas Kandagatla 776*c68cfb71SSrinivas Kandagatla static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp) 777*c68cfb71SSrinivas Kandagatla { 778*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_args *args = NULL; 779*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke inv; 780*c68cfb71SSrinivas Kandagatla u32 nscalars; 781*c68cfb71SSrinivas Kandagatla int err; 782*c68cfb71SSrinivas Kandagatla 783*c68cfb71SSrinivas Kandagatla if (copy_from_user(&inv, argp, sizeof(inv))) 784*c68cfb71SSrinivas Kandagatla return -EFAULT; 785*c68cfb71SSrinivas Kandagatla 786*c68cfb71SSrinivas Kandagatla /* nscalars is truncated here to max supported value */ 787*c68cfb71SSrinivas Kandagatla nscalars = REMOTE_SCALARS_LENGTH(inv.sc); 788*c68cfb71SSrinivas Kandagatla if (nscalars) { 789*c68cfb71SSrinivas Kandagatla args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL); 790*c68cfb71SSrinivas Kandagatla if (!args) 791*c68cfb71SSrinivas Kandagatla return -ENOMEM; 792*c68cfb71SSrinivas Kandagatla 793*c68cfb71SSrinivas Kandagatla if (copy_from_user(args, (void __user *)(uintptr_t)inv.args, 794*c68cfb71SSrinivas Kandagatla nscalars * sizeof(*args))) { 795*c68cfb71SSrinivas Kandagatla kfree(args); 796*c68cfb71SSrinivas Kandagatla return -EFAULT; 797*c68cfb71SSrinivas Kandagatla } 798*c68cfb71SSrinivas Kandagatla } 799*c68cfb71SSrinivas Kandagatla 800*c68cfb71SSrinivas Kandagatla err = fastrpc_internal_invoke(fl, false, inv.handle, inv.sc, args); 801*c68cfb71SSrinivas Kandagatla kfree(args); 802*c68cfb71SSrinivas Kandagatla 803*c68cfb71SSrinivas Kandagatla return err; 804*c68cfb71SSrinivas Kandagatla } 805*c68cfb71SSrinivas Kandagatla 806*c68cfb71SSrinivas Kandagatla static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, 807*c68cfb71SSrinivas Kandagatla unsigned long arg) 808*c68cfb71SSrinivas Kandagatla { 809*c68cfb71SSrinivas Kandagatla struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data; 810*c68cfb71SSrinivas Kandagatla char __user *argp = (char __user *)arg; 811*c68cfb71SSrinivas Kandagatla int err; 812*c68cfb71SSrinivas Kandagatla 813*c68cfb71SSrinivas Kandagatla switch (cmd) { 814*c68cfb71SSrinivas Kandagatla case FASTRPC_IOCTL_INVOKE: 815*c68cfb71SSrinivas Kandagatla err = fastrpc_invoke(fl, argp); 816*c68cfb71SSrinivas Kandagatla break; 817*c68cfb71SSrinivas Kandagatla default: 818*c68cfb71SSrinivas Kandagatla err = -ENOTTY; 819*c68cfb71SSrinivas Kandagatla break; 820*c68cfb71SSrinivas Kandagatla } 821*c68cfb71SSrinivas Kandagatla 822*c68cfb71SSrinivas Kandagatla return err; 823*c68cfb71SSrinivas Kandagatla } 824*c68cfb71SSrinivas Kandagatla 825f6f9279fSSrinivas Kandagatla static const struct file_operations fastrpc_fops = { 826f6f9279fSSrinivas Kandagatla .open = fastrpc_device_open, 827f6f9279fSSrinivas Kandagatla .release = fastrpc_device_release, 828*c68cfb71SSrinivas Kandagatla .unlocked_ioctl = fastrpc_device_ioctl, 829*c68cfb71SSrinivas Kandagatla .compat_ioctl = fastrpc_device_ioctl, 830f6f9279fSSrinivas Kandagatla }; 831f6f9279fSSrinivas Kandagatla 832f6f9279fSSrinivas Kandagatla static int fastrpc_cb_probe(struct platform_device *pdev) 833f6f9279fSSrinivas Kandagatla { 834f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx; 835f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *sess; 836f6f9279fSSrinivas Kandagatla struct device *dev = &pdev->dev; 837f6f9279fSSrinivas Kandagatla int i, sessions = 0; 838f6f9279fSSrinivas Kandagatla 839f6f9279fSSrinivas Kandagatla cctx = dev_get_drvdata(dev->parent); 840f6f9279fSSrinivas Kandagatla if (!cctx) 841f6f9279fSSrinivas Kandagatla return -EINVAL; 842f6f9279fSSrinivas Kandagatla 843f6f9279fSSrinivas Kandagatla of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions); 844f6f9279fSSrinivas Kandagatla 845f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 846f6f9279fSSrinivas Kandagatla sess = &cctx->session[cctx->sesscount]; 847f6f9279fSSrinivas Kandagatla sess->used = false; 848f6f9279fSSrinivas Kandagatla sess->valid = true; 849f6f9279fSSrinivas Kandagatla sess->dev = dev; 850f6f9279fSSrinivas Kandagatla dev_set_drvdata(dev, sess); 851f6f9279fSSrinivas Kandagatla 852f6f9279fSSrinivas Kandagatla if (of_property_read_u32(dev->of_node, "reg", &sess->sid)) 853f6f9279fSSrinivas Kandagatla dev_info(dev, "FastRPC Session ID not specified in DT\n"); 854f6f9279fSSrinivas Kandagatla 855f6f9279fSSrinivas Kandagatla if (sessions > 0) { 856f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *dup_sess; 857f6f9279fSSrinivas Kandagatla 858f6f9279fSSrinivas Kandagatla for (i = 1; i < sessions; i++) { 859f6f9279fSSrinivas Kandagatla if (cctx->sesscount++ >= FASTRPC_MAX_SESSIONS) 860f6f9279fSSrinivas Kandagatla break; 861f6f9279fSSrinivas Kandagatla dup_sess = &cctx->session[cctx->sesscount]; 862f6f9279fSSrinivas Kandagatla memcpy(dup_sess, sess, sizeof(*dup_sess)); 863f6f9279fSSrinivas Kandagatla } 864f6f9279fSSrinivas Kandagatla } 865f6f9279fSSrinivas Kandagatla cctx->sesscount++; 866f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 867f6f9279fSSrinivas Kandagatla dma_set_mask(dev, DMA_BIT_MASK(32)); 868f6f9279fSSrinivas Kandagatla 869f6f9279fSSrinivas Kandagatla return 0; 870f6f9279fSSrinivas Kandagatla } 871f6f9279fSSrinivas Kandagatla 872f6f9279fSSrinivas Kandagatla static int fastrpc_cb_remove(struct platform_device *pdev) 873f6f9279fSSrinivas Kandagatla { 874f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent); 875f6f9279fSSrinivas Kandagatla struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev); 876f6f9279fSSrinivas Kandagatla int i; 877f6f9279fSSrinivas Kandagatla 878f6f9279fSSrinivas Kandagatla spin_lock(&cctx->lock); 879f6f9279fSSrinivas Kandagatla for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) { 880f6f9279fSSrinivas Kandagatla if (cctx->session[i].sid == sess->sid) { 881f6f9279fSSrinivas Kandagatla cctx->session[i].valid = false; 882f6f9279fSSrinivas Kandagatla cctx->sesscount--; 883f6f9279fSSrinivas Kandagatla } 884f6f9279fSSrinivas Kandagatla } 885f6f9279fSSrinivas Kandagatla spin_unlock(&cctx->lock); 886f6f9279fSSrinivas Kandagatla 887f6f9279fSSrinivas Kandagatla return 0; 888f6f9279fSSrinivas Kandagatla } 889f6f9279fSSrinivas Kandagatla 890f6f9279fSSrinivas Kandagatla static const struct of_device_id fastrpc_match_table[] = { 891f6f9279fSSrinivas Kandagatla { .compatible = "qcom,fastrpc-compute-cb", }, 892f6f9279fSSrinivas Kandagatla {} 893f6f9279fSSrinivas Kandagatla }; 894f6f9279fSSrinivas Kandagatla 895f6f9279fSSrinivas Kandagatla static struct platform_driver fastrpc_cb_driver = { 896f6f9279fSSrinivas Kandagatla .probe = fastrpc_cb_probe, 897f6f9279fSSrinivas Kandagatla .remove = fastrpc_cb_remove, 898f6f9279fSSrinivas Kandagatla .driver = { 899f6f9279fSSrinivas Kandagatla .name = "qcom,fastrpc-cb", 900f6f9279fSSrinivas Kandagatla .of_match_table = fastrpc_match_table, 901f6f9279fSSrinivas Kandagatla .suppress_bind_attrs = true, 902f6f9279fSSrinivas Kandagatla }, 903f6f9279fSSrinivas Kandagatla }; 904f6f9279fSSrinivas Kandagatla 905f6f9279fSSrinivas Kandagatla static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) 906f6f9279fSSrinivas Kandagatla { 907f6f9279fSSrinivas Kandagatla struct device *rdev = &rpdev->dev; 908f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *data; 909f6f9279fSSrinivas Kandagatla int i, err, domain_id = -1; 910f6f9279fSSrinivas Kandagatla const char *domain; 911f6f9279fSSrinivas Kandagatla 912f6f9279fSSrinivas Kandagatla data = devm_kzalloc(rdev, sizeof(*data), GFP_KERNEL); 913f6f9279fSSrinivas Kandagatla if (!data) 914f6f9279fSSrinivas Kandagatla return -ENOMEM; 915f6f9279fSSrinivas Kandagatla 916f6f9279fSSrinivas Kandagatla err = of_property_read_string(rdev->of_node, "label", &domain); 917f6f9279fSSrinivas Kandagatla if (err) { 918f6f9279fSSrinivas Kandagatla dev_info(rdev, "FastRPC Domain not specified in DT\n"); 919f6f9279fSSrinivas Kandagatla return err; 920f6f9279fSSrinivas Kandagatla } 921f6f9279fSSrinivas Kandagatla 922f6f9279fSSrinivas Kandagatla for (i = 0; i <= CDSP_DOMAIN_ID; i++) { 923f6f9279fSSrinivas Kandagatla if (!strcmp(domains[i], domain)) { 924f6f9279fSSrinivas Kandagatla domain_id = i; 925f6f9279fSSrinivas Kandagatla break; 926f6f9279fSSrinivas Kandagatla } 927f6f9279fSSrinivas Kandagatla } 928f6f9279fSSrinivas Kandagatla 929f6f9279fSSrinivas Kandagatla if (domain_id < 0) { 930f6f9279fSSrinivas Kandagatla dev_info(rdev, "FastRPC Invalid Domain ID %d\n", domain_id); 931f6f9279fSSrinivas Kandagatla return -EINVAL; 932f6f9279fSSrinivas Kandagatla } 933f6f9279fSSrinivas Kandagatla 934f6f9279fSSrinivas Kandagatla data->miscdev.minor = MISC_DYNAMIC_MINOR; 935f6f9279fSSrinivas Kandagatla data->miscdev.name = kasprintf(GFP_KERNEL, "fastrpc-%s", 936f6f9279fSSrinivas Kandagatla domains[domain_id]); 937f6f9279fSSrinivas Kandagatla data->miscdev.fops = &fastrpc_fops; 938f6f9279fSSrinivas Kandagatla err = misc_register(&data->miscdev); 939f6f9279fSSrinivas Kandagatla if (err) 940f6f9279fSSrinivas Kandagatla return err; 941f6f9279fSSrinivas Kandagatla 942f6f9279fSSrinivas Kandagatla dev_set_drvdata(&rpdev->dev, data); 943f6f9279fSSrinivas Kandagatla dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32)); 944f6f9279fSSrinivas Kandagatla INIT_LIST_HEAD(&data->users); 945f6f9279fSSrinivas Kandagatla spin_lock_init(&data->lock); 946f6f9279fSSrinivas Kandagatla idr_init(&data->ctx_idr); 947f6f9279fSSrinivas Kandagatla data->domain_id = domain_id; 948f6f9279fSSrinivas Kandagatla data->rpdev = rpdev; 949f6f9279fSSrinivas Kandagatla 950f6f9279fSSrinivas Kandagatla return of_platform_populate(rdev->of_node, NULL, NULL, rdev); 951f6f9279fSSrinivas Kandagatla } 952f6f9279fSSrinivas Kandagatla 953*c68cfb71SSrinivas Kandagatla static void fastrpc_notify_users(struct fastrpc_user *user) 954*c68cfb71SSrinivas Kandagatla { 955*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx; 956*c68cfb71SSrinivas Kandagatla 957*c68cfb71SSrinivas Kandagatla spin_lock(&user->lock); 958*c68cfb71SSrinivas Kandagatla list_for_each_entry(ctx, &user->pending, node) 959*c68cfb71SSrinivas Kandagatla complete(&ctx->work); 960*c68cfb71SSrinivas Kandagatla spin_unlock(&user->lock); 961*c68cfb71SSrinivas Kandagatla } 962*c68cfb71SSrinivas Kandagatla 963f6f9279fSSrinivas Kandagatla static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) 964f6f9279fSSrinivas Kandagatla { 965f6f9279fSSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev); 966*c68cfb71SSrinivas Kandagatla struct fastrpc_user *user; 967*c68cfb71SSrinivas Kandagatla 968*c68cfb71SSrinivas Kandagatla spin_lock(&cctx->lock); 969*c68cfb71SSrinivas Kandagatla list_for_each_entry(user, &cctx->users, user) 970*c68cfb71SSrinivas Kandagatla fastrpc_notify_users(user); 971*c68cfb71SSrinivas Kandagatla spin_unlock(&cctx->lock); 972f6f9279fSSrinivas Kandagatla 973f6f9279fSSrinivas Kandagatla misc_deregister(&cctx->miscdev); 974f6f9279fSSrinivas Kandagatla of_platform_depopulate(&rpdev->dev); 975f6f9279fSSrinivas Kandagatla kfree(cctx); 976f6f9279fSSrinivas Kandagatla } 977f6f9279fSSrinivas Kandagatla 978f6f9279fSSrinivas Kandagatla static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, 979f6f9279fSSrinivas Kandagatla int len, void *priv, u32 addr) 980f6f9279fSSrinivas Kandagatla { 981*c68cfb71SSrinivas Kandagatla struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev); 982*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_rsp *rsp = data; 983*c68cfb71SSrinivas Kandagatla struct fastrpc_invoke_ctx *ctx; 984*c68cfb71SSrinivas Kandagatla unsigned long flags; 985*c68cfb71SSrinivas Kandagatla unsigned long ctxid; 986*c68cfb71SSrinivas Kandagatla 987*c68cfb71SSrinivas Kandagatla if (len < sizeof(*rsp)) 988*c68cfb71SSrinivas Kandagatla return -EINVAL; 989*c68cfb71SSrinivas Kandagatla 990*c68cfb71SSrinivas Kandagatla ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4); 991*c68cfb71SSrinivas Kandagatla 992*c68cfb71SSrinivas Kandagatla spin_lock_irqsave(&cctx->lock, flags); 993*c68cfb71SSrinivas Kandagatla ctx = idr_find(&cctx->ctx_idr, ctxid); 994*c68cfb71SSrinivas Kandagatla spin_unlock_irqrestore(&cctx->lock, flags); 995*c68cfb71SSrinivas Kandagatla 996*c68cfb71SSrinivas Kandagatla if (!ctx) { 997*c68cfb71SSrinivas Kandagatla dev_err(&rpdev->dev, "No context ID matches response\n"); 998*c68cfb71SSrinivas Kandagatla return -ENOENT; 999*c68cfb71SSrinivas Kandagatla } 1000*c68cfb71SSrinivas Kandagatla 1001*c68cfb71SSrinivas Kandagatla ctx->retval = rsp->retval; 1002*c68cfb71SSrinivas Kandagatla complete(&ctx->work); 1003*c68cfb71SSrinivas Kandagatla fastrpc_context_put(ctx); 1004*c68cfb71SSrinivas Kandagatla 1005f6f9279fSSrinivas Kandagatla return 0; 1006f6f9279fSSrinivas Kandagatla } 1007f6f9279fSSrinivas Kandagatla 1008f6f9279fSSrinivas Kandagatla static const struct of_device_id fastrpc_rpmsg_of_match[] = { 1009f6f9279fSSrinivas Kandagatla { .compatible = "qcom,fastrpc" }, 1010f6f9279fSSrinivas Kandagatla { }, 1011f6f9279fSSrinivas Kandagatla }; 1012f6f9279fSSrinivas Kandagatla MODULE_DEVICE_TABLE(of, fastrpc_rpmsg_of_match); 1013f6f9279fSSrinivas Kandagatla 1014f6f9279fSSrinivas Kandagatla static struct rpmsg_driver fastrpc_driver = { 1015f6f9279fSSrinivas Kandagatla .probe = fastrpc_rpmsg_probe, 1016f6f9279fSSrinivas Kandagatla .remove = fastrpc_rpmsg_remove, 1017f6f9279fSSrinivas Kandagatla .callback = fastrpc_rpmsg_callback, 1018f6f9279fSSrinivas Kandagatla .drv = { 1019f6f9279fSSrinivas Kandagatla .name = "qcom,fastrpc", 1020f6f9279fSSrinivas Kandagatla .of_match_table = fastrpc_rpmsg_of_match, 1021f6f9279fSSrinivas Kandagatla }, 1022f6f9279fSSrinivas Kandagatla }; 1023f6f9279fSSrinivas Kandagatla 1024f6f9279fSSrinivas Kandagatla static int fastrpc_init(void) 1025f6f9279fSSrinivas Kandagatla { 1026f6f9279fSSrinivas Kandagatla int ret; 1027f6f9279fSSrinivas Kandagatla 1028f6f9279fSSrinivas Kandagatla ret = platform_driver_register(&fastrpc_cb_driver); 1029f6f9279fSSrinivas Kandagatla if (ret < 0) { 1030f6f9279fSSrinivas Kandagatla pr_err("fastrpc: failed to register cb driver\n"); 1031f6f9279fSSrinivas Kandagatla return ret; 1032f6f9279fSSrinivas Kandagatla } 1033f6f9279fSSrinivas Kandagatla 1034f6f9279fSSrinivas Kandagatla ret = register_rpmsg_driver(&fastrpc_driver); 1035f6f9279fSSrinivas Kandagatla if (ret < 0) { 1036f6f9279fSSrinivas Kandagatla pr_err("fastrpc: failed to register rpmsg driver\n"); 1037f6f9279fSSrinivas Kandagatla platform_driver_unregister(&fastrpc_cb_driver); 1038f6f9279fSSrinivas Kandagatla return ret; 1039f6f9279fSSrinivas Kandagatla } 1040f6f9279fSSrinivas Kandagatla 1041f6f9279fSSrinivas Kandagatla return 0; 1042f6f9279fSSrinivas Kandagatla } 1043f6f9279fSSrinivas Kandagatla module_init(fastrpc_init); 1044f6f9279fSSrinivas Kandagatla 1045f6f9279fSSrinivas Kandagatla static void fastrpc_exit(void) 1046f6f9279fSSrinivas Kandagatla { 1047f6f9279fSSrinivas Kandagatla platform_driver_unregister(&fastrpc_cb_driver); 1048f6f9279fSSrinivas Kandagatla unregister_rpmsg_driver(&fastrpc_driver); 1049f6f9279fSSrinivas Kandagatla } 1050f6f9279fSSrinivas Kandagatla module_exit(fastrpc_exit); 1051f6f9279fSSrinivas Kandagatla 1052f6f9279fSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1053