From 1fc8bb63ec847d7e36633624e50658578b5e93f4 Mon Sep 17 00:00:00 2001 From: Yilun Lin Date: Fri, 21 Jun 2019 11:05:22 +0800 Subject: mt_scp/ipi: Add ref-counted API ipi_{en,dis}able_irq() Unify IPC IRQ accessing to prevent a wrong IRQ enabling status. An IPC IRQ could be shared across many IPI handlers. Those handlers would usually operate on disabling or enabling the IPC IRQ. This may disorder the actual timing to on/off the IRQ when there are many tasks try to operate on it. As a result, any access to the SCP_IRQ_* should go through ipi_{en,dis}able_irq(), which support a counter to enable/disable the IRQ at correct timeing. TEST=Boot scp. BUG=b:117917141 BRANCH=master Change-Id: I792849279dfeb5231f27fa7a9cf260e2059bbf4b Signed-off-by: Yilun Lin Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1670650 Tested-by: Yilun Lin Auto-Submit: Yilun Lin Reviewed-by: Nicolas Boichat Commit-Queue: Nicolas Boichat --- chip/mt_scp/ipi.c | 39 +++++++++++++++++++++++++++++++++++---- chip/mt_scp/ipi_chip.h | 13 +++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) (limited to 'chip') diff --git a/chip/mt_scp/ipi.c b/chip/mt_scp/ipi.c index 26f07baf71..1afdf108ea 100644 --- a/chip/mt_scp/ipi.c +++ b/chip/mt_scp/ipi.c @@ -39,6 +39,8 @@ #define HOSTCMD_TYPE_HOSTCMD 1 #define HOSTCMD_TYPE_HOSTEVENT 2 +static volatile int16_t ipc0_enabled_count; +static struct mutex ipc0_lock; static struct mutex ipi_lock; /* IPC0 shared objects, including send object and receive object. */ static struct ipc_shared_obj *const scp_send_obj = @@ -47,6 +49,7 @@ static struct ipc_shared_obj *const scp_recv_obj = (struct ipc_shared_obj *)(CONFIG_IPC_SHARED_OBJ_ADDR + sizeof(struct ipc_shared_obj)); static char ipi_ready; + #ifdef HAS_TASK_HOSTCMD /* * hostcmd and hostevent share the same IPI ID, and use first byte type to @@ -80,6 +83,34 @@ static inline void try_to_wakeup_ap(int32_t id) SCP_SPM_INT = SPM_INT_A2SPM; } +void ipi_disable_irq(int irq) +{ + /* Only support SCP_IRQ_IPC0 for now. */ + if (irq != SCP_IRQ_IPC0) + return; + + mutex_lock(&ipc0_lock); + + if ((--ipc0_enabled_count) == 0) + task_disable_irq(irq); + + mutex_unlock(&ipc0_lock); +} + +void ipi_enable_irq(int irq) +{ + /* Only support SCP_IRQ_IPC0 for now. */ + if (irq != SCP_IRQ_IPC0) + return; + + mutex_lock(&ipc0_lock); + + if ((++ipc0_enabled_count) == 1) + task_enable_irq(irq); + + mutex_unlock(&ipc0_lock); +} + /* Send data from SCP to AP. */ int ipi_send(int32_t id, const void *buf, uint32_t len, int wait) { @@ -95,7 +126,7 @@ int ipi_send(int32_t id, const void *buf, uint32_t len, int wait) if (len > sizeof(scp_send_obj->buffer)) return EC_ERROR_INVAL; - task_disable_irq(SCP_IRQ_IPC0); + ipi_disable_irq(SCP_IRQ_IPC0); mutex_lock(&ipi_lock); /* Check if there is already an IPI pending in AP. */ @@ -112,7 +143,7 @@ int ipi_send(int32_t id, const void *buf, uint32_t len, int wait) try_to_wakeup_ap(id); mutex_unlock(&ipi_lock); - task_enable_irq(SCP_IRQ_IPC0); + ipi_enable_irq(SCP_IRQ_IPC0); return EC_ERROR_BUSY; } @@ -130,7 +161,7 @@ int ipi_send(int32_t id, const void *buf, uint32_t len, int wait) ; mutex_unlock(&ipi_lock); - task_enable_irq(SCP_IRQ_IPC0); + ipi_enable_irq(SCP_IRQ_IPC0); return EC_SUCCESS; } @@ -273,7 +304,7 @@ static void ipi_enable_ipc0_deferred(void) /* All tasks are up, we can safely enable IPC0 IRQ now. */ SCP_INTC_IRQ_ENABLE |= IPC0_IRQ_EN; - task_enable_irq(SCP_IRQ_IPC0); + ipi_enable_irq(SCP_IRQ_IPC0); ipi_ready = 1; diff --git a/chip/mt_scp/ipi_chip.h b/chip/mt_scp/ipi_chip.h index ea05424804..b4178ae7e0 100644 --- a/chip/mt_scp/ipi_chip.h +++ b/chip/mt_scp/ipi_chip.h @@ -68,6 +68,19 @@ struct rpmsg_ns_msg { */ void ipc_handler(void); +/* + * An IPC IRQ could be shared across many IPI handlers. + * Those handlers would usually operate on disabling or enabling the IPC IRQ. + * This may disorder the actual timing to on/off the IRQ when there are many + * tasks try to operate on it. As a result, any access to the SCP_IRQ_* + * should go through ipi_{en,dis}able_irq(), which support a counter to + * enable/disable the IRQ at correct timeing. + */ +/* Disable IPI IRQ. */ +void ipi_disable_irq(int irq); +/* Enable IPI IRQ. */ +void ipi_enable_irq(int irq); + /* IPI tables */ extern void (*ipi_handler_table[])(int32_t, void *, uint32_t); extern int *ipi_wakeup_table[]; -- cgit v1.2.1