summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 12:31:56 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 12:31:56 +0100
commitdd6f9b17cd7af68b6a5090deedf1f5e84f66f4e6 (patch)
treea03ca96cddd4520555981e51d8e6072f2d48c416 /drivers/tty/serial
parentMerge tag 'staging-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/... (diff)
parentserial: atmel: don't stop the transmitter when doing PIO (diff)
downloadlinux-dd6f9b17cd7af68b6a5090deedf1f5e84f66f4e6.tar.xz
linux-dd6f9b17cd7af68b6a5090deedf1f5e84f66f4e6.zip
Merge tag 'tty-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH: "Here is the "big" set of tty/serial driver changes for 6.2-rc1. As in previous kernel releases, nothing big here at all, just some small incremental serial/tty layer cleanups and some individual driver additions and fixes. Highlights are: - serial helper macros from Jiri Slaby to reduce the amount of duplicated code in serial drivers - api cleanups and consolidations from Ilpo Järvinen in lots of serial drivers - the usual set of n_gsm fixes from Daniel Starke as that code gets exercised more - TIOCSTI is finally able to be disabled if requested (security hardening feature from Kees Cook) - fsl_lpuart driver fixes and features added - other small serial driver additions and fixes All of these have been in linux-next for a while with no reported problems" * tag 'tty-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (97 commits) serial: atmel: don't stop the transmitter when doing PIO serial: atmel: cleanup atmel_start+stop_tx() tty: serial: fsl_lpuart: switch to new dmaengine_terminate_* API serial: sunsab: Fix error handling in sunsab_init() serial: altera_uart: fix locking in polling mode serial: pch: Fix PCI device refcount leak in pch_request_dma() tty: serial: fsl_lpuart: Use pm_ptr() to avoid need to make pm __maybe_unused tty: serial: fsl_lpuart: Add runtime pm support tty: serial: fsl_lpuart: enable wakeup source for lpuart serdev: Replace poll loop by readx_poll_timeout() macro tty: synclink_gt: unwind actions in error path of net device open serial: stm32: move dma_request_chan() before clk_prepare_enable() dt-bindings: serial: xlnx,opb-uartlite: Drop 'contains' from 'xlnx,use-parity' serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle. serial: amba-pl011: avoid SBSA UART accessing DMACR register tty: serial: altera_jtaguart: remove struct altera_jtaguart tty: serial: altera_jtaguart: use uart_port::read_status_mask tty: serial: altera_jtaguart: remove unused altera_jtaguart::sigs tty: serial: altera_jtaguart: remove flag from altera_jtaguart_rx_chars() n_tty: Rename tail to old_tail in n_tty_read() ...
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/21285.c32
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c14
-rw-r--r--drivers/tty/serial/8250/8250_core.c5
-rw-r--r--drivers/tty/serial/8250/8250_dma.c19
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c32
-rw-r--r--drivers/tty/serial/8250/8250_omap.c85
-rw-r--r--drivers/tty/serial/8250/8250_port.c3
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/altera_jtaguart.c112
-rw-r--r--drivers/tty/serial/altera_uart.c34
-rw-r--r--drivers/tty/serial/amba-pl010.c32
-rw-r--r--drivers/tty/serial/amba-pl011.c17
-rw-r--r--drivers/tty/serial/apbuart.c34
-rw-r--r--drivers/tty/serial/ar933x_uart.c3
-rw-r--r--drivers/tty/serial/arc_uart.c3
-rw-r--r--drivers/tty/serial/atmel_serial.c80
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c47
-rw-r--r--drivers/tty/serial/clps711x.c3
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c3
-rw-r--r--drivers/tty/serial/digicolor-usart.c3
-rw-r--r--drivers/tty/serial/dz.c3
-rw-r--r--drivers/tty/serial/fsl_linflexuart.c3
-rw-r--r--drivers/tty/serial/fsl_lpuart.c386
-rw-r--r--drivers/tty/serial/imx.c71
-rw-r--r--drivers/tty/serial/ip22zilog.c6
-rw-r--r--drivers/tty/serial/lantiq.c36
-rw-r--r--drivers/tty/serial/liteuart.c3
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c33
-rw-r--r--drivers/tty/serial/max3100.c4
-rw-r--r--drivers/tty/serial/max310x.c5
-rw-r--r--drivers/tty/serial/mcf.c34
-rw-r--r--drivers/tty/serial/men_z135_uart.c5
-rw-r--r--drivers/tty/serial/meson_uart.c3
-rw-r--r--drivers/tty/serial/milbeaut_usio.c3
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c39
-rw-r--r--drivers/tty/serial/mps2-uart.c26
-rw-r--r--drivers/tty/serial/msm_serial.c13
-rw-r--r--drivers/tty/serial/mux.c45
-rw-r--r--drivers/tty/serial/mvebu-uart.c41
-rw-r--r--drivers/tty/serial/mxs-auart.c32
-rw-r--r--drivers/tty/serial/omap-serial.c32
-rw-r--r--drivers/tty/serial/owl-uart.c32
-rw-r--r--drivers/tty/serial/pch_uart.c16
-rw-r--r--drivers/tty/serial/pic32_uart.c3
-rw-r--r--drivers/tty/serial/pmac_zilog.c6
-rw-r--r--drivers/tty/serial/pxa.c33
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c35
-rw-r--r--drivers/tty/serial/rda-uart.c3
-rw-r--r--drivers/tty/serial/rp2.c31
-rw-r--r--drivers/tty/serial/sa1100.c34
-rw-r--r--drivers/tty/serial/samsung_tty.c10
-rw-r--r--drivers/tty/serial/sb1250-duart.c3
-rw-r--r--drivers/tty/serial/sc16is7xx.c5
-rw-r--r--drivers/tty/serial/sccnxp.c3
-rw-r--r--drivers/tty/serial/serial-tegra.c9
-rw-r--r--drivers/tty/serial/serial_txx9.c32
-rw-r--r--drivers/tty/serial/sh-sci.c5
-rw-r--r--drivers/tty/serial/sifive.c31
-rw-r--r--drivers/tty/serial/sprd_serial.c40
-rw-r--r--drivers/tty/serial/st-asc.c48
-rw-r--r--drivers/tty/serial/stm32-usart.c54
-rw-r--r--drivers/tty/serial/sunhv.c6
-rw-r--r--drivers/tty/serial/sunplus-uart.c4
-rw-r--r--drivers/tty/serial/sunsab.c14
-rw-r--r--drivers/tty/serial/sunsu.c3
-rw-r--r--drivers/tty/serial/sunzilog.c6
-rw-r--r--drivers/tty/serial/timbuart.c3
-rw-r--r--drivers/tty/serial/uartlite.c3
-rw-r--r--drivers/tty/serial/ucc_uart.c3
-rw-r--r--drivers/tty/serial/vt8500_serial.c32
-rw-r--r--drivers/tty/serial/xilinx_uartps.c4
-rw-r--r--drivers/tty/serial/zs.c3
72 files changed, 812 insertions, 1088 deletions
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
index c7d34823f715..185462fd959c 100644
--- a/drivers/tty/serial/21285.c
+++ b/drivers/tty/serial/21285.c
@@ -154,35 +154,13 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- serial21285_stop_tx(port);
+ uart_port_tx_limited(port, ch, 256,
+ !(*CSR_UARTFLG & 0x20),
+ *CSR_UARTDR = ch,
+ ({}));
- out:
return IRQ_HANDLED;
}
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index fa8ccf204d86..ed5a94747692 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -425,9 +425,7 @@ static int brcmuart_tx_dma(struct uart_8250_port *p)
priv->dma.tx_err = 0;
memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size);
- xmit->tail += tx_size;
- xmit->tail &= UART_XMIT_SIZE - 1;
- p->port.icount.tx += tx_size;
+ uart_xmit_advance(&p->port, tx_size);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
@@ -1212,9 +1210,17 @@ static struct platform_driver brcmuart_platform_driver = {
static int __init brcmuart_init(void)
{
+ int ret;
+
brcmuart_debugfs_root = debugfs_create_dir(
brcmuart_platform_driver.driver.name, NULL);
- return platform_driver_register(&brcmuart_platform_driver);
+ ret = platform_driver_register(&brcmuart_platform_driver);
+ if (ret) {
+ debugfs_remove_recursive(brcmuart_debugfs_root);
+ return ret;
+ }
+
+ return 0;
}
module_init(brcmuart_init);
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 74568292186f..ab63c308be0a 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -32,6 +32,7 @@
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#ifdef CONFIG_SPARC
@@ -1175,8 +1176,8 @@ static int __init serial8250_init(void)
serial8250_isa_init_ports();
- pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
- nr_uarts, share_irqs ? "en" : "dis");
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
+ nr_uarts, str_enabled_disabled(share_irqs));
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index b85c82616e8c..37d6af2ec427 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -38,9 +38,8 @@ static void __dma_tx_complete(void *param)
spin_unlock_irqrestore(&p->port.lock, flags);
}
-static void __dma_rx_complete(void *param)
+static void __dma_rx_complete(struct uart_8250_port *p)
{
- struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
struct tty_port *tty_port = &p->port.state->port;
struct dma_tx_state state;
@@ -57,6 +56,20 @@ static void __dma_rx_complete(void *param)
tty_flip_buffer_push(tty_port);
}
+static void dma_rx_complete(void *param)
+{
+ struct uart_8250_port *p = param;
+ struct uart_8250_dma *dma = p->dma;
+ unsigned long flags;
+
+ __dma_rx_complete(p);
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
+ p->dma->rx_dma(p);
+ spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
int serial8250_tx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
@@ -130,7 +143,7 @@ int serial8250_rx_dma(struct uart_8250_port *p)
return -EBUSY;
dma->rx_running = 1;
- desc->callback = __dma_rx_complete;
+ desc->callback = dma_rx_complete;
desc->callback_param = p;
dma->rx_cookie = dmaengine_submit(desc);
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 2b2f5d8d24b9..617b8ce60d6b 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -87,7 +87,7 @@ static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev
dev->port.uartclk = be32_to_cpup(prop);
}
-static int __init ingenic_early_console_setup(struct earlycon_device *dev,
+static int __init ingenic_earlycon_setup_tail(struct earlycon_device *dev,
const char *opt)
{
struct uart_port *port = &dev->port;
@@ -103,8 +103,6 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
uart_parse_options(opt, &baud, &parity, &bits, &flow);
}
- ingenic_early_console_setup_clock(dev);
-
if (dev->baud)
baud = dev->baud;
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
@@ -129,9 +127,36 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
return 0;
}
+static int __init ingenic_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ ingenic_early_console_setup_clock(dev);
+
+ return ingenic_earlycon_setup_tail(dev, opt);
+}
+
+static int __init jz4750_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ /*
+ * JZ4750/55/60 have an optional /2 divider between the EXT
+ * oscillator and some peripherals including UART, which will
+ * be enabled if using a 24 MHz oscillator, and disabled when
+ * using a 12 MHz oscillator.
+ */
+ ingenic_early_console_setup_clock(dev);
+ if (dev->port.uartclk >= 16000000)
+ dev->port.uartclk /= 2;
+
+ return ingenic_earlycon_setup_tail(dev, opt);
+}
+
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4750_uart, "ingenic,jz4750-uart",
+ jz4750_early_console_setup);
+
OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
ingenic_early_console_setup);
@@ -328,6 +353,7 @@ static const struct ingenic_uart_config x1000_uart_config = {
static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
+ { .compatible = "ingenic,jz4750-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 3f33014022f0..734f092ef839 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -44,6 +44,7 @@
#define UART_HAS_EFR2 BIT(4)
#define UART_HAS_RHR_IT_DIS BIT(5)
#define UART_RX_TIMEOUT_QUIRK BIT(6)
+#define UART_HAS_NATIVE_RS485 BIT(7)
#define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4
@@ -101,6 +102,11 @@
#define UART_OMAP_IER2 0x1B
#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
+/* Mode Definition Register 3 */
+#define UART_OMAP_MDR3 0x20
+#define UART_OMAP_MDR3_DIR_POL BIT(3)
+#define UART_OMAP_MDR3_DIR_EN BIT(4)
+
/* Enhanced features register 2 */
#define UART_OMAP_EFR2 0x23
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
@@ -112,6 +118,7 @@ struct omap8250_priv {
int line;
u8 habit;
u8 mdr1;
+ u8 mdr3;
u8 efr;
u8 scr;
u8 wer;
@@ -346,7 +353,10 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
__omap8250_set_mctrl(&up->port, up->port.mctrl);
- if (up->port.rs485.flags & SER_RS485_ENABLED)
+ serial_out(up, UART_OMAP_MDR3, priv->mdr3);
+
+ if (up->port.rs485.flags & SER_RS485_ENABLED &&
+ up->port.rs485_config == serial8250_em485_config)
serial8250_em485_stop_tx(up);
}
@@ -794,6 +804,74 @@ static void omap_8250_unthrottle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
+static int omap8250_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct omap8250_priv *priv = port->private_data;
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u32 fixed_delay_rts_before_send = 0;
+ u32 fixed_delay_rts_after_send = 0;
+ unsigned int baud;
+
+ /*
+ * There is a fixed delay of 3 bit clock cycles after the TX shift
+ * register is going empty to allow time for the stop bit to transition
+ * through the transceiver before direction is changed to receive.
+ *
+ * Additionally there appears to be a 1 bit clock delay between writing
+ * to the THR register and transmission of the start bit, per page 8783
+ * of the AM65 TRM: https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf
+ */
+ if (priv->quot) {
+ if (priv->mdr1 == UART_OMAP_MDR1_16X_MODE)
+ baud = port->uartclk / (16 * priv->quot);
+ else
+ baud = port->uartclk / (13 * priv->quot);
+
+ fixed_delay_rts_after_send = 3 * MSEC_PER_SEC / baud;
+ fixed_delay_rts_before_send = 1 * MSEC_PER_SEC / baud;
+ }
+
+ /*
+ * Fall back to RS485 software emulation if the UART is missing
+ * hardware support, if the device tree specifies an mctrl_gpio
+ * (indicates that RTS is unavailable due to a pinmux conflict)
+ * or if the requested delays exceed the fixed hardware delays.
+ */
+ if (!(priv->habit & UART_HAS_NATIVE_RS485) ||
+ mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) ||
+ rs485->delay_rts_after_send > fixed_delay_rts_after_send ||
+ rs485->delay_rts_before_send > fixed_delay_rts_before_send) {
+ priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
+ serial_out(up, UART_OMAP_MDR3, priv->mdr3);
+
+ port->rs485_config = serial8250_em485_config;
+ return serial8250_em485_config(port, termios, rs485);
+ }
+
+ rs485->delay_rts_after_send = fixed_delay_rts_after_send;
+ rs485->delay_rts_before_send = fixed_delay_rts_before_send;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ priv->mdr3 |= UART_OMAP_MDR3_DIR_EN;
+ else
+ priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
+
+ /*
+ * Retain same polarity semantics as RS485 software emulation,
+ * i.e. SER_RS485_RTS_ON_SEND means driving RTS low on send.
+ */
+ if (rs485->flags & SER_RS485_RTS_ON_SEND)
+ priv->mdr3 &= ~UART_OMAP_MDR3_DIR_POL;
+ else
+ priv->mdr3 |= UART_OMAP_MDR3_DIR_POL;
+
+ serial_out(up, UART_OMAP_MDR3, priv->mdr3);
+
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_8250_DMA
static int omap_8250_rx_dma(struct uart_8250_port *p);
@@ -1243,7 +1321,7 @@ static struct omap8250_dma_params am33xx_dma = {
static struct omap8250_platdata am654_platdata = {
.dma_params = &am654_dma,
.habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
- UART_RX_TIMEOUT_QUIRK,
+ UART_RX_TIMEOUT_QUIRK | UART_HAS_NATIVE_RS485,
};
static struct omap8250_platdata am33xx_platdata = {
@@ -1336,7 +1414,8 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
- up.port.rs485_config = serial8250_em485_config;
+ up.port.rs485_config = omap8250_rs485_config;
+ /* same rs485_supported for software emulation and native RS485 */
up.port.rs485_supported = serial8250_em485_supported;
up.rs485_start_tx = serial8250_em485_start_tx;
up.rs485_stop_tx = serial8250_em485_stop_tx;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 388172289627..beba8f38b3dc 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1842,8 +1842,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
*/
serial_in(up, UART_SCR);
}
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_empty(xmit))
break;
if ((up->capabilities & UART_CAP_HFIFO) &&
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 434f83168546..c55b947f3cdb 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -958,6 +958,7 @@ config SERIAL_OMAP_CONSOLE
config SERIAL_SIFIVE
tristate "SiFive UART support"
depends on OF
+ default SOC_SIFIVE || SOC_CANAAN
select SERIAL_CORE
help
Select this option if you are building a kernel for a device that
@@ -967,6 +968,7 @@ config SERIAL_SIFIVE
config SERIAL_SIFIVE_CONSOLE
bool "Console on SiFive UART"
depends on SERIAL_SIFIVE=y
+ default SOC_SIFIVE || SOC_CANAAN
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index c2d154d78e54..9f843d1cee40 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -50,15 +50,6 @@
#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400
#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000
-/*
- * Local per-uart structure.
- */
-struct altera_jtaguart {
- struct uart_port port;
- unsigned int sigs; /* Local copy of line sigs */
- unsigned long imr; /* Local IMR mirror */
-};
-
static unsigned int altera_jtaguart_tx_space(struct uart_port *port, u32 *ctlp)
{
u32 ctl = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG);
@@ -85,29 +76,23 @@ static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
static void altera_jtaguart_start_tx(struct uart_port *port)
{
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
-
- pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
- writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+ port->read_status_mask |= ALTERA_JTAGUART_CONTROL_WE_MSK;
+ writel(port->read_status_mask,
+ port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_tx(struct uart_port *port)
{
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
-
- pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
- writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+ port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
+ writel(port->read_status_mask,
+ port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_rx(struct uart_port *port)
{
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
-
- pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
- writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+ port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
+ writel(port->read_status_mask,
+ port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
@@ -123,78 +108,51 @@ static void altera_jtaguart_set_termios(struct uart_port *port,
tty_termios_copy_hw(termios, old);
}
-static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
+static void altera_jtaguart_rx_chars(struct uart_port *port)
{
- struct uart_port *port = &pp->port;
- unsigned char ch, flag;
+ unsigned char ch;
unsigned long status;
while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
ALTERA_JTAGUART_DATA_RVALID_MSK) {
ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
- flag = TTY_NORMAL;
port->icount.rx++;
if (uart_handle_sysrq_char(port, ch))
continue;
- uart_insert_char(port, 0, 0, ch, flag);
+ uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
}
tty_flip_buffer_push(&port->state->port);
}
-static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
+static void altera_jtaguart_tx_chars(struct uart_port *port)
{
- 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;
- }
+ unsigned int count;
+ u8 ch;
- pending = uart_circ_chars_pending(xmit);
- if (pending > 0) {
- count = altera_jtaguart_tx_space(port, NULL);
- 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);
- }
- }
+ count = altera_jtaguart_tx_space(port, NULL);
- if (pending == 0)
- altera_jtaguart_stop_tx(port);
+ uart_port_tx_limited(port, ch, count,
+ true,
+ writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG),
+ ({}));
}
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
unsigned int isr;
isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
- ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
+ ALTERA_JTAGUART_CONTROL_RI_OFF) & port->read_status_mask;
spin_lock(&port->lock);
if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
- altera_jtaguart_rx_chars(pp);
+ altera_jtaguart_rx_chars(port);
if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
- altera_jtaguart_tx_chars(pp);
+ altera_jtaguart_tx_chars(port);
spin_unlock(&port->lock);
@@ -211,8 +169,6 @@ static void altera_jtaguart_config_port(struct uart_port *port, int flags)
static int altera_jtaguart_startup(struct uart_port *port)
{
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
unsigned long flags;
int ret;
@@ -227,8 +183,9 @@ static int altera_jtaguart_startup(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
- pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
- writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+ port->read_status_mask = ALTERA_JTAGUART_CONTROL_RE_MSK;
+ writel(port->read_status_mask,
+ port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
@@ -237,15 +194,14 @@ static int altera_jtaguart_startup(struct uart_port *port)
static void altera_jtaguart_shutdown(struct uart_port *port)
{
- struct altera_jtaguart *pp =
- container_of(port, struct altera_jtaguart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
- pp->imr = 0;
- writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
+ port->read_status_mask = 0;
+ writel(port->read_status_mask,
+ port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
@@ -298,7 +254,7 @@ static const struct uart_ops altera_jtaguart_ops = {
};
#define ALTERA_JTAGUART_MAXPORTS 1
-static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
+static struct uart_port altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
@@ -341,7 +297,7 @@ static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c
static void altera_jtaguart_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
+ struct uart_port *port = &altera_jtaguart_ports[co->index];
uart_console_write(port, s, count, altera_jtaguart_console_putc);
}
@@ -353,7 +309,7 @@ static int __init altera_jtaguart_console_setup(struct console *co,
if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
- port = &altera_jtaguart_ports[co->index].port;
+ port = &altera_jtaguart_ports[co->index];
if (port->membase == NULL)
return -ENODEV;
return 0;
@@ -433,7 +389,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
if (i >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
- port = &altera_jtaguart_ports[i].port;
+ port = &altera_jtaguart_ports[i];
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_mem)
@@ -477,7 +433,7 @@ static int altera_jtaguart_remove(struct platform_device *pdev)
if (i == -1)
i = 0;
- port = &altera_jtaguart_ports[i].port;
+ port = &altera_jtaguart_ports[i];
uart_remove_one_port(&altera_jtaguart_driver, port);
iounmap(port->membase);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 82f2790de28d..9ce3d24af536 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -247,47 +247,29 @@ static void altera_uart_rx_chars(struct uart_port *port)
static void altera_uart_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
-
- if (port->x_char) {
- /* Send special char - probably flow control */
- altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
- port->x_char = 0;
- port->icount.tx++;
- return;
- }
-
- while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
- ALTERA_UART_STATUS_TRDY_MSK) {
- if (xmit->head == xmit->tail)
- break;
- altera_uart_writel(port, xmit->buf[xmit->tail],
- ALTERA_UART_TXDATA_REG);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ u8 ch;
- if (uart_circ_empty(xmit))
- altera_uart_stop_tx(port);
+ uart_port_tx(port, ch,
+ altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+ ALTERA_UART_STATUS_TRDY_MSK,
+ altera_uart_writel(port, ch, ALTERA_UART_TXDATA_REG));
}
static irqreturn_t altera_uart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
struct altera_uart *pp = container_of(port, struct altera_uart, port);
+ unsigned long flags;
unsigned int isr;
isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
- spin_lock(&port->lock);
+ spin_lock_irqsave(&port->lock, flags);
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
altera_uart_rx_chars(port);
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
altera_uart_tx_chars(port);
- spin_unlock(&port->lock);
+ spin_unlock_irqrestore(&port->lock, flags);
return IRQ_RETVAL(isr);
}
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index af27fb8ec145..a98fae2ca422 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -164,34 +164,12 @@ static void pl010_rx_chars(struct uart_port *port)
static void pl010_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- int count;
+ u8 ch;
- 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);
+ uart_port_tx_limited(port, ch, port->fifosize >> 1,
+ true,
+ writel(ch, port->membase + UART01x_DR),
+ ({}));
}
static void pl010_modem_status(struct uart_amba_port *uap)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 5cdced39eafd..d75c39f4622b 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -677,8 +677,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
* Now we know that DMA will fire, so advance the ring buffer
* with the stuff we just dispatched.
*/
- xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
- uap->port.icount.tx += count;
+ uart_xmit_advance(&uap->port, count);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
@@ -1045,6 +1044,9 @@ static void pl011_dma_rx_callback(void *data)
*/
static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
{
+ if (!uap->using_rx_dma)
+ return;
+
/* FIXME. Just disable the DMA enable */
uap->dmacr &= ~UART011_RXDMAE;
pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -1828,8 +1830,17 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
static void pl011_unthrottle_rx(struct uart_port *port)
{
struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
+ unsigned long flags;
- pl011_enable_interrupts(uap);
+ spin_lock_irqsave(&uap->port.lock, flags);
+
+ uap->im = UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
+
+ pl011_write(uap->im, uap, REG_IMSC);
+
+ spin_unlock_irqrestore(&uap->port.lock, flags);
}
static int pl011_startup(struct uart_port *port)
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 450f4edfda0f..915ee4b0d594 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -122,36 +122,12 @@ static void apbuart_rx_chars(struct uart_port *port)
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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- apbuart_stop_tx(port);
+ uart_port_tx_limited(port, ch, port->fifosize >> 1,
+ true,
+ UART_PUT_CHAR(port, ch),
+ ({}));
}
static irqreturn_t apbuart_int(int irq, void *dev_id)
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 925484a42c82..4c3d04c6826a 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -425,8 +425,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
ar933x_uart_putc(up, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 2a65ea2660e1..748e8b1cf4f7 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -166,8 +166,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
sent = 1;
} else if (!uart_circ_empty(xmit)) {
ch = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
while (!(UART_GET_STATUS(port) & TXEMPTY))
cpu_relax();
UART_SET_DATA(port, ch);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index bd07f79a2df9..f1c06e12efa0 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -552,19 +552,23 @@ static u_int atmel_get_mctrl(struct uart_port *port)
static void atmel_stop_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ bool is_pdc = atmel_use_pdc_tx(port);
+ bool is_dma = is_pdc || atmel_use_dma_tx(port);
- if (atmel_use_pdc_tx(port)) {
+ if (is_pdc) {
/* disable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
}
- /*
- * Disable the transmitter.
- * This is mandatory when DMA is used, otherwise the DMA buffer
- * is fully transmitted.
- */
- atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
- atmel_port->tx_stopped = true;
+ if (is_dma) {
+ /*
+ * Disable the transmitter.
+ * This is mandatory when DMA is used, otherwise the DMA buffer
+ * is fully transmitted.
+ */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+ atmel_port->tx_stopped = true;
+ }
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
@@ -572,7 +576,6 @@ static void atmel_stop_tx(struct uart_port *port)
if (atmel_uart_is_half_duplex(port))
if (!atomic_read(&atmel_port->tasklet_shutdown))
atmel_start_rx(port);
-
}
/*
@@ -581,27 +584,31 @@ static void atmel_stop_tx(struct uart_port *port)
static void atmel_start_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ bool is_pdc = atmel_use_pdc_tx(port);
+ bool is_dma = is_pdc || atmel_use_dma_tx(port);
- if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
+ if (is_pdc && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
& ATMEL_PDC_TXTEN))
/* The transmitter is already running. Yes, we
really need this.*/
return;
- if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
- if (atmel_uart_is_half_duplex(port))
- atmel_stop_rx(port);
+ if (is_dma && atmel_uart_is_half_duplex(port))
+ atmel_stop_rx(port);
- if (atmel_use_pdc_tx(port))
+ if (is_pdc) {
/* re-enable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
+ }
/* Enable interrupts */
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
- /* re-enable the transmitter */
- atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
- atmel_port->tx_stopped = false;
+ if (is_dma) {
+ /* re-enable the transmitter */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
+ atmel_port->tx_stopped = false;
+ }
}
/*
@@ -824,30 +831,14 @@ static void atmel_rx_chars(struct uart_port *port)
*/
static void atmel_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ bool pending;
+ u8 ch;
- if (port->x_char &&
- (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) {
- atmel_uart_write_char(port, port->x_char);
- port->icount.tx++;
- port->x_char = 0;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- return;
-
- while (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY) {
- atmel_uart_write_char(port, xmit->buf[xmit->tail]);
- 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)) {
+ pending = uart_port_tx(port, ch,
+ atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY,
+ atmel_uart_write_char(port, ch));
+ if (pending) {
/* we still have characters to transmit, so we should continue
* transmitting them when TX is ready, regardless of
* mode or duplexity
@@ -875,10 +866,7 @@ static void atmel_complete_tx_dma(void *arg)
if (chan)
dmaengine_terminate_all(chan);
- xmit->tail += atmel_port->tx_len;
- xmit->tail &= UART_XMIT_SIZE - 1;
-
- port->icount.tx += atmel_port->tx_len;
+ uart_xmit_advance(port, atmel_port->tx_len);
spin_lock_irq(&atmel_port->lock_tx);
async_tx_ack(atmel_port->desc_tx);
@@ -1471,11 +1459,7 @@ static void atmel_tx_pdc(struct uart_port *port)
/* nothing left to transmit? */
if (atmel_uart_readl(port, ATMEL_PDC_TCR))
return;
-
- xmit->tail += pdc->ofs;
- xmit->tail &= UART_XMIT_SIZE - 1;
-
- port->icount.tx += pdc->ofs;
+ uart_xmit_advance(port, pdc->ofs);
pdc->ofs = 0;
/* more to transmit - setup next transfer */
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 5d9737c2d1f2..62bc7244dc67 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -303,53 +303,24 @@ static void bcm_uart_do_rx(struct uart_port *port)
*/
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;
+ bool pending;
+ u8 ch;
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 = uart_port_tx_limited(port, ch, port->fifosize - val,
+ true,
+ bcm_uart_writel(port, ch, UART_FIFO_REG),
+ ({}));
+ 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/clps711x.c b/drivers/tty/serial/clps711x.c
index 404b43a5ae33..e190dce58f46 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -166,8 +166,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
u32 sysflg = 0;
writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
if (sysflg & SYSFLG_UTXFF)
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index b4369ed45ae2..5565f302cb21 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -684,8 +684,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
count++;
if (xmit->head == xmit->tail)
break;
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index 0c0a62346f23..ed197705f7ee 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -202,8 +202,7 @@ static void digicolor_uart_tx(struct uart_port *port)
while (!uart_circ_empty(xmit)) {
writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (digicolor_uart_tx_full(port))
break;
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index 829b452daee9..6b7ed7f2f3ca 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -279,9 +279,8 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
* so we go one char at a time) :-<
*/
tmp = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
dz_out(dport, DZ_TDR, tmp);
- dport->port.icount.tx++;
+ uart_xmit_advance(&dport->port, 1);
if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
uart_write_wakeup(&dport->port);
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 84e8153e5420..6fc21b6684e6 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -178,8 +178,7 @@ static inline void linflex_transmit_buffer(struct uart_port *sport)
while (!uart_circ_empty(xmit)) {
linflex_put_char(sport, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->icount.tx++;
+ uart_xmit_advance(sport, 1);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 888e01fbd9c5..5e69fb73f570 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -18,6 +18,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
@@ -232,6 +234,7 @@
/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
#define DMA_RX_TIMEOUT (10)
+#define UART_AUTOSUSPEND_TIMEOUT 3000
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
@@ -509,9 +512,7 @@ static void lpuart_dma_tx_complete(void *arg)
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
- xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
-
- sport->port.icount.tx += sport->dma_tx_bytes;
+ uart_xmit_advance(&sport->port, sport->dma_tx_bytes);
sport->dma_tx_in_progress = false;
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -582,7 +583,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
sport->dma_tx_nents, DMA_TO_DEVICE);
sport->dma_tx_in_progress = false;
}
- dmaengine_terminate_all(chan);
+ dmaengine_terminate_async(chan);
}
if (lpuart_is_32(sport)) {
@@ -716,32 +717,12 @@ static int lpuart32_poll_get_char(struct uart_port *port)
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
-
- if (sport->port.x_char) {
- writeb(sport->port.x_char, sport->port.membase + UARTDR);
- sport->port.icount.tx++;
- sport->port.x_char = 0;
- return;
- }
-
- if (lpuart_stopped_or_empty(&sport->port)) {
- lpuart_stop_tx(&sport->port);
- return;
- }
-
- while (!uart_circ_empty(xmit) &&
- (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
- writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&sport->port);
+ struct uart_port *port = &sport->port;
+ u8 ch;
- if (uart_circ_empty(xmit))
- lpuart_stop_tx(&sport->port);
+ uart_port_tx(port, ch,
+ readb(port->membase + UARTTCFIFO) < sport->txfifo_size,
+ writeb(ch, port->membase + UARTDR));
}
static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
@@ -766,8 +747,7 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
txcnt &= UARTWATER_COUNT_MASK;
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx++;
+ uart_xmit_advance(&sport->port, 1);
txcnt = lpuart32_read(&sport->port, UARTWATER);
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
txcnt &= UARTWATER_COUNT_MASK;
@@ -815,6 +795,20 @@ static void lpuart32_start_tx(struct uart_port *port)
}
}
+static void
+lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+ switch (state) {
+ case UART_PM_STATE_OFF:
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
+ break;
+ default:
+ pm_runtime_get_sync(port->dev);
+ break;
+ }
+}
+
/* return TIOCSER_TEMT when transmitter is not busy */
static unsigned int lpuart_tx_empty(struct uart_port *port)
{
@@ -1333,7 +1327,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct lpuart_port, port);
struct dma_chan *chan = sport->dma_rx_chan;
- dmaengine_terminate_all(chan);
+ dmaengine_terminate_sync(chan);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
@@ -1650,10 +1644,23 @@ err:
sport->lpuart_dma_rx_use = false;
}
+static void lpuart_hw_setup(struct lpuart_port *sport)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ lpuart_setup_watermark_enable(sport);
+
+ lpuart_rx_dma_startup(sport);
+ lpuart_tx_dma_startup(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long flags;
unsigned char temp;
/* determine FIFO size and enable FIFO mode */
@@ -1667,15 +1674,7 @@ static int lpuart_startup(struct uart_port *port)
UARTPFIFO_FIFOSIZE_MASK);
lpuart_request_dma(sport);
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
- lpuart_setup_watermark_enable(sport);
-
- lpuart_rx_dma_startup(sport);
- lpuart_tx_dma_startup(sport);
-
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ lpuart_hw_setup(sport);
return 0;
}
@@ -1698,10 +1697,25 @@ static void lpuart32_configure(struct lpuart_port *sport)
lpuart32_write(&sport->port, temp, UARTCTRL);
}
+static void lpuart32_hw_setup(struct lpuart_port *sport)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ lpuart32_setup_watermark_enable(sport);
+
+ lpuart_rx_dma_startup(sport);
+ lpuart_tx_dma_startup(sport);
+
+ lpuart32_configure(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
static int lpuart32_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long flags;
unsigned long temp;
/* determine FIFO size */
@@ -1726,17 +1740,8 @@ static int lpuart32_startup(struct uart_port *port)
}
lpuart_request_dma(sport);
+ lpuart32_hw_setup(sport);
- spin_lock_irqsave(&sport->port.lock, flags);
-
- lpuart32_setup_watermark_enable(sport);
-
- lpuart_rx_dma_startup(sport);
- lpuart_tx_dma_startup(sport);
-
- lpuart32_configure(sport);
-
- spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
@@ -1752,7 +1757,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
if (wait_event_interruptible_timeout(sport->dma_wait,
!sport->dma_tx_in_progress, msecs_to_jiffies(300)) <= 0) {
sport->dma_tx_in_progress = false;
- dmaengine_terminate_all(sport->dma_tx_chan);
+ dmaengine_terminate_sync(sport->dma_tx_chan);
}
sport->lpuart_dma_tx_use = false;
}
@@ -2240,6 +2245,7 @@ static const struct uart_ops lpuart_pops = {
.startup = lpuart_startup,
.shutdown = lpuart_shutdown,
.set_termios = lpuart_set_termios,
+ .pm = lpuart_uart_pm,
.type = lpuart_type,
.request_port = lpuart_request_port,
.release_port = lpuart_release_port,
@@ -2264,6 +2270,7 @@ static const struct uart_ops lpuart32_pops = {
.startup = lpuart32_startup,
.shutdown = lpuart32_shutdown,
.set_termios = lpuart32_set_termios,
+ .pm = lpuart_uart_pm,
.type = lpuart_type,
.request_port = lpuart_request_port,
.release_port = lpuart_release_port,
@@ -2744,6 +2751,11 @@ static int lpuart_probe(struct platform_device *pdev)
handler = lpuart_int;
}
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
ret = lpuart_global_reset(sport);
if (ret)
goto failed_reset;
@@ -2768,6 +2780,9 @@ failed_irq_request:
failed_attach_port:
failed_get_rs485:
failed_reset:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
lpuart_disable_clks(sport);
return ret;
}
@@ -2786,100 +2801,241 @@ static int lpuart_remove(struct platform_device *pdev)
if (sport->dma_rx_chan)
dma_release_channel(sport->dma_rx_chan);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
return 0;
}
-static int __maybe_unused lpuart_suspend(struct device *dev)
+static int lpuart_runtime_suspend(struct device *dev)
{
- struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned long temp;
- bool irq_wake;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
- if (lpuart_is_32(sport)) {
- /* disable Rx/Tx and interrupts */
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
- lpuart32_write(&sport->port, temp, UARTCTRL);
- } else {
- /* disable Rx/Tx and interrupts */
- temp = readb(sport->port.membase + UARTCR2);
- temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
- writeb(temp, sport->port.membase + UARTCR2);
- }
+ lpuart_disable_clks(sport);
- uart_suspend_port(&lpuart_reg, &sport->port);
+ return 0;
+};
- /* uart_suspend_port() might set wakeup flag */
- irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
+static int lpuart_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
- if (sport->lpuart_dma_rx_use) {
- /*
- * EDMA driver during suspend will forcefully release any
- * non-idle DMA channels. If port wakeup is enabled or if port
- * is console port or 'no_console_suspend' is set the Rx DMA
- * cannot resume as expected, hence gracefully release the
- * Rx DMA path before suspend and start Rx DMA path on resume.
- */
- if (irq_wake) {
- del_timer_sync(&sport->lpuart_timer);
- lpuart_dma_rx_free(&sport->port);
- }
+ return lpuart_enable_clks(sport);
+};
- /* Disable Rx DMA to use UART port as wakeup source */
- if (lpuart_is_32(sport)) {
- temp = lpuart32_read(&sport->port, UARTBAUD);
- lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
- UARTBAUD);
+static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
+{
+ unsigned int val, baud;
+
+ if (lpuart_is_32(sport)) {
+ val = lpuart32_read(&sport->port, UARTCTRL);
+ baud = lpuart32_read(&sport->port, UARTBAUD);
+ if (on) {
+ /* set rx_watermark to 0 in wakeup source mode */
+ lpuart32_write(&sport->port, 0, UARTWATER);
+ val |= UARTCTRL_RIE;
+ /* clear RXEDGIF flag before enable RXEDGIE interrupt */
+ lpuart32_write(&sport->port, UARTSTAT_RXEDGIF, UARTSTAT);
+ baud |= UARTBAUD_RXEDGIE;
} else {
- writeb(readb(sport->port.membase + UARTCR5) &
- ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+ val &= ~UARTCTRL_RIE;
+ baud &= ~UARTBAUD_RXEDGIE;
}
+ lpuart32_write(&sport->port, val, UARTCTRL);
+ lpuart32_write(&sport->port, baud, UARTBAUD);
+ } else {
+ val = readb(sport->port.membase + UARTCR2);
+ if (on)
+ val |= UARTCR2_RIE;
+ else
+ val &= ~UARTCR2_RIE;
+ writeb(val, sport->port.membase + UARTCR2);
}
+}
- if (sport->lpuart_dma_tx_use) {
- sport->dma_tx_in_progress = false;
- dmaengine_terminate_all(sport->dma_tx_chan);
+static bool lpuart_uport_is_active(struct lpuart_port *sport)
+{
+ struct tty_port *port = &sport->port.state->port;
+ struct tty_struct *tty;
+ struct device *tty_dev;
+ int may_wake = 0;
+
+ tty = tty_port_tty_get(port);
+ if (tty) {
+ tty_dev = tty->dev;
+ may_wake = device_may_wakeup(tty_dev);
+ tty_kref_put(tty);
}
- if (sport->port.suspended && !irq_wake)
- lpuart_disable_clks(sport);
+ if ((tty_port_initialized(port) && may_wake) ||
+ (!console_suspend_enabled && uart_console(&sport->port)))
+ return true;
- return 0;
+ return false;
}
-static int __maybe_unused lpuart_resume(struct device *dev)
+static int lpuart_suspend_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
- if (sport->port.suspended && !irq_wake)
- lpuart_enable_clks(sport);
+ if (lpuart_uport_is_active(sport))
+ serial_lpuart_enable_wakeup(sport, !!irq_wake);
- if (lpuart_is_32(sport))
- lpuart32_setup_watermark_enable(sport);
- else
- lpuart_setup_watermark_enable(sport);
+ pinctrl_pm_select_sleep_state(dev);
- if (sport->lpuart_dma_rx_use) {
- if (irq_wake) {
- if (!lpuart_start_rx_dma(sport))
- rx_dma_timer_init(sport);
- else
- sport->lpuart_dma_rx_use = false;
+ return 0;
+}
+
+static int lpuart_resume_noirq(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ unsigned int val;
+
+ pinctrl_pm_select_default_state(dev);
+
+ if (lpuart_uport_is_active(sport)) {
+ serial_lpuart_enable_wakeup(sport, false);
+
+ /* clear the wakeup flags */
+ if (lpuart_is_32(sport)) {
+ val = lpuart32_read(&sport->port, UARTSTAT);
+ lpuart32_write(&sport->port, val, UARTSTAT);
}
}
- lpuart_tx_dma_startup(sport);
+ return 0;
+}
- if (lpuart_is_32(sport))
- lpuart32_configure(sport);
+static int lpuart_suspend(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ unsigned long temp, flags;
+ uart_suspend_port(&lpuart_reg, &sport->port);
+
+ if (lpuart_uport_is_active(sport)) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (lpuart_is_32(sport)) {
+ /* disable Rx/Tx and interrupts */
+ temp = lpuart32_read(&sport->port, UARTCTRL);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(&sport->port, temp, UARTCTRL);
+ } else {
+ /* disable Rx/Tx and interrupts */
+ temp = readb(sport->port.membase + UARTCR2);
+ temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(temp, sport->port.membase + UARTCR2);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (sport->lpuart_dma_rx_use) {
+ /*
+ * EDMA driver during suspend will forcefully release any
+ * non-idle DMA channels. If port wakeup is enabled or if port
+ * is console port or 'no_console_suspend' is set the Rx DMA
+ * cannot resume as expected, hence gracefully release the
+ * Rx DMA path before suspend and start Rx DMA path on resume.
+ */
+ del_timer_sync(&sport->lpuart_timer);
+ lpuart_dma_rx_free(&sport->port);
+
+ /* Disable Rx DMA to use UART port as wakeup source */
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (lpuart_is_32(sport)) {
+ temp = lpuart32_read(&sport->port, UARTBAUD);
+ lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
+ UARTBAUD);
+ } else {
+ writeb(readb(sport->port.membase + UARTCR5) &
+ ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ }
+
+ if (sport->lpuart_dma_tx_use) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (lpuart_is_32(sport)) {
+ temp = lpuart32_read(&sport->port, UARTBAUD);
+ temp &= ~UARTBAUD_TDMAE;
+ lpuart32_write(&sport->port, temp, UARTBAUD);
+ } else {
+ temp = readb(sport->port.membase + UARTCR5);
+ temp &= ~UARTCR5_TDMAS;
+ writeb(temp, sport->port.membase + UARTCR5);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ sport->dma_tx_in_progress = false;
+ dmaengine_terminate_sync(sport->dma_tx_chan);
+ }
+ } else if (pm_runtime_active(sport->port.dev)) {
+ lpuart_disable_clks(sport);
+ pm_runtime_disable(sport->port.dev);
+ pm_runtime_set_suspended(sport->port.dev);
+ }
+
+ return 0;
+}
+
+static void lpuart_console_fixup(struct lpuart_port *sport)
+{
+ struct tty_port *port = &sport->port.state->port;
+ struct uart_port *uport = &sport->port;
+ struct ktermios termios;
+
+ /* i.MX7ULP enter VLLS mode that lpuart module power off and registers
+ * all lost no matter the port is wakeup source.
+ * For console port, console baud rate setting lost and print messy
+ * log when enable the console port as wakeup source. To avoid the
+ * issue happen, user should not enable uart port as wakeup source
+ * in VLLS mode, or restore console setting here.
+ */
+ if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
+ console_suspend_enabled && uart_console(&sport->port)) {
+
+ mutex_lock(&port->mutex);
+ memset(&termios, 0, sizeof(struct ktermios));
+ termios.c_cflag = uport->cons->cflag;
+ if (port->tty && termios.c_cflag == 0)
+ termios = port->tty->termios;
+ uport->ops->set_termios(uport, &termios, NULL);
+ mutex_unlock(&port->mutex);
+ }
+}
+
+static int lpuart_resume(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ int ret;
+
+ if (lpuart_uport_is_active(sport)) {
+ if (lpuart_is_32(sport))
+ lpuart32_hw_setup(sport);
+ else
+ lpuart_hw_setup(sport);
+ } else if (pm_runtime_active(sport->port.dev)) {
+ ret = lpuart_enable_clks(sport);
+ if (ret)
+ return ret;
+ pm_runtime_set_active(sport->port.dev);
+ pm_runtime_enable(sport->port.dev);
+ }
+
+ lpuart_console_fixup(sport);
uart_resume_port(&lpuart_reg, &sport->port);
return 0;
}
-static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
+static const struct dev_pm_ops lpuart_pm_ops = {
+ RUNTIME_PM_OPS(lpuart_runtime_suspend,
+ lpuart_runtime_resume, NULL)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq,
+ lpuart_resume_noirq)
+ SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
+};
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
@@ -2887,7 +3043,7 @@ static struct platform_driver lpuart_driver = {
.driver = {
.name = "fsl-lpuart",
.of_match_table = lpuart_dt_ids,
- .pm = &lpuart_pm_ops,
+ .pm = pm_ptr(&lpuart_pm_ops),
},
};
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index aadda66405b4..757825edb0cd 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -489,7 +489,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
static void imx_uart_stop_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- u32 ucr1, ucr2, ucr4;
+ u32 ucr1, ucr2, ucr4, uts;
ucr1 = imx_uart_readl(sport, UCR1);
ucr2 = imx_uart_readl(sport, UCR2);
@@ -505,7 +505,18 @@ static void imx_uart_stop_rx(struct uart_port *port)
imx_uart_writel(sport, ucr1, UCR1);
imx_uart_writel(sport, ucr4, UCR4);
- ucr2 &= ~UCR2_RXEN;
+ /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ port->rs485.flags & SER_RS485_RTS_ON_SEND &&
+ sport->have_rtscts && !sport->have_rtsgpio) {
+ uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
+ uts |= UTS_LOOP;
+ imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
+ ucr2 |= UCR2_RXEN;
+ } else {
+ ucr2 &= ~UCR2_RXEN;
+ }
+
imx_uart_writel(sport, ucr2, UCR2);
}
@@ -563,8 +574,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
/* send xmit->buf[xmit->tail]
* out the port here */
imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx++;
+ uart_xmit_advance(&sport->port, 1);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -590,9 +600,7 @@ static void imx_uart_dma_tx_callback(void *data)
ucr1 &= ~UCR1_TXDMAEN;
imx_uart_writel(sport, ucr1, UCR1);
- /* update the stat */
- xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx += sport->tx_bytes;
+ uart_xmit_advance(&sport->port, sport->tx_bytes);
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
@@ -1393,7 +1401,7 @@ static int imx_uart_startup(struct uart_port *port)
int retval, i;
unsigned long flags;
int dma_is_inited = 0;
- u32 ucr1, ucr2, ucr3, ucr4;
+ u32 ucr1, ucr2, ucr3, ucr4, uts;
retval = clk_prepare_enable(sport->clk_per);
if (retval)
@@ -1498,6 +1506,11 @@ static int imx_uart_startup(struct uart_port *port)
imx_uart_writel(sport, ucr2, UCR2);
}
+ /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
+ uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
+ uts &= ~UTS_LOOP;
+ imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
+
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
@@ -1507,7 +1520,7 @@ static void imx_uart_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- u32 ucr1, ucr2, ucr4;
+ u32 ucr1, ucr2, ucr4, uts;
if (sport->dma_is_enabled) {
dmaengine_terminate_sync(sport->dma_chan_tx);
@@ -1551,7 +1564,18 @@ static void imx_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&sport->port.lock, flags);
ucr1 = imx_uart_readl(sport, UCR1);
- ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
+ ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
+ /* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ port->rs485.flags & SER_RS485_RTS_ON_SEND &&
+ sport->have_rtscts && !sport->have_rtsgpio) {
+ uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
+ uts |= UTS_LOOP;
+ imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
+ ucr1 |= UCR1_UARTEN;
+ } else {
+ ucr1 &= ~UCR1_UARTEN;
+ }
imx_uart_writel(sport, ucr1, UCR1);
ucr4 = imx_uart_readl(sport, UCR4);
@@ -2213,7 +2237,7 @@ static int imx_uart_probe(struct platform_device *pdev)
void __iomem *base;
u32 dma_buf_conf[2];
int ret = 0;
- u32 ucr1;
+ u32 ucr1, ucr2, uts;
struct resource *res;
int txirq, rxirq, rtsirq;
@@ -2350,6 +2374,31 @@ static int imx_uart_probe(struct platform_device *pdev)
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
imx_uart_writel(sport, ucr1, UCR1);
+ /*
+ * In case RS485 is enabled without GPIO RTS control, the UART IP
+ * is used to control CTS signal. Keep both the UART and Receiver
+ * enabled, otherwise the UART IP pulls CTS signal always HIGH no
+ * matter how the UCR2 CTSC and CTS bits are set. To prevent any
+ * data from being fed into the RX FIFO, enable loopback mode in
+ * UTS register, which disconnects the RX path from external RXD
+ * pin and connects it to the Transceiver, which is disabled, so
+ * no data can be fed to the RX FIFO that way.
+ */
+ if (sport->port.rs485.flags & SER_RS485_ENABLED &&
+ sport->have_rtscts && !sport->have_rtsgpio) {
+ uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
+ uts |= UTS_LOOP;
+ imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
+
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 |= UCR1_UARTEN;
+ imx_uart_writel(sport, ucr1, UCR1);
+
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 |= UCR2_RXEN;
+ imx_uart_writel(sport, ucr2, UCR2);
+ }
+
if (!imx_uart_is_imx1(sport) && sport->dte_mode) {
/*
* The DCEDTE bit changes the direction of DSR, DCD, DTR and RI
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index dd0a8915ce4f..b1f27e168135 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -409,8 +409,7 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
ZSDELAY();
ZS_WSYNC(channel);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
@@ -609,8 +608,7 @@ static void ip22zilog_start_tx(struct uart_port *port)
ZSDELAY();
ZS_WSYNC(channel);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index c892f3c7d1ab..a58e9277dfad 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -95,7 +95,6 @@
#define ASCFSTAT_TXFFLMASK 0x3F00
#define ASCFSTAT_TXFREEMASK 0x3F000000
-static void lqasc_tx_chars(struct uart_port *port);
static struct ltq_uart_port *lqasc_port[MAXPORTS];
static struct uart_driver lqasc_reg;
@@ -151,9 +150,12 @@ lqasc_start_tx(struct uart_port *port)
{
unsigned long flags;
struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+ u8 ch;
spin_lock_irqsave(&ltq_port->lock, flags);
- lqasc_tx_chars(port);
+ uart_port_tx(port, ch,
+ lqasc_tx_ready(port),
+ writeb(ch, port->membase + LTQ_ASC_TBUF));
spin_unlock_irqrestore(&ltq_port->lock, flags);
return;
}
@@ -226,36 +228,6 @@ lqasc_rx_chars(struct uart_port *port)
return 0;
}
-static void
-lqasc_tx_chars(struct uart_port *port)
-{
- struct circ_buf *xmit = &port->state->xmit;
- if (uart_tx_stopped(port)) {
- lqasc_stop_tx(port);
- return;
- }
-
- while (lqasc_tx_ready(port)) {
- if (port->x_char) {
- writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
- port->icount.tx++;
- port->x_char = 0;
- continue;
- }
-
- if (uart_circ_empty(xmit))
- break;
-
- writeb(port->state->xmit.buf[port->state->xmit.tail],
- port->membase + LTQ_ASC_TBUF);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-}
-
static irqreturn_t
lqasc_tx_int(int irq, void *_port)
{
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 4c0604325ee9..062812fe1b09 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -136,8 +136,7 @@ static void liteuart_start_tx(struct uart_port *port)
} else if (!uart_circ_empty(xmit)) {
while (xmit->head != xmit->tail) {
ch = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
liteuart_putchar(port, ch);
}
}
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index ed47f4768338..b38fe4728c26 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -276,8 +276,6 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
tty_flip_buffer_push(tport);
}
-static void serial_lpc32xx_stop_tx(struct uart_port *port);
-
static bool serial_lpc32xx_tx_ready(struct uart_port *port)
{
u32 level = readl(LPC32XX_HSUART_LEVEL(port->membase));
@@ -287,34 +285,11 @@ static bool serial_lpc32xx_tx_ready(struct uart_port *port)
static void __serial_lpc32xx_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
-
- if (port->x_char) {
- writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
- port->icount.tx++;
- port->x_char = 0;
- return;
- }
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- goto exit_tx;
-
- /* Transfer data */
- while (serial_lpc32xx_tx_ready(port)) {
- writel((u32) xmit->buf[xmit->tail],
- LPC32XX_HSUART_FIFO(port->membase));
- 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);
+ u8 ch;
-exit_tx:
- if (uart_circ_empty(xmit))
- serial_lpc32xx_stop_tx(port);
+ uart_port_tx(port, ch,
+ serial_lpc32xx_tx_ready(port),
+ writel(ch, LPC32XX_HSUART_FIFO(port->membase)));
}
static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index c69602f356fd..bb74f23251fe 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -292,9 +292,7 @@ static void max3100_work(struct work_struct *w)
} else if (!uart_circ_empty(xmit) &&
!uart_tx_stopped(&s->port)) {
tx = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) &
- (UART_XMIT_SIZE - 1);
- s->port.icount.tx++;
+ uart_xmit_advance(&s->port, 1);
}
if (tx != 0xffff) {
max3100_calc_parity(s, &tx);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index fbf6e2b3161c..4eb24e3407f8 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -787,10 +787,7 @@ static void max310x_handle_tx(struct uart_port *port)
} else {
max310x_batch_write(port, xmit->buf + xmit->tail, to_send);
}
-
- /* Add data to send */
- port->icount.tx += to_send;
- xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1);
+ uart_xmit_advance(port, to_send);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index b1cd9a76dd93..3239babe12a4 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -327,34 +327,16 @@ static void mcf_rx_chars(struct mcf_uart *pp)
static void mcf_tx_chars(struct mcf_uart *pp)
{
struct uart_port *port = &pp->port;
- struct circ_buf *xmit = &port->state->xmit;
-
- if (port->x_char) {
- /* Send special char - probably flow control */
- writeb(port->x_char, port->membase + MCFUART_UTB);
- port->x_char = 0;
- port->icount.tx++;
- return;
- }
-
- while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
- if (uart_circ_empty(xmit))
- break;
- writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
- port->icount.tx++;
- }
+ bool pending;
+ u8 ch;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ pending = uart_port_tx(port, ch,
+ readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY,
+ writeb(ch, port->membase + MCFUART_UTB));
- if (uart_circ_empty(xmit)) {
- mcf_stop_tx(port);
- /* Disable TX to negate RTS automatically */
- if (port->rs485.flags & SER_RS485_ENABLED)
- writeb(MCFUART_UCR_TXDISABLE,
- port->membase + MCFUART_UCR);
- }
+ /* Disable TX to negate RTS automatically */
+ if (!pending && (port->rs485.flags & SER_RS485_ENABLED))
+ writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR);
}
/****************************************************************************/
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 3690f5cf0f43..d2502aaa3e8c 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -352,11 +352,8 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
n = min(n, s);
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
- xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
-
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
-
- port->icount.tx += n;
+ uart_xmit_advance(port, n);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 056243c12836..74110017988a 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -162,8 +162,7 @@ static void meson_uart_start_tx(struct uart_port *port)
ch = xmit->buf[xmit->tail];
writel(ch, port->membase + AML_UART_WFIFO);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
if (!uart_circ_empty(xmit)) {
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index c15e0d84dc7e..44988a2941b8 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -98,8 +98,7 @@ static void mlb_usio_tx_chars(struct uart_port *port)
do {
writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_empty(xmit))
break;
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 73362d4bc45d..384ca195e3d5 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1428,42 +1428,11 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
static inline bool
mpc52xx_uart_int_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
-
- /* Process out of band chars */
- if (port->x_char) {
- psc_ops->write_char(port, port->x_char);
- port->icount.tx++;
- port->x_char = 0;
- return true;
- }
-
- /* Nothing to do ? */
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- mpc52xx_uart_stop_tx(port);
- return false;
- }
-
- /* Send chars */
- while (psc_ops->raw_tx_rdy(port)) {
- psc_ops->write_char(port, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- }
-
- /* Wake up */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- /* Maybe we're done after all */
- if (uart_circ_empty(xmit)) {
- mpc52xx_uart_stop_tx(port);
- return false;
- }
+ u8 ch;
- return true;
+ return uart_port_tx(port, ch,
+ psc_ops->raw_tx_rdy(port),
+ psc_ops->write_char(port, ch));
}
static irqreturn_t
diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c
index 2e3e6cf16817..860d161fa594 100644
--- a/drivers/tty/serial/mps2-uart.c
+++ b/drivers/tty/serial/mps2-uart.c
@@ -129,29 +129,11 @@ static void mps2_uart_stop_tx(struct uart_port *port)
static void mps2_uart_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
-
- while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) {
- if (port->x_char) {
- mps2_uart_write8(port, port->x_char, UARTn_DATA);
- port->x_char = 0;
- port->icount.tx++;
- continue;
- }
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- break;
-
- mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA);
- xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
- port->icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ u8 ch;
- if (uart_circ_empty(xmit))
- mps2_uart_stop_tx(port);
+ uart_port_tx(port, ch,
+ mps2_uart_tx_empty(port),
+ mps2_uart_write8(port, ch, UARTn_DATA));
}
static void mps2_uart_start_tx(struct uart_port *port)
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 7dd19a281579..843798e63084 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -464,12 +464,9 @@ static void msm_complete_tx_dma(void *args)
}
count = dma->count - state.residue;
- port->icount.tx += count;
+ uart_xmit_advance(port, count);
dma->count = 0;
- xmit->tail += count;
- xmit->tail &= UART_XMIT_SIZE - 1;
-
/* Restore "Tx FIFO below watermark" interrupt */
msm_port->imr |= MSM_UART_IMR_TXLEV;
msm_write(port, msm_port->imr, MSM_UART_IMR);
@@ -819,7 +816,7 @@ static void msm_handle_rx(struct uart_port *port)
port->icount.rx++;
}
- /* Mask conditions we're ignorning. */
+ /* Mask conditions we're ignoring. */
sr &= port->read_status_mask;
if (sr & MSM_UART_SR_RX_BREAK)
@@ -866,13 +863,11 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
else
num_chars = 1;
- for (i = 0; i < num_chars; i++) {
+ for (i = 0; i < num_chars; i++)
buf[i] = xmit->buf[xmit->tail + i];
- port->icount.tx++;
- }
iowrite32_rep(tf, buf, 1);
- xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1);
+ uart_xmit_advance(port, num_chars);
tf_pointer += num_chars;
}
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index ed0e763f622a..85ce1e9af44a 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -171,6 +171,13 @@ 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);
+}
+
/**
* mux_write - Write chars to the mux fifo.
* @port: Ptr to the uart_port.
@@ -180,39 +187,13 @@ 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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- mux_stop_tx(port);
+ uart_port_tx_limited(port, ch,
+ port->fifosize - UART_GET_FIFO_CNT(port),
+ true,
+ UART_PUT_CHAR(port, ch),
+ mux_tx_done(port));
}
/**
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index ba16e1da6bd3..31f739c7a08b 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -223,8 +223,7 @@ static void mvebu_uart_start_tx(struct uart_port *port)
if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) {
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
ctl = readl(port->membase + UART_INTR(port));
@@ -335,40 +334,12 @@ ignore_char:
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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- mvebu_uart_stop_tx(port);
+ uart_port_tx_limited(port, ch, port->fifosize,
+ !(readl(port->membase + UART_STAT) & STAT_TX_FIFO_FUL),
+ writel(ch, port->membase + UART_TSH(port)),
+ ({}));
}
static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index d21a4f3ef2fe..ef6e7bb6105c 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -569,6 +569,8 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
static void mxs_auart_tx_chars(struct mxs_auart_port *s)
{
struct circ_buf *xmit = &s->port.state->xmit;
+ bool pending;
+ u8 ch;
if (auart_dma_enabled(s)) {
u32 i = 0;
@@ -603,31 +605,13 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
return;
}
-
- while (!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF)) {
- if (s->port.x_char) {
- s->port.icount.tx++;
- mxs_write(s->port.x_char, s, REG_DATA);
- s->port.x_char = 0;
- continue;
- }
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
- s->port.icount.tx++;
- mxs_write(xmit->buf[xmit->tail], s, REG_DATA);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } else
- break;
- }
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&s->port);
-
- if (uart_circ_empty(&(s->port.state->xmit)))
- mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
- else
+ pending = uart_port_tx(&s->port, ch,
+ !(mxs_read(s, REG_STAT) & AUART_STAT_TXFF),
+ mxs_write(ch, s, REG_DATA));
+ if (pending)
mxs_set(AUART_INTR_TXIEN, s, REG_INTR);
-
- if (uart_tx_stopped(&s->port))
- mxs_auart_stop_tx(&s->port);
+ else
+ mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
}
static void mxs_auart_rx_char(struct mxs_auart_port *s)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 7d0d2718ef59..82d35dbbfa6c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -347,34 +347,12 @@ static void serial_omap_put_char(struct uart_omap_port *up, unsigned char ch)
static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
{
- struct circ_buf *xmit = &up->port.state->xmit;
- int count;
+ u8 ch;
- if (up->port.x_char) {
- serial_omap_put_char(up, 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_omap_stop_tx(&up->port);
- return;
- }
- count = up->port.fifosize / 4;
- do {
- serial_omap_put_char(up, 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);
-
- if (uart_circ_empty(xmit))
- serial_omap_stop_tx(&up->port);
+ uart_port_tx_limited(&up->port, ch, up->port.fifosize / 4,
+ true,
+ serial_omap_put_char(up, ch),
+ ({}));
}
static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
index fde39cc1145d..e99970a9437f 100644
--- a/drivers/tty/serial/owl-uart.c
+++ b/drivers/tty/serial/owl-uart.c
@@ -181,35 +181,11 @@ static void owl_uart_start_tx(struct uart_port *port)
static void owl_uart_send_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int ch;
-
- if (port->x_char) {
- while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU))
- cpu_relax();
- owl_uart_write(port, port->x_char, OWL_UART_TXDAT);
- port->icount.tx++;
- port->x_char = 0;
- }
-
- if (uart_tx_stopped(port))
- return;
-
- while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) {
- if (uart_circ_empty(xmit))
- break;
+ u8 ch;
- ch = xmit->buf[xmit->tail];
- owl_uart_write(port, ch, OWL_UART_TXDAT);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- if (uart_circ_empty(xmit))
- owl_uart_stop_tx(port);
+ uart_port_tx(port, ch,
+ !(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU),
+ owl_uart_write(port, ch, OWL_UART_TXDAT));
}
static void owl_uart_receive_chars(struct uart_port *port)
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c59ce7886579..3d54a43768cd 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -694,6 +694,7 @@ static void pch_request_dma(struct uart_port *port)
if (!chan) {
dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
__func__);
+ pci_dev_put(dma_dev);
return;
}
priv->chan_tx = chan;
@@ -710,6 +711,7 @@ static void pch_request_dma(struct uart_port *port)
__func__);
dma_release_channel(priv->chan_tx);
priv->chan_tx = NULL;
+ pci_dev_put(dma_dev);
return;
}
@@ -717,6 +719,8 @@ static void pch_request_dma(struct uart_port *port)
priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
&priv->rx_buf_dma, GFP_KERNEL);
priv->chan_rx = chan;
+
+ pci_dev_put(dma_dev);
}
static void pch_dma_rx_complete(void *arg)
@@ -738,15 +742,12 @@ static void pch_dma_tx_complete(void *arg)
{
struct eg20t_port *priv = arg;
struct uart_port *port = &priv->port;
- struct circ_buf *xmit = &port->state->xmit;
struct scatterlist *sg = priv->sg_tx_p;
int i;
- for (i = 0; i < priv->nent; i++, sg++) {
- xmit->tail += sg_dma_len(sg);
- port->icount.tx += sg_dma_len(sg);
- }
- xmit->tail &= UART_XMIT_SIZE - 1;
+ for (i = 0; i < priv->nent; i++, sg++)
+ uart_xmit_advance(port, sg_dma_len(sg));
+
async_tx_ack(priv->desc_tx);
dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE);
priv->tx_dma_use = 0;
@@ -843,8 +844,7 @@ static unsigned int handle_tx(struct eg20t_port *priv)
while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) {
iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
fifo_size--;
tx_empty = 0;
}
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index c38754d593ca..ba3435263c1f 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -376,8 +376,7 @@ static void pic32_uart_do_tx(struct uart_port *port)
pic32_uart_writel(sport, PIC32_UART_TX, c);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_empty(xmit))
break;
if (--max_count == 0)
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index fe2e4ec423f7..13668ffdb1e7 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -410,8 +410,7 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
write_zsdata(uap, xmit->buf[xmit->tail]);
zssync(uap);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- uap->port.icount.tx++;
+ uart_xmit_advance(&uap->port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
@@ -627,8 +626,7 @@ static void pmz_start_tx(struct uart_port *port)
return;
write_zsdata(uap, xmit->buf[xmit->tail]);
zssync(uap);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 2d25231fad84..444fa4b654ac 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -174,35 +174,12 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
static void transmit_chars(struct uart_pxa_port *up)
{
- struct circ_buf *xmit = &up->port.state->xmit;
- int count;
+ u8 ch;
- 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);
-
-
- if (uart_circ_empty(xmit))
- serial_pxa_stop_tx(&up->port);
+ uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2,
+ true,
+ serial_out(up, UART_TX, ch),
+ ({}));
}
static void serial_pxa_start_tx(struct uart_port *port)
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 83b66b73303a..b487823f0e61 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -924,6 +924,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
false, true, true);
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
geni_se_select_mode(&port->se, GENI_SE_FIFO);
+ qcom_geni_serial_start_rx(uport);
port->setup = true;
return 0;
@@ -1547,9 +1548,43 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
return ret;
}
+static int qcom_geni_serial_sys_hib_resume(struct device *dev)
+{
+ int ret = 0;
+ struct uart_port *uport;
+ struct qcom_geni_private_data *private_data;
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+
+ uport = &port->uport;
+ private_data = uport->private_data;
+
+ if (uart_console(uport)) {
+ geni_icc_set_tag(&port->se, 0x7);
+ geni_icc_set_bw(&port->se);
+ ret = uart_resume_port(private_data->drv, uport);
+ /*
+ * For hibernation usecase clients for
+ * console UART won't call port setup during restore,
+ * hence call port setup for console uart.
+ */
+ qcom_geni_serial_port_setup(uport);
+ } else {
+ /*
+ * Peripheral register settings are lost during hibernation.
+ * Update setup flag such that port setup happens again
+ * during next session. Clients of HS-UART will close and
+ * open the port during hibernation.
+ */
+ port->setup = false;
+ }
+ return ret;
+}
+
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
qcom_geni_serial_sys_resume)
+ .restore = qcom_geni_serial_sys_hib_resume,
+ .thaw = qcom_geni_serial_sys_hib_resume,
};
static const struct of_device_id qcom_geni_serial_match_table[] = {
diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c
index 0e387e2144fa..be5c842b5ba9 100644
--- a/drivers/tty/serial/rda-uart.c
+++ b/drivers/tty/serial/rda-uart.c
@@ -353,8 +353,7 @@ static void rda_uart_send_chars(struct uart_port *port)
ch = xmit->buf[xmit->tail];
rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index b81afb06f1f4..749b873a5d99 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -427,32 +427,13 @@ static void rp2_rx_chars(struct rp2_uart_port *up)
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;
+ u8 ch;
- 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);
+ uart_port_tx_limited(&up->port, ch,
+ FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT),
+ true,
+ writeb(ch, up->base + RP2_DATA_BYTE),
+ ({}));
}
static void rp2_ch_interrupt(struct rp2_uart_port *up)
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index dd9e3253cab4..55107bbc00ce 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -228,14 +228,7 @@ sa1100_rx_chars(struct sa1100_port *sport)
static void sa1100_tx_chars(struct sa1100_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
-
- if (sport->port.x_char) {
- UART_PUT_CHAR(sport, sport->port.x_char);
- sport->port.icount.tx++;
- sport->port.x_char = 0;
- return;
- }
+ u8 ch;
/*
* Check the modem control lines before
@@ -243,28 +236,9 @@ static void sa1100_tx_chars(struct sa1100_port *sport)
*/
sa1100_mctrl_check(sport);
- if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- sa1100_stop_tx(&sport->port);
- return;
- }
-
- /*
- * Tried using FIFO (not checking TNF) for fifo fill:
- * still had the '4 bytes repeated' problem.
- */
- while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
- UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&sport->port);
-
- if (uart_circ_empty(xmit))
- sa1100_stop_tx(&sport->port);
+ uart_port_tx(&sport->port, ch,
+ UART_GET_UTSR1(sport) & UTSR1_TNF,
+ UART_PUT_CHAR(sport, ch));
}
static irqreturn_t sa1100_int(int irq, void *dev_id)
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 9c252c9ca95a..0fce856434da 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -288,7 +288,6 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct s3c24xx_uart_dma *dma = ourport->dma;
- struct circ_buf *xmit = &port->state->xmit;
struct dma_tx_state state;
int count;
@@ -316,8 +315,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
DMA_TO_DEVICE);
async_tx_ack(dma->tx_desc);
count = dma->tx_bytes_requested - state.residue;
- xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
- port->icount.tx += count;
+ uart_xmit_advance(port, count);
}
ourport->tx_enabled = 0;
@@ -351,8 +349,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
spin_lock_irqsave(&port->lock, flags);
- xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
- port->icount.tx += count;
+ uart_xmit_advance(port, count);
ourport->tx_in_progress = 0;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -916,8 +913,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
break;
wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
count--;
}
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index c5d2b6cdcb4a..de56f383964e 100644
--- a/drivers/tty/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
@@ -399,8 +399,7 @@ static void sbd_transmit_chars(struct sbd_port *sport)
/* Send char. */
if (!stop_tx) {
write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- sport->port.icount.tx++;
+ uart_xmit_advance(&sport->port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 524921360ca7..39f92eb1e698 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -686,13 +686,10 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
}
to_send = (to_send > txlen) ? txlen : to_send;
- /* Add data to send */
- port->icount.tx += to_send;
-
/* Convert to linear buffer */
for (i = 0; i < to_send; ++i) {
s->buf[i] = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart_xmit_advance(port, 1);
}
sc16is7xx_fifo_write(port, to_send);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index dd98509f52e5..7df687822634 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -468,8 +468,7 @@ static void sccnxp_handle_tx(struct uart_port *port)
break;
sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index b7170cb9a544..e5b9773db5e3 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -496,8 +496,7 @@ static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes)
break;
}
tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- tup->uport.icount.tx++;
+ uart_xmit_advance(&tup->uport, 1);
}
}
@@ -619,8 +618,9 @@ static void tegra_uart_stop_tx(struct uart_port *u)
if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
return;
- dmaengine_terminate_all(tup->tx_dma_chan);
+ dmaengine_pause(tup->tx_dma_chan);
dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
+ dmaengine_terminate_all(tup->tx_dma_chan);
count = tup->tx_bytes_requested - state.residue;
async_tx_ack(tup->tx_dma_desc);
uart_xmit_advance(&tup->uport, count);
@@ -763,8 +763,9 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup)
return;
}
- dmaengine_terminate_all(tup->rx_dma_chan);
+ dmaengine_pause(tup->rx_dma_chan);
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+ dmaengine_terminate_all(tup->rx_dma_chan);
tegra_uart_rx_buffer_push(tup, state.residue);
tup->rx_dma_active = false;
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index e12f1dc18c38..eab387b01e36 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -321,34 +321,12 @@ receive_chars(struct uart_port *up, unsigned int *status)
static inline void transmit_chars(struct uart_port *up)
{
- struct circ_buf *xmit = &up->state->xmit;
- int count;
+ u8 ch;
- 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);
+ uart_port_tx_limited(up, ch, TXX9_SIO_TX_FIFO,
+ true,
+ sio_out(up, TXX9_SITFIFO, ch),
+ ({}));
}
static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 76452fe2af86..7bd080720929 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1181,10 +1181,7 @@ static void sci_dma_tx_complete(void *arg)
spin_lock_irqsave(&port->lock, flags);
- xmit->tail += s->tx_dma_len;
- xmit->tail &= UART_XMIT_SIZE - 1;
-
- port->icount.tx += s->tx_dma_len;
+ uart_xmit_advance(port, s->tx_dma_len);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 7fb6760b5c37..1f565a216e74 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -288,33 +288,12 @@ static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch)
*/
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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- sifive_serial_stop_tx(&ssp->port);
+ uart_port_tx_limited(&ssp->port, ch, SIFIVE_TX_FIFO_DEPTH,
+ true,
+ __ssp_transmit_char(ssp, ch),
+ ({}));
}
/**
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 342a87967631..492a3bdab5ba 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -206,7 +206,6 @@ static void sprd_stop_tx_dma(struct uart_port *port)
{
struct sprd_uart_port *sp =
container_of(port, struct sprd_uart_port, port);
- struct circ_buf *xmit = &port->state->xmit;
struct dma_tx_state state;
u32 trans_len;
@@ -215,8 +214,7 @@ static void sprd_stop_tx_dma(struct uart_port *port)
dmaengine_tx_status(sp->tx_dma.chn, sp->tx_dma.cookie, &state);
if (state.residue) {
trans_len = state.residue - sp->tx_dma.phys_addr;
- xmit->tail = (xmit->tail + trans_len) & (UART_XMIT_SIZE - 1);
- port->icount.tx += trans_len;
+ uart_xmit_advance(port, trans_len);
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
sp->tx_dma.trans_len, DMA_TO_DEVICE);
}
@@ -253,8 +251,7 @@ static void sprd_complete_tx_dma(void *data)
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
sp->tx_dma.trans_len, DMA_TO_DEVICE);
- xmit->tail = (xmit->tail + sp->tx_dma.trans_len) & (UART_XMIT_SIZE - 1);
- port->icount.tx += sp->tx_dma.trans_len;
+ uart_xmit_advance(port, sp->tx_dma.trans_len);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -626,35 +623,12 @@ static inline void sprd_rx(struct uart_port *port)
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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- sprd_stop_tx(port);
+ uart_port_tx_limited(port, ch, THLD_TX_EMPTY,
+ true,
+ serial_out(port, SPRD_TXD, ch),
+ ({}));
}
/* this handles the interrupt from one port */
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index fcecea689a0d..5215e6910f68 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -237,50 +237,12 @@ 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);
+ u8 ch;
- if (uart_circ_empty(xmit))
- asc_disable_tx_interrupts(port);
+ uart_port_tx_limited(port, ch, asc_hw_txroom(port),
+ true,
+ asc_out(port, ASC_TXBUF, ch),
+ ({}));
}
static void asc_receive_chars(struct uart_port *port)
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index dfdbcf092fac..a1490033aa16 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -596,8 +596,7 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
break;
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
/* rely on TXE irq (mask or unmask) for sending remaining data */
@@ -673,8 +672,8 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
- xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
- port->icount.tx += count;
+ uart_xmit_advance(port, count);
+
return;
fallback_err:
@@ -1681,22 +1680,10 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
if (!stm32port->info)
return -EINVAL;
- ret = stm32_usart_init_port(stm32port, pdev);
- if (ret)
- return ret;
-
- if (stm32port->wakeup_src) {
- device_set_wakeup_capable(&pdev->dev, true);
- ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq);
- if (ret)
- goto err_deinit_port;
- }
-
stm32port->rx_ch = dma_request_chan(&pdev->dev, "rx");
- if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto err_wakeirq;
- }
+ if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
/* Fall back in interrupt mode for any non-deferral error */
if (IS_ERR(stm32port->rx_ch))
stm32port->rx_ch = NULL;
@@ -1710,6 +1697,17 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
if (IS_ERR(stm32port->tx_ch))
stm32port->tx_ch = NULL;
+ ret = stm32_usart_init_port(stm32port, pdev);
+ if (ret)
+ goto err_dma_tx;
+
+ if (stm32port->wakeup_src) {
+ device_set_wakeup_capable(&pdev->dev, true);
+ ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq);
+ if (ret)
+ goto err_deinit_port;
+ }
+
if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) {
/* Fall back in interrupt mode */
dma_release_channel(stm32port->rx_ch);
@@ -1746,19 +1744,11 @@ err_port:
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
- if (stm32port->tx_ch) {
+ if (stm32port->tx_ch)
stm32_usart_of_dma_tx_remove(stm32port, pdev);
- dma_release_channel(stm32port->tx_ch);
- }
-
if (stm32port->rx_ch)
stm32_usart_of_dma_rx_remove(stm32port, pdev);
-err_dma_rx:
- if (stm32port->rx_ch)
- dma_release_channel(stm32port->rx_ch);
-
-err_wakeirq:
if (stm32port->wakeup_src)
dev_pm_clear_wake_irq(&pdev->dev);
@@ -1768,6 +1758,14 @@ err_deinit_port:
stm32_usart_deinit_port(stm32port);
+err_dma_tx:
+ if (stm32port->tx_ch)
+ dma_release_channel(stm32port->tx_ch);
+
+err_dma_rx:
+ if (stm32port->rx_ch)
+ dma_release_channel(stm32port->rx_ch);
+
return ret;
}
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 1938ba5e98c0..16c746a63258 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -47,8 +47,7 @@ static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit
if (status != HV_EOK)
break;
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
}
@@ -63,8 +62,7 @@ static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
status = sun4v_con_write(ra, len, &sent);
if (status != HV_EOK)
break;
- xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
- port->icount.tx += sent;
+ uart_xmit_advance(port, sent);
}
}
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
index 7afe61a0e72e..727942c43c45 100644
--- a/drivers/tty/serial/sunplus-uart.c
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -216,9 +216,7 @@ static void transmit_chars(struct uart_port *port)
do {
sp_uart_put_char(port, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
- port->icount.tx++;
-
+ uart_xmit_advance(port, 1);
if (uart_circ_empty(xmit))
break;
} while (sunplus_tx_buf_not_full(port));
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 99608b2a2b74..48b39fdb0397 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -266,8 +266,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
for (i = 0; i < up->port.fifosize; i++) {
writeb(xmit->buf[xmit->tail],
&up->regs->w.xfifo[i]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
if (uart_circ_empty(xmit))
break;
}
@@ -453,8 +452,7 @@ static void sunsab_start_tx(struct uart_port *port)
for (i = 0; i < up->port.fifosize; i++) {
writeb(xmit->buf[xmit->tail],
&up->regs->w.xfifo[i]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
if (uart_circ_empty(xmit))
break;
}
@@ -1133,7 +1131,13 @@ static int __init sunsab_init(void)
}
}
- return platform_driver_register(&sab_driver);
+ err = platform_driver_register(&sab_driver);
+ if (err) {
+ kfree(sunsab_ports);
+ sunsab_ports = NULL;
+ }
+
+ return err;
}
static void __exit sunsab_exit(void)
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 9ea7e567540d..fed052a0b931 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -417,8 +417,7 @@ static void transmit_chars(struct uart_sunsu_port *up)
count = up->port.fifosize;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 87425290687d..ccb809216e94 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -508,8 +508,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
ZSDELAY();
ZS_WSYNC(channel);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- up->port.icount.tx++;
+ uart_xmit_advance(&up->port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
@@ -709,8 +708,7 @@ static void sunzilog_start_tx(struct uart_port *port)
ZSDELAY();
ZS_WSYNC(channel);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index bb19ed012def..0859394a78cd 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -101,8 +101,7 @@ static void timbuart_tx_chars(struct uart_port *port)
!uart_circ_empty(xmit)) {
iowrite8(xmit->buf[xmit->tail],
port->membase + TIMBUART_TXFIFO);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
}
dev_dbg(port->dev,
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index eca41ac5477c..94584e54ebbe 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -203,8 +203,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
return 0;
uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
/* wake up */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 82cf14dd3d43..b09b6496ee3e 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -372,8 +372,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port);
while (count < qe_port->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uart_xmit_advance(port, 1);
count++;
if (xmit->head == xmit->tail)
break;
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 10fbdb09965f..cc9157df732f 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -168,7 +168,7 @@ static void handle_rx(struct uart_port *port)
c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
- /* Mask conditions we're ignorning. */
+ /* Mask conditions we're ignoring. */
c &= ~port->read_status_mask;
if (c & FER) {
@@ -196,33 +196,11 @@ static unsigned int vt8500_tx_empty(struct uart_port *port)
static void handle_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ u8 ch;
- if (port->x_char) {
- writeb(port->x_char, port->membase + VT8500_TXFIFO);
- port->icount.tx++;
- port->x_char = 0;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- vt8500_stop_tx(port);
- return;
- }
-
- while (vt8500_tx_empty(port)) {
- if (uart_circ_empty(xmit))
- break;
-
- writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
-
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- if (uart_circ_empty(xmit))
- vt8500_stop_tx(port);
+ uart_port_tx(port, ch,
+ vt8500_tx_empty(port),
+ writeb(ch, port->membase + VT8500_TXFIFO));
}
static void vt8500_start_tx(struct uart_port *port)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 0cbd1892c53b..8e521c69a959 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -326,9 +326,7 @@ static void cdns_uart_handle_tx(void *dev_id)
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
writel(xmit->buf[xmit->tail], port->membase + CDNS_UART_FIFO);
-
- port->icount.tx++;
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart_xmit_advance(port, 1);
numbytes--;
}
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 688db7d8b748..730c648e32ff 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -623,8 +623,7 @@ static void zs_raw_transmit_chars(struct zs_port *zport)
/* Send char. */
write_zsdata(zport, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- zport->port.icount.tx++;
+ uart_xmit_advance(&zport->port, 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&zport->port);