summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2020-02-17 14:40:12 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-03-17 17:57:59 +0300
commita3cb39d258efef830181606134cfb0f7babe8c8e (patch)
tree6068aa6f92313fdb6d35909beba3ab8795830e8a /drivers/tty
parent5f3a48132412123135595fcbb2a760cfe626f592 (diff)
downloadlinux-a3cb39d258efef830181606134cfb0f7babe8c8e.tar.xz
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>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/serial_core.c60
1 files changed, 56 insertions, 4 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 38ef6afddce8..66a5e2faf57e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1922,7 +1922,7 @@ static inline bool uart_console_enabled(struct uart_port *port)
*/
static inline void uart_port_spin_lock_init(struct uart_port *port)
{
- if (uart_console_enabled(port))
+ if (uart_console(port))
return;
spin_lock_init(&port->lock);
@@ -2751,6 +2751,56 @@ static ssize_t iomem_reg_shift_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift);
}
+static ssize_t console_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tty_port *port = dev_get_drvdata(dev);
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport;
+ bool console = false;
+
+ mutex_lock(&port->mutex);
+ uport = uart_port_check(state);
+ if (uport)
+ console = uart_console_enabled(uport);
+ mutex_unlock(&port->mutex);
+
+ return sprintf(buf, "%c\n", console ? 'Y' : 'N');
+}
+
+static ssize_t console_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct tty_port *port = dev_get_drvdata(dev);
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport;
+ bool oldconsole, newconsole;
+ int ret;
+
+ ret = kstrtobool(buf, &newconsole);
+ if (ret)
+ return ret;
+
+ mutex_lock(&port->mutex);
+ uport = uart_port_check(state);
+ if (uport) {
+ oldconsole = uart_console_enabled(uport);
+ if (oldconsole && !newconsole) {
+ ret = unregister_console(uport->cons);
+ } else if (!oldconsole && newconsole) {
+ if (uart_console(uport))
+ register_console(uport->cons);
+ else
+ ret = -ENOENT;
+ }
+ } else {
+ ret = -ENXIO;
+ }
+ mutex_unlock(&port->mutex);
+
+ return ret < 0 ? ret : count;
+}
+
static DEVICE_ATTR_RO(uartclk);
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RO(line);
@@ -2764,6 +2814,7 @@ static DEVICE_ATTR_RO(custom_divisor);
static DEVICE_ATTR_RO(io_type);
static DEVICE_ATTR_RO(iomem_base);
static DEVICE_ATTR_RO(iomem_reg_shift);
+static DEVICE_ATTR_RW(console);
static struct attribute *tty_dev_attrs[] = {
&dev_attr_uartclk.attr,
@@ -2779,12 +2830,13 @@ static struct attribute *tty_dev_attrs[] = {
&dev_attr_io_type.attr,
&dev_attr_iomem_base.attr,
&dev_attr_iomem_reg_shift.attr,
- NULL,
- };
+ &dev_attr_console.attr,
+ NULL
+};
static const struct attribute_group tty_dev_attr_group = {
.attrs = tty_dev_attrs,
- };
+};
/**
* uart_add_one_port - attach a driver-defined port structure