diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/Kconfig.debug | 15 | ||||
-rw-r--r-- | arch/powerpc/include/asm/udbg.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/udbg.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 189 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pseries.h | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 5 |
6 files changed, 24 insertions, 192 deletions
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index e72dcf6a421d..067cb8480747 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug | |||
@@ -167,6 +167,13 @@ config PPC_EARLY_DEBUG_LPAR | |||
167 | Select this to enable early debugging for a machine with a HVC | 167 | Select this to enable early debugging for a machine with a HVC |
168 | console on vterm 0. | 168 | console on vterm 0. |
169 | 169 | ||
170 | config PPC_EARLY_DEBUG_LPAR_HVSI | ||
171 | bool "LPAR HVSI Console" | ||
172 | depends on PPC_PSERIES | ||
173 | help | ||
174 | Select this to enable early debugging for a machine with a HVSI | ||
175 | console on a specified vterm. | ||
176 | |||
170 | config PPC_EARLY_DEBUG_G5 | 177 | config PPC_EARLY_DEBUG_G5 |
171 | bool "Apple G5" | 178 | bool "Apple G5" |
172 | depends on PPC_PMAC64 | 179 | depends on PPC_PMAC64 |
@@ -253,6 +260,14 @@ config PPC_EARLY_DEBUG_WSP | |||
253 | 260 | ||
254 | endchoice | 261 | endchoice |
255 | 262 | ||
263 | config PPC_EARLY_DEBUG_HVSI_VTERMNO | ||
264 | hex "vterm number to use with early debug HVSI" | ||
265 | depends on PPC_EARLY_DEBUG_LPAR_HVSI | ||
266 | default "0x30000000" | ||
267 | help | ||
268 | You probably want 0x30000000 for your first serial port and | ||
269 | 0x30000001 for your second one | ||
270 | |||
256 | config PPC_EARLY_DEBUG_44x_PHYSLOW | 271 | config PPC_EARLY_DEBUG_44x_PHYSLOW |
257 | hex "Low 32 bits of early debug UART physical address" | 272 | hex "Low 32 bits of early debug UART physical address" |
258 | depends on PPC_EARLY_DEBUG_44x | 273 | depends on PPC_EARLY_DEBUG_44x |
diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 58580e94a2bb..93e05d1b34b2 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h | |||
@@ -40,6 +40,7 @@ extern void udbg_adb_init_early(void); | |||
40 | 40 | ||
41 | extern void __init udbg_early_init(void); | 41 | extern void __init udbg_early_init(void); |
42 | extern void __init udbg_init_debug_lpar(void); | 42 | extern void __init udbg_init_debug_lpar(void); |
43 | extern void __init udbg_init_debug_lpar_hvsi(void); | ||
43 | extern void __init udbg_init_pmac_realmode(void); | 44 | extern void __init udbg_init_pmac_realmode(void); |
44 | extern void __init udbg_init_maple_realmode(void); | 45 | extern void __init udbg_init_maple_realmode(void); |
45 | extern void __init udbg_init_pas_realmode(void); | 46 | extern void __init udbg_init_pas_realmode(void); |
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index a57e61ea0558..faa82c1f3f68 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c | |||
@@ -31,6 +31,9 @@ void __init udbg_early_init(void) | |||
31 | #if defined(CONFIG_PPC_EARLY_DEBUG_LPAR) | 31 | #if defined(CONFIG_PPC_EARLY_DEBUG_LPAR) |
32 | /* For LPAR machines that have an HVC console on vterm 0 */ | 32 | /* For LPAR machines that have an HVC console on vterm 0 */ |
33 | udbg_init_debug_lpar(); | 33 | udbg_init_debug_lpar(); |
34 | #elif defined(CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI) | ||
35 | /* For LPAR machines that have an HVSI console on vterm 0 */ | ||
36 | udbg_init_debug_lpar_hvsi(); | ||
34 | #elif defined(CONFIG_PPC_EARLY_DEBUG_G5) | 37 | #elif defined(CONFIG_PPC_EARLY_DEBUG_G5) |
35 | /* For use on Apple G5 machines */ | 38 | /* For use on Apple G5 machines */ |
36 | udbg_init_pmac_realmode(); | 39 | udbg_init_pmac_realmode(); |
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index e3a96c4348ab..f7205d344efd 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -52,195 +52,6 @@ EXPORT_SYMBOL(plpar_hcall_norets); | |||
52 | 52 | ||
53 | extern void pSeries_find_serial_port(void); | 53 | extern void pSeries_find_serial_port(void); |
54 | 54 | ||
55 | |||
56 | static int vtermno; /* virtual terminal# for udbg */ | ||
57 | |||
58 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) | ||
59 | static void udbg_hvsi_putc(char c) | ||
60 | { | ||
61 | /* packet's seqno isn't used anyways */ | ||
62 | uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c }; | ||
63 | int rc; | ||
64 | |||
65 | if (c == '\n') | ||
66 | udbg_hvsi_putc('\r'); | ||
67 | |||
68 | do { | ||
69 | rc = plpar_put_term_char(vtermno, sizeof(packet), packet); | ||
70 | } while (rc == H_BUSY); | ||
71 | } | ||
72 | |||
73 | static long hvsi_udbg_buf_len; | ||
74 | static uint8_t hvsi_udbg_buf[256]; | ||
75 | |||
76 | static int udbg_hvsi_getc_poll(void) | ||
77 | { | ||
78 | unsigned char ch; | ||
79 | int rc, i; | ||
80 | |||
81 | if (hvsi_udbg_buf_len == 0) { | ||
82 | rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); | ||
83 | if (rc != H_SUCCESS || hvsi_udbg_buf[0] != 0xff) { | ||
84 | /* bad read or non-data packet */ | ||
85 | hvsi_udbg_buf_len = 0; | ||
86 | } else { | ||
87 | /* remove the packet header */ | ||
88 | for (i = 4; i < hvsi_udbg_buf_len; i++) | ||
89 | hvsi_udbg_buf[i-4] = hvsi_udbg_buf[i]; | ||
90 | hvsi_udbg_buf_len -= 4; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | if (hvsi_udbg_buf_len <= 0 || hvsi_udbg_buf_len > 256) { | ||
95 | /* no data ready */ | ||
96 | hvsi_udbg_buf_len = 0; | ||
97 | return -1; | ||
98 | } | ||
99 | |||
100 | ch = hvsi_udbg_buf[0]; | ||
101 | /* shift remaining data down */ | ||
102 | for (i = 1; i < hvsi_udbg_buf_len; i++) { | ||
103 | hvsi_udbg_buf[i-1] = hvsi_udbg_buf[i]; | ||
104 | } | ||
105 | hvsi_udbg_buf_len--; | ||
106 | |||
107 | return ch; | ||
108 | } | ||
109 | |||
110 | static int udbg_hvsi_getc(void) | ||
111 | { | ||
112 | int ch; | ||
113 | for (;;) { | ||
114 | ch = udbg_hvsi_getc_poll(); | ||
115 | if (ch == -1) { | ||
116 | /* This shouldn't be needed...but... */ | ||
117 | volatile unsigned long delay; | ||
118 | for (delay=0; delay < 2000000; delay++) | ||
119 | ; | ||
120 | } else { | ||
121 | return ch; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void udbg_putcLP(char c) | ||
127 | { | ||
128 | char buf[16]; | ||
129 | unsigned long rc; | ||
130 | |||
131 | if (c == '\n') | ||
132 | udbg_putcLP('\r'); | ||
133 | |||
134 | buf[0] = c; | ||
135 | do { | ||
136 | rc = plpar_put_term_char(vtermno, 1, buf); | ||
137 | } while(rc == H_BUSY); | ||
138 | } | ||
139 | |||
140 | /* Buffered chars getc */ | ||
141 | static long inbuflen; | ||
142 | static long inbuf[2]; /* must be 2 longs */ | ||
143 | |||
144 | static int udbg_getc_pollLP(void) | ||
145 | { | ||
146 | /* The interface is tricky because it may return up to 16 chars. | ||
147 | * We save them statically for future calls to udbg_getc(). | ||
148 | */ | ||
149 | char ch, *buf = (char *)inbuf; | ||
150 | int i; | ||
151 | long rc; | ||
152 | if (inbuflen == 0) { | ||
153 | /* get some more chars. */ | ||
154 | inbuflen = 0; | ||
155 | rc = plpar_get_term_char(vtermno, &inbuflen, buf); | ||
156 | if (rc != H_SUCCESS) | ||
157 | inbuflen = 0; /* otherwise inbuflen is garbage */ | ||
158 | } | ||
159 | if (inbuflen <= 0 || inbuflen > 16) { | ||
160 | /* Catch error case as well as other oddities (corruption) */ | ||
161 | inbuflen = 0; | ||
162 | return -1; | ||
163 | } | ||
164 | ch = buf[0]; | ||
165 | for (i = 1; i < inbuflen; i++) /* shuffle them down. */ | ||
166 | buf[i-1] = buf[i]; | ||
167 | inbuflen--; | ||
168 | return ch; | ||
169 | } | ||
170 | |||
171 | static int udbg_getcLP(void) | ||
172 | { | ||
173 | int ch; | ||
174 | for (;;) { | ||
175 | ch = udbg_getc_pollLP(); | ||
176 | if (ch == -1) { | ||
177 | /* This shouldn't be needed...but... */ | ||
178 | volatile unsigned long delay; | ||
179 | for (delay=0; delay < 2000000; delay++) | ||
180 | ; | ||
181 | } else { | ||
182 | return ch; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* call this from early_init() for a working debug console on | ||
188 | * vterm capable LPAR machines | ||
189 | */ | ||
190 | void __init udbg_init_debug_lpar(void) | ||
191 | { | ||
192 | vtermno = 0; | ||
193 | udbg_putc = udbg_putcLP; | ||
194 | udbg_getc = udbg_getcLP; | ||
195 | udbg_getc_poll = udbg_getc_pollLP; | ||
196 | } | ||
197 | |||
198 | /* returns 0 if couldn't find or use /chosen/stdout as console */ | ||
199 | void __init find_udbg_vterm(void) | ||
200 | { | ||
201 | struct device_node *stdout_node; | ||
202 | const u32 *termno; | ||
203 | const char *name; | ||
204 | |||
205 | /* find the boot console from /chosen/stdout */ | ||
206 | if (!of_chosen) | ||
207 | return; | ||
208 | name = of_get_property(of_chosen, "linux,stdout-path", NULL); | ||
209 | if (name == NULL) | ||
210 | return; | ||
211 | stdout_node = of_find_node_by_path(name); | ||
212 | if (!stdout_node) | ||
213 | return; | ||
214 | name = of_get_property(stdout_node, "name", NULL); | ||
215 | if (!name) { | ||
216 | printk(KERN_WARNING "stdout node missing 'name' property!\n"); | ||
217 | goto out; | ||
218 | } | ||
219 | |||
220 | /* Check if it's a virtual terminal */ | ||
221 | if (strncmp(name, "vty", 3) != 0) | ||
222 | goto out; | ||
223 | termno = of_get_property(stdout_node, "reg", NULL); | ||
224 | if (termno == NULL) | ||
225 | goto out; | ||
226 | vtermno = termno[0]; | ||
227 | |||
228 | if (of_device_is_compatible(stdout_node, "hvterm1")) { | ||
229 | udbg_putc = udbg_putcLP; | ||
230 | udbg_getc = udbg_getcLP; | ||
231 | udbg_getc_poll = udbg_getc_pollLP; | ||
232 | add_preferred_console("hvc", termno[0] & 0xff, NULL); | ||
233 | } else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) { | ||
234 | vtermno = termno[0]; | ||
235 | udbg_putc = udbg_hvsi_putc; | ||
236 | udbg_getc = udbg_hvsi_getc; | ||
237 | udbg_getc_poll = udbg_hvsi_getc_poll; | ||
238 | add_preferred_console("hvsi", termno[0] & 0xff, NULL); | ||
239 | } | ||
240 | out: | ||
241 | of_node_put(stdout_node); | ||
242 | } | ||
243 | |||
244 | void vpa_init(int cpu) | 55 | void vpa_init(int cpu) |
245 | { | 56 | { |
246 | int hwcpu = get_hard_smp_processor_id(cpu); | 57 | int hwcpu = get_hard_smp_processor_id(cpu); |
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index e9f6d2859c3c..24c7162f11d9 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -47,7 +47,8 @@ extern void pSeries_final_fixup(void); | |||
47 | /* Poweron flag used for enabling auto ups restart */ | 47 | /* Poweron flag used for enabling auto ups restart */ |
48 | extern unsigned long rtas_poweron_auto; | 48 | extern unsigned long rtas_poweron_auto; |
49 | 49 | ||
50 | extern void find_udbg_vterm(void); | 50 | /* Provided by HVC VIO */ |
51 | extern void hvc_vio_init_early(void); | ||
51 | 52 | ||
52 | /* Dynamic logical Partitioning/Mobility */ | 53 | /* Dynamic logical Partitioning/Mobility */ |
53 | extern void dlpar_free_cc_nodes(struct device_node *); | 54 | extern void dlpar_free_cc_nodes(struct device_node *); |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 593acceeff96..d00e52926b71 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -512,9 +512,10 @@ static void __init pSeries_init_early(void) | |||
512 | { | 512 | { |
513 | pr_debug(" -> pSeries_init_early()\n"); | 513 | pr_debug(" -> pSeries_init_early()\n"); |
514 | 514 | ||
515 | #ifdef CONFIG_HVC_CONSOLE | ||
515 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 516 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
516 | find_udbg_vterm(); | 517 | hvc_vio_init_early(); |
517 | 518 | #endif | |
518 | if (firmware_has_feature(FW_FEATURE_DABR)) | 519 | if (firmware_has_feature(FW_FEATURE_DABR)) |
519 | ppc_md.set_dabr = pseries_set_dabr; | 520 | ppc_md.set_dabr = pseries_set_dabr; |
520 | else if (firmware_has_feature(FW_FEATURE_XDABR)) | 521 | else if (firmware_has_feature(FW_FEATURE_XDABR)) |