2024-02-02 06:41:04

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 00/16] Add missing features to FastRPC driver

This patch series adds the listed features that have been missing
in upstream fastRPC driver.

- Redesign and improve remote heap management.
- Add static PD restart support for audio and sensors PD using
PDR framework.
- Add changes to support multimode invocation ioctl request. This
ioctl call facilitates multiple types of requests from user including
CRC check, performance counters, shared context bank usage, etc.
This series also carries patch to save and restore interrupted
context.
- Add early wakeup support to allow DSP user to send early response
to CPU and improve fastrpc performance.
- Add polling mode support with which driver polls on memory to avoid
CPU from going to low power modes.
- Add notifications frameworks to provide users with the DSP PD status
notifications.
- Add a control mechanism to allow users to clean up DSP user PD
- Add wakelock management support
- Add DSP signalling support
- Add check for untrusted applications and allow trusted processed to
offload to system unsigned PD.

Ekansh Gupta (16):
misc: fastrpc: Redesign remote heap management
misc: fastrpc: Add support for unsigned PD
misc: fastrpc: Add static PD restart support
misc: fastrpc: Add fastrpc multimode invoke request support
misc: fastrpc: Add CRC support for remote buffers
misc: fastrpc: Capture kernel and DSP performance counters
misc: fastrpc: Add support to save and restore interrupted
misc: fastrpc: Add support to allocate shared context bank
misc: fastrpc: Add early wakeup support for fastRPC driver
misc: fastrpc: Add polling mode support for fastRPC driver
misc: fastrpc: Add DSP PD notification support
misc: fastrpc: Add support for users to clean up DSP user PD
misc: fastrpc: Add wakelock management support
misc: fastrpc: Add DSP signal support
misc: fastrpc: Restrict untrusted apk to spawn privileged PD
misc: fastrpc: Add system unsigned PD support

drivers/misc/fastrpc.c | 1949 +++++++++++++++++++++++++++++++----
include/uapi/misc/fastrpc.h | 112 ++
2 files changed, 1844 insertions(+), 217 deletions(-)

--
2.17.0



2024-02-02 06:41:34

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 02/16] misc: fastrpc: Add support for unsigned PD

Unsigned PD requires more initial memory to spawn. Also most of
the memory request are allocated from userspace. Add support for
unsigned PD by increasing init memory size and handling mapping
request for cases other than DSP heap grow requests.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 184 ++++++++++++++++++++++++++---------------
1 file changed, 118 insertions(+), 66 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index f3ef5e194f11..bdce5469de19 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -38,7 +38,7 @@
#define FASTRPC_INIT_HANDLE 1
#define FASTRPC_DSP_UTILITIES_HANDLE 2
#define FASTRPC_CTXID_MASK (0xFF0)
-#define INIT_FILELEN_MAX (2 * 1024 * 1024)
+#define INIT_FILELEN_MAX (5 * 1024 * 1024)
#define INIT_FILE_NAMELEN_MAX (128)
#define FASTRPC_DEVICE_NAME "fastrpc"

@@ -303,6 +303,7 @@ struct fastrpc_user {
int tgid;
int pd;
bool is_secure_dev;
+ bool is_unsigned_pd;
/* Lock for lists */
spinlock_t lock;
/* lock for allocations */
@@ -1403,7 +1404,6 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
u32 siglen;
} inbuf;
u32 sc;
- bool unsigned_module = false;

args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
if (!args)
@@ -1415,9 +1415,9 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
}

if (init.attrs & FASTRPC_MODE_UNSIGNED_MODULE)
- unsigned_module = true;
+ fl->is_unsigned_pd = true;

- if (is_session_rejected(fl, unsigned_module)) {
+ if (is_session_rejected(fl, fl->is_unsigned_pd)) {
err = -ECONNREFUSED;
goto err;
}
@@ -1486,6 +1486,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
goto err_invoke;

kfree(args);
+ fastrpc_map_put(map);

return 0;

@@ -1953,98 +1954,149 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_mmap_rsp_msg rsp_msg;
struct fastrpc_phy_page pages;
struct fastrpc_req_mmap req;
+ struct fastrpc_map *map = NULL;
struct device *dev = fl->sctx->dev;
int err;
u32 sc;
+ unsigned long flags;

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

- if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR) {
- dev_err(dev, "flag not supported 0x%x\n", req.flags);
+ if (req.flags == ADSP_MMAP_ADD_PAGES || req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
+ if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->is_unsigned_pd) {
+ dev_err(dev, "secure memory allocation is not supported in unsigned PD\n");
+ return -EINVAL;
+ }
+ if (req.vaddrin && !fl->is_unsigned_pd) {
+ dev_err(dev, "adding user allocated pages is not supported\n");
+ return -EINVAL;
+ }

- 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);

- if (req.vaddrin) {
- dev_err(dev, "adding user allocated pages is not supported\n");
- return -EINVAL;
- }
+ if (err) {
+ dev_err(dev, "failed to allocate buffer\n");
+ return err;
+ }

- 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);
+ req_msg.pgid = fl->tgid;
+ req_msg.flags = req.flags;
+ req_msg.vaddr = req.vaddrin;
+ req_msg.num = sizeof(pages);

- if (err) {
- dev_err(dev, "failed to allocate buffer\n");
- return err;
- }
+ args[0].ptr = (u64) (uintptr_t) &req_msg;
+ args[0].length = sizeof(req_msg);

- req_msg.pgid = fl->tgid;
- req_msg.flags = req.flags;
- req_msg.vaddr = req.vaddrin;
- req_msg.num = sizeof(pages);
+ pages.addr = buf->phys;
+ pages.size = buf->size;

- args[0].ptr = (u64) (uintptr_t) &req_msg;
- args[0].length = sizeof(req_msg);
+ args[1].ptr = (u64) (uintptr_t) &pages;
+ args[1].length = sizeof(pages);

- pages.addr = buf->phys;
- pages.size = buf->size;
+ args[2].ptr = (u64) (uintptr_t) &rsp_msg;
+ args[2].length = sizeof(rsp_msg);

- args[1].ptr = (u64) (uintptr_t) &pages;
- args[1].length = sizeof(pages);
+ sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+ err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
+ &args[0]);
+ if (err) {
+ dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size);
+ goto err_invoke;
+ }

- args[2].ptr = (u64) (uintptr_t) &rsp_msg;
- args[2].length = sizeof(rsp_msg);
+ /* update the buffer to be able to deallocate the memory on the DSP */
+ buf->raddr = (uintptr_t) rsp_msg.vaddr;
+ buf->flag = req.flags;

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
- if (err) {
- dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size);
- goto err_invoke;
- }
+ /* let the client know the address to use */
+ req.vaddrout = rsp_msg.vaddr;

- /* update the buffer to be able to deallocate the memory on the DSP */
- buf->raddr = (uintptr_t) rsp_msg.vaddr;
- buf->flag = req.flags;
+ /* Add memory to static PD pool, protection thru hypervisor */
+ if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
+ err = qcom_scm_assign_mem(buf->phys, (u64)buf->size,
+ &fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount);
+ if (err) {
+ dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
+ buf->phys, buf->size, err);
+ goto err_assign;
+ }
+ }

- /* let the client know the address to use */
- req.vaddrout = rsp_msg.vaddr;
+ if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
+ spin_lock_irqsave(&fl->cctx->lock, flags);
+ list_add_tail(&buf->node, &fl->cctx->rmaps);
+ spin_unlock_irqrestore(&fl->cctx->lock, flags);
+ } else {
+ spin_lock(&fl->lock);
+ list_add_tail(&buf->node, &fl->mmaps);
+ spin_unlock(&fl->lock);
+ }

- /* Add memory to static PD pool, protection thru hypervisor */
- if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
- err = qcom_scm_assign_mem(buf->phys, (u64)buf->size,
- &fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount);
- if (err) {
- dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
- buf->phys, buf->size, err);
+ if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
+ err = -EFAULT;
goto err_assign;
}
- }
+ } else {
+ err = fastrpc_map_create(fl, req.fd, req.size, 0, &map);
+ if (err) {
+ dev_err(dev, "failed to map buffer, fd = %d\n", req.fd);
+ return err;
+ }

- spin_lock(&fl->lock);
- if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
- list_add_tail(&buf->node, &fl->cctx->rmaps);
- else
- list_add_tail(&buf->node, &fl->mmaps);
- spin_unlock(&fl->lock);
+ req_msg.pgid = fl->tgid;
+ req_msg.flags = req.flags;
+ req_msg.vaddr = req.vaddrin;
+ req_msg.num = sizeof(pages);

- if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
- err = -EFAULT;
- goto err_assign;
- }
+ args[0].ptr = (u64) (uintptr_t) &req_msg;
+ args[0].length = sizeof(req_msg);

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

+ args[1].ptr = (u64) (uintptr_t) &pages;
+ args[1].length = sizeof(pages);
+
+ args[2].ptr = (u64) (uintptr_t) &rsp_msg;
+ args[2].length = sizeof(rsp_msg);
+
+ sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+
+ err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
+ &args[0]);
+ if (err) {
+ dev_err(dev, "mmap error (len 0x%08llx)\n", map->size);
+ goto err_invoke;
+ }
+
+ /* update the buffer to be able to deallocate the memory on the DSP */
+ map->raddr = (uintptr_t) rsp_msg.vaddr;
+
+ /* let the client know the address to use */
+ req.vaddrout = rsp_msg.vaddr;
+
+ if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
+ err = -EFAULT;
+ goto err_assign;
+ }
+ }
return 0;

err_assign:
- fastrpc_req_munmap_impl(fl, buf);
+ if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR)
+ fastrpc_map_put(map);
+ else
+ fastrpc_req_munmap_impl(fl, buf);
+
err_invoke:
- fastrpc_buf_free(buf);
+ if (map)
+ fastrpc_map_put(map);
+ if (buf)
+ fastrpc_buf_free(buf);

return err;
}
--
2.17.0


2024-02-02 06:41:56

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 03/16] misc: fastrpc: Add static PD restart support

Static PDs on the audio and sensor domains are expected to support
PD restart. The kernel resource handling for the PDs are expected
to be handled by fastrpc driver. For this, there is a requirement
of PD service locator to get the event notifications for static PD
services. Also when events are received, the driver needs to handle
based on PD states. Added changes to add service locator for audio
and sensor domain static PDs and handle the PD restart sequence.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 216 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 204 insertions(+), 12 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index bdce5469de19..e9b3b3b00aed 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -22,6 +22,7 @@
#include <linux/firmware/qcom/qcom_scm.h>
#include <uapi/misc/fastrpc.h>
#include <linux/of_reserved_mem.h>
+#include <linux/soc/qcom/pdr.h>

#define ADSP_DOMAIN_ID (0)
#define MDSP_DOMAIN_ID (1)
@@ -29,6 +30,7 @@
#define CDSP_DOMAIN_ID (3)
#define FASTRPC_DEV_MAX 4 /* adsp, mdsp, slpi, cdsp*/
#define FASTRPC_MAX_SESSIONS 14
+#define FASTRPC_MAX_SPD 4
#define FASTRPC_MAX_VMIDS 16
#define FASTRPC_ALIGN 128
#define FASTRPC_MAX_FDLIST 16
@@ -105,6 +107,18 @@

#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)

+#define AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME "audio_pdr_adsp"
+#define AUDIO_PDR_ADSP_SERVICE_NAME "avs/audio"
+#define ADSP_AUDIOPD_NAME "msm/adsp/audio_pd"
+
+#define SENSORS_PDR_ADSP_SERVICE_LOCATION_CLIENT_NAME "sensors_pdr_adsp"
+#define SENSORS_PDR_ADSP_SERVICE_NAME "tms/servreg"
+#define ADSP_SENSORPD_NAME "msm/adsp/sensor_pd"
+
+#define SENSORS_PDR_SLPI_SERVICE_LOCATION_CLIENT_NAME "sensors_pdr_slpi"
+#define SENSORS_PDR_SLPI_SERVICE_NAME SENSORS_PDR_ADSP_SERVICE_NAME
+#define SLPI_SENSORPD_NAME "msm/slpi/sensor_pd"
+
static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
"sdsp", "cdsp"};
struct fastrpc_phy_page {
@@ -260,6 +274,16 @@ struct fastrpc_session_ctx {
bool valid;
};

+struct fastrpc_static_pd {
+ char *servloc_name;
+ char *spdname;
+ void *pdrhandle;
+ u64 pdrcount;
+ u64 prevpdrcount;
+ atomic_t ispdup;
+ struct fastrpc_channel_ctx *cctx;
+};
+
struct fastrpc_channel_ctx {
int domain_id;
int sesscount;
@@ -268,6 +292,7 @@ struct fastrpc_channel_ctx {
struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS];
struct rpmsg_device *rpdev;
struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
+ struct fastrpc_static_pd spd[FASTRPC_MAX_SPD];
spinlock_t lock;
struct idr ctx_idr;
struct list_head users;
@@ -304,6 +329,7 @@ struct fastrpc_user {
int pd;
bool is_secure_dev;
bool is_unsigned_pd;
+ char *servloc_name;
/* Lock for lists */
spinlock_t lock;
/* lock for allocations */
@@ -1256,6 +1282,41 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_channel_ctx *cctx)
return 0;
}

+static int fastrpc_mmap_remove_pdr(struct fastrpc_user *fl)
+{
+ int i, err = 0, session = -1;
+
+ if (!fl)
+ return -EBADF;
+
+ for (i = 0; i < FASTRPC_MAX_SPD ; i++) {
+ if (!fl->cctx->spd[i].servloc_name)
+ continue;
+ if (!strcmp(fl->servloc_name, fl->cctx->spd[i].servloc_name)) {
+ session = i;
+ break;
+ }
+ }
+
+ if (i >= FASTRPC_MAX_SPD)
+ return -EUSERS;
+
+ if (atomic_read(&fl->cctx->spd[session].ispdup) == 0)
+ return -ENOTCONN;
+
+ if (fl->cctx->spd[session].pdrcount !=
+ fl->cctx->spd[session].prevpdrcount) {
+ err = fastrpc_mmap_remove_ssr(fl->cctx);
+ if (err)
+ dev_info(&fl->cctx->rpdev->dev,
+ "failed to unmap remote heap (err %d)\n", err);
+ fl->cctx->spd[session].prevpdrcount =
+ fl->cctx->spd[session].pdrcount;
+ }
+
+ return err;
+}
+
static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
char __user *argp)
{
@@ -1299,6 +1360,18 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
goto err_name;
}

+ fl->servloc_name = AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME;
+
+ if (!strcmp(name, "audiopd")) {
+ /*
+ * Remove any previous mappings in case process is trying
+ * to reconnect after a PD restart on remote subsystem.
+ */
+ err = fastrpc_mmap_remove_pdr(fl);
+ if (err)
+ goto err_name;
+ }
+
if (!fl->cctx->staticpd_status) {
err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &buf);
if (err)
@@ -1688,6 +1761,12 @@ static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
args[0].fd = -1;
sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
fl->pd = pd;
+ if (pd == SENSORS_PD) {
+ if (fl->cctx->domain_id == ADSP_DOMAIN_ID)
+ fl->servloc_name = SENSORS_PDR_ADSP_SERVICE_LOCATION_CLIENT_NAME;
+ else if (fl->cctx->domain_id == SDSP_DOMAIN_ID)
+ fl->servloc_name = SENSORS_PDR_SLPI_SERVICE_LOCATION_CLIENT_NAME;
+ }

return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
sc, &args[0]);
@@ -2281,6 +2360,72 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
return err;
}

+static void fastrpc_notify_users(struct fastrpc_user *user)
+{
+ struct fastrpc_invoke_ctx *ctx;
+
+ spin_lock(&user->lock);
+ list_for_each_entry(ctx, &user->pending, node) {
+ ctx->retval = -EPIPE;
+ complete(&ctx->work);
+ }
+ spin_unlock(&user->lock);
+}
+
+static void fastrpc_notify_pdr_drivers(struct fastrpc_channel_ctx *cctx,
+ char *servloc_name)
+{
+ struct fastrpc_user *fl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cctx->lock, flags);
+ list_for_each_entry(fl, &cctx->users, user) {
+ if (fl->servloc_name && !strcmp(servloc_name, fl->servloc_name))
+ fastrpc_notify_users(fl);
+ }
+ spin_unlock_irqrestore(&cctx->lock, flags);
+}
+
+static void fastrpc_pdr_cb(int state, char *service_path, void *priv)
+{
+ struct fastrpc_static_pd *spd = (struct fastrpc_static_pd *)priv;
+ struct fastrpc_channel_ctx *cctx;
+ unsigned long flags;
+
+ if (!spd)
+ return;
+
+ cctx = spd->cctx;
+ switch (state) {
+ case SERVREG_SERVICE_STATE_DOWN:
+ dev_info(&cctx->rpdev->dev,
+ "%s: %s (%s) is down for PDR on %s\n",
+ __func__, spd->spdname,
+ spd->servloc_name,
+ domains[cctx->domain_id]);
+ spin_lock_irqsave(&cctx->lock, flags);
+ spd->pdrcount++;
+ atomic_set(&spd->ispdup, 0);
+ spin_unlock_irqrestore(&cctx->lock, flags);
+ if (!strcmp(spd->servloc_name,
+ AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME))
+ cctx->staticpd_status = false;
+
+ fastrpc_notify_pdr_drivers(cctx, spd->servloc_name);
+ break;
+ case SERVREG_SERVICE_STATE_UP:
+ dev_info(&cctx->rpdev->dev,
+ "%s: %s (%s) is up for PDR on %s\n",
+ __func__, spd->spdname,
+ spd->servloc_name,
+ domains[cctx->domain_id]);
+ atomic_set(&spd->ispdup, 1);
+ break;
+ default:
+ break;
+ }
+}
+
static const struct file_operations fastrpc_fops = {
.open = fastrpc_device_open,
.release = fastrpc_device_release,
@@ -2402,6 +2547,39 @@ static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ct
return err;
}

+static int fastrpc_setup_service_locator(struct fastrpc_channel_ctx *cctx, char *client_name,
+ char *service_name, char *service_path, int domain, int spd_session)
+{
+ int err = 0;
+ struct pdr_handle *handle = NULL;
+ struct pdr_service *service = NULL;
+
+ /* Register the service locator's callback function */
+ handle = pdr_handle_alloc(fastrpc_pdr_cb, &cctx->spd[spd_session]);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto bail;
+ }
+ cctx->spd[spd_session].pdrhandle = handle;
+ cctx->spd[spd_session].servloc_name = client_name;
+ cctx->spd[spd_session].spdname = service_path;
+ cctx->spd[spd_session].cctx = cctx;
+ service = pdr_add_lookup(handle, service_name, service_path);
+ if (IS_ERR(service)) {
+ err = PTR_ERR(service);
+ goto bail;
+ }
+ pr_info("fastrpc: %s: pdr_add_lookup enabled for %s (%s, %s)\n",
+ __func__, service_name, client_name, service_path);
+
+bail:
+ if (err) {
+ pr_warn("fastrpc: %s: failed for %s (%s, %s)with err %d\n",
+ __func__, service_name, client_name, service_path, err);
+ }
+ return err;
+}
+
static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
{
struct device *rdev = &rpdev->dev;
@@ -2481,6 +2659,25 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
goto fdev_error;
}

