serial-core: resume serial hardware with no_console_suspend

Perform a tricky suspend/resume even with no_console_suspend.

With no_console_suspend, kernel skips serial port suspend/resume and the
serial hardware may remain in undefined state after resume. It actually
happens on devices that don't have BIOS that handle serial
initialization. It makes impossible to use serial console after resume.

Devices affected by this problem include:
Sharp Zaurus devices
Several PXA based ARM embedded boards

The patch does:
- Save the hardware state
- Perform buffer flush in time of its suspend call
- Tell the driver that port is suspended
- But still accept new data
- And keep console hardware in state that allows to send them

It allows to capture late console messages without breaking console
after resume.

This is just a resend of a patch discussed in these threads, as the
patch was not yet applied.

"Possible suspend/resume regression in .32-rc?" (Nov 1-5, 2009, ARM
list, later LKML)

"serial-core: resume serial hardware with no_console_suspend" (Sep
15-Oct 18, 2009, LKML & ARM lists)

Signed-off-by: Stanislav Brabec <sbrabec@suse.cz>
Tested-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Tested-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by Stanislav Brabec and committed by Greg Kroah-Hartman 4547be78 6d34855d

+33 -55
+33 -55
drivers/serial/serial_core.c
··· 2006 2006 2007 2007 mutex_lock(&port->mutex); 2008 2008 2009 - if (!console_suspend_enabled && uart_console(uport)) { 2010 - /* we're going to avoid suspending serial console */ 2011 - mutex_unlock(&port->mutex); 2012 - return 0; 2013 - } 2014 - 2015 2009 tty_dev = device_find_child(uport->dev, &match, serial_match_port); 2016 2010 if (device_may_wakeup(tty_dev)) { 2017 2011 enable_irq_wake(uport->irq); ··· 2013 2019 mutex_unlock(&port->mutex); 2014 2020 return 0; 2015 2021 } 2016 - uport->suspended = 1; 2022 + if (console_suspend_enabled || !uart_console(uport)) 2023 + uport->suspended = 1; 2017 2024 2018 2025 if (port->flags & ASYNC_INITIALIZED) { 2019 2026 const struct uart_ops *ops = uport->ops; 2020 2027 int tries; 2021 2028 2022 - set_bit(ASYNCB_SUSPENDED, &port->flags); 2023 - clear_bit(ASYNCB_INITIALIZED, &port->flags); 2029 + if (console_suspend_enabled || !uart_console(uport)) { 2030 + set_bit(ASYNCB_SUSPENDED, &port->flags); 2031 + clear_bit(ASYNCB_INITIALIZED, &port->flags); 2024 2032 2025 - spin_lock_irq(&uport->lock); 2026 - ops->stop_tx(uport); 2027 - ops->set_mctrl(uport, 0); 2028 - ops->stop_rx(uport); 2029 - spin_unlock_irq(&uport->lock); 2033 + spin_lock_irq(&uport->lock); 2034 + ops->stop_tx(uport); 2035 + ops->set_mctrl(uport, 0); 2036 + ops->stop_rx(uport); 2037 + spin_unlock_irq(&uport->lock); 2038 + } 2030 2039 2031 2040 /* 2032 2041 * Wait for the transmitter to empty. ··· 2044 2047 drv->dev_name, 2045 2048 drv->tty_driver->name_base + uport->line); 2046 2049 2047 - ops->shutdown(uport); 2050 + if (console_suspend_enabled || !uart_console(uport)) 2051 + ops->shutdown(uport); 2048 2052 } 2049 2053 2050 2054 /* 2051 2055 * Disable the console device before suspending. 2052 2056 */ 2053 - if (uart_console(uport)) 2057 + if (console_suspend_enabled && uart_console(uport)) 2054 2058 console_stop(uport->cons); 2055 2059 2056 - uart_change_pm(state, 3); 2060 + if (console_suspend_enabled || !uart_console(uport)) 2061 + uart_change_pm(state, 3); 2057 2062 2058 2063 mutex_unlock(&port->mutex); 2059 2064 ··· 2071 2072 struct ktermios termios; 2072 2073 2073 2074 mutex_lock(&port->mutex); 2074 - 2075 - if (!console_suspend_enabled && uart_console(uport)) { 2076 - /* no need to resume serial console, it wasn't suspended */ 2077 - /* 2078 - * First try to use the console cflag setting. 2079 - */ 2080 - memset(&termios, 0, sizeof(struct ktermios)); 2081 - termios.c_cflag = uport->cons->cflag; 2082 - /* 2083 - * If that's unset, use the tty termios setting. 2084 - */ 2085 - if (termios.c_cflag == 0) 2086 - termios = *state->port.tty->termios; 2087 - else { 2088 - termios.c_ispeed = termios.c_ospeed = 2089 - tty_termios_input_baud_rate(&termios); 2090 - termios.c_ispeed = termios.c_ospeed = 2091 - tty_termios_baud_rate(&termios); 2092 - } 2093 - uport->ops->set_termios(uport, &termios, NULL); 2094 - mutex_unlock(&port->mutex); 2095 - return 0; 2096 - } 2097 2075 2098 2076 tty_dev = device_find_child(uport->dev, &match, serial_match_port); 2099 2077 if (!uport->suspended && device_may_wakeup(tty_dev)) { ··· 2097 2121 spin_lock_irq(&uport->lock); 2098 2122 ops->set_mctrl(uport, 0); 2099 2123 spin_unlock_irq(&uport->lock); 2100 - ret = ops->startup(uport); 2101 - if (ret == 0) { 2102 - uart_change_speed(state, NULL); 2103 - spin_lock_irq(&uport->lock); 2104 - ops->set_mctrl(uport, uport->mctrl); 2105 - ops->start_tx(uport); 2106 - spin_unlock_irq(&uport->lock); 2107 - set_bit(ASYNCB_INITIALIZED, &port->flags); 2108 - } else { 2109 - /* 2110 - * Failed to resume - maybe hardware went away? 2111 - * Clear the "initialized" flag so we won't try 2112 - * to call the low level drivers shutdown method. 2113 - */ 2114 - uart_shutdown(state); 2124 + if (console_suspend_enabled || !uart_console(uport)) { 2125 + ret = ops->startup(uport); 2126 + if (ret == 0) { 2127 + uart_change_speed(state, NULL); 2128 + spin_lock_irq(&uport->lock); 2129 + ops->set_mctrl(uport, uport->mctrl); 2130 + ops->start_tx(uport); 2131 + spin_unlock_irq(&uport->lock); 2132 + set_bit(ASYNCB_INITIALIZED, &port->flags); 2133 + } else { 2134 + /* 2135 + * Failed to resume - maybe hardware went away? 2136 + * Clear the "initialized" flag so we won't try 2137 + * to call the low level drivers shutdown method. 2138 + */ 2139 + uart_shutdown(state); 2140 + } 2115 2141 } 2116 2142 2117 2143 clear_bit(ASYNCB_SUSPENDED, &port->flags);