aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk.c
diff options
context:
space:
mode:
authorRobin Getz <rgetz@blackfin.uclinux.org>2009-07-01 21:08:37 -0400
committerIngo Molnar <mingo@elte.hu>2009-07-03 04:10:43 -0400
commit4d09161196c9a836eacea4b36e2f217bc34894cf (patch)
treed6ca11be7c741a4380f383bea4dc6c36a9587f77 /kernel/printk.c
parent7c5371c403abb29f01bc6cff6c5096abdf2dc524 (diff)
printk: Enable the use of more than one CON_BOOT (early console)
Today, register_console() assumes the following usage: - The first console to register with a flag set to CON_BOOT is the one and only bootconsole. - If another register_console() is called with an additional CON_BOOT, it is silently rejected. - As soon as a console without the CON_BOOT set calls registers the bootconsole is automatically unregistered. - Once there is a "real" console - register_console() will silently reject any consoles with it's CON_BOOT flag set. In many systems (alpha, blackfin, microblaze, mips, powerpc, sh, & x86), there are early_printk implementations, which use the CON_BOOT which come out serial ports, vga, usb, & memory buffers. In many embedded systems, it would be nice to have two bootconsoles - in case the primary fails, you always have access to a backup memory buffer - but this requires at least two CON_BOOT consoles... This patch enables that functionality. With the change applied, on boot you get (if you try to re-enable a boot console after the "real" console has been registered): root:/> dmesg | grep console bootconsole [early_shadow0] enabled bootconsole [early_BFuart0] enabled Kernel command line: root=/dev/mtdblock0 rw earlyprintk=serial,uart0,57600 console=ttyBF0,57600 nmi_debug=regs console handover:boot [early_BFuart0] boot [early_shadow0] -> real [ttyBF0] Too late to register bootconsole early_shadow0 or: root:/> dmesg | grep console Kernel command line: root=/dev/mtdblock0 rw console=ttyBF0,57600 console [ttyBF0] enabled Signed-off-by: Robin Getz <rgetz@blackfin.uclinux.org> Cc: "Linus Torvalds" <torvalds@linux-foundation.org> Cc: "Andrew Morton" <akpm@linux-foundation.org> Cc: "Mike Frysinger" <vapier.adi@gmail.com> Cc: "Paul Mundt" <lethal@linux-sh.org> LKML-Reference: <200907012108.38030.rgetz@blackfin.uclinux.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r--kernel/printk.c146
1 files changed, 92 insertions, 54 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index b4d97b54c1e..41fe6099553 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -37,6 +37,12 @@
37#include <asm/uaccess.h> 37#include <asm/uaccess.h>
38 38
39/* 39/*
40 * for_each_console() allows you to iterate on each console
41 */
42#define for_each_console(con) \
43 for (con = console_drivers; con != NULL; con = con->next)
44
45/*
40 * Architectures can override it: 46 * Architectures can override it:
41 */ 47 */
42void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) 48void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
@@ -412,7 +418,7 @@ static void __call_console_drivers(unsigned start, unsigned end)
412{ 418{
413 struct console *con; 419 struct console *con;
414 420
415 for (con = console_drivers; con; con = con->next) { 421 for_each_console(con) {
416 if ((con->flags & CON_ENABLED) && con->write && 422 if ((con->flags & CON_ENABLED) && con->write &&
417 (cpu_online(smp_processor_id()) || 423 (cpu_online(smp_processor_id()) ||
418 (con->flags & CON_ANYTIME))) 424 (con->flags & CON_ANYTIME)))
@@ -544,7 +550,7 @@ static int have_callable_console(void)
544{ 550{
545 struct console *con; 551 struct console *con;
546 552
547 for (con = console_drivers; con; con = con->next) 553 for_each_console(con)
548 if (con->flags & CON_ANYTIME) 554 if (con->flags & CON_ANYTIME)
549 return 1; 555 return 1;
550 556
@@ -1082,7 +1088,7 @@ void console_unblank(void)
1082 1088
1083 console_locked = 1; 1089 console_locked = 1;
1084 console_may_schedule = 0; 1090 console_may_schedule = 0;
1085 for (c = console_drivers; c != NULL; c = c->next) 1091 for_each_console(c)
1086 if ((c->flags & CON_ENABLED) && c->unblank) 1092 if ((c->flags & CON_ENABLED) && c->unblank)
1087 c->unblank(); 1093 c->unblank();
1088 release_console_sem(); 1094 release_console_sem();
@@ -1097,7 +1103,7 @@ struct tty_driver *console_device(int *index)
1097 struct tty_driver *driver = NULL; 1103 struct tty_driver *driver = NULL;
1098 1104
1099 acquire_console_sem(); 1105 acquire_console_sem();
1100 for (c = console_drivers; c != NULL; c = c->next) { 1106 for_each_console(c) {
1101 if (!c->device) 1107 if (!c->device)
1102 continue; 1108 continue;
1103 driver = c->device(c, index); 1109 driver = c->device(c, index);
@@ -1134,25 +1140,49 @@ EXPORT_SYMBOL(console_start);
1134 * to register the console printing procedure with printk() and to 1140 * to register the console printing procedure with printk() and to
1135 * print any messages that were printed by the kernel before the 1141 * print any messages that were printed by the kernel before the
1136 * console driver was initialized. 1142 * console driver was initialized.
1143 *
1144 * This can happen pretty early during the boot process (because of
1145 * early_printk) - sometimes before setup_arch() completes - be careful
1146 * of what kernel features are used - they may not be initialised yet.
1147 *
1148 * There are two types of consoles - bootconsoles (early_printk) and
1149 * "real" consoles (everything which is not a bootconsole) which are
1150 * handled differently.
1151 * - Any number of bootconsoles can be registered at any time.
1152 * - As soon as a "real" console is registered, all bootconsoles
1153 * will be unregistered automatically.
1154 * - Once a "real" console is registered, any attempt to register a
1155 * bootconsoles will be rejected
1137 */ 1156 */
1138void register_console(struct console *console) 1157void register_console(struct console *newcon)
1139{ 1158{
1140 int i; 1159 int i;
1141 unsigned long flags; 1160 unsigned long flags;
1142 struct console *bootconsole = NULL; 1161 struct console *bcon = NULL;
1143 1162
1144 if (console_drivers) { 1163 /*
1145 if (console->flags & CON_BOOT) 1164 * before we register a new CON_BOOT console, make sure we don't
1146 return; 1165 * already have a valid console
1147 if (console_drivers->flags & CON_BOOT) 1166 */
1148 bootconsole = console_drivers; 1167 if (console_drivers && newcon->flags & CON_BOOT) {
1168 /* find the last or real console */
1169 for_each_console(bcon) {
1170 if (!(bcon->flags & CON_BOOT)) {
1171 printk(KERN_INFO "Too late to register bootconsole %s%d\n",
1172 newcon->name, newcon->index);
1173 return;
1174 }
1175 }
1149 } 1176 }
1150 1177
1151 if (preferred_console < 0 || bootconsole || !console_drivers) 1178 if (console_drivers && console_drivers->flags & CON_BOOT)
1179 bcon = console_drivers;
1180
1181 if (preferred_console < 0 || bcon || !console_drivers)
1152 preferred_console = selected_console; 1182 preferred_console = selected_console;
1153 1183
1154 if (console->early_setup) 1184 if (newcon->early_setup)
1155 console->early_setup(); 1185 newcon->early_setup();
1156 1186
1157 /* 1187 /*
1158 * See if we want to use this console driver. If we 1188 * See if we want to use this console driver. If we
@@ -1160,13 +1190,13 @@ void register_console(struct console *console)
1160 * that registers here. 1190 * that registers here.
1161 */ 1191 */
1162 if (preferred_console < 0) { 1192 if (preferred_console < 0) {
1163 if (console->index < 0) 1193 if (newcon->index < 0)
1164 console->index = 0; 1194 newcon->index = 0;
1165 if (console->setup == NULL || 1195 if (newcon->setup == NULL ||
1166 console->setup(console, NULL) == 0) { 1196 newcon->setup(newcon, NULL) == 0) {
1167 console->flags |= CON_ENABLED; 1197 newcon->flags |= CON_ENABLED;
1168 if (console->device) { 1198 if (newcon->device) {
1169 console->flags |= CON_CONSDEV; 1199 newcon->flags |= CON_CONSDEV;
1170 preferred_console = 0; 1200 preferred_console = 0;
1171 } 1201 }
1172 } 1202 }
@@ -1178,47 +1208,53 @@ void register_console(struct console *console)
1178 */ 1208 */
1179 for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; 1209 for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
1180 i++) { 1210 i++) {
1181 if (strcmp(console_cmdline[i].name, console->name) != 0) 1211 if (strcmp(console_cmdline[i].name, newcon->name) != 0)
1182 continue; 1212 continue;
1183 if (console->index >= 0 && 1213 if (newcon->index >= 0 &&
1184 console->index != console_cmdline[i].index) 1214 newcon->index != console_cmdline[i].index)
1185 continue; 1215 continue;
1186 if (console->index < 0) 1216 if (newcon->index < 0)
1187 console->index = console_cmdline[i].index; 1217 newcon->index = console_cmdline[i].index;
1188#ifdef CONFIG_A11Y_BRAILLE_CONSOLE 1218#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
1189 if (console_cmdline[i].brl_options) { 1219 if (console_cmdline[i].brl_options) {
1190 console->flags |= CON_BRL; 1220 newcon->flags |= CON_BRL;
1191 braille_register_console(console, 1221 braille_register_console(newcon,
1192 console_cmdline[i].index, 1222 console_cmdline[i].index,
1193 console_cmdline[i].options, 1223 console_cmdline[i].options,
1194 console_cmdline[i].brl_options); 1224 console_cmdline[i].brl_options);
1195 return; 1225 return;
1196 } 1226 }
1197#endif 1227#endif
1198 if (console->setup && 1228 if (newcon->setup &&
1199 console->setup(console, console_cmdline[i].options) != 0) 1229 newcon->setup(newcon, console_cmdline[i].options) != 0)
1200 break; 1230 break;
1201 console->flags |= CON_ENABLED; 1231 newcon->flags |= CON_ENABLED;
1202 console->index = console_cmdline[i].index; 1232 newcon->index = console_cmdline[i].index;
1203 if (i == selected_console) { 1233 if (i == selected_console) {
1204 console->flags |= CON_CONSDEV; 1234 newcon->flags |= CON_CONSDEV;
1205 preferred_console = selected_console; 1235 preferred_console = selected_console;
1206 } 1236 }
1207 break; 1237 break;
1208 } 1238 }
1209 1239
1210 if (!(console->flags & CON_ENABLED)) 1240 if (!(newcon->flags & CON_ENABLED))
1211 return; 1241 return;
1212 1242
1213 if (bootconsole && (console->flags & CON_CONSDEV)) { 1243 if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
1214 printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", 1244 /* we need to iterate through twice, to make sure we print
1215 bootconsole->name, bootconsole->index, 1245 * everything out, before we unregister the console(s)
1216 console->name, console->index); 1246 */
1217 unregister_console(bootconsole); 1247 printk(KERN_INFO "console handover:");
1218 console->flags &= ~CON_PRINTBUFFER; 1248 for_each_console(bcon)
1249 printk("boot [%s%d] ", bcon->name, bcon->index);
1250 printk(" -> real [%s%d]\n", newcon->name, newcon->index);
1251 for_each_console(bcon)
1252 unregister_console(bcon);
1253 newcon->flags &= ~CON_PRINTBUFFER;
1219 } else { 1254 } else {
1220 printk(KERN_INFO "console [%s%d] enabled\n", 1255 printk(KERN_INFO "%sconsole [%s%d] enabled\n",
1221 console->name, console->index); 1256 (newcon->flags & CON_BOOT) ? "boot" : "" ,
1257 newcon->name, newcon->index);
1222 } 1258 }
1223 1259
1224 /* 1260 /*
@@ -1226,16 +1262,16 @@ void register_console(struct console *console)
1226 * preferred driver at the head of the list. 1262 * preferred driver at the head of the list.
1227 */ 1263 */
1228 acquire_console_sem(); 1264 acquire_console_sem();
1229 if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { 1265 if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
1230 console->next = console_drivers; 1266 newcon->next = console_drivers;
1231 console_drivers = console; 1267 console_drivers = newcon;
1232 if (console->next) 1268 if (newcon->next)
1233 console->next->flags &= ~CON_CONSDEV; 1269 newcon->next->flags &= ~CON_CONSDEV;
1234 } else { 1270 } else {
1235 console->next = console_drivers->next; 1271 newcon->next = console_drivers->next;
1236 console_drivers->next = console; 1272 console_drivers->next = newcon;
1237 } 1273 }
1238 if (console->flags & CON_PRINTBUFFER) { 1274 if (newcon->flags & CON_PRINTBUFFER) {
1239 /* 1275 /*
1240 * release_console_sem() will print out the buffered messages 1276 * release_console_sem() will print out the buffered messages
1241 * for us. 1277 * for us.
@@ -1287,11 +1323,13 @@ EXPORT_SYMBOL(unregister_console);
1287 1323
1288static int __init disable_boot_consoles(void) 1324static int __init disable_boot_consoles(void)
1289{ 1325{
1290 if (console_drivers != NULL) { 1326 struct console *con;
1291 if (console_drivers->flags & CON_BOOT) { 1327
1328 for_each_console(con) {
1329 if (con->flags & CON_BOOT) {
1292 printk(KERN_INFO "turn off boot console %s%d\n", 1330 printk(KERN_INFO "turn off boot console %s%d\n",
1293 console_drivers->name, console_drivers->index); 1331 con->name, con->index);
1294 return unregister_console(console_drivers); 1332 return unregister_console(con);
1295 } 1333 }
1296 } 1334 }
1297 return 0; 1335 return 0;