Skip to contentSkip to conversation

Per-console loglevel support, console device bus

RFC PATCH In review Calvin Owens 6 participants 23 messages Mar 2, 2019 – Mar 20, 2019

Subsystems (57)
lore
Share & tools
lore
#0 lore raw

cover Per-console loglevel support, console device bus

Hello all,

This is an extremely overdue refresh of this series:

	https://lkml.org/lkml/2017/9/28/770

The big change here is the 3rd patch, which actually wires up the console drivers to support embedding a device structure, so we can place them on a "console" bus and expose attributes in sysfs.

I left the very long list of driver maintainers off this first submission, once there's agreement on the core idea here I'll add them.

Thanks,
Calvin

Calvin Owens (4):
printk: Introduce per-console loglevel setting
printk: Add ability to set loglevel via "console=" cmdline
printk: Add consoles to a virtual "console" bus
printk: Add a device attribute for the per-console loglevel

 131 files changed, 1859 insertions(+), 1061 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/4 printk: Introduce per-console loglevel setting

Not all consoles are created equal: depending on the actual hardware, the latency of a printk() call can vary dramatically. The worst examples are serial consoles, where it can spin for tens of milliseconds banging the UART to emit a message, which can cause application-level problems when the kernel spews onto the console.

At Facebook we use netconsole to monitor our fleet, but we still have serial consoles attached on each host for live debugging, and the latter has caused problems. An obvious solution is to disable the kernel console output to ttyS0, but this makes live debugging frustrating, since crashes become silent and opaque to the ttyS0 user. Enabling it on the fly when needed isn't feasible, since boxes you need to debug via serial are likely to be borked in ways that make this impossible.

That puts us between a rock and a hard place: we'd love to set kernel.printk to KERN_INFO and get all the logs. But while netconsole is fast enough to permit that without perturbing userspace, ttyS0 is not, and we're forced to limit console logging to KERN_WARNING and higher.

This patch introduces a new per-console loglevel setting, and changes console_unlock() to use max(global_level, per_console_level) when deciding whether or not to emit a given log message.

This lets us have our cake and eat it too: instead of being forced to limit all consoles verbosity based on the speed of the slowest one, we can "promote" the faster console while still using a conservative system loglevel setting to avoid disturbing applications.

---
 include/linux/console.h |  1 +
 kernel/printk/printk.c  | 36 +++++++++++++++++++-----------------
 2 files changed, 20 insertions(+), 17 deletions(-)
include/linux/console.h +1 -0
index ec9bdb3d7bab..3c27a4a29b8c 100644
@@ -155,6 +155,7 @@ struct console {
 	int	cflag;
 	void	*data;
 	struct	 console *next;
+	int	level;
 };
 
 /*
kernel/printk/printk.c +19 -17
index d3d170374ceb..6ead14f8c2bc 100644
@@ -1164,9 +1164,14 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 
-static bool suppress_message_printing(int level)
+static int effective_loglevel(struct console *con)
 {
-	return (level >= console_loglevel && !ignore_loglevel);
+	return max(console_loglevel, con ? con->level : LOGLEVEL_EMERG);
+}
+
+static bool suppress_message_printing(int level, struct console *con)
+{
+	return (level >= effective_loglevel(con) && !ignore_loglevel);
 }
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
@@ -1198,7 +1203,7 @@ static void boot_delay_msec(int level)
 	unsigned long timeout;
 
 	if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
-		|| suppress_message_printing(level)) {
+		|| suppress_message_printing(level, NULL)) {
 		return;
 	}
 
@@ -1712,7 +1717,7 @@ static int console_trylock_spinning(void)
  * The console_lock must be held.
  */
 static void call_console_drivers(const char *ext_text, size_t ext_len,
-				 const char *text, size_t len)
+				 const char *text, size_t len, int level)
 {
 	struct console *con;
 
@@ -1731,6 +1736,8 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 		if (!cpu_online(smp_processor_id()) &&
 		    !(con->flags & CON_ANYTIME))
 			continue;
+		if (suppress_message_printing(level, con))
+			continue;
 		if (con->flags & CON_EXTENDED)
 			con->write(con, ext_text, ext_len);
 		else
@@ -2022,7 +2029,7 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
 static void console_lock_spinning_enable(void) { }
 static int console_lock_spinning_disable_and_check(void) { return 0; }
 static void call_console_drivers(const char *ext_text, size_t ext_len,
-				 const char *text, size_t len) {}
+				 const char *text, size_t len, int level) {}
 static size_t msg_print_text(const struct printk_log *msg, bool syslog,
 			     bool time, char *buf, size_t size) { return 0; }
 static bool suppress_message_printing(int level) { return false; }
@@ -2358,21 +2365,11 @@ void console_unlock(void)
 		} else {
 			len = 0;
 		}
-skip:
+
 		if (console_seq == log_next_seq)
 			break;
 
 		msg = log_from_idx(console_idx);
