From 86d0cd334faff59a721ebfc0fcd55e27d1dfaf4e Mon Sep 17 00:00:00 2001 From: Amir Samuelov Date: Thu, 20 Feb 2020 09:29:41 +0200 Subject: [PATCH] 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 | 112 ++++++++++++++++++++++++++++---- include/uapi/linux/spss_utils.h | 38 +++++++++-- 2 files changed, 131 insertions(+), 19 deletions(-) diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index 3854deb7f599..e3ab1c4b28e5 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -93,7 +93,11 @@ static phys_addr_t cmac_mem_addr; #define SPU_PRESENT_IN_EMULATION BIT(2) /* Events notification */ -struct completion spss_events[SPSS_NUM_EVENTS]; +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 @@ -418,6 +422,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; @@ -430,16 +436,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; } @@ -454,10 +496,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"); @@ -518,10 +557,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: @@ -530,10 +569,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: @@ -1010,22 +1061,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 */ @@ -1132,8 +1217,11 @@ static int spss_probe(struct platform_device *pdev) kfree(iar_nb); } - for (i = 0 ; i < SPSS_NUM_EVENTS; i++) + for (i = 0 ; i < SPSS_NUM_EVENTS; i++) { init_completion(&spss_events[i]); + spss_events_signaled[i] = false; + } + mutex_init(&event_lock); return 0; } diff --git a/include/uapi/linux/spss_utils.h b/include/uapi/linux/spss_utils.h index 34811d17ba96..6a34d19f073c 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 { - uint32_t cmac[4]; - uint32_t 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, +} spss_event_id; + +enum _spss_event_status { + EVENT_STATUS_SIGNALED = 0xAAAA, + EVENT_STATUS_NOT_SIGNALED = 0xFFFF, + EVENT_STATUS_TIMEOUT = 0xEEE1, + EVENT_STATUS_ABORTED = 0xEEE2, +} spss_event_status; 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_ */