Commit 0b526090 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull serial driver fixes from Greg KH:
 "Here are some small serial driver fixes for 6.7-rc4 to resolve some
  reported issues. Included in here are:

   - pl011 dma support fix

   - sc16is7xx driver fix

   - ma35d1 console index fix

   - 8250 driver fixes for small issues

  All of these have been in linux-next with no reported issues"

* tag 'tty-6.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: 8250_dw: Add ACPI ID for Granite Rapids-D UART
  serial: ma35d1: Validate console index before assignment
  ARM: PL011: Fix DMA support
  serial: sc16is7xx: address RX timeout interrupt errata
  serial: 8250: 8250_omap: Clear UART_HAS_RHR_IT_DIS bit
  serial: 8250_omap: Add earlycon support for the AM654 UART controller
  serial: 8250: 8250_omap: Do not start RX DMA on THRI interrupt
parents ca20f162 e92fad02
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -777,6 +777,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
	{ "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
	{ "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
	{ "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
	{ "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb },
	{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
+1 −0
Original line number Diff line number Diff line
@@ -189,5 +189,6 @@ static int __init early_omap8250_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
OF_EARLYCON_DECLARE(omap8250, "ti,am654-uart", early_omap8250_setup);

#endif
+8 −6
Original line number Diff line number Diff line
@@ -933,7 +933,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
	if (priv->habit & UART_HAS_RHR_IT_DIS) {
		reg = serial_in(p, UART_OMAP_IER2);
		reg &= ~UART_OMAP_IER2_RHR_IT_DIS;
		serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS);
		serial_out(p, UART_OMAP_IER2, reg);
	}

	dmaengine_tx_status(rxchan, cookie, &state);
@@ -1079,7 +1079,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p)
	if (priv->habit & UART_HAS_RHR_IT_DIS) {
		reg = serial_in(p, UART_OMAP_IER2);
		reg |= UART_OMAP_IER2_RHR_IT_DIS;
		serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS);
		serial_out(p, UART_OMAP_IER2, reg);
	}

	dma_async_issue_pending(dma->rxchan);
@@ -1298,10 +1298,12 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)

	status = serial_port_in(port, UART_LSR);

	if ((iir & 0x3f) != UART_IIR_THRI) {
		if (priv->habit & UART_HAS_EFR2)
			am654_8250_handle_rx_dma(up, iir, status);
		else
			status = omap_8250_handle_rx_dma(up, iir, status);
	}

	serial8250_modem_status(up);
	if (status & UART_LSR_THRE && up->dma->tx_err) {
+54 −58
Original line number Diff line number Diff line
@@ -218,8 +218,9 @@ static struct vendor_data vendor_st = {

/* Deals with DMA transactions */

struct pl011_sgbuf {
	struct scatterlist sg;
struct pl011_dmabuf {
	dma_addr_t		dma;
	size_t			len;
	char			*buf;
};

@@ -227,8 +228,8 @@ struct pl011_dmarx_data {
	struct dma_chan		*chan;
	struct completion	complete;
	bool			use_buf_b;
	struct pl011_sgbuf	sgbuf_a;
	struct pl011_sgbuf	sgbuf_b;
	struct pl011_dmabuf	dbuf_a;
	struct pl011_dmabuf	dbuf_b;
	dma_cookie_t		cookie;
	bool			running;
	struct timer_list	timer;
@@ -241,7 +242,8 @@ struct pl011_dmarx_data {

struct pl011_dmatx_data {
	struct dma_chan		*chan;
	struct scatterlist	sg;
	dma_addr_t		dma;
	size_t			len;
	char			*buf;
	bool			queued;
};
@@ -366,32 +368,24 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)

#define PL011_DMA_BUFFER_SIZE PAGE_SIZE

static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
	enum dma_data_direction dir)
{
	dma_addr_t dma_addr;

	sg->buf = dma_alloc_coherent(chan->device->dev,
		PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);
	if (!sg->buf)
	db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
				     &db->dma, GFP_KERNEL);
	if (!db->buf)
		return -ENOMEM;

	sg_init_table(&sg->sg, 1);
	sg_set_page(&sg->sg, phys_to_page(dma_addr),
		PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
	sg_dma_address(&sg->sg) = dma_addr;
	sg_dma_len(&sg->sg) = PL011_DMA_BUFFER_SIZE;
	db->len = PL011_DMA_BUFFER_SIZE;

	return 0;
}

static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
	enum dma_data_direction dir)
{
	if (sg->buf) {
	if (db->buf) {
		dma_free_coherent(chan->device->dev,
			PL011_DMA_BUFFER_SIZE, sg->buf,
			sg_dma_address(&sg->sg));
				  PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
	}
}

@@ -552,8 +546,8 @@ static void pl011_dma_tx_callback(void *data)

	uart_port_lock_irqsave(&uap->port, &flags);
	if (uap->dmatx.queued)
		dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1,
			     DMA_TO_DEVICE);
		dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
				dmatx->len, DMA_TO_DEVICE);

	dmacr = uap->dmacr;
	uap->dmacr = dmacr & ~UART011_TXDMAE;
@@ -639,18 +633,19 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
			memcpy(&dmatx->buf[first], &xmit->buf[0], second);
	}

	dmatx->sg.length = count;

	if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) {
	dmatx->len = count;
	dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
				    DMA_TO_DEVICE);
	if (dmatx->dma == DMA_MAPPING_ERROR) {
		uap->dmatx.queued = false;
		dev_dbg(uap->port.dev, "unable to map TX DMA\n");
		return -EBUSY;
	}

	desc = dmaengine_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
	desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!desc) {
		dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
		dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
		uap->dmatx.queued = false;
		/*
		 * If DMA cannot be used right now, we complete this
@@ -813,8 +808,8 @@ __acquires(&uap->port.lock)
	dmaengine_terminate_async(uap->dmatx.chan);

	if (uap->dmatx.queued) {
		dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
			     DMA_TO_DEVICE);
		dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
				 uap->dmatx.len, DMA_TO_DEVICE);
		uap->dmatx.queued = false;
		uap->dmacr &= ~UART011_TXDMAE;
		pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -828,15 +823,15 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
	struct dma_chan *rxchan = uap->dmarx.chan;
	struct pl011_dmarx_data *dmarx = &uap->dmarx;
	struct dma_async_tx_descriptor *desc;
	struct pl011_sgbuf *sgbuf;
	struct pl011_dmabuf *dbuf;

	if (!rxchan)
		return -EIO;

	/* Start the RX DMA job */
	sgbuf = uap->dmarx.use_buf_b ?
		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
	desc = dmaengine_prep_slave_sg(rxchan, &sgbuf->sg, 1,
	dbuf = uap->dmarx.use_buf_b ?
		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
	desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
					DMA_DEV_TO_MEM,
					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	/*
@@ -876,8 +871,8 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
			       bool readfifo)
{
	struct tty_port *port = &uap->port.state->port;
	struct pl011_sgbuf *sgbuf = use_buf_b ?
		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
	struct pl011_dmabuf *dbuf = use_buf_b ?
		&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
	int dma_count = 0;
	u32 fifotaken = 0; /* only used for vdbg() */

@@ -886,7 +881,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,

	if (uap->dmarx.poll_rate) {
		/* The data can be taken by polling */
		dmataken = sgbuf->sg.length - dmarx->last_residue;
		dmataken = dbuf->len - dmarx->last_residue;
		/* Recalculate the pending size */
		if (pending >= dmataken)
			pending -= dmataken;
@@ -900,7 +895,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
		 * Note that tty_insert_flip_buf() tries to take as many chars
		 * as it can.
		 */
		dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
				pending);

		uap->port.icount.rx += dma_count;
@@ -911,7 +906,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,

	/* Reset the last_residue for Rx DMA poll */
	if (uap->dmarx.poll_rate)
		dmarx->last_residue = sgbuf->sg.length;
		dmarx->last_residue = dbuf->len;

	/*
	 * Only continue with trying to read the FIFO if all DMA chars have
@@ -946,8 +941,8 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
{
	struct pl011_dmarx_data *dmarx = &uap->dmarx;
	struct dma_chan *rxchan = dmarx->chan;
	struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
		&dmarx->sgbuf_b : &dmarx->sgbuf_a;
	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
		&dmarx->dbuf_b : &dmarx->dbuf_a;
	size_t pending;
	struct dma_tx_state state;
	enum dma_status dmastat;
@@ -969,7 +964,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
	pl011_write(uap->dmacr, uap, REG_DMACR);
	uap->dmarx.running = false;

	pending = sgbuf->sg.length - state.residue;
	pending = dbuf->len - state.residue;
	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
	/* Then we terminate the transfer - we now know our residue */
	dmaengine_terminate_all(rxchan);
@@ -996,8 +991,8 @@ static void pl011_dma_rx_callback(void *data)
	struct pl011_dmarx_data *dmarx = &uap->dmarx;
	struct dma_chan *rxchan = dmarx->chan;
	bool lastbuf = dmarx->use_buf_b;
	struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
		&dmarx->sgbuf_b : &dmarx->sgbuf_a;
	struct pl011_dmabuf *dbuf = dmarx->use_buf_b ?
		&dmarx->dbuf_b : &dmarx->dbuf_a;
	size_t pending;
	struct dma_tx_state state;
	int ret;
@@ -1015,7 +1010,7 @@ static void pl011_dma_rx_callback(void *data)
	 * the DMA irq handler. So we check the residue here.
	 */
	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
	pending = sgbuf->sg.length - state.residue;
	pending = dbuf->len - state.residue;
	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
	/* Then we terminate the transfer - we now know our residue */
	dmaengine_terminate_all(rxchan);
@@ -1067,16 +1062,16 @@ static void pl011_dma_rx_poll(struct timer_list *t)
	unsigned long flags;
	unsigned int dmataken = 0;
	unsigned int size = 0;
	struct pl011_sgbuf *sgbuf;
	struct pl011_dmabuf *dbuf;
	int dma_count;
	struct dma_tx_state state;

	sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
	dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
	if (likely(state.residue < dmarx->last_residue)) {
		dmataken = sgbuf->sg.length - dmarx->last_residue;
		dmataken = dbuf->len - dmarx->last_residue;
		size = dmarx->last_residue - state.residue;
		dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
		dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
				size);
		if (dma_count == size)
			dmarx->last_residue =  state.residue;
@@ -1123,7 +1118,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
		return;
	}

	sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE);
	uap->dmatx.len = PL011_DMA_BUFFER_SIZE;

	/* The DMA buffer is now the FIFO the TTY subsystem can use */
	uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
