summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/glados/board.h2
-rw-r--r--board/rambi/board.h3
-rw-r--r--board/samus/board.h2
-rw-r--r--chip/it83xx/lpc.c12
-rw-r--r--chip/lm4/lpc.c12
-rw-r--r--chip/mec1322/lpc.c12
-rw-r--r--chip/npcx/lpc.c13
-rw-r--r--common/acpi.c34
-rw-r--r--common/host_command.c6
-rw-r--r--include/host_command.h5
-rw-r--r--include/lpc.h7
11 files changed, 105 insertions, 3 deletions
diff --git a/board/glados/board.h b/board/glados/board.h
index 6768b61749..4762f3916c 100644
--- a/board/glados/board.h
+++ b/board/glados/board.h
@@ -75,7 +75,7 @@
#define I2C_PORT_USB_CHARGER_2 MEC1322_I2C3
#undef DEFERRABLE_MAX_COUNT
-#define DEFERRABLE_MAX_COUNT 10
+#define DEFERRABLE_MAX_COUNT 11
#ifndef __ASSEMBLER__
diff --git a/board/rambi/board.h b/board/rambi/board.h
index 84d378d4df..f08e6a0266 100644
--- a/board/rambi/board.h
+++ b/board/rambi/board.h
@@ -48,6 +48,9 @@
#define CONFIG_WIRELESS_SUSPEND \
(EC_WIRELESS_SWITCH_WLAN | EC_WIRELESS_SWITCH_WLAN_POWER)
+#undef DEFERRABLE_MAX_COUNT
+#define DEFERRABLE_MAX_COUNT 9
+
#ifndef __ASSEMBLER__
/* I2C ports */
diff --git a/board/samus/board.h b/board/samus/board.h
index f1eb461c27..ee793ff8d2 100644
--- a/board/samus/board.h
+++ b/board/samus/board.h
@@ -81,7 +81,7 @@
/* Do we want EC_WIRELESS_SWITCH_WWAN as well? */
#undef DEFERRABLE_MAX_COUNT
-#define DEFERRABLE_MAX_COUNT 9
+#define DEFERRABLE_MAX_COUNT 10
#ifndef __ASSEMBLER__
diff --git a/chip/it83xx/lpc.c b/chip/it83xx/lpc.c
index 9db2719b87..95fcb23aee 100644
--- a/chip/it83xx/lpc.c
+++ b/chip/it83xx/lpc.c
@@ -638,6 +638,18 @@ void lpcrst_interrupt(enum gpio_signal signal)
lpc_get_pltrst_asserted() ? "" : "de");
}
+/* Enable LPC ACPI-EC interrupts */
+void lpc_enable_acpi_interrupts(void)
+{
+ task_enable_irq(IT83XX_IRQ_PMC_IN);
+}
+
+/* Disable LPC ACPI-EC interrupts */
+void lpc_disable_acpi_interrupts(void)
+{
+ task_disable_irq(IT83XX_IRQ_PMC_IN);
+}
+
static void lpc_resume(void)
{
/* Mask all host events until the host unmasks them itself. */
diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c
index 149145f3c0..2cca35f796 100644
--- a/chip/lm4/lpc.c
+++ b/chip/lm4/lpc.c
@@ -677,6 +677,18 @@ static void lpc_post_sysjump(void)
memcpy(event_mask, prev_mask, sizeof(event_mask));
}
+/* Enable LPC ACPI-EC interrupts */
+void lpc_enable_acpi_interrupts(void)
+{
+ LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_ACPI, 6);
+}
+
+/* Disable LPC ACPI-EC interrupts */
+void lpc_disable_acpi_interrupts(void)
+{
+ LM4_LPC_LPCIM &= ~(LM4_LPC_INT_MASK(LPC_CH_ACPI, 6));
+}
+
static void lpc_init(void)
{
/* Enable LPC clock in run and sleep modes. */
diff --git a/chip/mec1322/lpc.c b/chip/mec1322/lpc.c
index 7cdc120330..c486f75e77 100644
--- a/chip/mec1322/lpc.c
+++ b/chip/mec1322/lpc.c
@@ -557,6 +557,18 @@ int lpc_get_pltrst_asserted(void)
return (MEC1322_LPC_BUS_MONITOR & (1<<1)) ? 1 : 0;
}
+/* Enable LPC ACPI-EC0 interrupts */
+void lpc_enable_acpi_interrupts(void)
+{
+ task_enable_irq(MEC1322_IRQ_ACPIEC0_IBF);
+}
+
+/* Disable LPC ACPI-EC0 interrupts */
+void lpc_disable_acpi_interrupts(void)
+{
+ task_disable_irq(MEC1322_IRQ_ACPIEC0_IBF);
+}
+
/* On boards without a host, this command is used to set up LPC */
static int lpc_command_init(int argc, char **argv)
{
diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c
index 79e0675ede..595edf28e9 100644
--- a/chip/npcx/lpc.c
+++ b/chip/npcx/lpc.c
@@ -646,6 +646,19 @@ static void lpc_init(void)
/* initial IO port address via SIB-write modules */
system_lpc_host_register_init();
}
+
+/* Enable LPC ACPI-EC interrupts */
+void lpc_enable_acpi_interrupts(void)
+{
+ SET_BIT(NPCX_HIPMCTL(PM_CHAN_1), 0);
+}
+
+/* Disable LPC ACPI-EC interrupts */
+void lpc_disable_acpi_interrupts(void)
+{
+ CLEAR_BIT(NPCX_HIPMCTL(PM_CHAN_1), 0);
+}
+
/*
* Set prio to higher than default; this way LPC memory mapped data is ready
* before other inits try to initialize their memmap data.
diff --git a/common/acpi.c b/common/acpi.c
index 425f7e2337..b5cb763c40 100644
--- a/common/acpi.c
+++ b/common/acpi.c
@@ -42,6 +42,17 @@ static void acpi_unlock_memmap_deferred(void)
DECLARE_DEFERRED(acpi_unlock_memmap_deferred);
/*
+ * Deferred function to lock memmap and to enable LPC interrupts.
+ * This is due to LPC interrupt was unable to acquire memmap mutex.
+ */
+static void deferred_host_lock_memmap(void)
+{
+ host_lock_memmap();
+ lpc_enable_acpi_interrupts();
+}
+DECLARE_DEFERRED(deferred_host_lock_memmap);
+
+/*
* This handles AP writes to the EC via the ACPI I/O port. There are only a few
* ACPI commands (EC_CMD_ACPI_*), but they are all handled here.
*/
@@ -180,8 +191,29 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr)
*resultptr = evt_index;
retval = 1;
} else if (acpi_cmd == EC_CMD_ACPI_BURST_ENABLE && !acpi_data_count) {
+ /*
+ * TODO: The kernel only enables BURST when doing multi-byte
+ * value reads over the ACPI port. We don't do such reads
+ * when our memmap data can be accessed directly over LPC,
+ * so on LM4, for example, this is dead code. We might want
+ * to re-add the CONFIG, now that we have overhead of one
+ * deferred function.
+ */
+ if (host_memmap_is_locked()) {
+ /*
+ * If already locked by a task, we can not acquire
+ * the mutex and will have to wait in the interrupt
+ * context. But then the task will not get chance to
+ * release the mutex. This will create deadlock
+ * situation. To avoid the deadlock, disable ACPI
+ * interrupts and defer locking.
+ */
+ lpc_disable_acpi_interrupts();
+ hook_call_deferred(deferred_host_lock_memmap, 0);
+ } else {
+ host_lock_memmap();
+ }
/* Enter burst mode */
- host_lock_memmap();
lpc_set_acpi_status_mask(EC_LPC_STATUS_BURST_MODE);
/*
diff --git a/common/host_command.c b/common/host_command.c
index da73d2dbd5..bc40a68441 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -88,6 +88,12 @@ void host_lock_memmap()
mutex_lock(&memmap_write_mutex);
}
+/* Returns host memmap lock status */
+int host_memmap_is_locked(void)
+{
+ return (memmap_write_mutex.lock != 0);
+}
+
void host_unlock_memmap()
{
mutex_unlock(&memmap_write_mutex);
diff --git a/include/host_command.h b/include/host_command.h
index 2667cb9a27..0d1ff998f3 100644
--- a/include/host_command.h
+++ b/include/host_command.h
@@ -130,6 +130,11 @@ uint8_t *host_get_memmap(int offset);
*/
void host_lock_memmap(void);
+/*
+ * Returns status of host memmap lock.
+ */
+int host_memmap_is_locked(void);
+
/**
* Release the memmap write mutex. This function should be called once
* a multi-byte variable read from ACPI is done, and when updating multi-byte
diff --git a/include/lpc.h b/include/lpc.h
index c38f711bda..c90a54a71c 100644
--- a/include/lpc.h
+++ b/include/lpc.h
@@ -113,4 +113,11 @@ void lpc_clear_acpi_status_mask(uint8_t mask);
*/
int lpc_get_pltrst_asserted(void);
+
+/* Disable LPC ACPI interrupts */
+void lpc_disable_acpi_interrupts(void);
+
+/* Enable LPC ACPI interrupts */
+void lpc_enable_acpi_interrupts(void);
+
#endif /* __CROS_EC_LPC_H */