From: Xu Qiang <xuqiang36(a)huawei.com>
ascend inclusion
category: bugfix
Bugzilla: N/A
CVE: N/A
---------------------------------------
Hisi when designing ascend chip, connect the serial port interrupt
signal lines to mbigen equipment, mbigen write GICD_SETSPI_NSR
register trigger the SPI interrupt. This can result in serial
port drop interrupts.
Signed-off-by: Xu Qiang <xuqiang36(a)huawei.com>
Reviewed-by: Hanjun Guo <guohanjun(a)huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang(a)huawei.com>
---
drivers/tty/serial/Kconfig | 18 ++++++++++
drivers/tty/serial/amba-pl011.c | 64 +++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index df8bd0c7b97d..66e69c7d10a3 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -73,6 +73,24 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+if ASCEND_FEATURES
+
+config SERIAL_ATTACHED_MBIGEN
+ bool "Serial port interrupt signal lines connected to the mbigen"
+ depends on SERIAL_AMBA_PL011=y
+ default n
+ help
+ Say Y here when the interrupt signal line of the serial port is
+ connected to the mbigne. The mbigen device has the function of
+ clearing interrupts automatically. However, the interrupt processing
+ function of the serial port driver may process multiple interrupts
+ at a time. The mbigen device cannot adapt to this scenario.
+ As a result, interrupts are lost.Because it maybe discard interrupt.
+
+ If unsure, say N.
+
+endif
+
config SERIAL_EARLYCON_ARM_SEMIHOST
bool "Early console using ARM semihosting"
depends on ARM64 || ARM
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 1d501154e9f7..781a27eebf0b 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1473,6 +1473,63 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
dummy_read = pl011_read(uap, REG_ICR);
}
+#ifdef CONFIG_SERIAL_ATTACHED_MBIGEN
+struct workaround_oem_info {
+ char oem_id[ACPI_OEM_ID_SIZE + 1];
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
+ u32 oem_revision;
+};
+
+static bool pl011_enable_hisi_wkrd;
+static struct workaround_oem_info pl011_wkrd_info[] = {
+ {
+ .oem_id = "HISI ",
+ .oem_table_id = "HIP08 ",
+ .oem_revision = 0x300,
+ }, {
+ .oem_id = "HISI ",
+ .oem_table_id = "HIP08 ",
+ .oem_revision = 0x301,
+ }, {
+ .oem_id = "HISI ",
+ .oem_table_id = "HIP08 ",
+ .oem_revision = 0x400,
+ }, {
+ .oem_id = "HISI ",
+ .oem_table_id = "HIP08 ",
+ .oem_revision = 0x401,
+ }, {
+ .oem_id = "HISI ",
+ .oem_table_id = "HIP08 ",
+ .oem_revision = 0x402,
+ }
+};
+
+static void pl011_check_hisi_workaround(void)
+{
+ struct acpi_table_header *tbl;
+ acpi_status status = AE_OK;
+ int i;
+
+ status = acpi_get_table(ACPI_SIG_MADT, 0, &tbl);
+ if (ACPI_FAILURE(status) || !tbl)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(pl011_wkrd_info); i++) {
+ if (!memcmp(pl011_wkrd_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
+ !memcmp(pl011_wkrd_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
+ pl011_wkrd_info[i].oem_revision == tbl->oem_revision) {
+ pl011_enable_hisi_wkrd = true;
+ break;
+ }
+ }
+}
+
+#else
+#define pl011_enable_hisi_wkrd 0
+static inline void pl011_check_hisi_workaround(void){ }
+#endif
+
static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
@@ -1510,6 +1567,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
handled = 1;
}
+ if (pl011_enable_hisi_wkrd) {
+ pl011_write(0, uap, REG_IMSC);
+ pl011_write(uap->im, uap, REG_IMSC);
+ }
+
spin_unlock_irqrestore(&uap->port.lock, flags);
return IRQ_RETVAL(handled);
@@ -1687,6 +1749,8 @@ static int pl011_hwinit(struct uart_port *port)
if (plat->init)
plat->init();
}
+
+ pl011_check_hisi_workaround();
return 0;
}
--
2.25.1