+ if (domain_id == ADSP_DOMAIN_ID) {
+ err = fastrpc_setup_service_locator(data, AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME,
+ AUDIO_PDR_ADSP_SERVICE_NAME, ADSP_AUDIOPD_NAME, domain_id, 0);
+ if (err)
+ goto populate_error;
+
+ err = fastrpc_setup_service_locator(data,
+ SENSORS_PDR_ADSP_SERVICE_LOCATION_CLIENT_NAME,
+ SENSORS_PDR_ADSP_SERVICE_NAME, ADSP_SENSORPD_NAME, domain_id, 1);
+ if (err)
+ goto populate_error;
+ } else if (domain_id == SDSP_DOMAIN_ID) {
+ err = fastrpc_setup_service_locator(data,
+ SENSORS_PDR_SLPI_SERVICE_LOCATION_CLIENT_NAME,
+ SENSORS_PDR_SLPI_SERVICE_NAME, SLPI_SENSORPD_NAME, domain_id, 0);
+ if (err)
+ goto populate_error;
+ }
+
kref_init(&data->refcount);

dev_set_drvdata(&rpdev->dev, data);
@@ -2510,18 +2707,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
return err;
}

-static void fastrpc_notify_users(struct fastrpc_user *user)
-{
- struct fastrpc_invoke_ctx *ctx;
-
- spin_lock(&user->lock);
- list_for_each_entry(ctx, &user->pending, 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);
@@ -2537,6 +2722,13 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
fastrpc_notify_users(user);
spin_unlock_irqrestore(&cctx->lock, flags);

+ if (cctx->domain_id == ADSP_DOMAIN_ID) {
+ pdr_handle_release(cctx->spd[0].pdrhandle);
+ pdr_handle_release(cctx->spd[1].pdrhandle);
+ } else if (cctx->domain_id == SDSP_DOMAIN_ID) {
+ pdr_handle_release(cctx->spd[0].pdrhandle);
+ }
+
if (cctx->fdevice)
misc_deregister(&cctx->fdevice->miscdev);

--
2.17.0


2024-02-02 06:42:12

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 01/16] misc: fastrpc: Redesign remote heap management

Current remote heap design comes with problems where all types
of buffers are getting added to interrupted list and also user
unmap request is not handled properly. Add changes to maintain
list in a way that it can be properly managed and used at different
audio PD specific scenarios.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 180 +++++++++++++++++++++++++++++++----------
1 file changed, 139 insertions(+), 41 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 1c6c62a7f7f5..f3ef5e194f11 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -196,6 +196,7 @@ struct fastrpc_buf {
struct dma_buf *dmabuf;
struct device *dev;
void *virt;
+ u32 flag;
u64 phys;
u64 size;
/* Lock for dma buf attachments */
@@ -273,11 +274,11 @@ struct fastrpc_channel_ctx {
struct kref refcount;
/* Flag if dsp attributes are cached */
bool valid_attributes;
+ bool staticpd_status;
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;
+ struct list_head rmaps;
bool secure;
bool unsigned_support;
u64 dma_mask;
@@ -326,7 +327,7 @@ static void fastrpc_free_map(struct kref *ref)
err = qcom_scm_assign_mem(map->phys, map->size,
&src_perms, &perm, 1);
if (err) {
- dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
+ dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
map->phys, map->size, err);
return;
}
@@ -817,7 +818,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
map->attr = attr;
err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2);
if (err) {
- dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
+ dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d\n",
map->phys, map->size, err);
goto map_err;
}
@@ -1139,7 +1140,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;

@@ -1200,13 +1200,6 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
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);

@@ -1231,14 +1224,48 @@ static bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_reques
return false;
}

+static int fastrpc_mmap_remove_ssr(struct fastrpc_channel_ctx *cctx)
+{
+ struct fastrpc_buf *buf, *b;
+ int err = 0;
+
+ list_for_each_entry_safe(buf, b, &cctx->rmaps, node) {
+ if (cctx->vmcount) {
+ u64 src_perms = 0;
+ struct qcom_scm_vmperm dst_perms;
+ u32 i;
+
+ 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(buf->phys, (u64)buf->size,
+ &src_perms, &dst_perms, 1);
+ if (err) {
+ pr_err("%s: Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
+ __func__, buf->phys, buf->size, err);
+ return err;
+ }
+ }
+ list_del(&buf->node);
+ fastrpc_buf_free(buf);
+ }
+
+ return 0;
+}
+
static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
char __user *argp)
{
struct fastrpc_init_create_static init;
struct fastrpc_invoke_args *args;
struct fastrpc_phy_page pages[1];
+ struct fastrpc_buf *buf = NULL;
+ u64 phys = 0, size = 0;
char *name;
int err;
+ bool scm_done = false;
struct {
int pgid;
u32 namelen;
@@ -1271,24 +1298,29 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
goto err_name;
}

- if (!fl->cctx->remote_heap) {
- err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
- &fl->cctx->remote_heap);
+ if (!fl->cctx->staticpd_status) {
+ err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &buf);
if (err)
goto err_name;

+ phys = buf->phys;
+ size = buf->size;
/* Map if we have any heap VMIDs associated with this ADSP Static Process. */
if (fl->cctx->vmcount) {
- err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
- (u64)fl->cctx->remote_heap->size,
+ err = qcom_scm_assign_mem(phys, (u64)size,
&fl->cctx->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",
- fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
+ dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d\n",
+ phys, size, err);
goto err_map;
}
+ scm_done = true;
}
+ fl->cctx->staticpd_status = true;
+ spin_lock(&fl->lock);
+ list_add_tail(&buf->node, &fl->cctx->rmaps);
+ spin_unlock(&fl->lock);
}

inbuf.pgid = fl->tgid;
@@ -1304,8 +1336,8 @@ 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;
+ pages[0].addr = phys;
+ pages[0].size = size;

args[2].ptr = (u64)(uintptr_t) pages;
args[2].length = sizeof(*pages);
@@ -1322,7 +1354,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,

return 0;
err_invoke:
- if (fl->cctx->vmcount) {
+ if (fl->cctx->vmcount && scm_done) {
u64 src_perms = 0;
struct qcom_scm_vmperm dst_perms;
u32 i;
@@ -1332,15 +1364,18 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,

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,
+ err = qcom_scm_assign_mem(phys, (u64)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",
- fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
+ dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
+ phys, size, err);
}
err_map:
- fastrpc_buf_free(fl->cctx->remote_heap);
+ fl->cctx->staticpd_status = false;
+ spin_lock(&fl->lock);
+ list_del(&buf->node);
+ spin_unlock(&fl->lock);
+ fastrpc_buf_free(buf);
err_name:
kfree(name);
err:
@@ -1807,6 +1842,26 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
&args[0]);
if (!err) {
+ if (buf->flag == ADSP_MMAP_REMOTE_HEAP_ADDR) {
+ if (fl->cctx->vmcount) {
+ 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(buf->phys, (u64)buf->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",
+ buf->phys, buf->size, err);
+ return err;
+ }
+ }
+ }
dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr);
spin_lock(&fl->lock);
list_del(&buf->node);
@@ -1823,7 +1878,12 @@ 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 fastrpc_munmap_req_msg req_msg;
+ struct fastrpc_map *map = NULL, *iterm, *m;
struct device *dev = fl->sctx->dev;
+ struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
+ int err = 0;
+ u32 sc;

if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;
@@ -1837,13 +1897,52 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
}
spin_unlock(&fl->lock);

- if (!buf) {
- dev_err(dev, "mmap\t\tpt 0x%09llx [len 0x%08llx] not in list\n",
- req.vaddrout, req.size);
+ if (buf) {
+ err = fastrpc_req_munmap_impl(fl, buf);
+ return err;
+ }
+
+ spin_lock(&fl->lock);
+ list_for_each_entry_safe(iter, b, &fl->cctx->rmaps, node) {
+ if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
+ buf = iter;
+ break;
+ }
+ }
+ spin_unlock(&fl->lock);
+ if (buf) {
+ err = fastrpc_req_munmap_impl(fl, buf);
+ return err;
+ }
+ spin_lock(&fl->lock);
+ list_for_each_entry_safe(iterm, m, &fl->maps, node) {
+ if (iterm->raddr == req.vaddrout) {
+ map = iterm;
+ break;
+ }
+ }
+ spin_unlock(&fl->lock);
+ if (!map) {
+ dev_err(dev, "map not in list\n");
return -EINVAL;
}

- return fastrpc_req_munmap_impl(fl, buf);
+ req_msg.pgid = fl->tgid;
+ req_msg.size = map->size;
+ req_msg.vaddr = map->raddr;
+
+ args[0].ptr = (u64) (uintptr_t) &req_msg;
+ args[0].length = sizeof(req_msg);
+
+ sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
+ err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
+ &args[0]);
+ if (err)
+ dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n", map->fd, map->raddr);
+ else
+ fastrpc_map_put(map);
+
+ return err;
}

static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
@@ -1909,6 +2008,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)

/* update the buffer to be able to deallocate the memory on the DSP */
buf->raddr = (uintptr_t) rsp_msg.vaddr;
+ buf->flag = req.flags;

/* let the client know the address to use */
req.vaddrout = rsp_msg.vaddr;
@@ -1918,14 +2018,17 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
err = qcom_scm_assign_mem(buf->phys, (u64)buf->size,
&fl->cctx->perms, fl->cctx->vmperms, fl->cctx->vmcount);
if (err) {
- dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
+ dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d\n",
buf->phys, buf->size, err);
goto err_assign;
}
}

spin_lock(&fl->lock);
- list_add_tail(&buf->node, &fl->mmaps);
+ if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
+ list_add_tail(&buf->node, &fl->cctx->rmaps);
+ else
+ list_add_tail(&buf->node, &fl->mmaps);
spin_unlock(&fl->lock);

if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
@@ -2332,7 +2435,7 @@ 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);
+ INIT_LIST_HEAD(&data->rmaps);
spin_lock_init(&data->lock);
idr_init(&data->ctx_idr);
data->domain_id = domain_id;
@@ -2370,13 +2473,14 @@ static void fastrpc_notify_users(struct fastrpc_user *user)
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;

/* No invocations past this point */
spin_lock_irqsave(&cctx->lock, flags);
cctx->rpdev = NULL;
+ cctx->staticpd_status = false;
+ fastrpc_mmap_remove_ssr(cctx);
list_for_each_entry(user, &cctx->users, user)
fastrpc_notify_users(user);
spin_unlock_irqrestore(&cctx->lock, flags);
@@ -2387,12 +2491,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)
- fastrpc_buf_free(cctx->remote_heap);
-
of_platform_depopulate(&rpdev->dev);

fastrpc_channel_ctx_put(cctx);
--
2.17.0


2024-02-02 06:42:48

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 04/16] misc: fastrpc: Add fastrpc multimode invoke request support

Multimode invocation request is intended to support multiple
different type of requests. This will include enhanced invoke
request to support CRC check and performance counter enablement.
This will also support few driver level user controllable
mechanisms like usage of shared context banks, wakelock support,
etc. This IOCTL is also added with the aim to support few
new fastrpc features like DSP PD notification framework,
DSP Signalling mechanism etc.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 176 ++++++++++++++++++++++++++----------
include/uapi/misc/fastrpc.h | 26 ++++++
2 files changed, 154 insertions(+), 48 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index e9b3b3b00aed..a7e959beabd4 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -601,7 +601,7 @@ static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx)

static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
struct fastrpc_user *user, u32 kernel, u32 sc,
- struct fastrpc_invoke_args *args)
+ struct fastrpc_enhanced_invoke *invoke)
{
struct fastrpc_channel_ctx *cctx = user->cctx;
struct fastrpc_invoke_ctx *ctx = NULL;
@@ -632,7 +632,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
kfree(ctx);
return ERR_PTR(-ENOMEM);
}
- ctx->args = args;
+ ctx->args = (struct fastrpc_invoke_args *)invoke->inv.args;
fastrpc_get_buff_overlaps(ctx);
}

@@ -1163,11 +1163,11 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
}

static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
- u32 handle, u32 sc,
- struct fastrpc_invoke_args *args)
+ struct fastrpc_enhanced_invoke *invoke)
{
struct fastrpc_invoke_ctx *ctx = NULL;
-
+ struct fastrpc_invoke *inv = &invoke->inv;
+ u32 handle, sc;
int err = 0;

if (!fl->sctx)
@@ -1176,12 +1176,14 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
if (!fl->cctx->rpdev)
return -EPIPE;

+ handle = inv->handle;
+ sc = inv->sc;
if (handle == FASTRPC_INIT_HANDLE && !kernel) {
dev_warn_ratelimited(fl->sctx->dev, "user app trying to send a kernel RPC message (%d)\n", handle);
return -EPERM;
}

- ctx = fastrpc_context_alloc(fl, kernel, sc, args);
+ ctx = fastrpc_context_alloc(fl, kernel, sc, invoke);
if (IS_ERR(ctx))
return PTR_ERR(ctx);

@@ -1322,6 +1324,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
{
struct fastrpc_init_create_static init;
struct fastrpc_invoke_args *args;
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_phy_page pages[1];
struct fastrpc_buf *buf = NULL;
u64 phys = 0, size = 0;
@@ -1333,7 +1336,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
u32 namelen;
u32 pageslen;
} inbuf;
- u32 sc;

args = kcalloc(FASTRPC_CREATE_STATIC_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
if (!args)
@@ -1417,10 +1419,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
args[2].length = sizeof(*pages);
args[2].fd = -1;

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
+ ioctl.inv.args = (u64)args;

- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
- sc, args);
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err)
goto err_invoke;

@@ -1463,6 +1466,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
{
struct fastrpc_init_create init;
struct fastrpc_invoke_args *args;
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_phy_page pages[1];
struct fastrpc_map *map = NULL;
struct fastrpc_buf *imem = NULL;
@@ -1476,7 +1480,6 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
u32 attrs;
u32 siglen;
} inbuf;
- u32 sc;

args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
if (!args)
@@ -1549,12 +1552,13 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
args[5].length = sizeof(inbuf.siglen);
args[5].fd = -1;

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
if (init.attrs)
- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
+ ioctl.inv.args = (u64)args;

- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
- sc, args);
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err)
goto err_invoke;

@@ -1607,17 +1611,19 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
{
struct fastrpc_invoke_args args[1];
+ struct fastrpc_enhanced_invoke ioctl;
int tgid = 0;
- u32 sc;

tgid = fl->tgid;
args[0].ptr = (u64)(uintptr_t) &tgid;
args[0].length = sizeof(tgid);
args[0].fd = -1;
- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);

- return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
- sc, &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
+ ioctl.inv.args = (u64)args;
+
+ return fastrpc_internal_invoke(fl, true, &ioctl);
}

static int fastrpc_device_release(struct inode *inode, struct file *file)
@@ -1753,13 +1759,12 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
{
struct fastrpc_invoke_args args[1];
+ struct fastrpc_enhanced_invoke ioctl;
int tgid = fl->tgid;
- u32 sc;

args[0].ptr = (u64)(uintptr_t) &tgid;
args[0].length = sizeof(tgid);
args[0].fd = -1;
- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
fl->pd = pd;
if (pd == SENSORS_PD) {
if (fl->cctx->domain_id == ADSP_DOMAIN_ID)
@@ -1768,13 +1773,17 @@ static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
fl->servloc_name = SENSORS_PDR_SLPI_SERVICE_LOCATION_CLIENT_NAME;
}

- return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
- sc, &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
+ ioctl.inv.args = (u64)args;
+
+ return fastrpc_internal_invoke(fl, true, &ioctl);
}

static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_invoke_args *args = NULL;
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_invoke inv;
u32 nscalars;
int err;
@@ -1796,16 +1805,70 @@ static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
}
}

- err = fastrpc_internal_invoke(fl, false, inv.handle, inv.sc, args);
+ ioctl.inv = inv;
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, false, &ioctl);
kfree(args);

return err;
}

