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/serial | |
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/serial')
-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 | ||