drivers/tty/serial/8250/8250_dma.c

Source file repositories/reference/linux-study-clean/drivers/tty/serial/8250/8250_dma.c

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_dma.c
Extension
.c
Size
8445 bytes
Lines
343
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (up->x_char) {
			dmaengine_pause(dma->txchan);
			uart_xchar_out(up, UART_TX);
			dmaengine_resume(dma->txchan);
		}
		return 0;
	} else if (up->x_char) {
		uart_xchar_out(up, UART_TX);
	}

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

	serial8250_do_prepare_tx_dma(p);

	sg_init_table(sgl, ARRAY_SIZE(sgl));

	ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, sgl, ARRAY_SIZE(sgl),
					   UART_XMIT_SIZE, dma->tx_addr);

	dma->tx_size = 0;

	for_each_sg(sgl, sg, ret, i)
		dma->tx_size += sg_dma_len(sg);

	desc = dmaengine_prep_slave_sg(dma->txchan, sgl, ret,
				       DMA_MEM_TO_DEV,
				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!desc) {
		ret = -EBUSY;
		goto err;
	}

	dma->tx_running = 1;
	desc->callback = __dma_tx_complete;
	desc->callback_param = p;

	dma->tx_cookie = dmaengine_submit(desc);

	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
				   UART_XMIT_SIZE, DMA_TO_DEVICE);

	dma_async_issue_pending(dma->txchan);
	serial8250_clear_THRI(p);
	dma->tx_err = 0;

	return 0;
err:
	dma->tx_err = 1;
	return ret;
}

void serial8250_tx_dma_flush(struct uart_8250_port *p)
{
	struct uart_8250_dma *dma = p->dma;

	if (!dma->tx_running)
		return;

	/*
	 * kfifo_reset() has been called by the serial core, avoid
	 * advancing and underflowing in __dma_tx_complete().
	 */
	dma->tx_size = 0;

	/*
	 * We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
	 * holding the uart port spinlock.
	 */
	dmaengine_terminate_async(dma->txchan);

	/*
	 * The callback might or might not run. If it doesn't run, we need to ensure
	 * that `tx_running` is cleared so that we can schedule new transactions.
	 * If it does run, then the zombie callback will clear `tx_running` again
	 * and perform a no-op since `tx_size` was cleared above.
	 *
	 * In either case, we ASSUME the DMA transaction will terminate before we
	 * issue a new `serial8250_tx_dma`.
	 */
	dma->tx_running = 0;
}

int serial8250_rx_dma(struct uart_8250_port *p)
{
	struct uart_8250_dma		*dma = p->dma;
	struct dma_async_tx_descriptor	*desc;

Annotation

Implementation Notes