From 09c2045118b2ea135a63b86950e9eb260b39ce10 Mon Sep 17 00:00:00 2001 From: Amir Samuelov Date: Mon, 11 May 2020 12:53:28 +0300 Subject: [PATCH 1/2] soc: qcom: spss_utils: add spss events support Add IOCTL for wait/signal spss events. Change-Id: Ia8ad37a1632de21e6ae4e70013ca72b4b35c68ba Signed-off-by: Amir Samuelov --- drivers/soc/qcom/spss_utils.c | 118 ++++++++++++++++++++++++++++++-- include/uapi/linux/spss_utils.h | 29 +++++++- 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index 3314b137c9f9..a88f3c195f62 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -33,6 +33,7 @@ #include #include /* SZ_4K */ #include /* copy_from_user() */ +#include /* wait_for_completion_timeout() */ #include #include @@ -91,6 +92,9 @@ static phys_addr_t cmac_mem_addr; #define SPU_EMULATUION (BIT(0) | BIT(1)) #define SPU_PRESENT_IN_EMULATION BIT(0) +/* Events notification */ +static struct completion spss_events[SPSS_NUM_EVENTS]; + /** * struct device state */ @@ -386,15 +390,84 @@ static void spss_destroy_sysfs(struct device *dev) /*==========================================================================*/ /* IOCTL */ /*==========================================================================*/ +static int spss_wait_for_event(struct spss_ioc_wait_for_event *req) +{ + int ret; + uint32_t event_id; + uint32_t timeout_sec; + long timeleft = 1; + + event_id = req->event_id; + timeout_sec = req->timeout_sec; + + if (event_id >= SPSS_NUM_EVENTS) { + pr_err("event_id [%d] invalid\n", event_id); + return -EINVAL; + } + + pr_debug("wait for event [%d], timeout_sec [%d]\n", + event_id, timeout_sec); + + if (timeout_sec) { + unsigned long jiffies = 0; + + jiffies = msecs_to_jiffies(timeout_sec*1000); + timeleft = wait_for_completion_interruptible_timeout( + &spss_events[event_id], jiffies); + ret = timeleft; + } else { + ret = wait_for_completion_interruptible( + &spss_events[event_id]); + } + + if (timeleft == 0) { + pr_err("wait for event [%d] timeout [%d] sec expired\n", + event_id, timeout_sec); + req->status = EVENT_STATUS_TIMEOUT; + } else if (ret < 0) { + pr_err("wait for event [%d] interrupted. ret [%d]\n", + event_id, ret); + req->status = EVENT_STATUS_ABORTED; + } else { + pr_debug("wait for event [%d] completed.\n", event_id); + req->status = EVENT_STATUS_SIGNALED; + } + + return 0; +} + +static int spss_signal_event(struct spss_ioc_signal_event *req) +{ + uint32_t event_id; + + event_id = req->event_id; + + if (event_id >= SPSS_NUM_EVENTS) { + pr_err("event_id [%d] invalid\n", event_id); + return -EINVAL; + } + + pr_debug("signal event [%d]\n", event_id); + complete_all(&spss_events[event_id]); + req->status = EVENT_STATUS_SIGNALED; + + return 0; +} + static long spss_utils_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret; void *buf = (void *) arg; unsigned char data[64] = {0}; size_t size = 0; u32 i = 0; /* Saved cmacs of spu firmware and UEFI loaded spu apps */ u32 fw_and_apps_cmacs[FW_AND_APPS_CMAC_SIZE]; + struct spss_ioc_wait_for_event *wait_req = + (struct spss_ioc_wait_for_event *) data; + struct spss_ioc_signal_event *signal_req = + (struct spss_ioc_signal_event *) data; if (buf == NULL) { pr_err("invalid ioctl arg\n"); @@ -439,7 +512,7 @@ static long spss_utils_ioctl(struct file *file, /* * SPSS is loaded now by UEFI, - * so IAR callback is not being called on powerup by PIL. + * so IAR callback is not being called on power-up by PIL. * therefore read the spu pbl fw cmac and apps cmac from ioctl. * The callback shall be called on spss SSR. */ @@ -449,6 +522,30 @@ static long spss_utils_ioctl(struct file *file, spss_get_saved_uefi_apps_cmac(); break; + case SPSS_IOC_WAIT_FOR_EVENT: + /* check input params */ + if (size != sizeof(struct spss_ioc_wait_for_event)) { + pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size); + return -EINVAL; + } + ret = spss_wait_for_event(wait_req); + if (ret < 0) + return ret; + copy_to_user((void __user *)arg, data, size); + break; + + case SPSS_IOC_SIGNAL_EVENT: + /* check input params */ + if (size != sizeof(struct spss_ioc_signal_event)) { + pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size); + return -EINVAL; + } + ret = spss_signal_event(signal_req); + if (ret < 0) + return ret; + copy_to_user((void __user *)arg, data, size); + break; + default: pr_err("invalid ioctl cmd [0x%x]\n", cmd); return -EINVAL; @@ -797,7 +894,7 @@ static int spss_parse_dt(struct device_node *node) iar_state = val1; - pr_info("iar_state [%d]\n", iar_state); + pr_debug("iar_state [%d]\n", iar_state); return 0; } @@ -934,13 +1031,11 @@ static int spss_set_saved_uefi_apps_cmac(void) return 0; } -static int spss_utils_iar_callback(struct notifier_block *nb, +static int spss_utils_pil_callback(struct notifier_block *nb, unsigned long code, void *data) { - /* do nothing if IAR is not active */ - if (!is_iar_active) - return NOTIFY_OK; + int i; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: @@ -951,11 +1046,16 @@ static int spss_utils_iar_callback(struct notifier_block *nb, break; case SUBSYS_BEFORE_POWERUP: pr_debug("[SUBSYS_BEFORE_POWERUP] event.\n"); + for (i = 0 ; i < SPSS_NUM_EVENTS; i++) + reinit_completion(&spss_events[i]); break; case SUBSYS_AFTER_POWERUP: pr_debug("[SUBSYS_AFTER_POWERUP] event.\n"); break; case SUBSYS_BEFORE_AUTH_AND_RESET: + /* do nothing if IAR is not active */ + if (!is_iar_active) + return NOTIFY_OK; pr_debug("[SUBSYS_BEFORE_AUTH_AND_RESET] event.\n"); /* Called on SSR as spss firmware is loaded by UEFI */ spss_set_fw_cmac(cmac_buf, sizeof(cmac_buf)); @@ -1030,7 +1130,7 @@ static int spss_probe(struct platform_device *pdev) if (!iar_nb) return -ENOMEM; - iar_nb->notifier_call = spss_utils_iar_callback; + iar_nb->notifier_call = spss_utils_pil_callback; iar_notif_handle = subsys_notif_register_notifier("spss", iar_nb); if (IS_ERR_OR_NULL(iar_notif_handle)) { @@ -1047,6 +1147,7 @@ static int spss_probe(struct platform_device *pdev) static int spss_remove(struct platform_device *pdev) { + int i; spss_utils_destroy_chardev(); spss_destroy_sysfs(spss_dev); @@ -1065,6 +1166,9 @@ static int spss_remove(struct platform_device *pdev) cmac_mem = NULL; } + for (i = 0 ; i < SPSS_NUM_EVENTS; i++) + init_completion(&spss_events[i]); + return 0; } diff --git a/include/uapi/linux/spss_utils.h b/include/uapi/linux/spss_utils.h index c767dbcc531e..5f17c0c5c663 100644 --- a/include/uapi/linux/spss_utils.h +++ b/include/uapi/linux/spss_utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _UAPI_SPSS_UTILS_H_ @@ -17,6 +17,8 @@ */ #define SPSS_IOC_MAGIC 'S' + +/* ---------- set fw cmac --------------------------------- */ #define NUM_SPU_UEFI_APPS 3 struct spss_ioc_set_fw_cmac { @@ -27,4 +29,29 @@ struct spss_ioc_set_fw_cmac { #define SPSS_IOC_SET_FW_CMAC \ _IOWR(SPSS_IOC_MAGIC, 1, struct spss_ioc_set_fw_cmac) +/* ---------- wait for event ------------------------------ */ +#define SPSS_NUM_EVENTS 8 + +#define EVENT_STATUS_SIGNALED 0xAAAA +#define EVENT_STATUS_TIMEOUT 0xEEE1 +#define EVENT_STATUS_ABORTED 0xEEE2 + +struct spss_ioc_wait_for_event { + uint32_t event_id; /* input */ + uint32_t timeout_sec; /* input */ + uint32_t status; /* output */ +} __packed; + +#define SPSS_IOC_WAIT_FOR_EVENT \ + _IOWR(SPSS_IOC_MAGIC, 2, struct spss_ioc_wait_for_event) + +/* ---------- signal event ------------------------------ */ +struct spss_ioc_signal_event { + uint32_t event_id; /* input */ + uint32_t status; /* output */ +} __packed; + +#define SPSS_IOC_SIGNAL_EVENT \ + _IOWR(SPSS_IOC_MAGIC, 3, struct spss_ioc_signal_event) + #endif /* _UAPI_SPSS_UTILS_H_ */ From a50479ab2ea5c1f56b96acc9eff642eed49215ba Mon Sep 17 00:00:00 2001 From: Amir Samuelov Date: Tue, 12 May 2020 12:43:25 +0300 Subject: [PATCH 2/2] soc: qcom: spss_utils: protect from event signaled twice avoid event signaled twice. add ioctl to check if event was signaled. Change-Id: Ie75b9db86f2badddc08d65eee30ecd6a15795256 Signed-off-by: Amir Samuelov --- drivers/soc/qcom/spss_utils.c | 117 ++++++++++++++++++++++++++++---- include/uapi/linux/spss_utils.h | 38 +++++++++-- 2 files changed, 133 insertions(+), 22 deletions(-) diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index a88f3c195f62..2f8c4750e4b4 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -94,6 +94,10 @@ static phys_addr_t cmac_mem_addr; /* Events notification */ static struct completion spss_events[SPSS_NUM_EVENTS]; +static bool spss_events_signaled[SPSS_NUM_EVENTS]; + +/* Protect from ioctl signal func called by multiple-proc at the same time */ +static struct mutex event_lock; /** * struct device state @@ -428,6 +432,8 @@ static int spss_wait_for_event(struct spss_ioc_wait_for_event *req) pr_err("wait for event [%d] interrupted. ret [%d]\n", event_id, ret); req->status = EVENT_STATUS_ABORTED; + if (ret == -ERESTARTSYS) /* handle LPM event */ + return ret; } else { pr_debug("wait for event [%d] completed.\n", event_id); req->status = EVENT_STATUS_SIGNALED; @@ -440,16 +446,52 @@ static int spss_signal_event(struct spss_ioc_signal_event *req) { uint32_t event_id; + mutex_lock(&event_lock); + event_id = req->event_id; if (event_id >= SPSS_NUM_EVENTS) { pr_err("event_id [%d] invalid\n", event_id); + mutex_unlock(&event_lock); + return -EINVAL; + } + + if (spss_events_signaled[event_id]) { + pr_err("event_id [%d] already signaled\n", event_id); + mutex_unlock(&event_lock); return -EINVAL; } pr_debug("signal event [%d]\n", event_id); complete_all(&spss_events[event_id]); req->status = EVENT_STATUS_SIGNALED; + spss_events_signaled[event_id] = true; + + mutex_unlock(&event_lock); + + return 0; +} + +static int spss_is_event_signaled(struct spss_ioc_is_signaled *req) +{ + uint32_t event_id; + + mutex_lock(&event_lock); + + event_id = req->event_id; + + if (event_id >= SPSS_NUM_EVENTS) { + pr_err("event_id [%d] invalid\n", event_id); + mutex_unlock(&event_lock); + return -EINVAL; + } + + if (spss_events_signaled[event_id]) + req->status = EVENT_STATUS_SIGNALED; + else + req->status = EVENT_STATUS_NOT_SIGNALED; + + mutex_unlock(&event_lock); return 0; } @@ -464,10 +506,7 @@ static long spss_utils_ioctl(struct file *file, u32 i = 0; /* Saved cmacs of spu firmware and UEFI loaded spu apps */ u32 fw_and_apps_cmacs[FW_AND_APPS_CMAC_SIZE]; - struct spss_ioc_wait_for_event *wait_req = - (struct spss_ioc_wait_for_event *) data; - struct spss_ioc_signal_event *signal_req = - (struct spss_ioc_signal_event *) data; + void *req = (void *) data; if (buf == NULL) { pr_err("invalid ioctl arg\n"); @@ -528,10 +567,10 @@ static long spss_utils_ioctl(struct file *file, pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size); return -EINVAL; } - ret = spss_wait_for_event(wait_req); + ret = spss_wait_for_event(req); + copy_to_user((void __user *)arg, data, size); if (ret < 0) return ret; - copy_to_user((void __user *)arg, data, size); break; case SPSS_IOC_SIGNAL_EVENT: @@ -540,10 +579,22 @@ static long spss_utils_ioctl(struct file *file, pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size); return -EINVAL; } - ret = spss_signal_event(signal_req); + ret = spss_signal_event(req); + copy_to_user((void __user *)arg, data, size); if (ret < 0) return ret; + break; + + case SPSS_IOC_IS_EVENT_SIGNALED: + /* check input params */ + if (size != sizeof(struct spss_ioc_is_signaled)) { + pr_err("cmd [0x%x] invalid size [0x%x]\n", cmd, size); + return -EINVAL; + } + ret = spss_is_event_signaled(req); copy_to_user((void __user *)arg, data, size); + if (ret < 0) + return ret; break; default: @@ -1035,22 +1086,56 @@ static int spss_utils_pil_callback(struct notifier_block *nb, unsigned long code, void *data) { - int i; + int i, event_id; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: pr_debug("[SUBSYS_BEFORE_SHUTDOWN] event.\n"); + mutex_lock(&event_lock); + /* Reset NVM-ready and SPU-ready events */ + for (i = SPSS_EVENT_ID_NVM_READY; + i <= SPSS_EVENT_ID_SPU_READY; i++) { + reinit_completion(&spss_events[i]); + spss_events_signaled[i] = false; + } + mutex_unlock(&event_lock); + pr_debug("reset spss events.\n"); break; case SUBSYS_AFTER_SHUTDOWN: pr_debug("[SUBSYS_AFTER_SHUTDOWN] event.\n"); + mutex_lock(&event_lock); + event_id = SPSS_EVENT_ID_SPU_POWER_DOWN; + complete_all(&spss_events[event_id]); + spss_events_signaled[event_id] = true; + + event_id = SPSS_EVENT_ID_SPU_POWER_UP; + reinit_completion(&spss_events[event_id]); + spss_events_signaled[event_id] = false; + mutex_unlock(&event_lock); break; case SUBSYS_BEFORE_POWERUP: pr_debug("[SUBSYS_BEFORE_POWERUP] event.\n"); - for (i = 0 ; i < SPSS_NUM_EVENTS; i++) - reinit_completion(&spss_events[i]); break; case SUBSYS_AFTER_POWERUP: pr_debug("[SUBSYS_AFTER_POWERUP] event.\n"); + mutex_lock(&event_lock); + event_id = SPSS_EVENT_ID_SPU_POWER_UP; + complete_all(&spss_events[event_id]); + spss_events_signaled[event_id] = true; + + event_id = SPSS_EVENT_ID_SPU_POWER_DOWN; + reinit_completion(&spss_events[event_id]); + spss_events_signaled[event_id] = false; + mutex_unlock(&event_lock); + break; + case SUBSYS_RAMDUMP_NOTIFICATION: + pr_debug("[SUBSYS_RAMDUMP_NOTIFICATION] event.\n"); + break; + case SUBSYS_PROXY_VOTE: + pr_debug("[SUBSYS_PROXY_VOTE] event.\n"); + break; + case SUBSYS_PROXY_UNVOTE: + pr_debug("[SUBSYS_PROXY_UNVOTE] event.\n"); break; case SUBSYS_BEFORE_AUTH_AND_RESET: /* do nothing if IAR is not active */ @@ -1076,6 +1161,7 @@ static int spss_utils_pil_callback(struct notifier_block *nb, static int spss_probe(struct platform_device *pdev) { int ret = 0; + int i; struct device_node *np = NULL; struct device *dev = &pdev->dev; @@ -1140,6 +1226,12 @@ static int spss_probe(struct platform_device *pdev) iar_nb = NULL; } + for (i = 0 ; i < SPSS_NUM_EVENTS; i++) { + init_completion(&spss_events[i]); + spss_events_signaled[i] = false; + } + mutex_init(&event_lock); + pr_info("Probe completed successfully, [%s].\n", firmware_name); return 0; @@ -1147,8 +1239,6 @@ static int spss_probe(struct platform_device *pdev) static int spss_remove(struct platform_device *pdev) { - int i; - spss_utils_destroy_chardev(); spss_destroy_sysfs(spss_dev); @@ -1166,9 +1256,6 @@ static int spss_remove(struct platform_device *pdev) cmac_mem = NULL; } - for (i = 0 ; i < SPSS_NUM_EVENTS; i++) - init_completion(&spss_events[i]); - return 0; } diff --git a/include/uapi/linux/spss_utils.h b/include/uapi/linux/spss_utils.h index 5f17c0c5c663..c93c5034175a 100644 --- a/include/uapi/linux/spss_utils.h +++ b/include/uapi/linux/spss_utils.h @@ -19,22 +19,37 @@ #define SPSS_IOC_MAGIC 'S' /* ---------- set fw cmac --------------------------------- */ -#define NUM_SPU_UEFI_APPS 3 +#define NUM_SPU_UEFI_APPS 3 +#define CMAC_SIZE_IN_WORDS 4 struct spss_ioc_set_fw_cmac { - __u32 cmac[4]; - __u32 app_cmacs[NUM_SPU_UEFI_APPS][4]; + uint32_t cmac[CMAC_SIZE_IN_WORDS]; + uint32_t app_cmacs[NUM_SPU_UEFI_APPS][CMAC_SIZE_IN_WORDS]; } __packed; #define SPSS_IOC_SET_FW_CMAC \ _IOWR(SPSS_IOC_MAGIC, 1, struct spss_ioc_set_fw_cmac) /* ---------- wait for event ------------------------------ */ -#define SPSS_NUM_EVENTS 8 +enum spss_event_id { + /* signaled from user */ + SPSS_EVENT_ID_PIL_CALLED = 0, + SPSS_EVENT_ID_NVM_READY = 1, + SPSS_EVENT_ID_SPU_READY = 2, + SPSS_NUM_USER_EVENTS, -#define EVENT_STATUS_SIGNALED 0xAAAA -#define EVENT_STATUS_TIMEOUT 0xEEE1 -#define EVENT_STATUS_ABORTED 0xEEE2 + /* signaled from kernel */ + SPSS_EVENT_ID_SPU_POWER_DOWN = 6, + SPSS_EVENT_ID_SPU_POWER_UP = 7, + SPSS_NUM_EVENTS, +}; + +enum spss_event_status { + EVENT_STATUS_SIGNALED = 0xAAAA, + EVENT_STATUS_NOT_SIGNALED = 0xFFFF, + EVENT_STATUS_TIMEOUT = 0xEEE1, + EVENT_STATUS_ABORTED = 0xEEE2, +}; struct spss_ioc_wait_for_event { uint32_t event_id; /* input */ @@ -54,4 +69,13 @@ struct spss_ioc_signal_event { #define SPSS_IOC_SIGNAL_EVENT \ _IOWR(SPSS_IOC_MAGIC, 3, struct spss_ioc_signal_event) +/* ---------- is event isgnaled ------------------------------ */ +struct spss_ioc_is_signaled { + uint32_t event_id; /* input */ + uint32_t status; /* output */ +} __attribute__((packed)); + +#define SPSS_IOC_IS_EVENT_SIGNALED \ + _IOWR(SPSS_IOC_MAGIC, 4, struct spss_ioc_is_signaled) + #endif /* _UAPI_SPSS_UTILS_H_ */