From patchwork Tue Sep 6 10:48:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Slaby X-Patchwork-Id: 603312 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 7E47FECAAD5 for ; Tue, 6 Sep 2022 10:50:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239450AbiIFKuO (ORCPT ); Tue, 6 Sep 2022 06:50:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239901AbiIFKtf (ORCPT ); Tue, 6 Sep 2022 06:49:35 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E23264CC; Tue, 6 Sep 2022 03:48:13 -0700 (PDT) Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id D8C1333D51; Tue, 6 Sep 2022 10:48:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1662461291; h=from:from:reply-to: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=wXg40FtDTQekKCv07crrElZ3bycY17ctga5/37ZAiuE=; b=zsJoTTROoMn7ToJb08w/FhmULyJS6lXrjQ2hePviemxvzXYrjnhRpd8517I+WWSIXYE85C JXVUMZbKmt0AbgguQ9DkpfqUxAThn2AuR285rz2DJkoxCZCH/BBd98buMOQZxY+uEKoBUF a0c4lvrjPBT5R30q+fwiXLPTdNUMp4A= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1662461291; h=from:from:reply-to: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=wXg40FtDTQekKCv07crrElZ3bycY17ctga5/37ZAiuE=; b=/oMrtaxMJfXLXWF5nVTzTlHygLO2oVpeeG6F66smS4A1HlLVqKRSHflMVmGKaQ170vMvrZ eC5hXbzNXvcs5qDg== Received: from localhost.localdomain (unknown [10.100.208.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id A11862C142; Tue, 6 Sep 2022 10:48:11 +0000 (UTC) From: Jiri Slaby To: gregkh@linuxfoundation.org Cc: =?utf-8?q?Ilpo_J=C3=A4rvinen?= , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Jiri Slaby , linux-arm-kernel@lists.infradead.org Subject: [PATCH v3 1/4] tty: serial: move and cleanup vt8500_tx_empty() Date: Tue, 6 Sep 2022 12:48:02 +0200 Message-Id: <20220906104805.23211-2-jslaby@suse.cz> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220906104805.23211-1-jslaby@suse.cz> References: <20220906104805.23211-1-jslaby@suse.cz> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org Make vt8500_tx_empty() more readable by introducing a new local variable and move the function before handle_tx(). That way we can reuse it in there too. Cc: Signed-off-by: Jiri Slaby --- Notes: [v3] this is new in v3 -- extracted as a separate change from later patches drivers/tty/serial/vt8500_serial.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 6f08136ce78a..9e2c745b4535 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -187,6 +187,13 @@ static void handle_rx(struct uart_port *port) tty_flip_buffer_push(tport); } +static unsigned int vt8500_tx_empty(struct uart_port *port) +{ + unsigned int idx = vt8500_read(port, VT8500_URFIDX) & 0x1f; + + return idx < 16 ? TIOCSER_TEMT : 0; +} + static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; @@ -201,7 +208,7 @@ static void handle_tx(struct uart_port *port) return; } - while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) { + while (vt8500_tx_empty(port)) { if (uart_circ_empty(xmit)) break; @@ -260,12 +267,6 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static unsigned int vt8500_tx_empty(struct uart_port *port) -{ - return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ? - TIOCSER_TEMT : 0; -} - static unsigned int vt8500_get_mctrl(struct uart_port *port) { unsigned int usr; From patchwork Tue Sep 6 10:48:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Slaby X-Patchwork-Id: 603311 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 A5E74C6FA83 for ; Tue, 6 Sep 2022 10:50:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239498AbiIFKuQ (ORCPT ); Tue, 6 Sep 2022 06:50:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42222 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239903AbiIFKtf (ORCPT ); Tue, 6 Sep 2022 06:49:35 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A691F7C33D; Tue, 6 Sep 2022 03:48:13 -0700 (PDT) Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 28FD11F9BF; Tue, 6 Sep 2022 10:48:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1662461292; h=from:from:reply-to: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=Jl/AwoQC7omJtY8qaihwuhwpfv9ehxsS4h2wzd8CKzc=; b=xkDX8Ij15AD2TDmoqGVD+4LRk+9V1ZIvQJ6jbhx0S+EQ8/pvprAlGTaRbniPvGL9igRtJe z3Id3zxFqq1yC4HgjA7j/cYrqmOEZEmfM/Cp/SMGonbD3pbPY0OL/tPCQZSG8U0SMl8SJA 3+Z6zUZ96unUGtL2fSfHvhX0yixsf5A= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1662461292; h=from:from:reply-to: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=Jl/AwoQC7omJtY8qaihwuhwpfv9ehxsS4h2wzd8CKzc=; b=6UnIPwdWXRWGvKl26dpxf6fBlwfo8DprLQufs9eGP6ScR50ibzZdnIZ0yXHrqwz5XPHa8/ EEJ7+/VsBH4ZORDg== Received: from localhost.localdomain (unknown [10.100.208.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id EBD7F2C143; Tue, 6 Sep 2022 10:48:11 +0000 (UTC) From: Jiri Slaby To: gregkh@linuxfoundation.org Cc: =?utf-8?q?Ilpo_J=C3=A4rvinen?= , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Jiri Slaby Subject: [PATCH v3 2/4] tty: serial: introduce transmit helper generators Date: Tue, 6 Sep 2022 12:48:03 +0200 Message-Id: <20220906104805.23211-3-jslaby@suse.cz> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220906104805.23211-1-jslaby@suse.cz> References: <20220906104805.23211-1-jslaby@suse.cz> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org Many serial drivers do the same thing: * send x_char if set * keep sending from the xmit circular buffer until either - the loop reaches the end of the xmit buffer - TX is stopped - HW fifo is full * check for pending characters and: - wake up tty writers to fill for more data into xmit buffer - stop TX if there is nothing in the xmit buffer The only differences are: * how to write the character to the HW fifo * the check of the end condition: - is the HW fifo full? - is limit of the written characters reached? So unify the above into two helper generators: * DEFINE_UART_PORT_TX_HELPER_LIMITED() -- it performs the above taking the written characters limit into account, and * DEFINE_UART_PORT_TX_HELPER() -- the same as above, except it only checks the HW readiness, not the characters limit. The HW specific operations (as stated as "differences" above) are passed as arguments to the macros. They are: * tx_ready -- returns true if HW can accept more data. * put_char -- write a character to the device. * tx_done -- when the write loop is done, perform arbitrary action before potential invocation of ops->stop_tx() happens. Note that the above macros are generators. This means the code is generated in place and the above 3 arguments are "inlined". I.e. no added penalty by generating call instructions for every single character. Nor any indirect calls. (As in previous versions of this patchset.) Signed-off-by: Jiri Slaby --- Notes: [v3] remove port + ch parameters of the macros (Greg) [v2] instead of a function (uart_port_tx_limit()) in serial_core, generate these in-place using macros. Thus eliminating "call" penalty. Documentation/driver-api/serial/driver.rst | 3 + include/linux/serial_core.h | 81 ++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Documentation/driver-api/serial/driver.rst b/Documentation/driver-api/serial/driver.rst index 23c6b956cd90..25775bf1fcc6 100644 --- a/Documentation/driver-api/serial/driver.rst +++ b/Documentation/driver-api/serial/driver.rst @@ -78,6 +78,9 @@ Other functions uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change uart_try_toggle_sysrq uart_get_console +.. kernel-doc:: include/linux/serial_core.h + :identifiers: DEFINE_UART_PORT_TX_HELPER_LIMITED DEFINE_UART_PORT_TX_HELPER + Other notes ----------- diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 6e4f4765d209..69abcc05fcfb 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -646,6 +646,87 @@ struct uart_driver { void uart_write_wakeup(struct uart_port *port); +#define __DEFINE_UART_PORT_TX_HELPER(name, tx_ready, put_char, tx_done, \ + for_test, for_post, ...) \ +unsigned int name(struct uart_port *port __VA_OPT__(,) __VA_ARGS__) \ +{ \ + struct circ_buf *xmit = &port->state->xmit; \ + unsigned int pending; \ + u8 ch; \ + \ + for (; (for_test) && (tx_ready); (for_post), port->icount.tx++) { \ + if (port->x_char) { \ + ch = port->x_char; \ + (put_char); \ + port->x_char = 0; \ + continue; \ + } \ + \ + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) \ + break; \ + \ + ch = xmit->buf[xmit->tail]; \ + (put_char); \ + xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; \ + } \ + \ + (tx_done); \ + \ + pending = uart_circ_chars_pending(xmit); \ + if (pending < WAKEUP_CHARS) { \ + uart_write_wakeup(port); \ + \ + if (pending == 0) \ + port->ops->stop_tx(port); \ + } \ + \ + return pending; \ +} + +/** + * DEFINE_UART_PORT_TX_HELPER_LIMITED -- generate transmit helper for uart_port + * with count limiting + * @name: name of the helper to generate + * @tx_ready: can HW accept more data function + * @put_char: function to write a character + * @tx_done: function to call after the loop is done + * + * This macro generates a function @name. The generated function is meant as a + * helper to transmit characters from the xmit buffer to the hardware using + * @put_char(). It does so until count (passed to @name) characters are sent + * and while @tx_ready evaluates to true. + * + * The generated function returns the number of characters in the xmit buffer + * when done. + * + * The expression in macro parameters are free to use @port (uart port) and @ch + * (character to send) variables and shall be designed as follows: + * * **tx_ready:** should evaluate to true if the HW can accept more data to + * be sent. This parameter can be %true, which means the HW is always ready. + * * **put_char:** shall write @ch to the device of @port. + * * **tx_done:** when the write loop is done, this can perform arbitrary + * action before potential invocation of ops->stop_tx() happens. If the + * driver does not need to do anything, use e.g. ({}). + * + * For all of them, @port->lock is held, interrupts are locally disabled and + * the expressions must not sleep. + */ +#define DEFINE_UART_PORT_TX_HELPER_LIMITED(name, tx_ready, put_char, tx_done) \ + __DEFINE_UART_PORT_TX_HELPER(name, tx_ready, put_char, tx_done, \ + count, count--, unsigned int count) + +/** + * DEFINE_UART_PORT_TX_HELPER -- generate transmit helper for uart_port + * @name: name of the helper to generate + * @tx_ready: can HW accept more data function + * @put_char: function to write a character + * + * See DEFINE_UART_PORT_TX_HELPER_LIMITED() for more details. + */ +#define DEFINE_UART_PORT_TX_HELPER(name, tx_ready, put_char) \ + __DEFINE_UART_PORT_TX_HELPER(name, tx_ready, put_char, ({}), \ + true, ({})) + /* * Baud rate helpers. */ From patchwork Tue Sep 6 10:48:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jiri Slaby X-Patchwork-Id: 603310 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 C7AF5C6FA8C for ; Tue, 6 Sep 2022 10:50:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239796AbiIFKuS (ORCPT ); Tue, 6 Sep 2022 06:50:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42800 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233684AbiIFKtl (ORCPT ); Tue, 6 Sep 2022 06:49:41 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 944336F263; Tue, 6 Sep 2022 03:48:15 -0700 (PDT) Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id 8535133D95; Tue, 6 Sep 2022 10:48:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1662461293; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0kAWodMmpnsf0bypfEI1H0YnomNVis6QDqasa5CcX1w=; b=I9Jvr0uzkyCVKyEXNllBvmFC5o9OVX3AFEXH0sYoPVzRi3b9ZtKRdg+Nw6RHt2gpdVDBbQ IelN2I8bZU1ZizdgPOV/1ueJdZUp0VhI7RQ2tnKhNuT2VS82pip6fx8fpjzuqDexaDR0ZA B9TtfD/iRt4L/enL3ct6ZNt6MJ7+xHw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1662461293; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0kAWodMmpnsf0bypfEI1H0YnomNVis6QDqasa5CcX1w=; b=tIziqNurfpCoDr5JEL/1sCQgNWnqoa1P0PLjBzdrcswOxVdomwRRdlbg5m2n06263Y3sT/ 828lzg0H5rPUNAAg== Received: from localhost.localdomain (unknown [10.100.208.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 091B62C141; Tue, 6 Sep 2022 10:48:13 +0000 (UTC) From: Jiri Slaby To: gregkh@linuxfoundation.org Cc: =?utf-8?q?Ilpo_J=C3=A4rvinen?= , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Jiri Slaby , Russell King , Florian Fainelli , bcm-kernel-feedback-list@broadcom.com, =?utf-8?q?Pali_Roh=C3=A1r?= , Kevin Cernekee , Palmer Dabbelt , Paul Walmsley , Orson Zhai , Baolin Wang , Chunyan Zhang , Patrice Chotard , linux-riscv@lists.infradead.org Subject: [PATCH v3 4/4] tty: serial: use DEFINE_UART_PORT_TX_HELPER_LIMITED() Date: Tue, 6 Sep 2022 12:48:05 +0200 Message-Id: <20220906104805.23211-5-jslaby@suse.cz> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220906104805.23211-1-jslaby@suse.cz> References: <20220906104805.23211-1-jslaby@suse.cz> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org DEFINE_UART_PORT_TX_HELPER_LIMITED() is a new helper to send characters to the device. Use it in these drivers. mux.c also needs to define tx_done(). But I'm not sure if the driver really wants to wait for all the characters to dismiss from the HW fifo at this code point. Hence I marked this as FIXME. Signed-off-by: Jiri Slaby Cc: Russell King Cc: Florian Fainelli Cc: bcm-kernel-feedback-list@broadcom.com Cc: "Pali Rohár" Cc: Kevin Cernekee Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Orson Zhai Cc: Baolin Wang Cc: Chunyan Zhang Cc: Patrice Chotard Cc: linux-riscv@lists.infradead.org --- drivers/tty/serial/21285.c | 33 ++++-------------- drivers/tty/serial/altera_jtaguart.c | 42 ++++++----------------- drivers/tty/serial/amba-pl010.c | 37 +++----------------- drivers/tty/serial/apbuart.c | 36 ++++---------------- drivers/tty/serial/bcm63xx_uart.c | 47 +++++--------------------- drivers/tty/serial/mux.c | 46 ++++++++----------------- drivers/tty/serial/mvebu-uart.c | 40 ++++------------------ drivers/tty/serial/omap-serial.c | 47 +++++++------------------- drivers/tty/serial/pxa.c | 39 +++++----------------- drivers/tty/serial/rp2.c | 36 ++++---------------- drivers/tty/serial/serial_txx9.c | 37 +++----------------- drivers/tty/serial/sifive.c | 45 +++---------------------- drivers/tty/serial/sprd_serial.c | 38 +++------------------ drivers/tty/serial/st-asc.c | 50 ++++------------------------ 14 files changed, 103 insertions(+), 470 deletions(-) diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 7520cc02fd4d..c057ae367b09 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -151,38 +151,17 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) return IRQ_HANDLED; } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(serial21285_do_tx_chars, + !(*CSR_UARTFLG & 0x20), + *CSR_UARTDR = ch, + ({})); + static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - int count = 256; - - if (port->x_char) { - *CSR_UARTDR = port->x_char; - port->icount.tx++; - port->x_char = 0; - goto out; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - serial21285_stop_tx(port); - goto out; - } - - do { - *CSR_UARTDR = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - serial21285_stop_tx(port); + serial21285_do_tx_chars(port, 256); - out: return IRQ_HANDLED; } diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index cb791c5149a3..a8b7a6f58100 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -134,42 +134,20 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) tty_flip_buffer_push(&port->state->port); } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(altera_jtaguart_do_tx_chars, + true, + writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG), + ({})); + static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) { struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned int pending, count; - - if (port->x_char) { - /* Send special char - probably flow control */ - writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG); - port->x_char = 0; - port->icount.tx++; - return; - } - - pending = uart_circ_chars_pending(xmit); - if (pending > 0) { - count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> - ALTERA_JTAGUART_CONTROL_WSPACE_OFF; - if (count > pending) - count = pending; - if (count > 0) { - pending -= count; - while (count--) { - writel(xmit->buf[xmit->tail], - port->membase + ALTERA_JTAGUART_DATA_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (pending < WAKEUP_CHARS) - uart_write_wakeup(port); - } - } + unsigned int space; - if (pending == 0) - altera_jtaguart_stop_tx(port); + space = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & + ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> + ALTERA_JTAGUART_CONTROL_WSPACE_OFF; + altera_jtaguart_do_tx_chars(port, space); } static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index fae0b581ff42..a7b558a3bc15 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -162,37 +162,10 @@ static void pl010_rx_chars(struct uart_port *port) tty_flip_buffer_push(&port->state->port); } -static void pl010_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - writel(port->x_char, port->membase + UART01x_DR); - port->icount.tx++; - port->x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - pl010_stop_tx(port); - return; - } - - count = port->fifosize >> 1; - do { - writel(xmit->buf[xmit->tail], port->membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - pl010_stop_tx(port); -} +static DEFINE_UART_PORT_TX_HELPER_LIMITED(pl010_tx_chars, + true, + writel(ch, port->membase + UART01x_DR), + ({})); static void pl010_modem_status(struct uart_amba_port *uap) { @@ -238,7 +211,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id) if (status & UART010_IIR_MIS) pl010_modem_status(uap); if (status & UART010_IIR_TIS) - pl010_tx_chars(port); + pl010_tx_chars(port, port->fifosize >> 1); if (pass_counter-- == 0) break; diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 9ef82d870ff2..e810b4a12d13 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -120,38 +120,14 @@ static void apbuart_rx_chars(struct uart_port *port) tty_flip_buffer_push(&port->state->port); } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(apbuart_do_tx_chars, + true, + UART_PUT_CHAR(port, ch), + ({})); + static void apbuart_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - apbuart_stop_tx(port); - return; - } - - /* amba: fill FIFO */ - count = port->fifosize >> 1; - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - apbuart_stop_tx(port); + apbuart_do_tx_chars(port, port->fifosize >> 1); } static irqreturn_t apbuart_int(int irq, void *dev_id) diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 53b43174aa40..e29b7290ab66 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -297,59 +297,30 @@ static void bcm_uart_do_rx(struct uart_port *port) tty_flip_buffer_push(tty_port); } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(bcm_uart_tx, + true, + bcm_uart_writel(port, ch, UART_FIFO_REG), + ({})); + /* * fill tx fifo with chars to send, stop when fifo is about to be full * or when all chars have been sent. */ static void bcm_uart_do_tx(struct uart_port *port) { - struct circ_buf *xmit; - unsigned int val, max_count; - - if (port->x_char) { - bcm_uart_writel(port, port->x_char, UART_FIFO_REG); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_tx_stopped(port)) { - bcm_uart_stop_tx(port); - return; - } - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit)) - goto txq_empty; + unsigned int val, pending; val = bcm_uart_readl(port, UART_MCTL_REG); val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; - max_count = port->fifosize - val; - - while (max_count--) { - unsigned int c; - c = xmit->buf[xmit->tail]; - bcm_uart_writel(port, c, UART_FIFO_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - goto txq_empty; - return; + pending = bcm_uart_tx(port, port->fifosize - val); + if (pending) + return; -txq_empty: /* nothing to send, disable transmit interrupt */ val = bcm_uart_readl(port, UART_IR_REG); val &= ~UART_TX_INT_MASK; bcm_uart_writel(port, val, UART_IR_REG); - return; } /* diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 0ba0f4d9459d..de928d5def77 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -171,6 +171,18 @@ static void mux_break_ctl(struct uart_port *port, int break_state) { } +static void mux_tx_done(struct uart_port *port) +{ + /* FIXME js: really needs to wait? */ + while (UART_GET_FIFO_CNT(port)) + udelay(1); +} + +static DEFINE_UART_PORT_TX_HELPER_LIMITED(mux_transmit, + true, + UART_PUT_CHAR(port, ch), + mux_tx_done(port)); + /** * mux_write - Write chars to the mux fifo. * @port: Ptr to the uart_port. @@ -180,39 +192,7 @@ static void mux_break_ctl(struct uart_port *port, int break_state) */ static void mux_write(struct uart_port *port) { - int count; - struct circ_buf *xmit = &port->state->xmit; - - if(port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mux_stop_tx(port); - return; - } - - count = (port->fifosize) - UART_GET_FIFO_CNT(port); - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if(uart_circ_empty(xmit)) - break; - - } while(--count > 0); - - while(UART_GET_FIFO_CNT(port)) - udelay(1); - - if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mux_stop_tx(port); + mux_transmit(port, port->fifosize - UART_GET_FIFO_CNT(port)); } /** diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 65eaecd10b7c..bc015b63a402 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -333,42 +333,14 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) tty_flip_buffer_push(tport); } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(mvebu_uart_do_tx_chars, + !(readl(port->membase + UART_STAT) & STAT_TX_FIFO_FUL), + writel(ch, port->membase + UART_TSH(port)), + ({})); + static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status) { - struct circ_buf *xmit = &port->state->xmit; - unsigned int count; - unsigned int st; - - if (port->x_char) { - writel(port->x_char, port->membase + UART_TSH(port)); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mvebu_uart_stop_tx(port); - return; - } - - for (count = 0; count < port->fifosize; count++) { - writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port)); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_empty(xmit)) - break; - - st = readl(port->membase + UART_STAT); - if (st & STAT_TX_FIFO_FUL) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mvebu_uart_stop_tx(port); + mvebu_uart_do_tx_chars(port, port->fifosize); } static irqreturn_t mvebu_uart_isr(int irq, void *dev_id) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0aa666e247d5..8c5202f88f45 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -337,45 +337,22 @@ static void serial_omap_stop_rx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) +static void serial_omap_put_char(struct uart_port *port, unsigned char ch) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - if ((up->port.rs485.flags & SER_RS485_ENABLED) && - !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) - up->rs485_tx_filter_count++; - - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_omap_stop_tx(&up->port); - return; - } - count = up->port.fifosize / 4; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if ((up->port.rs485.flags & SER_RS485_ENABLED) && - !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) - up->rs485_tx_filter_count++; - - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); + struct uart_omap_port *up = to_uart_omap_port(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + serial_out(up, UART_TX, ch); - if (uart_circ_empty(xmit)) - serial_omap_stop_tx(&up->port); + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + up->rs485_tx_filter_count++; } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(transmit_chars, + true, + serial_omap_put_char(port, ch), + ({})); + static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) { if (!(up->ier & UART_IER_THRI)) { @@ -573,7 +550,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) check_modem_status(up); break; case UART_IIR_THRI: - transmit_chars(up, lsr); + transmit_chars(&up->port, up->port.fifosize / 4); break; case UART_IIR_RX_TIMEOUT: case UART_IIR_RDI: diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 9309ffd87c8e..45778be46f3c 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -172,39 +172,18 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) serial_out(up, UART_IER, up->ier); } -static void transmit_chars(struct uart_pxa_port *up) +static void serial_pxa_put_char(struct uart_port *port, u8 ch) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_pxa_stop_tx(&up->port); - return; - } - - count = up->port.fifosize / 2; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - + struct uart_pxa_port *up = (struct uart_pxa_port *)port; - if (uart_circ_empty(xmit)) - serial_pxa_stop_tx(&up->port); + serial_out(up, UART_TX, ch); } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(transmit_chars, + true, + serial_pxa_put_char(port, ch), + ({})); + static void serial_pxa_start_tx(struct uart_port *port) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; @@ -254,7 +233,7 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) - transmit_chars(up); + transmit_chars(&up->port, up->port.fifosize / 2); spin_unlock(&up->port.lock); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 6689d8add8f7..4f59c883539a 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -426,35 +426,10 @@ static void rp2_rx_chars(struct rp2_uart_port *up) tty_flip_buffer_push(port); } -static void rp2_tx_chars(struct rp2_uart_port *up) -{ - u16 max_tx = FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT); - struct circ_buf *xmit = &up->port.state->xmit; - - if (uart_tx_stopped(&up->port)) { - rp2_uart_stop_tx(&up->port); - return; - } - - for (; max_tx != 0; max_tx--) { - if (up->port.x_char) { - writeb(up->port.x_char, up->base + RP2_DATA_BYTE); - up->port.x_char = 0; - up->port.icount.tx++; - continue; - } - if (uart_circ_empty(xmit)) { - rp2_uart_stop_tx(&up->port); - break; - } - writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); -} +static DEFINE_UART_PORT_TX_HELPER_LIMITED(rp2_tx_chars, + true, + writeb(ch, port_to_up(port)->base + RP2_DATA_BYTE), + ({})); static void rp2_ch_interrupt(struct rp2_uart_port *up) { @@ -472,7 +447,8 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up) if (status & RP2_CHAN_STAT_RXDATA_m) rp2_rx_chars(up); if (status & RP2_CHAN_STAT_TXEMPTY_m) - rp2_tx_chars(up); + rp2_tx_chars(&up->port, + FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT)); if (status & RP2_CHAN_STAT_MS_CHANGED_MASK) wake_up_interruptible(&up->port.state->port.delta_msr_wait); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 228e380db080..6e7a71e9a917 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -319,37 +319,10 @@ receive_chars(struct uart_port *up, unsigned int *status) *status = disr; } -static inline void transmit_chars(struct uart_port *up) -{ - struct circ_buf *xmit = &up->state->xmit; - int count; - - if (up->x_char) { - sio_out(up, TXX9_SITFIFO, up->x_char); - up->icount.tx++; - up->x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(up)) { - serial_txx9_stop_tx(up); - return; - } - - count = TXX9_SIO_TX_FIFO; - do { - sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(up); - - if (uart_circ_empty(xmit)) - serial_txx9_stop_tx(up); -} +static DEFINE_UART_PORT_TX_HELPER_LIMITED(transmit_chars, + true, + sio_out(port, TXX9_SITFIFO, ch), + ({})); static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) { @@ -371,7 +344,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) if (status & TXX9_SIDISR_RDIS) receive_chars(up, &status); if (status & TXX9_SIDISR_TDIS) - transmit_chars(up); + transmit_chars(up, TXX9_SIO_TX_FIFO); /* Clear TX/RX Int. Status */ sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 5c3a07546a58..1440f7d55fbd 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -277,45 +277,10 @@ static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch) __ssp_writel(ch, SIFIVE_SERIAL_TXDATA_OFFS, ssp); } -/** - * __ssp_transmit_chars() - enqueue multiple bytes onto the TX FIFO - * @ssp: pointer to a struct sifive_serial_port - * - * Transfer up to a TX FIFO size's worth of characters from the Linux serial - * transmit buffer to the SiFive UART TX FIFO. - * - * Context: Any context. Expects @ssp->port.lock to be held by caller. - */ -static void __ssp_transmit_chars(struct sifive_serial_port *ssp) -{ - struct circ_buf *xmit = &ssp->port.state->xmit; - int count; - - if (ssp->port.x_char) { - __ssp_transmit_char(ssp, ssp->port.x_char); - ssp->port.icount.tx++; - ssp->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&ssp->port)) { - sifive_serial_stop_tx(&ssp->port); - return; - } - count = SIFIVE_TX_FIFO_DEPTH; - do { - __ssp_transmit_char(ssp, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - ssp->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&ssp->port); - - if (uart_circ_empty(xmit)) - sifive_serial_stop_tx(&ssp->port); -} +static DEFINE_UART_PORT_TX_HELPER_LIMITED(__ssp_transmit_chars, + true, + __ssp_transmit_char(port_to_sifive_serial_port(port), ch), + ({})); /** * __ssp_enable_txwm() - enable transmit watermark interrupts @@ -553,7 +518,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id) if (ip & SIFIVE_SERIAL_IP_RXWM_MASK) __ssp_receive_chars(ssp); if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) - __ssp_transmit_chars(ssp); + __ssp_transmit_chars(&ssp->port, SIFIVE_TX_FIFO_DEPTH); spin_unlock(&ssp->port.lock); diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 4329b9c9cbf0..1616b63281bc 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -624,38 +624,10 @@ static inline void sprd_rx(struct uart_port *port) tty_flip_buffer_push(tty); } -static inline void sprd_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - serial_out(port, SPRD_TXD, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - sprd_stop_tx(port); - return; - } - - count = THLD_TX_EMPTY; - do { - serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - sprd_stop_tx(port); -} +static DEFINE_UART_PORT_TX_HELPER_LIMITED(sprd_tx, + true, + serial_out(port, SPRD_TXD, ch), + ({})); /* this handles the interrupt from one port */ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) @@ -683,7 +655,7 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) sprd_rx(port); if (ims & SPRD_IMSR_TX_FIFO_EMPTY) - sprd_tx(port); + sprd_tx(port, THLD_TX_EMPTY); spin_unlock(&port->lock); diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index cce42f4c9bc2..8157fb52ceeb 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -230,6 +230,11 @@ static inline unsigned asc_hw_txroom(struct uart_port *port) return 0; } +static DEFINE_UART_PORT_TX_HELPER_LIMITED(asc_do_transmit_chars, + true, + asc_out(port, ASC_TXBUF, ch), + ({})); + /* * Start transmitting chars. * This is called from both interrupt and task level. @@ -237,50 +242,7 @@ static inline unsigned asc_hw_txroom(struct uart_port *port) */ static void asc_transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - int txroom; - unsigned char c; - - txroom = asc_hw_txroom(port); - - if ((txroom != 0) && port->x_char) { - c = port->x_char; - port->x_char = 0; - asc_out(port, ASC_TXBUF, c); - port->icount.tx++; - txroom = asc_hw_txroom(port); - } - - if (uart_tx_stopped(port)) { - /* - * We should try and stop the hardware here, but I - * don't think the ASC has any way to do that. - */ - asc_disable_tx_interrupts(port); - return; - } - - if (uart_circ_empty(xmit)) { - asc_disable_tx_interrupts(port); - return; - } - - if (txroom == 0) - return; - - do { - c = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - asc_out(port, ASC_TXBUF, c); - port->icount.tx++; - txroom--; - } while ((txroom > 0) && (!uart_circ_empty(xmit))); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - asc_disable_tx_interrupts(port); + asc_do_transmit_chars(port, asc_hw_txroom(port)); } static void asc_receive_chars(struct uart_port *port)