From patchwork Tue Jan 7 21:26:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855644 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B364A1E1C22; Tue, 7 Jan 2025 21:27:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285227; cv=none; b=nLV0VUzobCkXqDwrHOdTqhSRbvwjPZtY3p19pQFebD5xZq8CVHMF4V4nCh6QmOMT2JssSm9tIPd7T22uxsa1a6zsqUlyahkOCSOV5FMmY03QqycALGqKrg+RVcrbNiaTfI9mcKd6eDUFirT5JO6e7dK+bie8Ff/DV0LbXq76lnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285227; c=relaxed/simple; bh=XDbzG0gcJbop7qXsJsxlnTF4HAqo+ydLvGwcJqZ2RcI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=uUi1C6feR4q6bBkhBIFkrbRvmI9P38osqUTXgnu1snAyjEGFmbsVOrDurP46oobEgxVkhNFtQCffKs/Pk9VaNWdj2kGXAn0AE/BEP0gqm0jKHI2FKZOKDHiCoKIEIoJL4BUHEpoRmKInI8ZXFztVbFBA8EM9BrxqbpL9DPDvPE4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=NHrVdoWl; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=ftpkPjD5; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="NHrVdoWl"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="ftpkPjD5" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285223; 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=4I6OfXIPQ0o4KssvrVrBILFnz2W2yB8TbDql7wg4hVc=; b=NHrVdoWlTURTz1RSTKVXne6ZgSybJEgMEjFKgQL/EbuYiKTpWaK2miDh+eo55oCbYK/CX3 XxIXOoskHj2dULakP8QPPldIQpu3OOymqTEtDEP4e1D20AnSrB/prD62OEWGlBrYE1n4mA KOC/jL0Qg2/xerkcxhtd1+0Ox+toxuvh2TtO1KpCSA/Rsln91ktsu+Dl6Kkn6mwudOWGz+ zUKNQRkeqTynPty7geafPoMS5RwGfOkgmyGYVe14oeEAi/aEAyhNvMAfKUVWg4InDYg8zv hoiOiVwai0Tc/xWFr7WgPFbs3Y9b/WZXr2uoelaED9jdFbduGeOy8Ghfp8KFlA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285223; 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=4I6OfXIPQ0o4KssvrVrBILFnz2W2yB8TbDql7wg4hVc=; b=ftpkPjD587Pm/MlhgnZmRaDHYASrsQO8gbWXzfjbHxx8UXsHIB93oMV2HfFxq2WmNJOyqh wz1UPNhUrnV0K6AQ== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko , Arnd Bergmann , Niklas Schnelle , Serge Semin , Wander Lairson Costa Subject: [PATCH tty-next v5 1/6] serial: 8250: Adjust the timeout for FIFO mode Date: Tue, 7 Jan 2025 22:32:57 +0106 Message-Id: <20250107212702.169493-2-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 After a console has written a record into UART_TX, it uses wait_for_xmitr() to wait until the data has been sent out before returning. However, wait_for_xmitr() will timeout after 10ms, regardless if the data has been transmitted or not. For single bytes, this timeout is sufficient even at very slow baud rates, such as 1200bps. However, when FIFO mode is used, there may be 64 bytes pushed into the FIFO at once. At a baud rate of 115200bps, the 10ms timeout is still sufficient. But when using lower baud rates (such as 57600bps), the timeout is _not_ sufficient. This causes longer lines to be cut off, resulting in lost and horribly misformatted output on the console. When using FIFO mode, take the number of bytes into account to determine an appropriate maximum timeout. Increasing the timeout does not affect performance since ideally the timeout never occurs. Fixes: 8f3631f0f6eb ("serial/8250: Use fifo in 8250 console driver") Signed-off-by: John Ogness Reviewed-by: Andy Shevchenko Reviewed-by: Wander Lairson Costa Reviewed-by: Petr Mladek --- drivers/tty/serial/8250/8250_port.c | 32 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1a65d3e5f3c0..3a946ebe9139 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2078,7 +2078,8 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) serial8250_rpm_put(up); } -static void wait_for_lsr(struct uart_8250_port *up, int bits) +/* Returns true if @bits were set, false on timeout */ +static bool wait_for_lsr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -2093,11 +2094,11 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits) udelay(1); touch_nmi_watchdog(); } + + return (tmout != 0); } -/* - * Wait for transmitter & holding register to empty - */ +/* Wait for transmitter and holding register to empty with timeout */ static void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int tmout; @@ -3322,6 +3323,16 @@ static void serial8250_console_restore(struct uart_8250_port *up) serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); } +static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + if (wait_for_lsr(up, UART_LSR_THRE)) + return; + } +} + /* * Print a string to the serial port using the device FIFO * @@ -3331,13 +3342,15 @@ static void serial8250_console_restore(struct uart_8250_port *up) static void serial8250_console_fifo_write(struct uart_8250_port *up, const char *s, unsigned int count) { - int i; const char *end = s + count; unsigned int fifosize = up->tx_loadsz; + unsigned int tx_count = 0; bool cr_sent = false; + unsigned int i; while (s != end) { - wait_for_lsr(up, UART_LSR_THRE); + /* Allow timeout for each byte of a possibly full FIFO */ + fifo_wait_for_lsr(up, fifosize); for (i = 0; i < fifosize && s != end; ++i) { if (*s == '\n' && !cr_sent) { @@ -3348,7 +3361,14 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up, cr_sent = false; } } + tx_count = i; } + + /* + * Allow timeout for each byte written since the caller will only wait + * for UART_LSR_BOTH_EMPTY using the timeout of a single character + */ + fifo_wait_for_lsr(up, tx_count); } /* From patchwork Tue Jan 7 21:26:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855907 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C66F21DF98E; Tue, 7 Jan 2025 21:27:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285228; cv=none; b=G9ZBD7ZWPaAorLXsfsy9/PcdWR5r9UqAM7f+jFQ+pn+ZuOO56wHnYhN4W2sCGuU2lOwcVOnN3WVAJSLlcSXaA+E2iWc2dPog6GW7EWypbFSFQZKOgMU4a2g/zhgvFaLIwLqnWslFPu8eHnar7Bn3BqIfS+qbq+URUX83Mu/Qs5s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285228; c=relaxed/simple; bh=k0Q7/kE8NFWHNVqwkfK4VuiF6b9NdEUM/yuU8tMN0yU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=OO4Na30ElYTNhFDmnYTjUqGijCp8t8Jb73YY93zEnhO7h46q7EPMb+4pwM9qoDxo0FBELNrCpQUrPfCzdvE1bv7Lc/3ATIUOEcyM254KW+FjLlc/Z3h+Q+DaGAMYLnS63+UZIgV5DCVADqNSjn8VrzGl7cGdYg5KnsbTFhJyHB8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=eaNzQpF3; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=/eM0g+St; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="eaNzQpF3"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="/eM0g+St" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285224; 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=MXHBlOmJeQ1OCbuaqy6OasohF0dAyiGphfIWtBEz/jg=; b=eaNzQpF3ErnHuhPJAByo3tJ/09h3jVwbeA3AwZc+XsXjDMHE+tBIJEHanENV6QK4tIspRr p6sN85i/nUNM/g5NoSjyk6nG5C4kDUaKE0B7EHaT0tR4eiWdbfX8xWnUawcUeMKPqK9G2s oaholfX3VRU+xazEyuXwHUIv3OKZaPd9yiOGI1NWw5J9VVSYsfajbHdK3AxXoppUxF/ZdV xqMVaXDbRBu4OsQNMBeFDrBW5QR3iic4qreezQ4TUNUQc3DHbqRfSoGm4mE1VkIFG0vP+1 d3mflhqWSMXQ3GXyqvWS3FkkS+XPGLAfK+emqxgB1fnnMTTUSgJTH1h+RnBU0w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285224; 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=MXHBlOmJeQ1OCbuaqy6OasohF0dAyiGphfIWtBEz/jg=; b=/eM0g+St07im1wc9YBFQM9f6hZ13n3lzXXoo9XcW70A02MxanVC9fZXAcMHkf2t7iop0WJ 2bwlOsr7ia6TgFBg== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko , Arnd Bergmann , Niklas Schnelle , Serge Semin Subject: [PATCH tty-next v5 2/6] serial: 8250: Use frame time to determine timeout Date: Tue, 7 Jan 2025 22:32:58 +0106 Message-Id: <20250107212702.169493-3-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Rather than using a hard-coded per-character Tx-timeout of 10ms, use the frame time to determine a timeout value. The value is doubled to ensure that a timeout is only hit during unexpected circumstances. Since the frame time may not be available during early printing, the previous 10ms value is kept as a fallback. Signed-off-by: John Ogness Reviewed-by: Petr Mladek --- drivers/tty/serial/8250/8250_port.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3a946ebe9139..ca8f6f3855eb 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2081,9 +2081,17 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) /* Returns true if @bits were set, false on timeout */ static bool wait_for_lsr(struct uart_8250_port *up, int bits) { - unsigned int status, tmout = 10000; + unsigned int status, tmout; + + /* + * Wait for a character to be sent. Fallback to a safe default + * timeout value if @frame_time is not available. + */ + if (up->port.frame_time) + tmout = up->port.frame_time * 2 / NSEC_PER_USEC; + else + tmout = 10000; - /* Wait up to 10ms for the character(s) to be sent. */ for (;;) { status = serial_lsr_in(up); From patchwork Tue Jan 7 21:26:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855643 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C67581F3D47; Tue, 7 Jan 2025 21:27:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285228; cv=none; b=fxAeAFBRSoWR0l03+LeLA0NDFzD4J7ICfBxE5wJnh54kAirkeAMuloFnrBimwcFryYCSxx+NHNFUJ/Ytm5HZl+rrjZP9ZNXYh+QnNx3OUXBHqY3G+FLHk21IkXqB+9OpfaVFB7OEpXiOvVMDRNH0lEXPwVsqfI95/Hwhrq4a6BM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285228; c=relaxed/simple; bh=aASTNKlKjZuw3fqXpnn84K4ZGSMAkwvO2wilf3jlqtc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=imuOKDpcqzupPyOXbItb/rGqa5z7zB7jT5ZB0cIqKqycyIFTHYUPnSWbt+2PS73aeNyhL5CFC+iTfKruMqmfeHt8/5Cj22H0RLAwEnGboFkyd1AdsXVW8IA++MVzz3agisfWcjtvh16ZSqMaCOxRq/N9Z1f7J3WU1Tpf0UO9+Ng= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=STZ9capF; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=8Pz7zK+U; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="STZ9capF"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="8Pz7zK+U" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285225; 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=/zOrW+LUkSiZr+TvOblyugUylHsj+wMZv3FMYyd9KnU=; b=STZ9capF54VzMUuFLF72oG+cJ4dB9zQ9ProQ1zbyZfGn52tBZ8CMK+G0kwYKZNXclTwvsL tG/fHJUz2wT8xXJUuHhEAJnBSO6wrCnOjYnU+8r88R3sTIWUZfZ06ZPq3/DUZi2VVTczEn HeWuS+vpdVDMAA8XaGg3QaV3T83e0Dkv4Yr/xcpXKQwGtX45vhnHDpTHOMQeFE0TWSdZqc F4wF3Uro/Ei/VJW6w96J/0bsDs6IcB75Jwyadhlq92GYE4I2vKcSVHOiLWeLFY9FVGVPBA 9mhtkoRnz1cEdt4O/j/QbZObObhkV8GK9eLhAV/tqVPS3g9UouMrbqvtEH4Yig== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285225; 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=/zOrW+LUkSiZr+TvOblyugUylHsj+wMZv3FMYyd9KnU=; b=8Pz7zK+Um3oHCIr62tLdX6zwRR9MuTmfUxG6SKxzEng2pZbV5LBvr2aBqyQJpZyIgvegHi VKMSzwQk5lJZsLAw== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko , Arnd Bergmann , Niklas Schnelle , Serge Semin Subject: [PATCH tty-next v5 3/6] serial: 8250: Use high-level writing function for FIFO Date: Tue, 7 Jan 2025 22:32:59 +0106 Message-Id: <20250107212702.169493-4-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently serial8250_console_fifo_write() directly writes into the UART_TX register rather than using the high-level function serial8250_console_putchar(). This is because serial8250_console_putchar() waits for the holding register to become empty, which would defeat the purpose of the FIFO code. Move the LSR_THRE waiting to a new function serial8250_console_wait_putchar() so that the FIFO code can use serial8250_console_putchar(). This will be particularly important for a follow-up commit, where output bytes are inspected to track newlines. This is only refactoring and has no functional change. Signed-off-by: John Ogness Reviewed-by: Andy Shevchenko Reviewed-by: Petr Mladek --- drivers/tty/serial/8250/8250_port.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index ca8f6f3855eb..15abd95fcf06 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3298,11 +3298,16 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); #ifdef CONFIG_SERIAL_8250_CONSOLE static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) +{ + serial_port_out(port, UART_TX, ch); +} + +static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch) { struct uart_8250_port *up = up_to_u8250p(port); wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out(port, UART_TX, ch); + serial8250_console_putchar(port, ch); } /* @@ -3352,6 +3357,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up, { const char *end = s + count; unsigned int fifosize = up->tx_loadsz; + struct uart_port *port = &up->port; unsigned int tx_count = 0; bool cr_sent = false; unsigned int i; @@ -3362,10 +3368,10 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up, for (i = 0; i < fifosize && s != end; ++i) { if (*s == '\n' && !cr_sent) { - serial_out(up, UART_TX, '\r'); + serial8250_console_putchar(port, '\r'); cr_sent = true; } else { - serial_out(up, UART_TX, *s++); + serial8250_console_putchar(port, *s++); cr_sent = false; } } @@ -3445,7 +3451,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (likely(use_fifo)) serial8250_console_fifo_write(up, s, count); else - uart_console_write(port, s, count, serial8250_console_putchar); + uart_console_write(port, s, count, serial8250_console_wait_putchar); /* * Finally, wait for transmitter to become empty From patchwork Tue Jan 7 21:27:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855906 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D60511F7574; Tue, 7 Jan 2025 21:27:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285230; cv=none; b=seeOjyWxvW1mXePxEd3xN/QDZMlrlMX/DE4WymQebb0LVMYbiSDr/gNN9EBE/dMkXOqFMu3PUbX0Elxesrhxn/jXCh6UgOAKQEaXLblg6aXegYPwJbJFgRBe9zTL+w7B8wUq/JLQAKg4xX3VjrP1FTXIkorngzCSXnnxDEoVjas= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285230; c=relaxed/simple; bh=xoEKJl7W1y0MwDU9yqj3w6HHZd25I6yetBuQMwqyHOw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pVWcsTn6lJ2na4VCiIe8hIk9PYnJb00AaW3rqsRKOM3LZSoCqq0HMqTP4dK4+elBuvAfvJ4EfLWn5zC04j8w2Z+hr1C+oNanIGyUr4G1d14BliD0XosAQBtgzxDLEZ4c8fr1xD6ycC7cq084jg+PodByNulSX6IXNMrhfFKyyu4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=afi5bwTI; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=6zm8OTot; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="afi5bwTI"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="6zm8OTot" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285225; 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=+C20CE/6jV0p4sUYOQkXzzELl/Lbh4IHLGETviL3Hbg=; b=afi5bwTI933XJ2JWDC8sQBjxiwmolsU8jhrE/Q4hXIeVdYPvsO5EtQkS84XXeKZPAxRvzK LX1XbwkGMGBCHupuQXlNqni3wMiQ37yIgc9bKFtOGNSvCozmUeyg6cjeJ5HSe9Tyv1KbXi SQOXTYskM6mPuD3RpzjUB5exKfar4tRj2aspufqEBNRMpnEOtULfXtAw91Z1HWF5AjGosn uLlGFoX5Lv2IgqaoLjNVrlNLjUR+YX4CDj703TBBzHcdbg+gqdf4F3lFzCsTk6jLrvGUrh E8pi8w7JRdT2kYEa3RyXaaBmhBnLUpy3/TTQYf1LagQg2FI9Q+zkCXuDhCelJw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285225; 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=+C20CE/6jV0p4sUYOQkXzzELl/Lbh4IHLGETviL3Hbg=; b=6zm8OTot0Vxq9xDFz1fpcViI67qsrgHkIuciMnAkk1o+gQ5SbM3eP8vVCwCyg7I/ykdTP4 M1a7AZ9TecTaMxCQ== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Fainelli , Ray Jui , Scott Branden , Broadcom internal kernel review list , Andy Shevchenko , Sunil V L , Arnd Bergmann , Stefan Wahren , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Kevin Hilman , Markus Schneider-Pargmann , Udit Kumar , Griffin Kroah-Hartman , Niklas Schnelle , Serge Semin , linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH tty-next v5 4/6] serial: 8250: Provide flag for IER toggling for RS485 Date: Tue, 7 Jan 2025 22:33:00 +0106 Message-Id: <20250107212702.169493-5-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 For RS485 mode, if SER_RS485_RX_DURING_TX is not available, the console ->write() callback needs to enable/disable Tx. It does this by calling the ->rs485_start_tx() and ->rs485_stop_tx() callbacks. However, some of these callbacks also disable/enable interrupts and makes power management calls. This causes 2 problems for console writing: 1. A console write can occur in contexts that are illegal for pm_runtime_*(). It is not even necessary for console writing to use pm_runtime_*() because a console already does this in serial8250_console_setup() and serial8250_console_exit(). 2. The console ->write() callback already handles disabling/enabling the interrupts by properly restoring the previous IER value. Add an argument @toggle_ier to the ->rs485_start_tx() and ->rs485_stop_tx() callbacks to specify if they may disable/enable receive interrupts while using pm_runtime_*(). Console writing will not allow the toggling. For all call sites other than console writing there is no functional change. Signed-off-by: John Ogness Reviewed-by: Petr Mladek --- drivers/tty/serial/8250/8250.h | 4 ++-- drivers/tty/serial/8250/8250_bcm2835aux.c | 4 ++-- drivers/tty/serial/8250/8250_omap.c | 2 +- drivers/tty/serial/8250/8250_port.c | 26 +++++++++++++---------- include/linux/serial_8250.h | 4 ++-- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index e5310c65cf52..11e05aa014e5 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -231,8 +231,8 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p); int serial8250_em485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485); -void serial8250_em485_start_tx(struct uart_8250_port *p); -void serial8250_em485_stop_tx(struct uart_8250_port *p); +void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier); +void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier); void serial8250_em485_destroy(struct uart_8250_port *p); extern struct serial_rs485 serial8250_em485_supported; diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index fdb53b54e99e..0609582a62f7 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -46,7 +46,7 @@ struct bcm2835aux_data { u32 cntl; }; -static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) +static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev); @@ -65,7 +65,7 @@ static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) serial8250_out_MCR(up, UART_MCR_RTS); } -static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up) +static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up, bool toggle_ier) { if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) serial8250_out_MCR(up, 0); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 42b4aa56b902..c2b75e3f106d 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -365,7 +365,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) if (up->port.rs485.flags & SER_RS485_ENABLED && up->port.rs485_config == serial8250_em485_config) - serial8250_em485_stop_tx(up); + serial8250_em485_stop_tx(up, true); } /* diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 15abd95fcf06..d7976a21cca9 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -578,7 +578,7 @@ static int serial8250_em485_init(struct uart_8250_port *p) deassert_rts: if (p->em485->tx_stopped) - p->rs485_stop_tx(p); + p->rs485_stop_tx(p, true); return 0; } @@ -1398,10 +1398,11 @@ static void serial8250_stop_rx(struct uart_port *port) /** * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback * @p: uart 8250 port + * @toggle_ier: true to allow enabling receive interrupts * * Generic callback usable by 8250 uart drivers to stop rs485 transmission. */ -void serial8250_em485_stop_tx(struct uart_8250_port *p) +void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier) { unsigned char mcr = serial8250_in_MCR(p); @@ -1422,8 +1423,10 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p) if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { serial8250_clear_and_reinit_fifos(p); - p->ier |= UART_IER_RLSI | UART_IER_RDI; - serial_port_out(&p->port, UART_IER, p->ier); + if (toggle_ier) { + p->ier |= UART_IER_RLSI | UART_IER_RDI; + serial_port_out(&p->port, UART_IER, p->ier); + } } } EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); @@ -1438,7 +1441,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) serial8250_rpm_get(p); uart_port_lock_irqsave(&p->port, &flags); if (em485->active_timer == &em485->stop_tx_timer) { - p->rs485_stop_tx(p); + p->rs485_stop_tx(p, true); em485->active_timer = NULL; em485->tx_stopped = true; } @@ -1470,7 +1473,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay) em485->active_timer = &em485->stop_tx_timer; hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL); } else { - p->rs485_stop_tx(p); + p->rs485_stop_tx(p, true); em485->active_timer = NULL; em485->tx_stopped = true; } @@ -1559,6 +1562,7 @@ static inline void __start_tx(struct uart_port *port) /** * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback * @up: uart 8250 port + * @toggle_ier: true to allow disabling receive interrupts * * Generic callback usable by 8250 uart drivers to start rs485 transmission. * Assumes that setting the RTS bit in the MCR register means RTS is high. @@ -1566,11 +1570,11 @@ static inline void __start_tx(struct uart_port *port) * stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the * UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.) */ -void serial8250_em485_start_tx(struct uart_8250_port *up) +void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier) { unsigned char mcr = serial8250_in_MCR(up); - if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier) serial8250_stop_rx(&up->port); if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) @@ -1604,7 +1608,7 @@ static bool start_tx_rs485(struct uart_port *port) if (em485->tx_stopped) { em485->tx_stopped = false; - up->rs485_start_tx(up); + up->rs485_start_tx(up, true); if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; @@ -3424,7 +3428,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (em485) { if (em485->tx_stopped) - up->rs485_start_tx(up); + up->rs485_start_tx(up, false); mdelay(port->rs485.delay_rts_before_send); } @@ -3462,7 +3466,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (em485) { mdelay(port->rs485.delay_rts_after_send); if (em485->tx_stopped) - up->rs485_stop_tx(up); + up->rs485_stop_tx(up, false); } serial_port_out(port, UART_IER, ier); diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index e0717c8393d7..144de7a7948d 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -161,8 +161,8 @@ struct uart_8250_port { void (*dl_write)(struct uart_8250_port *up, u32 value); struct uart_8250_em485 *em485; - void (*rs485_start_tx)(struct uart_8250_port *); - void (*rs485_stop_tx)(struct uart_8250_port *); + void (*rs485_start_tx)(struct uart_8250_port *up, bool toggle_ier); + void (*rs485_stop_tx)(struct uart_8250_port *up, bool toggle_ier); /* Serial port overrun backoff */ struct delayed_work overrun_backoff; From patchwork Tue Jan 7 21:27:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855905 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E9DAC1F76C4; Tue, 7 Jan 2025 21:27:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285231; cv=none; b=u2fquGTUkhPzLZ+b2Vr8BEP4NQswcASjYCkNMCc6axFmAG66Uqi0IpRiPVikBC9BQhy8Bg//UGtsVHJHtGjwdJjbPc+wQtV2kaMzvgXOeui6MfPvnY2S9ltIvP9f8MVF2+R6PgeeftHoSFEp8ymZWRwJjbJmJXWSHAKf+2A7pKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285231; c=relaxed/simple; bh=zWGShgMjg3bzxOVj+sxSWLyycy7WN0mLDd9lKPIdf1g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Un5WgQcU3u/3x+n+TD1g0+QPGyIyryG3zjr0Pi/KByh+itKn49wOdOi0LYD85zxcDQheJ0ZtTKcPq//sTlu1XwJGX2s1o2uLskJM2cY3PJqNuqPFRx/M9tO5dnv51EZi4sUkWGmFyPyPLndHbcbDJ7TU9TgjJ6pjvtqF1v+8Ifg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=cfkBwSlR; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=OGtGFx0R; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="cfkBwSlR"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="OGtGFx0R" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285226; 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=bNH0OgX5TNywdQ9m7FjwOAmcWOXxAahlrAKh1GjWcUo=; b=cfkBwSlRu0pW3bLqQWnBTz9U6J+9DyxUZxRFtGErUsZktmIJoTIKO4hocx6dNPUQfBaYY6 FbMF09449eHLn/8DoNhCHhz/65tNCv49NYefPXQxgC+QiN03FK9ai9WjddpRzS5UwZnfZq iqgkQzoUMXUgSEr4t8Zhn7ny7jtGUzPoRRCE6MLbOHlo9InpDVUpqxepFR+RIB7FVlFrHV niEKn7KpnW6hKBk0HACQgcJsMXpPxAUsq1nLEZF4AM0KdSU0fwbiVSWmsyRekHolcUegRU JlIwpQmnfhSlXIqc88+rjyfsKghYhMScZOCno1eEq991N28rP1JWgRANrPzFbg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285226; 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=bNH0OgX5TNywdQ9m7FjwOAmcWOXxAahlrAKh1GjWcUo=; b=OGtGFx0RQoo1QFsWgoRUG3c0Ga8AZysy7OxDZu0G6ISVz6rCMTVTFJAGGOgdZ9aaoyJEuf SQyKKKr/XxVTDIDQ== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko , Arnd Bergmann , Tony Lindgren , Niklas Schnelle , Serge Semin Subject: [PATCH tty-next v5 5/6] serial: 8250: Switch to nbcon console Date: Tue, 7 Jan 2025 22:33:01 +0106 Message-Id: <20250107212702.169493-6-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Implement the necessary callbacks to switch the 8250 console driver to perform as an nbcon console. Add implementations for the nbcon console callbacks: ->write_atomic() ->write_thread() ->device_lock() ->device_unlock() and add CON_NBCON to the initial @flags. All register access in the callbacks are within unsafe sections. The ->write_atomic() and ->write_thread() callbacks allow safe handover/takeover per byte and add a preceding newline if they take over from another context mid-line. For the ->write_atomic() callback, a new irq_work is used to defer modem control since it may be called from a context that does not allow waking up tasks. Note: A new __serial8250_clear_IER() is introduced for direct clearing of UART_IER. This will allow to restore the lockdep check to serial8250_clear_IER() in a follow-up commit. Signed-off-by: John Ogness --- drivers/tty/serial/8250/8250_core.c | 35 +++++- drivers/tty/serial/8250/8250_port.c | 180 ++++++++++++++++++++++------ include/linux/serial_8250.h | 13 +- 3 files changed, 187 insertions(+), 41 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 2b70e82dffeb..3d5a2183ff13 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -388,12 +388,34 @@ void __init serial8250_register_ports(struct uart_driver *drv, struct device *de #ifdef CONFIG_SERIAL_8250_CONSOLE -static void univ8250_console_write(struct console *co, const char *s, - unsigned int count) +static void univ8250_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct uart_8250_port *up = &serial8250_ports[co->index]; - serial8250_console_write(up, s, count); + serial8250_console_write(up, wctxt, true); +} + +static void univ8250_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + + serial8250_console_write(up, wctxt, false); +} + +static void univ8250_console_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &serial8250_ports[co->index].port; + + __uart_port_lock_irqsave(up, flags); +} + +static void univ8250_console_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &serial8250_ports[co->index].port; + + __uart_port_unlock_irqrestore(up, flags); } static int univ8250_console_setup(struct console *co, char *options) @@ -494,12 +516,15 @@ static int univ8250_console_match(struct console *co, char *name, int idx, static struct console univ8250_console = { .name = "ttyS", - .write = univ8250_console_write, + .write_atomic = univ8250_console_write_atomic, + .write_thread = univ8250_console_write_thread, + .device_lock = univ8250_console_device_lock, + .device_unlock = univ8250_console_device_unlock, .device = uart_console_device, .setup = univ8250_console_setup, .exit = univ8250_console_exit, .match = univ8250_console_match, - .flags = CON_PRINTBUFFER | CON_ANYTIME, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON, .index = -1, .data = &serial8250_reg, }; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d7976a21cca9..08466cf10d73 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -711,7 +711,12 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial8250_rpm_put(p); } -static void serial8250_clear_IER(struct uart_8250_port *up) +/* + * Only to be used directly by the callback helper serial8250_console_write(), + * which may not require the port lock. Use serial8250_clear_IER() instead for + * all other cases. + */ +static void __serial8250_clear_IER(struct uart_8250_port *up) { if (up->capabilities & UART_CAP_UUE) serial_out(up, UART_IER, UART_IER_UUE); @@ -719,6 +724,11 @@ static void serial8250_clear_IER(struct uart_8250_port *up) serial_out(up, UART_IER, 0); } +static inline void serial8250_clear_IER(struct uart_8250_port *up) +{ + __serial8250_clear_IER(up); +} + #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. @@ -1406,9 +1416,6 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier) { 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 @@ -1424,6 +1431,16 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier) serial8250_clear_and_reinit_fifos(p); if (toggle_ier) { + /* + * Port locked to synchronize UART_IER access against + * the console. The lockdep_assert must be restricted + * to this condition because only here is it + * guaranteed that the port lock is held. The other + * hardware access in this function is synchronized + * by console ownership. + */ + lockdep_assert_held_once(&p->port.lock); + p->ier |= UART_IER_RLSI | UART_IER_RDI; serial_port_out(&p->port, UART_IER, p->ier); } @@ -3303,7 +3320,11 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults); static void serial8250_console_putchar(struct uart_port *port, unsigned char ch) { + struct uart_8250_port *up = up_to_u8250p(port); + serial_port_out(port, UART_TX, ch); + + up->console_line_ended = (ch == '\n'); } static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch) @@ -3340,11 +3361,22 @@ static void serial8250_console_restore(struct uart_8250_port *up) serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); } -static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count) +static void fifo_wait_for_lsr(struct uart_8250_port *up, + struct nbcon_write_context *wctxt, + unsigned int count) { unsigned int i; for (i = 0; i < count; i++) { + /* + * Pass the ownership as quickly as possible to a higher + * priority context. Otherwise, its attempt to take over + * the ownership might timeout. The new owner will wait + * for UART_LSR_THRE before reusing the fifo. + */ + if (!nbcon_can_proceed(wctxt)) + return; + if (wait_for_lsr(up, UART_LSR_THRE)) return; } @@ -3357,20 +3389,29 @@ static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count) * to get empty. */ static void serial8250_console_fifo_write(struct uart_8250_port *up, - const char *s, unsigned int count) + struct nbcon_write_context *wctxt) { - const char *end = s + count; unsigned int fifosize = up->tx_loadsz; struct uart_port *port = &up->port; + const char *s = wctxt->outbuf; + const char *end = s + wctxt->len; unsigned int tx_count = 0; bool cr_sent = false; unsigned int i; while (s != end) { /* Allow timeout for each byte of a possibly full FIFO */ - fifo_wait_for_lsr(up, fifosize); + fifo_wait_for_lsr(up, wctxt, fifosize); + /* + * Fill the FIFO. If a handover or takeover occurs, writing + * must be aborted since wctxt->outbuf and wctxt->len are no + * longer valid. + */ for (i = 0; i < fifosize && s != end; ++i) { + if (!nbcon_enter_unsafe(wctxt)) + return; + if (*s == '\n' && !cr_sent) { serial8250_console_putchar(port, '\r'); cr_sent = true; @@ -3378,6 +3419,8 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up, serial8250_console_putchar(port, *s++); cr_sent = false; } + + nbcon_exit_unsafe(wctxt); } tx_count = i; } @@ -3386,39 +3429,57 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up, * Allow timeout for each byte written since the caller will only wait * for UART_LSR_BOTH_EMPTY using the timeout of a single character */ - fifo_wait_for_lsr(up, tx_count); + fifo_wait_for_lsr(up, wctxt, tx_count); +} + +static void serial8250_console_byte_write(struct uart_8250_port *up, + struct nbcon_write_context *wctxt) +{ + struct uart_port *port = &up->port; + const char *s = wctxt->outbuf; + const char *end = s + wctxt->len; + + /* + * Write out the message. If a handover or takeover occurs, writing + * must be aborted since wctxt->outbuf and wctxt->len are no longer + * valid. + */ + while (s != end) { + if (!nbcon_enter_unsafe(wctxt)) + return; + + uart_console_write(port, s++, 1, serial8250_console_wait_putchar); + + nbcon_exit_unsafe(wctxt); + } } /* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. + * Print a string to the serial port trying not to disturb + * any possible real use of the port... * - * Doing runtime PM is really a bad idea for the kernel console. - * Thus, we assume the function is called when device is powered up. + * Doing runtime PM is really a bad idea for the kernel console. + * Thus, assume it is called when device is powered up. */ -void serial8250_console_write(struct uart_8250_port *up, const char *s, - unsigned int count) +void serial8250_console_write(struct uart_8250_port *up, + struct nbcon_write_context *wctxt, + bool is_atomic) { struct uart_8250_em485 *em485 = up->em485; struct uart_port *port = &up->port; - unsigned long flags; - unsigned int ier, use_fifo; - int locked = 1; - - touch_nmi_watchdog(); + unsigned int ier; + bool use_fifo; - if (oops_in_progress) - locked = uart_port_trylock_irqsave(port, &flags); - else - uart_port_lock_irqsave(port, &flags); + if (!nbcon_enter_unsafe(wctxt)) + return; /* - * First save the IER then disable the interrupts + * First, save the IER, then disable the interrupts. The special + * variant to clear the IER is used because console printing may + * occur without holding the port lock. */ ier = serial_port_in(port, UART_IER); - serial8250_clear_IER(up); + __serial8250_clear_IER(up); /* check scratch reg to see if port powered off during system sleep */ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { @@ -3432,6 +3493,18 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, mdelay(port->rs485.delay_rts_before_send); } + /* If ownership was lost, no writing is allowed */ + if (!nbcon_can_proceed(wctxt)) + goto skip_write; + + /* + * If console printer did not fully output the previous line, it must + * have been handed or taken over. Insert a newline in order to + * maintain clean output. + */ + if (!up->console_line_ended) + uart_console_write(port, "\n", 1, serial8250_console_wait_putchar); + use_fifo = (up->capabilities & UART_CAP_FIFO) && /* * BCM283x requires to check the fifo @@ -3452,10 +3525,23 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, */ !(up->port.flags & UPF_CONS_FLOW); + nbcon_exit_unsafe(wctxt); + if (likely(use_fifo)) - serial8250_console_fifo_write(up, s, count); + serial8250_console_fifo_write(up, wctxt); else - uart_console_write(port, s, count, serial8250_console_wait_putchar); + serial8250_console_byte_write(up, wctxt); +skip_write: + /* + * If ownership was lost, this context must reacquire ownership and + * re-enter the unsafe section in order to perform final actions + * (such as re-enabling interrupts). + */ + if (!nbcon_can_proceed(wctxt)) { + do { + nbcon_reacquire_nobuf(wctxt); + } while (!nbcon_enter_unsafe(wctxt)); + } /* * Finally, wait for transmitter to become empty @@ -3478,11 +3564,18 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * call it if we have saved something in the saved flags * while processing with interrupts off. */ - if (up->msr_saved_flags) - serial8250_modem_status(up); + if (up->msr_saved_flags) { + /* + * For atomic, it must be deferred to irq_work because this + * may be a context that does not permit waking up tasks. + */ + if (is_atomic) + irq_work_queue(&up->modem_status_work); + else + serial8250_modem_status(up); + } - if (locked) - uart_port_unlock_irqrestore(port, flags); + nbcon_exit_unsafe(wctxt); } static unsigned int probe_baud(struct uart_port *port) @@ -3500,8 +3593,24 @@ static unsigned int probe_baud(struct uart_port *port) return (port->uartclk / 16) / quot; } +/* + * irq_work handler to perform modem control. Only triggered via + * ->write_atomic() callback because it may be in a scheduler or + * NMI context, unable to wake tasks. + */ +static void modem_status_handler(struct irq_work *iwp) +{ + struct uart_8250_port *up = container_of(iwp, struct uart_8250_port, modem_status_work); + struct uart_port *port = &up->port; + + uart_port_lock(port); + serial8250_modem_status(up); + uart_port_unlock(port); +} + int serial8250_console_setup(struct uart_port *port, char *options, bool probe) { + struct uart_8250_port *up = up_to_u8250p(port); int baud = 9600; int bits = 8; int parity = 'n'; @@ -3511,6 +3620,9 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) if (!port->iobase && !port->membase) return -ENODEV; + up->console_line_ended = true; + init_irq_work(&up->modem_status_work, modem_status_handler); + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else if (probe) diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 144de7a7948d..57875c37023a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -150,8 +150,17 @@ struct uart_8250_port { #define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS u16 lsr_saved_flags; u16 lsr_save_mask; + + /* + * Track when a console line has been fully written to the + * hardware, i.e. true when the most recent byte written to + * UART_TX by the console was '\n'. + */ + bool console_line_ended; + #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; + struct irq_work modem_status_work; struct uart_8250_dma *dma; const struct uart_8250_ops *ops; @@ -202,8 +211,8 @@ void serial8250_tx_chars(struct uart_8250_port *up); unsigned int serial8250_modem_status(struct uart_8250_port *up); void serial8250_init_port(struct uart_8250_port *up); void serial8250_set_defaults(struct uart_8250_port *up); -void serial8250_console_write(struct uart_8250_port *up, const char *s, - unsigned int count); +void serial8250_console_write(struct uart_8250_port *up, + struct nbcon_write_context *wctxt, bool in_atomic); int serial8250_console_setup(struct uart_port *port, char *options, bool probe); int serial8250_console_exit(struct uart_port *port); From patchwork Tue Jan 7 21:27:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 855642 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EB7051F76C5; Tue, 7 Jan 2025 21:27:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285230; cv=none; b=OoSoD5drtG+o1YzMlHcia5UZKa2RejWwqxwUh3424jqFNFs48FbVUhpJHTldyttJ8QM1Z6+jTEcw70bLYBX9ke2FFaqHI2YBHbFVaPhqtVFNIE3QycEQzWrMiwpgl69FtKZ1W5/9E6kdYJK91xQmVRvhuKRdOzCEkNaeVx2Sluo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736285230; c=relaxed/simple; bh=OgQFgFI8mqle482HvlsTcIXoK8iw7KjJLocnV26f9e0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=n0KqlpVSTNHSlGjYNx/wxh2fCcM+AVLHygqxqiiRS1B2i5jYE1wHSYQmu3W8J/SuhCuugysy7mzoWqMWrKJc5++GDAs+P8t4VtrtZL4Re/vqLkp9wrk0Ojk1WyY5R6ScVUxBnS7Pfkl4MOg6ofvdEDuxt/bLvu6gQNQTCPgpyhw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=eXsgkppJ; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=NS9Uh985; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="eXsgkppJ"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="NS9Uh985" From: John Ogness DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1736285227; 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=ei4zvvvTXWkQeATDXNtrrdLz3tj4qXsyOa/UJODf288=; b=eXsgkppJp2LcAij0VSNgD6ghZjadUtNGBbRq6BQnNhNhsNTjhTKIFEN6t28gQMFWvM8YxE LYs2gv9uxiJTQWw014JTnD9pr+wjr3z1R9mopXqZrmkDHeqXpl/noL9xdT7RLtzxQqvjZY CCvwN4lKWFaOZgsIx8Ne5Chu6D0oQv/aYPTlTtlu+gjSSYOx+2rnxOsnRzl5n0eB/m7O0j COdmF0fXeLbaLEo2/2jpWLoISA208E8XtQfOYVqm/FLPMO+WRoScL+JwBNj25TBg50aNFc PqHb/Q7jmkxhaQx4mnmPLbNla0Zb0zLmPD4SSae6tAjfi1o1p+IAbrGIixapdw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1736285227; 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=ei4zvvvTXWkQeATDXNtrrdLz3tj4qXsyOa/UJODf288=; b=NS9Uh985Qv0KMqAObhGkeakKJVbSlcBnMKGGX4JNffnwX+ez9AosHeVPocIEdRKhgKO/sA jWqqegem7/Oj5VCw== To: Greg Kroah-Hartman Cc: Jiri Slaby , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Thomas Gleixner , Esben Haabendal , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Shevchenko , Arnd Bergmann , Niklas Schnelle , Serge Semin Subject: [PATCH tty-next v5 6/6] serial: 8250: Revert "drop lockdep annotation from serial8250_clear_IER()" Date: Tue, 7 Jan 2025 22:33:02 +0106 Message-Id: <20250107212702.169493-7-john.ogness@linutronix.de> In-Reply-To: <20250107212702.169493-1-john.ogness@linutronix.de> References: <20250107212702.169493-1-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The 8250 driver no longer depends on @oops_in_progress and will no longer violate the port->lock locking constraints. This reverts commit 3d9e6f556e235ddcdc9f73600fdd46fe1736b090. Signed-off-by: John Ogness --- drivers/tty/serial/8250/8250_port.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 08466cf10d73..76a8d74f16e8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -726,6 +726,9 @@ static void __serial8250_clear_IER(struct uart_8250_port *up) static inline 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); + __serial8250_clear_IER(up); }