+static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
+{
+ struct fastrpc_enhanced_invoke einv;
+ struct fastrpc_invoke_args *args = NULL;
+ struct fastrpc_ioctl_multimode_invoke invoke;
+ u32 nscalars;
+ int err, i;
+
+ if (copy_from_user(&invoke, argp, sizeof(invoke)))
+ return -EFAULT;
+
+ for (i = 0; i < 8; i++) {
+ if (invoke.reserved[i] != 0)
+ return -EINVAL;
+ }
+ if (invoke.rsvd != 0)
+ return -EINVAL;
+
+ switch (invoke.req) {
+ case FASTRPC_INVOKE:
+ /* nscalars is truncated here to max supported value */
+ if (copy_from_user(&einv, (void __user *)(uintptr_t)invoke.invparam,
+ invoke.size))
+ return -EFAULT;
+ for (i = 0; i < 8; i++) {
+ if (einv.reserved[i] != 0)
+ return -EINVAL;
+ }
+ nscalars = REMOTE_SCALARS_LENGTH(einv.inv.sc);
+ if (nscalars) {
+ args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL);
+ if (!args)
+ return -ENOMEM;
+ if (copy_from_user(args, (void __user *)(uintptr_t)einv.inv.args,
+ nscalars * sizeof(*args))) {
+ kfree(args);
+ return -EFAULT;
+ }
+ }
+ einv.inv.args = (u64)args;
+ err = fastrpc_internal_invoke(fl, false, &einv);
+ kfree(args);
+ break;
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ return err;
+}
+
static int fastrpc_get_info_from_dsp(struct fastrpc_user *fl, uint32_t *dsp_attr_buf,
uint32_t dsp_attr_buf_len)
{
struct fastrpc_invoke_args args[2] = { 0 };
+ struct fastrpc_enhanced_invoke ioctl;

/* Capability filled in userspace */
dsp_attr_buf[0] = 0;
@@ -1818,8 +1881,11 @@ static int fastrpc_get_info_from_dsp(struct fastrpc_user *fl, uint32_t *dsp_attr
args[1].fd = -1;
fl->pd = USER_PD;

- return fastrpc_internal_invoke(fl, true, FASTRPC_DSP_UTILITIES_HANDLE,
- FASTRPC_SCALARS(0, 1, 1), args);
+ ioctl.inv.handle = FASTRPC_DSP_UTILITIES_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(0, 1, 1);
+ ioctl.inv.args = (u64)args;
+
+ return fastrpc_internal_invoke(fl, true, &ioctl);
}

static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap,
@@ -1906,10 +1972,10 @@ static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp)
static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *buf)
{
struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_munmap_req_msg req_msg;
struct device *dev = fl->sctx->dev;
int err;
- u32 sc;

req_msg.pgid = fl->tgid;
req_msg.size = buf->size;
@@ -1918,9 +1984,11 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
args[0].ptr = (u64) (uintptr_t) &req_msg;
args[0].length = sizeof(req_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (!err) {
if (buf->flag == ADSP_MMAP_REMOTE_HEAP_ADDR) {
if (fl->cctx->vmcount) {
@@ -1962,8 +2030,8 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_map *map = NULL, *iterm, *m;
struct device *dev = fl->sctx->dev;
struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
+ struct fastrpc_enhanced_invoke ioctl;
int err = 0;
- u32 sc;

if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;
@@ -2014,9 +2082,10 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
args[0].ptr = (u64) (uintptr_t) &req_msg;
args[0].length = sizeof(req_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
+ ioctl.inv.args = (u64)args;
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err)
dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n", map->fd, map->raddr);
else
@@ -2028,6 +2097,7 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_invoke_args args[3] = { [0 ... 2] = { 0 } };
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_buf *buf = NULL;
struct fastrpc_mmap_req_msg req_msg;
struct fastrpc_mmap_rsp_msg rsp_msg;
@@ -2036,7 +2106,6 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_map *map = NULL;
struct device *dev = fl->sctx->dev;
int err;
- u32 sc;
unsigned long flags;

if (copy_from_user(&req, argp, sizeof(req)))
@@ -2079,9 +2148,11 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
args[2].ptr = (u64) (uintptr_t) &rsp_msg;
args[2].length = sizeof(rsp_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err) {
dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size);
goto err_invoke;
@@ -2143,10 +2214,11 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
args[2].ptr = (u64) (uintptr_t) &rsp_msg;
args[2].length = sizeof(rsp_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1);
+ ioctl.inv.args = (u64)args;

- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err) {
dev_err(dev, "mmap error (len 0x%08llx)\n", map->size);
goto err_invoke;
@@ -2183,10 +2255,10 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
static int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_mem_unmap *req)
{
struct fastrpc_invoke_args args[1] = { [0] = { 0 } };
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_map *map = NULL, *iter, *m;
struct fastrpc_mem_unmap_req_msg req_msg = { 0 };
int err = 0;
- u32 sc;
struct device *dev = fl->sctx->dev;

spin_lock(&fl->lock);
@@ -2212,9 +2284,11 @@ static int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_me
args[0].ptr = (u64) (uintptr_t) &req_msg;
args[0].length = sizeof(req_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc,
- &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0);
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err) {
dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n", map->fd, map->raddr);
return err;
@@ -2237,6 +2311,7 @@ static int fastrpc_req_mem_unmap(struct fastrpc_user *fl, char __user *argp)
static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_invoke_args args[4] = { [0 ... 3] = { 0 } };
+ struct fastrpc_enhanced_invoke ioctl;
struct fastrpc_mem_map_req_msg req_msg = { 0 };
struct fastrpc_mmap_rsp_msg rsp_msg = { 0 };
struct fastrpc_mem_unmap req_unmap = { 0 };
@@ -2245,7 +2320,6 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
struct device *dev = fl->sctx->dev;
struct fastrpc_map *map = NULL;
int err;
- u32 sc;

if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;
@@ -2281,8 +2355,11 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
args[3].ptr = (u64) (uintptr_t) &rsp_msg;
args[3].length = sizeof(rsp_msg);

- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_MAP, 3, 1);
- err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, &args[0]);
+ ioctl.inv.handle = FASTRPC_INIT_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_MAP, 3, 1);
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
if (err) {
dev_err(dev, "mem mmap error, fd %d, vaddr %llx, size %lld\n",
req.fd, req.vaddrin, map->size);
@@ -2322,6 +2399,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
case FASTRPC_IOCTL_INVOKE:
err = fastrpc_invoke(fl, argp);
break;
+ case FASTRPC_IOCTL_MULTIMODE_INVOKE:
+ err = fastrpc_multimode_invoke(fl, argp);
+ break;
case FASTRPC_IOCTL_INIT_ATTACH:
err = fastrpc_init_attach(fl, ROOT_PD);
break;
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index f33d914d8f46..45c15be1de58 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -16,6 +16,7 @@
#define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_init_create_static)
#define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map)
#define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap)
+#define FASTRPC_IOCTL_MULTIMODE_INVOKE _IOWR('R', 12, struct fastrpc_ioctl_multimode_invoke)
#define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability)

/**
@@ -80,6 +81,31 @@ struct fastrpc_invoke {
__u64 args;
};

+struct fastrpc_enhanced_invoke {
+ struct fastrpc_invoke inv;
+ __u64 crc;
+ __u64 perf_kernel;
+ __u64 perf_dsp;
+ __u32 reserved[8]; /* keeping reserved bits for new requirements */
+};
+
+struct fastrpc_ioctl_multimode_invoke {
+ __u32 req;
+ __u32 rsvd; /* padding field */
+ __u64 invparam;
+ __u64 size;
+ __u32 reserved[8]; /* keeping reserved bits for new requirements */
+};
+
+enum fastrpc_multimode_invoke_type {
+ FASTRPC_INVOKE = 1,
+ FASTRPC_INVOKE_ENHANCED = 2,
+ FASTRPC_INVOKE_CONTROL = 3,
+ FASTRPC_INVOKE_DSPSIGNAL = 4,
+ FASTRPC_INVOKE_NOTIF = 5,
+ FASTRPC_INVOKE_MULTISESSION = 6,
+};
+
struct fastrpc_init_create {
__u32 filelen; /* elf file length */
__s32 filefd; /* fd for the file */
--
2.17.0


2024-02-02 06:42:49

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 06/16] misc: fastrpc: Capture kernel and DSP performance counters

Add support to capture kernel performance counters for different
kernel level operations. These counters collects the information
for remote call and copies the information to a buffer shared
by user.

Collection of DSP performance counters is also added as part of
this change. DSP updates the performance information in the
metadata which is then copied to a buffer passed by the users.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 136 ++++++++++++++++++++++++++++++++++--
include/uapi/misc/fastrpc.h | 14 ++++
2 files changed, 143 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index a1b910459a90..33687d7f9a28 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -19,6 +19,7 @@
#include <linux/rpmsg.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <uapi/misc/fastrpc.h>
#include <linux/of_reserved_mem.h>
@@ -35,6 +36,8 @@
#define FASTRPC_ALIGN 128
#define FASTRPC_MAX_FDLIST 16
#define FASTRPC_MAX_CRCLIST 64
+#define FASTRPC_KERNEL_PERF_LIST (PERF_KEY_MAX)
+#define FASTRPC_DSP_PERF_LIST 12
#define FASTRPC_PHYS(p) ((p) & 0xffffffff)
#define FASTRPC_CTX_MAX (256)
#define FASTRPC_INIT_HANDLE 1
@@ -119,6 +122,27 @@
#define SENSORS_PDR_SLPI_SERVICE_NAME SENSORS_PDR_ADSP_SERVICE_NAME
#define SLPI_SENSORPD_NAME "msm/slpi/sensor_pd"

+#define PERF_END ((void)0)
+
+#define PERF(enb, cnt, ff) \
+ {\
+ struct timespec64 startT = {0};\
+ uint64_t *counter = cnt;\
+ if (enb && counter) {\
+ ktime_get_real_ts64(&startT);\
+ } \
+ ff ;\
+ if (enb && counter) {\
+ *counter += getnstimediff(&startT);\
+ } \
+ }
+
+#define GET_COUNTER(perf_ptr, offset) \
+ (perf_ptr != NULL ?\
+ (((offset >= 0) && (offset < PERF_KEY_MAX)) ?\
+ (uint64_t *)(perf_ptr + offset)\
+ : (uint64_t *)NULL) : (uint64_t *)NULL)
+
static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
"sdsp", "cdsp"};
struct fastrpc_phy_page {
@@ -243,6 +267,19 @@ struct fastrpc_map {
struct kref refcount;
};

+struct fastrpc_perf {
+ u64 count;
+ u64 flush;
+ u64 map;
+ u64 copy;
+ u64 link;
+ u64 getargs;
+ u64 putargs;
+ u64 invargs;
+ u64 invoke;
+ u64 tid;
+};
+
struct fastrpc_invoke_ctx {
int nscalars;
int nbufs;
@@ -251,6 +288,8 @@ struct fastrpc_invoke_ctx {
int tgid;
u32 sc;
u32 *crc;
+ u64 *perf_kernel;
+ u64 *perf_dsp;
u64 ctxid;
u64 msg_sz;
struct kref refcount;
@@ -265,6 +304,7 @@ struct fastrpc_invoke_ctx {
struct fastrpc_invoke_args *args;
struct fastrpc_buf_overlap *olaps;
struct fastrpc_channel_ctx *cctx;
+ struct fastrpc_perf *perf;
};

struct fastrpc_session_ctx {
@@ -325,6 +365,7 @@ struct fastrpc_user {
struct fastrpc_session_ctx *sctx;
struct fastrpc_buf *init_mem;

+ u32 profile;
int tgid;
int pd;
bool is_secure_dev;
@@ -336,6 +377,17 @@ struct fastrpc_user {
struct mutex mutex;
};

+static inline int64_t getnstimediff(struct timespec64 *start)
+{
+ int64_t ns;
+ struct timespec64 ts, b;
+
+ ktime_get_real_ts64(&ts);
+ b = timespec64_sub(ts, *start);
+ ns = timespec64_to_ns(&b);
+ return ns;
+}
+
static void fastrpc_free_map(struct kref *ref)
{
struct fastrpc_map *map;
@@ -521,6 +573,9 @@ static void fastrpc_context_free(struct kref *ref)
if (ctx->buf)
fastrpc_buf_free(ctx->buf);

+ if (ctx->fl->profile)
+ kfree(ctx->perf);
+
spin_lock_irqsave(&cctx->lock, flags);
idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
spin_unlock_irqrestore(&cctx->lock, flags);
@@ -640,6 +695,14 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
fastrpc_channel_ctx_get(cctx);

ctx->crc = (u32 *)(uintptr_t)invoke->crc;
+ ctx->perf_dsp = (u64 *)(uintptr_t)invoke->perf_dsp;
+ ctx->perf_kernel = (u64 *)(uintptr_t)invoke->perf_kernel;
+ if (ctx->fl->profile) {
+ ctx->perf = kzalloc(sizeof(*(ctx->perf)), GFP_KERNEL);
+ if (!ctx->perf)
+ return ERR_PTR(-ENOMEM);
+ ctx->perf->tid = ctx->fl->tgid;
+ }
ctx->sc = sc;
ctx->retval = -1;
ctx->pid = current->pid;
@@ -903,7 +966,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
sizeof(struct fastrpc_invoke_buf) +
sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
sizeof(u64) * FASTRPC_MAX_FDLIST +
- sizeof(u32) * FASTRPC_MAX_CRCLIST;
+ sizeof(u32) * FASTRPC_MAX_CRCLIST +
+ sizeof(u32) + sizeof(u64) * FASTRPC_DSP_PERF_LIST;

return size;
}
@@ -970,16 +1034,22 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
int inbufs, i, oix, err = 0;
u64 len, rlen, pkt_size;
u64 pg_start, pg_end;
+ u64 *perf_counter = NULL;
uintptr_t args;
int metalen;

+ if (ctx->fl->profile)
+ perf_counter = (u64 *)ctx->perf + PERF_COUNT;
+
inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
metalen = fastrpc_get_meta_size(ctx);
pkt_size = fastrpc_get_payload_size(ctx, metalen);

+ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP),
err = fastrpc_create_maps(ctx);
if (err)
return err;
+ PERF_END);

ctx->msg_sz = pkt_size;

@@ -1012,6 +1082,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
if (ctx->maps[i]) {
struct vm_area_struct *vma = NULL;

+ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP),
rpra[i].buf.pv = (u64) ctx->args[i].ptr;
pages[i].addr = ctx->maps[i]->phys;

@@ -1026,9 +1097,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
pg_end = ((ctx->args[i].ptr + len - 1) & PAGE_MASK) >>
PAGE_SHIFT;
pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
-
+ PERF_END);
} else {
-
+ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY),
if (ctx->olaps[oix].offset == 0) {
rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
args = ALIGN(args, FASTRPC_ALIGN);
@@ -1050,12 +1121,14 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
args = args + mlen;
rlen -= mlen;
+ PERF_END);
}

if (i < inbufs && !ctx->maps[i]) {
void *dst = (void *)(uintptr_t)rpra[i].buf.pv;
void *src = (void *)(uintptr_t)ctx->args[i].ptr;

+ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY),
if (!kernel) {
if (copy_from_user(dst, (void __user *)src,
len)) {
@@ -1065,6 +1138,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
} else {
memcpy(dst, src, len);
}
+ PERF_END);
}
}

@@ -1095,9 +1169,9 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
struct fastrpc_map *mmap = NULL;
struct fastrpc_invoke_buf *list;
struct fastrpc_phy_page *pages;
- u64 *fdlist;
- u32 *crclist;
- int i, inbufs, outbufs, handles;
+ u64 *fdlist, *perf_dsp_list;
+ u32 *crclist, *poll;
+ int i, inbufs, outbufs, handles, perferr;

inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);
@@ -1106,6 +1180,8 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
pages = fastrpc_phy_page_start(list, ctx->nscalars);
fdlist = (u64 *)(pages + inbufs + outbufs + handles);
crclist = (u32 *)(fdlist + FASTRPC_MAX_FDLIST);
+ poll = (u32 *)(crclist + FASTRPC_MAX_CRCLIST);
+ perf_dsp_list = (u64 *)(poll + 1);

for (i = inbufs; i < ctx->nbufs; ++i) {
if (!ctx->maps[i]) {
@@ -1135,6 +1211,12 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
FASTRPC_MAX_CRCLIST * sizeof(u32)))
return -EFAULT;
}
+ if (ctx->perf_dsp && perf_dsp_list) {
+ perferr = copy_to_user((void __user *)ctx->perf_dsp,
+ perf_dsp_list, FASTRPC_DSP_PERF_LIST * sizeof(u64));
+ if (perferr)
+ dev_info(fl->sctx->dev, "Warning: failed to copy perf data %d\n", perferr);
+ }
return 0;
}

@@ -1170,13 +1252,32 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,

}

+static void fastrpc_update_invoke_count(u32 handle, u64 *perf_counter,
+ struct timespec64 *invoket)
+{
+ u64 *invcount, *count;
+
+ invcount = GET_COUNTER(perf_counter, PERF_INVOKE);
+ if (invcount)
+ *invcount += getnstimediff(invoket);
+
+ count = GET_COUNTER(perf_counter, PERF_COUNT);
+ if (count)
+ *count += 1;
+}
+
static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
struct fastrpc_enhanced_invoke *invoke)
{
struct fastrpc_invoke_ctx *ctx = NULL;
struct fastrpc_invoke *inv = &invoke->inv;
u32 handle, sc;
- int err = 0;
+ u64 *perf_counter = NULL;
+ int err = 0, perferr = 0;
+ struct timespec64 invoket = {0};
+
+ if (fl->profile)
+ ktime_get_real_ts64(&invoket);

if (!fl->sctx)
return -EINVAL;
@@ -1195,16 +1296,22 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
if (IS_ERR(ctx))
return PTR_ERR(ctx);

+ if (fl->profile)
+ perf_counter = (u64 *)ctx->perf + PERF_COUNT;
+ PERF(fl->profile, GET_COUNTER(perf_counter, PERF_GETARGS),
err = fastrpc_get_args(kernel, ctx);
if (err)
goto bail;
+ PERF_END);

/* make sure that all CPU memory writes are seen by DSP */
dma_wmb();
+ PERF(fl->profile, GET_COUNTER(perf_counter, PERF_LINK),
/* Send invoke buffer to remote dsp */
err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle);
if (err)
goto bail;
+ PERF_END);

if (kernel) {
if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
@@ -1218,10 +1325,12 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,

/* make sure that all memory writes by DSP are seen by CPU */
dma_rmb();
+ PERF(fl->profile, GET_COUNTER(perf_counter, PERF_PUTARGS),
/* populate all the output buffers with results */
err = fastrpc_put_args(ctx, kernel);
if (err)
goto bail;
+ PERF_END);

/* Check the response from remote dsp */
err = ctx->retval;
@@ -1235,6 +1344,15 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
list_del(&ctx->node);
spin_unlock(&fl->lock);
fastrpc_context_put(ctx);
+ } else if (ctx) {
+ if (fl->profile && !err)
+ fastrpc_update_invoke_count(handle, perf_counter, &invoket);
+ if (fl->profile && ctx->perf && ctx->perf_kernel) {
+ perferr = copy_to_user((void __user *)ctx->perf_kernel,
+ ctx->perf, FASTRPC_KERNEL_PERF_LIST * sizeof(u64));
+ if (perferr)
+ dev_info(fl->sctx->dev, "Warning: failed to copy perf data %d\n", perferr);
+ }
}

if (err)
@@ -1828,6 +1946,7 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_invoke_args *args = NULL;
struct fastrpc_ioctl_multimode_invoke invoke;
u32 nscalars;
+ u64 *perf_kernel;
int err, i;

if (copy_from_user(&invoke, argp, sizeof(invoke)))
@@ -1862,6 +1981,9 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
return -EFAULT;
}
}
+ perf_kernel = (u64 *)(uintptr_t)einv.perf_kernel;
+ if (perf_kernel)
+ fl->profile = true;
einv.inv.args = (u64)args;
err = fastrpc_internal_invoke(fl, false, &einv);
kfree(args);
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index 45c15be1de58..559a3aea85b9 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -166,4 +166,18 @@ struct fastrpc_ioctl_capability {
__u32 reserved[4];
};

+enum fastrpc_perfkeys {
+ PERF_COUNT = 0,
+ PERF_FLUSH = 1,
+ PERF_MAP = 2,
+ PERF_COPY = 3,
+ PERF_LINK = 4,
+ PERF_GETARGS = 5,
+ PERF_PUTARGS = 6,
+ PERF_INVARGS = 7,
+ PERF_INVOKE = 8,
+ PERF_TID = 9,
+ PERF_KEY_MAX = 10,
+};
+
#endif /* __QCOM_FASTRPC_H__ */
--
2.17.0


2024-02-02 06:43:16

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 05/16] misc: fastrpc: Add CRC support for remote buffers

