Commit 83485f82 authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Linus Torvalds

[PATCH] serial: serial_txx9 driver update

Update the serial_txx9 driver.

 * More strict check in verify_port.  Cleanup.
 * Do not insert a char caused previous overrun.
 * Fix some spin_locks.
 * Do not call uart_add_one_port for absent ports.

Also, this patch removes a BROKEN tag from Kconfig.  This driver has been
marked as BROKEN by removal of uart_register_port, but it has been solved
already on Sep 2005.
Signed-off-by: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4024ce5e
...@@ -866,7 +866,7 @@ config SERIAL_M32R_PLDSIO ...@@ -866,7 +866,7 @@ config SERIAL_M32R_PLDSIO
config SERIAL_TXX9 config SERIAL_TXX9
bool "TMPTX39XX/49XX SIO support" bool "TMPTX39XX/49XX SIO support"
depends HAS_TXX9_SERIAL && BROKEN depends HAS_TXX9_SERIAL
select SERIAL_CORE select SERIAL_CORE
default y default y
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
* 1.02 Cleanup. (import 8250.c changes) * 1.02 Cleanup. (import 8250.c changes)
* 1.03 Fix low-latency mode. (import 8250.c changes) * 1.03 Fix low-latency mode. (import 8250.c changes)
* 1.04 Remove usage of deprecated functions, cleanup. * 1.04 Remove usage of deprecated functions, cleanup.
* 1.05 More strict check in verify_port. Cleanup.
* 1.06 Do not insert a char caused previous overrun.
* Fix some spin_locks.
* Do not call uart_add_one_port for absent ports.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -57,7 +61,7 @@ ...@@ -57,7 +61,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
static char *serial_version = "1.04"; static char *serial_version = "1.06";
static char *serial_name = "TX39/49 Serial driver"; static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256 #define PASS_LIMIT 256
...@@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver"; ...@@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver";
#define UART_NR 4 #define UART_NR 4
#endif #endif
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
struct uart_txx9_port { struct uart_txx9_port {
struct uart_port port; struct uart_port port;
...@@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset) ...@@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
{ {
switch (up->port.iotype) { switch (up->port.iotype) {
default: default:
return *(volatile u32 *)(up->port.membase + offset); return __raw_readl(up->port.membase + offset);
case UPIO_PORT: case UPIO_PORT:
return inl(up->port.iobase + offset); return inl(up->port.iobase + offset);
} }
...@@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value) ...@@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value)
{ {
switch (up->port.iotype) { switch (up->port.iotype) {
default: default:
*(volatile u32 *)(up->port.membase + offset) = value; __raw_writel(value, up->port.membase + offset);
break; break;
case UPIO_PORT: case UPIO_PORT:
outl(value, up->port.iobase + offset); outl(value, up->port.iobase + offset);
...@@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot) ...@@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
static void serial_txx9_stop_tx(struct uart_port *port) static void serial_txx9_stop_tx(struct uart_port *port)
{ {
struct uart_txx9_port *up = (struct uart_txx9_port *)port; struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
spin_unlock_irqrestore(&up->port.lock, flags);
} }
static void serial_txx9_start_tx(struct uart_port *port) static void serial_txx9_start_tx(struct uart_port *port)
{ {
struct uart_txx9_port *up = (struct uart_txx9_port *)port; struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
spin_unlock_irqrestore(&up->port.lock, flags);
} }
static void serial_txx9_stop_rx(struct uart_port *port) static void serial_txx9_stop_rx(struct uart_port *port)
{ {
struct uart_txx9_port *up = (struct uart_txx9_port *)port; struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
#if 0
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
#endif
spin_unlock_irqrestore(&up->port.lock, flags);
} }
static void serial_txx9_enable_ms(struct uart_port *port) static void serial_txx9_enable_ms(struct uart_port *port)
...@@ -302,12 +293,16 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r ...@@ -302,12 +293,16 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
unsigned int disr = *status; unsigned int disr = *status;
int max_count = 256; int max_count = 256;
char flag; char flag;
unsigned int next_ignore_status_mask;
do { do {
ch = sio_in(up, TXX9_SIRFIFO); ch = sio_in(up, TXX9_SIRFIFO);
flag = TTY_NORMAL; flag = TTY_NORMAL;
up->port.icount.rx++; up->port.icount.rx++;
/* mask out RFDN_MASK bit added by previous overrun */
next_ignore_status_mask =
up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
/* /*
...@@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r ...@@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
up->port.icount.parity++; up->port.icount.parity++;
else if (disr & TXX9_SIDISR_UFER) else if (disr & TXX9_SIDISR_UFER)
up->port.icount.frame++; up->port.icount.frame++;
if (disr & TXX9_SIDISR_UOER) if (disr & TXX9_SIDISR_UOER) {
up->port.icount.overrun++; up->port.icount.overrun++;
/*
* The receiver read buffer still hold
* a char which caused overrun.
* Ignore next char by adding RFDN_MASK
* to ignore_status_mask temporarily.
*/
next_ignore_status_mask |=
TXX9_SIDISR_RFDN_MASK;
}
/* /*
* Mask off conditions which should be ingored. * Mask off conditions which should be ingored.
...@@ -349,6 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r ...@@ -349,6 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
ignore_char: ignore_char:
up->port.ignore_status_mask = next_ignore_status_mask;
disr = sio_in(up, TXX9_SIDISR); disr = sio_in(up, TXX9_SIDISR);
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
spin_unlock(&up->port.lock); spin_unlock(&up->port.lock);
...@@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port) ...@@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct uart_txx9_port *up = (struct uart_txx9_port *)port; struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
if (mctrl & TIOCM_RTS) if (mctrl & TIOCM_RTS)
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
else else
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
spin_unlock_irqrestore(&up->port.lock, flags);
} }
static void serial_txx9_break_ctl(struct uart_port *port, int break_state) static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
...@@ -784,8 +786,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) ...@@ -784,8 +786,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
static int static int
serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
{ {
if (ser->irq < 0 || unsigned long new_port = ser->port;
ser->baud_base < 9600 || ser->type != PORT_TXX9) if (HIGH_BITS_OFFSET)
new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
if (ser->type != port->type ||
ser->irq != port->irq ||
ser->io_type != port->iotype ||
new_port != port->iobase ||
(unsigned long)ser->iomem_base != port->mapbase)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
...@@ -827,7 +835,8 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv) ...@@ -827,7 +835,8 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
up->port.line = i; up->port.line = i;
up->port.ops = &serial_txx9_pops; up->port.ops = &serial_txx9_pops;
uart_add_one_port(drv, &up->port); if (up->port.iobase || up->port.mapbase)
uart_add_one_port(drv, &up->port);
} }
} }
...@@ -926,11 +935,6 @@ static int serial_txx9_console_setup(struct console *co, char *options) ...@@ -926,11 +935,6 @@ static int serial_txx9_console_setup(struct console *co, char *options)
if (!port->ops) if (!port->ops)
return -ENODEV; return -ENODEV;
/*
* Temporary fix.
*/
spin_lock_init(&port->lock);
/* /*
* Disable UART interrupts, set DTR and RTS high * Disable UART interrupts, set DTR and RTS high
* and set speed. * and set speed.
...@@ -1041,11 +1045,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) ...@@ -1041,11 +1045,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
mutex_lock(&serial_txx9_mutex); mutex_lock(&serial_txx9_mutex);
for (i = 0; i < UART_NR; i++) { for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i]; uart = &serial_txx9_ports[i];
if (uart->port.type == PORT_UNKNOWN) if (!(uart->port.iobase || uart->port.mapbase))
break; break;
} }
if (i < UART_NR) { if (i < UART_NR) {
uart_remove_one_port(&serial_txx9_reg, &uart->port);
uart->port.iobase = port->iobase; uart->port.iobase = port->iobase;
uart->port.membase = port->membase; uart->port.membase = port->membase;
uart->port.irq = port->irq; uart->port.irq = port->irq;
...@@ -1080,9 +1083,8 @@ static void __devexit serial_txx9_unregister_port(int line) ...@@ -1080,9 +1083,8 @@ static void __devexit serial_txx9_unregister_port(int line)
uart->port.type = PORT_UNKNOWN; uart->port.type = PORT_UNKNOWN;
uart->port.iobase = 0; uart->port.iobase = 0;
uart->port.mapbase = 0; uart->port.mapbase = 0;
uart->port.membase = 0; uart->port.membase = NULL;
uart->port.dev = NULL; uart->port.dev = NULL;
uart_add_one_port(&serial_txx9_reg, &uart->port);
mutex_unlock(&serial_txx9_mutex); mutex_unlock(&serial_txx9_mutex);
} }
...@@ -1198,8 +1200,11 @@ static void __exit serial_txx9_exit(void) ...@@ -1198,8 +1200,11 @@ static void __exit serial_txx9_exit(void)
#ifdef ENABLE_SERIAL_TXX9_PCI #ifdef ENABLE_SERIAL_TXX9_PCI
pci_unregister_driver(&serial_txx9_pci_driver); pci_unregister_driver(&serial_txx9_pci_driver);
#endif #endif
for (i = 0; i < UART_NR; i++) for (i = 0; i < UART_NR; i++) {
uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port); struct uart_txx9_port *up = &serial_txx9_ports[i];
if (up->port.iobase || up->port.mapbase)
uart_remove_one_port(&serial_txx9_reg, &up->port);
}
uart_unregister_driver(&serial_txx9_reg); uart_unregister_driver(&serial_txx9_reg);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment