diff options
author | Robin Getz <rgetz@blackfin.uclinux.org> | 2009-07-01 21:08:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-07-03 04:10:43 -0400 |
commit | 4d09161196c9a836eacea4b36e2f217bc34894cf (patch) | |
tree | d6ca11be7c741a4380f383bea4dc6c36a9587f77 /kernel/printk.c | |
parent | 7c5371c403abb29f01bc6cff6c5096abdf2dc524 (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.c | 146 |
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 | */ |
42 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | 48 | void 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 | */ |
1138 | void register_console(struct console *console) | 1157 | void 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 | ||
1288 | static int __init disable_boot_consoles(void) | 1324 | static 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; |