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

serial: core: Allow detach and attach serial device for console

In the future we would like to disable power management on the serial devices
used as kernel consoles to avoid weird behaviour in some cases. However,
disabling PM may prevent system to go to deep sleep states, which in its turn
leads to the higher power consumption.

Tony Lindgren proposed a work around, i.e. allow user to detach such consoles
to make PM working again. In case user wants to see what's going on, it also
provides a mechanism to attach console back.

Link: https://lists.openwall.net/linux-kernel/2018/09/29/65
Suggested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20200217114016.49856-3-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andy Shevchenko and committed by
Greg Kroah-Hartman
a3cb39d2 5f3a4813

+63 -4
+7
Documentation/ABI/testing/sysfs-tty
··· 154 154 device specification. For example, when user sets 7bytes on 155 155 16550A, which has 1/4/8/14 bytes trigger, the RX trigger is 156 156 automatically changed to 4 bytes. 157 + 158 + What: /sys/class/tty/ttyS0/console 159 + Date: February 2020 160 + Contact: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 161 + Description: 162 + Allows user to detach or attach back the given device as 163 + kernel console. It shows and accepts a boolean variable.
+56 -4
drivers/tty/serial/serial_core.c
··· 1922 1922 */ 1923 1923 static inline void uart_port_spin_lock_init(struct uart_port *port) 1924 1924 { 1925 - if (uart_console_enabled(port)) 1925 + if (uart_console(port)) 1926 1926 return; 1927 1927 1928 1928 spin_lock_init(&port->lock); ··· 2751 2751 return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); 2752 2752 } 2753 2753 2754 + static ssize_t console_show(struct device *dev, 2755 + struct device_attribute *attr, char *buf) 2756 + { 2757 + struct tty_port *port = dev_get_drvdata(dev); 2758 + struct uart_state *state = container_of(port, struct uart_state, port); 2759 + struct uart_port *uport; 2760 + bool console = false; 2761 + 2762 + mutex_lock(&port->mutex); 2763 + uport = uart_port_check(state); 2764 + if (uport) 2765 + console = uart_console_enabled(uport); 2766 + mutex_unlock(&port->mutex); 2767 + 2768 + return sprintf(buf, "%c\n", console ? 'Y' : 'N'); 2769 + } 2770 + 2771 + static ssize_t console_store(struct device *dev, 2772 + struct device_attribute *attr, const char *buf, size_t count) 2773 + { 2774 + struct tty_port *port = dev_get_drvdata(dev); 2775 + struct uart_state *state = container_of(port, struct uart_state, port); 2776 + struct uart_port *uport; 2777 + bool oldconsole, newconsole; 2778 + int ret; 2779 + 2780 + ret = kstrtobool(buf, &newconsole); 2781 + if (ret) 2782 + return ret; 2783 + 2784 + mutex_lock(&port->mutex); 2785 + uport = uart_port_check(state); 2786 + if (uport) { 2787 + oldconsole = uart_console_enabled(uport); 2788 + if (oldconsole && !newconsole) { 2789 + ret = unregister_console(uport->cons); 2790 + } else if (!oldconsole && newconsole) { 2791 + if (uart_console(uport)) 2792 + register_console(uport->cons); 2793 + else 2794 + ret = -ENOENT; 2795 + } 2796 + } else { 2797 + ret = -ENXIO; 2798 + } 2799 + mutex_unlock(&port->mutex); 2800 + 2801 + return ret < 0 ? ret : count; 2802 + } 2803 + 2754 2804 static DEVICE_ATTR_RO(uartclk); 2755 2805 static DEVICE_ATTR_RO(type); 2756 2806 static DEVICE_ATTR_RO(line); ··· 2814 2764 static DEVICE_ATTR_RO(io_type); 2815 2765 static DEVICE_ATTR_RO(iomem_base); 2816 2766 static DEVICE_ATTR_RO(iomem_reg_shift); 2767 + static DEVICE_ATTR_RW(console); 2817 2768 2818 2769 static struct attribute *tty_dev_attrs[] = { 2819 2770 &dev_attr_uartclk.attr, ··· 2830 2779 &dev_attr_io_type.attr, 2831 2780 &dev_attr_iomem_base.attr, 2832 2781 &dev_attr_iomem_reg_shift.attr, 2833 - NULL, 2834 - }; 2782 + &dev_attr_console.attr, 2783 + NULL 2784 + }; 2835 2785 2836 2786 static const struct attribute_group tty_dev_attr_group = { 2837 2787 .attrs = tty_dev_attrs, 2838 - }; 2788 + }; 2839 2789 2840 2790 /** 2841 2791 * uart_add_one_port - attach a driver-defined port structure