diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
| commit | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch) | |
| tree | f5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /drivers/serial/serial_txx9.c | |
| parent | ac58c9059da8886b5e8cde012a80266b18ca146e (diff) | |
| parent | 674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff) | |
Merge branch 'linus'
Diffstat (limited to 'drivers/serial/serial_txx9.c')
| -rw-r--r-- | drivers/serial/serial_txx9.c | 103 |
1 files changed, 50 insertions, 53 deletions
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index ee98a867bc6d..b848b7d94412 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 | ||
| 60 | static char *serial_version = "1.04"; | 64 | static char *serial_version = "1.06"; |
| 61 | static char *serial_name = "TX39/49 Serial driver"; | 65 | static 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 | |||
| 97 | struct uart_txx9_port { | 103 | struct 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) | |||
| 259 | static void serial_txx9_stop_tx(struct uart_port *port) | 265 | static 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 | ||
| 269 | static void serial_txx9_start_tx(struct uart_port *port) | 271 | static 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 | ||
| 279 | static void serial_txx9_stop_rx(struct uart_port *port) | 277 | static 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 | ||
| 292 | static void serial_txx9_enable_ms(struct uart_port *port) | 283 | 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 | 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) | |||
| 450 | static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) | 455 | static 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 | ||
| 463 | static void serial_txx9_break_ctl(struct uart_port *port, int break_state) | 465 | 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 | static int | 786 | static int |
| 785 | serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser) | 787 | serial_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 | ||
| @@ -854,6 +863,14 @@ static inline void wait_for_xmitr(struct uart_txx9_port *up) | |||
| 854 | } | 863 | } |
| 855 | } | 864 | } |
| 856 | 865 | ||
| 866 | static void serial_txx9_console_putchar(struct uart_port *port, int ch) | ||
| 867 | { | ||
| 868 | struct uart_txx9_port *up = (struct uart_txx9_port *)port; | ||
| 869 | |||
| 870 | wait_for_xmitr(up); | ||
| 871 | sio_out(up, TXX9_SITFIFO, ch); | ||
| 872 | } | ||
| 873 | |||
| 857 | /* | 874 | /* |
| 858 | * Print a string to the serial port trying not to disturb | 875 | * Print a string to the serial port trying not to disturb |
| 859 | * any possible real use of the port... | 876 | * any possible real use of the port... |
| @@ -865,7 +882,6 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) | |||
| 865 | { | 882 | { |
| 866 | struct uart_txx9_port *up = &serial_txx9_ports[co->index]; | 883 | struct uart_txx9_port *up = &serial_txx9_ports[co->index]; |
| 867 | unsigned int ier, flcr; | 884 | unsigned int ier, flcr; |
| 868 | int i; | ||
| 869 | 885 | ||
| 870 | /* | 886 | /* |
| 871 | * First save the UER then disable the interrupts | 887 | * First save the UER then disable the interrupts |
| @@ -879,22 +895,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) | |||
| 879 | if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) | 895 | if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) |
| 880 | sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); | 896 | sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); |
| 881 | 897 | ||
| 882 | /* | 898 | uart_console_write(&up->port, s, count, serial_txx9_console_putchar); |
| 883 | * Now, do each character | ||
| 884 | */ | ||
| 885 | for (i = 0; i < count; i++, s++) { | ||
| 886 | wait_for_xmitr(up); | ||
| 887 | |||
| 888 | /* | ||
| 889 | * Send the character out. | ||
| 890 | * If a LF, also do CR... | ||
| 891 | */ | ||
| 892 | sio_out(up, TXX9_SITFIFO, *s); | ||
| 893 | if (*s == 10) { | ||
| 894 | wait_for_xmitr(up); | ||
| 895 | sio_out(up, TXX9_SITFIFO, 13); | ||
| 896 | } | ||
| 897 | } | ||
| 898 | 899 | ||
| 899 | /* | 900 | /* |
| 900 | * Finally, wait for transmitter to become empty | 901 | * Finally, wait for transmitter to become empty |
| @@ -927,11 +928,6 @@ static int serial_txx9_console_setup(struct console *co, char *options) | |||
| 927 | return -ENODEV; | 928 | return -ENODEV; |
| 928 | 929 | ||
| 929 | /* | 930 | /* |
| 930 | * Temporary fix. | ||
| 931 | */ | ||
| 932 | spin_lock_init(&port->lock); | ||
| 933 | |||
| 934 | /* | ||
| 935 | * Disable UART interrupts, set DTR and RTS high | 931 | * Disable UART interrupts, set DTR and RTS high |
| 936 | * and set speed. | 932 | * and set speed. |
| 937 | */ | 933 | */ |
| @@ -1041,11 +1037,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) | |||
| 1041 | mutex_lock(&serial_txx9_mutex); | 1037 | mutex_lock(&serial_txx9_mutex); |
| 1042 | for (i = 0; i < UART_NR; i++) { | 1038 | for (i = 0; i < UART_NR; i++) { |
| 1043 | uart = &serial_txx9_ports[i]; | 1039 | uart = &serial_txx9_ports[i]; |
| 1044 | if (uart->port.type == PORT_UNKNOWN) | 1040 | if (!(uart->port.iobase || uart->port.mapbase)) |
| 1045 | break; | 1041 | break; |
| 1046 | } | 1042 | } |
| 1047 | if (i < UART_NR) { | 1043 | if (i < UART_NR) { |
| 1048 | uart_remove_one_port(&serial_txx9_reg, &uart->port); | ||
| 1049 | uart->port.iobase = port->iobase; | 1044 | uart->port.iobase = port->iobase; |
| 1050 | uart->port.membase = port->membase; | 1045 | uart->port.membase = port->membase; |
| 1051 | uart->port.irq = port->irq; | 1046 | uart->port.irq = port->irq; |
| @@ -1080,9 +1075,8 @@ static void __devexit serial_txx9_unregister_port(int line) | |||
| 1080 | uart->port.type = PORT_UNKNOWN; | 1075 | uart->port.type = PORT_UNKNOWN; |
| 1081 | uart->port.iobase = 0; | 1076 | uart->port.iobase = 0; |
| 1082 | uart->port.mapbase = 0; | 1077 | uart->port.mapbase = 0; |
| 1083 | uart->port.membase = 0; | 1078 | uart->port.membase = NULL; |
| 1084 | uart->port.dev = NULL; | 1079 | uart->port.dev = NULL; |
| 1085 | uart_add_one_port(&serial_txx9_reg, &uart->port); | ||
| 1086 | mutex_unlock(&serial_txx9_mutex); | 1080 | mutex_unlock(&serial_txx9_mutex); |
| 1087 | } | 1081 | } |
| 1088 | 1082 | ||
| @@ -1198,8 +1192,11 @@ static void __exit serial_txx9_exit(void) | |||
| 1198 | #ifdef ENABLE_SERIAL_TXX9_PCI | 1192 | #ifdef ENABLE_SERIAL_TXX9_PCI |
| 1199 | pci_unregister_driver(&serial_txx9_pci_driver); | 1193 | pci_unregister_driver(&serial_txx9_pci_driver); |
| 1200 | #endif | 1194 | #endif |
| 1201 | for (i = 0; i < UART_NR; i++) | 1195 | for (i = 0; i < UART_NR; i++) { |
| 1202 | uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port); | 1196 | struct uart_txx9_port *up = &serial_txx9_ports[i]; |
| 1197 | if (up->port.iobase || up->port.mapbase) | ||
| 1198 | uart_remove_one_port(&serial_txx9_reg, &up->port); | ||
| 1199 | } | ||
| 1203 | 1200 | ||
| 1204 | uart_unregister_driver(&serial_txx9_reg); | 1201 | uart_unregister_driver(&serial_txx9_reg); |
| 1205 | } | 1202 | } |
