aboutsummaryrefslogtreecommitdiffstatshomepage
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.c238
1 files changed, 180 insertions, 58 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 0325f2e53b74..f77bf820b7a3 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -557,17 +557,6 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
-static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
-{
- unsigned char mcr = serial8250_in_MCR(p);
-
- if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
- mcr |= UART_MCR_RTS;
- else
- mcr &= ~UART_MCR_RTS;
- serial8250_out_MCR(p, mcr);
-}
-
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -615,7 +604,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
*
* Return 0 - success, -errno - otherwise
*/
-int serial8250_em485_init(struct uart_8250_port *p)
+static int serial8250_em485_init(struct uart_8250_port *p)
{
if (p->em485)
return 0;
@@ -632,11 +621,12 @@ int serial8250_em485_init(struct uart_8250_port *p)
p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
p->em485->port = p;
p->em485->active_timer = NULL;
- serial8250_em485_rts_after_send(p);
+ p->em485->tx_stopped = true;
+
+ p->rs485_stop_tx(p);
return 0;
}
-EXPORT_SYMBOL_GPL(serial8250_em485_init);
/**
* serial8250_em485_destroy() - put uart_8250_port into normal state
@@ -664,6 +654,52 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+/**
+ * serial8250_em485_config() - generic ->rs485_config() callback
+ * @port: uart port
+ * @rs485: rs485 settings
+ *
+ * Generic callback usable by 8250 uart drivers to activate rs485 settings
+ * if the uart is incapable of driving RTS as a Transmit Enable signal in
+ * hardware, relying on software emulation instead.
+ */
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
+{
+ 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;
+ }
+
+ /* clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ memset(rs485->padding, 0, sizeof(rs485->padding));
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init() and serial8250_em485_destroy()
+ * are idempotent.
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_config);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -1318,8 +1354,8 @@ out_lock:
fintek_8250_probe(up);
if (up->capabilities != old_capabilities) {
- pr_warn("%s: detected caps %08x should be %08x\n",
- port->name, old_capabilities, up->capabilities);
+ dev_warn(port->dev, "detected caps %08x should be %08x\n",
+ old_capabilities, up->capabilities);
}
out:
DEBUG_AUTOCONF("iir=%d ", scratch);
@@ -1394,9 +1430,21 @@ static void serial8250_stop_rx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void __do_stop_tx_rs485(struct uart_8250_port *p)
+/**
+ * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
+ * @up: uart 8250 port
+ *
+ * Generic callback usable by 8250 uart drivers to stop rs485 transmission.
+ */
+void serial8250_em485_stop_tx(struct uart_8250_port *p)
{
- serial8250_em485_rts_after_send(p);
+ unsigned char mcr = serial8250_in_MCR(p);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial8250_out_MCR(p, mcr);
/*
* Empty the RX FIFO, we are not interested in anything
@@ -1410,6 +1458,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
serial_port_out(&p->port, UART_IER, p->ier);
}
}
+EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
+
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
{
struct uart_8250_em485 *em485;
@@ -1422,8 +1472,9 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
serial8250_rpm_get(p);
spin_lock_irqsave(&p->port.lock, flags);
if (em485->active_timer == &em485->stop_tx_timer) {
- __do_stop_tx_rs485(p);
+ p->rs485_stop_tx(p);
em485->active_timer = NULL;
+ em485->tx_stopped = true;
}
spin_unlock_irqrestore(&p->port.lock, flags);
serial8250_rpm_put(p);
@@ -1444,7 +1495,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
struct uart_8250_em485 *em485 = p->em485;
/*
- * __do_stop_tx_rs485 is going to set RTS according to config
+ * rs485_stop_tx() is going to set RTS according to config
* AND flush RX FIFO if required.
*/
if (p->port.rs485.delay_rts_after_send > 0) {
@@ -1452,7 +1503,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
start_hrtimer_ms(&em485->stop_tx_timer,
p->port.rs485.delay_rts_after_send);
} else {
- __do_stop_tx_rs485(p);
+ p->rs485_stop_tx(p);
+ em485->active_timer = NULL;
+ em485->tx_stopped = true;
}
}
@@ -1477,8 +1530,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
return;
- em485->active_timer = NULL;
-
__stop_tx_rs485(p);
}
__do_stop_tx(p);
@@ -1528,25 +1579,42 @@ static inline void __start_tx(struct uart_port *port)
}
}
-static inline void start_tx_rs485(struct uart_port *port)
+/**
+ * serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
+ * @up: uart 8250 port
+ *
+ * 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.
+ * (Some chips use inverse semantics.) Further assumes that reception is
+ * 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)
{
- struct uart_8250_port *up = up_to_u8250p(port);
- struct uart_8250_em485 *em485 = up->em485;
- unsigned char mcr;
+ unsigned char mcr = serial8250_in_MCR(up);
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
serial8250_stop_rx(&up->port);
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial8250_out_MCR(up, mcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_start_tx);
+
+static inline void start_tx_rs485(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+
em485->active_timer = NULL;
- mcr = serial8250_in_MCR(up);
- if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
- !!(mcr & UART_MCR_RTS)) {
- if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
- mcr |= UART_MCR_RTS;
- else
- mcr &= ~UART_MCR_RTS;
- serial8250_out_MCR(up, mcr);
+ if (em485->tx_stopped) {
+ em485->tx_stopped = false;
+
+ up->rs485_start_tx(up);
if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer;
@@ -1683,7 +1751,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
lsr &= port->read_status_mask;
if (lsr & UART_LSR_BI) {
- pr_debug("%s: handling break\n", __func__);
+ dev_dbg(port->dev, "handling break\n");
flag = TTY_BREAK;
} else if (lsr & UART_LSR_PE)
flag = TTY_PARITY;
@@ -1815,6 +1883,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
unsigned char status;
unsigned long flags;
struct uart_8250_port *up = up_to_u8250p(port);
+ bool skip_rx = false;
if (iir & UART_IIR_NO_INT)
return 0;
@@ -1823,7 +1892,20 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial_port_in(port, UART_LSR);
- if (status & (UART_LSR_DR | UART_LSR_BI)) {
+ /*
+ * If port is stopped and there are no error conditions in the
+ * FIFO, then don't drain the FIFO, as this may lead to TTY buffer
+ * overflow. Not servicing, RX FIFO would trigger auto HW flow
+ * control when FIFO occupancy reaches preset threshold, thus
+ * halting RX. This only works when auto HW flow control is
+ * available.
+ */
+ if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
+ (port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
+ !(port->read_status_mask & UART_LSR_DR))
+ skip_rx = true;
+
+ if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
if (!up->dma || handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
@@ -1924,6 +2006,13 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char mcr;
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if (serial8250_in_MCR(up) & UART_MCR_RTS)
+ mctrl |= TIOCM_RTS;
+ else
+ mctrl &= ~TIOCM_RTS;
+ }
+
mcr = serial8250_TIOCM_to_MCR(mctrl);
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
@@ -2134,7 +2223,7 @@ int serial8250_do_startup(struct uart_port *port)
*/
if (!(port->flags & UPF_BUGGY_UART) &&
(serial_port_in(port, UART_LSR) == 0xff)) {
- pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name);
+ dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
retval = -ENODEV;
goto out;
}
@@ -2166,8 +2255,7 @@ int serial8250_do_startup(struct uart_port *port)
(port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */
if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
- pr_err("%s TX FIFO Threshold errors, skipping\n",
- port->name);
+ dev_err(port->dev, "TX FIFO Threshold errors, skipping\n");
} else {
serial_port_out(port, UART_ALTR_AFR,
UART_ALTR_EN_TXFIFO_LW);
@@ -2268,8 +2356,7 @@ int serial8250_do_startup(struct uart_port *port)
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
if (!(up->bugs & UART_BUG_TXEN)) {
up->bugs |= UART_BUG_TXEN;
- pr_debug("%s - enabling bad tx status workarounds\n",
- port->name);
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
}
} else {
up->bugs &= ~UART_BUG_TXEN;
@@ -2294,10 +2381,14 @@ dont_test_tx_en:
* Request DMA channels for both RX and TX.
*/
if (up->dma) {
- retval = serial8250_request_dma(up);
- if (retval) {
- pr_warn_ratelimited("%s - failed to request DMA\n",
- port->name);
+ const char *msg = NULL;
+
+ if (uart_console(port))
+ msg = "forbid DMA for kernel console";
+ else if (serial8250_request_dma(up))
+ msg = "failed to request DMA";
+ if (msg) {
+ dev_warn_ratelimited(port->dev, "%s\n", msg);
up->dma = NULL;
}
}
@@ -2880,7 +2971,7 @@ static int do_serial8250_get_rxtrig(struct tty_port *port)
return rxtrig_bytes;
}
-static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev,
+static ssize_t rx_trig_bytes_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tty_port *port = dev_get_drvdata(dev);
@@ -2926,7 +3017,7 @@ static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes)
return ret;
}
-static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
+static ssize_t rx_trig_bytes_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tty_port *port = dev_get_drvdata(dev);
@@ -2947,18 +3038,16 @@ static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
return count;
}
-static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP,
- serial8250_get_attr_rx_trig_bytes,
- serial8250_set_attr_rx_trig_bytes);
+static DEVICE_ATTR_RW(rx_trig_bytes);
static struct attribute *serial8250_dev_attrs[] = {
&dev_attr_rx_trig_bytes.attr,
- NULL,
- };
+ NULL
+};
static struct attribute_group serial8250_dev_attr_group = {
.attrs = serial8250_dev_attrs,
- };
+};
static void register_dev_spec_attr_grp(struct uart_8250_port *up)
{
@@ -2987,6 +3076,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (flags & UART_CONFIG_TYPE)
autoconfig(up);
+ if (port->rs485.flags & SER_RS485_ENABLED)
+ port->rs485_config(port, &port->rs485);
+
/* if access method is AU, it is a 16550 with a quirk */
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
up->bugs |= UART_BUG_NOMSR;
@@ -3127,10 +3219,14 @@ static void serial8250_console_restore(struct uart_8250_port *up)
* any possible real use of the port...
*
* The console_lock must be held when we get here.
+ *
+ * Doing runtime PM is really a bad idea for the kernel console.
+ * Thus, we assume the function is called when device is powered up.
*/
void serial8250_console_write(struct uart_8250_port *up, const char *s,
unsigned int count)
{
+ struct uart_8250_em485 *em485 = up->em485;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier;
@@ -3138,8 +3234,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
touch_nmi_watchdog();
- serial8250_rpm_get(up);
-
if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
@@ -3161,6 +3255,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
up->canary = 0;
}
+ if (em485) {
+ if (em485->tx_stopped)
+ up->rs485_start_tx(up);
+ mdelay(port->rs485.delay_rts_before_send);
+ }
+
uart_console_write(port, s, count, serial8250_console_putchar);
/*
@@ -3168,6 +3268,13 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
* and restore the IER
*/
wait_for_xmitr(up, BOTH_EMPTY);
+
+ if (em485) {
+ mdelay(port->rs485.delay_rts_after_send);
+ if (em485->tx_stopped)
+ up->rs485_stop_tx(up);
+ }
+
serial_port_out(port, UART_IER, ier);
/*
@@ -3182,7 +3289,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
- serial8250_rpm_put(up);
}
static unsigned int probe_baud(struct uart_port *port)
@@ -3206,6 +3312,7 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int ret;
if (!port->iobase && !port->membase)
return -ENODEV;
@@ -3215,7 +3322,22 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
else if (probe)
baud = probe_baud(port);
- return uart_set_options(port, port->cons, baud, parity, bits, flow);
+ ret = uart_set_options(port, port->cons, baud, parity, bits, flow);
+ if (ret)
+ return ret;
+
+ if (port->dev)
+ pm_runtime_get_sync(port->dev);
+
+ return 0;
+}
+
+int serial8250_console_exit(struct uart_port *port)
+{
+ if (port->dev)
+ pm_runtime_put_sync(port->dev);
+
+ return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */