aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
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/sparc64
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/sparc64')
-rw-r--r--arch/sparc64/kernel/power.c2
-rw-r--r--arch/sparc64/kernel/process.c6
-rw-r--r--arch/sparc64/kernel/prom.c56
-rw-r--r--arch/sparc64/kernel/setup.c70
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c1
-rw-r--r--arch/sparc64/prom/console.c85
-rw-r--r--arch/sparc64/prom/misc.c4
-rw-r--r--arch/sparc64/prom/tree.c8
8 files changed, 71 insertions, 161 deletions
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index b00feb01c16f..881a09ee4c4c 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -46,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
46void machine_power_off(void) 46void machine_power_off(void)
47{ 47{
48 sstate_poweroff(); 48 sstate_poweroff();
49 if (!serial_console || scons_pwroff) { 49 if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
50 if (power_reg) { 50 if (power_reg) {
51 /* Both register bits seem to have the 51 /* Both register bits seem to have the
52 * same effect, so until I figure out 52 * same effect, so until I figure out
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 93557507ec9f..fd7899ba1d70 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void);
119void machine_halt(void) 119void machine_halt(void)
120{ 120{
121 sstate_halt(); 121 sstate_halt();
122 if (!serial_console && prom_palette) 122 if (prom_palette)
123 prom_palette (1); 123 prom_palette (1);
124 if (prom_keyboard) 124 if (prom_keyboard)
125 prom_keyboard(); 125 prom_keyboard();
@@ -130,7 +130,7 @@ void machine_halt(void)
130void machine_alt_power_off(void) 130void machine_alt_power_off(void)
131{ 131{
132 sstate_poweroff(); 132 sstate_poweroff();
133 if (!serial_console && prom_palette) 133 if (prom_palette)
134 prom_palette(1); 134 prom_palette(1);
135 if (prom_keyboard) 135 if (prom_keyboard)
136 prom_keyboard(); 136 prom_keyboard();
@@ -145,7 +145,7 @@ void machine_restart(char * cmd)
145 sstate_reboot(); 145 sstate_reboot();
146 p = strchr (reboot_command, '\n'); 146 p = strchr (reboot_command, '\n');
147 if (p) *p = 0; 147 if (p) *p = 0;
148 if (!serial_console && prom_palette) 148 if (prom_palette)
149 prom_palette (1); 149 prom_palette (1);
150 if (prom_keyboard) 150 if (prom_keyboard)
151 prom_keyboard(); 151 prom_keyboard();
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 2b2017ce2267..f4e0a9ad9be3 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1646,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void)
1646 smp_fill_in_sib_core_maps(); 1646 smp_fill_in_sib_core_maps();
1647} 1647}
1648 1648
1649struct device_node *of_console_device;
1650EXPORT_SYMBOL(of_console_device);
1651
1652char *of_console_path;
1653EXPORT_SYMBOL(of_console_path);
1654
1655char *of_console_options;
1656EXPORT_SYMBOL(of_console_options);
1657
1658static void __init of_console_init(void)
1659{
1660 char *msg = "OF stdout device is: %s\n";
1661 struct device_node *dp;
1662 const char *type;
1663 phandle node;
1664
1665 of_console_path = prom_early_alloc(256);
1666 if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
1667 prom_printf("Cannot obtain path of stdout.\n");
1668 prom_halt();
1669 }
1670 of_console_options = strrchr(of_console_path, ':');
1671 if (of_console_options) {
1672 of_console_options++;
1673 if (*of_console_options == '\0')
1674 of_console_options = NULL;
1675 }
1676
1677 node = prom_inst2pkg(prom_stdout);
1678 if (!node) {
1679 prom_printf("Cannot resolve stdout node from "
1680 "instance %08x.\n", prom_stdout);
1681 prom_halt();
1682 }
1683
1684 dp = of_find_node_by_phandle(node);
1685 type = of_get_property(dp, "device_type", NULL);
1686 if (!type) {
1687 prom_printf("Console stdout lacks device_type property.\n");
1688 prom_halt();
1689 }
1690
1691 if (strcmp(type, "display") && strcmp(type, "serial")) {
1692 prom_printf("Console device_type is neither display "
1693 "nor serial.\n");
1694 prom_halt();
1695 }
1696
1697 of_console_device = dp;
1698
1699 prom_printf(msg, of_console_path);
1700 printk(msg, of_console_path);
1701}
1702
1649void __init prom_build_devicetree(void) 1703void __init prom_build_devicetree(void)
1650{ 1704{
1651 struct device_node **nextp; 1705 struct device_node **nextp;
@@ -1658,6 +1712,8 @@ void __init prom_build_devicetree(void)
1658 allnodes->child = build_tree(allnodes, 1712 allnodes->child = build_tree(allnodes,
1659 prom_getchild(allnodes->node), 1713 prom_getchild(allnodes->node),
1660 &nextp); 1714 &nextp);
1715 of_console_init();
1716
1661 printk("PROM: Built device tree with %u bytes of memory.\n", 1717 printk("PROM: Built device tree with %u bytes of memory.\n",
1662 prom_early_allocated); 1718 prom_early_allocated);
1663 1719
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index aafde3dd9fd4..0f5be828ee92 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -133,33 +133,6 @@ static void __init process_switch(char c)
133 } 133 }
134} 134}
135 135
136static void __init process_console(char *commands)
137{
138 serial_console = 0;
139 commands += 8;
140 /* Linux-style serial */
141 if (!strncmp(commands, "ttyS", 4))
142 serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
143 else if (!strncmp(commands, "tty", 3)) {
144 char c = *(commands + 3);
145 /* Solaris-style serial */
146 if (c == 'a' || c == 'b') {
147 serial_console = c - 'a' + 1;
148 prom_printf ("Using /dev/tty%c as console.\n", c);
149 }
150 /* else Linux-style fbcon, not serial */
151 }
152#if defined(CONFIG_PROM_CONSOLE)
153 if (!strncmp(commands, "prom", 4)) {
154 char *p;
155
156 for (p = commands - 8; *p && *p != ' '; p++)
157 *p = ' ';
158 conswitchp = &prom_con;
159 }
160#endif
161}
162
163static void __init boot_flags_init(char *commands) 136static void __init boot_flags_init(char *commands)
164{ 137{
165 while (*commands) { 138 while (*commands) {
@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
176 process_switch(*commands++); 149 process_switch(*commands++);
177 continue; 150 continue;
178 } 151 }
179 if (!strncmp(commands, "console=", 8)) { 152 if (!strncmp(commands, "mem=", 4)) {
180 process_console(commands);
181 } else if (!strncmp(commands, "mem=", 4)) {
182 /* 153 /*
183 * "mem=XXX[kKmM]" overrides the PROM-reported 154 * "mem=XXX[kKmM]" overrides the PROM-reported
184 * memory size. 155 * memory size.
@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
378 paging_init(); 349 paging_init();
379} 350}
380 351
381static int __init set_preferred_console(void)
382{
383 int idev, odev;
384
385 /* The user has requested a console so this is already set up. */
386 if (serial_console >= 0)
387 return -EBUSY;
388
389 idev = prom_query_input_device();
390 odev = prom_query_output_device();
391 if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
392 serial_console = 0;
393 } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
394 serial_console = 1;
395 } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
396 serial_console = 2;
397 } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
398 serial_console = 3;
399 } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
400 /* sunhv_console_init() doesn't check the serial_console
401 * value anyways...
402 */
403 serial_console = 4;
404 return add_preferred_console("ttyHV", 0, NULL);
405 } else {
406 prom_printf("Inconsistent console: "
407 "input %d, output %d\n",
408 idev, odev);
409 prom_halt();
410 }
411
412 if (serial_console)
413 return add_preferred_console("ttyS", serial_console - 1, NULL);
414
415 return -ENODEV;
416}
417console_initcall(set_preferred_console);
418
419/* BUFFER is PAGE_SIZE bytes long. */ 352/* BUFFER is PAGE_SIZE bytes long. */
420 353
421extern char *sparc_cpu_type; 354extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@ void sun_do_break(void)
508 prom_cmdline(); 441 prom_cmdline();
509} 442}
510 443
511int serial_console = -1;
512int stop_a_enabled = 1; 444int stop_a_enabled = 1;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 719d676c2ddc..7d36531aa5b9 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -330,7 +330,6 @@ EXPORT_SYMBOL(VISenter);
330 330
331/* for input/keybdev */ 331/* for input/keybdev */
332EXPORT_SYMBOL(sun_do_break); 332EXPORT_SYMBOL(sun_do_break);
333EXPORT_SYMBOL(serial_console);
334EXPORT_SYMBOL(stop_a_enabled); 333EXPORT_SYMBOL(stop_a_enabled);
335 334
336#ifdef CONFIG_DEBUG_BUGVERBOSE 335#ifdef CONFIG_DEBUG_BUGVERBOSE
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 7c25c54cefdc..3fafa9a8b50b 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
73 P1275_INOUT(3,1), 73 P1275_INOUT(3,1),
74 prom_stdout, s, P1275_SIZE(len)); 74 prom_stdout, s, P1275_SIZE(len));
75} 75}
76
77/* Query for input device type */
78enum prom_input_device
79prom_query_input_device(void)
80{
81 int st_p;
82 char propb[64];
83
84 st_p = prom_inst2pkg(prom_stdin);
85 if(prom_node_has_property(st_p, "keyboard"))
86 return PROMDEV_IKBD;
87 prom_getproperty(st_p, "device_type", propb, sizeof(propb));
88 if(strncmp(propb, "serial", 6))
89 return PROMDEV_I_UNK;
90 /* FIXME: Is there any better way how to find out? */
91 memset(propb, 0, sizeof(propb));
92 st_p = prom_finddevice ("/options");
93 prom_getproperty(st_p, "input-device", propb, sizeof(propb));
94
95 /*
96 * If we get here with propb == 'keyboard', we are on ttya, as
97 * the PROM defaulted to this due to 'no input device'.
98 */
99 if (!strncmp(propb, "keyboard", 8))
100 return PROMDEV_ITTYA;
101
102 if (!strncmp (propb, "rsc", 3))
103 return PROMDEV_IRSC;
104
105 if (!strncmp (propb, "virtual-console", 3))
106 return PROMDEV_IVCONS;
107
108 if (strncmp (propb, "tty", 3) || !propb[3])
109 return PROMDEV_I_UNK;
110
111 switch (propb[3]) {
112 case 'a': return PROMDEV_ITTYA;
113 case 'b': return PROMDEV_ITTYB;
114 default: return PROMDEV_I_UNK;
115 }
116}
117
118/* Query for output device type */
119
120enum prom_output_device
121prom_query_output_device(void)
122{
123 int st_p;
124 char propb[64];
125 int propl;
126
127 st_p = prom_inst2pkg(prom_stdout);
128 propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
129 if (propl >= 0 && propl == sizeof("display") &&
130 strncmp("display", propb, sizeof("display")) == 0)
131 return PROMDEV_OSCREEN;
132 if(strncmp("serial", propb, 6))
133 return PROMDEV_O_UNK;
134 /* FIXME: Is there any better way how to find out? */
135 memset(propb, 0, sizeof(propb));
136 st_p = prom_finddevice ("/options");
137 prom_getproperty(st_p, "output-device", propb, sizeof(propb));
138
139 /*
140 * If we get here with propb == 'screen', we are on ttya, as
141 * the PROM defaulted to this due to 'no input device'.
142 */
143 if (!strncmp(propb, "screen", 6))
144 return PROMDEV_OTTYA;
145
146 if (!strncmp (propb, "rsc", 3))
147 return PROMDEV_ORSC;
148
149 if (!strncmp (propb, "virtual-console", 3))
150 return PROMDEV_OVCONS;
151
152 if (strncmp (propb, "tty", 3) || !propb[3])
153 return PROMDEV_O_UNK;
154
155 switch (propb[3]) {
156 case 'a': return PROMDEV_OTTYA;
157 case 'b': return PROMDEV_OTTYB;
158 default: return PROMDEV_O_UNK;
159 }
160}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 33c5b7da31e5..68c83ad04ad9 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -72,7 +72,7 @@ void prom_cmdline(void)
72 72
73 local_irq_save(flags); 73 local_irq_save(flags);
74 74
75 if (!serial_console && prom_palette) 75 if (prom_palette)
76 prom_palette(1); 76 prom_palette(1);
77 77
78#ifdef CONFIG_SMP 78#ifdef CONFIG_SMP
@@ -85,7 +85,7 @@ void prom_cmdline(void)
85 smp_release(); 85 smp_release();
86#endif 86#endif
87 87
88 if (!serial_console && prom_palette) 88 if (prom_palette)
89 prom_palette(0); 89 prom_palette(0);
90 90
91 local_irq_restore(flags); 91 local_irq_restore(flags);
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index 17b7ecfe7ca9..b2c5b12c9818 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path)
304 if (node == -1) return 0; 304 if (node == -1) return 0;
305 return node; 305 return node;
306} 306}
307
308int prom_ihandle2path(int handle, char *buffer, int bufsize)
309{
310 return p1275_cmd("instance-to-path",
311 P1275_ARG(1,P1275_ARG_OUT_BUF)|
312 P1275_INOUT(3, 1),
313 handle, buffer, P1275_SIZE(bufsize));
314}