aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/serial/atmel_serial.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 03:31:56 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-16 03:31:56 -0800
commitdd6f9b17cd7af68b6a5090deedf1f5e84f66f4e6 (patch)
treea03ca96cddd4520555981e51d8e6072f2d48c416 /drivers/tty/serial/atmel_serial.c
parentb83a7080d30032cf70832bc2bb04cc342e203b88 (diff)
parent6373ab4dfee731deec62b4452ea641611feff9b3 (diff)
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/atmel_serial.c')
-rw-r--r--drivers/tty/serial/atmel_serial.c80
1 files changed, 32 insertions, 48 deletions
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 */