Commit 1788cf6a authored by Jiri Slaby (SUSE)'s avatar Jiri Slaby (SUSE) Committed by Greg Kroah-Hartman
Browse files

tty: serial: switch from circ_buf to kfifo



Switch from struct circ_buf to proper kfifo. kfifo provides much better
API, esp. when wrap-around of the buffer needs to be taken into account.
Look at pl011_dma_tx_refill() or cpm_uart_tx_pump() changes for example.

Kfifo API can also fill in scatter-gather DMA structures, so it easier
for that use case too. Look at lpuart_dma_tx() for example. Note that
not all drivers can be converted to that (like atmel_serial), they
handle DMA specially.

Note that usb-serial uses kfifo for TX for ages.

omap needed a bit more care as it needs to put a char into FIFO to start
the DMA transfer when OMAP_DMA_TX_KICK is set. In that case, we have to
do kfifo_dma_out_prepare twice: once to find out the tx_size (to find
out if it is worths to do DMA at all -- size >= 4), the second time for
the actual transfer.

All traces of circ_buf are removed from serial_core.h (and its struct
uart_state).

Signed-off-by: default avatarJiri Slaby (SUSE) <jirislaby@kernel.org>
Cc: Al Cooper <alcooperx@gmail.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Cc: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
Cc: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Vineet Gupta <vgupta@kernel.org>
Cc: Richard Genoud <richard.genoud@gmail.com>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Cc: Alexander Shiyan <shc_work@mail.ru>
Cc: Baruch Siach <baruch@tkos.co.il>
Cc: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Neil Armstrong <neil.armstrong@linaro.org>
Cc: Kevin Hilman <khilman@baylibre.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Taichi Sugaya <sugaya.taichi@socionext.com>
Cc: Takao Orito <orito.takao@socionext.com>
Cc: Bjorn Andersson <andersson@kernel.org>
Cc: Konrad Dybcio <konrad.dybcio@linaro.org>
Cc: Pali Rohár <pali@kernel.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Aneesh Kumar K.V <aneesh.kumar@kernel.org>
Cc: Naveen N. Rao <naveen.n.rao@linux.ibm.com>
Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Cc: Alim Akhtar <alim.akhtar@samsung.com>
Cc: Laxman Dewangan <ldewangan@nvidia.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Jonathan Hunter <jonathanh@nvidia.com>
Cc: Orson Zhai <orsonzhai@gmail.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Chunyan Zhang <zhang.lyra@gmail.com>
Cc: Patrice Chotard <patrice.chotard@foss.st.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Hammer Hsieh <hammerh0314@gmail.com>
Cc: Peter Korsgaard <jacmet@sunsite.dk>
Cc: Timur Tabi <timur@kernel.org>
Cc: Michal Simek <michal.simek@amd.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Christian König <christian.koenig@amd.com>
Link: https://lore.kernel.org/r/20240405060826.2521-13-jirislaby@kernel.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f8fef2fa
Loading
Loading
Loading
Loading
+6 −8
Original line number Diff line number Diff line
@@ -413,20 +413,18 @@ static int stop_tx_dma(struct uart_8250_port *p)
static int brcmuart_tx_dma(struct uart_8250_port *p)
{
	struct brcmuart_priv *priv = p->port.private_data;
	struct circ_buf *xmit = &p->port.state->xmit;
	struct tty_port *tport = &p->port.state->port;
	u32 tx_size;

	if (uart_tx_stopped(&p->port) || priv->tx_running ||
		uart_circ_empty(xmit)) {
		kfifo_is_empty(&tport->xmit_fifo)) {
		return 0;
	}
	tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	priv->dma.tx_err = 0;
	memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size);
	uart_xmit_advance(&p->port, tx_size);
	tx_size = uart_fifo_out(&p->port, priv->tx_buf, UART_XMIT_SIZE);

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
		uart_write_wakeup(&p->port);

	udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size);