CRC check for input and output argument helps in ensuring data
consistency over a remote call. If user intends to enable CRC check,
first local user CRC is calculated at user end and a CRC buffer is
passed to DSP to capture remote CRC values. DSP is expected to
write to the remote CRC buffer which is then compared at user level
with the local CRC values.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index a7e959beabd4..a1b910459a90 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -639,6 +639,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
/* Released in fastrpc_context_put() */
fastrpc_channel_ctx_get(cctx);

+ ctx->crc = (u32 *)(uintptr_t)invoke->crc;
ctx->sc = sc;
ctx->retval = -1;
ctx->pid = current->pid;
@@ -1095,6 +1096,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
struct fastrpc_invoke_buf *list;
struct fastrpc_phy_page *pages;
u64 *fdlist;
+ u32 *crclist;
int i, inbufs, outbufs, handles;

inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
@@ -1102,7 +1104,8 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
handles = REMOTE_SCALARS_INHANDLES(ctx->sc) + REMOTE_SCALARS_OUTHANDLES(ctx->sc);
list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
pages = fastrpc_phy_page_start(list, ctx->nscalars);
- fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
+ fdlist = (u64 *)(pages + inbufs + outbufs + handles);
+ crclist = (u32 *)(fdlist + FASTRPC_MAX_FDLIST);

for (i = inbufs; i < ctx->nbufs; ++i) {
if (!ctx->maps[i]) {
@@ -1127,6 +1130,11 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
fastrpc_map_put(mmap);
}

+ if (ctx->crc && crclist && rpra) {
+ if (copy_to_user((void __user *)ctx->crc, crclist,
+ FASTRPC_MAX_CRCLIST * sizeof(u32)))
+ return -EFAULT;
+ }
return 0;
}

@@ -1834,6 +1842,7 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)

switch (invoke.req) {
case FASTRPC_INVOKE:
+ case FASTRPC_INVOKE_ENHANCED:
/* nscalars is truncated here to max supported value */
if (copy_from_user(&einv, (void __user *)(uintptr_t)invoke.invparam,
invoke.size))
--
2.17.0


2024-02-02 06:43:39

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 07/16] misc: fastrpc: Add support to save and restore interrupted

For any remote call, driver sends a message to DSP using RPMSG
framework. After message is sent, there is a wait on a completion
object at driver which is completed when DSP response is received.

There is a possibility that a signal is received while waiting
causing the wait function to return -ERESTARTSYS. In this case
the context should be saved and it should get restored for the
next invocation for the thread.

Adding changes to support saving and restoring of interrupted
fastrpc contexts.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 83 ++++++++++++++++++++++++++++++++++++------
1 file changed, 72 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 33687d7f9a28..88f065e78bc2 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -359,6 +359,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;
@@ -740,6 +741,40 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
return ERR_PTR(ret);
}

+static struct fastrpc_invoke_ctx *fastrpc_context_restore_interrupted(
+ struct fastrpc_user *fl, struct fastrpc_invoke *inv)
+{
+ struct fastrpc_invoke_ctx *ctx = NULL, *ictx = NULL, *n;
+
+ spin_lock(&fl->lock);
+ list_for_each_entry_safe(ictx, n, &fl->interrupted, node) {
+ if (ictx->pid == current->pid) {
+ if (inv->sc != ictx->sc || ictx->fl != fl) {
+ dev_err(ictx->fl->sctx->dev,
+ "interrupted sc (0x%x) or fl (%pK) does not match with invoke sc (0x%x) or fl (%pK)\n",
+ ictx->sc, ictx->fl, inv->sc, 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;
+}
+
+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 sg_table *
fastrpc_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction dir)
@@ -1292,6 +1327,14 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
return -EPERM;
}

+ if (!kernel) {
+ ctx = fastrpc_context_restore_interrupted(fl, inv);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+ if (ctx)
+ goto wait;
+ }
+
ctx = fastrpc_context_alloc(fl, kernel, sc, invoke);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
@@ -1313,6 +1356,7 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
goto bail;
PERF_END);

+wait:
if (kernel) {
if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
err = -ETIMEDOUT;
@@ -1338,12 +1382,9 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
goto bail;

bail:
- if (err != -ERESTARTSYS && 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) {
+ if (ctx)
+ fastrpc_context_save_interrupted(ctx);
} else if (ctx) {
if (fl->profile && !err)
fastrpc_update_invoke_count(handle, perf_counter, &invoket);
@@ -1353,6 +1394,10 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
if (perferr)
dev_info(fl->sctx->dev, "Warning: failed to copy perf data %d\n", perferr);
}
+ spin_lock(&fl->lock);
+ list_del(&ctx->node);
+ spin_unlock(&fl->lock);
+ fastrpc_context_put(ctx);
}

if (err)
@@ -1734,6 +1779,25 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
spin_unlock_irqrestore(&cctx->lock, flags);
}

+static void fastrpc_context_list_free(struct fastrpc_user *fl)
+{
+ struct fastrpc_invoke_ctx *ctx, *n;
+
+ list_for_each_entry_safe(ctx, n, &fl->interrupted, node) {
+ spin_lock(&fl->lock);
+ list_del(&ctx->node);
+ spin_unlock(&fl->lock);
+ fastrpc_context_put(ctx);
+ }
+
+ list_for_each_entry_safe(ctx, n, &fl->pending, node) {
+ spin_lock(&fl->lock);
+ list_del(&ctx->node);
+ spin_unlock(&fl->lock);
+ fastrpc_context_put(ctx);
+ }
+}
+
static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
{
struct fastrpc_invoke_args args[1];
@@ -1756,7 +1820,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
{
struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data;
struct fastrpc_channel_ctx *cctx = fl->cctx;
- struct fastrpc_invoke_ctx *ctx, *n;
struct fastrpc_map *map, *m;
struct fastrpc_buf *buf, *b;
unsigned long flags;
@@ -1770,10 +1833,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
if (fl->init_mem)
fastrpc_buf_free(fl->init_mem);

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

list_for_each_entry_safe(map, m, &fl->maps, node)
fastrpc_map_put(map);
@@ -1814,6 +1874,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);
--
2.17.0


2024-02-02 06:44:05

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 11/16] misc: fastrpc: Add DSP PD notification support

Current driver design does not provide any notification regarding
the status of used PD on DSP. Only when user makes a FastRPC
invocation, they get to know if the process has been killed on
DSP. Notifying status of user PD can help users to restart the
DSP PD session.

Co-developed-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 139 +++++++++++++++++++++++++++++++++++-
include/uapi/misc/fastrpc.h | 14 ++++
2 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 296ddae0ef7c..d4a4ad54a5c9 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -122,6 +122,8 @@
/* CPU feature information to DSP */
#define FASTRPC_CPUINFO_DEFAULT (0)
#define FASTRPC_CPUINFO_EARLY_WAKEUP (1)
+/* Process status notifications from DSP will be sent with this unique context */
+#define FASTRPC_NOTIF_CTX_RESERVED 0xABCDABCD

#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)

@@ -264,6 +266,13 @@ struct fastrpc_invoke_rspv2 {
u32 version; /* version number */
};

+struct dsp_notif_rsp {
+ u64 ctx; /* response context */
+ u32 type; /* Notification type */
+ int pid; /* user process pid */
+ u32 status; /* userpd status notification */
+};
+
struct fastrpc_buf_overlap {
u64 start;
u64 end;
@@ -324,6 +333,21 @@ struct fastrpc_perf {
u64 tid;
};

+struct fastrpc_notif_queue {
+ /* Number of pending status notifications in queue */
+ atomic_t notif_queue_count;
+ /* Wait queue to synchronize notifier thread and response */
+ wait_queue_head_t notif_wait_queue;
+ /* IRQ safe spin lock for protecting notif queue */
+ spinlock_t nqlock;
+};
+
+struct fastrpc_notif_rsp {
+ struct list_head notifn;
+ u32 domain;
+ enum fastrpc_status_flags status;
+};
+
struct fastrpc_invoke_ctx {
int nscalars;
int nbufs;
@@ -414,10 +438,13 @@ struct fastrpc_user {
struct list_head pending;
struct list_head interrupted;
struct list_head mmaps;
+ struct list_head notif_queue;

struct fastrpc_channel_ctx *cctx;
struct fastrpc_session_ctx *sctx;
struct fastrpc_buf *init_mem;
+ /* Process status notification queue */
+ struct fastrpc_notif_queue proc_state_notif;

u32 profile;
/* Threads poll for specified timeout and fall back to glink wait */
@@ -2196,6 +2223,99 @@ static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
return err;
}

+static void fastrpc_queue_pd_status(struct fastrpc_user *fl, int domain, int status)
+{
+ struct fastrpc_notif_rsp *notif_rsp = NULL;
+ unsigned long flags;
+
+ notif_rsp = kzalloc(sizeof(*notif_rsp), GFP_ATOMIC);
+ if (!notif_rsp)
+ return;
+
+ notif_rsp->status = status;
+ notif_rsp->domain = domain;
+
+ spin_lock_irqsave(&fl->proc_state_notif.nqlock, flags);
+ list_add_tail(&notif_rsp->notifn, &fl->notif_queue);
+ atomic_add(1, &fl->proc_state_notif.notif_queue_count);
+ wake_up_interruptible(&fl->proc_state_notif.notif_wait_queue);
+ spin_unlock_irqrestore(&fl->proc_state_notif.nqlock, flags);
+}
+
+static void fastrpc_notif_find_process(int domain, struct fastrpc_channel_ctx *cctx, struct dsp_notif_rsp *notif)
+{
+ bool is_process_found = false;
+ unsigned long irq_flags = 0;
+ struct fastrpc_user *user;
+
+ spin_lock_irqsave(&cctx->lock, irq_flags);
+ list_for_each_entry(user, &cctx->users, user) {
+ if (user->tgid == notif->pid) {
+ is_process_found = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cctx->lock, irq_flags);
+
+ if (!is_process_found)
+ return;
+ fastrpc_queue_pd_status(user, domain, notif->status);
+}
+
+static int fastrpc_wait_on_notif_queue(
+ struct fastrpc_internal_notif_rsp *notif_rsp,
+ struct fastrpc_user *fl)
+{
+ int err = 0;
+ unsigned long flags;
+ struct fastrpc_notif_rsp *notif, *inotif, *n;
+
+read_notif_status:
+ err = wait_event_interruptible(fl->proc_state_notif.notif_wait_queue,
+ atomic_read(&fl->proc_state_notif.notif_queue_count));
+ if (err) {
+ kfree(notif);
+ return err;
+ }
+
+ spin_lock_irqsave(&fl->proc_state_notif.nqlock, flags);
+ list_for_each_entry_safe(inotif, n, &fl->notif_queue, notifn) {
+ list_del(&inotif->notifn);
+ atomic_sub(1, &fl->proc_state_notif.notif_queue_count);
+ notif = inotif;
+ break;
+ }
+ spin_unlock_irqrestore(&fl->proc_state_notif.nqlock, flags);
+
+ if (notif) {
+ notif_rsp->status = notif->status;
+ notif_rsp->domain = notif->domain;
+ } else {// Go back to wait if ctx is invalid
+ dev_err(fl->sctx->dev, "Invalid status notification response\n");
+ goto read_notif_status;
+ }
+
+ kfree(notif);
+ return err;
+}
+
+static int fastrpc_get_notif_response(
+ struct fastrpc_internal_notif_rsp *notif,
+ void *param, struct fastrpc_user *fl)
+{
+ int err = 0;
+
+ err = fastrpc_wait_on_notif_queue(notif, fl);
+ if (err)
+ return err;
+
+ if (copy_to_user((void __user *)param, notif,
+ sizeof(struct fastrpc_internal_notif_rsp)))
+ return -EFAULT;
+
+ return 0;
+}
+
static int fastrpc_manage_poll_mode(struct fastrpc_user *fl, u32 enable, u32 timeout)
{
const unsigned int MAX_POLL_TIMEOUT_US = 10000;
@@ -2253,6 +2373,7 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
struct fastrpc_invoke_args *args = NULL;
struct fastrpc_ioctl_multimode_invoke invoke;
struct fastrpc_internal_control cp = {0};
+ struct fastrpc_internal_notif_rsp notif;
u32 nscalars;
u64 *perf_kernel;
int err, i;
@@ -2302,6 +2423,10 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)

err = fastrpc_internal_control(fl, &cp);
break;
+ case FASTRPC_INVOKE_NOTIF:
+ err = fastrpc_get_notif_response(&notif,
+ (void *)invoke.invparam, fl);
+ break;
default:
err = -ENOTTY;
break;
@@ -3278,8 +3403,10 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
cctx->rpdev = NULL;
cctx->staticpd_status = false;
fastrpc_mmap_remove_ssr(cctx);
- list_for_each_entry(user, &cctx->users, user)
+ list_for_each_entry(user, &cctx->users, user) {
+ fastrpc_queue_pd_status(user, cctx->domain_id, FASTRPC_DSP_SSR);
fastrpc_notify_users(user);
+ }
spin_unlock_irqrestore(&cctx->lock, flags);

if (cctx->domain_id == ADSP_DOMAIN_ID) {
@@ -3331,12 +3458,22 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
struct fastrpc_invoke_rsp *rsp = data;
struct fastrpc_invoke_rspv2 *rspv2 = NULL;
+ struct dsp_notif_rsp *notif = (struct dsp_notif_rsp *)data;
struct fastrpc_invoke_ctx *ctx;
unsigned long flags;
unsigned long ctxid;
u32 rsp_flags = 0;
u32 early_wake_time = 0;

+ if (notif->ctx == FASTRPC_NOTIF_CTX_RESERVED) {
+ if (notif->type == STATUS_RESPONSE && len >= sizeof(*notif)) {
+ fastrpc_notif_find_process(cctx->domain_id, cctx, notif);
+ return 0;
+ } else {
+ return -ENOENT;
+ }
+ }
+
if (len < sizeof(*rsp))
return -EINVAL;

diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index b4959cc4d254..a3bc6666a653 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -195,6 +195,12 @@ struct fastrpc_internal_control {
};
};

+struct fastrpc_internal_notif_rsp {
+ u32 domain; /* Domain of User PD */
+ u32 session; /* Session ID of User PD */
+ u32 status; /* Status of the process */
+};
+
enum fastrpc_perfkeys {
PERF_COUNT = 0,
PERF_FLUSH = 1,
@@ -209,4 +215,12 @@ enum fastrpc_perfkeys {
PERF_KEY_MAX = 10,
};

+enum fastrpc_status_flags {
+ FASTRPC_USERPD_UP = 0,
+ FASTRPC_USERPD_EXIT = 1,
+ FASTRPC_USERPD_FORCE_KILL = 2,
+ FASTRPC_USERPD_EXCEPTION = 3,
+ FASTRPC_DSP_SSR = 4,
+};
+
#endif /* __QCOM_FASTRPC_H__ */
--
2.17.0


2024-02-02 06:44:15

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 10/16] misc: fastrpc: Add polling mode support for fastRPC driver

For any remote call to DSP, after sending an invocation message,
fastRPC driver waits for glink response and during this time the
CPU can go into low power modes. Adding a polling mode support
with which fastRPC driver will poll continuously on a memory
after sending a message to remote subsystem which will eliminate
CPU wakeup and scheduling latencies and reduce fastRPC overhead.
With this change, DSP always sends a glink response which will
get ignored if polling mode didn't time out.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 50 +++++++++++++++++++++++++++++++++++++
include/uapi/misc/fastrpc.h | 10 +++++++-
2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index e4bb01bad7fb..296ddae0ef7c 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -111,6 +111,8 @@
#define FASTRPC_RSP_VERSION2 2
/* Early wake up poll completion number received from remoteproc */
#define FASTRPC_EARLY_WAKEUP_POLL (0xabbccdde)
+/* Poll response number from remote processor for call completion */
+#define FASTRPC_POLL_RESPONSE (0xdecaf)
/* timeout in us for polling until memory barrier */
#define FASTRPC_POLL_TIME_MEM_UPDATE (500)
/* timeout in us for busy polling after early response from remoteproc */
@@ -418,11 +420,15 @@ struct fastrpc_user {
struct fastrpc_buf *init_mem;

u32 profile;
+ /* Threads poll for specified timeout and fall back to glink wait */
+ u32 poll_timeout;
int tgid;
int pd;
bool is_secure_dev;
bool is_unsigned_pd;
bool sharedcb;
+ /* If set, threads will poll for DSP response instead of glink wait */
+ bool poll_mode;
char *servloc_name;
/* Lock for lists */
spinlock_t lock;
@@ -1398,6 +1404,11 @@ static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx, u32 timeout)
/* Remote processor sent early response */
err = 0;
break;
+ } else if (*poll == FASTRPC_POLL_RESPONSE) {
+ err = 0;
+ ctx->is_work_done = true;
+ ctx->retval = 0;
+ break;
}
if (j == FASTRPC_POLL_TIME_MEM_UPDATE) {
/* make sure that all poll memory writes by DSP are seen by CPU */
@@ -1475,6 +1486,15 @@ static void fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx,
if (*ptr_interrupted || ctx->is_work_done)
return;
break;
+ case POLL_MODE:
+ err = poll_for_remote_response(ctx, ctx->fl->poll_timeout);
+
+ /* If polling timed out, move to normal response state */
+ if (err)
+ ctx->rsp_flags = NORMAL_RESPONSE;
+ else
+ *ptr_interrupted = 0;
+ break;
default:
*ptr_interrupted = -EBADR;
dev_err(ctx->fl->sctx->dev, "unsupported response type:0x%x\n", ctx->rsp_flags);
@@ -2176,6 +2196,33 @@ static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
return err;
}

+static int fastrpc_manage_poll_mode(struct fastrpc_user *fl, u32 enable, u32 timeout)
+{
+ const unsigned int MAX_POLL_TIMEOUT_US = 10000;
+
+ if ((fl->cctx->domain_id != CDSP_DOMAIN_ID) || (fl->pd != USER_PD)) {
+ dev_err(&fl->cctx->rpdev->dev, "poll mode only allowed for dynamic CDSP process\n");
+ return -EPERM;
+ }
+ if (timeout > MAX_POLL_TIMEOUT_US) {
+ dev_err(&fl->cctx->rpdev->dev, "poll timeout %u is greater than max allowed value %u\n",
+ timeout, MAX_POLL_TIMEOUT_US);
+ return -EBADMSG;
+ }
+ spin_lock(&fl->lock);
+ if (enable) {
+ fl->poll_mode = true;
+ fl->poll_timeout = timeout;
+ } else {
+ fl->poll_mode = false;
+ fl->poll_timeout = 0;
+ }
+ spin_unlock(&fl->lock);
+ dev_info(&fl->cctx->rpdev->dev, "updated poll mode to %d, timeout %u\n", enable, timeout);
+
+ return 0;
+}
+
static int fastrpc_internal_control(struct fastrpc_user *fl,
struct fastrpc_internal_control *cp)
{
@@ -2190,6 +2237,9 @@ static int fastrpc_internal_control(struct fastrpc_user *fl,
case FASTRPC_CONTROL_SMMU:
fl->sharedcb = cp->smmu.sharedcb;
break;
+ case FASTRPC_CONTROL_RPC_POLL:
+ err = fastrpc_manage_poll_mode(fl, cp->lp.enable, cp->lp.latency);
+ break;
default:
err = -EBADRQC;
break;
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index d29188e43b21..b4959cc4d254 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -182,9 +182,17 @@ struct fastrpc_ctrl_smmu {
u32 sharedcb; /* Set to SMMU share context bank */
};

+struct fastrpc_ctrl_latency {
+ u32 enable; /* latency control enable */
+ u32 latency; /* latency request in us */
+};
+
struct fastrpc_internal_control {
u32 req;
- struct fastrpc_ctrl_smmu smmu;
+ union {
+ struct fastrpc_ctrl_smmu smmu;
+ struct fastrpc_ctrl_latency lp;
+ };
};

enum fastrpc_perfkeys {
--
2.17.0


2024-02-02 06:44:27

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 08/16] misc: fastrpc: Add support to allocate shared context bank

Context banks could be set as a shared one using a DT propery
"qcom,nsessions". The property takes the number of session to
be created of the context bank. This change provides a control
mechanism for user to use shared context banks for light weight
processes. The session is set as shared while its creation and if
a user requests for shared context bank, the same will be allocated
during process initialization.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 117 ++++++++++++++++++++++++------------
include/uapi/misc/fastrpc.h | 21 +++++++
2 files changed, 99 insertions(+), 39 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 88f065e78bc2..9f67cfbc0222 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -312,6 +312,7 @@ struct fastrpc_session_ctx {
int sid;
bool used;
bool valid;
+ bool sharedcb;
};

struct fastrpc_static_pd {
@@ -371,6 +372,7 @@ struct fastrpc_user {
int pd;
bool is_secure_dev;
bool is_unsigned_pd;
+ bool sharedcb;
char *servloc_name;
/* Lock for lists */
spinlock_t lock;
@@ -879,6 +881,37 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = {
.release = fastrpc_release,
};

+static struct fastrpc_session_ctx *fastrpc_session_alloc(
+ struct fastrpc_channel_ctx *cctx, bool sharedcb)
+{
+ struct fastrpc_session_ctx *session = NULL;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&cctx->lock, flags);
+ for (i = 0; i < cctx->sesscount; i++) {
+ if (!cctx->session[i].used && cctx->session[i].valid &&
+ cctx->session[i].sharedcb == sharedcb) {
+ cctx->session[i].used = true;
+ session = &cctx->session[i];
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cctx->lock, flags);
+
+ return session;
+}
+
+static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
+ struct fastrpc_session_ctx *session)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cctx->lock, flags);
+ session->used = false;
+ spin_unlock_irqrestore(&cctx->lock, flags);
+}
+
static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
{
@@ -1545,6 +1578,12 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
goto err_name;
}

+ fl->sctx = fastrpc_session_alloc(fl->cctx, fl->sharedcb);
+ if (!fl->sctx) {
+ err = -EBUSY;
+ goto err_name;
+ }
+
if (!fl->cctx->staticpd_status) {
err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &buf);
if (err)
@@ -1674,6 +1713,12 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
goto err;
}

+ fl->sctx = fastrpc_session_alloc(fl->cctx, fl->sharedcb);
+ if (!fl->sctx) {
+ err = -EBUSY;
+ goto err;
+ }
+
inbuf.pgid = fl->tgid;
inbuf.namelen = strlen(current->comm) + 1;
inbuf.filelen = init.filelen;
@@ -1749,36 +1794,6 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
return err;
}

-static struct fastrpc_session_ctx *fastrpc_session_alloc(
- struct fastrpc_channel_ctx *cctx)
-{
- struct fastrpc_session_ctx *session = NULL;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&cctx->lock, flags);
- for (i = 0; i < cctx->sesscount; i++) {
- if (!cctx->session[i].used && cctx->session[i].valid) {
- cctx->session[i].used = true;
- session = &cctx->session[i];
- break;
- }
- }
- spin_unlock_irqrestore(&cctx->lock, flags);
-
- return session;
-}
-
-static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
- struct fastrpc_session_ctx *session)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cctx->lock, flags);
- session->used = false;
- spin_unlock_irqrestore(&cctx->lock, flags);
-}
-
static void fastrpc_context_list_free(struct fastrpc_user *fl)
{
struct fastrpc_invoke_ctx *ctx, *n;
@@ -1882,15 +1897,6 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
fl->cctx = cctx;
fl->is_secure_dev = fdevice->secure;

- fl->sctx = fastrpc_session_alloc(cctx);
- if (!fl->sctx) {
- dev_err(&cctx->rpdev->dev, "No session available\n");
- mutex_destroy(&fl->mutex);
- kfree(fl);
-
- return -EBUSY;
- }
-
spin_lock_irqsave(&cctx->lock, flags);
list_add_tail(&fl->user, &cctx->users);
spin_unlock_irqrestore(&cctx->lock, flags);
@@ -1949,6 +1955,10 @@ static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
struct fastrpc_enhanced_invoke ioctl;
int tgid = fl->tgid;

+ fl->sctx = fastrpc_session_alloc(fl->cctx, fl->sharedcb);
+ if (!fl->sctx)
+ return -EBUSY;
+
args[0].ptr = (u64)(uintptr_t) &tgid;
args[0].length = sizeof(tgid);
args[0].fd = -1;
@@ -2001,11 +2011,33 @@ static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
return err;
}

