Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp176701pxv; Wed, 14 Jul 2021 01:08:23 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxEqFpmoRpaN9SIjPdhY/ne0EUqk7AkooYMkxFQYxmBR4kHXy3MHDIewg+3H6n2zbmKTsaH X-Received: by 2002:a05:6e02:68c:: with SMTP id o12mr6254079ils.261.1626250103644; Wed, 14 Jul 2021 01:08:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626250103; cv=none; d=google.com; s=arc-20160816; b=Up0NnxvMaggyEys0pnfrZdDgkHAl557w7SP/7+hTIEI+ZcO5ZBclr0Xf6VPz0rQQLy 3ziHXlQxqFAt1C34YaOr4cXlUMqmwUp/lbVskExGSJ0uvArOm/4or+q7JpRyl6TlL9j6 iBRXbuMswPVPy7JbYQ2TQaj7F73GZYhBimSf5/4eMvuBDTG/VlURoGD4hGbDIrbHojHk jzUUAKU7TpgJr47iJIoqeJuI1O/uaPvHwXe4Fpl7XqQdV5FDVA089ilmqgpRW0dhFs41 E0PwP1rCIiA1szS9j1RCIcUroDokKbCEMV5cLkeD+M1NXPSaw2AJhcraSP2Mvi8LVy9s aZSQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=aqfOa/Ws7Q0Q+zivPwZYqtn4r+aia/KCiCpa5MgmJT8=; b=xvgP5Q9l9FBWGl83GSR/U3c6/VbDub+NFoBN78KnSk3huAv0MqobmsT7pnHpd8D4EE FrRiN46xMp3jJCAQvdmaGh0NZAbwQahIQ/uOhQptRyC/n0OAEpzEmLvZZUoT25/3l3ZM oNM+TOZMUwrfRC74ObSuBJukCi2nwUK/GKRaBjgdj+Z361/MOzsknFZqLegLi/TkwJ0g wbnRRiF5n7Igue61OlwMP7wXuueLA+aMWBYqpWdYD2YIUJkh/K93Dorrx9DHQPbt6Ysu Msxe+5ouX9AIZ4T51+2cA/Xn11XClfVz64KnmENdPiZMFnZi6b4m9Ytamwob3V2sIyLA 563g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=DXxuwXaL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z12si1526100iln.160.2021.07.14.01.08.11; Wed, 14 Jul 2021 01:08:23 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=DXxuwXaL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238420AbhGNIJk (ORCPT + 99 others); Wed, 14 Jul 2021 04:09:40 -0400 Received: from mail.kernel.org ([198.145.29.99]:34446 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238385AbhGNIJj (ORCPT ); Wed, 14 Jul 2021 04:09:39 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 58FA3613AF; Wed, 14 Jul 2021 08:06:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626250008; bh=Ya3u94eMIcTHm5PPl4FfDKsZbgE5F56Nv1jfp2qsi8Y=; h=From:To:Cc:Subject:Date:From; b=DXxuwXaLwhI9n2rtysmsiXshuTT4jZIfwP4LrA8Ah/69Pg8rJrWjavP4kfhSitSjV RwBrWYuFqveLqZQ3dL49cWAfoX8Q9wVcpifnpnhN1lf6+yPStO6CfSONrSpRpbg2bI 4r5TvL3Ys2wrVVg3WbxJZjN4bMtidPRa5jBwpbNwtWHEDan78BlHil4rrffWNwzZWt PhJZwdhW8wG2EhN84fi82OMR9PfwxVlnbYuDmYU37SdVhZTYOcVUsBSscWjyDJqldW nkuXzshcT6Np4Te4lpzrtBpl0GWHc5gaxfP8YKrXwrWwM3UxsRxDRbwW9Pmg14o6yK 9iyVHMskpfQOw== Received: from johan by xi.lan with local (Exim 4.94.2) (envelope-from ) id 1m3ZuX-0007LK-KG; Wed, 14 Jul 2021 10:06:30 +0200 From: Johan Hovold To: Greg Kroah-Hartman Cc: Jiri Slaby , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Johan Hovold , kernel test robot , stable@vger.kernel.org, Joel Stanley , Andrew Jeffery Subject: [PATCH] serial: 8250: fix handle_irq locking Date: Wed, 14 Jul 2021 10:04:27 +0200 Message-Id: <20210714080427.28164-1-johan@kernel.org> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The 8250 handle_irq callback is not just called from the interrupt handler but also from a timer callback when polling (e.g. for ports without an interrupt line). Consequently the callback must explicitly disable interrupts to avoid a potential deadlock with another interrupt in polled mode. Add back an irqrestore-version of the sysrq port-unlock helper and use it in the 8250 callbacks that need it. Fixes: 75f4e830fa9c ("serial: do not restore interrupt state in sysrq helper") Reported-by: kernel test robot Cc: stable@vger.kernel.org # 5.13 Cc: Joel Stanley Cc: Andrew Jeffery Signed-off-by: Johan Hovold --- drivers/tty/serial/8250/8250_aspeed_vuart.c | 5 +++-- drivers/tty/serial/8250/8250_fsl.c | 5 +++-- drivers/tty/serial/8250/8250_port.c | 5 +++-- include/linux/serial_core.h | 24 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 4caab8714e2c..2350fb3bb5e4 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -329,6 +329,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir, lsr; + unsigned long flags; unsigned int space, count; iir = serial_port_in(port, UART_IIR); @@ -336,7 +337,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (iir & UART_IIR_NO_INT) return 0; - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); lsr = serial_port_in(port, UART_LSR); @@ -370,7 +371,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); - uart_unlock_and_check_sysrq(port); + uart_unlock_and_check_sysrq_irqrestore(port, flags); return 1; } diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 4e75d2e4f87c..fc65a2293ce9 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -30,10 +30,11 @@ struct fsl8250_data { int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; + unsigned long flags; unsigned int iir; struct uart_8250_port *up = up_to_u8250p(port); - spin_lock(&up->port.lock); + spin_lock_irqsave(&up->port.lock, flags); iir = port->serial_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) { @@ -82,7 +83,7 @@ int fsl8250_handle_irq(struct uart_port *port) up->lsr_saved_flags = orig_lsr; - uart_unlock_and_check_sysrq(&up->port); + uart_unlock_and_check_sysrq_irqrestore(&up->port, flags); return 1; } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 2164290cbd31..d65778c4e4ca 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1893,11 +1893,12 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) unsigned char status; struct uart_8250_port *up = up_to_u8250p(port); bool skip_rx = false; + unsigned long flags; if (iir & UART_IIR_NO_INT) return 0; - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); status = serial_port_in(port, UART_LSR); @@ -1923,7 +1924,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); - uart_unlock_and_check_sysrq(port); + uart_unlock_and_check_sysrq_irqrestore(port, flags); return 1; } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 52d7fb92a69d..c58cc142d23f 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -518,6 +518,25 @@ static inline void uart_unlock_and_check_sysrq(struct uart_port *port) if (sysrq_ch) handle_sysrq(sysrq_ch); } + +static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port, + unsigned long flags) +{ + int sysrq_ch; + + if (!port->has_sysrq) { + spin_unlock_irqrestore(&port->lock, flags); + return; + } + + sysrq_ch = port->sysrq_ch; + port->sysrq_ch = 0; + + spin_unlock_irqrestore(&port->lock, flags); + + if (sysrq_ch) + handle_sysrq(sysrq_ch); +} #else /* CONFIG_MAGIC_SYSRQ_SERIAL */ static inline int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) { @@ -531,6 +550,11 @@ static inline void uart_unlock_and_check_sysrq(struct uart_port *port) { spin_unlock(&port->lock); } +static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port, + unsigned long flags) +{ + spin_unlock_irqrestore(&port->lock, flags); +} #endif /* CONFIG_MAGIC_SYSRQ_SERIAL */ /* -- 2.31.1