TTY/Serial patches for 3.6-rc1
Here's the "tiny" set of patches for 3.6-rc1 for the tty layer and serial drivers. They were cherry-picked from the tty-next branch of the tty git tree, as they are small and "obvious" fixes. The larger changes, as mentioned before, will be saved for the 3.7-rc1 merge window. All of these changes have been in the linux-next releases for quite a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iEYEABECAAYFAlAS5OkACgkQMUfUDdst+ykYLgCfdCz1v64yvk21r8un9fa3JXYW dIIAoNcIeLHsUOcmMSp0JN2oZkBNZOb7 =y7gx -----END PGP SIGNATURE----- Merge tag 'tty-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull TTY/Serial patches from Greg Kroah-Hartman: "Here's the "tiny" set of patches for 3.6-rc1 for the tty layer and serial drivers. They were cherry-picked from the tty-next branch of the tty git tree, as they are small and "obvious" fixes. The larger changes, as mentioned before, will be saved for the 3.7-rc1 merge window. All of these changes have been in the linux-next releases for quite a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'tty-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: pch_uart: Fix parity setting issue pch_uart: Fix rx error interrupt setting issue pch_uart: Fix missing break for 16 byte fifo tty ldisc: Close/Reopen race prevention should check the proper flag pch_uart: Add eg20t_port lock field, avoid recursive spinlocks vt: fix race in vt_waitactive() serial/of-serial: Add LPC3220 standard UART compatible string serial/8250: Add LPC3220 standard UART type serial_core: Update buffer overrun statistics. serial: samsung: Fixed wrong comparison for baudclk_rate
This commit is contained in:
Коммит
c1e7179a38
|
@ -9,6 +9,7 @@ Required properties:
|
|||
- "ns16750"
|
||||
- "ns16850"
|
||||
- "nvidia,tegra20-uart"
|
||||
- "nxp,lpc3220-uart"
|
||||
- "ibm,qpace-nwp-serial"
|
||||
- "serial" if the port type is unknown.
|
||||
- reg : offset and length of the register set for the device.
|
||||
|
|
|
@ -282,6 +282,14 @@ static const struct serial8250_config uart_config[] = {
|
|||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||
.flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
|
||||
},
|
||||
[PORT_LPC3220] = {
|
||||
.name = "LPC3220",
|
||||
.fifo_size = 64,
|
||||
.tx_loadsz = 32,
|
||||
.fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO |
|
||||
UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
};
|
||||
|
||||
/* Uart divisor latch read */
|
||||
|
|
|
@ -208,6 +208,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
|
|||
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
|
||||
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
|
||||
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
|
||||
{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
|
||||
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
|
||||
{ .compatible = "ibm,qpace-nwp-serial",
|
||||
.data = (void *)PORT_NWPSERIAL, },
|
||||
|
|
|
@ -253,6 +253,9 @@ struct eg20t_port {
|
|||
dma_addr_t rx_buf_dma;
|
||||
|
||||
struct dentry *debugfs;
|
||||
|
||||
/* protect the eg20t_port private structure and io access to membase */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -754,7 +757,8 @@ static void pch_dma_rx_complete(void *arg)
|
|||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
async_tx_ack(priv->desc_rx);
|
||||
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||||
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
}
|
||||
|
||||
static void pch_dma_tx_complete(void *arg)
|
||||
|
@ -809,7 +813,8 @@ static int handle_rx_to(struct eg20t_port *priv)
|
|||
int rx_size;
|
||||
int ret;
|
||||
if (!priv->start_rx) {
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
return 0;
|
||||
}
|
||||
buf = &priv->rxbuf;
|
||||
|
@ -1058,7 +1063,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
int next = 1;
|
||||
u8 msr;
|
||||
|
||||
spin_lock_irqsave(&priv->port.lock, flags);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
handled = 0;
|
||||
while (next) {
|
||||
iid = pch_uart_hal_get_iid(priv);
|
||||
|
@ -1078,11 +1083,13 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
case PCH_UART_IID_RDR: /* Received Data Ready */
|
||||
if (priv->use_dma) {
|
||||
pch_uart_hal_disable_interrupt(priv,
|
||||
PCH_UART_HAL_RX_INT);
|
||||
PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
ret = dma_handle_rx(priv);
|
||||
if (!ret)
|
||||
pch_uart_hal_enable_interrupt(priv,
|
||||
PCH_UART_HAL_RX_INT);
|
||||
PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
} else {
|
||||
ret = handle_rx(priv);
|
||||
}
|
||||
|
@ -1116,7 +1123,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
handled |= (unsigned int)ret;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->port.lock, flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
@ -1208,7 +1215,8 @@ static void pch_uart_stop_rx(struct uart_port *port)
|
|||
struct eg20t_port *priv;
|
||||
priv = container_of(port, struct eg20t_port, port);
|
||||
priv->start_rx = 0;
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
}
|
||||
|
||||
/* Enable the modem status interrupts. */
|
||||
|
@ -1226,9 +1234,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl)
|
|||
unsigned long flags;
|
||||
|
||||
priv = container_of(port, struct eg20t_port, port);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
pch_uart_hal_set_break(priv, ctl);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
/* Grab any interrupt resources and initialise any low level driver state. */
|
||||
|
@ -1263,6 +1271,7 @@ static int pch_uart_startup(struct uart_port *port)
|
|||
break;
|
||||
case 16:
|
||||
fifo_size = PCH_UART_HAL_FIFO16;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
fifo_size = PCH_UART_HAL_FIFO_DIS;
|
||||
|
@ -1300,7 +1309,8 @@ static int pch_uart_startup(struct uart_port *port)
|
|||
pch_request_dma(port);
|
||||
|
||||
priv->start_rx = 1;
|
||||
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||||
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
uart_update_timeout(port, CS8, default_baud);
|
||||
|
||||
return 0;
|
||||
|
@ -1358,7 +1368,7 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|||
stb = PCH_UART_HAL_STB1;
|
||||
|
||||
if (termios->c_cflag & PARENB) {
|
||||
if (!(termios->c_cflag & PARODD))
|
||||
if (termios->c_cflag & PARODD)
|
||||
parity = PCH_UART_HAL_PARITY_ODD;
|
||||
else
|
||||
parity = PCH_UART_HAL_PARITY_EVEN;
|
||||
|
@ -1376,7 +1386,8 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
|
||||
|
@ -1389,7 +1400,8 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
spin_unlock(&port->lock);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static const char *pch_uart_type(struct uart_port *port)
|
||||
|
@ -1538,8 +1550,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|||
{
|
||||
struct eg20t_port *priv;
|
||||
unsigned long flags;
|
||||
int priv_locked = 1;
|
||||
int port_locked = 1;
|
||||
u8 ier;
|
||||
int locked = 1;
|
||||
|
||||
priv = pch_uart_ports[co->index];
|
||||
|
||||
|
@ -1547,12 +1560,16 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|||
|
||||
local_irq_save(flags);
|
||||
if (priv->port.sysrq) {
|
||||
/* serial8250_handle_port() already took the lock */
|
||||
locked = 0;
|
||||
spin_lock(&priv->lock);
|
||||
/* serial8250_handle_port() already took the port lock */
|
||||
port_locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&priv->port.lock);
|
||||
} else
|
||||
priv_locked = spin_trylock(&priv->lock);
|
||||
port_locked = spin_trylock(&priv->port.lock);
|
||||
} else {
|
||||
spin_lock(&priv->lock);
|
||||
spin_lock(&priv->port.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
|
@ -1570,8 +1587,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|||
wait_for_xmitr(priv, BOTH_EMPTY);
|
||||
iowrite8(ier, priv->membase + UART_IER);
|
||||
|
||||
if (locked)
|
||||
if (port_locked)
|
||||
spin_unlock(&priv->port.lock);
|
||||
if (priv_locked)
|
||||
spin_unlock(&priv->lock);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
@ -1669,6 +1688,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
pci_enable_msi(pdev);
|
||||
pci_set_master(pdev);
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
iobase = pci_resource_start(pdev, 0);
|
||||
mapbase = pci_resource_start(pdev, 1);
|
||||
priv->mapbase = mapbase;
|
||||
|
|
|
@ -1014,10 +1014,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
|
|||
* a disturbance in the clock-rate over the change.
|
||||
*/
|
||||
|
||||
if (IS_ERR(port->clk))
|
||||
if (IS_ERR(port->baudclk))
|
||||
goto exit;
|
||||
|
||||
if (port->baudclk_rate == clk_get_rate(port->clk))
|
||||
if (port->baudclk_rate == clk_get_rate(port->baudclk))
|
||||
goto exit;
|
||||
|
||||
if (val == CPUFREQ_PRECHANGE) {
|
||||
|
|
|
@ -2527,14 +2527,16 @@ void uart_insert_char(struct uart_port *port, unsigned int status,
|
|||
struct tty_struct *tty = port->state->port.tty;
|
||||
|
||||
if ((status & port->ignore_status_mask & ~overrun) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
if (tty_insert_flip_char(tty, ch, flag) == 0)
|
||||
++port->icount.buf_overrun;
|
||||
|
||||
/*
|
||||
* Overrun is special. Since it's reported immediately,
|
||||
* it doesn't affect the current character.
|
||||
*/
|
||||
if (status & ~port->ignore_status_mask & overrun)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
|
||||
++port->icount.buf_overrun;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_insert_char);
|
||||
|
||||
|
|
|
@ -659,7 +659,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
goto enable;
|
||||
}
|
||||
|
||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
if (test_bit(TTY_HUPPING, &tty->flags)) {
|
||||
/* We were raced by the hangup method. It will have stomped
|
||||
the ldisc data and closed the ldisc down */
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
|
|
|
@ -110,6 +110,34 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
|
|||
wake_up_interruptible(&vt_event_waitqueue);
|
||||
}
|
||||
|
||||
static void __vt_event_queue(struct vt_event_wait *vw)
|
||||
{
|
||||
unsigned long flags;
|
||||
/* Prepare the event */
|
||||
INIT_LIST_HEAD(&vw->list);
|
||||
vw->done = 0;
|
||||
/* Queue our event */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_add(&vw->list, &vt_events);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
}
|
||||
|
||||
static void __vt_event_wait(struct vt_event_wait *vw)
|
||||
{
|
||||
/* Wait for it to pass */
|
||||
wait_event_interruptible(vt_event_waitqueue, vw->done);
|
||||
}
|
||||
|
||||
static void __vt_event_dequeue(struct vt_event_wait *vw)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* Dequeue it */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_del(&vw->list);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_event_wait - wait for an event
|
||||
* @vw: our event
|
||||
|
@ -121,20 +149,9 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
|
|||
|
||||
static void vt_event_wait(struct vt_event_wait *vw)
|
||||
{
|
||||
unsigned long flags;
|
||||
/* Prepare the event */
|
||||
INIT_LIST_HEAD(&vw->list);
|
||||
vw->done = 0;
|
||||
/* Queue our event */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_add(&vw->list, &vt_events);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
/* Wait for it to pass */
|
||||
wait_event_interruptible(vt_event_waitqueue, vw->done);
|
||||
/* Dequeue it */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_del(&vw->list);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
__vt_event_queue(vw);
|
||||
__vt_event_wait(vw);
|
||||
__vt_event_dequeue(vw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,10 +194,14 @@ int vt_waitactive(int n)
|
|||
{
|
||||
struct vt_event_wait vw;
|
||||
do {
|
||||
if (n == fg_console + 1)
|
||||
break;
|
||||
vw.event.event = VT_EVENT_SWITCH;
|
||||
vt_event_wait(&vw);
|
||||
__vt_event_queue(&vw);
|
||||
if (n == fg_console + 1) {
|
||||
__vt_event_dequeue(&vw);
|
||||
break;
|
||||
}
|
||||
__vt_event_wait(&vw);
|
||||
__vt_event_dequeue(&vw);
|
||||
if (vw.done == 0)
|
||||
return -EINTR;
|
||||
} while (vw.event.newev != n);
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */
|
||||
#define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */
|
||||
#define PORT_XR17D15X 21 /* Exar XR17D15x UART */
|
||||
#define PORT_MAX_8250 21 /* max port ID */
|
||||
#define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */
|
||||
#define PORT_MAX_8250 22 /* max port ID */
|
||||
|
||||
/*
|
||||
* ARM specific type numbers. These are not currently guaranteed
|
||||
|
|
Загрузка…
Ссылка в новой задаче