+static int fastrpc_internal_control(struct fastrpc_user *fl,
+ struct fastrpc_internal_control *cp)
+{
+ int err = 0;
+
+ if (!fl)
+ return -EBADF;
+ if (!cp)
+ return -EINVAL;
+
+ switch (cp->req) {
+ case FASTRPC_CONTROL_SMMU:
+ fl->sharedcb = cp->smmu.sharedcb;
+ break;
+ default:
+ err = -EBADRQC;
+ break;
+ }
+ return err;
+}
+
static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_enhanced_invoke einv;
struct fastrpc_invoke_args *args = NULL;
struct fastrpc_ioctl_multimode_invoke invoke;
+ struct fastrpc_internal_control cp = {0};
u32 nscalars;
u64 *perf_kernel;
int err, i;
@@ -2049,6 +2081,12 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
err = fastrpc_internal_invoke(fl, false, &einv);
kfree(args);
break;
+ case FASTRPC_INVOKE_CONTROL:
+ if (copy_from_user(&cp, (void __user *)(uintptr_t)invoke.invparam, sizeof(cp)))
+ return -EFAULT;
+
+ err = fastrpc_internal_control(fl, &cp);
+ break;
default:
err = -ENOTTY;
break;
@@ -2738,6 +2776,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
if (sessions > 0) {
struct fastrpc_session_ctx *dup_sess;

+ sess->sharedcb = true;
for (i = 1; i < sessions; i++) {
if (cctx->sesscount >= FASTRPC_MAX_SESSIONS)
break;
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index 559a3aea85b9..d29188e43b21 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -166,6 +166,27 @@ struct fastrpc_ioctl_capability {
__u32 reserved[4];
};

+enum fastrpc_control_type {
+ FASTRPC_CONTROL_LATENCY = 1,
+ FASTRPC_CONTROL_SMMU = 2,
+ FASTRPC_CONTROL_KALLOC = 3,
+ FASTRPC_CONTROL_WAKELOCK = 4,
+ FASTRPC_CONTROL_PM = 5,
+ FASTRPC_CONTROL_DSPPROCESS_CLEAN = 6,
+ FASTRPC_CONTROL_RPC_POLL = 7,
+ FASTRPC_CONTROL_ASYNC_WAKE = 8,
+ FASTRPC_CONTROL_NOTIF_WAKE = 9,
+};
+
+struct fastrpc_ctrl_smmu {
+ u32 sharedcb; /* Set to SMMU share context bank */
+};
+
+struct fastrpc_internal_control {
+ u32 req;
+ struct fastrpc_ctrl_smmu smmu;
+};
+
enum fastrpc_perfkeys {
PERF_COUNT = 0,
PERF_FLUSH = 1,
--
2.17.0


2024-02-02 06:44:40

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 12/16] misc: fastrpc: Add support for users to clean up DSP user PD

Add a control mechanism for users to clean up DSP user PD. This
method can be used by users for handling any unexpected hang
scenarios on DSP PD. User can clean up DSP PD and restart the
user PD again.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index d4a4ad54a5c9..d1be89f84214 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -2360,6 +2360,11 @@ static int fastrpc_internal_control(struct fastrpc_user *fl,
case FASTRPC_CONTROL_RPC_POLL:
err = fastrpc_manage_poll_mode(fl, cp->lp.enable, cp->lp.latency);
break;
+ case FASTRPC_CONTROL_DSPPROCESS_CLEAN:
+ err = fastrpc_release_current_dsp_process(fl);
+ if (!err)
+ fastrpc_queue_pd_status(fl, fl->cctx->domain_id, FASTRPC_USERPD_FORCE_KILL);
+ break;
default:
err = -EBADRQC;
break;
--
2.17.0


2024-02-02 06:44:51

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 09/16] misc: fastrpc: Add early wakeup support for fastRPC driver

CPU wake up and context switch latency are significant in FastRPC
overhead for remote calls. As part of this change, DSP sends early
signal of completion to CPU and FastRPC driver detects early signal
on the given context and starts polling on a memory for actual
completion. Multiple different response flags are added to support
DSP user early hint of approximate time of completion, early response
from DSP user to wake up CPU and poll on memory for actual completion.
Complete signal is also added which is sent by DSP user in case of
timeout after early response is sent.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 267 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 254 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 9f67cfbc0222..e4bb01bad7fb 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -108,6 +108,19 @@
#define USER_PD (1)
#define SENSORS_PD (2)

+#define FASTRPC_RSP_VERSION2 2
+/* Early wake up poll completion number received from remoteproc */
+#define FASTRPC_EARLY_WAKEUP_POLL (0xabbccdde)
+/* timeout in us for polling until memory barrier */
+#define FASTRPC_POLL_TIME_MEM_UPDATE (500)
+/* timeout in us for busy polling after early response from remoteproc */
+#define FASTRPC_POLL_TIME (4000)
+/* timeout in us for polling completion signal after user early hint */
+#define FASTRPC_USER_EARLY_HINT_TIMEOUT (500)
+/* CPU feature information to DSP */
+#define FASTRPC_CPUINFO_DEFAULT (0)
+#define FASTRPC_CPUINFO_EARLY_WAKEUP (1)
+
#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)

#define AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME "audio_pdr_adsp"
@@ -143,6 +156,27 @@
(uint64_t *)(perf_ptr + offset)\
: (uint64_t *)NULL) : (uint64_t *)NULL)

+/* Response types supported for RPC calls
+ * Difference between response and signal terms used here -
+ * response carries return value where as signal is just a notification without return value
+ */
+enum fastrpc_response_flags {
+ /* normal job completion response */
+ NORMAL_RESPONSE = 0,
+ /* early response, cpu will poll on memory for actual completion */
+ EARLY_RESPONSE = 1,
+ /* user hint before completion with estimated completion time */
+ USER_EARLY_SIGNAL = 2,
+ /* extra completion clear signal to cpu when DSP updating poll
+ * memory later than 2 ms after sending early response
+ */
+ COMPLETE_SIGNAL = 3,
+ /* status notification response of DSP User PD */
+ STATUS_RESPONSE = 4,
+ /* process updates poll memory instead of glink response */
+ POLL_MODE = 5,
+};
+
static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp",
"sdsp", "cdsp"};
struct fastrpc_phy_page {
@@ -220,6 +254,14 @@ struct fastrpc_invoke_rsp {
int retval; /* invoke return value */
};

+struct fastrpc_invoke_rspv2 {
+ u64 ctx; /* invoke caller context */
+ int retval; /* invoke return value */
+ u32 flags; /* early response flags */
+ u32 early_wake_time; /* user hint in us */
+ u32 version; /* version number */
+};
+
struct fastrpc_buf_overlap {
u64 start;
u64 end;
@@ -287,11 +329,17 @@ struct fastrpc_invoke_ctx {
int pid;
int tgid;
u32 sc;
+ /* user hint of completion time in us */
+ u32 early_wake_time;
u32 *crc;
u64 *perf_kernel;
u64 *perf_dsp;
u64 ctxid;
u64 msg_sz;
+ /* work done status flag */
+ bool is_work_done;
+ /* response flags from remote processor */
+ enum fastrpc_response_flags rsp_flags;
struct kref refcount;
struct list_head node; /* list of ctxs */
struct completion work;
@@ -347,7 +395,9 @@ struct fastrpc_channel_ctx {
struct list_head rmaps;
bool secure;
bool unsigned_support;
+ bool cpuinfo_status;
u64 dma_mask;
+ u64 cpuinfo_todsp;
};

struct fastrpc_device {
@@ -711,6 +761,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
ctx->pid = current->pid;
ctx->tgid = user->tgid;
ctx->cctx = cctx;
+ ctx->rsp_flags = NORMAL_RESPONSE;
+ ctx->is_work_done = false;
init_completion(&ctx->work);
INIT_WORK(&ctx->put_work, fastrpc_context_put_wq);

@@ -1320,6 +1372,117 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,

}

+static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx, u32 timeout)
+{
+ int err = -EIO, i, j;
+ u32 sc = ctx->sc;
+ struct fastrpc_invoke_buf *list;
+ struct fastrpc_phy_page *pages;
+ u64 *fdlist = NULL;
+ u32 *crclist = NULL, *poll = NULL;
+ unsigned int inbufs, outbufs, handles;
+
+ /* calculate poll memory location */
+ inbufs = REMOTE_SCALARS_INBUFS(sc);
+ outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
+ list = fastrpc_invoke_buf_start(ctx->rpra, ctx->nscalars);
+ pages = fastrpc_phy_page_start(list, ctx->nscalars);
+ fdlist = (u64 *)(pages + inbufs + outbufs + handles);
+ crclist = (u32 *)(fdlist + FASTRPC_MAX_FDLIST);
+ poll = (u32 *)(crclist + FASTRPC_MAX_CRCLIST);
+
+ /* poll on memory for DSP response. Return failure on timeout */
+ for (i = 0, j = 0; i < timeout; i++, j++) {
+ if (*poll == FASTRPC_EARLY_WAKEUP_POLL) {
+ /* Remote processor sent early response */
+ err = 0;
+ break;
+ }
+ if (j == FASTRPC_POLL_TIME_MEM_UPDATE) {
+ /* make sure that all poll memory writes by DSP are seen by CPU */
+ dma_rmb();
+ j = 0;
+ }
+ udelay(1);
+ }
+ return err;
+}
+
+static inline int fastrpc_wait_for_response(struct fastrpc_invoke_ctx *ctx,
+ u32 kernel)
+{
+ int interrupted = 0;
+
+ if (kernel)
+ wait_for_completion(&ctx->work);
+ else
+ interrupted = wait_for_completion_interruptible(&ctx->work);
+
+ return interrupted;
+}
+
+static void fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx,
+ int *ptr_interrupted, u32 kernel)
+{
+ int err, i = 0;
+ bool wait_resp = false;
+ u32 wTimeout = FASTRPC_USER_EARLY_HINT_TIMEOUT;
+ u32 wakeTime = ctx->early_wake_time;
+
+ do {
+ switch (ctx->rsp_flags) {
+ /* Try polling on completion with timeout */
+ case USER_EARLY_SIGNAL:
+ /* Try wait if completion time is less than timeout
+ * disable preempt to avoid context switch latency
+ */
+ preempt_disable();
+ i = 0;
+ wait_resp = false;
+ for (; wakeTime < wTimeout && i < wTimeout; i++) {
+ wait_resp = try_wait_for_completion(&ctx->work);
+ if (wait_resp)
+ break;
+ udelay(1);
+ }
+ preempt_enable();
+ if (!wait_resp) {
+ *ptr_interrupted = fastrpc_wait_for_response(ctx, kernel);
+ if (*ptr_interrupted || ctx->is_work_done)
+ return;
+ }
+ break;
+ /* Busy poll on memory for actual job done */
+ case EARLY_RESPONSE:
+ err = poll_for_remote_response(ctx, FASTRPC_POLL_TIME);
+ /* Mark job done if poll on memory successful or
+ * wait for completion if poll on memory timeout
+ */
+ if (!err) {
+ ctx->is_work_done = true;
+ return;
+ }
+ if (!ctx->is_work_done) {
+ *ptr_interrupted = fastrpc_wait_for_response(ctx, kernel);
+ if (*ptr_interrupted || ctx->is_work_done)
+ return;
+ }
+ break;
+ case COMPLETE_SIGNAL:
+ case NORMAL_RESPONSE:
+ *ptr_interrupted = fastrpc_wait_for_response(ctx, kernel);
+ if (*ptr_interrupted || ctx->is_work_done)
+ return;
+ break;
+ default:
+ *ptr_interrupted = -EBADR;
+ dev_err(ctx->fl->sctx->dev, "unsupported response type:0x%x\n", ctx->rsp_flags);
+ break;
+ }
+ } while (!ctx->is_work_done);
+}
+
static void fastrpc_update_invoke_count(u32 handle, u64 *perf_counter,
struct timespec64 *invoket)
{
@@ -1341,7 +1504,7 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
struct fastrpc_invoke *inv = &invoke->inv;
u32 handle, sc;
u64 *perf_counter = NULL;
- int err = 0, perferr = 0;
+ int err = 0, perferr = 0, interrupted = 0;
struct timespec64 invoket = {0};

if (fl->profile)
@@ -1390,15 +1553,17 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
PERF_END);

wait:
- if (kernel) {
- if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
- err = -ETIMEDOUT;
- } else {
- err = wait_for_completion_interruptible(&ctx->work);
+ fastrpc_wait_for_completion(ctx, &interrupted, kernel);
+ if (interrupted != 0) {
+ err = interrupted;
+ goto bail;
}
-
- if (err)
+ if (!ctx->is_work_done) {
+ err = -ETIMEDOUT;
+ dev_err(fl->sctx->dev, "Error: Invalid workdone state for handle 0x%x, sc 0x%x\n",
+ handle, sc);
goto bail;
+ }

/* make sure that all memory writes by DSP are seen by CPU */
dma_rmb();
@@ -2162,6 +2327,36 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap,
return 0;
}

+static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_user *fl)
+{
+ int err = 0;
+ u64 cpuinfo = 0;
+ struct fastrpc_invoke_args args[1];
+ struct fastrpc_enhanced_invoke ioctl;
+
+ if (!fl)
+ return -EBADF;
+
+ cpuinfo = fl->cctx->cpuinfo_todsp;
+ /* return success if already updated to remote processor */
+ if (fl->cctx->cpuinfo_status)
+ return 0;
+
+ args[0].ptr = (u64)(uintptr_t)&cpuinfo;
+ args[0].length = sizeof(cpuinfo);
+ args[0].fd = -1;
+
+ ioctl.inv.handle = FASTRPC_DSP_UTILITIES_HANDLE;
+ ioctl.inv.sc = FASTRPC_SCALARS(1, 1, 0);
+ ioctl.inv.args = (u64)args;
+
+ err = fastrpc_internal_invoke(fl, true, &ioctl);
+ if (!err)
+ fl->cctx->cpuinfo_status = true;
+
+ return err;
+}
+
static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_ioctl_capability cap = {0};
@@ -2634,6 +2829,8 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
break;
case FASTRPC_IOCTL_INIT_ATTACH:
err = fastrpc_init_attach(fl, ROOT_PD);
+ if (!err)
+ fastrpc_send_cpuinfo_to_dsp(fl);
break;
case FASTRPC_IOCTL_INIT_ATTACH_SNS:
err = fastrpc_init_attach(fl, SENSORS_PD);
@@ -2953,6 +3150,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]);
if (err)
goto fdev_error;
+ data->cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT;
break;
case CDSP_DOMAIN_ID:
data->unsigned_support = true;
@@ -2964,6 +3162,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
err = fastrpc_device_register(rdev, data, false, domains[domain_id]);
if (err)
goto fdev_error;
+ data->cpuinfo_todsp = FASTRPC_CPUINFO_EARLY_WAKEUP;
break;
default:
err = -EINVAL;
@@ -3051,31 +3250,73 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
fastrpc_channel_ctx_put(cctx);
}

