diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-11 18:46:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-11 18:46:42 -0400 |
| commit | 2bf9d6d0f2dadc2a6c13684719c67dc043b9ce67 (patch) | |
| tree | 512d855751247641aa68991b11026c1fb48736af /drivers | |
| parent | 6572b2064a54f1ed29fcbf6d16dfc5de71dfe495 (diff) | |
| parent | d8a5a8d7cc32e4474326e0ecc1b959063490efc9 (diff) | |
Merge master.kernel.org:/home/rmk/linux-2.6-serial
* master.kernel.org:/home/rmk/linux-2.6-serial:
[SERIAL] 8250: add locking to console write function
[SERIAL] Remove unconditional enable of TX irq for console
[SERIAL] 8250: set divisor register correctly for AMD Alchemy SoC uart
[SERIAL] AMD Alchemy UART: claim memory range
[SERIAL] Clean up serial locking when obtaining a reference to a port
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/serial/8250.c | 74 | ||||
| -rw-r--r-- | drivers/serial/8250_au1x00.c | 5 | ||||
| -rw-r--r-- | drivers/serial/serial_core.c | 114 |
3 files changed, 121 insertions, 72 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 674b15c78f68..bbf78aaf9e01 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
| @@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value) | |||
| 362 | #define serial_inp(up, offset) serial_in(up, offset) | 362 | #define serial_inp(up, offset) serial_in(up, offset) |
| 363 | #define serial_outp(up, offset, value) serial_out(up, offset, value) | 363 | #define serial_outp(up, offset, value) serial_out(up, offset, value) |
| 364 | 364 | ||
| 365 | /* Uart divisor latch read */ | ||
| 366 | static inline int _serial_dl_read(struct uart_8250_port *up) | ||
| 367 | { | ||
| 368 | return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* Uart divisor latch write */ | ||
| 372 | static inline void _serial_dl_write(struct uart_8250_port *up, int value) | ||
| 373 | { | ||
| 374 | serial_outp(up, UART_DLL, value & 0xff); | ||
| 375 | serial_outp(up, UART_DLM, value >> 8 & 0xff); | ||
| 376 | } | ||
| 377 | |||
| 378 | #ifdef CONFIG_SERIAL_8250_AU1X00 | ||
| 379 | /* Au1x00 haven't got a standard divisor latch */ | ||
| 380 | static int serial_dl_read(struct uart_8250_port *up) | ||
| 381 | { | ||
| 382 | if (up->port.iotype == UPIO_AU) | ||
| 383 | return __raw_readl(up->port.membase + 0x28); | ||
| 384 | else | ||
| 385 | return _serial_dl_read(up); | ||
| 386 | } | ||
| 387 | |||
| 388 | static void serial_dl_write(struct uart_8250_port *up, int value) | ||
| 389 | { | ||
| 390 | if (up->port.iotype == UPIO_AU) | ||
| 391 | __raw_writel(value, up->port.membase + 0x28); | ||
| 392 | else | ||
| 393 | _serial_dl_write(up, value); | ||
| 394 | } | ||
| 395 | #else | ||
| 396 | #define serial_dl_read(up) _serial_dl_read(up) | ||
| 397 | #define serial_dl_write(up, value) _serial_dl_write(up, value) | ||
| 398 | #endif | ||
| 365 | 399 | ||
| 366 | /* | 400 | /* |
| 367 | * For the 16C950 | 401 | * For the 16C950 |
| @@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up) | |||
| 494 | */ | 528 | */ |
| 495 | static int size_fifo(struct uart_8250_port *up) | 529 | static int size_fifo(struct uart_8250_port *up) |
| 496 | { | 530 | { |
| 497 | unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr; | 531 | unsigned char old_fcr, old_mcr, old_lcr; |
| 532 | unsigned short old_dl; | ||
| 498 | int count; | 533 | int count; |
| 499 | 534 | ||
| 500 | old_lcr = serial_inp(up, UART_LCR); | 535 | old_lcr = serial_inp(up, UART_LCR); |
| @@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up) | |||
| 505 | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); | 540 | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); |
| 506 | serial_outp(up, UART_MCR, UART_MCR_LOOP); | 541 | serial_outp(up, UART_MCR, UART_MCR_LOOP); |
| 507 | serial_outp(up, UART_LCR, UART_LCR_DLAB); | 542 | serial_outp(up, UART_LCR, UART_LCR_DLAB); |
| 508 | old_dll = serial_inp(up, UART_DLL); | 543 | old_dl = serial_dl_read(up); |
| 509 | old_dlm = serial_inp(up, UART_DLM); | 544 | serial_dl_write(up, 0x0001); |
| 510 | serial_outp(up, UART_DLL, 0x01); | ||
| 511 | serial_outp(up, UART_DLM, 0x00); | ||
| 512 | serial_outp(up, UART_LCR, 0x03); | 545 | serial_outp(up, UART_LCR, 0x03); |
| 513 | for (count = 0; count < 256; count++) | 546 | for (count = 0; count < 256; count++) |
| 514 | serial_outp(up, UART_TX, count); | 547 | serial_outp(up, UART_TX, count); |
| @@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up) | |||
| 519 | serial_outp(up, UART_FCR, old_fcr); | 552 | serial_outp(up, UART_FCR, old_fcr); |
| 520 | serial_outp(up, UART_MCR, old_mcr); | 553 | serial_outp(up, UART_MCR, old_mcr); |
| 521 | serial_outp(up, UART_LCR, UART_LCR_DLAB); | 554 | serial_outp(up, UART_LCR, UART_LCR_DLAB); |
| 522 | serial_outp(up, UART_DLL, old_dll); | 555 | serial_dl_write(up, old_dl); |
| 523 | serial_outp(up, UART_DLM, old_dlm); | ||
| 524 | serial_outp(up, UART_LCR, old_lcr); | 556 | serial_outp(up, UART_LCR, old_lcr); |
| 525 | 557 | ||
| 526 | return count; | 558 | return count; |
| @@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
| 750 | 782 | ||
| 751 | serial_outp(up, UART_LCR, 0xE0); | 783 | serial_outp(up, UART_LCR, 0xE0); |
| 752 | 784 | ||
| 753 | quot = serial_inp(up, UART_DLM) << 8; | 785 | quot = serial_dl_read(up); |
| 754 | quot += serial_inp(up, UART_DLL); | ||
| 755 | quot <<= 3; | 786 | quot <<= 3; |
| 756 | 787 | ||
| 757 | status1 = serial_in(up, 0x04); /* EXCR1 */ | 788 | status1 = serial_in(up, 0x04); /* EXCR1 */ |
| @@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
| 759 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | 790 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ |
| 760 | serial_outp(up, 0x04, status1); | 791 | serial_outp(up, 0x04, status1); |
| 761 | 792 | ||
| 762 | serial_outp(up, UART_DLL, quot & 0xff); | 793 | serial_dl_write(up, quot); |
| 763 | serial_outp(up, UART_DLM, quot >> 8); | ||
| 764 | 794 | ||
| 765 | serial_outp(up, UART_LCR, 0); | 795 | serial_outp(up, UART_LCR, 0); |
| 766 | 796 | ||
| @@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, | |||
| 1862 | serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ | 1892 | serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ |
| 1863 | } | 1893 | } |
| 1864 | 1894 | ||
| 1865 | serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ | 1895 | serial_dl_write(up, quot); |
| 1866 | serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ | ||
| 1867 | 1896 | ||
| 1868 | /* | 1897 | /* |
| 1869 | * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR | 1898 | * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR |
| @@ -1906,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) | |||
| 1906 | int ret = 0; | 1935 | int ret = 0; |
| 1907 | 1936 | ||
| 1908 | switch (up->port.iotype) { | 1937 | switch (up->port.iotype) { |
| 1938 | case UPIO_AU: | ||
| 1939 | size = 0x100000; | ||
| 1940 | /* fall thru */ | ||
| 1909 | case UPIO_MEM: | 1941 | case UPIO_MEM: |
| 1910 | if (!up->port.mapbase) | 1942 | if (!up->port.mapbase) |
| 1911 | break; | 1943 | break; |
| @@ -1938,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) | |||
| 1938 | unsigned int size = 8 << up->port.regshift; | 1970 | unsigned int size = 8 << up->port.regshift; |
| 1939 | 1971 | ||
| 1940 | switch (up->port.iotype) { | 1972 | switch (up->port.iotype) { |
| 1973 | case UPIO_AU: | ||
| 1974 | size = 0x100000; | ||
| 1975 | /* fall thru */ | ||
| 1941 | case UPIO_MEM: | 1976 | case UPIO_MEM: |
| 1942 | if (!up->port.mapbase) | 1977 | if (!up->port.mapbase) |
| 1943 | break; | 1978 | break; |
| @@ -2200,10 +2235,17 @@ static void | |||
| 2200 | serial8250_console_write(struct console *co, const char *s, unsigned int count) | 2235 | serial8250_console_write(struct console *co, const char *s, unsigned int count) |
| 2201 | { | 2236 | { |
| 2202 | struct uart_8250_port *up = &serial8250_ports[co->index]; | 2237 | struct uart_8250_port *up = &serial8250_ports[co->index]; |
| 2238 | unsigned long flags; | ||
| 2203 | unsigned int ier; | 2239 | unsigned int ier; |
| 2240 | int locked = 1; | ||
| 2204 | 2241 | ||
| 2205 | touch_nmi_watchdog(); | 2242 | touch_nmi_watchdog(); |
| 2206 | 2243 | ||
| 2244 | if (oops_in_progress) { | ||
| 2245 | locked = spin_trylock_irqsave(&up->port.lock, flags); | ||
| 2246 | } else | ||
| 2247 | spin_lock_irqsave(&up->port.lock, flags); | ||
| 2248 | |||
| 2207 | /* | 2249 | /* |
| 2208 | * First save the IER then disable the interrupts | 2250 | * First save the IER then disable the interrupts |
| 2209 | */ | 2251 | */ |
| @@ -2221,8 +2263,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) | |||
| 2221 | * and restore the IER | 2263 | * and restore the IER |
| 2222 | */ | 2264 | */ |
| 2223 | wait_for_xmitr(up, BOTH_EMPTY); | 2265 | wait_for_xmitr(up, BOTH_EMPTY); |
| 2224 | up->ier |= UART_IER_THRI; | 2266 | serial_out(up, UART_IER, ier); |
| 2225 | serial_out(up, UART_IER, ier | UART_IER_THRI); | 2267 | |
| 2268 | if (locked) | ||
| 2269 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
| 2226 | } | 2270 | } |
| 2227 | 2271 | ||
| 2228 | static int serial8250_console_setup(struct console *co, char *options) | 2272 | static int serial8250_console_setup(struct console *co, char *options) |
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c index 3d1bfd07208d..58015fd14be9 100644 --- a/drivers/serial/8250_au1x00.c +++ b/drivers/serial/8250_au1x00.c | |||
| @@ -30,13 +30,12 @@ | |||
| 30 | { \ | 30 | { \ |
| 31 | .iobase = _base, \ | 31 | .iobase = _base, \ |
| 32 | .membase = (void __iomem *)_base,\ | 32 | .membase = (void __iomem *)_base,\ |
| 33 | .mapbase = _base, \ | 33 | .mapbase = CPHYSADDR(_base), \ |
| 34 | .irq = _irq, \ | 34 | .irq = _irq, \ |
| 35 | .uartclk = 0, /* filled */ \ | 35 | .uartclk = 0, /* filled */ \ |
| 36 | .regshift = 2, \ | 36 | .regshift = 2, \ |
| 37 | .iotype = UPIO_AU, \ | 37 | .iotype = UPIO_AU, \ |
| 38 | .flags = UPF_SKIP_TEST | \ | 38 | .flags = UPF_SKIP_TEST \ |
| 39 | UPF_IOREMAP, \ | ||
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | static struct plat_serial8250_port au1x00_data[] = { | 41 | static struct plat_serial8250_port au1x00_data[] = { |
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index fcd7744c4253..aeb8153ccf24 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
| @@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) | |||
| 1500 | static struct uart_state *uart_get(struct uart_driver *drv, int line) | 1500 | static struct uart_state *uart_get(struct uart_driver *drv, int line) |
| 1501 | { | 1501 | { |
| 1502 | struct uart_state *state; | 1502 | struct uart_state *state; |
| 1503 | int ret = 0; | ||
| 1503 | 1504 | ||
| 1504 | mutex_lock(&port_mutex); | ||
| 1505 | state = drv->state + line; | 1505 | state = drv->state + line; |
| 1506 | if (mutex_lock_interruptible(&state->mutex)) { | 1506 | if (mutex_lock_interruptible(&state->mutex)) { |
| 1507 | state = ERR_PTR(-ERESTARTSYS); | 1507 | ret = -ERESTARTSYS; |
| 1508 | goto out; | 1508 | goto err; |
| 1509 | } | 1509 | } |
| 1510 | 1510 | ||
| 1511 | state->count++; | 1511 | state->count++; |
| 1512 | if (!state->port) { | 1512 | if (!state->port || state->port->flags & UPF_DEAD) { |
| 1513 | state->count--; | 1513 | ret = -ENXIO; |
| 1514 | mutex_unlock(&state->mutex); | 1514 | goto err_unlock; |
| 1515 | state = ERR_PTR(-ENXIO); | ||
| 1516 | goto out; | ||
| 1517 | } | 1515 | } |
| 1518 | 1516 | ||
| 1519 | if (!state->info) { | 1517 | if (!state->info) { |
| @@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) | |||
| 1531 | tasklet_init(&state->info->tlet, uart_tasklet_action, | 1529 | tasklet_init(&state->info->tlet, uart_tasklet_action, |
| 1532 | (unsigned long)state); | 1530 | (unsigned long)state); |
| 1533 | } else { | 1531 | } else { |
| 1534 | state->count--; | 1532 | ret = -ENOMEM; |
| 1535 | mutex_unlock(&state->mutex); | 1533 | goto err_unlock; |
| 1536 | state = ERR_PTR(-ENOMEM); | ||
| 1537 | } | 1534 | } |
| 1538 | } | 1535 | } |
| 1539 | |||
| 1540 | out: | ||
| 1541 | mutex_unlock(&port_mutex); | ||
| 1542 | return state; | 1536 | return state; |
| 1537 | |||
| 1538 | err_unlock: | ||
| 1539 | state->count--; | ||
| 1540 | mutex_unlock(&state->mutex); | ||
| 1541 | err: | ||
| 1542 | return ERR_PTR(ret); | ||
| 1543 | } | 1543 | } |
| 1544 | 1544 | ||
| 1545 | /* | 1545 | /* |
| @@ -2085,45 +2085,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, | |||
| 2085 | } | 2085 | } |
| 2086 | } | 2086 | } |
| 2087 | 2087 | ||
| 2088 | /* | ||
| 2089 | * This reverses the effects of uart_configure_port, hanging up the | ||
| 2090 | * port before removal. | ||
| 2091 | */ | ||
| 2092 | static void | ||
| 2093 | uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state) | ||
| 2094 | { | ||
| 2095 | struct uart_port *port = state->port; | ||
| 2096 | struct uart_info *info = state->info; | ||
| 2097 | |||
| 2098 | if (info && info->tty) | ||
| 2099 | tty_vhangup(info->tty); | ||
| 2100 | |||
| 2101 | mutex_lock(&state->mutex); | ||
| 2102 | |||
| 2103 | state->info = NULL; | ||
| 2104 | |||
| 2105 | /* | ||
| 2106 | * Free the port IO and memory resources, if any. | ||
| 2107 | */ | ||
| 2108 | if (port->type != PORT_UNKNOWN) | ||
| 2109 | port->ops->release_port(port); | ||
| 2110 | |||
| 2111 | /* | ||
| 2112 | * Indicate that there isn't a port here anymore. | ||
| 2113 | */ | ||
| 2114 | port->type = PORT_UNKNOWN; | ||
| 2115 | |||
| 2116 | /* | ||
| 2117 | * Kill the tasklet, and free resources. | ||
| 2118 | */ | ||
| 2119 | if (info) { | ||
| 2120 | tasklet_kill(&info->tlet); | ||
| 2121 | kfree(info); | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | mutex_unlock(&state->mutex); | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | static struct tty_operations uart_ops = { | 2088 | static struct tty_operations uart_ops = { |
| 2128 | .open = uart_open, | 2089 | .open = uart_open, |
| 2129 | .close = uart_close, | 2090 | .close = uart_close, |
| @@ -2270,6 +2231,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
| 2270 | state = drv->state + port->line; | 2231 | state = drv->state + port->line; |
| 2271 | 2232 | ||
| 2272 | mutex_lock(&port_mutex); | 2233 | mutex_lock(&port_mutex); |
| 2234 | mutex_lock(&state->mutex); | ||
| 2273 | if (state->port) { | 2235 | if (state->port) { |
| 2274 | ret = -EINVAL; | 2236 | ret = -EINVAL; |
| 2275 | goto out; | 2237 | goto out; |
| @@ -2304,7 +2266,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
| 2304 | port->cons && !(port->cons->flags & CON_ENABLED)) | 2266 | port->cons && !(port->cons->flags & CON_ENABLED)) |
| 2305 | register_console(port->cons); | 2267 | register_console(port->cons); |
| 2306 | 2268 | ||
| 2269 | /* | ||
| 2270 | * Ensure UPF_DEAD is not set. | ||
| 2271 | */ | ||
| 2272 | port->flags &= ~UPF_DEAD; | ||
| 2273 | |||
| 2307 | out: | 2274 | out: |
| 2275 | mutex_unlock(&state->mutex); | ||
| 2308 | mutex_unlock(&port_mutex); | 2276 | mutex_unlock(&port_mutex); |
| 2309 | 2277 | ||
| 2310 | return ret; | 2278 | return ret; |
| @@ -2322,6 +2290,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
| 2322 | int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) | 2290 | int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) |
| 2323 | { | 2291 | { |
| 2324 | struct uart_state *state = drv->state + port->line; | 2292 | struct uart_state *state = drv->state + port->line; |
| 2293 | struct uart_info *info; | ||
| 2325 | 2294 | ||
| 2326 | BUG_ON(in_interrupt()); | 2295 | BUG_ON(in_interrupt()); |
| 2327 | 2296 | ||
| @@ -2332,11 +2301,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) | |||
| 2332 | mutex_lock(&port_mutex); | 2301 | mutex_lock(&port_mutex); |
| 2333 | 2302 | ||
| 2334 | /* | 2303 | /* |
| 2304 | * Mark the port "dead" - this prevents any opens from | ||
| 2305 | * succeeding while we shut down the port. | ||
| 2306 | */ | ||
| 2307 | mutex_lock(&state->mutex); | ||
| 2308 | port->flags |= UPF_DEAD; | ||
| 2309 | mutex_unlock(&state->mutex); | ||
| 2310 | |||
| 2311 | /* | ||
| 2335 | * Remove the devices from devfs | 2312 | * Remove the devices from devfs |
| 2336 | */ | 2313 | */ |
| 2337 | tty_unregister_device(drv->tty_driver, port->line); | 2314 | tty_unregister_device(drv->tty_driver, port->line); |
| 2338 | 2315 | ||
| 2339 | uart_unconfigure_port(drv, state); | 2316 | info = state->info; |
| 2317 | if (info && info->tty) | ||
| 2318 | tty_vhangup(info->tty); | ||
| 2319 | |||
| 2320 | /* | ||
| 2321 | * All users of this port should now be disconnected from | ||
| 2322 | * this driver, and the port shut down. We should be the | ||
| 2323 | * only thread fiddling with this port from now on. | ||
| 2324 | */ | ||
| 2325 | state->info = NULL; | ||
| 2326 | |||
| 2327 | /* | ||
| 2328 | * Free the port IO and memory resources, if any. | ||
| 2329 | */ | ||
| 2330 | if (port->type != PORT_UNKNOWN) | ||
| 2331 | port->ops->release_port(port); | ||
| 2332 | |||
| 2333 | /* | ||
| 2334 | * Indicate that there isn't a port here anymore. | ||
| 2335 | */ | ||
| 2336 | port->type = PORT_UNKNOWN; | ||
| 2337 | |||
| 2338 | /* | ||
| 2339 | * Kill the tasklet, and free resources. | ||
| 2340 | */ | ||
| 2341 | if (info) { | ||
| 2342 | tasklet_kill(&info->tlet); | ||
| 2343 | kfree(info); | ||
| 2344 | } | ||
| 2345 | |||
| 2340 | state->port = NULL; | 2346 | state->port = NULL; |
| 2341 | mutex_unlock(&port_mutex); | 2347 | mutex_unlock(&port_mutex); |
| 2342 | 2348 | ||
