aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-20 19:59:26 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-20 19:59:26 -0400
commitc73fcc846c91f53fd2c67fd9c6c04888a9e5892e (patch)
tree31faa68b4176636756926535a0f50ff780973275 /arch/sparc/kernel
parentede13d81b4dda409a6d271b34b8e2ec9383e255d (diff)
[SPARC]: Fix serial console device detection.
The current scheme works on static interpretation of text names, which is wrong. The output-device setting, for example, must be resolved via an alias or similar to a full path name to the console device. Paths also contain an optional set of 'options', which starts with a colon at the end of the path. The option area is used to specify which of two serial ports ('a' or 'b') the path refers to when a device node drives multiple ports. 'a' is assumed if the option specification is missing. This was caught by the UltraSPARC-T1 simulator. The 'output-device' property was set to 'ttya' and we didn't pick upon the fact that this is an OBP alias set to '/virtual-devices/console'. Instead we saw it as the first serial console device, instead of the hypervisor console. The infrastructure is now there to take advantage of this to resolve the console correctly even in multi-head situations in fbcon too. Thanks to Greg Onufer for the bug report. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/process.c8
-rw-r--r--arch/sparc/kernel/prom.c131
-rw-r--r--arch/sparc/kernel/setup.c65
3 files changed, 137 insertions, 67 deletions
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 8c37f8f5adb7..33f7a3ddb104 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -39,6 +39,7 @@
39#include <asm/processor.h> 39#include <asm/processor.h>
40#include <asm/psr.h> 40#include <asm/psr.h>
41#include <asm/elf.h> 41#include <asm/elf.h>
42#include <asm/prom.h>
42#include <asm/unistd.h> 43#include <asm/unistd.h>
43 44
44/* 45/*
@@ -150,7 +151,7 @@ void machine_halt(void)
150 local_irq_enable(); 151 local_irq_enable();
151 mdelay(8); 152 mdelay(8);
152 local_irq_disable(); 153 local_irq_disable();
153 if (!serial_console && prom_palette) 154 if (prom_palette)
154 prom_palette (1); 155 prom_palette (1);
155 prom_halt(); 156 prom_halt();
156 panic("Halt failed!"); 157 panic("Halt failed!");
@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
166 167
167 p = strchr (reboot_command, '\n'); 168 p = strchr (reboot_command, '\n');
168 if (p) *p = 0; 169 if (p) *p = 0;
169 if (!serial_console && prom_palette) 170 if (prom_palette)
170 prom_palette (1); 171 prom_palette (1);
171 if (cmd) 172 if (cmd)
172 prom_reboot(cmd); 173 prom_reboot(cmd);
@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
179void machine_power_off(void) 180void machine_power_off(void)
180{ 181{
181#ifdef CONFIG_SUN_AUXIO 182#ifdef CONFIG_SUN_AUXIO
182 if (auxio_power_register && (!serial_console || scons_pwroff)) 183 if (auxio_power_register &&
184 (strcmp(of_console_device->type, "serial") || scons_pwroff))
183 *auxio_power_register |= AUXIO_POWER_OFF; 185 *auxio_power_register |= AUXIO_POWER_OFF;
184#endif 186#endif
185 machine_halt(); 187 machine_halt();
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 012f98346bcd..e3a537650db1 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -397,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
397 return dp; 397 return dp;
398} 398}
399 399
400struct device_node *of_console_device;
401EXPORT_SYMBOL(of_console_device);
402
403char *of_console_path;
404EXPORT_SYMBOL(of_console_path);
405
406char *of_console_options;
407EXPORT_SYMBOL(of_console_options);
408
409extern void restore_current(void);
410
411static void __init of_console_init(void)
412{
413 char *msg = "OF stdout device is: %s\n";
414 struct device_node *dp;
415 unsigned long flags;
416 const char *type;
417 phandle node;
418 int skip, fd;
419
420 of_console_path = prom_early_alloc(256);
421
422 switch (prom_vers) {
423 case PROM_V0:
424 case PROM_SUN4:
425 skip = 0;
426 switch (*romvec->pv_stdout) {
427 case PROMDEV_SCREEN:
428 type = "display";
429 break;
430
431 case PROMDEV_TTYB:
432 skip = 1;
433 /* FALLTHRU */
434
435 case PROMDEV_TTYA:
436 type = "serial";
437 break;
438
439 default:
440 prom_printf("Invalid PROM_V0 stdout value %u\n",
441 *romvec->pv_stdout);
442 prom_halt();
443 }
444
445 for_each_node_by_type(dp, type) {
446 if (!skip--)
447 break;
448 }
449 if (!dp) {
450 prom_printf("Cannot find PROM_V0 console node.\n");
451 prom_halt();
452 }
453 of_console_device = dp;
454
455 strcpy(of_console_path, dp->full_name);
456 if (!strcmp(type, "serial")) {
457 strcat(of_console_path,
458 (skip ? ":b" : ":a"));
459 }
460 break;
461
462 default:
463 case PROM_V2:
464 case PROM_V3:
465 fd = *romvec->pv_v2bootargs.fd_stdout;
466
467 spin_lock_irqsave(&prom_lock, flags);
468 node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
469 restore_current();
470 spin_unlock_irqrestore(&prom_lock, flags);
471
472 if (!node) {
473 prom_printf("Cannot resolve stdout node from "
474 "instance %08x.\n", fd);
475 prom_halt();
476 }
477 dp = of_find_node_by_phandle(node);
478 type = of_get_property(dp, "device_type", NULL);
479
480 if (!type) {
481 prom_printf("Console stdout lacks "
482 "device_type property.\n");
483 prom_halt();
484 }
485
486 if (strcmp(type, "display") && strcmp(type, "serial")) {
487 prom_printf("Console device_type is neither display "
488 "nor serial.\n");
489 prom_halt();
490 }
491
492 of_console_device = dp;
493
494 if (prom_vers == PROM_V2) {
495 strcpy(of_console_path, dp->full_name);
496 switch (*romvec->pv_stdout) {
497 case PROMDEV_TTYA:
498 strcat(of_console_path, ":a");
499 break;
500 case PROMDEV_TTYB:
501 strcat(of_console_path, ":b");
502 break;
503 }
504 } else {
505 const char *path;
506
507 dp = of_find_node_by_path("/");
508 path = of_get_property(dp, "stdout-path", NULL);
509 if (!path) {
510 prom_printf("No stdout-path in root node.\n");
511 prom_halt();
512 }
513 strcpy(of_console_path, path);
514 }
515 break;
516 }
517
518 of_console_options = strrchr(of_console_path, ':');
519 if (of_console_options) {
520 of_console_options++;
521 if (*of_console_options == '\0')
522 of_console_options = NULL;
523 }
524
525 prom_printf(msg, of_console_path);
526 printk(msg, of_console_path);
527}
528
400void __init prom_build_devicetree(void) 529void __init prom_build_devicetree(void)
401{ 530{
402 struct device_node **nextp; 531 struct device_node **nextp;
@@ -409,6 +538,8 @@ void __init prom_build_devicetree(void)
409 allnodes->child = build_tree(allnodes, 538 allnodes->child = build_tree(allnodes,
410 prom_getchild(allnodes->node), 539 prom_getchild(allnodes->node),
411 &nextp); 540 &nextp);
541 of_console_init();
542
412 printk("PROM: Built device tree with %u bytes of memory.\n", 543 printk("PROM: Built device tree with %u bytes of memory.\n",
413 prom_early_allocated); 544 prom_early_allocated);
414} 545}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 64c0ed98820a..f8228383895a 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -146,31 +146,6 @@ static void __init process_switch(char c)
146 } 146 }
147} 147}
148 148
149static void __init process_console(char *commands)
150{
151 serial_console = 0;
152 commands += 8;
153 /* Linux-style serial */
154 if (!strncmp(commands, "ttyS", 4))
155 serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
156 else if (!strncmp(commands, "tty", 3)) {
157 char c = *(commands + 3);
158 /* Solaris-style serial */
159 if (c == 'a' || c == 'b')
160 serial_console = c - 'a' + 1;
161 /* else Linux-style fbcon, not serial */
162 }
163#if defined(CONFIG_PROM_CONSOLE)
164 if (!strncmp(commands, "prom", 4)) {
165 char *p;
166
167 for (p = commands - 8; *p && *p != ' '; p++)
168 *p = ' ';
169 conswitchp = &prom_con;
170 }
171#endif
172}
173
174static void __init boot_flags_init(char *commands) 149static void __init boot_flags_init(char *commands)
175{ 150{
176 while (*commands) { 151 while (*commands) {
@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands)
187 process_switch(*commands++); 162 process_switch(*commands++);
188 continue; 163 continue;
189 } 164 }
190 if (!strncmp(commands, "console=", 8)) { 165 if (!strncmp(commands, "mem=", 4)) {
191 process_console(commands);
192 } else if (!strncmp(commands, "mem=", 4)) {
193 /* 166 /*
194 * "mem=XXX[kKmM] overrides the PROM-reported 167 * "mem=XXX[kKmM] overrides the PROM-reported
195 * memory size. 168 * memory size.
@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
341 smp_setup_cpu_possible_map(); 314 smp_setup_cpu_possible_map();
342} 315}
343 316
344static int __init set_preferred_console(void)
345{
346 int idev, odev;
347
348 /* The user has requested a console so this is already set up. */
349 if (serial_console >= 0)
350 return -EBUSY;
351
352 idev = prom_query_input_device();
353 odev = prom_query_output_device();
354 if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
355 serial_console = 0;
356 } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
357 serial_console = 1;
358 } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
359 serial_console = 2;
360 } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
361 prom_printf("MrCoffee ttya\n");
362 serial_console = 1;
363 } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
364 serial_console = 0;
365 prom_printf("MrCoffee keyboard\n");
366 } else {
367 prom_printf("Confusing console (idev %d, odev %d)\n",
368 idev, odev);
369 serial_console = 1;
370 }
371
372 if (serial_console)
373 return add_preferred_console("ttyS", serial_console - 1, NULL);
374
375 return -ENODEV;
376}
377console_initcall(set_preferred_console);
378
379extern char *sparc_cpu_type; 317extern char *sparc_cpu_type;
380extern char *sparc_fpu_type; 318extern char *sparc_fpu_type;
381 319
@@ -461,7 +399,6 @@ void sun_do_break(void)
461 prom_cmdline(); 399 prom_cmdline();
462} 400}
463 401
464int serial_console = -1;
465int stop_a_enabled = 1; 402int stop_a_enabled = 1;
466 403
467static int __init topology_init(void) 404static int __init topology_init(void)