+static void fastrpc_notify_user_ctx(struct fastrpc_invoke_ctx *ctx, int retval,
+ u32 rsp_flags, u32 early_wake_time)
+{
+ ctx->retval = retval;
+ ctx->rsp_flags = (enum fastrpc_response_flags)rsp_flags;
+ switch (rsp_flags) {
+ case NORMAL_RESPONSE:
+ case COMPLETE_SIGNAL:
+ /* normal and complete response with return value */
+ ctx->is_work_done = true;
+ complete(&ctx->work);
+ break;
+ case USER_EARLY_SIGNAL:
+ /* user hint of approximate time of completion */
+ ctx->early_wake_time = early_wake_time;
+ break;
+ case EARLY_RESPONSE:
+ /* rpc framework early response with return value */
+ complete(&ctx->work);
+ break;
+ default:
+ break;
+ }
+}
+
static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
int len, void *priv, u32 addr)
{
struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
struct fastrpc_invoke_rsp *rsp = data;
+ struct fastrpc_invoke_rspv2 *rspv2 = NULL;
struct fastrpc_invoke_ctx *ctx;
unsigned long flags;
unsigned long ctxid;
+ u32 rsp_flags = 0;
+ u32 early_wake_time = 0;

if (len < sizeof(*rsp))
return -EINVAL;

+ if (len >= sizeof(*rspv2)) {
+ rspv2 = data;
+ if (rspv2) {
+ early_wake_time = rspv2->early_wake_time;
+ rsp_flags = rspv2->flags;
+ }
+ }
ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);

spin_lock_irqsave(&cctx->lock, flags);
ctx = idr_find(&cctx->ctx_idr, ctxid);
- spin_unlock_irqrestore(&cctx->lock, flags);

if (!ctx) {
- dev_err(&rpdev->dev, "No context ID matches response\n");
- return -ENOENT;
+ dev_info(&cctx->rpdev->dev, "Warning: No context ID matches response\n");
+ spin_unlock_irqrestore(&cctx->lock, flags);
+ return 0;
}

- ctx->retval = rsp->retval;
- complete(&ctx->work);
+ if (rspv2) {
+ if (rspv2->version != FASTRPC_RSP_VERSION2) {
+ dev_err(&cctx->rpdev->dev, "Incorrect response version %d\n", rspv2->version);
+ spin_unlock_irqrestore(&cctx->lock, flags);
+ return -EINVAL;
+ }
+ }
+ fastrpc_notify_user_ctx(ctx, rsp->retval, rsp_flags, early_wake_time);
+ spin_unlock_irqrestore(&cctx->lock, flags);

/*
* The DMA buffer associated with the context cannot be freed in
--
2.17.0


2024-02-02 06:44:57

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 13/16] misc: fastrpc: Add wakelock management support

CPU can go into suspend mode at anytime. Users might have a
requirement to keep the CPU awake until they get a response for
their remote call to DSP. Wakelock management can be used to
achieve this requirement.

Co-developed-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 98 ++++++++++++++++++++++++++++++++++++-
include/uapi/misc/fastrpc.h | 10 ++++
2 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index d1be89f84214..2b24d1f96978 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -125,6 +125,11 @@
/* Process status notifications from DSP will be sent with this unique context */
#define FASTRPC_NOTIF_CTX_RESERVED 0xABCDABCD

+/* Maximum PM timeout that can be voted through fastrpc */
+#define FASTRPC_MAX_PM_TIMEOUT_MS 50
+#define FASTRPC_NON_SECURE_WAKE_SOURCE_CLIENT_NAME "fastrpc-non_secure"
+#define FASTRPC_SECURE_WAKE_SOURCE_CLIENT_NAME "fastrpc-secure"
+
#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)

#define AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME "audio_pdr_adsp"
@@ -419,6 +424,10 @@ struct fastrpc_channel_ctx {
struct fastrpc_device *secure_fdevice;
struct fastrpc_device *fdevice;
struct list_head rmaps;
+ /* Secure subsystems like ADSP/SLPI will use secure client */
+ struct wakeup_source *wake_source_secure;
+ /* Non-secure subsystem like CDSP will use regular client */
+ struct wakeup_source *wake_source;
bool secure;
bool unsigned_support;
bool cpuinfo_status;
@@ -449,6 +458,8 @@ struct fastrpc_user {
u32 profile;
/* Threads poll for specified timeout and fall back to glink wait */
u32 poll_timeout;
+ u32 ws_timeout;
+ u32 wake_enable;
int tgid;
int pd;
bool is_secure_dev;
@@ -997,6 +1008,43 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
spin_unlock_irqrestore(&cctx->lock, flags);
}

+static void fastrpc_pm_awake(struct fastrpc_user *fl,
+ u32 is_secure_channel)
+{
+ struct fastrpc_channel_ctx *cctx = fl->cctx;
+ struct wakeup_source *wake_source = NULL;
+
+ /*
+ * Vote with PM to abort any suspend in progress and
+ * keep system awake for specified timeout
+ */
+ if (is_secure_channel)
+ wake_source = cctx->wake_source_secure;
+ else
+ wake_source = cctx->wake_source;
+
+ if (wake_source)
+ pm_wakeup_ws_event(wake_source, fl->ws_timeout, true);
+}
+
+static void fastrpc_pm_relax(struct fastrpc_user *fl,
+ u32 is_secure_channel)
+{
+ struct fastrpc_channel_ctx *cctx = fl->cctx;
+ struct wakeup_source *wake_source = NULL;
+
+ if (!fl->wake_enable)
+ return;
+
+ if (is_secure_channel)
+ wake_source = cctx->wake_source_secure;
+ else
+ wake_source = cctx->wake_source;
+
+ if (wake_source)
+ __pm_relax(wake_source);
+}
+
static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
{
@@ -2070,6 +2118,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
fastrpc_buf_free(buf);
}

+ fastrpc_pm_relax(fl, cctx->secure);
fastrpc_session_free(cctx, fl->sctx);
fastrpc_channel_ctx_put(cctx);

@@ -2357,14 +2406,32 @@ static int fastrpc_internal_control(struct fastrpc_user *fl,
case FASTRPC_CONTROL_SMMU:
fl->sharedcb = cp->smmu.sharedcb;
break;
- case FASTRPC_CONTROL_RPC_POLL:
- err = fastrpc_manage_poll_mode(fl, cp->lp.enable, cp->lp.latency);
+ case FASTRPC_CONTROL_WAKELOCK:
+ if (!fl->is_secure_dev) {
+ dev_err(&fl->cctx->rpdev->dev,
+ "PM voting not allowed for non-secure device node");
+ err = -EPERM;
+ return err;
+ }
+ fl->wake_enable = cp->wp.enable;
+ break;
+ case FASTRPC_CONTROL_PM:
+ if (!fl->wake_enable)
+ return -EACCES;
+ if (cp->pm.timeout > FASTRPC_MAX_PM_TIMEOUT_MS)
+ fl->ws_timeout = FASTRPC_MAX_PM_TIMEOUT_MS;
+ else
+ fl->ws_timeout = cp->pm.timeout;
+ fastrpc_pm_awake(fl, fl->cctx->secure);
break;
case FASTRPC_CONTROL_DSPPROCESS_CLEAN:
err = fastrpc_release_current_dsp_process(fl);
if (!err)
fastrpc_queue_pd_status(fl, fl->cctx->domain_id, FASTRPC_USERPD_FORCE_KILL);
break;
+ case FASTRPC_CONTROL_RPC_POLL:
+ err = fastrpc_manage_poll_mode(fl, cp->lp.enable, cp->lp.latency);
+ break;
default:
err = -EBADRQC;
break;
@@ -3268,6 +3335,21 @@ static int fastrpc_setup_service_locator(struct fastrpc_channel_ctx *cctx, char
return err;
}

+static void fastrpc_register_wakeup_source(struct device *dev,
+ const char *client_name, struct wakeup_source **device_wake_source)
+{
+ struct wakeup_source *wake_source = NULL;
+
+ wake_source = wakeup_source_register(dev, client_name);
+ if (IS_ERR_OR_NULL(wake_source)) {
+ dev_err(dev, "wakeup_source_register failed for dev %s, client %s with err %ld\n",
+ dev_name(dev), client_name, PTR_ERR(wake_source));
+ return;
+ }
+
+ *device_wake_source = wake_source;
+}
+
static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
{
struct device *rdev = &rpdev->dev;
@@ -3368,6 +3450,13 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
goto populate_error;
}

+ if (data->fdevice)
+ fastrpc_register_wakeup_source(data->fdevice->miscdev.this_device,
+ FASTRPC_NON_SECURE_WAKE_SOURCE_CLIENT_NAME, &data->wake_source);
+ if (data->secure_fdevice)
+ fastrpc_register_wakeup_source(data->secure_fdevice->miscdev.this_device,
+ FASTRPC_SECURE_WAKE_SOURCE_CLIENT_NAME, &data->wake_source_secure);
+
kref_init(&data->refcount);

dev_set_drvdata(&rpdev->dev, data);
@@ -3421,6 +3510,11 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
pdr_handle_release(cctx->spd[0].pdrhandle);
}

+ if (cctx->wake_source)
+ wakeup_source_unregister(cctx->wake_source);
+ if (cctx->wake_source_secure)
+ wakeup_source_unregister(cctx->wake_source_secure);
+
if (cctx->fdevice)
misc_deregister(&cctx->fdevice->miscdev);

diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index a3bc6666a653..f4c73f6774f7 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -187,11 +187,21 @@ struct fastrpc_ctrl_latency {
u32 latency; /* latency request in us */
};

+struct fastrpc_ctrl_wakelock {
+ u32 enable; /* wakelock control enable */
+};
+
+struct fastrpc_ctrl_pm {
+ u32 timeout; /* timeout(in ms) for PM to keep system awake */
+};
+
struct fastrpc_internal_control {
u32 req;
union {
struct fastrpc_ctrl_smmu smmu;
struct fastrpc_ctrl_latency lp;
+ struct fastrpc_ctrl_wakelock wp;
+ struct fastrpc_ctrl_pm pm;
};
};

--
2.17.0


2024-02-02 06:45:11

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 15/16] misc: fastrpc: Restrict untrusted apk to spawn privileged PD

Untrusted application can attach to guestOS and staticPD if it can
make root PD, sensors PD or audio PD attach request. This is a
potential security issue as the untrusted application can crash
rootPD or staticPD. Restrict attach to guestOS or staticPD request
if request is being made using non-secure device node.

Also for untrusted dynamic processes, DSP HAL process opens the
device node on behalf of the application. Add a check to restrict
such untrusted applications from offloading to signed PD.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 35 +++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 0308f717456f..4aa4e36bebc3 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -471,6 +471,7 @@ struct fastrpc_user {
bool sharedcb;
/* If set, threads will poll for DSP response instead of glink wait */
bool poll_mode;
+ bool untrusted_process;
char *servloc_name;
/* Lock for lists */
spinlock_t lock;
@@ -1722,20 +1723,24 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,

static bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_request)
{
- /* Check if the device node is non-secure and channel is secure*/
+ /* Check if the device node is non-secure and channel is secure */
if (!fl->is_secure_dev && fl->cctx->secure) {
/*
* Allow untrusted applications to offload only to Unsigned PD when
* channel is configured as secure and block untrusted apps on channel
* that does not support unsigned PD offload
*/
- if (!fl->cctx->unsigned_support || !unsigned_pd_request) {
- dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD");
- return true;
- }
+ if (!fl->cctx->unsigned_support || !unsigned_pd_request)
+ goto reject_session;
}
+ /* Check if untrusted process is trying to offload to signed PD */
+ if (fl->untrusted_process && !unsigned_pd_request)
+ goto reject_session;

return false;
+reject_session:
+ dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD");
+ return true;
}

static int fastrpc_mmap_remove_ssr(struct fastrpc_channel_ctx *cctx)
@@ -1822,6 +1827,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
u32 pageslen;
} inbuf;

+ if (!fl->is_secure_dev) {
+ dev_err(&fl->cctx->rpdev->dev, "untrusted app trying to attach to privileged DSP PD\n");
+ return -EACCES;
+ }
+
args = kcalloc(FASTRPC_CREATE_STATIC_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
if (!args)
return -ENOMEM;
@@ -1981,11 +1991,19 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
goto err;
}

+ /*
+ * Third-party apps don't have permission to open the fastrpc device, so
+ * it is opened on their behalf by DSP HAL. This is detected by
+ * comparing current PID with the one stored during device open.
+ */
+ if (current->tgid != fl->tgid)
+ fl->untrusted_process = true;
+
if (init.attrs & FASTRPC_MODE_UNSIGNED_MODULE)
fl->is_unsigned_pd = true;

if (is_session_rejected(fl, fl->is_unsigned_pd)) {
- err = -ECONNREFUSED;
+ err = -EACCES;
goto err;
}

@@ -2244,6 +2262,11 @@ static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
struct fastrpc_enhanced_invoke ioctl;
int tgid = fl->tgid;

+ if (!fl->is_secure_dev) {
+ dev_err(&fl->cctx->rpdev->dev, "untrusted app trying to attach to privileged DSP PD\n");
+ return -EACCES;
+ }
+
fl->sctx = fastrpc_session_alloc(fl->cctx, fl->sharedcb);
if (!fl->sctx)
return -EBUSY;
--
2.17.0


2024-02-02 06:45:35

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 16/16] misc: fastrpc: Add system unsigned PD support

Trusted CPU applications currently offload to signed PDs on CDSP to
gain some additional services provided by root PD. Unsigned PDs have
access to limited root PD services that may not be sufficient for
all use-cases. Signed PDs have a higher dynamic loading latency
which impacts the performance of applications. Limited root PD
services could be opened up for unsigned PDs but that should be
restricted for untrusted processes. For this requirement, System
unsigned PD is introduced which will be same as Unsigned PD for
most part but will have access to more root PD services. Add
changes to offload trusted applications to System unsigned PD
when unsigned offload is requested.

Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 7 +++++++
include/uapi/misc/fastrpc.h | 2 ++
2 files changed, 9 insertions(+)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 4aa4e36bebc3..2f893c94dcc8 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -2002,11 +2002,18 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
if (init.attrs & FASTRPC_MODE_UNSIGNED_MODULE)
fl->is_unsigned_pd = true;

+ /* Disregard any system unsigned PD attribute from userspace */
+ init.attrs &= (~FASTRPC_MODE_SYSTEM_UNSIGNED_PD);
+
if (is_session_rejected(fl, fl->is_unsigned_pd)) {
err = -EACCES;
goto err;
}

