stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH AUTOSEL 4.9 01/29] sc16is7xx: Fix for "Unexpected interrupt: 8"
@ 2019-10-18 22:08 Sasha Levin
  2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 02/29] HID: i2c-hid: add Direkt-Tek DTLAPY133-1 to descriptor override Sasha Levin
                   ` (27 more replies)
  0 siblings, 28 replies; 29+ messages in thread
From: Sasha Levin @ 2019-10-18 22:08 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Phil Elwell, Greg Kroah-Hartman, Sasha Levin, linux-serial

From: Phil Elwell <phil@raspberrypi.org>

[ Upstream commit 30ec514d440cf2c472c8e4b0079af2c731f71a3e ]

The SC16IS752 has an Enhanced Feature Register which is aliased at the
same address as the Interrupt Identification Register; accessing it
requires that a magic value is written to the Line Configuration
Register. If an interrupt is raised while the EFR is mapped in then
the ISR won't be able to access the IIR, leading to the "Unexpected
interrupt" error messages.

Avoid the problem by claiming a mutex around accesses to the EFR
register, also claiming the mutex in the interrupt handler work
item (this is equivalent to disabling interrupts to interlock against
a non-threaded interrupt handler).

See: https://github.com/raspberrypi/linux/issues/2529

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/tty/serial/sc16is7xx.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 82451bb6622bd..f80a88d107d7f 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -332,6 +332,7 @@ struct sc16is7xx_port {
 	struct kthread_worker		kworker;
 	struct task_struct		*kworker_task;
 	struct kthread_work		irq_work;
+	struct mutex			efr_lock;
 	struct sc16is7xx_one		p[0];
 };
 
@@ -503,6 +504,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
 		div /= 4;
 	}
 
+	/* In an amazing feat of design, the Enhanced Features Register shares
+	 * the address of the Interrupt Identification Register, and is
+	 * switched in by writing a magic value (0xbf) to the Line Control
+	 * Register. Any interrupt firing during this time will see the EFR
+	 * where it expects the IIR to be, leading to "Unexpected interrupt"
+	 * messages.
+	 *
+	 * Prevent this possibility by claiming a mutex while accessing the
+	 * EFR, and claiming the same mutex from within the interrupt handler.
+	 * This is similar to disabling the interrupt, but that doesn't work
+	 * because the bulk of the interrupt processing is run as a workqueue
+	 * job in thread context.
+	 */
+	mutex_lock(&s->efr_lock);
+
 	lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
 
 	/* Open the LCR divisors for configuration */
@@ -518,6 +534,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
 	/* Put LCR back to the normal mode */
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+	mutex_unlock(&s->efr_lock);
+
 	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
 			      SC16IS7XX_MCR_CLKSEL_BIT,
 			      prescaler);
@@ -700,6 +718,8 @@ static void sc16is7xx_ist(struct kthread_work *ws)
 {
 	struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
 
+	mutex_lock(&s->efr_lock);
+
 	while (1) {
 		bool keep_polling = false;
 		int i;
@@ -709,6 +729,8 @@ static void sc16is7xx_ist(struct kthread_work *ws)
 		if (!keep_polling)
 			break;
 	}
+
+	mutex_unlock(&s->efr_lock);
 }
 
 static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@@ -903,6 +925,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
 	if (!(termios->c_cflag & CREAD))
 		port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
 
+	/* As above, claim the mutex while accessing the EFR. */
+	mutex_lock(&s->efr_lock);
+
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
 			     SC16IS7XX_LCR_CONF_MODE_B);
 
@@ -924,6 +949,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
 	/* Update LCR register */
 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+	mutex_unlock(&s->efr_lock);
+
 	/* Get baud rate generator configuration */
 	baud = uart_get_baud_rate(port, termios, old,
 				  port->uartclk / 16 / 4 / 0xffff,
@@ -1186,6 +1213,7 @@ static int sc16is7xx_probe(struct device *dev,
 	s->regmap = regmap;
 	s->devtype = devtype;
 	dev_set_drvdata(dev, s);
+	mutex_init(&s->efr_lock);
 
 	kthread_init_worker(&s->kworker);
 	kthread_init_work(&s->irq_work, sc16is7xx_ist);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2019-10-18 22:14 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-18 22:08 [PATCH AUTOSEL 4.9 01/29] sc16is7xx: Fix for "Unexpected interrupt: 8" Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 02/29] HID: i2c-hid: add Direkt-Tek DTLAPY133-1 to descriptor override Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 03/29] x86/cpu: Add Atom Tremont (Jacobsville) Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 04/29] HID: i2c-hid: Add Odys Winbook 13 to descriptor override Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 05/29] scripts/setlocalversion: Improve -dirty check with git-status --no-optional-locks Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 06/29] usb: handle warm-reset port requests on hub resume Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 07/29] rtc: pcf8523: set xtal load capacitance from DT Sasha Levin
2019-10-18 22:08 ` [PATCH AUTOSEL 4.9 08/29] exec: load_script: Do not exec truncated interpreter path Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 09/29] iio: fix center temperature of bmc150-accel-core Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 10/29] perf map: Fix overlapped map handling Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 11/29] perf jevents: Fix period for Intel fixed counters Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 12/29] staging: rtl8188eu: fix null dereference when kzalloc fails Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 13/29] RDMA/iwcm: Fix a lock inversion issue Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 14/29] gpio: max77620: Use correct unit for debounce times Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 15/29] fs: cifs: mute -Wunused-const-variable message Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 16/29] serial: mctrl_gpio: Check for NULL pointer Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 17/29] efi/cper: Fix endianness of PCIe class code Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 18/29] efi/x86: Do not clean dummy variable in kexec path Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 19/29] ocfs2: clear zero in unaligned direct IO Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 20/29] fs: ocfs2: fix possible null-pointer dereferences in ocfs2_xa_prepare_entry() Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 21/29] fs: ocfs2: fix a possible null-pointer dereference in ocfs2_write_end_nolock() Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 22/29] fs: ocfs2: fix a possible null-pointer dereference in ocfs2_info_scan_inode_alloc() Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 23/29] iio: adc: ad799x: fix probe error handling Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 24/29] iio: light: opt3001: fix mutex unlock race Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 25/29] MIPS: fw: sni: Fix out of bounds init of o32 stack Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 26/29] USB: usb-skeleton: fix use-after-free after driver unbind Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 27/29] NFSv4: Fix leak of clp->cl_acceptor string Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 28/29] s390/uaccess: avoid (false positive) compiler warnings Sasha Levin
2019-10-18 22:09 ` [PATCH AUTOSEL 4.9 29/29] tracing: Initialize iter->seq after zeroing in tracing_read_pipe() Sasha Levin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).