@@ -1133,7 +1128,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
		goto skip_rx;

	/* Allocate and map DMA RX buffers */
	ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
			       DMA_FROM_DEVICE);
	if (ret) {
		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
@@ -1141,12 +1136,12 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
		goto skip_rx;
	}

	ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b,
	ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
			       DMA_FROM_DEVICE);
	if (ret) {
		dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
			"RX buffer B", ret);
		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
				 DMA_FROM_DEVICE);
		goto skip_rx;
	}
@@ -1200,7 +1195,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
		/* In theory, this should already be done by pl011_dma_flush_buffer */
		dmaengine_terminate_all(uap->dmatx.chan);
		if (uap->dmatx.queued) {
			dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
			dma_unmap_single(uap->dmatx.chan->device->dev,
					 uap->dmatx.dma, uap->dmatx.len,
					 DMA_TO_DEVICE);
			uap->dmatx.queued = false;
		}
@@ -1212,8 +1208,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
	if (uap->using_rx_dma) {
		dmaengine_terminate_all(uap->dmarx.chan);
		/* Clean up the RX DMA */
		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
		pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
		if (uap->dmarx.poll_rate)
			del_timer_sync(&uap->dmarx.timer);
		uap->using_rx_dma = false;
+9 −1
Original line number Diff line number Diff line
@@ -552,11 +552,19 @@ static void ma35d1serial_console_putchar(struct uart_port *port, unsigned char c
 */
static void ma35d1serial_console_write(struct console *co, const char *s, u32 count)
{
	struct uart_ma35d1_port *up = &ma35d1serial_ports[co->index];
	struct uart_ma35d1_port *up;
	unsigned long flags;
	int locked = 1;
	u32 ier;

	if ((co->index < 0) || (co->index >= MA35_UART_NR)) {
		pr_warn("Failed to write on ononsole port %x, out of range\n",
			co->index);
		return;
	}

	up = &ma35d1serial_ports[co->index];

	if (up->port.sysrq)
		locked = 0;
	else if (oops_in_progress)
Loading