From patchwork Thu May 25 09:31:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 686352 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D8627C7EE2F for ; Thu, 25 May 2023 09:35:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240602AbjEYJen (ORCPT ); Thu, 25 May 2023 05:34:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240503AbjEYJek (ORCPT ); Thu, 25 May 2023 05:34:40 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF70919C; Thu, 25 May 2023 02:34:30 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1685007268; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4NGWDH2m9xz3zGie63zl1kcLGjTJ0fX1VflVrGzz2ZQ=; b=Kja8EByGHMg80rkSKT9+A6oAP7Ytw5mSKQu0+uGfVfwe5tVdGCEi5josuEM1SwN606+mom tJOhrFWIt2zJG+DlK5DjPmWfVz6loRqSChpbkp8HXvZab2zEzJXhmgL0k+AWUZunXGh4bK ZB+SftTZW59pKhVFlzUNZNYOpZMdX8zxvpepVbJv55/P+jYmWnd8ln/AejbG3dDoZJevAa J7Qto8rkUPaEA13Qh78iauHtxD9/MNjhQsamwocWO64h7fGgSzp5rGrAHv5Xn4mRXNmpig fi0pD7NC4PYFiEdTiZBJclw3eqzxfLzFQqzujGa99ba9O296DwZrG+8YpmfJ+w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1685007268; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4NGWDH2m9xz3zGie63zl1kcLGjTJ0fX1VflVrGzz2ZQ=; b=mmiTP6jCW1+KvC8QM+LWeB5WcVHbyStKgJqzDNEQsZrG0o3PYsrEqd/a7KE5S+4YPNPZjx 20P+WWxS57IdbmBQ== To: Greg Kroah-Hartman Cc: Petr Mladek , Thomas Gleixner , linux-kernel@vger.kernel.org, Al Cooper , Broadcom internal kernel review list , Jiri Slaby , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Lino Sanfilippo , Matthew Howell , Tony Lindgren , Lukas Wunner , Matthias Schiffer , Andy Shevchenko , =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= , linux-serial@vger.kernel.org Subject: [PATCH tty v1 1/8] serial: 8250: lock port in startup() callbacks Date: Thu, 25 May 2023 11:37:52 +0206 Message-Id: <20230525093159.223817-2-john.ogness@linutronix.de> In-Reply-To: <20230525093159.223817-1-john.ogness@linutronix.de> References: <20230525093159.223817-1-john.ogness@linutronix.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org uart_ops startup() callback is called without interrupts disabled and without port->lock locked, relatively late during the boot process (from the call path of console_on_rootfs()). If the device is a console, it was already previously registered and could be actively printing messages. The console printing function serial8250_console_write() modifies the interrupt register (UART_IER) under the port->lock with the pattern: read, clear, restore. Since some startup() callbacks are modifying UART_IER without the port->lock locked, it is possible that the value intended to be written by the startup() callback will get overwritten and be lost. CPU0 CPU1 serial8250_console_write omap_8250_startup -------------------------- ----------------- spin_lock(port->lock) oldval = read(UART_IER) uart_console_write() write(newval, UART_IER) write(oldval, UART_IER) spin_unlock(port->lock) Add port->lock synchronization to the 8250 startup() callbacks where they need to access UART_IER. This avoids racing with serial8250_console_write(). Signed-off-by: John Ogness --- drivers/tty/serial/8250/8250_bcm7271.c | 4 ++++ drivers/tty/serial/8250/8250_exar.c | 4 ++++ drivers/tty/serial/8250/8250_omap.c | 3 +++ drivers/tty/serial/8250/8250_port.c | 18 ++++++++++++++++-- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index f801b1f5b46c..2b38bcc5112e 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -605,9 +605,13 @@ static int brcmuart_startup(struct uart_port *port) /* * Disable the Receive Data Interrupt because the DMA engine * will handle this. + * + * Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); up->ier &= ~UART_IER_RDI; serial_port_out(port, UART_IER, up->ier); + spin_unlock_irq(&port->lock); priv->tx_running = false; priv->dma.rx_dma = NULL; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 64770c62bbec..ae66ef9d863c 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -194,8 +194,12 @@ static int xr17v35x_startup(struct uart_port *port) /* * Make sure all interrups are masked until initialization is * complete and the FIFOs are cleared + * + * Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); serial_port_out(port, UART_IER, 0); + spin_unlock_irq(&port->lock); return serial8250_do_startup(port); } diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 5c093dfcee1d..fbca0692aa51 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -710,8 +710,11 @@ static int omap_8250_startup(struct uart_port *port) up->dma = NULL; } + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); up->ier = UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); + spin_unlock_irq(&port->lock); #ifdef CONFIG_PM up->capabilities |= UART_CAP_RPM; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 0cef9bfd0471..b3971302d8e5 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2149,7 +2149,12 @@ int serial8250_do_startup(struct uart_port *port) serial8250_rpm_get(up); if (port->type == PORT_16C950) { - /* Wake up and initialize UART */ + /* + * Wake up and initialize UART + * + * Synchronize UART_IER access against the console. + */ + spin_lock_irqsave(&port->lock, flags); up->acr = 0; serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); @@ -2159,12 +2164,19 @@ int serial8250_do_startup(struct uart_port *port) serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); serial_port_out(port, UART_EFR, UART_EFR_ECB); serial_port_out(port, UART_LCR, 0); + spin_unlock_irqrestore(&port->lock, flags); } if (port->type == PORT_DA830) { - /* Reset the port */ + /* + * Reset the port + * + * Synchronize UART_IER access against the console. + */ + spin_lock_irqsave(&port->lock, flags); serial_port_out(port, UART_IER, 0); serial_port_out(port, UART_DA830_PWREMU_MGMT, 0); + spin_unlock_irqrestore(&port->lock, flags); mdelay(10); /* Enable Tx, Rx and free run mode */ @@ -2275,6 +2287,8 @@ int serial8250_do_startup(struct uart_port *port) * this interrupt whenever the transmitter is idle and * the interrupt is enabled. Delays are necessary to * allow register changes to become visible. + * + * Synchronize UART_IER access against the console. */ spin_lock_irqsave(&port->lock, flags); From patchwork Thu May 25 09:31:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 686353 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05960C7EE2E for ; Thu, 25 May 2023 09:34:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240648AbjEYJel (ORCPT ); Thu, 25 May 2023 05:34:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60588 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240519AbjEYJeg (ORCPT ); Thu, 25 May 2023 05:34:36 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 548C71A2; Thu, 25 May 2023 02:34:31 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1685007269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4e3/MmglhQzDhzxZKmrh29ltZzGLtHjU6m+4lcF3Ohc=; b=NTr1IkyQZ3OjcNlK4kp6xH1FWtIZitO+012FKXjtrrK1TncJzHvVRCKB2HJMfrJeLNwbdv JqTB4lbCkHpWdmGVU5IV0oSMOrnCgco1IrJYFalyMgIYhkmoF+ls8sWoIXWwGHBTvAv2VM AsESQbtcYDRinZpSMAv2lQTsnptfIbem7K8AtFoGqFwud1/rfvw7F05ZvxvRy0LATu+F8T D+EFAcJK7ms+VnYmR2p2r9Qpx1ZLFq6Z0RTlRc1a0UNByZ9v138z6/F1HL5D3TdYva9DEW wga+ysXcWpNnhcGd/bCi+WRLYUf/VVV3R00jadPPgDtnIqKZbThruZgML7Vlfw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1685007269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4e3/MmglhQzDhzxZKmrh29ltZzGLtHjU6m+4lcF3Ohc=; b=OQ/ky65DAwfr8I0FKrHj0L+b/kkpcdBW/cvTc4v+Gja6TPoPnsWTFi/SGx6YP134mMOLhZ Z42apekShbMWanBQ== To: Greg Kroah-Hartman Cc: Petr Mladek , Thomas Gleixner , linux-kernel@vger.kernel.org, Jiri Slaby , Vijaya Krishna Nivarthi , Douglas Anderson , linux-serial@vger.kernel.org Subject: [PATCH tty v1 4/8] serial: core: lock port for start_rx() in uart_resume_port() Date: Thu, 25 May 2023 11:37:55 +0206 Message-Id: <20230525093159.223817-5-john.ogness@linutronix.de> In-Reply-To: <20230525093159.223817-1-john.ogness@linutronix.de> References: <20230525093159.223817-1-john.ogness@linutronix.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org The only user of the start_rx() callback (qcom_geni) directly calls its own stop_rx() callback. Since stop_rx() requires that the port->lock is taken and interrupts are disabled, the start_rx() callback has the same requirement. Fixes: cfab87c2c271 ("serial: core: Introduce callback for start_rx and do stop_rx in suspend only if this callback implementation is present.") Signed-off-by: John Ogness --- drivers/tty/serial/serial_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 37ad53616372..f856c7fae2fd 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2430,8 +2430,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (console_suspend_enabled) uart_change_pm(state, UART_PM_STATE_ON); uport->ops->set_termios(uport, &termios, NULL); - if (!console_suspend_enabled && uport->ops->start_rx) + if (!console_suspend_enabled && uport->ops->start_rx) { + spin_lock_irq(&uport->lock); uport->ops->start_rx(uport); + spin_unlock_irq(&uport->lock); + } if (console_suspend_enabled) console_start(uport->cons); } From patchwork Thu May 25 09:31:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 686351 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1FA00C77B7A for ; Thu, 25 May 2023 09:35:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240618AbjEYJfI (ORCPT ); Thu, 25 May 2023 05:35:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60670 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240627AbjEYJel (ORCPT ); Thu, 25 May 2023 05:34:41 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 074271B1; Thu, 25 May 2023 02:34:33 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1685007270; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nPDJHm4lU4uW5PYPRilpSR3PUXlYNGeyc1k5gm2WMrg=; b=Bn9RR6tFw4VHxMRtNu5ITPrZWhJi9VsTk3Ief2f7HcBlEtLMBnVNouWr0IM4OCsP02Dq7Q gdWxPPKFD6kokGHfylzCLf1elFujWvrjGvnJqujbqfHuADfuMLyd6ENik68sarNNrhQFuE c4RkxSMLo7Jg4Ctn+oJapV4snGobAEx0h5zm/6LKkgV48KMBlXtUQ7u4cf07BFSCaEYVjs CLVHT/h0C+zTSycU3IFxqCaSwRZY02Qgl4LpRpu15aLv5QBON8m6QA+BXf3T7MUmdcMh/v tARTQSo+S9rmvPFdJm8rCofDsynBzdEdXV+R9vlJp9w5Fe5d9Bc6DCZitRM3iw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1685007270; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nPDJHm4lU4uW5PYPRilpSR3PUXlYNGeyc1k5gm2WMrg=; b=D7c8sfO9B0xWafdKccZQxoeJ+NYAiCmP6zJoGfo+FNhKFSWjUhH4xcqrDjjtHasOyuCFUa o6+70hF7B7N+QMDA== To: Greg Kroah-Hartman Cc: Petr Mladek , Thomas Gleixner , linux-kernel@vger.kernel.org, Jiri Slaby , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Tony Lindgren , Lukas Wunner , Matthias Schiffer , linux-serial@vger.kernel.org Subject: [PATCH tty v1 6/8] serial: 8250: lock port for omap8250_restore_regs() Date: Thu, 25 May 2023 11:37:57 +0206 Message-Id: <20230525093159.223817-7-john.ogness@linutronix.de> In-Reply-To: <20230525093159.223817-1-john.ogness@linutronix.de> References: <20230525093159.223817-1-john.ogness@linutronix.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org omap8250_restore_regs() accesses UART_IER. This register is modified twice by each console write (serial8250_console_write()) under the port lock. However, not all calls to omap8250_restore_regs() are under the port lock. Add the missing port locking around omap8250_restore_regs() calls. Add lockdep notation to the omap8250_restore_regs(). Note that this is not fixing a real problem because the serial devices are resumed before console printing is enabled. However, adding this locking allows for clean locking semantics for omap8250_restore_regs() so that lockdep can be used to identify possible problems in the future. It also simplifies synchronization of UART_IER in general by not needing to rely on such implementation details. Signed-off-by: John Ogness --- drivers/tty/serial/8250/8250_omap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 3cb9cfa62331..34939462fd69 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -309,6 +309,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up) struct uart_8250_dma *dma = up->dma; u8 mcr = serial8250_in_MCR(up); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (dma && dma->tx_running) { /* * TCSANOW requests the change to occur immediately however if @@ -1739,8 +1742,11 @@ static int omap8250_runtime_resume(struct device *dev) if (priv->line >= 0) up = serial8250_get_port(priv->line); - if (up && omap8250_lost_context(up)) + if (up && omap8250_lost_context(up)) { + spin_lock_irq(&up->port.lock); omap8250_restore_regs(up); + spin_unlock_irq(&up->port.lock); + } if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) { spin_lock_irq(&up->port.lock); From patchwork Thu May 25 09:31:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 686350 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 100E1C7EE2E for ; Thu, 25 May 2023 09:35:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240699AbjEYJfL (ORCPT ); Thu, 25 May 2023 05:35:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbjEYJem (ORCPT ); Thu, 25 May 2023 05:34:42 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 529FEE42; Thu, 25 May 2023 02:34:37 -0700 (PDT) From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1685007271; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vZVepLjGQmA8Sd7Dsoz91hGyNnRRVtsxo9tL/VycGyM=; b=uZ3fJDvn3TkdggxynrSMSfRfldyWS4BjQknTKnFLPsovz8j7ATjj9wKY0YrNVgjmstnPDp RpaZS25BsNwZGpaoJ/p7EJJ0uIbBlS2FUZb7JOxDaj01/dymaraJMQq3HMBNo8AdoDtjj9 zicPN9Y+n59Eio5tvFDuMNg3FqCmngFYk44jhQfhJmmgYQqabA/sWVdNy5FxqS89PuRfOd aIlGwXIVvB3HqG5QjnSzYqSFoy17PnFrpG0S42MoYhVVriluyO/v7qDu49txvu1bQtu0UR T/hMyr5UmoePZahxw43d/YnRICYxjiOuqkO5KdkecSSs27EigiIE7kgVE4e+xA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1685007271; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vZVepLjGQmA8Sd7Dsoz91hGyNnRRVtsxo9tL/VycGyM=; b=sSWawuGzshyC+A1UZwduoT3u0VBy5TcXDOddQy8qoXvVAcuzGJyKZcT9rD6R+qnYz6FWGe gQLD6b6k+lHbNkAw== To: Greg Kroah-Hartman Cc: Petr Mladek , Thomas Gleixner , linux-kernel@vger.kernel.org, Jiri Slaby , Joel Stanley , Andrew Jeffery , Matthias Brugger , AngeloGioacchino Del Regno , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Andy Shevchenko , Tony Lindgren , Lukas Wunner , Matthias Schiffer , =?utf-8?q?Uwe_Kleine?= =?utf-8?q?-K=C3=B6nig?= , linux-serial@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-mediatek@lists.infradead.org Subject: [PATCH tty v1 8/8] serial: 8250: synchronize and annotate UART_IER access Date: Thu, 25 May 2023 11:37:59 +0206 Message-Id: <20230525093159.223817-9-john.ogness@linutronix.de> In-Reply-To: <20230525093159.223817-1-john.ogness@linutronix.de> References: <20230525093159.223817-1-john.ogness@linutronix.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org The UART_IER register is modified twice by each console write (serial8250_console_write()) under the port lock. Any driver code that accesses UART_IER must do so with the port locked in order to ensure consistent values, even when for read accesses. Add locking, lockdep notation, and/or comments everywhere UART_IER is accessed. The added locking is not fixing a real problem because it occurs where the console is not active. However, adding the locking to these non-critical paths greatly simplifies UART_IER access tracking by establishing a general policy that all UART_IER access is performed with the port locked. Signed-off-by: John Ogness --- drivers/tty/serial/8250/8250.h | 6 +++ drivers/tty/serial/8250/8250_aspeed_vuart.c | 3 ++ drivers/tty/serial/8250/8250_mtk.c | 9 ++++ drivers/tty/serial/8250/8250_omap.c | 14 ++++++ drivers/tty/serial/8250/8250_port.c | 53 +++++++++++++++++++++ 5 files changed, 85 insertions(+) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 5418708f4631..471c6bc5f78f 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -179,6 +179,9 @@ static inline void serial_dl_write(struct uart_8250_port *up, u32 value) static inline bool serial8250_set_THRI(struct uart_8250_port *up) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (up->ier & UART_IER_THRI) return false; up->ier |= UART_IER_THRI; @@ -188,6 +191,9 @@ static inline bool serial8250_set_THRI(struct uart_8250_port *up) static inline bool serial8250_clear_THRI(struct uart_8250_port *up) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (!(up->ier & UART_IER_THRI)) return false; up->ier &= ~UART_IER_THRI; diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 9d2a7856784f..4a9e71b2dbbc 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -275,6 +275,9 @@ static void __aspeed_vuart_set_throttle(struct uart_8250_port *up, { unsigned char irqs = UART_IER_RLSI | UART_IER_RDI; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + up->ier &= ~irqs; if (!throttle) up->ier |= irqs; diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index fb1d5ec0940e..aa8e98164d68 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -222,11 +222,17 @@ static void mtk8250_shutdown(struct uart_port *port) static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); } static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); } @@ -235,6 +241,9 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) struct uart_port *port = &up->port; int lcr = serial_in(up, UART_LCR); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, MTK_UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, lcr); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 3225c95fde1d..0498b9b0e4e9 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -533,6 +533,10 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, u8 efr; pm_runtime_get_sync(port->dev); + + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -543,6 +547,8 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); + spin_unlock_irq(&port->lock); + pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); } @@ -760,8 +766,11 @@ static void omap_8250_shutdown(struct uart_port *port) if (priv->habit & UART_HAS_EFR2) serial_out(up, UART_OMAP_EFR2, 0x0); + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); up->ier = 0; serial_out(up, UART_IER, 0); + spin_unlock_irq(&port->lock); disable_irq_nosync(up->port.irq); dev_pm_clear_wake_irq(port->dev); @@ -803,6 +812,7 @@ static void omap_8250_unthrottle(struct uart_port *port) pm_runtime_get_sync(port->dev); + /* Synchronize UART_IER access against the console. */ spin_lock_irqsave(&port->lock, flags); priv->throttled = false; if (up->dma) @@ -953,6 +963,7 @@ static void __dma_rx_complete(void *param) struct dma_tx_state state; unsigned long flags; + /* Synchronize UART_IER access against the console. */ spin_lock_irqsave(&p->port.lock, flags); /* @@ -1227,6 +1238,9 @@ static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + /* * Queue a new transfer if FIFO has data. */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b3971302d8e5..4b7bbd8b3305 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -539,6 +539,9 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); */ static int serial8250_em485_init(struct uart_8250_port *p) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + if (p->em485) goto deassert_rts; @@ -676,6 +679,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial8250_rpm_get(p); if (p->capabilities & UART_CAP_SLEEP) { + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&p->port.lock); if (p->capabilities & UART_CAP_EFR) { lcr = serial_in(p, UART_LCR); efr = serial_in(p, UART_EFR); @@ -689,6 +694,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial_out(p, UART_EFR, efr); serial_out(p, UART_LCR, lcr); } + spin_unlock_irq(&p->port.lock); } serial8250_rpm_put(p); @@ -696,6 +702,9 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) static void serial8250_clear_IER(struct uart_8250_port *up) { + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + if (up->capabilities & UART_CAP_UUE) serial_out(up, UART_IER, UART_IER_UUE); else @@ -968,6 +977,9 @@ static void autoconfig_16550a(struct uart_8250_port *up) unsigned char status1, status2; unsigned int iersave; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&up->port.lock); + up->port.type = PORT_16550A; up->capabilities |= UART_CAP_FIFO; @@ -1151,6 +1163,8 @@ static void autoconfig(struct uart_8250_port *up) /* * We really do need global IRQs disabled here - we're going to * be frobbing the chips IRQ enable register to see if it exists. + * + * Synchronize UART_IER access against the console. */ spin_lock_irqsave(&port->lock, flags); @@ -1323,7 +1337,10 @@ static void autoconfig_irq(struct uart_8250_port *up) /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); save_mcr = serial8250_in_MCR(up); + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); save_ier = serial_in(up, UART_IER); + spin_unlock_irq(&port->lock); serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); @@ -1335,7 +1352,10 @@ static void autoconfig_irq(struct uart_8250_port *up) serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); serial_out(up, UART_IER, UART_IER_ALL_INTR); + spin_unlock_irq(&port->lock); serial_in(up, UART_LSR); serial_in(up, UART_RX); serial_in(up, UART_IIR); @@ -1345,7 +1365,10 @@ static void autoconfig_irq(struct uart_8250_port *up) irq = probe_irq_off(irqs); serial8250_out_MCR(up, save_mcr); + /* Synchronize UART_IER access against the console. */ + spin_lock_irq(&port->lock); serial_out(up, UART_IER, save_ier); + spin_unlock_irq(&port->lock); if (port->flags & UPF_FOURPORT) outb_p(save_ICP, ICP); @@ -1360,6 +1383,9 @@ static void serial8250_stop_rx(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + serial8250_rpm_get(up); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); @@ -1379,6 +1405,9 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) { unsigned char mcr = serial8250_in_MCR(p); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) mcr |= UART_MCR_RTS; else @@ -1428,6 +1457,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay) { struct uart_8250_em485 *em485 = p->em485; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&p->port.lock); + stop_delay += (u64)p->port.rs485.delay_rts_after_send * NSEC_PER_MSEC; /* @@ -1607,6 +1639,9 @@ static void serial8250_start_tx(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + if (!port->x_char && uart_circ_empty(&port->state->xmit)) return; @@ -1634,6 +1669,9 @@ static void serial8250_disable_ms(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) return; @@ -1648,6 +1686,9 @@ static void serial8250_enable_ms(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + /* Port locked to synchronize UART_IER access against the console. */ + lockdep_assert_held_once(&port->lock); + /* no MSR capabilities */ if (up->bugs & UART_BUG_NOMSR) return; @@ -2104,6 +2145,14 @@ static void serial8250_put_poll_char(struct uart_port *port, unsigned int ier; struct uart_8250_port *up = up_to_u8250p(port); + /* + * Normally the port is locked to synchronize UART_IER access + * against the console. However, this function is only used by + * KDB/KGDB, where it may not be possible to acquire the port + * lock because all other CPUs are quiesced. The quiescence + * should allow safe lockless usage here. + */ + serial8250_rpm_get(up); /* * First save the IER then disable the interrupts @@ -2439,6 +2488,8 @@ void serial8250_do_shutdown(struct uart_port *port) serial8250_rpm_get(up); /* * Disable interrupts from this port + * + * Synchronize UART_IER access against the console. */ spin_lock_irqsave(&port->lock, flags); up->ier = 0; @@ -2738,6 +2789,8 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ok, we're now changing the port state. Do it with * interrupts disabled. + * + * Synchronize UART_IER access against the console. */ serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags);