summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250/8250_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250/8250_port.c')
-rw-r--r--drivers/tty/serial/8250/8250_port.c255
1 files changed, 158 insertions, 97 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index fc9dd5d45295..6d7b8c4667c9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -338,6 +338,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value)
serial_out(up, UART_DLM, value >> 8 & 0xff);
}
+#ifdef CONFIG_HAS_IOPORT
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -351,6 +352,7 @@ static void hub6_serial_out(struct uart_port *p, int offset, int value)
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
+#endif /* CONFIG_HAS_IOPORT */
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
@@ -400,6 +402,7 @@ static unsigned int mem32be_serial_in(struct uart_port *p, int offset)
return ioread32be(p->membase + offset);
}
+#ifdef CONFIG_HAS_IOPORT
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -411,6 +414,15 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
+#endif
+static unsigned int no_serial_in(struct uart_port *p, int offset)
+{
+ return (unsigned int)-1;
+}
+
+static void no_serial_out(struct uart_port *p, int offset, int value)
+{
+}
static int serial8250_default_handle_irq(struct uart_port *port);
@@ -422,10 +434,12 @@ static void set_io_from_upio(struct uart_port *p)
up->dl_write = default_serial_dl_write;
switch (p->iotype) {
+#ifdef CONFIG_HAS_IOPORT
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
p->serial_out = hub6_serial_out;
break;
+#endif
case UPIO_MEM:
p->serial_in = mem_serial_in;
@@ -446,11 +460,17 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_in = mem32be_serial_in;
p->serial_out = mem32be_serial_out;
break;
-
- default:
+#ifdef CONFIG_HAS_IOPORT
+ case UPIO_PORT:
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
break;
+#endif
+ default:
+ WARN(p->iotype != UPIO_PORT || p->iobase,
+ "Unsupported UART type %x\n", p->iotype);
+ p->serial_in = no_serial_in;
+ p->serial_out = no_serial_out;
}
/* Remember loaded iotype */
up->cur_iotype = p->iotype;
@@ -497,22 +517,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-void serial8250_rpm_get(struct uart_8250_port *p)
+static void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-void serial8250_rpm_put(struct uart_8250_port *p)
+static void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -546,19 +564,17 @@ static int serial8250_em485_init(struct uart_8250_port *p)
if (!p->em485)
return -ENOMEM;
- hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
- p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
+ hrtimer_setup(&p->em485->stop_tx_timer, &serial8250_em485_handle_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&p->em485->start_tx_timer, &serial8250_em485_handle_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
p->em485->port = p;
p->em485->active_timer = NULL;
p->em485->tx_stopped = true;
deassert_rts:
if (p->em485->tx_stopped)
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
return 0;
}
@@ -612,13 +628,6 @@ int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
{
struct uart_8250_port *up = up_to_u8250p(port);
- /* pick sane settings if the user hasn't */
- if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
- !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
- rs485->flags |= SER_RS485_RTS_ON_SEND;
- rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
- }
-
/*
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
@@ -636,7 +645,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again.
*/
-void serial8250_rpm_get_tx(struct uart_8250_port *p)
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -648,9 +657,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p)
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
-void serial8250_rpm_put_tx(struct uart_8250_port *p)
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -663,7 +671,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/*
* IER sleep support. UARTs which have EFRs need the "extended
@@ -1181,7 +1188,7 @@ static void autoconfig(struct uart_8250_port *up)
*/
scratch = serial_in(up, UART_IER);
serial_out(up, UART_IER, 0);
-#ifdef __i386__
+#if defined(__i386__) && defined(CONFIG_HAS_IOPORT)
outb(0xff, 0x080);
#endif
/*
@@ -1190,7 +1197,7 @@ static void autoconfig(struct uart_8250_port *up)
*/
scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
serial_out(up, UART_IER, UART_IER_ALL_INTR);
-#ifdef __i386__
+#if defined(__i386__) && defined(CONFIG_HAS_IOPORT)
outb(0, 0x080);
#endif
scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
@@ -1377,7 +1384,6 @@ static void serial8250_stop_rx(struct uart_port *port)
serial8250_rpm_get(up);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
serial_port_out(port, UART_IER, up->ier);
serial8250_rpm_put(up);
@@ -1386,10 +1392,11 @@ static void serial8250_stop_rx(struct uart_port *port)
/**
* serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
* @p: uart 8250 port
+ * @toggle_ier: true to allow enabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to stop rs485 transmission.
*/
-void serial8250_em485_stop_tx(struct uart_8250_port *p)
+void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(p);
@@ -1410,8 +1417,10 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p)
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_and_reinit_fifos(p);
- p->ier |= UART_IER_RLSI | UART_IER_RDI;
- serial_port_out(&p->port, UART_IER, p->ier);
+ if (toggle_ier) {
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_port_out(&p->port, UART_IER, p->ier);
+ }
}
}
EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
@@ -1426,7 +1435,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
serial8250_rpm_get(p);
uart_port_lock_irqsave(&p->port, &flags);
if (em485->active_timer == &em485->stop_tx_timer) {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1458,7 +1467,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay)
em485->active_timer = &em485->stop_tx_timer;
hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL);
} else {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1547,6 +1556,7 @@ static inline void __start_tx(struct uart_port *port)
/**
* serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
* @up: uart 8250 port
+ * @toggle_ier: true to allow disabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to start rs485 transmission.
* Assumes that setting the RTS bit in the MCR register means RTS is high.
@@ -1554,11 +1564,11 @@ static inline void __start_tx(struct uart_port *port)
* stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the
* UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.)
*/
-void serial8250_em485_start_tx(struct uart_8250_port *up)
+void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(up);
- if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier)
serial8250_stop_rx(&up->port);
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
@@ -1592,7 +1602,7 @@ static bool start_tx_rs485(struct uart_port *port)
if (em485->tx_stopped) {
em485->tx_stopped = false;
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, true);
if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer;
@@ -1630,7 +1640,7 @@ static void serial8250_start_tx(struct uart_port *port)
/* Port locked to synchronize UART_IER access against the console. */
lockdep_assert_held_once(&port->lock);
- if (!port->x_char && uart_circ_empty(&port->state->xmit))
+ if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo))
return;
serial8250_rpm_get_tx(up);
@@ -1664,7 +1674,7 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
- mctrl_gpio_disable_ms(up->gpios);
+ mctrl_gpio_disable_ms_no_sync(up->gpios);
up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier);
@@ -1778,7 +1788,7 @@ EXPORT_SYMBOL_GPL(serial8250_rx_chars);
void serial8250_tx_chars(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
int count;
if (port->x_char) {
@@ -1789,14 +1799,19 @@ void serial8250_tx_chars(struct uart_8250_port *up)
serial8250_stop_tx(port);
return;
}
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
__stop_tx(up);
return;
}
count = up->tx_loadsz;
do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+ unsigned char c;
+
+ if (!uart_fifo_get(port, &c))
+ break;
+
+ serial_out(up, UART_TX, c);
if (up->bugs & UART_BUG_TXRACE) {
/*
* The Aspeed BMC virtual UARTs have a bug where data
@@ -1809,9 +1824,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
*/
serial_in(up, UART_SCR);
}
- uart_xmit_advance(port, 1);
- if (uart_circ_empty(xmit))
- break;
+
if ((up->capabilities & UART_CAP_HFIFO) &&
!uart_lsr_tx_empty(serial_in(up, UART_LSR)))
break;
@@ -1821,7 +1834,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
break;
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
/*
@@ -1829,7 +1842,8 @@ void serial8250_tx_chars(struct uart_8250_port *up)
* HW can go idle. So we get here once again with empty FIFO and disable
* the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (kfifo_is_empty(&tport->xmit_fifo) &&
+ !(up->capabilities & UART_CAP_RPM))
__stop_tx(up);
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
@@ -1914,7 +1928,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
- !(port->read_status_mask & UART_LSR_DR))
+ !(up->ier & (UART_IER_RLSI | UART_IER_RDI)))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
@@ -2062,11 +2076,20 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
serial8250_rpm_put(up);
}
-static void wait_for_lsr(struct uart_8250_port *up, int bits)
+/* Returns true if @bits were set, false on timeout */
+static bool wait_for_lsr(struct uart_8250_port *up, int bits)
{
- unsigned int status, tmout = 10000;
+ unsigned int status, tmout;
+
+ /*
+ * Wait for a character to be sent. Fallback to a safe default
+ * timeout value if @frame_time is not available.
+ */
+ if (up->port.frame_time)
+ tmout = up->port.frame_time * 2 / NSEC_PER_USEC;
+ else
+ tmout = 10000;
- /* Wait up to 10ms for the character(s) to be sent. */
for (;;) {
status = serial_lsr_in(up);
@@ -2077,11 +2100,11 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
udelay(1);
touch_nmi_watchdog();
}
+
+ return (tmout != 0);
}
-/*
- * Wait for transmitter & holding register to empty
- */
+/* Wait for transmitter and holding register to empty with timeout */
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
@@ -2379,28 +2402,26 @@ int serial8250_do_startup(struct uart_port *port)
* test if we receive TX irq. This way, we'll never enable
* UART_BUG_TXEN.
*/
- if (up->port.quirks & UPQ_NO_TXEN_TEST)
- goto dont_test_tx_en;
-
- /*
- * Do a quick test to see if we receive an interrupt when we enable
- * the TX irq.
- */
- serial_port_out(port, UART_IER, UART_IER_THRI);
- lsr = serial_port_in(port, UART_LSR);
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
+ if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
+ /*
+ * Do a quick test to see if we receive an interrupt when we
+ * enable the TX irq.
+ */
+ serial_port_out(port, UART_IER, UART_IER_THRI);
+ lsr = serial_port_in(port, UART_LSR);
+ iir = serial_port_in(port, UART_IIR);
+ serial_port_out(port, UART_IER, 0);
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
- if (!(up->bugs & UART_BUG_TXEN)) {
- up->bugs |= UART_BUG_TXEN;
- dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ }
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
}
- } else {
- up->bugs &= ~UART_BUG_TXEN;
}
-dont_test_tx_en:
uart_port_unlock_irqrestore(port, flags);
/*
@@ -2526,6 +2547,14 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
+static void serial8250_flush_buffer(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ if (up->dma)
+ serial8250_tx_dma_flush(up);
+}
+
static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
@@ -2612,7 +2641,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
}
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
- unsigned int quot, unsigned int quot_frac)
+ unsigned int quot)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2644,7 +2673,7 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
if (port->set_divisor)
port->set_divisor(port, baud, quot, quot_frac);
else
- serial8250_do_set_divisor(port, baud, quot, quot_frac);
+ serial8250_do_set_divisor(port, baud, quot);
}
static unsigned int serial8250_get_baud_rate(struct uart_port *port,
@@ -2769,7 +2798,13 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ /*
+ * Specify which conditions may be considered for error
+ * handling and the ignoring of characters. The actual
+ * ignoring of characters only occurs if the bit is set
+ * in @ignore_status_mask as well.
+ */
+ port->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
@@ -2927,7 +2962,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
- int ret = 0;
switch (port->iotype) {
case UPIO_AU:
@@ -2936,32 +2970,30 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
- if (!port->mapbase) {
- ret = -EINVAL;
- break;
- }
+ if (!port->mapbase)
+ return -EINVAL;
- if (!request_mem_region(port->mapbase, size, "serial")) {
- ret = -EBUSY;
- break;
- }
+ if (!request_mem_region(port->mapbase, size, "serial"))
+ return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
release_mem_region(port->mapbase, size);
- ret = -ENOMEM;
+ return -ENOMEM;
}
}
- break;
-
+ return 0;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(port->iobase, size, "serial"))
- ret = -EBUSY;
+ return -EBUSY;
+ return 0;
+ case UPIO_UNKNOWN:
break;
}
- return ret;
+
+ return 0;
}
static void serial8250_release_std_resource(struct uart_8250_port *up)
@@ -2991,6 +3023,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase, size);
break;
+ case UPIO_UNKNOWN:
+ break;
}
}
@@ -3179,7 +3213,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
static int
serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= nr_irqs || ser->irq < 0 ||
+ if (ser->irq >= irq_get_nr_irqs() || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
ser->type == PORT_STARTECH)
@@ -3209,6 +3243,7 @@ static const struct uart_ops serial8250_pops = {
.break_ctl = serial8250_break_ctl,
.startup = serial8250_startup,
.shutdown = serial8250_shutdown,
+ .flush_buffer = serial8250_flush_buffer,
.set_termios = serial8250_set_termios,
.set_ldisc = serial8250_set_ldisc,
.pm = serial8250_pm,
@@ -3233,7 +3268,7 @@ void serial8250_init_port(struct uart_8250_port *up)
port->ops = &serial8250_pops;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
- up->cur_iotype = 0xFF;
+ up->cur_iotype = UPIO_UNKNOWN;
}
EXPORT_SYMBOL_GPL(serial8250_init_port);
@@ -3268,10 +3303,15 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
{
+ serial_port_out(port, UART_TX, ch);
+}
+
+static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch)
+{
struct uart_8250_port *up = up_to_u8250p(port);
wait_for_xmitr(up, UART_LSR_THRE);
- serial_port_out(port, UART_TX, ch);
+ serial8250_console_putchar(port, ch);
}
/*
@@ -3300,6 +3340,16 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
+static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_lsr(up, UART_LSR_THRE))
+ return;
+ }
+}
+
/*
* Print a string to the serial port using the device FIFO
*
@@ -3309,24 +3359,34 @@ static void serial8250_console_restore(struct uart_8250_port *up)
static void serial8250_console_fifo_write(struct uart_8250_port *up,
const char *s, unsigned int count)
{
- int i;
const char *end = s + count;
unsigned int fifosize = up->tx_loadsz;
+ struct uart_port *port = &up->port;
+ unsigned int tx_count = 0;
bool cr_sent = false;
+ unsigned int i;
while (s != end) {
- wait_for_lsr(up, UART_LSR_THRE);
+ /* Allow timeout for each byte of a possibly full FIFO */
+ fifo_wait_for_lsr(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
- serial_out(up, UART_TX, '\r');
+ serial8250_console_putchar(port, '\r');
cr_sent = true;
} else {
- serial_out(up, UART_TX, *s++);
+ serial8250_console_putchar(port, *s++);
cr_sent = false;
}
}
+ tx_count = i;
}
+
+ /*
+ * Allow timeout for each byte written since the caller will only wait
+ * for UART_LSR_BOTH_EMPTY using the timeout of a single character
+ */
+ fifo_wait_for_lsr(up, tx_count);
}
/*
@@ -3368,7 +3428,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
if (em485->tx_stopped)
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, false);
mdelay(port->rs485.delay_rts_before_send);
}
@@ -3395,7 +3455,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
- uart_console_write(port, s, count, serial8250_console_putchar);
+ uart_console_write(port, s, count, serial8250_console_wait_putchar);
/*
* Finally, wait for transmitter to become empty
@@ -3406,7 +3466,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
if (em485->tx_stopped)
- up->rs485_stop_tx(up);
+ up->rs485_stop_tx(up, false);
}
serial_port_out(port, UART_IER, ier);
@@ -3476,4 +3536,5 @@ int serial8250_console_exit(struct uart_port *port)
#endif /* CONFIG_SERIAL_8250_CONSOLE */
+MODULE_DESCRIPTION("Base port operations for 8250/16550-type serial ports");
MODULE_LICENSE("GPL");