Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: 8250_port: Don't use power management for kernel console

Doing any kind of power management for kernel console is really bad idea.

First of all, it runs in poll and atomic mode. This fact attaches a limitation
on the functions that might be called. For example, pm_runtime_get_sync() might
sleep and thus can't be used. This call needs, for example, to bring the device
to powered on state on the system, where the power on sequence may require
on-atomic operations, such as Intel Cherrytrail with ACPI enumerated UARTs.
That said, on ACPI enabled platforms it might even call firmware for a job.

On the other hand pm_runtime_get() doesn't guarantee that device will become
powered on fast enough.

Besides that, imagine the case when console is about to print a kernel Oops and
it's powered off. In such an emergency case calling the complex functions is
not the best what we can do, taking into consideration that user wants to see
at least something of the last kernel word before it passes away.

Here we modify the 8250 console code to prevent runtime power management.

Note, there is a behaviour change for OMAP boards. It will require to detach
kernel console to become idle.

Link: https://lists.openwall.net/linux-kernel/2018/09/29/65
Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20200217114016.49856-6-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andy Shevchenko and committed by
Greg Kroah-Hartman
bedb404e a3cb39d2

+30 -4
+9
drivers/tty/serial/8250/8250_core.c
··· 608 608 return retval; 609 609 } 610 610 611 + static int univ8250_console_exit(struct console *co) 612 + { 613 + struct uart_port *port; 614 + 615 + port = &serial8250_ports[co->index].port; 616 + return serial8250_console_exit(port); 617 + } 618 + 611 619 /** 612 620 * univ8250_console_match - non-standard console matching 613 621 * @co: registering console ··· 674 666 .write = univ8250_console_write, 675 667 .device = uart_console_device, 676 668 .setup = univ8250_console_setup, 669 + .exit = univ8250_console_exit, 677 670 .match = univ8250_console_match, 678 671 .flags = CON_PRINTBUFFER | CON_ANYTIME, 679 672 .index = -1,
+20 -4
drivers/tty/serial/8250/8250_port.c
··· 3200 3200 * any possible real use of the port... 3201 3201 * 3202 3202 * The console_lock must be held when we get here. 3203 + * 3204 + * Doing runtime PM is really a bad idea for the kernel console. 3205 + * Thus, we assume the function is called when device is powered up. 3203 3206 */ 3204 3207 void serial8250_console_write(struct uart_8250_port *up, const char *s, 3205 3208 unsigned int count) ··· 3214 3211 int locked = 1; 3215 3212 3216 3213 touch_nmi_watchdog(); 3217 - 3218 - serial8250_rpm_get(up); 3219 3214 3220 3215 if (oops_in_progress) 3221 3216 locked = spin_trylock_irqsave(&port->lock, flags); ··· 3269 3268 3270 3269 if (locked) 3271 3270 spin_unlock_irqrestore(&port->lock, flags); 3272 - serial8250_rpm_put(up); 3273 3271 } 3274 3272 3275 3273 static unsigned int probe_baud(struct uart_port *port) ··· 3292 3292 int bits = 8; 3293 3293 int parity = 'n'; 3294 3294 int flow = 'n'; 3295 + int ret; 3295 3296 3296 3297 if (!port->iobase && !port->membase) 3297 3298 return -ENODEV; ··· 3302 3301 else if (probe) 3303 3302 baud = probe_baud(port); 3304 3303 3305 - return uart_set_options(port, port->cons, baud, parity, bits, flow); 3304 + ret = uart_set_options(port, port->cons, baud, parity, bits, flow); 3305 + if (ret) 3306 + return ret; 3307 + 3308 + if (port->dev) 3309 + pm_runtime_get_sync(port->dev); 3310 + 3311 + return 0; 3312 + } 3313 + 3314 + int serial8250_console_exit(struct uart_port *port) 3315 + { 3316 + if (port->dev) 3317 + pm_runtime_put_sync(port->dev); 3318 + 3319 + return 0; 3306 3320 } 3307 3321 3308 3322 #endif /* CONFIG_SERIAL_8250_CONSOLE */
+1
include/linux/serial_8250.h
··· 179 179 void serial8250_console_write(struct uart_8250_port *up, const char *s, 180 180 unsigned int count); 181 181 int serial8250_console_setup(struct uart_port *port, char *options, bool probe); 182 + int serial8250_console_exit(struct uart_port *port); 182 183 183 184 extern void serial8250_set_isa_configurator(void (*v) 184 185 (int port, struct uart_port *up,