Commit d11cc8c3 authored by Jiri Slaby (SUSE)'s avatar Jiri Slaby (SUSE) Committed by Greg Kroah-Hartman

tty: serial: use uart_port_tx_limited()

uart_port_tx_limited() is a new helper to send characters to the device.
Use it in these drivers.

mux.c also needs to define tx_done(). But I'm not sure if the driver
really wants to wait for all the characters to dismiss from the HW fifo
at this code point. Hence I marked this as FIXME.

Cc: Russell King <linux@armlinux.org.uk>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: bcm-kernel-feedback-list@broadcom.com
Cc: "Pali Rohár" <pali@kernel.org>
Cc: Kevin Cernekee <cernekee@gmail.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Orson Zhai <orsonzhai@gmail.com>
Cc: Baolin Wang <baolin.wang7@gmail.com>
Cc: Chunyan Zhang <zhang.lyra@gmail.com>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: linux-riscv@lists.infradead.org
Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarJiri Slaby (SUSE) <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20221004104927.14361-4-jirislaby@kernel.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2d141e68
...@@ -154,35 +154,13 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) ...@@ -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) static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
{ {
struct uart_port *port = dev_id; struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->state->xmit; u8 ch;
int count = 256;
if (port->x_char) {
*CSR_UARTDR = port->x_char;
port->icount.tx++;
port->x_char = 0;
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
serial21285_stop_tx(port);
goto out;
}
do {
*CSR_UARTDR = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0 && !(*CSR_UARTFLG & 0x20));
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch, 256,
serial21285_stop_tx(port); !(*CSR_UARTFLG & 0x20),
*CSR_UARTDR = ch,
({}));
out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -146,37 +146,15 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) ...@@ -146,37 +146,15 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
{ {
struct uart_port *port = &pp->port; struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit; unsigned int count;
unsigned int pending, count; u8 ch;
if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}
pending = uart_circ_chars_pending(xmit); count = altera_jtaguart_tx_space(port, NULL);
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);
}
}
if (pending == 0) uart_port_tx_limited(port, ch, count,
altera_jtaguart_stop_tx(port); true,
writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG),
({}));
} }
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
......
...@@ -164,34 +164,12 @@ static void pl010_rx_chars(struct uart_port *port) ...@@ -164,34 +164,12 @@ static void pl010_rx_chars(struct uart_port *port)
static void pl010_tx_chars(struct uart_port *port) static void pl010_tx_chars(struct uart_port *port)
{ {
struct circ_buf *xmit = &port->state->xmit; u8 ch;
int count;
if (port->x_char) { uart_port_tx_limited(port, ch, port->fifosize >> 1,
writel(port->x_char, port->membase + UART01x_DR); true,
port->icount.tx++; writel(ch, port->membase + UART01x_DR),
port->x_char = 0; ({}));
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
pl010_stop_tx(port);
return;
}
count = port->fifosize >> 1;
do {
writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
pl010_stop_tx(port);
} }
static void pl010_modem_status(struct uart_amba_port *uap) static void pl010_modem_status(struct uart_amba_port *uap)
......
...@@ -122,36 +122,12 @@ static void apbuart_rx_chars(struct uart_port *port) ...@@ -122,36 +122,12 @@ static void apbuart_rx_chars(struct uart_port *port)
static void apbuart_tx_chars(struct uart_port *port) static void apbuart_tx_chars(struct uart_port *port)
{ {
struct circ_buf *xmit = &port->state->xmit; u8 ch;
int count;
if (port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
apbuart_stop_tx(port);
return;
}
/* amba: fill FIFO */
count = port->fifosize >> 1;
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch, port->fifosize >> 1,
apbuart_stop_tx(port); true,
UART_PUT_CHAR(port, ch),
({}));
} }
static irqreturn_t apbuart_int(int irq, void *dev_id) static irqreturn_t apbuart_int(int irq, void *dev_id)
......
...@@ -303,53 +303,24 @@ static void bcm_uart_do_rx(struct uart_port *port) ...@@ -303,53 +303,24 @@ static void bcm_uart_do_rx(struct uart_port *port)
*/ */
static void bcm_uart_do_tx(struct uart_port *port) static void bcm_uart_do_tx(struct uart_port *port)
{ {
struct circ_buf *xmit; unsigned int val;
unsigned int val, max_count; bool pending;
u8 ch;
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;
val = bcm_uart_readl(port, UART_MCTL_REG); val = bcm_uart_readl(port, UART_MCTL_REG);
val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; 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]; pending = uart_port_tx_limited(port, ch, port->fifosize - val,
bcm_uart_writel(port, c, UART_FIFO_REG); true,
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); bcm_uart_writel(port, ch, UART_FIFO_REG),
port->icount.tx++; ({}));
if (uart_circ_empty(xmit)) if (pending)
break; return;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
goto txq_empty;
return;
txq_empty:
/* nothing to send, disable transmit interrupt */ /* nothing to send, disable transmit interrupt */
val = bcm_uart_readl(port, UART_IR_REG); val = bcm_uart_readl(port, UART_IR_REG);
val &= ~UART_TX_INT_MASK; val &= ~UART_TX_INT_MASK;
bcm_uart_writel(port, val, UART_IR_REG); bcm_uart_writel(port, val, UART_IR_REG);
return;
} }
/* /*
......
...@@ -171,6 +171,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state) ...@@ -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. * mux_write - Write chars to the mux fifo.
* @port: Ptr to the uart_port. * @port: Ptr to the uart_port.
...@@ -180,39 +187,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state) ...@@ -180,39 +187,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state)
*/ */
static void mux_write(struct uart_port *port) static void mux_write(struct uart_port *port)
{ {
int count; u8 ch;
struct circ_buf *xmit = &port->state->xmit;
if(port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mux_stop_tx(port);
return;
}
count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if(uart_circ_empty(xmit))
break;
} while(--count > 0);
while(UART_GET_FIFO_CNT(port))
udelay(1);
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch,
mux_stop_tx(port); port->fifosize - UART_GET_FIFO_CNT(port),
true,
UART_PUT_CHAR(port, ch),
mux_tx_done(port));
} }
/** /**
......
...@@ -335,40 +335,12 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) ...@@ -335,40 +335,12 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status) static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
{ {
struct circ_buf *xmit = &port->state->xmit; u8 ch;
unsigned int count;
unsigned int st;
if (port->x_char) {
writel(port->x_char, port->membase + UART_TSH(port));
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mvebu_uart_stop_tx(port);
return;
}
for (count = 0; count < port->fifosize; count++) {
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
st = readl(port->membase + UART_STAT);
if (st & STAT_TX_FIFO_FUL)
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch, port->fifosize,
mvebu_uart_stop_tx(port); !(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) static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
......
...@@ -347,34 +347,12 @@ static void serial_omap_put_char(struct uart_omap_port *up, unsigned char ch) ...@@ -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) static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
{ {
struct circ_buf *xmit = &up->port.state->xmit; u8 ch;
int count;
if (up->port.x_char) { uart_port_tx_limited(&up->port, ch, up->port.fifosize / 4,
serial_omap_put_char(up, up->port.x_char); true,
up->port.icount.tx++; serial_omap_put_char(up, ch),
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);
} }
static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
......
...@@ -174,35 +174,12 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) ...@@ -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) static void transmit_chars(struct uart_pxa_port *up)
{ {
struct circ_buf *xmit = &up->port.state->xmit; u8 ch;
int count;
if (up->port.x_char) { uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2,
serial_out(up, UART_TX, up->port.x_char); true,
up->port.icount.tx++; serial_out(up, UART_TX, ch),
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);
} }
static void serial_pxa_start_tx(struct uart_port *port) static void serial_pxa_start_tx(struct uart_port *port)
......
...@@ -427,32 +427,13 @@ static void rp2_rx_chars(struct rp2_uart_port *up) ...@@ -427,32 +427,13 @@ static void rp2_rx_chars(struct rp2_uart_port *up)
static void rp2_tx_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); u8 ch;
struct circ_buf *xmit = &up->port.state->xmit;
if (uart_tx_stopped(&up->port)) { uart_port_tx_limited(&up->port, ch,
rp2_uart_stop_tx(&up->port); FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT),
return; true,
} writeb(ch, up->base + RP2_DATA_BYTE),
({}));
for (; max_tx != 0; max_tx--) {
if (up->port.x_char) {
writeb(up->port.x_char, up->base + RP2_DATA_BYTE);
up->port.x_char = 0;
up->port.icount.tx++;
continue;
}
if (uart_circ_empty(xmit)) {
rp2_uart_stop_tx(&up->port);
break;
}
writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
up->port.icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
} }
static void rp2_ch_interrupt(struct rp2_uart_port *up) static void rp2_ch_interrupt(struct rp2_uart_port *up)
......
...@@ -321,34 +321,12 @@ receive_chars(struct uart_port *up, unsigned int *status) ...@@ -321,34 +321,12 @@ receive_chars(struct uart_port *up, unsigned int *status)
static inline void transmit_chars(struct uart_port *up) static inline void transmit_chars(struct uart_port *up)
{ {
struct circ_buf *xmit = &up->state->xmit; u8 ch;
int count;
if (up->x_char) { uart_port_tx_limited(up, ch, TXX9_SIO_TX_FIFO,
sio_out(up, TXX9_SITFIFO, up->x_char); true,
up->icount.tx++; sio_out(up, TXX9_SITFIFO, ch),
up->x_char = 0; ({}));
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(up)) {
serial_txx9_stop_tx(up);
return;
}
count = TXX9_SIO_TX_FIFO;
do {
sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
up->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(up);
if (uart_circ_empty(xmit))
serial_txx9_stop_tx(up);
} }
static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
......
...@@ -288,33 +288,12 @@ static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch) ...@@ -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) static void __ssp_transmit_chars(struct sifive_serial_port *ssp)
{ {
struct circ_buf *xmit = &ssp->port.state->xmit; u8 ch;
int count;
if (ssp->port.x_char) {
__ssp_transmit_char(ssp, ssp->port.x_char);
ssp->port.icount.tx++;
ssp->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&ssp->port)) {
sifive_serial_stop_tx(&ssp->port);
return;
}
count = SIFIVE_TX_FIFO_DEPTH;
do {
__ssp_transmit_char(ssp, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
ssp->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&ssp->port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(&ssp->port, ch, SIFIVE_TX_FIFO_DEPTH,
sifive_serial_stop_tx(&ssp->port); true,
__ssp_transmit_char(ssp, ch),
({}));
} }
/** /**
......
...@@ -626,35 +626,12 @@ static inline void sprd_rx(struct uart_port *port) ...@@ -626,35 +626,12 @@ static inline void sprd_rx(struct uart_port *port)
static inline void sprd_tx(struct uart_port *port) static inline void sprd_tx(struct uart_port *port)
{ {
struct circ_buf *xmit = &port->state->xmit; u8 ch;
int count;
if (port->x_char) {
serial_out(port, SPRD_TXD, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
sprd_stop_tx(port);
return;
}
count = THLD_TX_EMPTY;
do {
serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch, THLD_TX_EMPTY,
sprd_stop_tx(port); true,
serial_out(port, SPRD_TXD, ch),
({}));
} }
/* this handles the interrupt from one port */ /* this handles the interrupt from one port */
......
...@@ -237,50 +237,12 @@ static inline unsigned asc_hw_txroom(struct uart_port *port) ...@@ -237,50 +237,12 @@ static inline unsigned asc_hw_txroom(struct uart_port *port)
*/ */
static void asc_transmit_chars(struct uart_port *port) static void asc_transmit_chars(struct uart_port *port)
{ {
struct circ_buf *xmit = &port->state->xmit; u8 ch;
int txroom;
unsigned char c;
txroom = asc_hw_txroom(port);
if ((txroom != 0) && port->x_char) {
c = port->x_char;
port->x_char = 0;
asc_out(port, ASC_TXBUF, c);
port->icount.tx++;
txroom = asc_hw_txroom(port);
}
if (uart_tx_stopped(port)) {
/*
* We should try and stop the hardware here, but I
* don't think the ASC has any way to do that.
*/
asc_disable_tx_interrupts(port);
return;
}
if (uart_circ_empty(xmit)) {
asc_disable_tx_interrupts(port);
return;
}
if (txroom == 0)
return;
do {
c = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
asc_out(port, ASC_TXBUF, c);
port->icount.tx++;
txroom--;
} while ((txroom > 0) && (!uart_circ_empty(xmit)));
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) uart_port_tx_limited(port, ch, asc_hw_txroom(port),
asc_disable_tx_interrupts(port); true,
asc_out(port, ASC_TXBUF, ch),
({}));
} }
static void asc_receive_chars(struct uart_port *port) static void asc_receive_chars(struct uart_port *port)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment