Skip to content

Commit

Permalink
tty: serial: use DEFINE_UART_PORT_TX_HELPER_LIMITED()
Browse files Browse the repository at this point in the history
DEFINE_UART_PORT_TX_HELPER_LIMITED() is a new helper to send characters
to the device. Use it in these drivers.

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

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
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
  • Loading branch information
Jiri Slaby authored and intel-lab-lkp committed Sep 1, 2022
1 parent 393b592 commit f6f9918
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 470 deletions.
33 changes: 6 additions & 27 deletions drivers/tty/serial/21285.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,38 +151,17 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
return IRQ_HANDLED;
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(serial21285_do_tx_chars, port, ch,
!(*CSR_UARTFLG & 0x20),
*CSR_UARTDR = ch,
({}));

static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->state->xmit;
int count = 256;

if (port->x_char) {
*CSR_UARTDR = port->x_char;
port->icount.tx++;
port->x_char = 0;
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
serial21285_stop_tx(port);
goto out;
}

do {
*CSR_UARTDR = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0 && !(*CSR_UARTFLG & 0x20));

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
serial21285_stop_tx(port);
serial21285_do_tx_chars(port, 256);

out:
return IRQ_HANDLED;
}

Expand Down
42 changes: 10 additions & 32 deletions drivers/tty/serial/altera_jtaguart.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,42 +134,20 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
tty_flip_buffer_push(&port->state->port);
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(altera_jtaguart_do_tx_chars, port, ch,
true,
writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG),
({}));

static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
{
struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned int pending, count;

if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}

pending = uart_circ_chars_pending(xmit);
if (pending > 0) {
count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
if (count > pending)
count = pending;
if (count > 0) {
pending -= count;
while (count--) {
writel(xmit->buf[xmit->tail],
port->membase + ALTERA_JTAGUART_DATA_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (pending < WAKEUP_CHARS)
uart_write_wakeup(port);
}
}
unsigned int space;

if (pending == 0)
altera_jtaguart_stop_tx(port);
space = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
altera_jtaguart_do_tx_chars(port, space);
}

static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
Expand Down
37 changes: 5 additions & 32 deletions drivers/tty/serial/amba-pl010.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,37 +162,10 @@ static void pl010_rx_chars(struct uart_port *port)
tty_flip_buffer_push(&port->state->port);
}

static void pl010_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
int count;

if (port->x_char) {
writel(port->x_char, port->membase + UART01x_DR);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
pl010_stop_tx(port);
return;
}

count = port->fifosize >> 1;
do {
writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
pl010_stop_tx(port);
}
static DEFINE_UART_PORT_TX_HELPER_LIMITED(pl010_tx_chars, port, ch,
true,
writel(ch, port->membase + UART01x_DR),
({}));

static void pl010_modem_status(struct uart_amba_port *uap)
{
Expand Down Expand Up @@ -238,7 +211,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id)
if (status & UART010_IIR_MIS)
pl010_modem_status(uap);
if (status & UART010_IIR_TIS)
pl010_tx_chars(port);
pl010_tx_chars(port, port->fifosize >> 1);

if (pass_counter-- == 0)
break;
Expand Down
36 changes: 6 additions & 30 deletions drivers/tty/serial/apbuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,38 +120,14 @@ static void apbuart_rx_chars(struct uart_port *port)
tty_flip_buffer_push(&port->state->port);
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(apbuart_do_tx_chars, port, ch,
true,
UART_PUT_CHAR(port, ch),
({}));

static void apbuart_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
int count;

if (port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}

if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
apbuart_stop_tx(port);
return;
}

/* amba: fill FIFO */
count = port->fifosize >> 1;
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
apbuart_stop_tx(port);
apbuart_do_tx_chars(port, port->fifosize >> 1);
}

static irqreturn_t apbuart_int(int irq, void *dev_id)
Expand Down
47 changes: 9 additions & 38 deletions drivers/tty/serial/bcm63xx_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,59 +297,30 @@ static void bcm_uart_do_rx(struct uart_port *port)
tty_flip_buffer_push(tty_port);
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(bcm_uart_tx, port, ch,
true,
bcm_uart_writel(port, ch, UART_FIFO_REG),
({}));

/*
* fill tx fifo with chars to send, stop when fifo is about to be full
* or when all chars have been sent.
*/
static void bcm_uart_do_tx(struct uart_port *port)
{
struct circ_buf *xmit;
unsigned int val, max_count;

if (port->x_char) {
bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
port->icount.tx++;
port->x_char = 0;
return;
}

if (uart_tx_stopped(port)) {
bcm_uart_stop_tx(port);
return;
}

xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
goto txq_empty;
unsigned int val, pending;

val = bcm_uart_readl(port, UART_MCTL_REG);
val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
max_count = port->fifosize - val;

while (max_count--) {
unsigned int c;

c = xmit->buf[xmit->tail];
bcm_uart_writel(port, c, UART_FIFO_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
}

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
goto txq_empty;
return;
pending = bcm_uart_tx(port, port->fifosize - val);
if (pending)
return;

txq_empty:
/* nothing to send, disable transmit interrupt */
val = bcm_uart_readl(port, UART_IR_REG);
val &= ~UART_TX_INT_MASK;
bcm_uart_writel(port, val, UART_IR_REG);
return;
}

/*
Expand Down
46 changes: 13 additions & 33 deletions drivers/tty/serial/mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,18 @@ static void mux_break_ctl(struct uart_port *port, int break_state)
{
}

static void mux_tx_done(struct uart_port *port)
{
/* FIXME js: really needs to wait? */
while (UART_GET_FIFO_CNT(port))
udelay(1);
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(mux_transmit, port, ch,
true,
UART_PUT_CHAR(port, ch),
mux_tx_done(port));

/**
* mux_write - Write chars to the mux fifo.
* @port: Ptr to the uart_port.
Expand All @@ -180,39 +192,7 @@ static void mux_break_ctl(struct uart_port *port, int break_state)
*/
static void mux_write(struct uart_port *port)
{
int count;
struct circ_buf *xmit = &port->state->xmit;

if(port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}

if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mux_stop_tx(port);
return;
}

count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if(uart_circ_empty(xmit))
break;

} while(--count > 0);

while(UART_GET_FIFO_CNT(port))
udelay(1);

if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
mux_stop_tx(port);
mux_transmit(port, port->fifosize - UART_GET_FIFO_CNT(port));
}

/**
Expand Down
40 changes: 6 additions & 34 deletions drivers/tty/serial/mvebu-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,42 +333,14 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
tty_flip_buffer_push(tport);
}

static DEFINE_UART_PORT_TX_HELPER_LIMITED(mvebu_uart_do_tx_chars, port, ch,
!(readl(port->membase + UART_STAT) & STAT_TX_FIFO_FUL),
writel(ch, port->membase + UART_TSH(port)),
({}));

static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned int count;
unsigned int st;

if (port->x_char) {
writel(port->x_char, port->membase + UART_TSH(port));
port->icount.tx++;
port->x_char = 0;
return;
}

if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mvebu_uart_stop_tx(port);
return;
}

for (count = 0; count < port->fifosize; count++) {
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;

if (uart_circ_empty(xmit))
break;

st = readl(port->membase + UART_STAT);
if (st & STAT_TX_FIFO_FUL)
break;
}

if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);

if (uart_circ_empty(xmit))
mvebu_uart_stop_tx(port);
mvebu_uart_do_tx_chars(port, port->fifosize);
}

static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
Expand Down

0 comments on commit f6f9918

Please sign in to comment.