[PATCH] SERIAL: Fix oops when removing suspended serial port
authorRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 17 Oct 2006 11:26:34 +0000 (13:26 +0200)
committerChris Wright <chrisw@sous-sol.org>
Sat, 4 Nov 2006 01:33:46 +0000 (17:33 -0800)
[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>
Signed-off-by: maximilian attems <maks@sternwelten.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
drivers/serial/serial_core.c
include/linux/serial_core.h

index 372e47f7d596392d3d4528bb0d2680d76eea3f5b..c59dcb7a8d667afafd0a09bfd95999fd0a123e23 100644 (file)
@@ -1932,6 +1932,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
        if (state->info && state->info->flags & UIF_INITIALIZED) {
                const struct uart_ops *ops = port->ops;
 
+               state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+                                    | UIF_SUSPENDED;
+
                spin_lock_irq(&port->lock);
                ops->stop_tx(port);
                ops->set_mctrl(port, 0);
@@ -1991,7 +1994,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                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;
                int ret;
 
@@ -2003,15 +2006,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                        ops->set_mctrl(port, port->mctrl);
                        ops->start_tx(port);
                        spin_unlock_irq(&port->lock);
+                       state->info->flags |= UIF_INITIALIZED;
                } else {
                        /*
                         * Failed to resume - maybe hardware went away?
                         * Clear the "initialized" flag so we won't try
                         * to call the low level drivers shutdown method.
                         */
-                       state->info->flags &= ~UIF_INITIALIZED;
                        uart_shutdown(state);
                }
+
+               state->info->flags &= ~UIF_SUSPENDED;
        }
 
        mutex_unlock(&state->mutex);
index 86501a3de2ac1d771c9b32958ca5b3fdf8a99dee..f9fdf97506eade00a210265477f9d112eedfb176 100644 (file)
@@ -319,6 +319,7 @@ struct uart_info {
 #define UIF_CTS_FLOW           ((__force uif_t) (1 << 26))
 #define UIF_NORMAL_ACTIVE      ((__force uif_t) (1 << 29))
 #define UIF_INITIALIZED                ((__force uif_t) (1 << 31))
+#define UIF_SUSPENDED          ((__force uif_t) (1 << 30))
 
        int                     blocked_open;