From 5c8c755ce508a9d41d8a8d80fff387cb4e2929fc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 12 Nov 2005 21:58:05 +0000 Subject: [PATCH 1/7] [SERIAL] don't disable xscale serial ports after autoconfig xscale-type UARTs have an extra bit (UUE) in the IER register that has to be written as 1 to enable the UART. At the end of autoconfig() in drivers/serial/8250.c, the IER register is unconditionally written as zero, which turns off the UART, and makes any subsequent printch() hang the box. Since other 8250-type UARTs don't have this enable bit and are thus always 'enabled' in this sense, it can't hurt to enable xscale-type serial ports all the time as well. The attached patch changes the autoconfig() exit path to see if the port has an UUE enable bit, and if yes, to write UUE=1 instead of just putting a zero into IER, using the same test as is used at the beginning of serial8250_console_write(). Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- drivers/serial/8250.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 3742753241ee..e08510d09ff6 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -999,7 +999,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) serial_outp(up, UART_MCR, save_mcr); serial8250_clear_fifos(up); (void)serial_in(up, UART_RX); - serial_outp(up, UART_IER, 0); + if (up->capabilities & UART_CAP_UUE) + serial_outp(up, UART_IER, UART_IER_UUE); + else + serial_outp(up, UART_IER, 0); out: spin_unlock_irqrestore(&up->port.lock, flags); From fd8c597214f868df7c0055c54e27baaae8df9e70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 12 Nov 2005 21:59:59 +0000 Subject: [PATCH 2/7] [SERIAL] dz: Nuke trailing whitespace Signed-off-by: Ralf Baechle Signed-off-by: Russell King --- drivers/serial/dz.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index e63b9dffc8d7..84840f445345 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -1,9 +1,9 @@ /* - * dz.c: Serial port driver for DECStations equiped + * dz.c: Serial port driver for DECStations equiped * with the DZ chipset. * - * Copyright (C) 1998 Olivier A. D. Lebaillif - * + * Copyright (C) 1998 Olivier A. D. Lebaillif + * * Email: olivier.lebaillif@ifrsys.com * * [31-AUG-98] triemer @@ -11,14 +11,14 @@ * removed base_addr code - moving address assignment to setup.c * Changed name of dz_init to rs_init to be consistent with tc code * [13-NOV-98] triemer fixed code to receive characters - * after patches by harald to irq code. + * after patches by harald to irq code. * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout * field from "current" - somewhere between 2.1.121 and 2.1.131 Qua Jun 27 15:02:26 BRT 2001 * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups - * - * Parts (C) 1999 David Airlie, airlied@linux.ie - * [07-SEP-99] Bugfixes + * + * Parts (C) 1999 David Airlie, airlied@linux.ie + * [07-SEP-99] Bugfixes * * [06-Jan-2002] Russell King * Converted to new serial core @@ -64,7 +64,7 @@ static struct dz_port dz_ports[DZ_NB_PORT]; #ifdef DEBUG_DZ /* - * debugging code to send out chars via prom + * debugging code to send out chars via prom */ static void debug_console(const char *s, int count) { @@ -82,7 +82,7 @@ static void debug_console(const char *s, int count) * ------------------------------------------------------------ * dz_in () and dz_out () * - * These routines are used to access the registers of the DZ + * These routines are used to access the registers of the DZ * chip, hiding relocation differences between implementation. * ------------------------------------------------------------ */ @@ -106,8 +106,8 @@ static inline void dz_out(struct dz_port *dport, unsigned offset, * ------------------------------------------------------------ * rs_stop () and rs_start () * - * These routines are called before setting or resetting - * tty->stopped. They enable or disable transmitter interrupts, + * These routines are called before setting or resetting + * tty->stopped. They enable or disable transmitter interrupts, * as necessary. * ------------------------------------------------------------ */ @@ -156,17 +156,17 @@ static void dz_enable_ms(struct uart_port *port) /* * ------------------------------------------------------------ - * Here starts the interrupt handling routines. All of the - * following subroutines are declared as inline and are folded - * into dz_interrupt. They were separated out for readability's - * sake. + * Here starts the interrupt handling routines. All of the + * following subroutines are declared as inline and are folded + * into dz_interrupt. They were separated out for readability's + * sake. * * Note: rs_interrupt() is a "fast" interrupt, which means that it * runs with interrupts turned off. People who may want to modify * rs_interrupt() should try to keep the interrupt handler as fast as * possible. After you are done making modifications, it is not a bad * idea to do: - * + * * make drivers/serial/dz.s * * and look at the resulting assemble code in dz.s. @@ -403,7 +403,7 @@ static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl) * startup () * * various initialization tasks - * ------------------------------------------------------------------- + * ------------------------------------------------------------------- */ static int dz_startup(struct uart_port *uport) { @@ -430,13 +430,13 @@ static int dz_startup(struct uart_port *uport) return 0; } -/* +/* * ------------------------------------------------------------------- * shutdown () * * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. - * ------------------------------------------------------------------- + * ------------------------------------------------------------------- */ static void dz_shutdown(struct uart_port *uport) { @@ -451,7 +451,7 @@ static void dz_shutdown(struct uart_port *uport) * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. + * allows an RS485 driver to be written in user space. */ static unsigned int dz_tx_empty(struct uart_port *uport) { @@ -695,13 +695,13 @@ static void dz_console_put_char(struct dz_port *dport, unsigned char ch) spin_unlock_irqrestore(&dport->port.lock, flags); } -/* +/* * ------------------------------------------------------------------- * dz_console_print () * * dz_console_print is registered for printk. * The console must be locked when we get here. - * ------------------------------------------------------------------- + * ------------------------------------------------------------------- */ static void dz_console_print(struct console *cons, const char *str, From 46677736bec5c44601987e8780e55bc242e0aa46 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 12 Nov 2005 22:00:27 +0000 Subject: [PATCH 3/7] [SERIAL] dz: Use CKSEG1ADDR to setup mappings. Use physical addresses at the interface level, letting drivers remap them as appropriate. Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle Signed-off-by: Russell King --- drivers/serial/dz.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index 84840f445345..4d8516d1bb71 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -645,9 +645,9 @@ static void __init dz_init_ports(void) if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100) - base = (unsigned long) KN01_DZ11_BASE; + base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_DZ11); else - base = (unsigned long) KN02_DZ11_BASE; + base = CKSEG1ADDR(KN02_SLOT_BASE + KN02_DZ11); for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) { spin_lock_init(&dport->port.lock); From 38801e2e54308ec52fc580c0fcdee98fe8696195 Mon Sep 17 00:00:00 2001 From: Andrey Volkov Date: Sat, 12 Nov 2005 22:04:06 +0000 Subject: [PATCH 4/7] [SERIAL] Fix mpc52xx_uart.c Fix copy-paste bug in mpc52xx_uart.c (pdev<->dev) Signed-off-by: Andrey Volkov Signed-off-by: Russell King --- drivers/serial/mpc52xx_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 5d3cb8486447..b8727d9bf690 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -725,7 +725,7 @@ mpc52xx_uart_probe(struct platform_device *dev) int i, idx, ret; /* Check validity & presence */ - idx = pdev->id; + idx = dev->id; if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM) return -EINVAL; @@ -748,7 +748,7 @@ mpc52xx_uart_probe(struct platform_device *dev) port->ops = &mpc52xx_uart_ops; /* Search for IRQ and mapbase */ - for (i=0 ; inum_resources ; i++, res++) { + for (i=0 ; inum_resources ; i++, res++) { if (res->flags & IORESOURCE_MEM) port->mapbase = res->start; else if (res->flags & IORESOURCE_IRQ) From fa609435a6edaaca14a646d470d7e10abebc8604 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sat, 12 Nov 2005 22:06:31 +0000 Subject: [PATCH 5/7] [SERIAL] Claim Wacom tablet device on HP tc1100 tablet Claim the WACF005 device. This is the pen display pointing device on the HP Compaq tc1100 Tablet PC. More information about using this device, including using it as an X pointer device: http://www.theory.bham.ac.uk/staff/schofield/linux/tc1100/ Christopher Kemp did the legwork of determining that the WACF005 is really just a plain old UART and doing an initial ACPI driver (before we had PNPACPI), and David Ludlow confirmed that PNPACPI + the attached patch is now sufficient: pnp: Device 00:05 activated. ttyS4 at I/O 0x300 (irq = 4) is a 16550A Signed-off-by: Bjorn Helgaas Signed-off-by: Russell King --- drivers/serial/8250_pnp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index 5d8660a42b77..b79ed0665d51 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -323,6 +323,8 @@ static const struct pnp_device_id pnp_dev_table[] = { { "USR9180", 0 }, /* U.S. Robotics 56K Voice INT PnP*/ { "USR9190", 0 }, + /* HP Compaq Tablet PC tc1100 Wacom tablet */ + { "WACF005", 0 }, /* Rockwell's (PORALiNK) 33600 INT PNP */ { "WCI0003", 0 }, /* Unkown PnP modems */ From 270c7a721548d116d9e054f48469e75cb0f35288 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Sat, 12 Nov 2005 22:09:22 +0000 Subject: [PATCH 6/7] [SERIAL] sa1100_start_tx spinlock recursion The serial core aquires the port spinlock before calling port->ops->start_tx(), so sa1100_start_tx() shouldn't try to lock it again. BUG: spinlock recursion on CPU#0, init/1 lock: c0205f20, .magic: dead4ead, .owner: init/1, .owner_cpu: 0 [] (dump_stack+0x0/0x14) [] (spin_bug+0x0/0xbc) [] (_raw_spin_lock+0x0/0x170) r8 = 00000007 r7 = C02FE0070 [] (_spin_lock_irqsave+0x0/0x24) r4 = C0205F20 [] (sa1100_start_tx+0x0/0x40) r4 = C038C000 [] (__uart_start+0x0/0x5c) [] (uart_start+0x0/0x3 [] (uart_write+0x0/0xdc) [] (write_chan+0x0/0x370 Signed-off-by: Florin Malita Signed-off-by: Russell King --- drivers/serial/sa1100.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index fd9deee20e05..0e3daf6d7b50 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -156,7 +156,7 @@ static void sa1100_stop_tx(struct uart_port *port) } /* - * interrupts may not be disabled on entry + * port locked and interrupts disabled */ static void sa1100_start_tx(struct uart_port *port) { @@ -164,11 +164,9 @@ static void sa1100_start_tx(struct uart_port *port) unsigned long flags; u32 utcr3; - spin_lock_irqsave(&sport->port.lock, flags); utcr3 = UART_GET_UTCR3(sport); sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS); UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE); - spin_unlock_irqrestore(&sport->port.lock, flags); } /* From ee31b337852ca8a65840702544ff5c64d37740f5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 13 Nov 2005 15:28:51 +0000 Subject: [PATCH 7/7] [SERIAL] Fix Bug 4900: S3 resume oops with irattach - Thinkpad A21m If we fail to re-startup a serial port on resume, shut it down immediately and mark it as an error condition. Signed-off-by: Russell King --- drivers/serial/serial_core.c | 92 +++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 427a23858076..2331296e1e17 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -209,33 +209,45 @@ static void uart_shutdown(struct uart_state *state) struct uart_info *info = state->info; struct uart_port *port = state->port; - if (!(info->flags & UIF_INITIALIZED)) - return; + /* + * Set the TTY IO error marker + */ + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + if (info->flags & UIF_INITIALIZED) { + info->flags &= ~UIF_INITIALIZED; + + /* + * Turn off DTR and RTS early. + */ + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free + * the irq here so the queue might never be woken up. Note + * that we won't end up waiting on delta_msr_wait again since + * any outstanding file descriptors should be pointing at + * hung_up_tty_fops now. + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ and disable the port. + */ + port->ops->shutdown(port); + + /* + * Ensure that the IRQ handler isn't running on another CPU. + */ + synchronize_irq(port->irq); + } /* - * Turn off DTR and RTS early. + * kill off our tasklet */ - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free - * the irq here so the queue might never be woken up. Note - * that we won't end up waiting on delta_msr_wait again since - * any outstanding file descriptors should be pointing at - * hung_up_tty_fops now. - */ - wake_up_interruptible(&info->delta_msr_wait); - - /* - * Free the IRQ and disable the port. - */ - port->ops->shutdown(port); - - /* - * Ensure that the IRQ handler isn't running on another CPU. - */ - synchronize_irq(port->irq); + tasklet_kill(&info->tlet); /* * Free the transmit buffer page. @@ -244,15 +256,6 @@ static void uart_shutdown(struct uart_state *state) free_page((unsigned long)info->xmit.buf); info->xmit.buf = NULL; } - - /* - * kill off our tasklet - */ - tasklet_kill(&info->tlet); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~UIF_INITIALIZED; } /** @@ -1928,14 +1931,25 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) if (state->info && state->info->flags & UIF_INITIALIZED) { struct uart_ops *ops = port->ops; + int ret; ops->set_mctrl(port, 0); - ops->startup(port); - uart_change_speed(state, NULL); - spin_lock_irq(&port->lock); - ops->set_mctrl(port, port->mctrl); - ops->start_tx(port); - spin_unlock_irq(&port->lock); + ret = ops->startup(port); + if (ret == 0) { + uart_change_speed(state, NULL); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, port->mctrl); + ops->start_tx(port); + spin_unlock_irq(&port->lock); + } else { + /* + * Failed to resume - maybe hardware went away? + * Clear the "initialized" flag so we won't try + * to call the low level drivers shutdown method. + */ + state->info->flags &= ~UIF_INITIALIZED; + uart_shutdown(state); + } } up(&state->sem);