+ /* Trusted apps will be launched as system unsigned PDs */
+ if (!fl->untrusted_process && fl->is_unsigned_pd)
+ init.attrs |= FASTRPC_MODE_SYSTEM_UNSIGNED_PD;
+
if (init.filelen > INIT_FILELEN_MAX) {
err = -EINVAL;
goto err;
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index 7053a5b6b16b..d0fb01e7277d 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -63,6 +63,8 @@ enum fastrpc_proc_attr {
FASTRPC_MODE_SYSTEM_PROCESS = (1 << 5),
/* Macro for Prvileged Process */
FASTRPC_MODE_PRIVILEGED = (1 << 6),
+ /* Macro for system unsigned PD */
+ FASTRPC_MODE_SYSTEM_UNSIGNED_PD = (1 << 17),
};

/* Fastrpc attribute for memory protection of buffers */
--
2.17.0


2024-02-02 06:48:26

by Ekansh Gupta

[permalink] [raw]
Subject: [PATCH v1 14/16] misc: fastrpc: Add DSP signal support

Add a dedicated signaling channel between fastrpc driver and DSP
root PD, with a new dsp signaling interface between the userspace
framework and drivers. This makes dspqueue signaling latency
comparable to or better than synchronous FastRPC calls, and reduces
the processing overhead since the signaling code path is simpler than
synchronous FastRPC calls.

Co-developed-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Anandu Krishnan E <[email protected]>
Signed-off-by: Ekansh Gupta <[email protected]>
---
drivers/misc/fastrpc.c | 307 +++++++++++++++++++++++++++++++++++-
include/uapi/misc/fastrpc.h | 17 ++
2 files changed, 323 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 2b24d1f96978..0308f717456f 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -144,6 +144,10 @@
#define SENSORS_PDR_SLPI_SERVICE_NAME SENSORS_PDR_ADSP_SERVICE_NAME
#define SLPI_SENSORPD_NAME "msm/slpi/sensor_pd"

+#define FASTRPC_DSPSIGNAL_TIMEOUT_NONE 0xffffffff
+#define FASTRPC_DSPSIGNAL_NUM_SIGNALS 1024
+#define FASTRPC_DSPSIGNAL_GROUP_SIZE 256
+
#define PERF_END ((void)0)

#define PERF(enb, cnt, ff) \
@@ -470,8 +474,25 @@ struct fastrpc_user {
char *servloc_name;
/* Lock for lists */
spinlock_t lock;
+ /* lock for dsp signals */
+ spinlock_t dspsignals_lock;
/* lock for allocations */
struct mutex mutex;
+ struct mutex signal_create_mutex;
+ /* Completion objects and state for dspsignals */
+ struct fastrpc_dspsignal *signal_groups[FASTRPC_DSPSIGNAL_NUM_SIGNALS / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+};
+
+enum fastrpc_dspsignal_state {
+ DSPSIGNAL_STATE_UNUSED = 0,
+ DSPSIGNAL_STATE_PENDING,
+ DSPSIGNAL_STATE_SIGNALED,
+ DSPSIGNAL_STATE_CANCELED,
+};
+
+struct fastrpc_dspsignal {
+ struct completion comp;
+ int state;
};

static inline int64_t getnstimediff(struct timespec64 *start)
@@ -2098,6 +2119,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
struct fastrpc_map *map, *m;
struct fastrpc_buf *buf, *b;
unsigned long flags;
+ int i;

fastrpc_release_current_dsp_process(fl);

@@ -2122,6 +2144,10 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
fastrpc_session_free(cctx, fl->sctx);
fastrpc_channel_ctx_put(cctx);

+ for (i = 0; i < (FASTRPC_DSPSIGNAL_NUM_SIGNALS / FASTRPC_DSPSIGNAL_GROUP_SIZE); i++)
+ kfree(fl->signal_groups[i]);
+
+ mutex_destroy(&fl->signal_create_mutex);
mutex_destroy(&fl->mutex);
kfree(fl);
file->private_data = NULL;
@@ -2149,6 +2175,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
filp->private_data = fl;
spin_lock_init(&fl->lock);
mutex_init(&fl->mutex);
+ spin_lock_init(&fl->dspsignals_lock);
+ mutex_init(&fl->signal_create_mutex);
INIT_LIST_HEAD(&fl->pending);
INIT_LIST_HEAD(&fl->interrupted);
INIT_LIST_HEAD(&fl->maps);
@@ -2439,12 +2467,235 @@ static int fastrpc_internal_control(struct fastrpc_user *fl,
return err;
}

+static int fastrpc_dspsignal_signal(struct fastrpc_user *fl,
+ struct fastrpc_internal_dspsignal *fsig)
+{
+ int err = 0;
+ struct fastrpc_channel_ctx *cctx = NULL;
+ u64 msg = 0;
+ u32 signal_id = fsig->signal_id;
+
+ cctx = fl->cctx;
+
+ if (!(signal_id < FASTRPC_DSPSIGNAL_NUM_SIGNALS))
+ return -EINVAL;
+
+ msg = (((uint64_t)fl->tgid) << 32) | ((uint64_t)fsig->signal_id);
+ err = rpmsg_send(cctx->rpdev->ept, (void *)&msg, sizeof(msg));
+
+ return err;
+}
+
+static int fastrpc_dspsignal_wait(struct fastrpc_user *fl,
+ struct fastrpc_internal_dspsignal *fsig)
+{
+ int err = 0;
+ unsigned long timeout = usecs_to_jiffies(fsig->timeout_usec);
+ u32 signal_id = fsig->signal_id;
+ struct fastrpc_dspsignal *s = NULL;
+ long ret = 0;
+ unsigned long irq_flags = 0;
+
+ if (!(signal_id < FASTRPC_DSPSIGNAL_NUM_SIGNALS))
+ return -EINVAL;
+
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+ if (fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE] != NULL) {
+ struct fastrpc_dspsignal *group =
+ fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+
+ s = &group[signal_id % FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ }
+ if ((s == NULL) || (s->state == DSPSIGNAL_STATE_UNUSED)) {
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ dev_err(&fl->cctx->rpdev->dev, "Unknown signal id %u\n", signal_id);
+ return -ENOENT;
+ }
+ if (s->state != DSPSIGNAL_STATE_PENDING) {
+ if ((s->state == DSPSIGNAL_STATE_CANCELED) || (s->state == DSPSIGNAL_STATE_UNUSED))
+ err = -EINTR;
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ dev_dbg(&fl->cctx->rpdev->dev, "Signal %u in state %u, complete wait immediately",
+ signal_id, s->state);
+ return err;
+ }
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+
+ if (timeout != 0xffffffff)
+ ret = wait_for_completion_interruptible_timeout(&s->comp, timeout);
+ else
+ ret = wait_for_completion_interruptible(&s->comp);
+
+ if (ret == 0) {
+ dev_dbg(&fl->cctx->rpdev->dev, "Wait for signal %u timed out\n", signal_id);
+ return -ETIMEDOUT;
+ } else if (ret < 0) {
+ dev_err(&fl->cctx->rpdev->dev, "Wait for signal %u failed %d\n", signal_id, (int)ret);
+ return ret;
+ }
+
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+ if (s->state == DSPSIGNAL_STATE_SIGNALED) {
+ s->state = DSPSIGNAL_STATE_PENDING;
+ } else if ((s->state == DSPSIGNAL_STATE_CANCELED) || (s->state == DSPSIGNAL_STATE_UNUSED)) {
+ dev_err(&fl->cctx->rpdev->dev, "Signal %u cancelled or destroyed\n", signal_id);
+ err = -EINTR;
+ }
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+
+ return err;
+}
+
+static int fastrpc_dspsignal_create(struct fastrpc_user *fl,
+ struct fastrpc_internal_dspsignal *fsig)
+{
+ int err = 0;
+ u32 signal_id = fsig->signal_id;
+ struct fastrpc_dspsignal *group, *sig;
+ unsigned long irq_flags = 0;
+
+ if (!(signal_id < FASTRPC_DSPSIGNAL_NUM_SIGNALS))
+ return -EINVAL;
+
+ mutex_lock(&fl->signal_create_mutex);
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+
+ group = fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ if (group == NULL) {
+ int i;
+
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ group = kcalloc(FASTRPC_DSPSIGNAL_GROUP_SIZE, sizeof(*group),
+ GFP_KERNEL);
+ if (group == NULL) {
+ mutex_unlock(&fl->signal_create_mutex);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < FASTRPC_DSPSIGNAL_GROUP_SIZE; i++) {
+ sig = &group[i];
+ init_completion(&sig->comp);
+ sig->state = DSPSIGNAL_STATE_UNUSED;
+ }
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+ fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE] = group;
+ }
+
+ sig = &group[signal_id % FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ if (sig->state != DSPSIGNAL_STATE_UNUSED) {
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ mutex_unlock(&fl->signal_create_mutex);
+ dev_err(&fl->cctx->rpdev->dev, "Attempting to create signal %u already in use (state %u)\n",
+ signal_id, sig->state);
+ return -EBUSY;
+ }
+
+ sig->state = DSPSIGNAL_STATE_PENDING;
+ reinit_completion(&sig->comp);
+
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ mutex_unlock(&fl->signal_create_mutex);
+
+ return err;
+}
+
+static int fastrpc_dspsignal_destroy(struct fastrpc_user *fl,
+ struct fastrpc_internal_dspsignal *fsig)
+{
+ u32 signal_id = fsig->signal_id;
+ struct fastrpc_dspsignal *s = NULL;
+ unsigned long irq_flags = 0;
+
+ if (!(signal_id < FASTRPC_DSPSIGNAL_NUM_SIGNALS))
+ return -EINVAL;
+
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+
+ if (fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE] != NULL) {
+ struct fastrpc_dspsignal *group =
+ fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+
+ s = &group[signal_id % FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ }
+ if ((s == NULL) || (s->state == DSPSIGNAL_STATE_UNUSED)) {
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ dev_err(&fl->cctx->rpdev->dev, "Attempting to destroy unused signal %u\n", signal_id);
+ return -ENOENT;
+ }
+
+ s->state = DSPSIGNAL_STATE_UNUSED;
+ complete_all(&s->comp);
+
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+
+ return 0;
+}
+
+static int fastrpc_dspsignal_cancel_wait(struct fastrpc_user *fl,
+ struct fastrpc_internal_dspsignal *fsig)
+{
+ u32 signal_id = fsig->signal_id;
+ struct fastrpc_dspsignal *s = NULL;
+ unsigned long irq_flags = 0;
+
+ if (!(signal_id < FASTRPC_DSPSIGNAL_NUM_SIGNALS))
+ return -EINVAL;
+
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+
+ if (fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE] != NULL) {
+ struct fastrpc_dspsignal *group =
+ fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+
+ s = &group[signal_id % FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ }
+ if ((s == NULL) || (s->state == DSPSIGNAL_STATE_UNUSED)) {
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+ dev_err(&fl->cctx->rpdev->dev, "Attempting to cancel unused signal %u\n", signal_id);
+ return -ENOENT;
+ }
+
+ if (s->state != DSPSIGNAL_STATE_CANCELED) {
+ s->state = DSPSIGNAL_STATE_CANCELED;
+ complete_all(&s->comp);
+ }
+
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+
+ return 0;
+}
+
+static int fastrpc_invoke_dspsignal(struct fastrpc_user *fl, struct fastrpc_internal_dspsignal *fsig)
+{
+ int err = 0;
+
+ switch (fsig->req) {
+ case FASTRPC_DSPSIGNAL_SIGNAL:
+ err = fastrpc_dspsignal_signal(fl, fsig);
+ break;
+ case FASTRPC_DSPSIGNAL_WAIT:
+ err = fastrpc_dspsignal_wait(fl, fsig);
+ break;
+ case FASTRPC_DSPSIGNAL_CREATE:
+ err = fastrpc_dspsignal_create(fl, fsig);
+ break;
+ case FASTRPC_DSPSIGNAL_DESTROY:
+ err = fastrpc_dspsignal_destroy(fl, fsig);
+ break;
+ case FASTRPC_DSPSIGNAL_CANCEL_WAIT:
+ err = fastrpc_dspsignal_cancel_wait(fl, fsig);
+ break;
+ }
+ return err;
+}
+
static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
{
struct fastrpc_enhanced_invoke einv;
struct fastrpc_invoke_args *args = NULL;
struct fastrpc_ioctl_multimode_invoke invoke;
struct fastrpc_internal_control cp = {0};
+ struct fastrpc_internal_dspsignal *fsig = NULL;
struct fastrpc_internal_notif_rsp notif;
u32 nscalars;
u64 *perf_kernel;
@@ -2465,7 +2716,7 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)
case FASTRPC_INVOKE_ENHANCED:
/* nscalars is truncated here to max supported value */
if (copy_from_user(&einv, (void __user *)(uintptr_t)invoke.invparam,
- invoke.size))
+ sizeof(struct fastrpc_enhanced_invoke)))
return -EFAULT;
for (i = 0; i < 8; i++) {
if (einv.reserved[i] != 0)
@@ -2495,6 +2746,19 @@ static int fastrpc_multimode_invoke(struct fastrpc_user *fl, char __user *argp)

err = fastrpc_internal_control(fl, &cp);
break;
+ case FASTRPC_INVOKE_DSPSIGNAL:
+ if (invoke.size > sizeof(*fsig))
+ return -EINVAL;
+ fsig = kzalloc(invoke.size, GFP_KERNEL);
+ if (!fsig)
+ return -ENOMEM;
+ if (copy_from_user(fsig, (void __user *)(uintptr_t)invoke.invparam,
+ sizeof(*fsig))) {
+ kfree(fsig);
+ return -EFAULT;
+ }
+ err = fastrpc_invoke_dspsignal(fl, fsig);
+ break;
case FASTRPC_INVOKE_NOTIF:
err = fastrpc_get_notif_response(&notif,
(void *)invoke.invparam, fl);
@@ -3526,6 +3790,42 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
fastrpc_channel_ctx_put(cctx);
}

