[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>
This commit is contained in:
parent
fe59d5372a
commit
a6b93a9085
|
@ -1940,6 +1940,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
if (state->info && state->info->flags & UIF_INITIALIZED) {
|
if (state->info && state->info->flags & UIF_INITIALIZED) {
|
||||||
const struct uart_ops *ops = port->ops;
|
const struct uart_ops *ops = port->ops;
|
||||||
|
|
||||||
|
state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
|
||||||
|
| UIF_SUSPENDED;
|
||||||
|
|
||||||
spin_lock_irq(&port->lock);
|
spin_lock_irq(&port->lock);
|
||||||
ops->stop_tx(port);
|
ops->stop_tx(port);
|
||||||
ops->set_mctrl(port, 0);
|
ops->set_mctrl(port, 0);
|
||||||
|
@ -2006,7 +2009,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
console_start(port->cons);
|
console_start(port->cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->info && state->info->flags & UIF_INITIALIZED) {
|
if (state->info && state->info->flags & UIF_SUSPENDED) {
|
||||||
const struct uart_ops *ops = port->ops;
|
const struct uart_ops *ops = port->ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2018,15 +2021,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
|
||||||
ops->set_mctrl(port, port->mctrl);
|
ops->set_mctrl(port, port->mctrl);
|
||||||
ops->start_tx(port);
|
ops->start_tx(port);
|
||||||
spin_unlock_irq(&port->lock);
|
spin_unlock_irq(&port->lock);
|
||||||
|
state->info->flags |= UIF_INITIALIZED;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Failed to resume - maybe hardware went away?
|
* Failed to resume - maybe hardware went away?
|
||||||
* Clear the "initialized" flag so we won't try
|
* Clear the "initialized" flag so we won't try
|
||||||
* to call the low level drivers shutdown method.
|
* to call the low level drivers shutdown method.
|
||||||
*/
|
*/
|
||||||
state->info->flags &= ~UIF_INITIALIZED;
|
|
||||||
uart_shutdown(state);
|
uart_shutdown(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state->info->flags &= ~UIF_SUSPENDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&state->mutex);
|
mutex_unlock(&state->mutex);
|
||||||
|
|
|
@ -319,6 +319,7 @@ struct uart_info {
|
||||||
#define UIF_CTS_FLOW ((__force uif_t) (1 << 26))
|
#define UIF_CTS_FLOW ((__force uif_t) (1 << 26))
|
||||||
#define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29))
|
#define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29))
|
||||||
#define UIF_INITIALIZED ((__force uif_t) (1 << 31))
|
#define UIF_INITIALIZED ((__force uif_t) (1 << 31))
|
||||||
|
#define UIF_SUSPENDED ((__force uif_t) (1 << 30))
|
||||||
|
|
||||||
int blocked_open;
|
int blocked_open;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue