aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/serial_txx9.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2006-03-22 03:07:45 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-22 10:53:55 -0500
commit83485f826bea154a0ab41e9b8689105531dd7cb2 (patch)
tree0413f90dda66cabbbcbe076cea5a03cb1982c5bf /drivers/serial/serial_txx9.c
parent4024ce5e0f396447cc1e07fd65c2a1d056b066bb (diff)
[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: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/serial/serial_txx9.c')
-rw-r--r--drivers/serial/serial_txx9.c77
1 files changed, 41 insertions, 36 deletions
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index ee98a867bc6d..141173efd463 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -33,6 +33,10 @@
33 * 1.02 Cleanup. (import 8250.c changes) 33 * 1.02 Cleanup. (import 8250.c changes)
34 * 1.03 Fix low-latency mode. (import 8250.c changes) 34 * 1.03 Fix low-latency mode. (import 8250.c changes)
35 * 1.04 Remove usage of deprecated functions, cleanup. 35 * 1.04 Remove usage of deprecated functions, cleanup.
36 * 1.05 More strict check in verify_port. Cleanup.
37 * 1.06 Do not insert a char caused previous overrun.
38 * Fix some spin_locks.
39 * Do not call uart_add_one_port for absent ports.
36 */ 40 */
37#include <linux/config.h> 41#include <linux/config.h>
38 42
@@ -57,7 +61,7 @@
57#include <asm/io.h> 61#include <asm/io.h>
58#include <asm/irq.h> 62#include <asm/irq.h>
59 63
60static char *serial_version = "1.04"; 64static char *serial_version = "1.06";
61static char *serial_name = "TX39/49 Serial driver"; 65static char *serial_name = "TX39/49 Serial driver";
62 66
63#define PASS_LIMIT 256 67#define PASS_LIMIT 256
@@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver";
94#define UART_NR 4 98#define UART_NR 4
95#endif 99#endif
96 100
101#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
102
97struct uart_txx9_port { 103struct uart_txx9_port {
98 struct uart_port port; 104 struct uart_port port;
99 105
@@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
210{ 216{
211 switch (up->port.iotype) { 217 switch (up->port.iotype) {
212 default: 218 default:
213 return *(volatile u32 *)(up->port.membase + offset); 219 return __raw_readl(up->port.membase + offset);
214 case UPIO_PORT: 220 case UPIO_PORT:
215 return inl(up->port.iobase + offset); 221 return inl(up->port.iobase + offset);
216 } 222 }
@@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value)
221{ 227{
222 switch (up->port.iotype) { 228 switch (up->port.iotype) {
223 default: 229 default:
224 *(volatile u32 *)(up->port.membase + offset) = value; 230 __raw_writel(value, up->port.membase + offset);
225 break; 231 break;
226 case UPIO_PORT: 232 case UPIO_PORT:
227 outl(value, up->port.iobase + offset); 233 outl(value, up->port.iobase + offset);
@@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
259static void serial_txx9_stop_tx(struct uart_port *port) 265static void serial_txx9_stop_tx(struct uart_port *port)
260{ 266{
261 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 267 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
262 unsigned long flags;
263
264 spin_lock_irqsave(&up->port.lock, flags);
265 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); 268 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
266 spin_unlock_irqrestore(&up->port.lock, flags);
267} 269}
268 270
269static void serial_txx9_start_tx(struct uart_port *port) 271static void serial_txx9_start_tx(struct uart_port *port)
270{ 272{
271 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 273 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
272 unsigned long flags;
273
274 spin_lock_irqsave(&up->port.lock, flags);
275 sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); 274 sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
276 spin_unlock_irqrestore(&up->port.lock, flags);
277} 275}
278 276
279static void serial_txx9_stop_rx(struct uart_port *port) 277static void serial_txx9_stop_rx(struct uart_port *port)
280{ 278{
281 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 279 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
282 unsigned long flags;
283
284 spin_lock_irqsave(&up->port.lock, flags);
285 up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; 280 up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
286#if 0
287 sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
288#endif
289 spin_unlock_irqrestore(&up->port.lock, flags);
290} 281}
291 282
292static void serial_txx9_enable_ms(struct uart_port *port) 283static 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 unsigned int disr = *status; 293 unsigned int disr = *status;
303 int max_count = 256; 294 int max_count = 256;
304 char flag; 295 char flag;
296 unsigned int next_ignore_status_mask;
305 297
306 do { 298 do {
307 ch = sio_in(up, TXX9_SIRFIFO); 299 ch = sio_in(up, TXX9_SIRFIFO);
308 flag = TTY_NORMAL; 300 flag = TTY_NORMAL;
309 up->port.icount.rx++; 301 up->port.icount.rx++;
310 302
303 /* mask out RFDN_MASK bit added by previous overrun */
304 next_ignore_status_mask =
305 up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
311 if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | 306 if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
312 TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { 307 TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
313 /* 308 /*
@@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
328 up->port.icount.parity++; 323 up->port.icount.parity++;
329 else if (disr & TXX9_SIDISR_UFER) 324 else if (disr & TXX9_SIDISR_UFER)
330 up->port.icount.frame++; 325 up->port.icount.frame++;
331 if (disr & TXX9_SIDISR_UOER) 326 if (disr & TXX9_SIDISR_UOER) {
332 up->port.icount.overrun++; 327 up->port.icount.overrun++;
328 /*
329 * The receiver read buffer still hold
330 * a char which caused overrun.
331 * Ignore next char by adding RFDN_MASK
332 * to ignore_status_mask temporarily.
333 */
334 next_ignore_status_mask |=
335 TXX9_SIDISR_RFDN_MASK;
336 }
333 337
334 /* 338 /*
335 * Mask off conditions which should be ingored. 339 * 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 uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); 353 uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
350 354
351 ignore_char: 355 ignore_char:
356 up->port.ignore_status_mask = next_ignore_status_mask;
352 disr = sio_in(up, TXX9_SIDISR); 357 disr = sio_in(up, TXX9_SIDISR);
353 } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); 358 } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
354 spin_unlock(&up->port.lock); 359 spin_unlock(&up->port.lock);
@@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
450static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) 455static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
451{ 456{
452 struct uart_txx9_port *up = (struct uart_txx9_port *)port; 457 struct uart_txx9_port *up = (struct uart_txx9_port *)port;
453 unsigned long flags;
454 458
455 spin_lock_irqsave(&up->port.lock, flags);
456 if (mctrl & TIOCM_RTS) 459 if (mctrl & TIOCM_RTS)
457 sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); 460 sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
458 else 461 else
459 sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); 462 sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
460 spin_unlock_irqrestore(&up->port.lock, flags);
461} 463}
462 464
463static void serial_txx9_break_ctl(struct uart_port *port, int break_state) 465static 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)
784static int 786static int
785serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) 787serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
786{ 788{
787 if (ser->irq < 0 || 789 unsigned long new_port = ser->port;
788 ser->baud_base < 9600 || ser->type != PORT_TXX9) 790 if (HIGH_BITS_OFFSET)
791 new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
792 if (ser->type != port->type ||
793 ser->irq != port->irq ||
794 ser->io_type != port->iotype ||
795 new_port != port->iobase ||
796 (unsigned long)ser->iomem_base != port->mapbase)
789 return -EINVAL; 797 return -EINVAL;
790 return 0; 798 return 0;
791} 799}
@@ -827,7 +835,8 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
827 835
828 up->port.line = i; 836 up->port.line = i;
829 up->port.ops = &serial_txx9_pops; 837 up->port.ops = &serial_txx9_pops;
830 uart_add_one_port(drv, &up->port); 838 if (up->port.iobase || up->port.mapbase)
839 uart_add_one_port(drv, &up->port);
831 } 840 }
832} 841}
833 842
@@ -927,11 +936,6 @@ static int serial_txx9_console_setup(struct console *co, char *options)
927 return -ENODEV; 936 return -ENODEV;
928 937
929 /* 938 /*
930 * Temporary fix.
931 */
932 spin_lock_init(&port->lock);
933
934 /*
935 * Disable UART interrupts, set DTR and RTS high 939 * Disable UART interrupts, set DTR and RTS high
936 * and set speed. 940 * and set speed.
937 */ 941 */
@@ -1041,11 +1045,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
1041 mutex_lock(&serial_txx9_mutex); 1045 mutex_lock(&serial_txx9_mutex);
1042 for (i = 0; i < UART_NR; i++) { 1046 for (i = 0; i < UART_NR; i++) {
1043 uart = &serial_txx9_ports[i]; 1047 uart = &serial_txx9_ports[i];
1044 if (uart->port.type == PORT_UNKNOWN) 1048 if (!(uart->port.iobase || uart->port.mapbase))
1045 break; 1049 break;
1046 } 1050 }
1047 if (i < UART_NR) { 1051 if (i < UART_NR) {
1048 uart_remove_one_port(&serial_txx9_reg, &uart->port);
1049 uart->port.iobase = port->iobase; 1052 uart->port.iobase = port->iobase;
1050 uart->port.membase = port->membase; 1053 uart->port.membase = port->membase;
1051 uart->port.irq = port->irq; 1054 uart->port.irq = port->irq;
@@ -1080,9 +1083,8 @@ static void __devexit serial_txx9_unregister_port(int line)
1080 uart->port.type = PORT_UNKNOWN; 1083 uart->port.type = PORT_UNKNOWN;
1081 uart->port.iobase = 0; 1084 uart->port.iobase = 0;
1082 uart->port.mapbase = 0; 1085 uart->port.mapbase = 0;
1083 uart->port.membase = 0; 1086 uart->port.membase = NULL;
1084 uart->port.dev = NULL; 1087 uart->port.dev = NULL;
1085 uart_add_one_port(&serial_txx9_reg, &uart->port);
1086 mutex_unlock(&serial_txx9_mutex); 1088 mutex_unlock(&serial_txx9_mutex);
1087} 1089}
1088 1090
@@ -1198,8 +1200,11 @@ static void __exit serial_txx9_exit(void)
1198#ifdef ENABLE_SERIAL_TXX9_PCI 1200#ifdef ENABLE_SERIAL_TXX9_PCI
1199 pci_unregister_driver(&serial_txx9_pci_driver); 1201 pci_unregister_driver(&serial_txx9_pci_driver);
1200#endif 1202#endif
1201 for (i = 0; i < UART_NR; i++) 1203 for (i = 0; i < UART_NR; i++) {
1202 uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port); 1204 struct uart_txx9_port *up = &serial_txx9_ports[i];
1205 if (up->port.iobase || up->port.mapbase)
1206 uart_remove_one_port(&serial_txx9_reg, &up->port);
1207 }
1203 1208
1204 uart_unregister_driver(&serial_txx9_reg); 1209 uart_unregister_driver(&serial_txx9_reg);
1205} 1210}