summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2015-02-13 22:12:06 (GMT)
committerScott Wood <scottwood@freescale.com>2015-02-13 22:19:22 (GMT)
commit6faa2909871d8937cb2f79a10e1b21ffe193fac1 (patch)
treef558a94f1553814cc122ab8d9e04c0ebad5262a5 /drivers/tty/serial/8250
parentfcb2fb84301c673ee15ca04e7a2fc965712d49a0 (diff)
downloadlinux-fsl-qoriq-6faa2909871d8937cb2f79a10e1b21ffe193fac1.tar.xz
Reset to 3.12.37
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r--drivers/tty/serial/8250/8250_core.c33
-rw-r--r--drivers/tty/serial/8250/8250_dma.c26
-rw-r--r--drivers/tty/serial/8250/8250_dw.c43
-rw-r--r--drivers/tty/serial/8250/8250_pci.c31
4 files changed, 98 insertions, 35 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index f70ecf1..04c8772 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -38,7 +38,6 @@
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/kdb.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>
#endif
@@ -81,16 +80,7 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define DEBUG_INTR(fmt...) do { } while (0)
#endif
-/*
- * On -rt we can have a more delays, and legitimately
- * so - so don't drop work spuriously and spam the
- * syslog:
- */
-#ifdef CONFIG_PREEMPT_RT_FULL
-# define PASS_LIMIT 1000000
-#else
-# define PASS_LIMIT 512
-#endif
+#define PASS_LIMIT 512
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
@@ -565,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
*/
if ((p->port.type == PORT_XR17V35X) ||
(p->port.type == PORT_XR17D15X)) {
- serial_out(p, UART_EXAR_SLEEP, 0xff);
+ serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
return;
}
@@ -1530,7 +1520,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
- if (status & UART_LSR_THRE)
+ if (!up->dma && (status & UART_LSR_THRE))
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
@@ -2366,7 +2356,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART_LSR_BI;
/*
@@ -2874,10 +2864,14 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
touch_nmi_watchdog();
- if (port->sysrq || oops_in_progress || in_kdb_printk())
- locked = spin_trylock_irqsave(&port->lock, flags);
- else
- spin_lock_irqsave(&port->lock, flags);
+ local_irq_save(flags);
+ if (port->sysrq) {
+ /* serial8250_handle_irq() already took the lock */
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&port->lock);
+ } else
+ spin_lock(&port->lock);
/*
* First save the IER then disable the interrupts
@@ -2909,7 +2903,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
serial8250_modem_status(up);
if (locked)
- spin_unlock_irqrestore(&port->lock, flags);
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
}
static int __init serial8250_console_setup(struct console *co, char *options)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 7046769..148ffe4 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -20,12 +20,15 @@ static void __dma_tx_complete(void *param)
struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
struct circ_buf *xmit = &p->port.state->xmit;
-
- dma->tx_running = 0;
+ unsigned long flags;
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
+ spin_lock_irqsave(&p->port.lock, flags);
+
+ dma->tx_running = 0;
+
xmit->tail += dma->tx_size;
xmit->tail &= UART_XMIT_SIZE - 1;
p->port.icount.tx += dma->tx_size;
@@ -35,6 +38,8 @@ static void __dma_tx_complete(void *param)
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
serial8250_tx_dma(p);
+
+ spin_unlock_irqrestore(&p->port.lock, flags);
}
static void __dma_rx_complete(void *param)
@@ -187,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
- if (!dma->rx_buf) {
- dma_release_channel(dma->rxchan);
- dma_release_channel(dma->txchan);
- return -ENOMEM;
- }
+ if (!dma->rx_buf)
+ goto err;
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
+ if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
+ dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
+ dma->rx_buf, dma->rx_addr);
+ goto err;
+ }
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
return 0;
+err:
+ dma_release_channel(dma->rxchan);
+ dma_release_channel(dma->txchan);
+
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(serial8250_request_dma);
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 8b2accb..70ecf54 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -56,7 +56,6 @@
struct dw8250_data {
- int last_lcr;
int last_mcr;
int line;
struct clk *clk;
@@ -76,17 +75,34 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
return value;
}
+static void dw8250_force_idle(struct uart_port *p)
+{
+ serial8250_clear_and_reinit_fifos(container_of
+ (p, struct uart_8250_port, port));
+ (void)p->serial_in(p, UART_RX);
+}
+
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
- if (offset == UART_LCR)
- d->last_lcr = value;
-
if (offset == UART_MCR)
d->last_mcr = value;
writeb(value, p->membase + (offset << p->regshift));
+
+ /* Make sure LCR write wasn't ignored */
+ if (offset == UART_LCR) {
+ int tries = 1000;
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+ dw8250_force_idle(p);
+ writeb(value, p->membase + (UART_LCR << p->regshift));
+ }
+ dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ }
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
@@ -107,13 +123,23 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
- if (offset == UART_LCR)
- d->last_lcr = value;
-
if (offset == UART_MCR)
d->last_mcr = value;
writel(value, p->membase + (offset << p->regshift));
+
+ /* Make sure LCR write wasn't ignored */
+ if (offset == UART_LCR) {
+ int tries = 1000;
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+ dw8250_force_idle(p);
+ writel(value, p->membase + (UART_LCR << p->regshift));
+ }
+ dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ }
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -131,9 +157,8 @@ static int dw8250_handle_irq(struct uart_port *p)
if (serial8250_handle_irq(p, iir)) {
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
- /* Clear the USR and write the LCR again. */
+ /* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
- p->serial_out(p, UART_LCR, d->last_lcr);
return 1;
}
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index f5df8b7..ee1f7c5 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1558,6 +1558,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
@@ -1567,6 +1568,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
+#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936
#define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
@@ -1875,6 +1877,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = sbs_setup,
.exit = sbs_exit,
},
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_QRK_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
/*
* SBS Technologies, Inc., PMC-OCTALPRO 422
*/
@@ -2151,6 +2160,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
},
+ /* WCH CH353 1S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_1S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
/* WCH CH353 2S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
@@ -2450,6 +2467,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_4_3906250,
pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200,
+ pbn_qrk,
pbn_omegapci,
pbn_NETMOS9900_2s_115200,
pbn_brcm_trumanage,
@@ -3186,6 +3204,12 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
+ [pbn_qrk] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 2764800,
+ .reg_shift = 2,
+ },
[pbn_omegapci] = {
.flags = FL_BASE0,
.num_ports = 8,
@@ -3213,6 +3237,7 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
+ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
};
/*
@@ -4854,6 +4879,12 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_ce4100_1_115200 },
/*
+ * Intel Quark x1000
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_qrk },
+ /*
* Cronyx Omega PCI
*/
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,