@@ -540,7 +538,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
	struct brcmuart_priv *priv = up->private_data;
	struct device *dev = up->dev;
	struct uart_8250_port *port_8250 = up_to_u8250p(up);
	struct circ_buf	*xmit = &port_8250->port.state->xmit;
	struct tty_port *tport = &port_8250->port.state->port;

	if (isr & UDMA_INTR_TX_ABORT) {
		if (priv->tx_running)
@@ -548,7 +546,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
		return;
	}
	priv->tx_running = false;
	if (!uart_circ_empty(xmit) && !uart_tx_stopped(up))
	if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up))
		brcmuart_tx_dma(port_8250);
}

+2 −1
Original line number Diff line number Diff line
@@ -280,7 +280,8 @@ static void serial8250_backup_timeout(struct timer_list *t)
	 */
	lsr = serial_lsr_in(up);
	if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
	    (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
	    (!kfifo_is_empty(&up->port.state->port.xmit_fifo) ||
	     up->port.x_char) &&
	    (lsr & UART_LSR_THRE)) {
		iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
		iir |= UART_IIR_THRI;
+14 −9
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ static void __dma_tx_complete(void *param)
{
	struct uart_8250_port	*p = param;
	struct uart_8250_dma	*dma = p->dma;
	struct circ_buf		*xmit = &p->port.state->xmit;
	struct tty_port		*tport = &p->port.state->port;
	unsigned long	flags;
	int		ret;

@@ -28,7 +28,7 @@ static void __dma_tx_complete(void *param)

	uart_xmit_advance(&p->port, dma->tx_size);

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
		uart_write_wakeup(&p->port);

	ret = serial8250_tx_dma(p);
@@ -86,7 +86,7 @@ static void dma_rx_complete(void *param)
int serial8250_tx_dma(struct uart_8250_port *p)
{
	struct uart_8250_dma		*dma = p->dma;
	struct circ_buf			*xmit = &p->port.state->xmit;
	struct tty_port			*tport = &p->port.state->port;
	struct dma_async_tx_descriptor	*desc;
	struct uart_port		*up = &p->port;
	struct scatterlist sg;
@@ -103,18 +103,23 @@ int serial8250_tx_dma(struct uart_8250_port *p)
		uart_xchar_out(up, UART_TX);
	}

	if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
	if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
		/* We have been called from __dma_tx_complete() */
		return 0;
	}

	dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	serial8250_do_prepare_tx_dma(p);

	sg_init_table(&sg, 1);
	sg_dma_address(&sg) = dma->tx_addr + xmit->tail;
	sg_dma_len(&sg) = dma->tx_size;
	/* kfifo can do more than one sg, we don't (quite yet) */
	ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
					   UART_XMIT_SIZE, dma->tx_addr);

	/* we already checked empty fifo above, so there should be something */
	if (WARN_ON_ONCE(ret != 1))
		return 0;

	dma->tx_size = sg_dma_len(&sg);

	desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1,
				       DMA_MEM_TO_DEV,
@@ -257,7 +262,7 @@ int serial8250_request_dma(struct uart_8250_port *p)

	/* TX buffer */
	dma->tx_addr = dma_map_single(dma->txchan->device->dev,
					p->port.state->xmit.buf,
					p->port.state->port.xmit_buf,
					UART_XMIT_SIZE,
					DMA_TO_DEVICE);
	if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
+3 −2
Original line number Diff line number Diff line
@@ -214,7 +214,7 @@ static void exar_shutdown(struct uart_port *port)
{
	bool tx_complete = false;
	struct uart_8250_port *up = up_to_u8250p(port);
	struct circ_buf *xmit = &port->state->xmit;
	struct tty_port *tport = &port->state->port;
	int i = 0;
	u16 lsr;

@@ -225,7 +225,8 @@ static void exar_shutdown(struct uart_port *port)
		else
			tx_complete = false;
		usleep_range(1000, 1100);
	} while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000);
	} while (!kfifo_is_empty(&tport->xmit_fifo) &&
			!tx_complete && i++ < 1000);

	serial8250_do_shutdown(port);
}
+1 −1
Original line number Diff line number Diff line
@@ -199,7 +199,7 @@ static int mtk8250_startup(struct uart_port *port)

	if (up->dma) {
		data->rx_status = DMA_RX_START;
		uart_circ_clear(&port->state->xmit);
		kfifo_reset(&port->state->port.xmit_fifo);
	}
#endif
	memset(&port->icount, 0, sizeof(port->icount));
Loading