+static void fastrpc_handle_signal_rpmsg(uint64_t msg, struct fastrpc_channel_ctx *cctx)
+{
+ u32 pid = msg >> 32;
+ u32 signal_id = msg & 0xffffffff;
+ struct fastrpc_user *fl;
+ unsigned long irq_flags = 0;
+
+ if (signal_id >= FASTRPC_DSPSIGNAL_NUM_SIGNALS)
+ return;
+
+ list_for_each_entry(fl, &cctx->users, user) {
+ if (fl->tgid == pid)
+ break;
+ }
+
+ spin_lock_irqsave(&fl->dspsignals_lock, irq_flags);
+ if (fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE]) {
+ struct fastrpc_dspsignal *group =
+ fl->signal_groups[signal_id / FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ struct fastrpc_dspsignal *sig =
+ &group[signal_id % FASTRPC_DSPSIGNAL_GROUP_SIZE];
+ if ((sig->state == DSPSIGNAL_STATE_PENDING) ||
+ (sig->state == DSPSIGNAL_STATE_SIGNALED)) {
+ complete(&sig->comp);
+ sig->state = DSPSIGNAL_STATE_SIGNALED;
+ } else if (sig->state == DSPSIGNAL_STATE_UNUSED) {
+ pr_err("Received unknown signal %u for PID %u\n",
+ signal_id, pid);
+ }
+ } else {
+ pr_err("Received unknown signal %u for PID %u\n",
+ signal_id, pid);
+ }
+ spin_unlock_irqrestore(&fl->dspsignals_lock, irq_flags);
+}
+
static void fastrpc_notify_user_ctx(struct fastrpc_invoke_ctx *ctx, int retval,
u32 rsp_flags, u32 early_wake_time)
{
@@ -3564,6 +3864,11 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
u32 rsp_flags = 0;
u32 early_wake_time = 0;

+ if (len == sizeof(uint64_t)) {
+ fastrpc_handle_signal_rpmsg(*((uint64_t *)data), cctx);
+ return 0;
+ }
+
if (notif->ctx == FASTRPC_NOTIF_CTX_RESERVED) {
if (notif->type == STATUS_RESPONSE && len >= sizeof(*notif)) {
fastrpc_notif_find_process(cctx->domain_id, cctx, notif);
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index f4c73f6774f7..7053a5b6b16b 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -211,6 +211,15 @@ struct fastrpc_internal_notif_rsp {
u32 status; /* Status of the process */
};

+struct fastrpc_internal_dspsignal {
+ u32 req;
+ u32 signal_id;
+ union {
+ u32 flags;
+ u32 timeout_usec;
+ };
+};
+
enum fastrpc_perfkeys {
PERF_COUNT = 0,
PERF_FLUSH = 1,
@@ -225,6 +234,14 @@ enum fastrpc_perfkeys {
PERF_KEY_MAX = 10,
};

+enum fastrpc_dspsignal_type {
+ FASTRPC_DSPSIGNAL_SIGNAL = 1,
+ FASTRPC_DSPSIGNAL_WAIT = 2,
+ FASTRPC_DSPSIGNAL_CREATE = 3,
+ FASTRPC_DSPSIGNAL_DESTROY = 4,
+ FASTRPC_DSPSIGNAL_CANCEL_WAIT = 5,
+};
+
enum fastrpc_status_flags {
FASTRPC_USERPD_UP = 0,
FASTRPC_USERPD_EXIT = 1,
--
2.17.0


2024-02-02 08:29:50

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v1 00/16] Add missing features to FastRPC driver

Hi,

On 02/02/2024 07:40, Ekansh Gupta wrote:
> This patch series adds the listed features that have been missing
> in upstream fastRPC driver.
>
> - Redesign and improve remote heap management.
> - Add static PD restart support for audio and sensors PD using
> PDR framework.
> - Add changes to support multimode invocation ioctl request. This
> ioctl call facilitates multiple types of requests from user including
> CRC check, performance counters, shared context bank usage, etc.
> This series also carries patch to save and restore interrupted
> context.
> - Add early wakeup support to allow DSP user to send early response
> to CPU and improve fastrpc performance.
> - Add polling mode support with which driver polls on memory to avoid
> CPU from going to low power modes.
> - Add notifications frameworks to provide users with the DSP PD status
> notifications.
> - Add a control mechanism to allow users to clean up DSP user PD
> - Add wakelock management support
> - Add DSP signalling support
> - Add check for untrusted applications and allow trusted processed to
> offload to system unsigned PD.

Could you precise:
- Which workload are you fixing
- Which platforms are concerned
- Which platforms were tested

So far I've been trying to run the "getserial" on SM8550-QRD and SM8650-QRD without
success, would those changes fix this ?
Is there any chance we could get an open-source minimal implementation of a fastRPC SDK using
the open-source Hexagon LLVM like we have for the AIC100 ?
It would definitely help validating the upstream fastRPC implementation.

Thanks,
Neil

>
> Ekansh Gupta (16):
> misc: fastrpc: Redesign remote heap management
> misc: fastrpc: Add support for unsigned PD
> misc: fastrpc: Add static PD restart support
> misc: fastrpc: Add fastrpc multimode invoke request support
> misc: fastrpc: Add CRC support for remote buffers
> misc: fastrpc: Capture kernel and DSP performance counters
> misc: fastrpc: Add support to save and restore interrupted
> misc: fastrpc: Add support to allocate shared context bank
> misc: fastrpc: Add early wakeup support for fastRPC driver
> misc: fastrpc: Add polling mode support for fastRPC driver
> misc: fastrpc: Add DSP PD notification support
> misc: fastrpc: Add support for users to clean up DSP user PD
> misc: fastrpc: Add wakelock management support
> misc: fastrpc: Add DSP signal support
> misc: fastrpc: Restrict untrusted apk to spawn privileged PD
> misc: fastrpc: Add system unsigned PD support
>
> drivers/misc/fastrpc.c | 1949 +++++++++++++++++++++++++++++++----
> include/uapi/misc/fastrpc.h | 112 ++
> 2 files changed, 1844 insertions(+), 217 deletions(-)
>


2024-02-02 14:43:40

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH v1 02/16] misc: fastrpc: Add support for unsigned PD

On Fri, Feb 02, 2024 at 12:10:25PM +0530, Ekansh Gupta wrote:
> Unsigned PD requires more initial memory to spawn.

What exactly is "Unsigned PD"?

And where are all of the userspace changes for this series so we can
verify they work properly?

thanks,

greg k-h

2024-02-03 15:38:20

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 03/16] misc: fastrpc: Add static PD restart support

Hi Ekansh,

kernel test robot noticed the following build errors:

[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on char-misc/char-misc-next char-misc/char-misc-linus linus/master v6.8-rc2 next-20240202]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Ekansh-Gupta/misc-fastrpc-Redesign-remote-heap-management/20240202-144921
base: char-misc/char-misc-testing
patch link: https://lore.kernel.org/r/20240202064039.15505-4-quic_ekangupt%40quicinc.com
patch subject: [PATCH v1 03/16] misc: fastrpc: Add static PD restart support
config: i386-buildonly-randconfig-006-20240203 (https://download.01.org/0day-ci/archive/20240203/[email protected]/config)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240203/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

ld: drivers/misc/fastrpc.o: in function `fastrpc_setup_service_locator.constprop.0':
>> fastrpc.c:(.text+0x752): undefined reference to `pdr_handle_alloc'
>> ld: fastrpc.c:(.text+0x781): undefined reference to `pdr_add_lookup'
ld: drivers/misc/fastrpc.o: in function `fastrpc_rpmsg_remove':
>> fastrpc.c:(.text+0x16f4): undefined reference to `pdr_handle_release'
>> ld: fastrpc.c:(.text+0x16ff): undefined reference to `pdr_handle_release'
ld: fastrpc.c:(.text+0x172c): undefined reference to `pdr_handle_release'

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2024-02-04 01:10:44

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 03/16] misc: fastrpc: Add static PD restart support

Hi Ekansh,

kernel test robot noticed the following build errors:

[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on char-misc/char-misc-next char-misc/char-misc-linus linus/master v6.8-rc2 next-20240202]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Ekansh-Gupta/misc-fastrpc-Redesign-remote-heap-management/20240202-144921
base: char-misc/char-misc-testing
patch link: https://lore.kernel.org/r/20240202064039.15505-4-quic_ekangupt%40quicinc.com
patch subject: [PATCH v1 03/16] misc: fastrpc: Add static PD restart support
config: arm64-randconfig-r053-20240203 (https://download.01.org/0day-ci/archive/20240204/[email protected]/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240204/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: pdr_handle_alloc
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_probe) in archive vmlinux.a
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_probe) in archive vmlinux.a
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_setup_service_locator) in archive vmlinux.a
--
>> ld.lld: error: undefined symbol: pdr_add_lookup
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_probe) in archive vmlinux.a
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_probe) in archive vmlinux.a
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_setup_service_locator) in archive vmlinux.a
--
>> ld.lld: error: undefined symbol: pdr_handle_release
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_remove) in archive vmlinux.a
>>> referenced by fastrpc.c
>>> drivers/misc/fastrpc.o:(fastrpc_rpmsg_remove) in archive vmlinux.a

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2024-02-04 04:27:57

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 08/16] misc: fastrpc: Add support to allocate shared context bank

Hi Ekansh,

kernel test robot noticed the following build errors:

[auto build test ERROR on char-misc/char-misc-testing]
[also build test ERROR on char-misc/char-misc-next char-misc/char-misc-linus linus/master v6.8-rc2 next-20240202]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Ekansh-Gupta/misc-fastrpc-Redesign-remote-heap-management/20240202-144921
base: char-misc/char-misc-testing
patch link: https://lore.kernel.org/r/20240202064039.15505-9-quic_ekangupt%40quicinc.com
patch subject: [PATCH v1 08/16] misc: fastrpc: Add support to allocate shared context bank
config: i386-buildonly-randconfig-001-20240203 (https://download.01.org/0day-ci/archive/20240204/[email protected]/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240204/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from <built-in>:1:
>> ./usr/include/misc/fastrpc.h:182:2: error: unknown type name 'u32'
182 | u32 sharedcb; /* Set to SMMU share context bank */
| ^
./usr/include/misc/fastrpc.h:186:2: error: unknown type name 'u32'
186 | u32 req;
| ^
2 errors generated.

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2024-02-07 08:30:46

by Ekansh Gupta

[permalink] [raw]
Subject: Re: [PATCH v1 00/16] Add missing features to FastRPC driver


On 2/2/2024 1:41 PM, [email protected] wrote:
> Hi,
>
> On 02/02/2024 07:40, Ekansh Gupta wrote:
>> This patch series adds the listed features that have been missing
>> in upstream fastRPC driver.
>>
>> - Redesign and improve remote heap management.
>> - Add static PD restart support for audio and sensors PD using
>>    PDR framework.
>> - Add changes to support multimode invocation ioctl request. This
>>    ioctl call facilitates multiple types of requests from user including
>>    CRC check, performance counters, shared context bank usage, etc.
>>    This series also carries patch to save and restore interrupted
>>    context.
>> - Add early wakeup support to allow DSP user to send early response
>>    to CPU and improve fastrpc performance.
>> - Add polling mode support with which driver polls on memory to avoid
>>    CPU from going to low power modes.
>> - Add notifications frameworks to provide users with the DSP PD status
>>    notifications.
>> - Add a control mechanism to allow users to clean up DSP user PD
>> - Add wakelock management support
>> - Add DSP signalling support
>> - Add check for untrusted applications and allow trusted processed to
>>    offload to system unsigned PD.
>
> Could you precise:
> - Which workload are you fixing
> - Which platforms are concerned
> - Which platforms were tested
>
1. This patch mostly consists of missing features from fastrpc driver and it doesn't
carry any bug fixes.
2. We are not targeting these changes for any specific platform. These features are
applicable for most of the recent platforms .
3. These changes were tested on SM8650 and QCM6490 platforms.

> So far I've been trying to run the "getserial" on SM8550-QRD and
> SM8650-QRD without
> success, would those changes fix this ?

Can you please help me with the "getserial" failure details? Or the steps that you are
running to get to the failure? I can have a look at that to understand the reason for
failure.

> Is there any chance we could get an open-source minimal implementation
> of a fastRPC SDK using
> the open-source Hexagon LLVM like we have for the AIC100 ?
> It would definitely help validating the upstream fastRPC implementation.

Generally Hexagon SDK is used to write and test fastRPC use-cases which is well documented.
Is there anything else that you can suggest would help here?

>
> Thanks,
> Neil
>
Hi Neil, added my comments.

--ekansh

>>
>> Ekansh Gupta (16):
>>    misc: fastrpc: Redesign remote heap management
>>    misc: fastrpc: Add support for unsigned PD
>>    misc: fastrpc: Add static PD restart support
>>    misc: fastrpc: Add fastrpc multimode invoke request support
>>    misc: fastrpc: Add CRC support for remote buffers
>>    misc: fastrpc: Capture kernel and DSP performance counters
>>    misc: fastrpc: Add support to save and restore interrupted
>>    misc: fastrpc: Add support to allocate shared context bank
>>    misc: fastrpc: Add early wakeup support for fastRPC driver
>>    misc: fastrpc: Add polling mode support for fastRPC driver
>>    misc: fastrpc: Add DSP PD notification support
>>    misc: fastrpc: Add support for users to clean up DSP user PD
>>    misc: fastrpc: Add wakelock management support
>>    misc: fastrpc: Add DSP signal support
>>    misc: fastrpc: Restrict untrusted apk to spawn privileged PD
>>    misc: fastrpc: Add system unsigned PD support
>>
>>   drivers/misc/fastrpc.c      | 1949 +++++++++++++++++++++++++++++++----
>>   include/uapi/misc/fastrpc.h |  112 ++
>>   2 files changed, 1844 insertions(+), 217 deletions(-)
>>
>

2024-02-07 08:57:54

by Ekansh Gupta

[permalink] [raw]
Subject: Re: [PATCH v1 02/16] misc: fastrpc: Add support for unsigned PD


On 2/2/2024 8:13 PM, Greg KH wrote:
> On Fri, Feb 02, 2024 at 12:10:25PM +0530, Ekansh Gupta wrote:
>> Unsigned PD requires more initial memory to spawn.
> What exactly is "Unsigned PD"?
>
> And where are all of the userspace changes for this series so we can
> verify they work properly?
>
> thanks,
>
> greg k-h

Hi Greg,
Unsigned PDs are sandboxed DSP processes used to offload computation
workloads to the DSP. Unsigned PD have less privileges in terms of
DSP resource access as compared to Signed PD.

Unsigned PD can be enabled using userspace API:
https://git.codelinaro.org/linaro/qcomlt/fastrpc/-/blob/master/src/fastrpc_apps_user.c?ref_type=heads#L1173

For multimode invoke request(other feature) also I've shared the
userspace changes with Srini which he will be pulling to userspace
project.

Please let me know if you have any other queries.

Thanks
--ekansh


2024-02-07 09:52:50

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [PATCH v1 00/16] Add missing features to FastRPC driver

On Wed, 7 Feb 2024 at 10:30, Ekansh Gupta <[email protected]> wrote:
>
>
> On 2/2/2024 1:41 PM, [email protected] wrote:
> > Hi,
> >
> > On 02/02/2024 07:40, Ekansh Gupta wrote:
> >> This patch series adds the listed features that have been missing
> >> in upstream fastRPC driver.
> >>
> >> - Redesign and improve remote heap management.
> >> - Add static PD restart support for audio and sensors PD using
> >> PDR framework.
> >> - Add changes to support multimode invocation ioctl request. This
> >> ioctl call facilitates multiple types of requests from user including
> >> CRC check, performance counters, shared context bank usage, etc.
> >> This series also carries patch to save and restore interrupted
> >> context.
> >> - Add early wakeup support to allow DSP user to send early response
> >> to CPU and improve fastrpc performance.
> >> - Add polling mode support with which driver polls on memory to avoid
> >> CPU from going to low power modes.
> >> - Add notifications frameworks to provide users with the DSP PD status
> >> notifications.
> >> - Add a control mechanism to allow users to clean up DSP user PD
> >> - Add wakelock management support
> >> - Add DSP signalling support
> >> - Add check for untrusted applications and allow trusted processed to
> >> offload to system unsigned PD.
> >
> > Could you precise:
> > - Which workload are you fixing
> > - Which platforms are concerned
> > - Which platforms were tested
> >
> 1. This patch mostly consists of missing features from fastrpc driver and it doesn't
> carry any bug fixes.
> 2. We are not targeting these changes for any specific platform. These features are
> applicable for most of the recent platforms .

Please define 'recent'. The upstream kernel supports a wide set of
platforms. We have fastrpc supported since msm8916. Please make sure
that your patches will not break on such platforms.

> 3. These changes were tested on SM8650 and QCM6490 platforms.
>
> > So far I've been trying to run the "getserial" on SM8550-QRD and
> > SM8650-QRD without
> > success, would those changes fix this ?
>
> Can you please help me with the "getserial" failure details? Or the steps that you are
> running to get to the failure? I can have a look at that to understand the reason for
> failure.
>
> > Is there any chance we could get an open-source minimal implementation
> > of a fastRPC SDK using
> > the open-source Hexagon LLVM like we have for the AIC100 ?
> > It would definitely help validating the upstream fastRPC implementation.
>
> Generally Hexagon SDK is used to write and test fastRPC use-cases which is well documented.
> Is there anything else that you can suggest would help here?

Hexagon SDK is a closed source toolkit. Both in terms of toolchain,
library code and generated code.
The fastrpc_shell_N, which is used to handle loaded code, is also
closed source. As such, it is nearly impossible to verify the code.
Please consider the requirements for the drivers/accel/ subsystem: to
have complete open source userspace. Qualcomm AIC100, for example,
fulfills those requirements.

>
> >
> > Thanks,
> > Neil
> >
> Hi Neil, added my comments.
>
> --ekansh
>
> >>
> >> Ekansh Gupta (16):
> >> misc: fastrpc: Redesign remote heap management
> >> misc: fastrpc: Add support for unsigned PD
> >> misc: fastrpc: Add static PD restart support
> >> misc: fastrpc: Add fastrpc multimode invoke request support
> >> misc: fastrpc: Add CRC support for remote buffers
> >> misc: fastrpc: Capture kernel and DSP performance counters
> >> misc: fastrpc: Add support to save and restore interrupted
> >> misc: fastrpc: Add support to allocate shared context bank
> >> misc: fastrpc: Add early wakeup support for fastRPC driver
> >> misc: fastrpc: Add polling mode support for fastRPC driver
> >> misc: fastrpc: Add DSP PD notification support
> >> misc: fastrpc: Add support for users to clean up DSP user PD
> >> misc: fastrpc: Add wakelock management support
> >> misc: fastrpc: Add DSP signal support
> >> misc: fastrpc: Restrict untrusted apk to spawn privileged PD
> >> misc: fastrpc: Add system unsigned PD support
> >>
> >> drivers/misc/fastrpc.c | 1949 +++++++++++++++++++++++++++++++----
> >> include/uapi/misc/fastrpc.h | 112 ++
> >> 2 files changed, 1844 insertions(+), 217 deletions(-)
> >>
> >
>


--
With best wishes
Dmitry

2024-02-07 09:53:56

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [PATCH v1 02/16] misc: fastrpc: Add support for unsigned PD

On Wed, 7 Feb 2024 at 10:57, Ekansh Gupta <[email protected]> wrote:
>
>
> On 2/2/2024 8:13 PM, Greg KH wrote:
> > On Fri, Feb 02, 2024 at 12:10:25PM +0530, Ekansh Gupta wrote:
> >> Unsigned PD requires more initial memory to spawn.
> > What exactly is "Unsigned PD"?
> >
> > And where are all of the userspace changes for this series so we can
> > verify they work properly?
> >
> > thanks,
> >
> > greg k-h
>
> Hi Greg,
> Unsigned PDs are sandboxed DSP processes used to offload computation
> workloads to the DSP. Unsigned PD have less privileges in terms of
> DSP resource access as compared to Signed PD.

All such details must be described in commit messages for the patches.

>
> Unsigned PD can be enabled using userspace API:
> https://git.codelinaro.org/linaro/qcomlt/fastrpc/-/blob/master/src/fastrpc_apps_user.c?ref_type=heads#L1173
>
> For multimode invoke request(other feature) also I've shared the
> userspace changes with Srini which he will be pulling to userspace
> project.

And this should be a part of the cover letter.

>
> Please let me know if you have any other queries.
>
> Thanks
> --ekansh
>
>


--
With best wishes
Dmitry

2024-02-14 07:47:33

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH v1 04/16] misc: fastrpc: Add fastrpc multimode invoke request support



On 02/02/2024 06:40, Ekansh Gupta wrote:
> Multimode invocation request is intended to support multiple
> different type of requests. This will include enhanced invoke
> request to support CRC check and performance counter enablement.
> This will also support few driver level user controllable
> mechanisms like usage of shared context banks, wakelock support,
> etc. This IOCTL is also added with the aim to support few
> new fastrpc features like DSP PD notification framework,
> DSP Signalling mechanism etc.
>
> Signed-off-by: Ekansh Gupta <[email protected]>
> ---
> drivers/misc/fastrpc.c | 176 ++++++++++++++++++++++++++----------
> include/uapi/misc/fastrpc.h | 26 ++++++
> 2 files changed, 154 insertions(+), 48 deletions(-)
>
..

> diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
> index f33d914d8f46..45c15be1de58 100644
> --- a/include/uapi/misc/fastrpc.h
> +++ b/include/uapi/misc/fastrpc.h
> @@ -16,6 +16,7 @@
> #define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_init_create_static)
> #define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map)
> #define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap)
> +#define FASTRPC_IOCTL_MULTIMODE_INVOKE _IOWR('R', 12, struct fastrpc_ioctl_multimode_invoke)
> #define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability)
>
> /**
> @@ -80,6 +81,31 @@ struct fastrpc_invoke {
> __u64 args;
> };
>
> +struct fastrpc_enhanced_invoke {
> + struct fastrpc_invoke inv;
> + __u64 crc;
> + __u64 perf_kernel;
> + __u64 perf_dsp;
> + __u32 reserved[8]; /* keeping reserved bits for new requirements */
> +};
> +
> +struct fastrpc_ioctl_multimode_invoke {
This struct needs some documentation.

> + __u32 req;
we use req here and then in next few lines we define the same as
fastrpc_multimode_invoke_type. I would recommend to make this type
instead of req.

> + __u32 rsvd; /* padding field */
reserved?

<---
> + __u64 invparam;
> + __u64 size;
-->
Isn't size obvious when we know request type?

This is also opening up a path for userspace to pass some random structures.

It makes more sense to have a union of all the request structures.

Why not add all the enhanced invoke uapi structures as part of this patch?

> + __u32 reserved[8]; /* keeping reserved bits for new requirements */
> +};
> +
> +enum fastrpc_multimode_invoke_type {
> + FASTRPC_INVOKE = 1,
> + FASTRPC_INVOKE_ENHANCED = 2,
> + FASTRPC_INVOKE_CONTROL = 3,
> + FASTRPC_INVOKE_DSPSIGNAL = 4,
> + FASTRPC_INVOKE_NOTIF = 5,
> + FASTRPC_INVOKE_MULTISESSION = 6,

All of these needs a proper documentation. Its impossible to understand
what they actually mean.

This applies to all the enums that are added as part of other patches to
the uapi headers.

thanks,
Srini


> +};
> +
> struct fastrpc_init_create {
> __u32 filelen; /* elf file length */
> __s32 filefd; /* fd for the file */

2024-02-22 07:04:06

by Wentong Wu

[permalink] [raw]
Subject: RE: [PATCH v1 00/16] Add missing features to FastRPC driver

> From: Ekansh Gupta <[email protected]>
> This patch series adds the listed features that have been missing in
> upstream fastRPC driver.

Thanks for the patch, and is there any latency data on driver side?

BR,
Wentong
>
> - Redesign and improve remote heap management.
> - Add static PD restart support for audio and sensors PD using
> PDR framework.
> - Add changes to support multimode invocation ioctl request. This
> ioctl call facilitates multiple types of requests from user including
> CRC check, performance counters, shared context bank usage, etc.
> This series also carries patch to save and restore interrupted
> context.
> - Add early wakeup support to allow DSP user to send early response
> to CPU and improve fastrpc performance.
> - Add polling mode support with which driver polls on memory to avoid
> CPU from going to low power modes.
> - Add notifications frameworks to provide users with the DSP PD status
> notifications.
> - Add a control mechanism to allow users to clean up DSP user PD
> - Add wakelock management support
> - Add DSP signalling support
> - Add check for untrusted applications and allow trusted processed to
> offload to system unsigned PD.
>
> Ekansh Gupta (16):
> misc: fastrpc: Redesign remote heap management
> misc: fastrpc: Add support for unsigned PD
> misc: fastrpc: Add static PD restart support
> misc: fastrpc: Add fastrpc multimode invoke request support
> misc: fastrpc: Add CRC support for remote buffers
> misc: fastrpc: Capture kernel and DSP performance counters
> misc: fastrpc: Add support to save and restore interrupted
> misc: fastrpc: Add support to allocate shared context bank
> misc: fastrpc: Add early wakeup support for fastRPC driver
> misc: fastrpc: Add polling mode support for fastRPC driver
> misc: fastrpc: Add DSP PD notification support
> misc: fastrpc: Add support for users to clean up DSP user PD
> misc: fastrpc: Add wakelock management support
> misc: fastrpc: Add DSP signal support
> misc: fastrpc: Restrict untrusted apk to spawn privileged PD
> misc: fastrpc: Add system unsigned PD support
>
> drivers/misc/fastrpc.c | 1949 +++++++++++++++++++++++++++++++----
> include/uapi/misc/fastrpc.h | 112 ++
> 2 files changed, 1844 insertions(+), 217 deletions(-)
>
> --
> 2.17.0
>