diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index 3314b137c9f9..2f8c4750e4b4 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,13 @@ 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]; +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 */ @@ -386,15 +394,119 @@ 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; + if (ret == -ERESTARTSYS) /* handle LPM event */ + return ret; + } 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; + + 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; +} + 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]; + void *req = (void *) data; if (buf == NULL) { pr_err("invalid ioctl arg\n"); @@ -439,7 +551,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 +561,42 @@ 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(req); + copy_to_user((void __user *)arg, data, size); + if (ret < 0) + return ret; + 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(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: pr_err("invalid ioctl cmd [0x%x]\n", cmd); return -EINVAL; @@ -797,7 +945,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,28 +1082,65 @@ 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, 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"); 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 */ + 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)); @@ -976,6 +1161,7 @@ static int spss_utils_iar_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; @@ -1030,7 +1216,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)) { @@ -1040,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; @@ -1047,7 +1239,6 @@ static int spss_probe(struct platform_device *pdev) static int spss_remove(struct platform_device *pdev) { - spss_utils_destroy_chardev(); spss_destroy_sysfs(spss_dev); diff --git a/include/uapi/linux/spss_utils.h b/include/uapi/linux/spss_utils.h index c767dbcc531e..c93c5034175a 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,14 +17,65 @@ */ #define SPSS_IOC_MAGIC 'S' -#define NUM_SPU_UEFI_APPS 3 + +/* ---------- set fw cmac --------------------------------- */ +#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 ------------------------------ */ +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, + + /* 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 */ + 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) + +/* ---------- 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_ */