summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/8250/8250_dw.c108
-rw-r--r--drivers/tty/serial/8250/8250_early.c3
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c3
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/arc_uart.c2
-rw-r--r--drivers/tty/serial/mxs-auart.c38
-rw-r--r--drivers/tty/serial/serial-tegra.c2
-rw-r--r--drivers/tty/synclinkmp.c2
-rw-r--r--drivers/tty/sysrq.c19
-rw-r--r--drivers/tty/tty_port.c5
10 files changed, 115 insertions, 69 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index d07b6af3a93..76a8daadff4 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -29,6 +29,8 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <asm/byteorder.h>
+
#include "8250.h"
/* Offsets for the DesignWare specific registers */
@@ -57,6 +59,7 @@ struct dw8250_data {
int last_lcr;
int line;
struct clk *clk;
+ u8 usr_reg;
};
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
@@ -77,6 +80,13 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
return readb(p->membase + offset);
}
+/* Read Back (rb) version to ensure register access ording. */
+static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value)
+{
+ dw8250_serial_out(p, offset, value);
+ dw8250_serial_in(p, UART_LCR);
+}
+
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -104,7 +114,7 @@ static int dw8250_handle_irq(struct uart_port *p)
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR and write the LCR again. */
- (void)p->serial_in(p, DW_UART_USR);
+ (void)p->serial_in(p, d->usr_reg);
p->serial_out(p, UART_LCR, d->last_lcr);
return 1;
@@ -125,12 +135,60 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
pm_runtime_put_sync_suspend(port->dev);
}
-static int dw8250_probe_of(struct uart_port *p)
+static void dw8250_setup_port(struct uart_8250_port *up)
+{
+ struct uart_port *p = &up->port;
+ u32 reg = readl(p->membase + DW_UART_UCV);
+
+ /*
+ * If the Component Version Register returns zero, we know that
+ * ADDITIONAL_FEATURES are not enabled. No need to go any further.
+ */
+ if (!reg)
+ return;
+
+ dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+
+ reg = readl(p->membase + DW_UART_CPR);
+ if (!reg)
+ return;
+
+ /* Select the type based on fifo */
+ if (reg & DW_UART_CPR_FIFO_MODE) {
+ p->type = PORT_16550A;
+ p->flags |= UPF_FIXED_TYPE;
+ p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
+ up->tx_loadsz = p->fifosize;
+ up->capabilities = UART_CAP_FIFO;
+ }
+
+ if (reg & DW_UART_CPR_AFCE_MODE)
+ up->capabilities |= UART_CAP_AFE;
+}
+
+static int dw8250_probe_of(struct uart_port *p,
+ struct dw8250_data *data)
{
struct device_node *np = p->dev->of_node;
u32 val;
-
- if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ bool has_ucv = true;
+
+ if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
+#ifdef __BIG_ENDIAN
+ /*
+ * Low order bits of these 64-bit registers, when
+ * accessed as a byte, are 7 bytes further down in the
+ * address space in big endian mode.
+ */
+ p->membase += 7;
+#endif
+ p->serial_out = dw8250_serial_out_rb;
+ p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ p->type = PORT_OCTEON;
+ data->usr_reg = 0x27;
+ has_ucv = false;
+ } else if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
@@ -144,6 +202,8 @@ static int dw8250_probe_of(struct uart_port *p)
return -EINVAL;
}
}
+ if (has_ucv)
+ dw8250_setup_port(container_of(p, struct uart_8250_port, port));
if (!of_property_read_u32(np, "reg-shift", &val))
p->regshift = val;
@@ -168,6 +228,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up)
const struct acpi_device_id *id;
struct uart_port *p = &up->port;
+ dw8250_setup_port(up);
+
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
if (!id)
return -ENODEV;
@@ -196,38 +258,6 @@ static inline int dw8250_probe_acpi(struct uart_8250_port *up)
}
#endif /* CONFIG_ACPI */
-static void dw8250_setup_port(struct uart_8250_port *up)
-{
- struct uart_port *p = &up->port;
- u32 reg = readl(p->membase + DW_UART_UCV);
-
- /*
- * If the Component Version Register returns zero, we know that
- * ADDITIONAL_FEATURES are not enabled. No need to go any further.
- */
- if (!reg)
- return;
-
- dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
- (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
-
- reg = readl(p->membase + DW_UART_CPR);
- if (!reg)
- return;
-
- /* Select the type based on fifo */
- if (reg & DW_UART_CPR_FIFO_MODE) {
- p->type = PORT_16550A;
- p->flags |= UPF_FIXED_TYPE;
- p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
- up->tx_loadsz = p->fifosize;
- up->capabilities = UART_CAP_FIFO;
- }
-
- if (reg & DW_UART_CPR_AFCE_MODE)
- up->capabilities |= UART_CAP_AFE;
-}
-
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
@@ -259,6 +289,7 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ data->usr_reg = DW_UART_USR;
data->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(data->clk)) {
clk_prepare_enable(data->clk);
@@ -270,10 +301,8 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.serial_out = dw8250_serial_out;
uart.port.private_data = data;
- dw8250_setup_port(&uart);
-
if (pdev->dev.of_node) {
- err = dw8250_probe_of(&uart.port);
+ err = dw8250_probe_of(&uart.port, data);
if (err)
return err;
} else if (ACPI_HANDLE(&pdev->dev)) {
@@ -362,6 +391,7 @@ static const struct dev_pm_ops dw8250_pm_ops = {
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" },
+ { .compatible = "cavium,octeon-3860-uart" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 721904f8efa..946ddd2b3a5 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -193,7 +193,8 @@ static int __init parse_options(struct early_serial8250_device *device,
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
- length = min(strcspn(options, " "), sizeof(device->options));
+ length = min(strcspn(options, " ") + 1,
+ sizeof(device->options));
strlcpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index bb91b4713eb..2e3ea1a70d7 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
int err;
#ifdef CONFIG_64BIT
- extern int iosapic_serial_irq(int cellnum);
if (!dev->irq && (dev->id.sversion == 0xad))
- dev->irq = iosapic_serial_irq(dev->mod_index-1);
+ dev->irq = iosapic_serial_irq(dev);
#endif
if (!dev->irq) {
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 5e3d68917ff..1456673bcca 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -277,7 +277,7 @@ config SERIAL_TEGRA
select SERIAL_CORE
help
Support for the on-chip UARTs on the NVIDIA Tegra series SOCs
- providing /dev/ttyHS0, 1, 2, 3 and 4 (note, some machines may not
+ providing /dev/ttyTHS0, 1, 2, 3 and 4 (note, some machines may not
provide all of these ports, depending on how the serial port
are enabled). This driver uses the APB DMA to achieve higher baudrate
and better performance.
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index cbf1d155b7b..22f280aa4f2 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -773,6 +773,6 @@ module_init(arc_serial_init);
module_exit(arc_serial_exit);
MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Vineet Gupta");
MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 4f5f161896a..f85b8e6d034 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
{
- u32 istatus, istat;
+ u32 istat;
struct mxs_auart_port *s = context;
u32 stat = readl(s->port.membase + AUART_STAT);
- istatus = istat = readl(s->port.membase + AUART_INTR);
+ istat = readl(s->port.membase + AUART_INTR);
+
+ /* ack irq */
+ writel(istat & (AUART_INTR_RTIS
+ | AUART_INTR_TXIS
+ | AUART_INTR_RXIS
+ | AUART_INTR_CTSMIS),
+ s->port.membase + AUART_INTR_CLR);
if (istat & AUART_INTR_CTSMIS) {
uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
istat &= ~AUART_INTR_TXIS;
}
- writel(istatus & (AUART_INTR_RTIS
- | AUART_INTR_TXIS
- | AUART_INTR_RXIS
- | AUART_INTR_CTSMIS),
- s->port.membase + AUART_INTR_CLR);
-
return IRQ_HANDLED;
}
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
struct mxs_auart_port *s;
struct uart_port *port;
unsigned int old_ctrl0, old_ctrl2;
- unsigned int to = 1000;
+ unsigned int to = 20000;
if (co->index >= MXS_AUART_PORTS || co->index < 0)
return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
uart_console_write(port, str, count, mxs_auart_console_putchar);
- /*
- * Finally, wait for transmitter to become empty
- * and restore the TCR
- */
+ /* Finally, wait for transmitter to become empty ... */
while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+ udelay(1);
if (!to--)
break;
- udelay(1);
}
- writel(old_ctrl0, port->membase + AUART_CTRL0);
- writel(old_ctrl2, port->membase + AUART_CTRL2);
+ /*
+ * ... and restore the TCR if we waited long enough for the transmitter
+ * to be idle. This might keep the transmitter enabled although it is
+ * unused, but that is better than to disable it while it is still
+ * transmitting.
+ */
+ if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+ writel(old_ctrl0, port->membase + AUART_CTRL0);
+ writel(old_ctrl2, port->membase + AUART_CTRL2);
+ }
clk_disable(s->clk);
}
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 9799d043a9b..ee7c8123c37 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -1377,7 +1377,7 @@ static int __init tegra_uart_init(void)
ret = platform_driver_register(&tegra_uart_platform_driver);
if (ret < 0) {
- pr_err("Uart platfrom driver register failed, e = %d\n", ret);
+ pr_err("Uart platform driver register failed, e = %d\n", ret);
uart_unregister_driver(&tegra_uart_driver);
return ret;
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index ff171384ea5..dc6e96996ea 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3478,7 +3478,7 @@ static int alloc_buf_list(SLMP_INFO *info)
for ( i = 0; i < info->rx_buf_count; i++ ) {
/* calculate and store physical address of this buffer entry */
info->rx_buf_list_ex[i].phys_entry =
- info->buffer_list_phys + (i * sizeof(SCABUFSIZE));
+ info->buffer_list_phys + (i * SCABUFSIZE);
/* calculate and store physical address of */
/* next entry in cirular list of entries */
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 5f68f2cfdfd..d5cc3acecfd 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -44,6 +44,7 @@
#include <linux/uaccess.h>
#include <linux/moduleparam.h>
#include <linux/jiffies.h>
+#include <linux/syscalls.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -586,6 +587,7 @@ struct sysrq_state {
/* reset sequence handling */
bool reset_canceled;
+ bool reset_requested;
unsigned long reset_keybit[BITS_TO_LONGS(KEY_CNT)];
int reset_seq_len;
int reset_seq_cnt;
@@ -624,18 +626,26 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state)
state->reset_seq_version = sysrq_reset_seq_version;
}
-static void sysrq_do_reset(unsigned long dummy)
+static void sysrq_do_reset(unsigned long _state)
{
- __handle_sysrq(sysrq_xlate[KEY_B], false);
+ struct sysrq_state *state = (struct sysrq_state *) _state;
+
+ state->reset_requested = true;
+
+ sys_sync();
+ kernel_restart(NULL);
}
static void sysrq_handle_reset_request(struct sysrq_state *state)
{
+ if (state->reset_requested)
+ __handle_sysrq(sysrq_xlate[KEY_B], false);
+
if (sysrq_reset_downtime_ms)
mod_timer(&state->keyreset_timer,
jiffies + msecs_to_jiffies(sysrq_reset_downtime_ms));
else
- sysrq_do_reset(0);
+ sysrq_do_reset((unsigned long)state);
}
static void sysrq_detect_reset_sequence(struct sysrq_state *state,
@@ -837,7 +847,8 @@ static int sysrq_connect(struct input_handler *handler,
sysrq->handle.handler = handler;
sysrq->handle.name = "sysrq";
sysrq->handle.private = sysrq;
- setup_timer(&sysrq->keyreset_timer, sysrq_do_reset, 0);
+ setup_timer(&sysrq->keyreset_timer,
+ sysrq_do_reset, (unsigned long)sysrq);
error = input_register_handle(&sysrq->handle);
if (error) {
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 121aeb9393e..f597e88a705 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
{
struct tty_struct *tty = tty_port_tty_get(port);
- if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+ if (tty && (!check_clocal || !C_CLOCAL(tty)))
tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_kref_put(tty);
}
EXPORT_SYMBOL_GPL(tty_port_tty_hangup);