-		if (suppress_message_printing(msg->level)) {
-			/*
-			 * Skip record we have buffered and already printed
-			 * directly to the console when we received it, and
-			 * record that has level above the console loglevel.
-			 */
-			console_idx = log_next(console_idx);
-			console_seq++;
-			goto skip;
-		}
 
 		/* Output to all consoles once old messages replayed. */
 		if (unlikely(exclusive_console &&
@@ -2405,7 +2402,7 @@ void console_unlock(void)
 		console_lock_spinning_enable();
 
 		stop_critical_timings();	/* don't trace print latency */
-		call_console_drivers(ext_text, ext_len, text, len);
+		call_console_drivers(ext_text, ext_len, text, len, msg->level);
 		start_critical_timings();
 
 		if (console_lock_spinning_disable_and_check()) {
@@ -2671,6 +2668,11 @@ void register_console(struct console *newcon)
 	if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV))
 		newcon->flags &= ~CON_PRINTBUFFER;
 
+	/*
+	 * By default, the per-console minimum forces no messages through.
+	 */
+	newcon->level = LOGLEVEL_EMERG;
+
 	/*
 	 *	Put this console in the list - keep the
 	 *	preferred driver at the head of the list.
Signature · 1 line
2.17.1
#2 lore raw

Re: [PATCH 1/4] printk: Introduce per-console loglevel setting

On (03/01/19 16:48), Calvin Owens wrote:
[..]

Quoted 15 lines
kernel/printk/printk.c +0 -10
 		msg = log_from_idx(console_idx);
-		if (suppress_message_printing(msg->level)) {
-			/*
-			 * Skip record we have buffered and already printed
-			 * directly to the console when we received it, and
-			 * record that has level above the console loglevel.
-			 */
-			console_idx = log_next(console_idx);
-			console_seq++;
-			goto skip;
-		}
 
 		/* Output to all consoles once old messages replayed. */
 		if (unlikely(exclusive_console &&

kernel/printk/printk.c void console_unlock(void) · line 2406

Quoted 6 lines
kernel/printk/printk.c +1 -1
@@ -2405,7 +2402,7 @@ void console_unlock(void)
 		console_lock_spinning_enable();
 
 		stop_critical_timings();	/* don't trace print latency */
-		call_console_drivers(ext_text, ext_len, text, len);
+		call_console_drivers(ext_text, ext_len, text, len, msg->level);
 		start_critical_timings();

So it seems that now we always format the text and ext message (if needed) and only then check if there is at least one console we can print that message on.

Can we iterate the consoles first and check if msg is worth the effort (per console suppress_message_printing()) and only if it is do all the formatting and call console drivers?

	-ss
#3 lore raw

Re: [PATCH 1/4] printk: Introduce per-console loglevel setting

Quoted 28 lines · Sergey Senozhatsky

On (03/01/19 16:48), Calvin Owens wrote:
[..]

Quoted 15 lines
kernel/printk/printk.c +0 -10
 		msg = log_from_idx(console_idx);
-		if (suppress_message_printing(msg->level)) {
-			/*
-			 * Skip record we have buffered and already printed
-			 * directly to the console when we received it, and
-			 * record that has level above the console loglevel.
-			 */
-			console_idx = log_next(console_idx);
-			console_seq++;
-			goto skip;
-		}
 
 		/* Output to all consoles once old messages replayed. */
 		if (unlikely(exclusive_console &&

kernel/printk/printk.c void console_unlock(void) · line 2406

Quoted 6 lines
kernel/printk/printk.c +1 -1
@@ -2405,7 +2402,7 @@ void console_unlock(void)
 		console_lock_spinning_enable();
 
 		stop_critical_timings();	/* don't trace print latency */
-		call_console_drivers(ext_text, ext_len, text, len);
+		call_console_drivers(ext_text, ext_len, text, len, msg->level);
 		start_critical_timings();

So it seems that now we always format the text and ext message (if needed) and only then check if there is at least one console we can print that message on.

Quoted 3 lines

Can we iterate the consoles first and check if msg is worth the effort (per console suppress_message_printing()) and only if it is do all the formatting and call console drivers?

Makes sense, will do.

Thanks,
Calvin

Quoted 1 line
	-ss
maintainer
#4 lore raw

Re: [PATCH 1/4] printk: Introduce per-console loglevel setting

In reply to Calvin Owens
Quoted 6 lines · Calvin Owens

Not all consoles are created equal: depending on the actual hardware, the latency of a printk() call can vary dramatically. The worst examples are serial consoles, where it can spin for tens of milliseconds banging the UART to emit a message, which can cause application-level problems when the kernel spews onto the console.

Quoted 7 lines

At Facebook we use netconsole to monitor our fleet, but we still have serial consoles attached on each host for live debugging, and the latter has caused problems. An obvious solution is to disable the kernel console output to ttyS0, but this makes live debugging frustrating, since crashes become silent and opaque to the ttyS0 user. Enabling it on the fly when needed isn't feasible, since boxes you need to debug via serial are likely to be borked in ways that make this impossible.

I guess that many other people have similar problem.

Quoted 8 lines
kernel/printk/printk.c +0 -0
index d3d170374ceb..6ead14f8c2bc 100644
@@ -1164,9 +1164,14 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 

kernel/printk/printk.c module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); · line 1174

Quoted 10 lines
kernel/printk/printk.c +7 -2
-static bool suppress_message_printing(int level)
+static int effective_loglevel(struct console *con)
 {
-	return (level >= console_loglevel && !ignore_loglevel);
+	return max(console_loglevel, con ? con->level : LOGLEVEL_EMERG);
+}
+
+static bool suppress_message_printing(int level, struct console *con)
+{
+	return (level >= effective_loglevel(con) && !ignore_loglevel);

Hmm, the semantic is cleaner when the per-console level defines the minimal loglevel. But it is still complicated. Also it is very confusing that the per-console value is called "level" or "loglevel" but it is actually minimal loglevel.

It might be even more straightforward when the per-console value defines the effective console level. I mean the following semantic:

+ "console_loglevel" would define the default loglevel used by consoles at runtime.

+ the per-console loglevel could override the default console_loglevel.

+ We would need a custom handler for the sysctl "console_loglevel". It would write the given value to the global console_loglevel variable and for all already registered consoles (con->loglevel).

The value will be used also for all newly registered consoles when they do not have any custom one.

+ The handler for "loglevel" early param should behave the same as the sysctl handler.

IMHO, there is no perfect solution. The advantage of the above proposal is that you "see" and "use" exactly what you "set".

kernel/printk/printk.c static void boot_delay_msec(int level) · line 1206

Quoted 9 lines
kernel/printk/printk.c +1 -1
 }
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
@@ -1198,7 +1203,7 @@ static void boot_delay_msec(int level)
 	unsigned long timeout;
 
 	if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING)
-		|| suppress_message_printing(level)) {
+		|| suppress_message_printing(level, NULL)) {

We should delay the message only when it will really reach the console. The same check might be used also for formatting the text as pointed out by Sergey in the other mail.

If the above proposal was accepted, we would have custom handlers for sysctl. Then we could easily maintain a global variable with maximal effective console loglevel.

Best Regards,
Petr

#5 lore raw

Re: [PATCH 1/4] printk: Introduce per-console loglevel setting

Quoted 6 lines · Petr Mladek

It might be even more straightforward when the per-console value defines the effective console level. I mean the following semantic:

+ "console_loglevel" would define the default loglevel used by consoles at runtime.

Quoted 6 lines

+ the per-console loglevel could override the default console_loglevel.

+ We would need a custom handler for the sysctl "console_loglevel". It would write the given value to the global console_loglevel variable and for all already registered consoles (con->loglevel).

But some functions change console_loglevel without sysctl (e.g. console_verbose() when reporting hung tasks and panic()). Should con->loglevel be changed (which might result in too much messages to slow consoles) when console_loglevel changes?

Quoted 11 lines

The value will be used also for all newly registered consoles when they do not have any custom one.

+ The handler for "loglevel" early param should behave the same as the sysctl handler.

IMHO, there is no perfect solution. The advantage of the above proposal is that you "see" and "use" exactly what you "set".

maintainer
#6 lore raw

Re: [PATCH 1/4] printk: Introduce per-console loglevel setting

Quoted 10 lines · Tetsuo Handa
Quoted 9 lines · Petr Mladek

It might be even more straightforward when the per-console value defines the effective console level. I mean the following semantic:

+ "console_loglevel" would define the default loglevel used by consoles at runtime.

+ the per-console loglevel could override the default console_loglevel.

Quoted 8 lines
Quoted 3 lines

+ We would need a custom handler for the sysctl "console_loglevel". It would write the given value to the global console_loglevel variable and for all already registered consoles (con->loglevel).

But some functions change console_loglevel without sysctl (e.g. console_verbose() when reporting hung tasks and panic()). Should con->loglevel be changed (which might result in too much messages to slow consoles) when console_loglevel changes?

It is about the semantic. We either want to set a hard limit for each console or we want to set per-console loglevel that will get used in normal situations.

I prefer the 2nd semantic. IMHO, console_verbose() should be used only in situations when people really want to see all lines, for example, panic, sysrq output when the machine looks deadlocked, ignore_loglevel is set. I believe that they want to see them even on the slow consoles that are there exactly for debugging these critical situations.

Best Regards,
Petr

#7 lore raw

PATCH 2/4 printk: Add ability to set loglevel via "console=" cmdline

In reply to Calvin Owens

This extends the "console=" interface to allow setting the per-console loglevel by adding "/N" to the string, where N is the desired loglevel expressed as a base 10 integer. Invalid values are silently ignored.

---
 .../admin-guide/kernel-parameters.txt         |  6 ++--
 kernel/printk/console_cmdline.h               |  1 +
 kernel/printk/printk.c                        | 30 +++++++++++++++----
 3 files changed, 28 insertions(+), 9 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +3 -3
index 858b6c0b9a15..afada61dcbce 100644
@@ -612,10 +612,10 @@
 		ttyS<n>[,options]
 		ttyUSB0[,options]
 			Use the specified serial port.  The options are of
-			the form "bbbbpnf", where "bbbb" is the baud rate,
+			the form "bbbbpnf/l", where "bbbb" is the baud rate,
 			"p" is parity ("n", "o", or "e"), "n" is number of
-			bits, and "f" is flow control ("r" for RTS or
-			omit it).  Default is "9600n8".
+			bits, "f" is flow control ("r" for RTS or omit it),
+			and "l" is the loglevel on [0,7]. Default is "9600n8".
 
 			See Documentation/admin-guide/serial-console.rst for more
 			information.  See
kernel/printk/console_cmdline.h +1 -0
index 11f19c466af5..fbf9b539366e 100644
@@ -6,6 +6,7 @@ struct console_cmdline
 {
 	char	name[16];			/* Name of the driver	    */
 	int	index;				/* Minor dev. to use	    */
+	int	loglevel;			/* Loglevel to use */
 	char	*options;			/* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
 	char	*brl_options;			/* Options for braille driver */
kernel/printk/printk.c +24 -6
index 6ead14f8c2bc..2e0eb89f046c 100644
@@ -2057,7 +2057,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 #endif
 
 static int __add_preferred_console(char *name, int idx, char *options,
-				   char *brl_options)
+				   int loglevel, char *brl_options)
 {
 	struct console_cmdline *c;
 	int i;
@@ -2083,6 +2083,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
 	c->options = options;
 	braille_set_options(c, brl_options);
 
+	c->loglevel = loglevel;
 	c->index = idx;
 	return 0;
 }
@@ -2104,8 +2105,8 @@ __setup("console_msg_format=", console_msg_format_setup);
 static int __init console_setup(char *str)
 {
 	char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */
-	char *s, *options, *brl_options = NULL;
-	int idx;
+	char *s, *options, *llevel, *brl_options = NULL;
+	int idx, loglevel = LOGLEVEL_EMERG;
 
 	if (_braille_console_setup(&str, &brl_options))
 		return 1;
@@ -2123,6 +2124,14 @@ static int __init console_setup(char *str)
 	options = strchr(str, ',');
 	if (options)
 		*(options++) = 0;
+
+	llevel = strchr(str, '/');
+	if (llevel) {
+		*(llevel++) = 0;
+		if (kstrtoint(llevel, 10, &loglevel))
+			loglevel = LOGLEVEL_EMERG;
+	}
+
 #ifdef __sparc__
 	if (!strcmp(str, "ttya"))
 		strcpy(buf, "ttyS0");
@@ -2135,7 +2144,7 @@ static int __init console_setup(char *str)
 	idx = simple_strtoul(s, NULL, 10);
 	*s = 0;
 
-	__add_preferred_console(buf, idx, options, brl_options);
+	__add_preferred_console(buf, idx, options, loglevel, brl_options);
 	console_set_on_cmdline = 1;
 	return 1;
 }
@@ -2156,7 +2165,8 @@ __setup("console=", console_setup);
  */
 int add_preferred_console(char *name, int idx, char *options)
 {
-	return __add_preferred_console(name, idx, options, NULL);
+	return __add_preferred_console(name, idx, options, LOGLEVEL_EMERG,
+				       NULL);
 }
 
 bool console_suspend_enabled = true;
@@ -2574,6 +2584,7 @@ void register_console(struct console *newcon)
 	struct console *bcon = NULL;
 	struct console_cmdline *c;
 	static bool has_preferred;
+	bool cmdline_exists = false;
 
 	if (console_drivers)
 		for_each_console(bcon)
@@ -2640,6 +2651,12 @@ void register_console(struct console *newcon)
 			if (newcon->index < 0)
 				newcon->index = c->index;
 
+			/*
+			 * Carry over the loglevel from the cmdline
+			 */
+			newcon->level = c->loglevel;
+			cmdline_exists = true;
+
 			if (_braille_register_console(newcon, c))
 				return;
 
@@ -2671,7 +2688,8 @@ void register_console(struct console *newcon)
 	/*
 	 * By default, the per-console minimum forces no messages through.
 	 */
-	newcon->level = LOGLEVEL_EMERG;
+	if (!cmdline_exists)
+		newcon->level = LOGLEVEL_EMERG;
 
 	/*
 	 *	Put this console in the list - keep the
Signature · 1 line
2.17.1
maintainer
#8 lore raw

Re: [PATCH 2/4] printk: Add ability to set loglevel via "console=" cmdline

Quoted 16 lines · Calvin Owens

This extends the "console=" interface to allow setting the per-console loglevel by adding "/N" to the string, where N is the desired loglevel expressed as a base 10 integer. Invalid values are silently ignored.

---
 .../admin-guide/kernel-parameters.txt         |  6 ++--
 kernel/printk/console_cmdline.h               |  1 +
 kernel/printk/printk.c                        | 30 +++++++++++++++----
 3 files changed, 28 insertions(+), 9 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +0 -0
index 858b6c0b9a15..afada61dcbce 100644

Documentation/admin-guide/kernel-parameters.txt line 618

Quoted 10 lines
Documentation/admin-guide/kernel-parameters.txt +3 -3
@@ -612,10 +612,10 @@
 		ttyS<n>[,options]
 		ttyUSB0[,options]
 			Use the specified serial port.  The options are of
-			the form "bbbbpnf", where "bbbb" is the baud rate,
+			the form "bbbbpnf/l", where "bbbb" is the baud rate,
 			"p" is parity ("n", "o", or "e"), "n" is number of
-			bits, and "f" is flow control ("r" for RTS or
-			omit it).  Default is "9600n8".
+			bits, "f" is flow control ("r" for RTS or omit it),
+			and "l" is the loglevel on [0,7]. Default is "9600n8".

We should a more detailed explanation about the loglevel semantic. It is either minimal loglevel. Or that it overrides the global console_loglevel if you accept my proposal.

kernel/printk/console_cmdline.h struct console_cmdline · line 9

Quoted 12 lines
Documentation/admin-guide/kernel-parameters.txt +0 -0
 			See Documentation/admin-guide/serial-console.rst for more
 			information.  See
kernel/printk/console_cmdline.h +1 -0
index 11f19c466af5..fbf9b539366e 100644
@@ -6,6 +6,7 @@ struct console_cmdline
 {
 	char	name[16];			/* Name of the driver	    */
 	int	index;				/* Minor dev. to use	    */
+	int	loglevel;			/* Loglevel to use */

The comment will be true only with the new proposal.

Quoted 19 lines
kernel/printk/console_cmdline.h +0 -0
 	char	*options;			/* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
 	char	*brl_options;			/* Options for braille driver */
kernel/printk/printk.c +2 -2
index 6ead14f8c2bc..2e0eb89f046c 100644
@@ -2104,8 +2105,8 @@ __setup("console_msg_format=", console_msg_format_setup);
 static int __init console_setup(char *str)
 {
 	char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */
-	char *s, *options, *brl_options = NULL;
-	int idx;
+	char *s, *options, *llevel, *brl_options = NULL;
+	int idx, loglevel = LOGLEVEL_EMERG;
 
 	if (_braille_console_setup(&str, &brl_options))
 		return 1;

kernel/printk/printk.c static int __init console_setup(char *str) · line 2128

Quoted 5 lines
kernel/printk/printk.c +2 -0
@@ -2123,6 +2124,14 @@ static int __init console_setup(char *str)
 	options = strchr(str, ',');
 	if (options)
 		*(options++) = 0;
+
+	llevel = strchr(str, '/');

This should be:

      if (options)
		llevel = strchr(options, '/');

kernel/printk/printk.c static int __init console_setup(char *str) · line 2137

Quoted 9 lines
kernel/printk/printk.c +6 -0
+	if (llevel) {
+		*(llevel++) = 0;
+		if (kstrtoint(llevel, 10, &loglevel))
+			loglevel = LOGLEVEL_EMERG;
+	}
+
 #ifdef __sparc__
 	if (!strcmp(str, "ttya"))
 		strcpy(buf, "ttyS0");

Best Regards,
Petr

#9 lore raw

PATCH 3/4 printk: Add consoles to a virtual "console" bus

In reply to Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Currently, most drivers declare static console structs, and that is incompatible with the dev refcount model. So we end up needing to patch all of the console drivers to:

1. Dynamically allocate the console struct using a new helper
2. Handle the allocation in (1) possibly failing
3. Dispose of (1) with put_device()

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

---
 arch/alpha/kernel/srmcons.c                   |  10 +-
 arch/arm/kernel/early_printk.c                |   7 +-
 arch/ia64/hp/sim/hpsim_console.c              |   9 +-
 arch/m68k/amiga/config.c                      |  17 ++-
 arch/m68k/atari/debug.c                       |  29 ++++-
 arch/m68k/emu/nfcon.c                         |  60 ++++++---
 arch/m68k/kernel/early_printk.c               |   9 +-
 arch/m68k/q40/config.c                        |   7 +-
 arch/m68k/sun3x/prom.c                        |   7 +-
 arch/mips/dec/prom/console.c                  |   7 +-
 arch/mips/fw/arc/arc_con.c                    |  12 +-
 arch/mips/kernel/early_printk.c               |   9 +-
 arch/mips/sibyte/common/cfe_console.c         |  12 +-
 arch/parisc/kernel/pdc_cons.c                 |   9 +-
 arch/powerpc/kernel/udbg.c                    |   7 +-
 arch/s390/kernel/early_printk.c               |   7 +-
 arch/sh/kernel/sh_bios.c                      |   9 +-
 arch/sparc/kernel/btext.c                     |   7 +-
 arch/sparc/kernel/setup_32.c                  |   7 +-
 arch/sparc/kernel/setup_64.c                  |   7 +-
 arch/um/drivers/mconsole_kern.c               |  15 ++-
 arch/um/drivers/ssl.c                         |  22 +++-
 arch/um/drivers/stderr_console.c              |   7 +-
 arch/um/drivers/stdio_console.c               |  22 +++-
 arch/um/kernel/early_printk.c                 |   7 +-
 arch/unicore32/kernel/early_printk.c          |   7 +-
 arch/x86/include/asm/efi.h                    |   1 +
 arch/x86/kernel/early_printk.c                |  14 ++-
 arch/x86/platform/efi/early_printk.c          |   9 +-
 arch/xtensa/platforms/iss/console.c           |  10 +-
 .../accessibility/braille/braille_console.c   |   6 +-
 drivers/char/lp.c                             |  19 ++-
 drivers/hwtracing/stm/console.c               |  19 +--
 drivers/misc/pti.c                            |  26 ++--
 drivers/net/netconsole.c                      |  99 +++++++--------
 drivers/s390/char/con3215.c                   |  11 +-
 drivers/s390/char/con3270.c                   |  12 +-
 drivers/s390/char/sclp_con.c                  |  17 ++-
 drivers/s390/char/sclp_vt220.c                |  18 ++-
 drivers/tty/amiserial.c                       |  13 +-
 drivers/tty/ehv_bytechan.c                    |  19 ++-
 drivers/tty/goldfish.c                        |  34 ++++--
 drivers/tty/hvc/hvc_console.c                 |   8 +-
 drivers/tty/hvc/hvc_xen.c                     |  15 ++-
 drivers/tty/hvc/hvsi.c                        |  14 ++-
 drivers/tty/mips_ejtag_fdc.c                  |  44 ++++---
 drivers/tty/serial/21285.c                    |  25 ++--
 drivers/tty/serial/8250/8250_core.c           |  22 ++--
 drivers/tty/serial/8250/8250_early.c          |  18 ++-
 drivers/tty/serial/8250/8250_ingenic.c        |   6 +-
 drivers/tty/serial/altera_jtaguart.c          |  33 +++--
 drivers/tty/serial/altera_uart.c              |  25 ++--
 drivers/tty/serial/amba-pl010.c               |  35 ++++--
 drivers/tty/serial/amba-pl011.c               |  47 +++++---
 drivers/tty/serial/apbuart.c                  |  24 ++--
 drivers/tty/serial/ar933x_uart.c              |  13 +-
 drivers/tty/serial/arc_uart.c                 |  27 +++--
 drivers/tty/serial/atmel_serial.c             |  31 +++--
 drivers/tty/serial/bcm63xx_uart.c             |  25 ++--
 drivers/tty/serial/clps711x.c                 |  17 +--
 drivers/tty/serial/cpm_uart/cpm_uart_core.c   |  21 ++--
 drivers/tty/serial/digicolor-usart.c          |  24 ++--
 drivers/tty/serial/dz.c                       |  18 +--
 drivers/tty/serial/earlycon-arm-semihost.c    |   6 +-
 drivers/tty/serial/earlycon.c                 |   5 +-
 drivers/tty/serial/efm32-uart.c               |  22 ++--
 drivers/tty/serial/fsl_lpuart.c               |  57 ++++-----
 drivers/tty/serial/imx.c                      |  35 ++++--
 drivers/tty/serial/ip22zilog.c                |  18 +--
 drivers/tty/serial/kgdb_nmi.c                 |  21 +++-
 drivers/tty/serial/kgdboc.c                   |   2 +-
 drivers/tty/serial/lantiq.c                   |  23 ++--
 drivers/tty/serial/lpc32xx_hs.c               |  21 ++--
 drivers/tty/serial/mcf.c                      |  18 +--
 drivers/tty/serial/meson_uart.c               |  26 ++--
 drivers/tty/serial/mpc52xx_uart.c             |  18 +--
 drivers/tty/serial/mps2-uart.c                |  34 ++++--
 drivers/tty/serial/mpsc.c                     |  23 ++--
 drivers/tty/serial/msm_serial.c               |  36 ++++--
 drivers/tty/serial/mux.c                      |  44 ++++---
 drivers/tty/serial/mvebu-uart.c               |  30 +++--
 drivers/tty/serial/mxs-auart.c                |  18 +--
 drivers/tty/serial/netx-serial.c              |  20 +--
 drivers/tty/serial/omap-serial.c              |  40 +++---
 drivers/tty/serial/owl-uart.c                 |  29 +++--
 drivers/tty/serial/pch_uart.c                 |  26 ++--
 drivers/tty/serial/pic32_uart.c               |  30 +++--
 drivers/tty/serial/pmac_zilog.c               |  19 +--
 drivers/tty/serial/pnx8xxx_uart.c             |  20 +--
 drivers/tty/serial/pxa.c                      |  25 ++--
 drivers/tty/serial/qcom_geni_serial.c         |  57 ++++-----
 drivers/tty/serial/rda-uart.c                 |  26 ++--
 drivers/tty/serial/sa1100.c                   |  20 +--
 drivers/tty/serial/samsung.c                  |  41 +++++--
 drivers/tty/serial/sb1250-duart.c             |  20 +--
 drivers/tty/serial/sccnxp.c                   |  26 ++--
 drivers/tty/serial/serial_core.c              |  16 ++-
 drivers/tty/serial/serial_ks8695.c            |  25 ++--
 drivers/tty/serial/serial_txx9.c              |  21 ++--
 drivers/tty/serial/sh-sci.c                   |  55 ++++++---
 drivers/tty/serial/sirfsoc_uart.c             |  26 ++--
 drivers/tty/serial/sn_console.c               |  25 ++--
 drivers/tty/serial/sprd_serial.c              |  25 ++--
 drivers/tty/serial/st-asc.c                   |  27 +++--
 drivers/tty/serial/stm32-usart.c              |  17 ++-
 drivers/tty/serial/sunhv.c                    |  29 +++--
 drivers/tty/serial/sunsab.c                   |  29 ++---
 drivers/tty/serial/sunsu.c                    |  26 ++--
 drivers/tty/serial/sunzilog.c                 |  26 ++--
 drivers/tty/serial/uartlite.c                 |  23 ++--
 drivers/tty/serial/vr41xx_siu.c               |  31 +++--
 drivers/tty/serial/vt8500_serial.c            |  25 ++--
 drivers/tty/serial/xilinx_uartps.c            |  42 +++----
 drivers/tty/serial/zs.c                       |  25 ++--
 drivers/tty/tty_io.c                          |   6 +-
 drivers/tty/vt/vt.c                           |  14 ++-
 drivers/usb/early/ehci-dbgp.c                 |   7 +-
 drivers/usb/early/xhci-dbc.c                  |   7 +-
 drivers/usb/gadget/function/u_serial.c        |  22 ++--
 drivers/usb/serial/console.c                  |  24 ++--
 drivers/usb/serial/usb-serial.c               |  13 +-
 fs/proc/consoles.c                            |  10 +-
 fs/pstore/platform.c                          |  25 ++--
 include/linux/console.h                       |  36 +++++-
 include/linux/serial_core.h                   |  19 +++
 include/linux/usb/serial.h                    |   4 +-
 kernel/debug/debug_core.c                     |   7 +-
 kernel/debug/kdb/kdb_io.c                     |   4 +-
 kernel/printk/printk.c                        | 114 +++++++++++++++---
 129 files changed, 1772 insertions(+), 1036 deletions(-)
arch/alpha/kernel/srmcons.c +8 -2
index 438b10c44d73..f4de0ba8240b 100644
@@ -266,15 +266,21 @@ srm_console_setup(struct console *co, char *options)
 	return 0;
 }
 
-static struct console srmcons = {
-	.name		= "srm",
+static const struct console_operations srmcons_cons_ops = {
 	.write		= srm_console_write,
 	.device		= srm_console_device,
 	.setup		= srm_console_setup,
+};
+
+static struct console srmcons = {
+	.name		= "srm",
+	.ops		= &srmcons_cons_ops,
 	.flags		= CON_PRINTBUFFER | CON_BOOT,
 	.index		= -1,
+	.is_static	= 1,
 };
 
+
 void __init
 register_srm_console(void)
 {
arch/arm/kernel/early_printk.c +6 -1
index 9257736ec9fa..3af38403468e 100644
@@ -33,11 +33,16 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
 	early_write(s, n);
 }
 
+static const struct console_operations early_console_ops = {
+	.write =	early_console_write,
+};
+
 static struct console early_console_dev = {
 	.name =		"earlycon",
-	.write =	early_console_write,
 	.flags =	CON_PRINTBUFFER | CON_BOOT,
 	.index =	-1,
+	.ops =		&early_console_ops,
+	.is_static =	1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/ia64/hp/sim/hpsim_console.c +7 -2
index bffd9f67a8a1..68be4eb8c5c8 100644
@@ -30,13 +30,18 @@ static int simcons_init (struct console *, char *);
 static void simcons_write (struct console *, const char *, unsigned);
 static struct tty_driver *simcons_console_device (struct console *, int *);
 
-static struct console hpsim_cons = {
-	.name =		"simcons",
+static const struct console_operations hpsim_cons_ops = {
 	.write =	simcons_write,
 	.device =	simcons_console_device,
 	.setup =	simcons_init,
+};
+
+static struct console hpsim_cons = {
+	.name =		"simcons",
 	.flags =	CON_PRINTBUFFER,
+	.ops =		&hpsim_cons_ops,
 	.index =	-1,
+	.is_static =	1,
 };
 
 static int
arch/m68k/amiga/config.c +13 -4
index 65f63a457130..184520b4461f 100644
@@ -110,6 +110,7 @@ static struct console amiga_console_driver = {
 	.name	= "debug",
 	.flags	= CON_PRINTBUFFER,
 	.index	= -1,
+	.is_static = 1,
 };
 
 
@@ -617,6 +618,10 @@ static void amiga_mem_console_write(struct console *co, const char *s,
 	}
 }
 
+static const struct console_operations amiga_mem_ops = {
+	.write = amiga_mem_console_write,
+};
+
 static int __init amiga_savekmsg_setup(char *arg)
 {
 	bool registered;
@@ -637,8 +642,8 @@ static int __init amiga_savekmsg_setup(char *arg)
 	savekmsg->magicptr = ZTWO_PADDR(savekmsg);
 	savekmsg->size = 0;
 
-	registered = !!amiga_console_driver.write;
-	amiga_console_driver.write = amiga_mem_console_write;
+	registered = !!amiga_console_driver.ops;
+	amiga_console_driver.ops = &amiga_mem_ops;
 	if (!registered)
 		register_console(&amiga_console_driver);
 	return 0;
@@ -663,6 +668,10 @@ static void amiga_serial_console_write(struct console *co, const char *s,
 	}
 }
 
+static const struct console_operations amiga_serial_ops = {
+	.write = amiga_serial_console_write,
+};
+
 #if 0
 void amiga_serial_puts(const char *s)
 {
@@ -728,8 +737,8 @@ static int __init amiga_debug_setup(char *arg)
 		return 0;
 
 	/* no initialization required (?) */
-	registered = !!amiga_console_driver.write;
-	amiga_console_driver.write = amiga_serial_console_write;
+	registered = !!amiga_console_driver.ops;
+	amiga_console_driver.ops = &amiga_serial_ops;
 	if (!registered)
 		register_console(&amiga_console_driver);
 	return 0;
arch/m68k/atari/debug.c +23 -6
index 03cb5e08d7cf..3edb58b52b8c 100644
@@ -29,6 +29,7 @@ static struct console atari_console_driver = {
 	.name	= "debug",
 	.flags	= CON_PRINTBUFFER,
 	.index	= -1,
+	.is_static = 1,
 };
 
 
@@ -49,6 +50,10 @@ static void atari_mfp_console_write(struct console *co, const char *str,
 	}
 }
 
+static const struct console_operations mfp_ops = {
+	.write = atari_mfp_console_write,
+};
+
 static inline void ata_scc_out(char c)
 {
 	do {
@@ -68,6 +73,10 @@ static void atari_scc_console_write(struct console *co, const char *str,
 	}
 }
 
+static const struct console_operations scc_ops = {
+	.write = atari_scc_console_write,
+};
+
 static inline void ata_midi_out(char c)
 {
 	while (!(acia.mid_ctrl & ACIA_TDRE))	/* wait for tx buf empty */
@@ -85,6 +94,10 @@ static void atari_midi_console_write(struct console *co, const char *str,
 	}
 }
 
+static const struct console_operations midi_ops = {
+	.write = atari_midi_console_write,
+};
+
 static int ata_par_out(char c)
 {
 	unsigned char tmp;
@@ -128,6 +141,10 @@ static void atari_par_console_write(struct console *co, const char *str,
 	}
 }
 
+static const struct console_operations par_ops = {
+	.write = atari_par_console_write,
+};
+
 #if 0
 int atari_mfp_console_wait_key(struct console *co)
 {
@@ -296,19 +313,19 @@ static int __init atari_debug_setup(char *arg)
 		/* defaults to ser2 for a Falcon and ser1 otherwise */
 		arg = MACH_IS_FALCON ? "ser2" : "ser1";
 
-	registered = !!atari_console_driver.write;
+	registered = !!atari_console_driver.ops;
 	if (!strcmp(arg, "ser1")) {
 		/* ST-MFP Modem1 serial port */
 		atari_init_mfp_port(B9600|CS8);
-		atari_console_driver.write = atari_mfp_console_write;
+		atari_console_driver.ops = &mfp_ops;
 	} else if (!strcmp(arg, "ser2")) {
 		/* SCC Modem2 serial port */
 		atari_init_scc_port(B9600|CS8);
-		atari_console_driver.write = atari_scc_console_write;
+		atari_console_driver.ops = &scc_ops;
 	} else if (!strcmp(arg, "midi")) {
 		/* MIDI port */
 		atari_init_midi_port(B9600|CS8);
-		atari_console_driver.write = atari_midi_console_write;
+		atari_console_driver.ops = &midi_ops;
 	} else if (!strcmp(arg, "par")) {
 		/* parallel printer */
 		atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
@@ -318,9 +335,9 @@ static int __init atari_debug_setup(char *arg)
 		sound_ym.wd_data = 0;		/* no char */
 		sound_ym.rd_data_reg_sel = 14;	/* select port A */
 		sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
-		atari_console_driver.write = atari_par_console_write;
+		atari_console_driver.ops = &par_ops;
 	}
-	if (atari_console_driver.write && !registered)
+	if (atari_console_driver.ops && !registered)
 		register_console(&atari_console_driver);
 
 	return 0;
arch/m68k/emu/nfcon.c +41 -19

94 lines not on this page · raw message

arch/m68k/kernel/early_printk.c +7 -2
index 7d3fe08a48eb..e8f8efb42044 100644
@@ -29,11 +29,16 @@ static void __ref debug_cons_write(struct console *c,
 #endif
 }
 
+static const struct console_operations early_ops = {
+	.write = debug_cons_write,
+};
+
 static struct console early_console_instance = {
 	.name  = "debug",
-	.write = debug_cons_write,
 	.flags = CON_PRINTBUFFER | CON_BOOT,
-	.index = -1
+	.ops = &early_ops,
+	.index = -1,
+	.is_static = 1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/m68k/q40/config.c +6 -1
index 96810d91da2b..6a919a61a5d4 100644
@@ -53,11 +53,16 @@ static void q40_mem_console_write(struct console *co, const char *b,
 
 extern int ql_ticks;
 
+static const struct console_operations q40_mem_ops = {
+	.write	= q40_mem_console_write,
+};
+
 static struct console q40_console_driver = {
 	.name	= "debug",
-	.write	= q40_mem_console_write,
 	.flags	= CON_PRINTBUFFER,
+	.ops = &q40_mem_ops,
 	.index	= -1,
+	.is_static = 1,
 };
 
 
arch/m68k/sun3x/prom.c +6 -1
index be14c899ab7d..661ef959a451 100644
@@ -85,11 +85,16 @@ static void sun3x_prom_write(struct console *co, const char *s,
 
 /* debug console - write-only */
 
+static const struct console_operations sun3x_prom = {
+	.write	= sun3x_prom_write,
+};
+
 static struct console sun3x_debug = {
 	.name	= "debug",
-	.write	= sun3x_prom_write,
 	.flags	= CON_PRINTBUFFER,
+	.ops = &sun3x_prom,
 	.index	= -1,
+	.is_static = 1,
 };
 
 void __init sun3x_prom_init(void)
arch/mips/dec/prom/console.c +6 -1
index caa6e047caf1..707237815e2b 100644
@@ -32,11 +32,16 @@ static void __init prom_console_write(struct console *con, const char *s,
 	}
 }
 
+static struct console_operations early_ops __initdata = {
+	.write	= prom_console_write,
+};
+
 static struct console promcons __initdata = {
 	.name	= "prom",
-	.write	= prom_console_write,
 	.flags	= CON_BOOT | CON_PRINTBUFFER,
+	.ops = &early_ops,
 	.index	= -1,
+	.is_static = 1,
 };
 
 void __init register_prom_console(void)
arch/mips/fw/arc/arc_con.c +7 -5
index 365e3913231e..2cd246958e1f 100644
@@ -31,12 +31,9 @@ static int prom_console_setup(struct console *co, char *options)
 	return !(prom_flags & PROM_FLAG_USE_AS_CONSOLE);
 }
 
-static struct console arc_cons = {
-	.name		= "arc",
+static const struct console_operations arc_ops = {
 	.write		= prom_console_write,
 	.setup		= prom_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
 };
 
 /*
@@ -45,8 +42,13 @@ static struct console arc_cons = {
 
 static int __init arc_console_init(void)
 {
-	register_console(&arc_cons);
+	struct console *arc_cons;
 
+	arc_cons = allocate_console_dfl(&arc_ops, "arc", NULL);
+	if (!arc_cons)
+		return -ENOMEM;
+
+	register_console(arc_cons);
 	return 0;
 }
 console_initcall(arc_console_init);
arch/mips/kernel/early_printk.c +7 -2
index 4a1647ddfbd9..1b7b8994dd76 100644
@@ -24,11 +24,16 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
 	}
 }
 
+static const struct console_operations early_ops = {
+	.write	= early_console_write,
+};
+
 static struct console early_console_prom = {
 	.name	= "early",
-	.write	= early_console_write,
 	.flags	= CON_PRINTBUFFER | CON_BOOT,
-	.index	= -1
+	.ops = &early_ops,
+	.index	= -1,
+	.is_static = 1,
 };
 
 void __init setup_early_printk(void)
arch/mips/sibyte/common/cfe_console.c +7 -5
index 8af7b41f7c19..51e81c0d3923 100644
@@ -64,17 +64,19 @@ static int cfe_console_setup(struct console *cons, char *str)
 	return 0;
 }
 
-static struct console sb1250_cfe_cons = {
-	.name		= "cfe",
+static const struct console_operations cfe_ops = {
 	.write		= cfe_console_write,
 	.setup		= cfe_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
 };
 
 static int __init sb1250_cfe_console_init(void)
 {
-	register_console(&sb1250_cfe_cons);
+	struct console *sb1250_cfe = allocate_console_dfl(&cfe_ops, "cfe",
+							  NULL);
+	if (!sb1250_cfe)
+		return -ENOMEM;
+
+	register_console(sb1250_cfe);
 	return 0;
 }
 
arch/parisc/kernel/pdc_cons.c +7 -2
index c46bf29ae412..9c7f157aa133 100644
@@ -218,13 +218,18 @@ static struct tty_driver * pdc_console_device (struct console *c, int *index)
 #define pdc_console_device NULL
 #endif
 
-static struct console pdc_cons = {
-	.name =		"ttyB",
+static const struct console_operations pdc_ops = {
 	.write =	pdc_console_write,
 	.device =	pdc_console_device,
 	.setup =	pdc_console_setup,
+};
+
+static struct console pdc_cons = {
+	.name =		"ttyB",
 	.flags =	CON_BOOT | CON_PRINTBUFFER,
+	.ops =		&pdc_ops,
 	.index =	-1,
+	.is_static =	1,
 };
 
 static int pdc_console_initialized;
arch/powerpc/kernel/udbg.c +6 -1
index 7cc38b5b58bc..91a369c9691e 100644
@@ -148,11 +148,16 @@ static void udbg_console_write(struct console *con, const char *s,
 	udbg_write(s, n);
 }
 
+static const struct console_operations udbg_ops = {
+	.write	= udbg_console_write,
+};
+
 static struct console udbg_console = {
 	.name	= "udbg",
-	.write	= udbg_console_write,
 	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+	.ops	= &udbg_ops,
 	.index	= 0,
+	.is_static = 1,
 };
 
 /*
arch/s390/kernel/early_printk.c +6 -1
index 40c1dfec944e..f3aaf7748027 100644
@@ -13,11 +13,16 @@ static void sclp_early_write(struct console *con, const char *s, unsigned int le
 	__sclp_early_printk(s, len, 0);
 }
 
+static const struct console_operations sclp_ops = {
+	.write = sclp_early_write,
+};
+
 static struct console sclp_early_console = {
 	.name  = "earlysclp",
-	.write = sclp_early_write,
 	.flags = CON_PRINTBUFFER | CON_BOOT,
+	.ops = &sclp_ops,
 	.index = -1,
+	.is_static = 1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/sh/kernel/sh_bios.c +7 -2
index 250dbdf3fa74..2cbd042d452f 100644
@@ -134,12 +134,17 @@ static int __init sh_console_setup(struct console *co, char *options)
 	return 0;
 }
 
-static struct console bios_console = {
-	.name		= "bios",
+static const struct console_operations bios_ops = {
 	.write		= sh_console_write,
 	.setup		= sh_console_setup,
+};
+
+static struct console bios_console = {
+	.name		= "bios",
 	.flags		= CON_PRINTBUFFER,
+	.ops		= &bios_ops,
 	.index		= -1,
+	.is_static	= 1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/sparc/kernel/btext.c +6 -1
index 5869773f3dc4..d5a165eaa161 100644
@@ -300,11 +300,16 @@ static void btext_console_write(struct console *con, const char *s,
 	btext_drawtext(s, n);
 }
 
+static const struct console_operations btext_ops = {
+	.write	= btext_console_write,
+};
+
 static struct console btext_console = {
 	.name	= "btext",
-	.write	= btext_console_write,
 	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
+	.ops = &btext_ops,
 	.index	= 0,
+	.is_static = 1,
 };
 
 int __init btext_find_display(void)
arch/sparc/kernel/setup_32.c +6 -1
index afe1592a6d08..e36dbc2cb8da 100644
@@ -114,11 +114,16 @@ prom_console_write(struct console *con, const char *s, unsigned int n)
 	prom_write(s, n);
 }
 
+static const struct console_operations prom_ops = {
+	.write =	prom_console_write,
+};
+
 static struct console prom_early_console = {
 	.name =		"earlyprom",
-	.write =	prom_console_write,
 	.flags =	CON_PRINTBUFFER | CON_BOOT,
+	.ops =		&prom_ops,
 	.index =	-1,
+	.is_static =	1,
 };
 
 /* 
arch/sparc/kernel/setup_64.c +6 -1
index 51c4d12c0853..0cc1dfcd8d5b 100644
@@ -90,11 +90,16 @@ prom_console_write(struct console *con, const char *s, unsigned int n)
 /* Exported for mm/init.c:paging_init. */
 unsigned long cmdline_memory_size = 0;
 
+static const struct console_operations prom_ops = {
+	.write =	prom_console_write,
+};
+
 static struct console prom_early_console = {
 	.name =		"earlyprom",
-	.write =	prom_console_write,
 	.flags =	CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
+	.ops =		&prom_ops,
 	.index =	-1,
+	.is_static =	1,
 };
 
 /*
arch/um/drivers/mconsole_kern.c +10 -5
index ff3ab72fd90f..5a6e5acec5d0 100644
@@ -572,14 +572,19 @@ static void console_write(struct console *console, const char *string,
 	}
 }
 
-static struct console mc_console = { .name	= "mc",
-				     .write	= console_write,
-				     .flags	= CON_ENABLED,
-				     .index	= -1 };
+static const struct console_operations mc_cons_ops = {
+	.write = console_write,
+};
 
 static int mc_add_console(void)
 {
-	register_console(&mc_console);
+	struct console *mc_console = allocate_console_dfl(&mc_cons_ops, "mc",
+							  NULL);
+	if (!mc_console)
+		return -ENOMEM;
+
+	mc_console->flags = CON_ENABLED;
+	register_console(mc_console);
 	return 0;
 }
 
arch/um/drivers/ssl.c +17 -5
index b8d14fa52059..2f44fea2c455 100644
@@ -138,15 +138,15 @@ static int ssl_console_setup(struct console *co, char *options)
 }
 
 /* No locking for register_console call - relies on single-threaded initcalls */
-static struct console ssl_cons = {
-	.name		= "ttyS",
+
+static const struct console_operations ssl_cons_ops = {
 	.write		= ssl_console_write,
 	.device		= ssl_console_device,
 	.setup		= ssl_console_setup,
-	.flags		= CON_PRINTBUFFER|CON_ANYTIME,
-	.index		= -1,
 };
 
+static struct console *ssl_cons;
+
 static int ssl_init(void)
 {
 	char *new_title;
@@ -156,10 +156,16 @@ static int ssl_init(void)
 	printk(KERN_INFO "Initializing software serial port version %d\n",
 	       ssl_version);
 
+	ssl_cons = allocate_console_dfl(&ssl_cons_ops, "ttyS", NULL);
+	if (!ssl_cons)
+		return -ENOMEM;
+
+	ssl_cons->flags |= CON_ANYTIME;
+
 	err = register_lines(&driver, &ssl_ops, serial_lines,
 				    ARRAY_SIZE(serial_lines));
 	if (err)
-		return err;
+		goto out;
 
 	new_title = add_xterm_umid(opts.xterm_title);
 	if (new_title != NULL)
@@ -178,6 +184,9 @@ static int ssl_init(void)
 	ssl_init_done = 1;
 	register_console(&ssl_cons);
 	return 0;
+out:
+	kfree(ssl_cons);
+	return err;
 }
 late_initcall(ssl_init);
 
@@ -185,7 +194,10 @@ static void ssl_exit(void)
 {
 	if (!ssl_init_done)
 		return;
+
+	unregister_console(&ssl_cons);
 	close_lines(serial_lines, ARRAY_SIZE(serial_lines));
+	put_device(&ssl_cons->dev);
 }
 __uml_exitcall(ssl_exit);
 
arch/um/drivers/stderr_console.c +6 -1
index ecc3a5814932..8c4c6f8e1a32 100644
@@ -22,10 +22,15 @@ static void stderr_console_write(struct console *console, const char *string,
 	generic_write(2 /* stderr */, string, len, NULL);
 }
 
+static const struct console_operations stderr_ops = {
+	.write		= stderr_console_write,
+};
+
 static struct console stderr_console = {
 	.name		= "stderr",
-	.write		= stderr_console_write,
 	.flags		= CON_PRINTBUFFER,
+	.ops		= &stderr_ops,
+	.is_static	= 1,
 };
 
 static int __init stderr_console_init(void)
arch/um/drivers/stdio_console.c +16 -6
index c90817b04da9..7cd000b3b095 100644
@@ -138,25 +138,31 @@ static int uml_console_setup(struct console *co, char *options)
 }
 
 /* No locking for register_console call - relies on single-threaded initcalls */
-static struct console stdiocons = {
-	.name		= "tty",
+
+static const struct console_operations uml_cons_ops = {
 	.write		= uml_console_write,
 	.device		= uml_console_device,
 	.setup		= uml_console_setup,
-	.flags		= CON_PRINTBUFFER|CON_ANYTIME,
-	.index		= -1,
 };
 
+static struct console *stdiocons;
+
 static int stdio_init(void)
 {
 	char *new_title;
 	int err;
 	int i;
 
+	stdiocons = allocate_console_dfl(&uml_cons_ops, "tty", NULL);
+	if (!stdiocons)
+		return -ENOMEM;
+
+	stdiocons->flags |= CON_ANYTIME;
+
 	err = register_lines(&driver, &console_ops, vts,
 					ARRAY_SIZE(vts));
 	if (err)
-		return err;
+		goto out;
 
 	printk(KERN_INFO "Initialized stdio console driver\n");
 
@@ -177,8 +183,11 @@ static int stdio_init(void)
 	}
 
 	con_init_done = 1;
-	register_console(&stdiocons);
+	register_console(stdiocons);
 	return 0;
+out:
+	put_console(stdiocons);
+	return err;
 }
 late_initcall(stdio_init);
 
@@ -187,6 +196,7 @@ static void console_exit(void)
 	if (!con_init_done)
 		return;
 	close_lines(vts, ARRAY_SIZE(vts));
+	put_console(stdiocons);
 }
 __uml_exitcall(console_exit);
 
arch/um/kernel/early_printk.c +6 -1
index 4a0800bc37b2..96b20439d6f3 100644
@@ -16,11 +16,16 @@ static void early_console_write(struct console *con, const char *s, unsigned int
 	um_early_printk(s, n);
 }
 
+static const struct console_operations early_ops = {
+	.write = early_console_write,
+};
+
 static struct console early_console_dev = {
 	.name = "earlycon",
-	.write = early_console_write,
 	.flags = CON_BOOT,
+	.ops = &early_ops,
 	.index = -1,
+	.is_static = 1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/unicore32/kernel/early_printk.c +6 -1
index f2f6323c8d64..31d66e9e3d0d 100644
@@ -26,11 +26,16 @@ static void early_ocd_write(struct console *con, const char *s, unsigned n)
 	}
 }
 
+static const struct console_operations ocd_ops = {
+	.write =	early_ocd_write,
+};
+
 static struct console early_ocd_console = {
 	.name =		"earlyocd",
-	.write =	early_ocd_write,
 	.flags =	CON_PRINTBUFFER,
+	.ops =		&ocd_ops,
 	.index =	-1,
+	.is_static =	1,
 };
 
 static int __init setup_early_printk(char *buf)
arch/x86/include/asm/efi.h +1 -0
index 107283b1eb1e..790d0f4bcbb2 100644
@@ -171,6 +171,7 @@ static inline bool efi_runtime_supported(void)
 }
 
 extern struct console early_efi_console;
+extern const struct console_operations early_efi_ops;
 extern void parse_efi_setup(u64 phys_addr, u32 data_len);
 
 extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
arch/x86/kernel/early_printk.c +12 -2
index 374a52fa5296..56034af5bc6c 100644
@@ -70,11 +70,16 @@ static void early_vga_write(struct console *con, const char *str, unsigned n)
 	}
 }
 
+static const struct console_operations early_vga_ops = {
+	.write =	early_vga_write,
+};
+
 static struct console early_vga_console = {
 	.name =		"earlyvga",
-	.write =	early_vga_write,
 	.flags =	CON_PRINTBUFFER,
 	.index =	-1,
+	.ops =		&early_vga_ops,
+	.is_static =	1,
 };
 
 /* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
@@ -320,11 +325,16 @@ static __init void early_pci_serial_init(char *s)
 }
 #endif
 
+static const struct console_operations early_serial_ops = {
+	.write =	early_serial_write,
+};
+
 static struct console early_serial_console = {
 	.name =		"earlyser",
-	.write =	early_serial_write,
 	.flags =	CON_PRINTBUFFER,
 	.index =	-1,
+	.ops =		&early_serial_ops,
+	.is_static =	1,
 };
 
 static void early_console_register(struct console *con, int keep_early)
arch/x86/platform/efi/early_printk.c +7 -2
index 7138bc7a265c..d1d706ac026e 100644
@@ -231,10 +231,15 @@ static __init int early_efi_setup(struct console *con, char *options)
 	return 0;
 }
 
-struct console early_efi_console = {
-	.name =		"earlyefi",
+static const struct console_operations early_efi_ops = {
 	.write =	early_efi_write,
 	.setup =	early_efi_setup,
+};
+
+struct console early_efi_console = {
+	.name =		"earlyefi",
 	.flags =	CON_PRINTBUFFER,
+	.ops =		&early_efi_ops,
 	.index =	-1,
+	.is_static =	1,
 };
arch/xtensa/platforms/iss/console.c +7 -3
index af81a62faba6..cd2189f7aa35 100644
@@ -236,13 +236,17 @@ static struct tty_driver* iss_console_device(struct console *c, int *index)
 	return serial_driver;
 }
 
+static const struct console_operations iss_ops = {
+	.write = iss_console_write,
+	.device = iss_console_device,
+};
 
 static struct console sercons = {
 	.name = "ttyS",
-	.write = iss_console_write,
-	.device = iss_console_device,
 	.flags = CON_PRINTBUFFER,
-	.index = -1
+	.ops = &iss_ops,
+	.index = -1,
+	.is_static = 1,
 };
 
 static int __init iss_console_init(void)
drivers/accessibility/braille/braille_console.c +3 -3
index dc34a5b8bcee..7fcc5c8a8c24 100644
@@ -116,7 +116,7 @@ static void braille_write(u16 *buf)
 	*c++ = csum;
 	*c++ = ETX;
 
-	braille_co->write(braille_co, data, c - data);
+	braille_co->ops->write(braille_co, data, c - data);
 }
 
 /* Follow the VC cursor*/
@@ -367,8 +367,8 @@ int braille_register_console(struct console *console, int index,
 		console_options = "57600o8";
 	if (braille_co)
 		return -ENODEV;
-	if (console->setup) {
-		ret = console->setup(console, console_options);
+	if (console->ops->setup) {
+		ret = console->ops->setup(console, console_options);
 		if (ret != 0)
 			return ret;
 	}
drivers/char/lp.c +13 -6
index 5c8d780637bd..e09cb192a469 100644
@@ -857,12 +857,12 @@ static void lp_console_write(struct console *co, const char *s,
 	parport_release(dev);
 }
 
-static struct console lpcons = {
-	.name		= "lp",
+static const struct console_operations lp_cons_ops = {
 	.write		= lp_console_write,
-	.flags		= CON_PRINTBUFFER,
 };
 
+static struct console *lpcons;
+
 #endif /* console on line printer */
 
 /* --- initialisation code ------------------------------------- */
@@ -921,6 +921,11 @@ static int lp_register(int nr, struct parport *port)
 						      &ppdev_cb, nr);
 	if (lp_table[nr].dev == NULL)
 		return 1;
+
+	lpcons = allocate_console_dfl(&lp_cons_ops, "lp", NULL);
+	if (!lpcons)
+		return -ENOMEM;
+
 	lp_table[nr].flags |= LP_EXIST;
 
 	if (reset)
@@ -935,7 +940,7 @@ static int lp_register(int nr, struct parport *port)
 #ifdef CONFIG_LP_CONSOLE
 	if (!nr) {
 		if (port->modes & PARPORT_MODE_SAFEININT) {
-			register_console(&lpcons);
+			register_console(lpcons);
 			console_registered = port;
 			printk(KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
 		} else
@@ -989,8 +994,9 @@ static void lp_detach(struct parport *port)
 	/* Write this some day. */
 #ifdef CONFIG_LP_CONSOLE
 	if (console_registered == port) {
-		unregister_console(&lpcons);
+		unregister_console(lpcons);
 		console_registered = NULL;
+		put_device(&lpcons->dev);
 	}
 #endif /* CONFIG_LP_CONSOLE */
 
@@ -1105,7 +1111,8 @@ static void lp_cleanup_module(void)
 	parport_unregister_driver(&lp_driver);
 
 #ifdef CONFIG_LP_CONSOLE
-	unregister_console(&lpcons);
+	unregister_console(lpcons);
+	put_device(&lpcons->dev);
 #endif
 
 	unregister_chrdev(LP_MAJOR, "lp");
drivers/hwtracing/stm/console.c +12 -7
index a00f65e21747..8271b1772f58 100644
@@ -17,7 +17,7 @@ static void stm_console_unlink(struct stm_source_data *data);
 
 static struct stm_console {
 	struct stm_source_data	data;
-	struct console		console;
+	struct console		*console;
 } stm_console = {
 	.data	= {
 		.name		= "console",
@@ -30,20 +30,25 @@ static struct stm_console {
 static void
 stm_console_write(struct console *con, const char *buf, unsigned len)
 {
-	struct stm_console *sc = container_of(con, struct stm_console, console);
+	struct stm_console *sc = con->data;
 
 	stm_source_write(&sc->data, 0, buf, len);
 }
 
+static const struct console_operations stm_cons_ops = {
+	.write = stm_console_write,
+};
+
 static int stm_console_link(struct stm_source_data *data)
 {
 	struct stm_console *sc = container_of(data, struct stm_console, data);
 
-	strcpy(sc->console.name, "stm_console");
-	sc->console.write = stm_console_write;
-	sc->console.flags = CON_ENABLED | CON_PRINTBUFFER;
-	register_console(&sc->console);
+	sc->console = allocate_console_dfl(&stm_cons_ops, "stm_console", data);
+	if (!sc->console)
+		return -ENOMEM;
 
+	sc->console->flags |= CON_ENABLED;
+	register_console(sc->console);
 	return 0;
 }
 
@@ -51,7 +56,7 @@ static void stm_console_unlink(struct stm_source_data *data)
 {
 	struct stm_console *sc = container_of(data, struct stm_console, data);
 
-	unregister_console(&sc->console);
+	unregister_console(sc->console);
 }
 
 static int stm_console_init(void)
drivers/misc/pti.c +16 -10
index 41f2a9f6851d..89219d09291b 100644
@@ -729,15 +729,14 @@ static int pti_console_setup(struct console *c, char *opts)
  * the tty port is to hook up syslog to it, the tty port
  * will be open for a really long time.
  */
-static struct console pti_console = {
-	.name		= TTYNAME,
+static const struct console_operations pti_cons_ops = {
 	.write		= pti_console_write,
 	.device		= pti_console_device,
 	.setup		= pti_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= 0,
 };
 
+static struct console *pti_console;
+
 /**
  * pti_port_activate()- Used to start/initialize any items upon
  * first opening of tty_port().
@@ -755,7 +754,7 @@ static struct console pti_console = {
 static int pti_port_activate(struct tty_port *port, struct tty_struct *tty)
 {
 	if (port->tty->index == PTITTY_MINOR_START)
-		console_start(&pti_console);
+		console_start(pti_console);
 	return 0;
 }
 
@@ -772,7 +771,7 @@ static int pti_port_activate(struct tty_port *port, struct tty_struct *tty)
 static void pti_port_shutdown(struct tty_port *port)
 {
 	if (port->tty->index == PTITTY_MINOR_START)
-		console_stop(&pti_console);
+		console_stop(pti_console);
 }
 
 static const struct tty_port_operations tty_port_ops = {
@@ -800,19 +799,23 @@ static int pti_pci_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
 	unsigned int a;
-	int retval = -EINVAL;
+	int retval = -ENOMEM;
 	int pci_bar = 1;
 
 	dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
 			__func__, __LINE__, pdev->vendor, pdev->device);
 
+	pti_console = allocate_console_dfl(&pti_cons_ops, TTYNAME, NULL);
+	if (!pti_console)
+		goto err;
+
 	retval = misc_register(&pti_char_driver);
 	if (retval) {
 		pr_err("%s(%d): CHAR registration failed of pti driver\n",
 			__func__, __LINE__);
 		pr_err("%s(%d): Error value returned: %d\n",
 			__func__, __LINE__, retval);
-		goto err;
+		goto err_put_con;
 	}
 
 	retval = pci_enable_device(pdev);
@@ -859,7 +862,7 @@ static int pti_pci_probe(struct pci_dev *pdev,
 		tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
 	}
 
-	register_console(&pti_console);
+	register_console(pti_console);
 
 	return 0;
 err_rel_reg:
@@ -870,6 +873,8 @@ static int pti_pci_probe(struct pci_dev *pdev,
 	pci_disable_device(pdev);
 err_unreg_misc:
 	misc_deregister(&pti_char_driver);
+err_put_con:
+	put_device(&pti_console->dev);
 err:
 	return retval;
 }
@@ -884,7 +889,8 @@ static void pti_pci_remove(struct pci_dev *pdev)
 	struct pti_dev *drv_data = pci_get_drvdata(pdev);
 	unsigned int a;
 
-	unregister_console(&pti_console);
+	unregister_console(pti_console);
+	put_device(&pti_console->dev);
 
 	for (a = 0; a < PTITTY_MINOR_NUM; a++) {
 		tty_unregister_device(pti_tty_driver, a);
drivers/net/netconsole.c +41 -58

176 lines not on this page · raw message

drivers/s390/char/con3215.c +7 -4
index 8c9d412b6d33..1d04fef525f7 100644
@@ -887,11 +887,9 @@ static struct notifier_block on_reboot_nb = {
 /*
  *  The console structure for the 3215 console
  */
-static struct console con3215 = {
-	.name	 = "ttyS",
+static const struct console_operations con3215_cons_ops = {
 	.write	 = con3215_write,
 	.device	 = con3215_device,
-	.flags	 = CON_PRINTBUFFER,
 };
 
 /*
@@ -902,6 +900,7 @@ static int __init con3215_init(void)
 	struct ccw_device *cdev;
 	struct raw3215_info *raw;
 	struct raw3215_req *req;
+	struct console *con3215;
 	int i;
 
 	/* Check if 3215 is to be the console */
@@ -925,6 +924,10 @@ static int __init con3215_init(void)
 		raw3215_freelist = req;
 	}
 
+	con3215 = allocate_console_dfl(&con3215_cons_ops, "ttyS", NULL);
+	if (!con3215)
+		return -ENOMEM;
+
 	cdev = ccw_device_create_console(&raw3215_ccw_driver);
 	if (IS_ERR(cdev))
 		return -ENODEV;
@@ -950,7 +953,7 @@ static int __init con3215_init(void)
 	}
 	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
 	register_reboot_notifier(&on_reboot_nb);
-	register_console(&con3215);
+	register_console(con3215);
 	return 0;
 }
 console_initcall(con3215_init);
drivers/s390/char/con3270.c +8 -4
index fd2146bcc0ad..4871be8568f1 100644
@@ -580,11 +580,10 @@ static struct notifier_block on_reboot_nb = {
 /*
  *  The console structure for the 3270 console
  */
-static struct console con3270 = {
-	.name	 = "tty3270",
+
+static const struct console_operations con3270_cons_ops = {
 	.write	 = con3270_write,
 	.device	 = con3270_device,
-	.flags	 = CON_PRINTBUFFER,
 };
 
 /*
@@ -593,6 +592,7 @@ static struct console con3270 = {
 static int __init
 con3270_init(void)
 {
+	struct console *con3270;
 	struct raw3270 *rp;
 	void *cbuf;
 	int i;
@@ -607,6 +607,10 @@ con3270_init(void)
 		cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
 	}
 
+	con3270 = allocate_console_dfl(&con3270_cons_ops, "tty3270", NULL);
+	if (!con3270)
+		return -ENOMEM;
+
 	rp = raw3270_setup_console();
 	if (IS_ERR(rp))
 		return PTR_ERR(rp);
@@ -642,7 +646,7 @@ con3270_init(void)
 	condev->input = alloc_string(&condev->freemem, 80);
 	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
 	register_reboot_notifier(&on_reboot_nb);
-	register_console(&con3270);
+	register_console(con3270);
 	return 0;
 }
 
drivers/s390/char/sclp_con.c +11 -6
index 8966a1c1b548..b837089f52c5 100644
@@ -281,15 +281,12 @@ static struct notifier_block on_reboot_nb = {
  * used to register the SCLP console to the kernel and to
  * give printk necessary information
  */
-static struct console sclp_console =
-{
-	.name = sclp_console_name,
+static const struct console_operations sclp_cons_ops = {
 	.write = sclp_console_write,
 	.device = sclp_console_device,
-	.flags = CON_PRINTBUFFER,
-	.index = 0 /* ttyS0 */
 };
 
+
 /*
  * This function is called for SCLP suspend and resume events.
  */
@@ -312,6 +309,7 @@ void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
 static int __init
 sclp_console_init(void)
 {
+	struct console *sclp_console;
 	void *page;
 	int i;
 	int rc;
@@ -319,9 +317,16 @@ sclp_console_init(void)
 	/* SCLP consoles are handled together */
 	if (!(CONSOLE_IS_SCLP || CONSOLE_IS_VT220))
 		return 0;
+
 	rc = sclp_rw_init();
 	if (rc)
 		return rc;
+
+	sclp_console = allocate_console_dfl(&sclp_cons_ops, sclp_console_name,
+					    NULL);
+	if (!sclp_console)
+		return -ENOMEM;
+
 	/* Allocate pages for output buffering */
 	INIT_LIST_HEAD(&sclp_con_pages);
 	for (i = 0; i < sclp_console_pages; i++) {
@@ -347,7 +352,7 @@ sclp_console_init(void)
 	/* enable printk-access to this driver */
 	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
 	register_reboot_notifier(&on_reboot_nb);
-	register_console(&sclp_console);
+	register_console(sclp_console);
 	return 0;
 }
 
drivers/s390/char/sclp_vt220.c +12 -6
index 3f9a6ef650fa..adbaeefbd05f 100644
@@ -869,27 +869,33 @@ static struct notifier_block on_reboot_nb = {
 };
 
 /* Structure needed to register with printk */
-static struct console sclp_vt220_console =
-{
-	.name = SCLP_VT220_CONSOLE_NAME,
+static const struct console_operations sclp_vt220_cons_ops = {
 	.write = sclp_vt220_con_write,
 	.device = sclp_vt220_con_device,
-	.flags = CON_PRINTBUFFER,
-	.index = SCLP_VT220_CONSOLE_INDEX
 };
 
 static int __init
 sclp_vt220_con_init(void)
 {
+	struct console *sclp_vt220_console;
 	int rc;
 
+	sclp_vt220_console = allocate_console_dfl(&sclp_vt220_cons_ops,
+						  SCLP_VT220_CONSOLE_NAME,
+						  NULL);
+	if (!sclp_vt220_console)
+		return -ENOMEM;
+
+	sclp_vt220_console->index = SCLP_VT220_CONSOLE_INDEX;
+
 	rc = __sclp_vt220_init(sclp_console_pages);
 	if (rc)
 		return rc;
+
 	/* Attach linux console */
 	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
 	register_reboot_notifier(&on_reboot_nb);
-	register_console(&sclp_vt220_console);
+	register_console(sclp_vt220_console);
 	return 0;
 }
 
drivers/tty/amiserial.c +8 -5
index 8330fd809a05..3c7f29da0163 100644
@@ -1779,12 +1779,9 @@ static struct tty_driver *serial_console_device(struct console *c, int *index)
 	return serial_driver;
 }
 
-static struct console sercons = {
-	.name =		"ttyS",
+static const struct console_operations ami_cons_ops = {
 	.write =	serial_console_write,
 	.device =	serial_console_device,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
 };
 
 /*
@@ -1792,10 +1789,16 @@ static struct console sercons = {
  */
 static int __init amiserial_console_init(void)
 {
+	struct console *sercons;
+
 	if (!MACH_IS_AMIGA)
 		return -ENODEV;
 
-	register_console(&sercons);
+	sercons = allocate_console_dfl(&ami_cons_ops, "ttyS", NULL);
+	if (!sercons)
+		return -ENOMEM;
+
+	register_console(sercons);
 	return 0;
 }
 console_initcall(amiserial_console_init);
drivers/tty/ehv_bytechan.c +13 -6
index 769e0a5d1dfc..4d45dac7f6c5 100644
@@ -277,13 +277,13 @@ static struct tty_driver *ehv_bc_console_device(struct console *co, int *index)
 	return ehv_bc_driver;
 }
 
-static struct console ehv_bc_console = {
-	.name		= "ttyEHV",
+static const struct console_operations ehv_bc_cons_ops = {
 	.write		= ehv_bc_console_write,
 	.device		= ehv_bc_console_device,
-	.flags		= CON_PRINTBUFFER | CON_ENABLED,
 };
 
+static struct console *ehv_bc_console;
+
 /*
  * Console initialization
  *
@@ -308,12 +308,19 @@ static int __init ehv_bc_console_init(void)
 			CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
 #endif
 
+	ehv_bc_console = allocate_console_dfl(&ehv_bc_cons_ops, "ttyEHV", NULL);
+	if (!ehv_bc_console)
+		return -ENOMEM;
+
+	ehv_bc_console->flags |= CON_ENABLED;
+
 	/* add_preferred_console() must be called before register_console(),
 	   otherwise it won't work.  However, we don't want to enumerate all the
 	   byte channels here, either, since we only care about one. */
 
-	add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
-	register_console(&ehv_bc_console);
+	add_preferred_console(ehv_bc_console->name, ehv_bc_console->index,
+			      NULL);
+	register_console(ehv_bc_console);
 
 	pr_info("ehv-bc: registered console driver for byte channel %u\n",
 		stdout_bc);
@@ -765,7 +772,7 @@ static int __init ehv_bc_init(void)
 	}
 
 	ehv_bc_driver->driver_name = "ehv-bc";
-	ehv_bc_driver->name = ehv_bc_console.name;
+	ehv_bc_driver->name = ehv_bc_console->name;
 	ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
 	ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE;
 	ehv_bc_driver->init_termios = tty_std_termios;
drivers/tty/goldfish.c +23 -11
index c8c5cdfc5e19..49ce7f5a8542 100644
@@ -39,7 +39,7 @@ struct goldfish_tty {
 	void __iomem *base;
 	u32 irq;
 	int opencount;
-	struct console console;
+	struct console *console;
 	u32 version;
 	struct device *dev;
 };
@@ -241,6 +241,12 @@ static const struct tty_operations goldfish_tty_ops = {
 	.chars_in_buffer = goldfish_tty_chars_in_buffer,
 };
 
+static const struct console_operations goldfish_cons_ops = {
+	.write = goldfish_tty_console_write,
+	.device = goldfish_tty_console_device,
+	.setup = goldfish_tty_console_setup,
+};
+
 static int goldfish_tty_create_driver(void)
 {
 	int ret;
@@ -392,18 +398,19 @@ static int goldfish_tty_probe(struct platform_device *pdev)
 		goto err_tty_register_device_failed;
 	}
 
-	strcpy(qtty->console.name, "ttyGF");
-	qtty->console.write = goldfish_tty_console_write;
-	qtty->console.device = goldfish_tty_console_device;
-	qtty->console.setup = goldfish_tty_console_setup;
-	qtty->console.flags = CON_PRINTBUFFER;
-	qtty->console.index = line;
-	register_console(&qtty->console);
+	qtty->console = allocate_console_dfl(&goldfish_cons_ops, "ttyGF", NULL);
+	if (!qtty->console)
+		goto err_alloc_console_failed;
+
+	qtty->console->index = line;
+	register_console(qtty->console);
 	platform_set_drvdata(pdev, qtty);
 
 	mutex_unlock(&goldfish_tty_lock);
 	return 0;
 
+err_alloc_console_failed:
+	tty_unregister_device(goldfish_tty_driver, line);
 err_tty_register_device_failed:
 	free_irq(irq, qtty);
 err_dec_line_count:
@@ -423,8 +430,9 @@ static int goldfish_tty_remove(struct platform_device *pdev)
 
 	mutex_lock(&goldfish_tty_lock);
 
-	unregister_console(&qtty->console);
-	tty_unregister_device(goldfish_tty_driver, qtty->console.index);
+	unregister_console(qtty->console);
+	put_device(&qtty->console->dev);
+	tty_unregister_device(goldfish_tty_driver, qtty->console->index);
 	iounmap(qtty->base);
 	qtty->base = NULL;
 	free_irq(qtty->irq, pdev);
@@ -448,13 +456,17 @@ static void gf_early_write(struct console *con, const char *s, unsigned int n)
 	uart_console_write(&dev->port, s, n, gf_early_console_putchar);
 }
 
+static const struct console_operations goldfish_early_cons_ops = {
+	.write = gf_early_write,
+};
+
 static int __init gf_earlycon_setup(struct earlycon_device *device,
 				    const char *opt)
 {
 	if (!device->port.membase)
 		return -ENODEV;
 
-	device->con->write = gf_early_write;
+	device->con->ops = &goldfish_early_cons_ops;
 	return 0;
 }
 
drivers/tty/hvc/hvc_console.c +6 -2
index 27284a2dcd2b..a9efffc461eb 100644
@@ -214,13 +214,17 @@ static int hvc_console_setup(struct console *co, char *options)
 	return 0;
 }
 
-static struct console hvc_console = {
-	.name		= "hvc",
+static const struct console_operations hvc_console_ops = {
 	.write		= hvc_console_print,
 	.device		= hvc_console_device,
 	.setup		= hvc_console_setup,
+};
+
+static struct console hvc_console = {
 	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
+	.ops		= &hvc_console_ops,
+	.is_static	= 1,
 };
 
 /*
drivers/tty/hvc/hvc_xen.c +12 -3
index dc43fa96c3de..ce14942b340d 100644
@@ -644,12 +644,17 @@ static void xenboot_write_console(struct console *console, const char *string,
 		domU_write_console(0, string+off, len-off);
 }
 
-struct console xenboot_console = {
-	.name		= "xenboot",
+static const struct console_operations xenboot_cons_ops = {
 	.write		= xenboot_write_console,
 	.setup		= xenboot_setup_console,
+};
+
+struct console xenboot_console = {
+	.name		= "xenboot",
+	.ops		= &xenboot_cons_ops,
 	.flags		= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 	.index		= -1,
+	.is_static	= 1,
 };
 #endif	/* CONFIG_EARLY_PRINTK */
 
@@ -685,10 +690,14 @@ static void xenboot_earlycon_write(struct console *console,
 	dom0_write_console(0, string, len);
 }
 
+static const struct console_operations xenboot_early_cons_ops = {
+	.write = xenboot_earlycon_write,
+};
+
 static int __init xenboot_earlycon_setup(struct earlycon_device *device,
 					    const char *opt)
 {
-	device->con->write = xenboot_earlycon_write;
+	device->con->ops = &xenboot_early_cons_ops;
 	return 0;
 }
 EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);
drivers/tty/hvc/hvsi.c +9 -5
index 66f95f758be0..f6bba2d97490 100644
@@ -1151,21 +1151,23 @@ static int __init hvsi_console_setup(struct console *console, char *options)
 	return 0;
 }
 
-static struct console hvsi_console = {
-	.name		= "hvsi",
+static const struct console_operations hvsi_cons_ops = {
 	.write		= hvsi_console_print,
 	.device		= hvsi_console_device,
 	.setup		= hvsi_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
 };
 
 static int __init hvsi_console_init(void)
 {
+	struct console *hvsi_console;
 	struct device_node *vty;
 
 	hvsi_wait = poll_for_state; /* no irqs yet; must poll */
 
+	hvsi_console = allocate_console_dfl(&hvsi_cons_ops, "hvsi", NULL);
+	if (!hvsi_console)
+		return -ENOMEM;
+
 	/* search device tree for vty nodes */
 	for_each_compatible_node(vty, "serial", "hvterm-protocol") {
 		struct hvsi_struct *hp;
@@ -1204,7 +1206,9 @@ static int __init hvsi_console_init(void)
 	}
 
 	if (hvsi_count)
-		register_console(&hvsi_console);
+		register_console(hvsi_console);
+
+	put_console(hvsi_console);
 	return 0;
 }
 console_initcall(hvsi_console_init);
drivers/tty/mips_ejtag_fdc.c +24 -20

97 lines not on this page · raw message

drivers/tty/serial/21285.c +13 -12
index 32b3acf8150a..6e3fbc8cd562 100644
@@ -444,28 +444,28 @@ static int __init serial21285_console_setup(struct console *co, char *options)
 
 static struct uart_driver serial21285_reg;
 
-static struct console serial21285_console =
-{
-	.name		= SERIAL_21285_NAME,
+static const struct console_operations serial2125_cons_ops = {
 	.write		= serial21285_console_write,
 	.device		= uart_console_device,
 	.setup		= serial21285_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &serial21285_reg,
 };
 
+static struct console __initdata *serial21285_console;
+
 static int __init rs285_console_init(void)
 {
+	serial21285_console = allocate_console_dfl(&serial2125_cons_ops,
+						   SERIAL_21285_NAME,
+						   &serial21285_reg);
+	if (!serial21285_console)
+		return -ENOMEM;
+
 	serial21285_setup_ports();
-	register_console(&serial21285_console);
+	register_console(serial21285_console);
 	return 0;
 }
 console_initcall(rs285_console_init);
 
-#define SERIAL_21285_CONSOLE	&serial21285_console
-#else
-#define SERIAL_21285_CONSOLE	NULL
 #endif
 
 static struct uart_driver serial21285_reg = {
@@ -475,7 +475,6 @@ static struct uart_driver serial21285_reg = {
 	.major			= SERIAL_21285_MAJOR,
 	.minor			= SERIAL_21285_MINOR,
 	.nr			= 1,
-	.cons			= SERIAL_21285_CONSOLE,
 };
 
 static int __init serial21285_init(void)
@@ -487,8 +486,10 @@ static int __init serial21285_init(void)
 	serial21285_setup_ports();
 
 	ret = uart_register_driver(&serial21285_reg);
-	if (ret == 0)
+	if (ret == 0) {
 		uart_add_one_port(&serial21285_reg, &serial21285_port);
+		serial21285_reg.cons = serial21285_console;
+	}
 
 	return ret;
 }
drivers/tty/serial/8250/8250_core.c +14 -8
index e441221e04b9..696c80f49878 100644
@@ -661,29 +661,33 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
 	return -ENODEV;
 }
 
-static struct console univ8250_console = {
-	.name		= "ttyS",
+static const struct console_operations univ8250_console_ops = {
 	.write		= univ8250_console_write,
 	.device		= uart_console_device,
 	.setup		= univ8250_console_setup,
 	.match		= univ8250_console_match,
-	.flags		= CON_PRINTBUFFER | CON_ANYTIME,
-	.index		= -1,
-	.data		= &serial8250_reg,
 };
 
+static struct console __initdata *univ8250_console;
+
 static int __init univ8250_console_init(void)
 {
 	if (nr_uarts == 0)
 		return -ENODEV;
 
+	univ8250_console = allocate_console_dfl(&univ8250_console_ops, "ttyS",
+						&serial8250_reg);
+	if (!univ8250_console)
+		return -ENOMEM;
+
+	univ8250_console->flags |= CON_ANYTIME;
 	serial8250_isa_init_ports();
-	register_console(&univ8250_console);
+	register_console(univ8250_console);
 	return 0;
 }
 console_initcall(univ8250_console_init);
 
-#define SERIAL8250_CONSOLE	(&univ8250_console)
+#define SERIAL8250_CONSOLE	(univ8250_console)
 #else
 #define SERIAL8250_CONSOLE	NULL
 #endif
@@ -694,7 +698,6 @@ static struct uart_driver serial8250_reg = {
 	.dev_name		= "ttyS",
 	.major			= TTY_MAJOR,
 	.minor			= 64,
-	.cons			= SERIAL8250_CONSOLE,
 };
 
 /*
@@ -1136,6 +1139,8 @@ static int __init serial8250_init(void)
 	pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
 		nr_uarts, share_irqs ? "en" : "dis");
 
+	serial8250_reg.cons = SERIAL8250_CONSOLE;
+
 #ifdef CONFIG_SPARC
 	ret = sunserial_register_minors(&serial8250_reg, UART_NR);
 #else
@@ -1178,6 +1183,7 @@ static int __init serial8250_init(void)
 	uart_unregister_driver(&serial8250_reg);
 #endif
 out:
+	put_console(SERIAL8250_CONSOLE);
 	return ret;
 }
 
drivers/tty/serial/8250/8250_early.c +15 -3
index 5cd8c36c8fcc..cffffca9c49e 100644
@@ -132,6 +132,10 @@ static void __init init_port(struct earlycon_device *device)
 	}
 }
 
+static struct console_operations early_serial8250_ops = {
+	.write = early_serial8250_write,
+};
+
 int __init early_serial8250_setup(struct earlycon_device *device,
 					 const char *options)
 {
@@ -148,7 +152,7 @@ int __init early_serial8250_setup(struct earlycon_device *device,
 	} else
 		init_port(device);
 
-	device->con->write = early_serial8250_write;
+	device->con->ops = &early_serial8250_ops;
 	return 0;
 }
 EARLYCON_DECLARE(uart8250, early_serial8250_setup);
@@ -160,6 +164,10 @@ OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
 
 #ifdef CONFIG_SERIAL_8250_OMAP
 
+static const struct console_operations early_omap8250_cons_ops = {
+	.write = early_serial8250_write,
+};
+
 static int __init early_omap8250_setup(struct earlycon_device *device,
 				       const char *options)
 {
@@ -169,7 +177,7 @@ static int __init early_omap8250_setup(struct earlycon_device *device,
 		return -ENODEV;
 
 	port->regshift = 2;
-	device->con->write = early_serial8250_write;
+	device->con->ops = &early_omap8250_cons_ops;
 	return 0;
 }
 
@@ -184,12 +192,16 @@ OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
 unsigned int au_serial_in(struct uart_port *p, int offset);
 void au_serial_out(struct uart_port *p, int offset, int value);
 
+static const struct console_operations early_serial8250_cons_ops = {
+	.write = early_serial8250_write,
+};
+
 static int __init early_au_setup(struct earlycon_device *dev, const char *opt)
 {
 	dev->port.serial_in = au_serial_in;
 	dev->port.serial_out = au_serial_out;
 	dev->port.iotype = UPIO_AU;
-	dev->con->write = early_serial8250_write;
+	dev->con->ops = &early_serial8250_cons_ops;
 	return 0;
 }
 OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup);
drivers/tty/serial/8250/8250_ingenic.c +5 -1
index 15a8c8dfa92b..9795ae0da711 100644
@@ -87,6 +87,10 @@ static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev
 	dev->port.uartclk = be32_to_cpup(prop);
 }
 
+static struct console_operations ingenic_early_cons_ops = {
+	.write = ingenic_early_console_write,
+};
+
 static int __init ingenic_early_console_setup(struct earlycon_device *dev,
 					      const char *opt)
 {
@@ -124,7 +128,7 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
 	early_out(port, UART_LCR, UART_LCR_WLEN8);
 
 	early_device = dev;
-	dev->con->write = ingenic_early_console_write;
+	dev->con->ops = &ingenic_early_cons_ops;
 
 	return 0;
 }
drivers/tty/serial/altera_jtaguart.c +20 -13
index c90e503d6b57..9222427cd761 100644
@@ -359,26 +359,28 @@ static int __init altera_jtaguart_console_setup(struct console *co,
 
 static struct uart_driver altera_jtaguart_driver;
 
-static struct console altera_jtaguart_console = {
-	.name	= "ttyJ",
+static const struct console_operations jtaguart_cons_ops = {
 	.write	= altera_jtaguart_console_write,
 	.device	= uart_console_device,
 	.setup	= altera_jtaguart_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
-	.data	= &altera_jtaguart_driver,
 };
 
+static struct console __initdata *altera_jtaguart_console;
+
 static int __init altera_jtaguart_console_init(void)
 {
-	register_console(&altera_jtaguart_console);
+	altera_jtaguart_console = allocate_console_dfl(&jtaguart_cons_ops,
+						       "ttyJ",
+						       &altera_jtaguart_driver);
+	if (!altera_jtaguart_console)
+		return -ENOMEM;
+
+	register_console(altera_jtaguart_console);
 	return 0;
 }
 
 console_initcall(altera_jtaguart_console_init);
 
-#define	ALTERA_JTAGUART_CONSOLE	(&altera_jtaguart_console)
-
 static void altera_jtaguart_earlycon_write(struct console *co, const char *s,
 					   unsigned int count)
 {
@@ -387,22 +389,25 @@ static void altera_jtaguart_earlycon_write(struct console *co, const char *s,
 	uart_console_write(&dev->port, s, count, altera_jtaguart_console_putc);
 }
 
+static const struct console_operations jtaguart_earlycon_con_ops = {
+	.write = altera_jtaguart_earlycon_write,
+};
+
 static int __init altera_jtaguart_earlycon_setup(struct earlycon_device *dev,
 						 const char *options)
 {
 	if (!dev->port.membase)
 		return -ENODEV;
 
-	dev->con->write = altera_jtaguart_earlycon_write;
+	dev->con->ops = &jtaguart_earlycon_con_ops;
 	return 0;
 }
 
 OF_EARLYCON_DECLARE(juart, "altr,juart-1.0", altera_jtaguart_earlycon_setup);
 
+#define ALTERA_JTAGUART_CONSOLE (altera_jtaguart_console)
 #else
-
-#define	ALTERA_JTAGUART_CONSOLE	NULL
-
+#define ALTERA_JTAGUART_CONSOLE NULL
 #endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */
 
 static struct uart_driver altera_jtaguart_driver = {
@@ -412,7 +417,6 @@ static struct uart_driver altera_jtaguart_driver = {
 	.major		= ALTERA_JTAGUART_MAJOR,
 	.minor		= ALTERA_JTAGUART_MINOR,
 	.nr		= ALTERA_JTAGUART_MAXPORTS,
-	.cons		= ALTERA_JTAGUART_CONSOLE,
 };
 
 static int altera_jtaguart_probe(struct platform_device *pdev)
@@ -501,12 +505,15 @@ static int __init altera_jtaguart_init(void)
 {
 	int rc;
 
+	altera_jtaguart_driver.cons = ALTERA_JTAGUART_CONSOLE;
 	rc = uart_register_driver(&altera_jtaguart_driver);
 	if (rc)
 		return rc;
+
 	rc = platform_driver_register(&altera_jtaguart_platform_driver);
 	if (rc)
 		uart_unregister_driver(&altera_jtaguart_driver);
+
 	return rc;
 }
 
drivers/tty/serial/altera_uart.c +16 -9
index 0e487ce091ac..6e0a7b6af214 100644
@@ -479,25 +479,28 @@ static int __init altera_uart_console_setup(struct console *co, char *options)
 
 static struct uart_driver altera_uart_driver;
 
-static struct console altera_uart_console = {
-	.name	= "ttyAL",
+static const struct console_operations altera_cons_ops = {
 	.write	= altera_uart_console_write,
 	.device	= uart_console_device,
 	.setup	= altera_uart_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
-	.data	= &altera_uart_driver,
 };
 
+static struct console __initdata *altera_uart_console;
+
 static int __init altera_uart_console_init(void)
 {
-	register_console(&altera_uart_console);
+	altera_uart_console = allocate_console_dfl(&altera_cons_ops, "ttyAL",
+						   &altera_uart_driver);
+	if (!altera_uart_console)
+		return -ENOMEM;
+
+	register_console(altera_uart_console);
 	return 0;
 }
 
 console_initcall(altera_uart_console_init);
 
-#define	ALTERA_UART_CONSOLE	(&altera_uart_console)
+#define	ALTERA_UART_CONSOLE	(altera_uart_console)
 
 static void altera_uart_earlycon_write(struct console *co, const char *s,
 				       unsigned int count)
@@ -507,6 +510,10 @@ static void altera_uart_earlycon_write(struct console *co, const char *s,
 	uart_console_write(&dev->port, s, count, altera_uart_console_putc);
 }
 
+static const struct console_operations altera_early_cons_ops = {
+	.write = altera_uart_earlycon_write,
+};
+
 static int __init altera_uart_earlycon_setup(struct earlycon_device *dev,
 					     const char *options)
 {
@@ -525,7 +532,7 @@ static int __init altera_uart_earlycon_setup(struct earlycon_device *dev,
 		altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
 	}
 
-	dev->con->write = altera_uart_earlycon_write;
+	dev->con->ops = &altera_early_cons_ops;
 	return 0;
 }
 
@@ -547,7 +554,6 @@ static struct uart_driver altera_uart_driver = {
 	.major		= SERIAL_ALTERA_MAJOR,
 	.minor		= SERIAL_ALTERA_MINOR,
 	.nr		= CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
-	.cons		= ALTERA_UART_CONSOLE,
 };
 
 static int altera_uart_probe(struct platform_device *pdev)
@@ -653,6 +659,7 @@ static int __init altera_uart_init(void)
 {
 	int rc;
 
+	altera_uart_driver.cons	= ALTERA_UART_CONSOLE;
 	rc = uart_register_driver(&altera_uart_driver);
 	if (rc)
 		return rc;
drivers/tty/serial/amba-pl010.c +22 -13
index 2c37d11726ab..22283935dee9 100644
@@ -668,20 +668,14 @@ static int __init pl010_console_setup(struct console *co, char *options)
 	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
 }
 
-static struct uart_driver amba_reg;
-static struct console amba_console = {
-	.name		= "ttyAM",
+static const struct console_operations amba_cons_ops = {
 	.write		= pl010_console_write,
 	.device		= uart_console_device,
 	.setup		= pl010_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &amba_reg,
 };
 
-#define AMBA_CONSOLE	&amba_console
 #else
-#define AMBA_CONSOLE	NULL
+static const struct console_operations amba_cons_ops;
 #endif
 
 static DEFINE_MUTEX(amba_reg_lock);
@@ -692,7 +686,6 @@ static struct uart_driver amba_reg = {
 	.major			= SERIAL_AMBA_MAJOR,
 	.minor			= SERIAL_AMBA_MINOR,
 	.nr			= UART_NR,
-	.cons			= AMBA_CONSOLE,
 };
 
 static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
@@ -740,20 +733,36 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
 
 	mutex_lock(&amba_reg_lock);
 	if (!amba_reg.state) {
+		ret = uart_allocate_console_dfl(&amba_reg, &amba_cons_ops,
+						"ttyAM",
+						SERIAL_AMBA_PL010_CONSOLE);
+		if (ret < 0) {
+			mutex_unlock(&amba_reg_lock);
+			goto out;
+		}
+
 		ret = uart_register_driver(&amba_reg);
 		if (ret < 0) {
 			mutex_unlock(&amba_reg_lock);
-			dev_err(uap->port.dev,
-				"Failed to register AMBA-PL010 driver\n");
-			return ret;
+			goto out;
 		}
 	}
 	mutex_unlock(&amba_reg_lock);
 
 	ret = uart_add_one_port(&amba_reg, &uap->port);
 	if (ret)
-		amba_ports[i] = NULL;
+		goto out_unregister;
+
+	return 0;
+
+out_unregister:
+	uart_unregister_driver(&amba_reg);
+out:
+	amba_ports[i] = NULL;
+	uart_put_console(&amba_reg);
+	kfree(uap);
 
+	pr_err("Failed to register AMBA-PL010 driver\n");
 	return ret;
 }
 
drivers/tty/serial/amba-pl011.c +29 -18

106 lines not on this page · raw message

drivers/tty/serial/apbuart.c +15 -9
index 60cd133ffbbc..0257fe1dbf00 100644
@@ -507,30 +507,36 @@ static int __init apbuart_console_setup(struct console *co, char *options)
 
 static struct uart_driver grlib_apbuart_driver;
 
-static struct console grlib_apbuart_console = {
-	.name = "ttyS",
+static const struct console_operations grlib_cons_ops = {
 	.write = apbuart_console_write,
 	.device = uart_console_device,
 	.setup = apbuart_console_setup,
-	.flags = CON_PRINTBUFFER,
-	.index = -1,
-	.data = &grlib_apbuart_driver,
 };
 
+static struct console __initdata *grlib_apbuart_console;
 
 static int grlib_apbuart_configure(void);
 
 static int __init apbuart_console_init(void)
 {
+	grlib_apbuart_console = allocate_console_dfl(&grlib_cons_ops, "ttyS",
+						     &grlib_apbuart_driver);
+	if (!grlib_apbuart_console)
+		return -ENOMEM;
+
 	if (grlib_apbuart_configure())
-		return -ENODEV;
-	register_console(&grlib_apbuart_console);
+		goto err;
+
+	register_console(grlib_apbuart_console);
 	return 0;
+err:
+	put_console(grlib_apbuart_console);
+	return -ENODEV;
 }
 
 console_initcall(apbuart_console_init);
 
-#define APBUART_CONSOLE	(&grlib_apbuart_console)
+#define APBUART_CONSOLE	(grlib_apbuart_console)
 #else
 #define APBUART_CONSOLE	NULL
 #endif
@@ -542,7 +548,6 @@ static struct uart_driver grlib_apbuart_driver = {
 	.major = SERIAL_APBUART_MAJOR,
 	.minor = SERIAL_APBUART_MINOR,
 	.nr = UART_NR,
-	.cons = APBUART_CONSOLE,
 };
 
 
@@ -652,6 +657,7 @@ static int __init grlib_apbuart_init(void)
 
 	printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
 
+	grlib_apbuart_driver.cons = APBUART_CONSOLE;
 	ret = uart_register_driver(&grlib_apbuart_driver);
 
 	if (ret) {
drivers/tty/serial/ar933x_uart.c +6 -7
index db5df3d54818..3bce82a216d7 100644
@@ -595,14 +595,10 @@ static int ar933x_uart_console_setup(struct console *co, char *options)
 	return uart_set_options(&up->port, co, baud, parity, bits, flow);
 }
 
-static struct console ar933x_uart_console = {
-	.name		= "ttyATH",
+static const struct console_operations ar933x_cons_ops = {
 	.write		= ar933x_uart_console_write,
 	.device		= uart_console_device,
 	.setup		= ar933x_uart_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &ar933x_uart_driver,
 };
 
 static void ar933x_uart_add_console_port(struct ar933x_uart_port *up)
@@ -749,8 +745,10 @@ static int __init ar933x_uart_init(void)
 {
 	int ret;
 
-	if (ar933x_uart_console_enabled())
-		ar933x_uart_driver.cons = &ar933x_uart_console;
+	ret = uart_allocate_console_dfl(&ar933x_uart_driver, &ar933x_cons_ops,
+					"ttyATH", SERIAL_AR933X_CONSOLE);
+	if (ret)
+		return ret;
 
 	ret = uart_register_driver(&ar933x_uart_driver);
 	if (ret)
@@ -765,6 +763,7 @@ static int __init ar933x_uart_init(void)
 err_unregister_uart_driver:
 	uart_unregister_driver(&ar933x_uart_driver);
 err_out:
+	uart_put_console(&ar933x_uart_driver);
 	return ret;
 }
 
drivers/tty/serial/arc_uart.c +14 -13
index d904a3a345e7..8637e95b0d7f 100644
@@ -105,10 +105,6 @@ struct arc_uart_port {
 
 static struct arc_uart_port arc_uart_ports[CONFIG_SERIAL_ARC_NR_PORTS];
 
-#ifdef CONFIG_SERIAL_ARC_CONSOLE
-static struct console arc_console;
-#endif
-
 #define DRIVER_NAME	"arc-uart"
 
 static struct uart_driver arc_uart_driver = {
@@ -118,9 +114,6 @@ static struct uart_driver arc_uart_driver = {
 	.major		= 0,
 	.minor		= 0,
 	.nr		= CONFIG_SERIAL_ARC_NR_PORTS,
-#ifdef CONFIG_SERIAL_ARC_CONSOLE
-	.cons		= &arc_console,
-#endif
 };
 
 static void arc_serial_stop_rx(struct uart_port *port)
@@ -536,14 +529,10 @@ static void arc_serial_console_write(struct console *co, const char *s,
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static struct console arc_console = {
-	.name	= ARC_SERIAL_DEV_NAME,
+static const struct console_operations arc_cons_ops = {
 	.write	= arc_serial_console_write,
 	.device	= uart_console_device,
 	.setup	= arc_serial_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
-	.data	= &arc_uart_driver
 };
 
 static void arc_early_serial_write(struct console *con, const char *s,
@@ -554,6 +543,10 @@ static void arc_early_serial_write(struct console *con, const char *s,
 	uart_console_write(&dev->port, s, n, arc_serial_console_putchar);
 }
 
+static const struct console_operations arc_early_cons_ops = {
+	.write = arc_early_serial_write,
+};
+
 static int __init arc_early_console_setup(struct earlycon_device *dev,
 					  const char *opt)
 {
@@ -570,11 +563,13 @@ static int __init arc_early_console_setup(struct earlycon_device *dev,
 	UART_SET_BAUDL(port, l);
 	UART_SET_BAUDH(port, h);
 
-	dev->con->write = arc_early_serial_write;
+	dev->con->ops = &arc_early_cons_ops;
 	return 0;
 }
 OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup);
 
+#else
+static const struct console_operations arc_cons_ops;
 #endif	/* CONFIG_SERIAL_ARC_CONSOLE */
 
 static int arc_serial_probe(struct platform_device *pdev)
@@ -662,6 +657,12 @@ static int __init arc_serial_init(void)
 {
 	int ret;
 
+	ret = uart_allocate_console_dfl(&arc_uart_driver, &arc_cons_ops,
+					ARC_SERIAL_DEV_NAME,
+					SERIAL_ARC_CONSOLE);
+	if (ret)
+		return ret;
+
 	ret = uart_register_driver(&arc_uart_driver);
 	if (ret)
 		return ret;
drivers/tty/serial/atmel_serial.c +15 -16
index 05147fe24343..b37f2f640005 100644
@@ -194,10 +194,6 @@ struct atmel_uart_port {
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
 static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART);
 
-#ifdef SUPPORT_SYSRQ
-static struct console atmel_console;
-#endif
-
 #if defined(CONFIG_OF)
 static const struct of_device_id atmel_serial_dt_ids[] = {
 	{ .compatible = "atmel,at91rm9200-usart-serial" },
@@ -2684,25 +2680,19 @@ static int __init atmel_console_setup(struct console *co, char *options)
 
 static struct uart_driver atmel_uart;
 
-static struct console atmel_console = {
-	.name		= ATMEL_DEVICENAME,
+static const struct console_operations atmel_cons_ops = {
 	.write		= atmel_console_write,
 	.device		= uart_console_device,
 	.setup		= atmel_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &atmel_uart,
 };
 
-#define ATMEL_CONSOLE_DEVICE	(&atmel_console)
-
 static inline bool atmel_is_console_port(struct uart_port *port)
 {
 	return port->cons && port->cons->index == port->line;
 }
 
 #else
-#define ATMEL_CONSOLE_DEVICE	NULL
+static const struct console_operations atmel_cons_ops;
 
 static inline bool atmel_is_console_port(struct uart_port *port)
 {
@@ -2717,7 +2707,6 @@ static struct uart_driver atmel_uart = {
 	.major		= SERIAL_ATMEL_MAJOR,
 	.minor		= MINOR_START,
 	.nr		= ATMEL_MAX_UART,
-	.cons		= ATMEL_CONSOLE_DEVICE,
 };
 
 #ifdef CONFIG_PM
@@ -2933,7 +2922,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
 	if (atmel_is_console_port(&atmel_port->uart)
-			&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
+			&& atmel_uart.cons->flags & CON_ENABLED) {
 		/*
 		 * The serial core enabled the clock for us, so undo
 		 * the clk_prepare_enable() in atmel_console_setup()
@@ -3035,14 +3024,24 @@ static int __init atmel_serial_init(void)
 {
 	int ret;
 
-	ret = uart_register_driver(&atmel_uart);
+	ret = uart_allocate_console_dfl(&atmel_uart, &atmel_cons_ops,
+					ATMEL_DEVICENAME,
+					SERIAL_ATMEL_CONSOLE);
 	if (ret)
 		return ret;
 
+	ret = uart_register_driver(&atmel_uart);
+	if (ret)
+		goto out;
+
 	ret = platform_driver_register(&atmel_serial_driver);
 	if (ret)
-		uart_unregister_driver(&atmel_uart);
+		goto out_unregister;
 
+out_unregister:
+	uart_unregister_driver(&atmel_uart);
+out:
+	uart_put_console(&atmel_uart);
 	return ret;
 }
 device_initcall(atmel_serial_init);
drivers/tty/serial/bcm63xx_uart.c +16 -9
index b7adc6127b3d..706a0c7e572b 100644
@@ -752,19 +752,22 @@ static int bcm_console_setup(struct console *co, char *options)
 
 static struct uart_driver bcm_uart_driver;
 
-static struct console bcm63xx_console = {
-	.name		= "ttyS",
+static const struct console_operations bcm63xx_cons_ops = {
 	.write		= bcm_console_write,
 	.device		= uart_console_device,
 	.setup		= bcm_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &bcm_uart_driver,
 };
 
+static struct console __initdata *bcm63xx_console;
+
 static int __init bcm63xx_console_init(void)
 {
-	register_console(&bcm63xx_console);
+	bcm63xx_console = allocate_console_dfl(&bcm63xx_cons_ops, "ttyS",
+					       &bcm_uart_driver);
+	if (!bcm63xx_console)
+		return -ENOMEM;
+
+	register_console(bcm63xx_console);
 	return 0;
 }
 
@@ -778,19 +781,23 @@ static void bcm_early_write(struct console *con, const char *s, unsigned n)
 	wait_for_xmitr(&dev->port);
 }
 
+static const struct console_operations bcm63xx_early_ops = {
+	.write = bcm_early_write,
+};
+
 static int __init bcm_early_console_setup(struct earlycon_device *device,
 					  const char *opt)
 {
 	if (!device->port.membase)
 		return -ENODEV;
 
-	device->con->write = bcm_early_write;
+	device->con->ops = &bcm63xx_early_ops;
 	return 0;
 }
 
 OF_EARLYCON_DECLARE(bcm63xx_uart, "brcm,bcm6345-uart", bcm_early_console_setup);
 
-#define BCM63XX_CONSOLE	(&bcm63xx_console)
+#define BCM63XX_CONSOLE	(bcm63xx_console)
 #else
 #define BCM63XX_CONSOLE	NULL
 #endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */
@@ -802,7 +809,6 @@ static struct uart_driver bcm_uart_driver = {
 	.major		= TTY_MAJOR,
 	.minor		= 64,
 	.nr		= BCM63XX_NR_UARTS,
-	.cons		= BCM63XX_CONSOLE,
 };
 
 /*
@@ -902,6 +908,7 @@ static int __init bcm_uart_init(void)
 {
 	int ret;
 
+	bcm_uart_driver.cons = BCM63XX_CONSOLE;
 	ret = uart_register_driver(&bcm_uart_driver);
 	if (ret)
 		return ret;
drivers/tty/serial/clps711x.c +9 -8
index 98f193a83392..d37a538768f5 100644
@@ -429,14 +429,14 @@ static int uart_clps711x_console_setup(struct console *co, char *options)
 				  SYSCON_UARTEN, SYSCON_UARTEN);
 }
 
-static struct console clps711x_console = {
-	.name	= UART_CLPS711X_DEVNAME,
+static const struct console_operations clps711x_cons_ops = {
 	.device	= uart_console_device,
 	.write	= uart_clps711x_console_write,
 	.setup	= uart_clps711x_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
 };
+
+#else
+static const struct console_operations clps711x_cons_ops;
 #endif
 
 static int uart_clps711x_probe(struct platform_device *pdev)
@@ -553,10 +553,11 @@ static int __init uart_clps711x_init(void)
 {
 	int ret;
 
-#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-	clps711x_uart.cons = &clps711x_console;
-	clps711x_console.data = &clps711x_uart;
-#endif
+	ret = uart_allocate_console_dfl(&clps711x_uart, &clps711x_cons_ops,
+					UART_CLPS711X_DEVNAME,
+					SERIAL_CLPS711X_CONSOLE);
+	if (ret)
+		return ret;
 
 	ret = uart_register_driver(&clps711x_uart);
 	if (ret)
drivers/tty/serial/cpm_uart/cpm_uart_core.c +11 -10
index b929c7ae3a27..8e2685f1ecc0 100644
@@ -1363,27 +1363,29 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
 }
 
 static struct uart_driver cpm_reg;
-static struct console cpm_scc_uart_console = {
-	.name		= "ttyCPM",
+
+static const struct console_operations cpm_scc_cons_ops = {
 	.write		= cpm_uart_console_write,
 	.device		= uart_console_device,
 	.setup		= cpm_uart_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &cpm_reg,
 };
 
 static int __init cpm_uart_console_init(void)
 {
-	register_console(&cpm_scc_uart_console);
+	struct console *cpm_scc_uart_console;
+
+	cpm_scc_uart_console = allocate_console_dfl(&cpm_scc_cons_ops, "ttyCPM",
+						    &cpm_reg);
+	if (!cpm_scc_uart_console)
+		return -ENOMEM;
+
+	cpm_reg->cons = cpm_scc_uart_console;
+	register_console(cpm_scc_uart_console);
 	return 0;
 }
 
 console_initcall(cpm_uart_console_init);
 
-#define CPM_UART_CONSOLE	&cpm_scc_uart_console
-#else
-#define CPM_UART_CONSOLE	NULL
 #endif
 
 static struct uart_driver cpm_reg = {
@@ -1392,7 +1394,6 @@ static struct uart_driver cpm_reg = {
 	.dev_name	= "ttyCPM",
 	.major		= SERIAL_CPM_MAJOR,
 	.minor		= SERIAL_CPM_MINOR,
-	.cons		= CPM_UART_CONSOLE,
 	.nr		= UART_NR,
 };
 
drivers/tty/serial/digicolor-usart.c +11 -13
index f460cca139e2..2f95a469b814 100644
@@ -431,21 +431,18 @@ static int digicolor_uart_console_setup(struct console *co, char *options)
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
-static struct console digicolor_console = {
-	.name	= "ttyS",
-	.device	= uart_console_device,
-	.write	= digicolor_uart_console_write,
-	.setup	= digicolor_uart_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
-};
-
 static struct uart_driver digicolor_uart = {
 	.driver_name	= "digicolor-usart",
 	.dev_name	= "ttyS",
 	.nr		= DIGICOLOR_USART_NR,
 };
 
+static const struct console_operations digicolor_cons_ops = {
+	.device	= uart_console_device,
+	.write	= digicolor_uart_console_write,
+	.setup	= digicolor_uart_console_setup,
+};
+
 static int digicolor_uart_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -532,10 +529,11 @@ static int __init digicolor_uart_init(void)
 {
 	int ret;
 
-	if (IS_ENABLED(CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE)) {
-		digicolor_uart.cons = &digicolor_console;
-		digicolor_console.data = &digicolor_uart;
-	}
+	ret = uart_allocate_console_dfl(&digicolor_uart, &digicolor_cons_ops,
+					"ttyS",
+					SERIAL_CONEXANT_DIGICOLOR_CONSOLE);
+	if (ret)
+		return ret;
 
 	ret = uart_register_driver(&digicolor_uart);
 	if (ret)
drivers/tty/serial/dz.c +11 -7
index 7b57e840e255..68972dc25497 100644
@@ -887,19 +887,23 @@ static int __init dz_console_setup(struct console *co, char *options)
 }
 
 static struct uart_driver dz_reg;
-static struct console dz_console = {
-	.name	= "ttyS",
+
+static const struct console_operations dz_cons_ops = {
 	.write	= dz_console_print,
 	.device	= uart_console_device,
 	.setup	= dz_console_setup,
-	.flags	= CON_PRINTBUFFER,
-	.index	= -1,
-	.data	= &dz_reg,
 };
 
+static struct console __initdata *dz_console;
+
 static int __init dz_serial_console_init(void)
 {
 	if (!IOASIC) {
+		dz_console = allocate_console_dfl(&dz_cons_ops, "ttyS",
+						  &dz_reg);
+		if (!dz_console)
+			return -ENOMEM;
+
 		dz_init_ports();
 		register_console(&dz_console);
 		return 0;
@@ -909,7 +913,7 @@ static int __init dz_serial_console_init(void)
 
 console_initcall(dz_serial_console_init);
 
-#define SERIAL_DZ_CONSOLE	&dz_console
+#define SERIAL_DZ_CONSOLE	(dz_console)
 #else
 #define SERIAL_DZ_CONSOLE	NULL
 #endif /* CONFIG_SERIAL_DZ_CONSOLE */
@@ -921,7 +925,6 @@ static struct uart_driver dz_reg = {
 	.major			= TTY_MAJOR,
 	.minor			= 64,
 	.nr			= DZ_NB_PORT,
-	.cons			= SERIAL_DZ_CONSOLE,
 };
 
 static int __init dz_init(void)
@@ -935,6 +938,7 @@ static int __init dz_init(void)
 
 	dz_init_ports();
 
+	dz_reg.cons = SERIAL_DZ_CONSOLE;
 	ret = uart_register_driver(&dz_reg);
 	if (ret)
 		return ret;
drivers/tty/serial/earlycon-arm-semihost.c +5 -1
index fa096c10b591..f4c73327cd18 100644
@@ -42,10 +42,14 @@ static void smh_write(struct console *con, const char *s, unsigned n)
 	uart_console_write(&dev->port, s, n, smh_putc);
 }
 
+static const struct console_operations smh_early_cons_ops = {
+	.write = smh_write,
+};
+
 static int
 __init early_smh_setup(struct earlycon_device *device, const char *opt)
 {
-	device->con->write = smh_write;
+	device->con->ops = &smh_early_cons_ops;
 	return 0;
 }
 EARLYCON_DECLARE(smh, early_smh_setup);
drivers/tty/serial/earlycon.c +3 -2
index c14873b67803..b32281ce86dc 100644
@@ -30,6 +30,7 @@ static struct console early_con = {
 	.name =		"uart",		/* fixed up at earlycon registration */
 	.flags =	CON_PRINTBUFFER | CON_BOOT,
 	.index =	0,
+	.is_static =	1,
 };
 
 static struct earlycon_device early_console_dev = {
@@ -142,7 +143,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
 	err = match->setup(&early_console_dev, buf);
 	if (err < 0)
 		return err;
-	if (!early_console_dev.con->write)
+	if (!early_console_dev.con->ops || !early_console_dev.con->ops->write)
 		return -ENODEV;
 
 	register_console(early_console_dev.con);
@@ -293,7 +294,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
 	err = match->setup(&early_console_dev, options);
 	if (err < 0)
 		return err;
-	if (!early_console_dev.con->write)
+	if (!early_console_dev.con->ops || !early_console_dev.con->ops->write)
 		return -ENODEV;
 
 
drivers/tty/serial/efm32-uart.c +14 -8
index d6b5e5463746..ad07349f7f2e 100644
@@ -639,18 +639,14 @@ static int efm32_uart_console_setup(struct console *co, char *options)
 
 static struct uart_driver efm32_uart_reg;
 
-static struct console efm32_uart_console = {
-	.name = DEV_NAME,
+static const struct console_operations efm32_cons_ops = {
 	.write = efm32_uart_console_write,
 	.device = uart_console_device,
 	.setup = efm32_uart_console_setup,
-	.flags = CON_PRINTBUFFER,
-	.index = -1,
-	.data = &efm32_uart_reg,
 };
 
 #else
-#define efm32_uart_console (*(struct console *)NULL)
+static const struct console_operations efm32_cons_ops;
 #endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
 
 static struct uart_driver efm32_uart_reg = {
@@ -828,16 +824,26 @@ static int __init efm32_uart_init(void)
 {
 	int ret;
 
-	ret = uart_register_driver(&efm32_uart_reg);
+	ret = uart_allocate_console_dfl(&efm32_uart_reg, &efm32_cons_ops,
+					DEV_NAME, SERIAL_EFM32_UART_CONSOLE);
 	if (ret)
 		return ret;
 
+	ret = uart_register_driver(&efm32_uart_reg);
+	if (ret)
+		goto out;
+
 	ret = platform_driver_register(&efm32_uart_driver);
 	if (ret)
-		uart_unregister_driver(&efm32_uart_reg);
+		goto out_unregister;
 
 	pr_info("EFM32 UART/USART driver\n");
+	return 0;
 
+out_unregister:
+	uart_unregister_driver(&efm32_uart_reg);
+out:
+	uart_put_console(&efm32_uart_reg);
 	return ret;
 }
 module_init(efm32_uart_init);
drivers/tty/serial/fsl_lpuart.c +29 -28

141 lines not on this page · raw message

drivers/tty/serial/imx.c +22 -13
index dff75dc94731..741a382b7c9b 100644
@@ -2071,18 +2071,13 @@ imx_uart_console_setup(struct console *co, char *options)
 }
 
 static struct uart_driver imx_uart_uart_driver;
-static struct console imx_uart_console = {
-	.name		= DEV_NAME,
+
+static const struct console_operations imx_cons_ops = {
 	.write		= imx_uart_console_write,
 	.device		= uart_console_device,
 	.setup		= imx_uart_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &imx_uart_uart_driver,
 };
 
-#define IMX_CONSOLE	&imx_uart_console
-
 #ifdef CONFIG_OF
 static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
 {
@@ -2102,14 +2097,17 @@ static void imx_uart_console_early_write(struct console *con, const char *s,
 	uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
 }
 
+static const struct console_operations imx_early_cons_ops = {
+	.write = imx_uart_console_early_write,
+};
+
 static int __init
 imx_console_early_setup(struct earlycon_device *dev, const char *opt)
 {
 	if (!dev->port.membase)
 		return -ENODEV;
 
-	dev->con->write = imx_uart_console_early_write;
-
+	dev->con->ops = &imx_early_cons_ops;
 	return 0;
 }
 OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
@@ -2117,7 +2115,7 @@ OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
 #endif
 
 #else
-#define IMX_CONSOLE	NULL
+static const struct console_operations imx_cons_ops;
 #endif
 
 static struct uart_driver imx_uart_uart_driver = {
@@ -2127,7 +2125,6 @@ static struct uart_driver imx_uart_uart_driver = {
 	.major          = SERIAL_IMX_MAJOR,
 	.minor          = MINOR_START,
 	.nr             = ARRAY_SIZE(imx_uart_ports),
-	.cons           = IMX_CONSOLE,
 };
 
 #ifdef CONFIG_OF
@@ -2553,15 +2550,27 @@ static struct platform_driver imx_uart_platform_driver = {
 
 static int __init imx_uart_init(void)
 {
-	int ret = uart_register_driver(&imx_uart_uart_driver);
+	int ret;
 
+	ret = uart_allocate_console_dfl(&imx_uart_uart_driver, &imx_cons_ops,
+					DEV_NAME, SERIAL_IMX_CONSOLE);
 	if (ret)
 		return ret;
 
+	ret = uart_register_driver(&imx_uart_uart_driver);
+	if (ret)
+		goto out;
+
 	ret = platform_driver_register(&imx_uart_platform_driver);
 	if (ret != 0)
-		uart_unregister_driver(&imx_uart_uart_driver);
+		goto out_unregister;
+
+	return 0;
 
+out_unregister:
+	uart_unregister_driver(&imx_uart_uart_driver);
+out:
+	uart_put_console(&imx_uart_uart_driver);
 	return ret;
 }
 
drivers/tty/serial/ip22zilog.c +10 -8
index 8c810733df3d..ab90fc59a488 100644
@@ -1055,15 +1055,14 @@ static int __init ip22zilog_console_setup(struct console *con, char *options)
 
 static struct uart_driver ip22zilog_reg;
 
-static struct console ip22zilog_console = {
-	.name	=	"ttyS",
+static const struct console_operations ip22zilog_cons_ops = {
 	.write	=	ip22zilog_console_write,
 	.device	=	uart_console_device,
 	.setup	=	ip22zilog_console_setup,
-	.flags	=	CON_PRINTBUFFER,
-	.index	=	-1,
-	.data	=	&ip22zilog_reg,
 };
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/tty/serial/kgdb_nmi.c +15 -6
index 4029272891f9..00cc3a50f601 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/kgdboc.c +1 -1
index 6fb312e7af71..d0f1b306cf9f 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/lantiq.c +15 -8
index 9de9f0f239a1..ae54f5c04a64 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/lpc32xx_hs.c +13 -8
index d1d73261575b..6f3104187aeb 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mcf.c +10 -8
index 7dbfb4cde124..0490c17c5e68 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/meson_uart.c +17 -9
index 8a842591b37c..09d1a5c60053 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mpc52xx_uart.c +10 -8
index 3a75ee08d619..91f0d6b90e50 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mps2-uart.c +21 -13
index 9f8f63719126..a9a9b216e651 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mpsc.c +14 -9
index 1f60d6fe4ff2..6bbbd55ab7d5 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/msm_serial.c +23 -13
index 736b74fd6623..43e326d0e6ff 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mux.c +30 -14

44 lines not on this page · raw message

drivers/tty/serial/mvebu-uart.c +18 -12
index 231f751d1ef4..9b001eeea9f7 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/mxs-auart.c +10 -8
index 27235a526cce..5d532627d8d4 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/netx-serial.c +12 -8
index b3556863491f..6533c1881902 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/omap-serial.c +23 -17
index 6420ae581a80..090fa8a46e4a 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/owl-uart.c +19 -10
index 29a6dc6a8d23..7dc2b50eee6a 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/pch_uart.c +16 -10
index 9ed121f08a54..aa70a0cf206f 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/pic32_uart.c +17 -13
index 0bdf1687983f..ddba3ccfdec8 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/pmac_zilog.c +10 -9
index bcb5bf70534e..de67ee47e1fc 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/pnx8xxx_uart.c +12 -8
index 223a9499104e..f01c27d30015 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/pxa.c +15 -10
index 4932b674f7ef..47b35ff9a48f 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/qcom_geni_serial.c +21 -36

57 lines not on this page · raw message

drivers/tty/serial/rda-uart.c +16 -10
index 284623eefaeb..8dc1429c27a0 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sa1100.c +12 -8
index a399772be3fc..2eb016e547ae 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/samsung.c +30 -11

41 lines not on this page · raw message

drivers/tty/serial/sb1250-duart.c +11 -9
index 329aced26bd8..c5ab9b590303 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sccnxp.c +16 -10
index 68a24a14f6b7..46d0f0e9fd92 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/serial_core.c +14 -2
index 556f50aa1b58..208eb735f086 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/serial_ks8695.c +12 -13
index b461d791188c..f89889c33372 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/serial_txx9.c +13 -8
index 1b4008d022bf..6e0c11625e6d 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sh-sci.c +35 -20

55 lines not on this page · raw message

drivers/tty/serial/sirfsoc_uart.c +15 -11
index 38622f2a30a9..fe0a26e06b65 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sn_console.c +17 -8
index fe9170731c16..404efc8c4e3a 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sprd_serial.c +15 -10
index 4287ca305b6b..511d3563a6ac 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/st-asc.c +16 -11
index 7971997cdead..663695e91a8c 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/stm32-usart.c +8 -9
index e8d7a7bb4339..733020efc0be 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sunhv.c +20 -9
index 63e34d868de8..52ad551cba9c 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sunsab.c +12 -17
index 72131b5e132e..254ce117e02a 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sunsu.c +9 -17
index 4db6aaa330b2..229afa1d9c75 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/sunzilog.c +13 -13
index bc7af8b08a72..f82397a679ea 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/uartlite.c +14 -9
index b8b912b5a8b9..c88681617c08 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/vr41xx_siu.c +21 -10
index 6d106e33f842..8eaaf62db1c7 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/vt8500_serial.c +13 -12
index 3d58e9b34553..caf0f789fee9 100644

Lines of this file are not shown. View the raw message.

drivers/tty/serial/xilinx_uartps.c +20 -22

42 lines not on this page · raw message

drivers/tty/serial/zs.c +16 -9
index b03d3e458ea2..e3e6c09b7f64 100644

Lines of this file are not shown. View the raw message.

drivers/tty/tty_io.c +3 -3
index 21ffcce16927..e06c9a1d4e89 100644

Lines of this file are not shown. View the raw message.

drivers/tty/vt/vt.c +9 -5
index bba75560d11e..ca66365c3cd6 100644

Lines of this file are not shown. View the raw message.

drivers/usb/early/ehci-dbgp.c +6 -1
index ea0d531c63e2..83d97f55ec6a 100644

Lines of this file are not shown. View the raw message.

drivers/usb/early/xhci-dbc.c +6 -1
index d2652dccc699..80a5f6d28be8 100644

Lines of this file are not shown. View the raw message.

drivers/usb/gadget/function/u_serial.c +13 -9
index 29436f75bbe0..6728ec61f9f4 100644

Lines of this file are not shown. View the raw message.

drivers/usb/serial/console.c +15 -9
index 7d289302ff6c..0983c574133b 100644

Lines of this file are not shown. View the raw message.

drivers/usb/serial/usb-serial.c +10 -3
index 7e89efbf2c28..b3c4ea62a0f0 100644

Lines of this file are not shown. View the raw message.

fs/proc/consoles.c +5 -5
index 954caf0b7fee..8c71658707b8 100644

Lines of this file are not shown. View the raw message.

fs/pstore/platform.c +18 -7
index 2d1066ed3c28..2cc38460b70c 100644

Lines of this file are not shown. View the raw message.

include/linux/console.h +34 -2
index 3c27a4a29b8c..382591683033 100644

Lines of this file are not shown. View the raw message.

include/linux/serial_core.h +19 -0
index 5fe2b037e833..29b43c4df3d6 100644

Lines of this file are not shown. View the raw message.

include/linux/usb/serial.h +2 -2
index 1c19f77ed541..48841e441e2e 100644

Lines of this file are not shown. View the raw message.

kernel/debug/debug_core.c +6 -1
index 5cc608de6883..d082d7fbea27 100644

Lines of this file are not shown. View the raw message.

kernel/debug/kdb/kdb_io.c +2 -2
index 6a4b41484afe..eb48ad341411 100644

Lines of this file are not shown. View the raw message.

kernel/printk/printk.c +95 -19

114 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.17.1

Part of the diff is not shown here. View the raw message.

maintainer
#10 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 2 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

I expect that "class" would be more appropriate than "bus". These devices really are grouped together based on their function and not the medium by which they are accessed.

John Ogness

maintainer
#11 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 7 lines · John Ogness
Quoted 2 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

I expect that "class" would be more appropriate than "bus". These devices really are grouped together based on their function and not the medium by which they are accessed.

Good point. "class" looks better to me as well.

Greg, any opinion, where to put the entries for struct console ?

Best Regards,
Petr

#12 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 5 lines · Petr Mladek
Quoted 4 lines · John Ogness
Quoted 2 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Quoted 7 lines
Quoted 3 lines

I expect that "class" would be more appropriate than "bus". These devices really are grouped together based on their function and not the medium by which they are accessed.

Good point. "class" looks better to me as well.

Greg, any opinion, where to put the entries for struct console ?

Hang them off of the device that the console belongs to?

Classes and busses are almost identical except:
- busses is the binding of a driver to a device (usb, pci, etc.)
- classes are usually userspace interactions to a device (input, tty, etc.)

So this sounds like a class to me.

If you want me to review this, I'll be glad to so do once 5.1-rc1 is out...

thanks,

greg k-h

#13 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 14 lines · Greg Kroah-Hartman
Quoted 5 lines · Petr Mladek
Quoted 4 lines · John Ogness
Quoted 2 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Quoted 7 lines
Quoted 3 lines

I expect that "class" would be more appropriate than "bus". These devices really are grouped together based on their function and not the medium by which they are accessed.

Good point. "class" looks better to me as well.

Greg, any opinion, where to put the entries for struct console ?

Quoted 8 lines

Hang them off of the device that the console belongs to?

Classes and busses are almost identical except:
- busses is the binding of a driver to a device (usb, pci, etc.)
- classes are usually userspace interactions to a device (input, tty, etc.)

So this sounds like a class to me.

Sounds good, will make it a class.

Quoted 2 lines

If you want me to review this, I'll be glad to so do once 5.1-rc1 is out...

Yeah, I realized after sending this the timing was pretty terrible, I'll wait for 5.1-rc1 before rebasing/resending.

Thanks,
Calvin

Quoted 3 lines

thanks,

greg k-h

maintainer
#14 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

In reply to Calvin Owens
Quoted 7 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

I wonder if it might get detected by is_kernel_inittext().

Best Regards,
Petr

#15 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 10 lines · Petr Mladek
Quoted 7 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

I wonder if it might get detected by is_kernel_inittext().

I don't think inittext() in particular would work, since these actually need to exist forever if you pass "earlyprintk=[...],keep" so they aren't __init.

But I bet you're right that we could catch the static case without needing the explicit flag, something like is_module_address() (but it would also need to work for the built-in case). I'll see if I can get this to work.

Thanks,
Calvin

Quoted 2 lines

Best Regards,
Petr

maintainer
#16 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

In reply to Calvin Owens
Quoted 22 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Currently, most drivers declare static console structs, and that is incompatible with the dev refcount model. So we end up needing to patch all of the console drivers to:

1. Dynamically allocate the console struct using a new helper
2. Handle the allocation in (1) possibly failing
3. Dispose of (1) with put_device()

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

drivers/char/lp.c +0 -0
index 5c8d780637bd..e09cb192a469 100644
@@ -857,12 +857,12 @@ static void lp_console_write(struct console *co, const char *s,
 	parport_release(dev);

drivers/char/lp.c static void lp_console_write(struct console *co, const char *s, · line 864

Quoted 10 lines
drivers/char/lp.c +2 -3
 }
 
-static struct console lpcons = {
-	.name		= "lp",
+static const struct console_operations lp_cons_ops = {
 	.write		= lp_console_write,
-	.flags		= CON_PRINTBUFFER,
 };
 
+static struct console *lpcons;

I have got the following compilation error (see below):

CC drivers/char/lp.o
drivers/char/lp.c: In function ‘lp_register’:
drivers/char/lp.c:925:2: error: ‘lpcons’ undeclared (first use in this function)
lpcons = allocate_console_dfl(&lp_cons_ops, "lp", NULL);
^
drivers/char/lp.c:925:2: note: each undeclared identifier is reported only once for each function it appears in In file included from drivers/char/lp.c:125:0:
drivers/char/lp.c:925:33: error: ‘lp_cons_ops’ undeclared (first use in this function)

drivers/char/lp.c static int lp_register(int nr, struct parport *port) · line 927

Quoted 11 lines
drivers/char/lp.c +4 -0
 #endif /* console on line printer */
 
 /* --- initialisation code ------------------------------------- */
@@ -921,6 +921,11 @@ static int lp_register(int nr, struct parport *port)
 						      &ppdev_cb, nr);
 	if (lp_table[nr].dev == NULL)
 		return 1;
+
+	lpcons = allocate_console_dfl(&lp_cons_ops, "lp", NULL);
+	if (!lpcons)
+		return -ENOMEM;

This should be done inside #ifdef CONFIG_LP_CONSOLE to avoid the above compilation error.

Quoted 4 lines
drivers/char/lp.c +1 -0
+
 	lp_table[nr].flags |= LP_EXIST;
 
 	if (reset)

[...]

Quoted 71 lines
include/linux/console.h +33 -2
index 3c27a4a29b8c..382591683033 100644
@@ -142,20 +143,28 @@ static inline int con_debug_leave(void)
 #define CON_BRL		(32) /* Used for a braille device */
 #define CON_EXTENDED	(64) /* Use the extended output format a la /dev/kmsg */
 
-struct console {
-	char	name[16];
+struct console;
+
+struct console_operations {
 	void	(*write)(struct console *, const char *, unsigned);
 	int	(*read)(struct console *, char *, unsigned);
 	struct tty_driver *(*device)(struct console *, int *);
 	void	(*unblank)(void);
 	int	(*setup)(struct console *, char *);
 	int	(*match)(struct console *, char *name, int idx, char *options);
+};
+
+struct console {
+	char	name[16];
 	short	flags;
 	short	index;
 	int	cflag;
 	void	*data;
 	struct	 console *next;
 	int	level;
+	const struct console_operations *ops;
+	struct device dev;
+	int is_static;
 };
 
 /*
@@ -167,6 +176,29 @@ struct console {
 extern int console_set_on_cmdline;
 extern struct console *early_console;
 
+extern struct console *allocate_console(const struct console_operations *ops,
+					const char *name, short flags,
+					short index, void *data);
+
+#define allocate_console_dfl(ops, name, data) \
+	allocate_console(ops, name, CON_PRINTBUFFER, -1, data)
+
+/*
+ * Helpers for get/put that do the right thing for static early consoles.
+ */
+
+#define get_console(con) \
+do { \
+	if (!con->is_static) \
+		get_device(&(con)->dev); \
+} while (0)
+
+#define put_console(con) \
+do { \
+	if (con && !con->is_static) \
+		put_device(&((struct console *)con)->dev); \
+} while (0)
+
 extern int add_preferred_console(char *name, int idx, char *options);
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
include/linux/serial_core.h +0 -0
index 5fe2b037e833..29b43c4df3d6 100644
@@ -426,6 +426,25 @@ int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);

include/linux/serial_core.h int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); · line 436

Quoted 10 lines
include/linux/serial_core.h +8 -0
 int uart_match_port(struct uart_port *port1, struct uart_port *port2);
 
+/*
+ * This ugliness removes the need for #ifdef boilerplate in UART drivers which
+ * allow their console functionality to be disabled via Kconfig.
+ */
+#define uart_allocate_console(drv, ops, name, flags, idx, kcfg)		    \
+({									    \
+	int __retval = 0;						    \
+	if (IS_ENABLED(CONFIG_##kcfg)) {				    \

I wonder if it is worth it. I do not see much existing #ifdef's removed by this patch. I would expect that the code is never called when the driver is disabled in Kconfig.

IMHO, such a trick hidden in a macro could cause more confusion than good.

Quoted 122 lines
include/linux/serial_core.h +11 -0
+		(drv)->cons = allocate_console(ops, name, flags, idx, drv); \
+		__retval = (drv)->cons ? 0 : -ENOMEM;			    \
+	}								    \
+	__retval;							    \
+})
+
+#define uart_allocate_console_dfl(drv, ops, name, kcfg) \
+	uart_allocate_console(drv, ops, name, CON_PRINTBUFFER, -1, kcfg)
+
+#define uart_put_console(drv) put_console((drv)->cons)
+
 /*
  * Power Management
  */
kernel/printk/printk.c +48 -8
index 2e0eb89f046c..67e1e993ab80 100644
@@ -108,6 +108,8 @@ enum devkmsg_log_masks {
 
 static unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT;
 
+static int printk_late_done;
+
 static int __control_devkmsg(char *str)
 {
 	if (!str)
@@ -1731,7 +1733,7 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 			continue;
 		if (!(con->flags & CON_ENABLED))
 			continue;
-		if (!con->write)
+		if (!con->ops->write)
 			continue;
 		if (!cpu_online(smp_processor_id()) &&
 		    !(con->flags & CON_ANYTIME))
@@ -1739,9 +1741,9 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 		if (suppress_message_printing(level, con))
 			continue;
 		if (con->flags & CON_EXTENDED)
-			con->write(con, ext_text, ext_len);
+			con->ops->write(con, ext_text, ext_len);
 		else
-			con->write(con, text, len);
+			con->ops->write(con, text, len);
 	}
 }
 
@@ -2052,7 +2054,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 	n = vscnprintf(buf, sizeof(buf), fmt, ap);
 	va_end(ap);
 
-	early_console->write(early_console, buf, n);
+	early_console->ops->write(early_console, buf, n);
 }
 #endif
 
@@ -2481,8 +2483,8 @@ void console_unblank(void)
 	console_locked = 1;
 	console_may_schedule = 0;
 	for_each_console(c)
-		if ((c->flags & CON_ENABLED) && c->unblank)
-			c->unblank();
+		if ((c->flags & CON_ENABLED) && c->ops->unblank)
+			c->ops->unblank();
 	console_unlock();
 }
 
@@ -2515,9 +2517,9 @@ struct tty_driver *console_device(int *index)
 
 	console_lock();
 	for_each_console(c) {
-		if (!c->device)
+		if (!c->ops->device)
 			continue;
-		driver = c->device(c, index);
+		driver = c->ops->device(c, index);
 		if (driver)
 			break;
 	}
@@ -2558,6 +2560,68 @@ static int __init keep_bootcon_setup(char *str)
 
 early_param("keep_bootcon", keep_bootcon_setup);
 
+static struct bus_type console_subsys = {
+	.name = "console",
+};
+
+static void console_release(struct device *dev)
+{
+	struct console *con = container_of(dev, struct console, dev);
+
+	if (WARN(con->is_static, "Freeing static early console!\n"))
+		return;
+
+	if (WARN(con->flags & CON_ENABLED, "Freeing running console!\n"))
+		return;
+
+	pr_info("Freeing console %s\n", con->name);
+	kfree(con);
+}
+
+static void console_init_device(struct console *con)
+{
+	device_initialize(&con->dev);
+	dev_set_name(&con->dev, "%s", con->name);
+	con->dev.release = console_release;
+}
+
+static void console_register_device(struct console *new)
+{
+	/*
+	 * We might be called very early from register_console(): in that case,
+	 * printk_late_init() will take care of this later.
+	 */
+	if (!printk_late_done)
+		return;
+
+	if (new->is_static)
+		console_init_device(new);
+
+	new->dev.bus = &console_subsys;

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2610

Quoted 10 lines
kernel/printk/printk.c +10 -0
+	WARN_ON(device_add(&new->dev));
+}
+
+struct console *allocate_console(const struct console_operations *ops,
+				 const char *name, short flags, short index,
+				 void *data)
+{
+	struct console *new;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);

I have just realized that page_alloc_init() is called before parse_early_param(). Therefore we should be able to use memblock_alloc() for early consoles and reduce problems with static structures.

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2620

Quoted 10 lines
kernel/printk/printk.c +10 -0
+	if (!new)
+		return NULL;
+
+	new->ops = ops;
+	strscpy(new->name, name, sizeof(new->name));
+	new->flags = flags;
+	new->index = index;
+	new->data = data;
+
+	console_init_device(new);

This is a side effect that I would not expect from a function called alloc*(). I would rename:

s/allocate_console/create_console/ or
s/allocate_console/init_console/

Quoted 8 lines
kernel/printk/printk.c +4 -0
+	return new;
+}
+EXPORT_SYMBOL_GPL(allocate_console);
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to

kernel/printk/printk.c void register_console(struct console *newcon) · line 2692

Quoted 10 lines
kernel/printk/printk.c +3 -3
@@ -2622,10 +2686,10 @@ void register_console(struct console *newcon)
 	if (!has_preferred) {
 		if (newcon->index < 0)
 			newcon->index = 0;
-		if (newcon->setup == NULL ||
-		    newcon->setup(newcon, NULL) == 0) {
+		if (newcon->ops->setup == NULL ||
+		    newcon->ops->setup(newcon, NULL) == 0) {
 			newcon->flags |= CON_ENABLED;
-			if (newcon->device) {
+			if (newcon->ops->device) {

There might be confusion why we need two devices (con->dev and con->ops->device).

I would rename con->ops->device to con->ops->tty_dev.

Quoted 35 lines
kernel/printk/printk.c +6 -4
 				newcon->flags |= CON_CONSDEV;
 				has_preferred = true;
 			}
@@ -2639,8 +2703,8 @@ void register_console(struct console *newcon)
 	for (i = 0, c = console_cmdline;
 	     i < MAX_CMDLINECONSOLES && c->name[0];
 	     i++, c++) {
-		if (!newcon->match ||
-		    newcon->match(newcon, c->name, c->index, c->options) != 0) {
+		if (!newcon->ops->match ||
+		    newcon->ops->match(newcon, c->name, c->index, c->options) != 0) {
 			/* default matching */
 			BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
 			if (strcmp(c->name, newcon->name) != 0)
@@ -2660,8 +2724,8 @@ void register_console(struct console *newcon)
 			if (_braille_register_console(newcon, c))
 				return;
 
-			if (newcon->setup &&
-			    newcon->setup(newcon, c->options) != 0)
+			if (newcon->ops->setup &&
+			    newcon->ops->setup(newcon, c->options) != 0)
 				break;
 		}
 
@@ -2706,6 +2770,8 @@ void register_console(struct console *newcon)
 		console_drivers->next = newcon;
 	}
 
+	get_console(newcon);
+
 	if (newcon->flags & CON_EXTENDED)
 		nr_ext_console_drivers++;
 

kernel/printk/printk.c void register_console(struct console *newcon) · line 2799

Quoted 4 lines
kernel/printk/printk.c +1 -0
@@ -2730,6 +2796,7 @@ void register_console(struct console *newcon)
 		exclusive_console_stop_seq = console_seq;
 		logbuf_unlock_irqrestore(flags);
 	}
+	console_register_device(newcon);

This calls console_init_device() for the statically defined early consoles. I guess that it would invalidate the above get_console().

Also it is not symmetric with unregister_console(). We add it to the console_subsys here and did not remove it when the console is unregistered.

IMHO, this might be done already in allocate_console(). And eventually in printk_late_init() for consoles that are allocated earlier.

I am not familiar with the device-related sysfs API. But I see that device_initialize() and device_add() can be done by device_register(). The separate calls are needed only when a special reference handling is needed. Are we special?

Anyway, please, try to describe the expected workflow in the commit description:

+ where the structure should get allocated
+ when it is added to the sysfs hierarchy
+ what happens when the console gets registered and unregistered
+ when it is removed from the sysfs hierarchy
+ when the structure is released/freed

+ What is needed to get the console registered and unregistered repeatedly on a running system

Finally, we might want to show state of the CON_ENABLED flag in sysfs to distinguish the currently used consoles.

kernel/printk/printk.c void register_console(struct console *newcon) · line 2801

Quoted 2 lines
kernel/printk/printk.c +0 -0
 	console_unlock();
 	console_sysfs_notify();

Thanks a lot for working on this. I know that it is not easy. But it is really appreciated.

Best Regards,
Petr

#17 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 36 lines · Petr Mladek
Quoted 22 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Currently, most drivers declare static console structs, and that is incompatible with the dev refcount model. So we end up needing to patch all of the console drivers to:

1. Dynamically allocate the console struct using a new helper
2. Handle the allocation in (1) possibly failing
3. Dispose of (1) with put_device()

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

drivers/char/lp.c +0 -0
index 5c8d780637bd..e09cb192a469 100644
@@ -857,12 +857,12 @@ static void lp_console_write(struct console *co, const char *s,
 	parport_release(dev);

drivers/char/lp.c static void lp_console_write(struct console *co, const char *s, · line 864

Quoted 10 lines
drivers/char/lp.c +2 -3
 }
 
-static struct console lpcons = {
-	.name		= "lp",
+static const struct console_operations lp_cons_ops = {
 	.write		= lp_console_write,
-	.flags		= CON_PRINTBUFFER,
 };
 
+static struct console *lpcons;

I have got the following compilation error (see below):

Quoted 8 lines

CC drivers/char/lp.o
drivers/char/lp.c: In function ‘lp_register’:
drivers/char/lp.c:925:2: error: ‘lpcons’ undeclared (first use in this function)
lpcons = allocate_console_dfl(&lp_cons_ops, "lp", NULL);
^
drivers/char/lp.c:925:2: note: each undeclared identifier is reported only once for each function it appears in In file included from drivers/char/lp.c:125:0:
drivers/char/lp.c:925:33: error: ‘lp_cons_ops’ undeclared (first use in this function)

D'oh, will fix.

Quoted 108 lines

drivers/char/lp.c static int lp_register(int nr, struct parport *port) · line 927

Quoted 12 lines
drivers/char/lp.c +4 -0
 #endif /* console on line printer */
 
 /* --- initialisation code ------------------------------------- */
@@ -921,6 +921,11 @@ static int lp_register(int nr, struct parport *port)
 						      &ppdev_cb, nr);
 	if (lp_table[nr].dev == NULL)
 		return 1;
+
+	lpcons = allocate_console_dfl(&lp_cons_ops, "lp", NULL);
+	if (!lpcons)
+		return -ENOMEM;

This should be done inside #ifdef CONFIG_LP_CONSOLE to avoid the above compilation error.

Quoted 4 lines
drivers/char/lp.c +1 -0
+
 	lp_table[nr].flags |= LP_EXIST;
 
 	if (reset)

[...]

Quoted 71 lines
include/linux/console.h +33 -2
index 3c27a4a29b8c..382591683033 100644
@@ -142,20 +143,28 @@ static inline int con_debug_leave(void)
 #define CON_BRL		(32) /* Used for a braille device */
 #define CON_EXTENDED	(64) /* Use the extended output format a la /dev/kmsg */
 
-struct console {
-	char	name[16];
+struct console;
+
+struct console_operations {
 	void	(*write)(struct console *, const char *, unsigned);
 	int	(*read)(struct console *, char *, unsigned);
 	struct tty_driver *(*device)(struct console *, int *);
 	void	(*unblank)(void);
 	int	(*setup)(struct console *, char *);
 	int	(*match)(struct console *, char *name, int idx, char *options);
+};
+
+struct console {
+	char	name[16];
 	short	flags;
 	short	index;
 	int	cflag;
 	void	*data;
 	struct	 console *next;
 	int	level;
+	const struct console_operations *ops;
+	struct device dev;
+	int is_static;
 };
 
 /*
@@ -167,6 +176,29 @@ struct console {
 extern int console_set_on_cmdline;
 extern struct console *early_console;
 
+extern struct console *allocate_console(const struct console_operations *ops,
+					const char *name, short flags,
+					short index, void *data);
+
+#define allocate_console_dfl(ops, name, data) \
+	allocate_console(ops, name, CON_PRINTBUFFER, -1, data)
+
+/*
+ * Helpers for get/put that do the right thing for static early consoles.
+ */
+
+#define get_console(con) \
+do { \
+	if (!con->is_static) \
+		get_device(&(con)->dev); \
+} while (0)
+
+#define put_console(con) \
+do { \
+	if (con && !con->is_static) \
+		put_device(&((struct console *)con)->dev); \
+} while (0)
+
 extern int add_preferred_console(char *name, int idx, char *options);
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
include/linux/serial_core.h +0 -0
index 5fe2b037e833..29b43c4df3d6 100644
@@ -426,6 +426,25 @@ int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);

include/linux/serial_core.h int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); · line 436

Quoted 10 lines
include/linux/serial_core.h +8 -0
 int uart_match_port(struct uart_port *port1, struct uart_port *port2);
 
+/*
+ * This ugliness removes the need for #ifdef boilerplate in UART drivers which
+ * allow their console functionality to be disabled via Kconfig.
+ */
+#define uart_allocate_console(drv, ops, name, flags, idx, kcfg)		    \
+({									    \
+	int __retval = 0;						    \
+	if (IS_ENABLED(CONFIG_##kcfg)) {				    \

I wonder if it is worth it. I do not see much existing #ifdef's removed by this patch. I would expect that the code is never called when the driver is disabled in Kconfig.

Quoted 2 lines

IMHO, such a trick hidden in a macro could cause more confusion than good.

Yeah... I wasn't really sure about this either, I don't disagree that it's marginally evil.

Quoted 130 lines
Quoted 130 lines
include/linux/serial_core.h +11 -0
+		(drv)->cons = allocate_console(ops, name, flags, idx, drv); \
+		__retval = (drv)->cons ? 0 : -ENOMEM;			    \
+	}								    \
+	__retval;							    \
+})
+
+#define uart_allocate_console_dfl(drv, ops, name, kcfg) \
+	uart_allocate_console(drv, ops, name, CON_PRINTBUFFER, -1, kcfg)
+
+#define uart_put_console(drv) put_console((drv)->cons)
+
 /*
  * Power Management
  */
kernel/printk/printk.c +55 -8
index 2e0eb89f046c..67e1e993ab80 100644
@@ -108,6 +108,8 @@ enum devkmsg_log_masks {
 
 static unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT;
 
+static int printk_late_done;
+
 static int __control_devkmsg(char *str)
 {
 	if (!str)
@@ -1731,7 +1733,7 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 			continue;
 		if (!(con->flags & CON_ENABLED))
 			continue;
-		if (!con->write)
+		if (!con->ops->write)
 			continue;
 		if (!cpu_online(smp_processor_id()) &&
 		    !(con->flags & CON_ANYTIME))
@@ -1739,9 +1741,9 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
 		if (suppress_message_printing(level, con))
 			continue;
 		if (con->flags & CON_EXTENDED)
-			con->write(con, ext_text, ext_len);
+			con->ops->write(con, ext_text, ext_len);
 		else
-			con->write(con, text, len);
+			con->ops->write(con, text, len);
 	}
 }
 
@@ -2052,7 +2054,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 	n = vscnprintf(buf, sizeof(buf), fmt, ap);
 	va_end(ap);
 
-	early_console->write(early_console, buf, n);
+	early_console->ops->write(early_console, buf, n);
 }
 #endif
 
@@ -2481,8 +2483,8 @@ void console_unblank(void)
 	console_locked = 1;
 	console_may_schedule = 0;
 	for_each_console(c)
-		if ((c->flags & CON_ENABLED) && c->unblank)
-			c->unblank();
+		if ((c->flags & CON_ENABLED) && c->ops->unblank)
+			c->ops->unblank();
 	console_unlock();
 }
 
@@ -2515,9 +2517,9 @@ struct tty_driver *console_device(int *index)
 
 	console_lock();
 	for_each_console(c) {
-		if (!c->device)
+		if (!c->ops->device)
 			continue;
-		driver = c->device(c, index);
+		driver = c->ops->device(c, index);
 		if (driver)
 			break;
 	}
@@ -2558,6 +2560,68 @@ static int __init keep_bootcon_setup(char *str)
 
 early_param("keep_bootcon", keep_bootcon_setup);
 
+static struct bus_type console_subsys = {
+	.name = "console",
+};
+
+static void console_release(struct device *dev)
+{
+	struct console *con = container_of(dev, struct console, dev);
+
+	if (WARN(con->is_static, "Freeing static early console!\n"))
+		return;
+
+	if (WARN(con->flags & CON_ENABLED, "Freeing running console!\n"))
+		return;
+
+	pr_info("Freeing console %s\n", con->name);
+	kfree(con);
+}
+
+static void console_init_device(struct console *con)
+{
+	device_initialize(&con->dev);
+	dev_set_name(&con->dev, "%s", con->name);
+	con->dev.release = console_release;
+}
+
+static void console_register_device(struct console *new)
+{
+	/*
+	 * We might be called very early from register_console(): in that case,
+	 * printk_late_init() will take care of this later.
+	 */
+	if (!printk_late_done)
+		return;
+
+	if (new->is_static)
+		console_init_device(new);
+
+	new->dev.bus = &console_subsys;
+	WARN_ON(device_add(&new->dev));
+}
+
+struct console *allocate_console(const struct console_operations *ops,
+				 const char *name, short flags, short index,
+				 void *data)
+{
Quoted 8 lines

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2610

Quoted 3 lines
kernel/printk/printk.c +3 -0
+	struct console *new;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);

I have just realized that page_alloc_init() is called before parse_early_param(). Therefore we should be able to use memblock_alloc() for early consoles and reduce problems with static structures.

Ah nice, I'll look into that. This would all be a lot nicer without the special cases.

Quoted 15 lines

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2620

Quoted 11 lines
kernel/printk/printk.c +10 -0
+	if (!new)
+		return NULL;
+
+	new->ops = ops;
+	strscpy(new->name, name, sizeof(new->name));
+	new->flags = flags;
+	new->index = index;
+	new->data = data;
+
+	console_init_device(new);

This is a side effect that I would not expect from a function called alloc*(). I would rename:

Quoted 2 lines

s/allocate_console/create_console/ or
s/allocate_console/init_console/

Makes sense.

Quoted 23 lines
Quoted 9 lines
kernel/printk/printk.c +4 -0
+	return new;
+}
+EXPORT_SYMBOL_GPL(allocate_console);
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to

kernel/printk/printk.c void register_console(struct console *newcon) · line 2692

Quoted 10 lines
kernel/printk/printk.c +3 -3
@@ -2622,10 +2686,10 @@ void register_console(struct console *newcon)
 	if (!has_preferred) {
 		if (newcon->index < 0)
 			newcon->index = 0;
-		if (newcon->setup == NULL ||
-		    newcon->setup(newcon, NULL) == 0) {
+		if (newcon->ops->setup == NULL ||
+		    newcon->ops->setup(newcon, NULL) == 0) {
 			newcon->flags |= CON_ENABLED;
-			if (newcon->device) {
+			if (newcon->ops->device) {

There might be confusion why we need two devices (con->dev and con->ops->device).

Quoted 1 line

I would rename con->ops->device to con->ops->tty_dev.

Makes sense.

Quoted 35 lines
Quoted 35 lines
kernel/printk/printk.c +6 -4
 				newcon->flags |= CON_CONSDEV;
 				has_preferred = true;
 			}
@@ -2639,8 +2703,8 @@ void register_console(struct console *newcon)
 	for (i = 0, c = console_cmdline;
 	     i < MAX_CMDLINECONSOLES && c->name[0];
 	     i++, c++) {
-		if (!newcon->match ||
-		    newcon->match(newcon, c->name, c->index, c->options) != 0) {
+		if (!newcon->ops->match ||
+		    newcon->ops->match(newcon, c->name, c->index, c->options) != 0) {
 			/* default matching */
 			BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
 			if (strcmp(c->name, newcon->name) != 0)
@@ -2660,8 +2724,8 @@ void register_console(struct console *newcon)
 			if (_braille_register_console(newcon, c))
 				return;
 
-			if (newcon->setup &&
-			    newcon->setup(newcon, c->options) != 0)
+			if (newcon->ops->setup &&
+			    newcon->ops->setup(newcon, c->options) != 0)
 				break;
 		}
 
@@ -2706,6 +2770,8 @@ void register_console(struct console *newcon)
 		console_drivers->next = newcon;
 	}
 
+	get_console(newcon);
+
 	if (newcon->flags & CON_EXTENDED)
 		nr_ext_console_drivers++;
 
Quoted 9 lines

kernel/printk/printk.c void register_console(struct console *newcon) · line 2799

Quoted 5 lines
kernel/printk/printk.c +1 -0
@@ -2730,6 +2796,7 @@ void register_console(struct console *newcon)
 		exclusive_console_stop_seq = console_seq;
 		logbuf_unlock_irqrestore(flags);
 	}
+	console_register_device(newcon);

This calls console_init_device() for the statically defined early consoles. I guess that it would invalidate the above get_console().

The get_console() macro checks for ->is_static and is a NOP if it's set, which is definitely confusing.

Quoted 3 lines

Also it is not symmetric with unregister_console(). We add it to the console_subsys here and did not remove it when the console is unregistered.

We do a put() in the unregister path, somebody could hold a reference through sysfs so we can't just remove it. Or am I misunderstanding?

Quoted 9 lines

IMHO, this might be done already in allocate_console(). And eventually in printk_late_init() for consoles that are allocated earlier.

I am not familiar with the device-related sysfs API. But I see that device_initialize() and device_add() can be done by device_register(). The separate calls are needed only when a special reference handling is needed. Are we special?

We're special: the console initcalls run before the device core is initialized, initialize() lets us use the refcount.

That said, I'm hopeful your suggestion about using memblock_alloc() will make some of this confusion unnecessary, it's definitely... confusing.

Quoted 10 lines

Anyway, please, try to describe the expected workflow in the commit description:

+ where the structure should get allocated
+ when it is added to the sysfs hierarchy
+ what happens when the console gets registered and unregistered
+ when it is removed from the sysfs hierarchy
+ when the structure is released/freed

Quoted 5 lines

+ What is needed to get the console registered and unregistered repeatedly on a running system

Finally, we might want to show state of the CON_ENABLED flag in sysfs to distinguish the currently used consoles.

Makes sense.

Quoted 6 lines

kernel/printk/printk.c void register_console(struct console *newcon) · line 2801

Quoted 3 lines
kernel/printk/printk.c +0 -0
 	console_unlock();
 	console_sysfs_notify();

Thanks a lot for working on this. I know that it is not easy. But it is really appreciated.

Thanks :)

--Calvin

Quoted 2 lines

Best Regards,
Petr

maintainer
#18 lore raw

Re: [PATCH 3/4] printk: Add consoles to a virtual "console" bus

Quoted 44 lines · Calvin Owens
Quoted 30 lines · Petr Mladek
Quoted 29 lines · Calvin Owens

This patch embeds a device struct in the console struct, and registers them on a "console" bus so we can expose attributes in sysfs.

Currently, most drivers declare static console structs, and that is incompatible with the dev refcount model. So we end up needing to patch all of the console drivers to:

1. Dynamically allocate the console struct using a new helper
2. Handle the allocation in (1) possibly failing
3. Dispose of (1) with put_device()

Early console structures must still be static, since they're required before we're able to allocate memory. The least ugly way I can come up with to handle this is an "is_static" flag in the structure which makes the gets and puts NOPs, and is checked in ->release() to catch mistakes.

kernel/printk/printk.c +2 -0
index 2e0eb89f046c..67e1e993ab80 100644
@@ -2706,6 +2770,8 @@ void register_console(struct console *newcon)
 		console_drivers->next = newcon;
 	}
 
+	get_console(newcon);
+
 	if (newcon->flags & CON_EXTENDED)
 		nr_ext_console_drivers++;
 
Quoted 9 lines

kernel/printk/printk.c void register_console(struct console *newcon) · line 2799

Quoted 5 lines
kernel/printk/printk.c +1 -0
@@ -2730,6 +2796,7 @@ void register_console(struct console *newcon)
 		exclusive_console_stop_seq = console_seq;
 		logbuf_unlock_irqrestore(flags);
 	}
+	console_register_device(newcon);

This calls console_init_device() for the statically defined early consoles. I guess that it would invalidate the above get_console().

The get_console() macro checks for ->is_static and is a NOP if it's set, which is definitely confusing.

Quoted 6 lines
Quoted 3 lines

Also it is not symmetric with unregister_console(). We add it to the console_subsys here and did not remove it when the console is unregistered.

We do a put() in the unregister path, somebody could hold a reference through sysfs so we can't just remove it. Or am I misunderstanding?

To be honest, I am not sure what the effect of get_device() and put_device() is. But they are called also in device_add(). This suggests that the sysfs interface and struct device stay even when we call device_put() in unregister_console().

This is an asymmetry. The sysfs interface is created only for successfully registered console but it stays even after unregistration (if it works as I expect).

Another problem is that register_console()/unregister_console() might get called repeatedly for the same console. But device_add() should get called only once.

I think that we could do better, see below.

Quoted 4 lines
Quoted 4 lines

IMHO, this might be done already in allocate_console(). And eventually in printk_late_init() for consoles that are allocated earlier.

Quoted 8 lines
Quoted 5 lines

I am not familiar with the device-related sysfs API. But I see that device_initialize() and device_add() can be done by device_register(). The separate calls are needed only when a special reference handling is needed. Are we special?

We're special: the console initcalls run before the device core is initialized, initialize() lets us use the refcount.

But console_init_device() is called later from printk_late_init() for the statically defined structures (early consoles). This would reset the refcount for these consoles.

I think that we should delay calling console_init_device() for all consoles until printk_late_done is set. Then it should be safe to call device_register() there.

Best Regards,
Petr

#19 lore raw

PATCH 4/4 printk: Add a device attribute for the per-console loglevel

In reply to Calvin Owens
---
 kernel/printk/printk.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
kernel/printk/printk.c +40 -0
index 67e1e993ab80..e7e602fa2d0b 100644
@@ -2560,8 +2560,48 @@ static int __init keep_bootcon_setup(char *str)
 
 early_param("keep_bootcon", keep_bootcon_setup);
 
+static ssize_t loglevel_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct console *con = container_of(dev, struct console, dev);
+	return sprintf(buf, "%d\n", con->level);
+}
+
+static ssize_t loglevel_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct console *con = container_of(dev, struct console, dev);
+	ssize_t ret;
+	int tmp;
+
+	ret = kstrtoint(buf, 10, &tmp);
+	if (ret < 0)
+		return ret;
+
+	if (tmp < LOGLEVEL_EMERG)
+		return -ERANGE;
+
+	/*
+	 * Mimic the behavior of /dev/kmsg with respect to minimum_loglevel.
+	 */
+	if (tmp < minimum_console_loglevel)
+		tmp = minimum_console_loglevel;
+
+	con->level = tmp;
+	return ret;
+}
+
+static DEVICE_ATTR_RW(loglevel);
+
+static struct attribute *console_sysfs_attrs[] = {
+	&dev_attr_loglevel.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(console_sysfs);
+
 static struct bus_type console_subsys = {
 	.name = "console",
+	.dev_groups = console_sysfs_groups,
 };
 
 static void console_release(struct device *dev)
Signature · 1 line
2.17.1
#20 lore raw

Re: [PATCH 4/4] printk: Add a device attribute for the per-console loglevel

Quoted 26 lines · Calvin Owens
kernel/printk/printk.c +26 -0
+static ssize_t loglevel_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct console *con = container_of(dev, struct console, dev);
+	ssize_t ret;
+	int tmp;
+
+	ret = kstrtoint(buf, 10, &tmp);
+	if (ret < 0)
+		return ret;
+
+	if (tmp < LOGLEVEL_EMERG)
+		return -ERANGE;
+
+	/*
+	 * Mimic the behavior of /dev/kmsg with respect to minimum_loglevel.
+	 */
+	if (tmp < minimum_console_loglevel)
+		tmp = minimum_console_loglevel;
+
+	con->level = tmp;
+	return ret;
+}
+
+static DEVICE_ATTR_RW(loglevel);
+

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2605

Quoted 10 lines
kernel/printk/printk.c +7 -0
+static struct attribute *console_sysfs_attrs[] = {
+	&dev_attr_loglevel.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(console_sysfs);
+
 static struct bus_type console_subsys = {
 	.name = "console",
+	.dev_groups = console_sysfs_groups,
 };

Do we really need to change this dynamically? Console options are traditionally static (boot param or DT). Can we also be happy with the static per-console loglevel?

	-ss
#21 lore raw

Re: [PATCH 4/4] printk: Add a device attribute for the per-console loglevel

Quoted 15 lines · Sergey Senozhatsky

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2605

Quoted 10 lines · Calvin Owens
kernel/printk/printk.c +7 -0
+static struct attribute *console_sysfs_attrs[] = {
+	&dev_attr_loglevel.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(console_sysfs);
+
 static struct bus_type console_subsys = {
 	.name = "console",
+	.dev_groups = console_sysfs_groups,
 };

Do we really need to change this dynamically? Console options are traditionally static (boot param or DT). Can we also be happy with the static per-console loglevel?

It really does need to be runtime configurable: there are a lot of usecases that enables, like turning the fast console up to KERN_DEBUG on a pile of machines you want to take a closer look at. The 'kernel.printk' global loglevel is also already changable at runtime, and since that setting interacts with this one it would be strange if only the former were able to be changed.

I also want to add more attribute knobs related to extended consoles, so the plumbing to get things exposed in sysfs is worth it for me.

Thanks,
Calvin

#22 lore raw

Re: [PATCH 4/4] printk: Add a device attribute for the per-console loglevel

Quoted 17 lines · Calvin Owens
Quoted 15 lines · Sergey Senozhatsky

kernel/printk/printk.c static int __init keep_bootcon_setup(char *str) · line 2605

Quoted 10 lines · Calvin Owens
kernel/printk/printk.c +7 -0
+static struct attribute *console_sysfs_attrs[] = {
+	&dev_attr_loglevel.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(console_sysfs);
+
 static struct bus_type console_subsys = {
 	.name = "console",
+	.dev_groups = console_sysfs_groups,
 };

Do we really need to change this dynamically? Console options are traditionally static (boot param or DT). Can we also be happy with the static per-console loglevel?

Quoted 6 lines

It really does need to be runtime configurable: there are a lot of usecases that enables, like turning the fast console up to KERN_DEBUG on a pile of machines you want to take a closer look at. The 'kernel.printk' global loglevel is also already changable at runtime, and since that setting interacts with this one it would be strange if only the former were able to be changed.

Fair enough.

	-ss