summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorYilun Lin <yllin@google.com>2019-06-21 11:05:22 +0800
committerCommit Bot <commit-bot@chromium.org>2019-07-02 04:51:44 +0000
commit1fc8bb63ec847d7e36633624e50658578b5e93f4 (patch)
tree2760c02f8fae39c8f9fe6e1aecb28ba3c98070cd /chip
parent0e662b07aae39979e65637e80f5baecbf0a92a0f (diff)
downloadchrome-ec-1fc8bb63ec847d7e36633624e50658578b5e93f4.tar.gz
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 <yllin@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1670650 Tested-by: Yilun Lin <yllin@chromium.org> Auto-Submit: Yilun Lin <yllin@chromium.org> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org> Commit-Queue: Nicolas Boichat <drinkcat@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r--chip/mt_scp/ipi.c39
-rw-r--r--chip/mt_scp/ipi_chip.h13
2 files changed, 48 insertions, 4 deletions
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[];