diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2006-10-01 12:17:40 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-10-01 12:17:40 -0400 |
commit | a6b93a908508810c5d51dd9b390283345af6f2d9 (patch) | |
tree | 71b48d3a659a025ebf333abfeec7b828becb60cb | |
parent | fe59d5372ae719ca4550958f1e5bb4dd6eeac9cd (diff) |
[SERIAL] Fix oops when removing suspended serial port
A serial card might have been removed when the system is resumed.
This results in a suspended port being shut down, which results in
the ports shutdown method being called twice in a row. This causes
BUGs. Avoid this by tracking the suspended state separately from
the initialised state.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | drivers/serial/serial_core.c | 9 | ||||
-rw-r--r-- | include/linux/serial_core.h | 1 |
2 files changed, 8 insertions, 2 deletions
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index d814bb1dcb05..397147a7054f 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -1940,6 +1940,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) | |||
1940 | if (state->info && state->info->flags & UIF_INITIALIZED) { | 1940 | if (state->info && state->info->flags & UIF_INITIALIZED) { |
1941 | const struct uart_ops *ops = port->ops; | 1941 | const struct uart_ops *ops = port->ops; |
1942 | 1942 | ||
1943 | state->info->flags = (state->info->flags & ~UIF_INITIALIZED) | ||
1944 | | UIF_SUSPENDED; | ||
1945 | |||
1943 | spin_lock_irq(&port->lock); | 1946 | spin_lock_irq(&port->lock); |
1944 | ops->stop_tx(port); | 1947 | ops->stop_tx(port); |
1945 | ops->set_mctrl(port, 0); | 1948 | ops->set_mctrl(port, 0); |
@@ -2006,7 +2009,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) | |||
2006 | console_start(port->cons); | 2009 | console_start(port->cons); |
2007 | } | 2010 | } |
2008 | 2011 | ||
2009 | if (state->info && state->info->flags & UIF_INITIALIZED) { | 2012 | if (state->info && state->info->flags & UIF_SUSPENDED) { |
2010 | const struct uart_ops *ops = port->ops; | 2013 | const struct uart_ops *ops = port->ops; |
2011 | int ret; | 2014 | int ret; |
2012 | 2015 | ||
@@ -2018,15 +2021,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) | |||
2018 | ops->set_mctrl(port, port->mctrl); | 2021 | ops->set_mctrl(port, port->mctrl); |
2019 | ops->start_tx(port); | 2022 | ops->start_tx(port); |
2020 | spin_unlock_irq(&port->lock); | 2023 | spin_unlock_irq(&port->lock); |
2024 | state->info->flags |= UIF_INITIALIZED; | ||
2021 | } else { | 2025 | } else { |
2022 | /* | 2026 | /* |
2023 | * Failed to resume - maybe hardware went away? | 2027 | * Failed to resume - maybe hardware went away? |
2024 | * Clear the "initialized" flag so we won't try | 2028 | * Clear the "initialized" flag so we won't try |
2025 | * to call the low level drivers shutdown method. | 2029 | * to call the low level drivers shutdown method. |
2026 | */ | 2030 | */ |
2027 | state->info->flags &= ~UIF_INITIALIZED; | ||
2028 | uart_shutdown(state); | 2031 | uart_shutdown(state); |
2029 | } | 2032 | } |
2033 | |||
2034 | state->info->flags &= ~UIF_SUSPENDED; | ||
2030 | } | 2035 | } |
2031 | 2036 | ||
2032 | mutex_unlock(&state->mutex); | 2037 | mutex_unlock(&state->mutex); |
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 86501a3de2ac..f9fdf97506ea 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
@@ -319,6 +319,7 @@ struct uart_info { | |||
319 | #define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) | 319 | #define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) |
320 | #define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29)) | 320 | #define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29)) |
321 | #define UIF_INITIALIZED ((__force uif_t) (1 << 31)) | 321 | #define UIF_INITIALIZED ((__force uif_t) (1 << 31)) |
322 | #define UIF_SUSPENDED ((__force uif_t) (1 << 30)) | ||
322 | 323 | ||
323 | int blocked_open; | 324 | int blocked_open; |
324 | 325 | ||