]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b Mon Sep 17 00:00:00 2001 |
2 | From: Yinghai Lu <yhlu.kernel@gmail.com> | |
3 | Date: Thu, 24 Jul 2008 17:29:40 -0700 | |
4 | Subject: x86: usb debug port early console, v4 | |
5 | Patch-mainline: 2.6.28 | |
6 | ||
7 | From: Yinghai Lu <yhlu.kernel@gmail.com> | |
8 | ||
9 | commit 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b upstream. | |
10 | ||
11 | based on work from Eric, and add some timeout so don't dead loop when debug | |
12 | device is not installed | |
13 | ||
14 | v2: fix checkpatch warning | |
15 | v3: move ehci struct def to linux/usrb/ehci_def.h from host/ehci.h | |
16 | also add CONFIG_EARLY_PRINTK_DBGP to disable it by default | |
17 | v4: address comments from Ingo, seperate ehci reg def moving to another patch | |
18 | also add auto detect port that connect to debug device for Nvidia | |
19 | southbridge | |
20 | ||
21 | Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> | |
22 | Cc: Andrew Morton <akpm@linux-foundation.org> | |
23 | Cc: Andi Kleen <andi@firstfloor.org> | |
24 | Cc: "Arjan van de Ven" <arjan@infradead.org> | |
25 | Cc: "Eric W. Biederman" <ebiederm@xmission.com> | |
26 | Cc: "Greg KH" <greg@kroah.com> | |
27 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
29 | ||
30 | --- | |
31 | Documentation/kernel-parameters.txt | 3 | |
32 | arch/x86/Kconfig.debug | 13 | |
33 | arch/x86/kernel/early_printk.c | 762 +++++++++++++++++++++++++++++++++++- | |
34 | 3 files changed, 774 insertions(+), 4 deletions(-) | |
35 | ||
36 | --- a/arch/x86/Kconfig.debug | |
37 | +++ b/arch/x86/Kconfig.debug | |
38 | @@ -43,6 +43,19 @@ config EARLY_PRINTK | |
39 | with klogd/syslogd or the X server. You should normally N here, | |
40 | unless you want to debug such a crash. | |
41 | ||
42 | +config EARLY_PRINTK_DBGP | |
43 | + bool "Early printk via EHCI debug port" | |
44 | + default n | |
45 | + depends on EARLY_PRINTK | |
46 | + help | |
47 | + Write kernel log output directly into the EHCI debug port. | |
48 | + | |
49 | + This is useful for kernel debugging when your machine crashes very | |
50 | + early before the console code is initialized. For normal operation | |
51 | + it is not recommended because it looks ugly and doesn't cooperate | |
52 | + with klogd/syslogd or the X server. You should normally N here, | |
53 | + unless you want to debug such a crash. You need usb debug device. | |
54 | + | |
55 | config DEBUG_STACKOVERFLOW | |
56 | bool "Check for stack overflows" | |
57 | depends on DEBUG_KERNEL | |
58 | --- a/arch/x86/kernel/early_printk.c | |
59 | +++ b/arch/x86/kernel/early_printk.c | |
60 | @@ -3,11 +3,19 @@ | |
61 | #include <linux/init.h> | |
62 | #include <linux/string.h> | |
63 | #include <linux/screen_info.h> | |
64 | +#include <linux/usb/ch9.h> | |
65 | +#include <linux/pci_regs.h> | |
66 | +#include <linux/pci_ids.h> | |
67 | +#include <linux/errno.h> | |
68 | #include <asm/io.h> | |
69 | #include <asm/processor.h> | |
70 | #include <asm/fcntl.h> | |
71 | #include <asm/setup.h> | |
72 | #include <xen/hvc-console.h> | |
73 | +#include <asm/pci-direct.h> | |
74 | +#include <asm/pgtable.h> | |
75 | +#include <asm/fixmap.h> | |
76 | +#include <linux/usb/ehci_def.h> | |
77 | ||
78 | /* Simple VGA output */ | |
79 | #define VGABASE (__ISA_IO_base + 0xb8000) | |
80 | @@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8; / | |
81 | static int early_serial_putc(unsigned char ch) | |
82 | { | |
83 | unsigned timeout = 0xffff; | |
84 | + | |
85 | while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) | |
86 | cpu_relax(); | |
87 | outb(ch, early_serial_base + TXR); | |
88 | @@ -151,6 +160,721 @@ static struct console early_serial_conso | |
89 | .index = -1, | |
90 | }; | |
91 | ||
92 | +#ifdef CONFIG_EARLY_PRINTK_DBGP | |
93 | + | |
94 | +static struct ehci_caps __iomem *ehci_caps; | |
95 | +static struct ehci_regs __iomem *ehci_regs; | |
96 | +static struct ehci_dbg_port __iomem *ehci_debug; | |
97 | +static unsigned int dbgp_endpoint_out; | |
98 | + | |
99 | +struct ehci_dev { | |
100 | + u32 bus; | |
101 | + u32 slot; | |
102 | + u32 func; | |
103 | +}; | |
104 | + | |
105 | +static struct ehci_dev ehci_dev; | |
106 | + | |
107 | +#define USB_DEBUG_DEVNUM 127 | |
108 | + | |
109 | +#define DBGP_DATA_TOGGLE 0x8800 | |
110 | + | |
111 | +static inline u32 dbgp_pid_update(u32 x, u32 tok) | |
112 | +{ | |
113 | + return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff); | |
114 | +} | |
115 | + | |
116 | +static inline u32 dbgp_len_update(u32 x, u32 len) | |
117 | +{ | |
118 | + return (x & ~0x0f) | (len & 0x0f); | |
119 | +} | |
120 | + | |
121 | +/* | |
122 | + * USB Packet IDs (PIDs) | |
123 | + */ | |
124 | + | |
125 | +/* token */ | |
126 | +#define USB_PID_OUT 0xe1 | |
127 | +#define USB_PID_IN 0x69 | |
128 | +#define USB_PID_SOF 0xa5 | |
129 | +#define USB_PID_SETUP 0x2d | |
130 | +/* handshake */ | |
131 | +#define USB_PID_ACK 0xd2 | |
132 | +#define USB_PID_NAK 0x5a | |
133 | +#define USB_PID_STALL 0x1e | |
134 | +#define USB_PID_NYET 0x96 | |
135 | +/* data */ | |
136 | +#define USB_PID_DATA0 0xc3 | |
137 | +#define USB_PID_DATA1 0x4b | |
138 | +#define USB_PID_DATA2 0x87 | |
139 | +#define USB_PID_MDATA 0x0f | |
140 | +/* Special */ | |
141 | +#define USB_PID_PREAMBLE 0x3c | |
142 | +#define USB_PID_ERR 0x3c | |
143 | +#define USB_PID_SPLIT 0x78 | |
144 | +#define USB_PID_PING 0xb4 | |
145 | +#define USB_PID_UNDEF_0 0xf0 | |
146 | + | |
147 | +#define USB_PID_DATA_TOGGLE 0x88 | |
148 | +#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) | |
149 | + | |
150 | +#define PCI_CAP_ID_EHCI_DEBUG 0xa | |
151 | + | |
152 | +#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ | |
153 | +#define HUB_SHORT_RESET_TIME 10 | |
154 | +#define HUB_LONG_RESET_TIME 200 | |
155 | +#define HUB_RESET_TIMEOUT 500 | |
156 | + | |
157 | +#define DBGP_MAX_PACKET 8 | |
158 | + | |
159 | +static int dbgp_wait_until_complete(void) | |
160 | +{ | |
161 | + u32 ctrl; | |
162 | + int loop = 0x100000; | |
163 | + | |
164 | + do { | |
165 | + ctrl = readl(&ehci_debug->control); | |
166 | + /* Stop when the transaction is finished */ | |
167 | + if (ctrl & DBGP_DONE) | |
168 | + break; | |
169 | + } while (--loop > 0); | |
170 | + | |
171 | + if (!loop) | |
172 | + return -1; | |
173 | + | |
174 | + /* | |
175 | + * Now that we have observed the completed transaction, | |
176 | + * clear the done bit. | |
177 | + */ | |
178 | + writel(ctrl | DBGP_DONE, &ehci_debug->control); | |
179 | + return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl); | |
180 | +} | |
181 | + | |
182 | +static void dbgp_mdelay(int ms) | |
183 | +{ | |
184 | + int i; | |
185 | + | |
186 | + while (ms--) { | |
187 | + for (i = 0; i < 1000; i++) | |
188 | + outb(0x1, 0x80); | |
189 | + } | |
190 | +} | |
191 | + | |
192 | +static void dbgp_breath(void) | |
193 | +{ | |
194 | + /* Sleep to give the debug port a chance to breathe */ | |
195 | +} | |
196 | + | |
197 | +static int dbgp_wait_until_done(unsigned ctrl) | |
198 | +{ | |
199 | + u32 pids, lpid; | |
200 | + int ret; | |
201 | + int loop = 3; | |
202 | + | |
203 | +retry: | |
204 | + writel(ctrl | DBGP_GO, &ehci_debug->control); | |
205 | + ret = dbgp_wait_until_complete(); | |
206 | + pids = readl(&ehci_debug->pids); | |
207 | + lpid = DBGP_PID_GET(pids); | |
208 | + | |
209 | + if (ret < 0) | |
210 | + return ret; | |
211 | + | |
212 | + /* | |
213 | + * If the port is getting full or it has dropped data | |
214 | + * start pacing ourselves, not necessary but it's friendly. | |
215 | + */ | |
216 | + if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET)) | |
217 | + dbgp_breath(); | |
218 | + | |
219 | + /* If I get a NACK reissue the transmission */ | |
220 | + if (lpid == USB_PID_NAK) { | |
221 | + if (--loop > 0) | |
222 | + goto retry; | |
223 | + } | |
224 | + | |
225 | + return ret; | |
226 | +} | |
227 | + | |
228 | +static void dbgp_set_data(const void *buf, int size) | |
229 | +{ | |
230 | + const unsigned char *bytes = buf; | |
231 | + u32 lo, hi; | |
232 | + int i; | |
233 | + | |
234 | + lo = hi = 0; | |
235 | + for (i = 0; i < 4 && i < size; i++) | |
236 | + lo |= bytes[i] << (8*i); | |
237 | + for (; i < 8 && i < size; i++) | |
238 | + hi |= bytes[i] << (8*(i - 4)); | |
239 | + writel(lo, &ehci_debug->data03); | |
240 | + writel(hi, &ehci_debug->data47); | |
241 | +} | |
242 | + | |
243 | +static void dbgp_get_data(void *buf, int size) | |
244 | +{ | |
245 | + unsigned char *bytes = buf; | |
246 | + u32 lo, hi; | |
247 | + int i; | |
248 | + | |
249 | + lo = readl(&ehci_debug->data03); | |
250 | + hi = readl(&ehci_debug->data47); | |
251 | + for (i = 0; i < 4 && i < size; i++) | |
252 | + bytes[i] = (lo >> (8*i)) & 0xff; | |
253 | + for (; i < 8 && i < size; i++) | |
254 | + bytes[i] = (hi >> (8*(i - 4))) & 0xff; | |
255 | +} | |
256 | + | |
257 | +static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, | |
258 | + const char *bytes, int size) | |
259 | +{ | |
260 | + u32 pids, addr, ctrl; | |
261 | + int ret; | |
262 | + | |
263 | + if (size > DBGP_MAX_PACKET) | |
264 | + return -1; | |
265 | + | |
266 | + addr = DBGP_EPADDR(devnum, endpoint); | |
267 | + | |
268 | + pids = readl(&ehci_debug->pids); | |
269 | + pids = dbgp_pid_update(pids, USB_PID_OUT); | |
270 | + | |
271 | + ctrl = readl(&ehci_debug->control); | |
272 | + ctrl = dbgp_len_update(ctrl, size); | |
273 | + ctrl |= DBGP_OUT; | |
274 | + ctrl |= DBGP_GO; | |
275 | + | |
276 | + dbgp_set_data(bytes, size); | |
277 | + writel(addr, &ehci_debug->address); | |
278 | + writel(pids, &ehci_debug->pids); | |
279 | + | |
280 | + ret = dbgp_wait_until_done(ctrl); | |
281 | + if (ret < 0) | |
282 | + return ret; | |
283 | + | |
284 | + return ret; | |
285 | +} | |
286 | + | |
287 | +static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, | |
288 | + int size) | |
289 | +{ | |
290 | + u32 pids, addr, ctrl; | |
291 | + int ret; | |
292 | + | |
293 | + if (size > DBGP_MAX_PACKET) | |
294 | + return -1; | |
295 | + | |
296 | + addr = DBGP_EPADDR(devnum, endpoint); | |
297 | + | |
298 | + pids = readl(&ehci_debug->pids); | |
299 | + pids = dbgp_pid_update(pids, USB_PID_IN); | |
300 | + | |
301 | + ctrl = readl(&ehci_debug->control); | |
302 | + ctrl = dbgp_len_update(ctrl, size); | |
303 | + ctrl &= ~DBGP_OUT; | |
304 | + ctrl |= DBGP_GO; | |
305 | + | |
306 | + writel(addr, &ehci_debug->address); | |
307 | + writel(pids, &ehci_debug->pids); | |
308 | + ret = dbgp_wait_until_done(ctrl); | |
309 | + if (ret < 0) | |
310 | + return ret; | |
311 | + | |
312 | + if (size > ret) | |
313 | + size = ret; | |
314 | + dbgp_get_data(data, size); | |
315 | + return ret; | |
316 | +} | |
317 | + | |
318 | +static int dbgp_control_msg(unsigned devnum, int requesttype, int request, | |
319 | + int value, int index, void *data, int size) | |
320 | +{ | |
321 | + u32 pids, addr, ctrl; | |
322 | + struct usb_ctrlrequest req; | |
323 | + int read; | |
324 | + int ret; | |
325 | + | |
326 | + read = (requesttype & USB_DIR_IN) != 0; | |
327 | + if (size > (read ? DBGP_MAX_PACKET:0)) | |
328 | + return -1; | |
329 | + | |
330 | + /* Compute the control message */ | |
331 | + req.bRequestType = requesttype; | |
332 | + req.bRequest = request; | |
333 | + req.wValue = value; | |
334 | + req.wIndex = index; | |
335 | + req.wLength = size; | |
336 | + | |
337 | + pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); | |
338 | + addr = DBGP_EPADDR(devnum, 0); | |
339 | + | |
340 | + ctrl = readl(&ehci_debug->control); | |
341 | + ctrl = dbgp_len_update(ctrl, sizeof(req)); | |
342 | + ctrl |= DBGP_OUT; | |
343 | + ctrl |= DBGP_GO; | |
344 | + | |
345 | + /* Send the setup message */ | |
346 | + dbgp_set_data(&req, sizeof(req)); | |
347 | + writel(addr, &ehci_debug->address); | |
348 | + writel(pids, &ehci_debug->pids); | |
349 | + ret = dbgp_wait_until_done(ctrl); | |
350 | + if (ret < 0) | |
351 | + return ret; | |
352 | + | |
353 | + /* Read the result */ | |
354 | + return dbgp_bulk_read(devnum, 0, data, size); | |
355 | +} | |
356 | + | |
357 | + | |
358 | +/* Find a PCI capability */ | |
359 | +static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) | |
360 | +{ | |
361 | + u8 pos; | |
362 | + int bytes; | |
363 | + | |
364 | + if (!(read_pci_config_16(num, slot, func, PCI_STATUS) & | |
365 | + PCI_STATUS_CAP_LIST)) | |
366 | + return 0; | |
367 | + | |
368 | + pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST); | |
369 | + for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { | |
370 | + u8 id; | |
371 | + | |
372 | + pos &= ~3; | |
373 | + id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID); | |
374 | + if (id == 0xff) | |
375 | + break; | |
376 | + if (id == cap) | |
377 | + return pos; | |
378 | + | |
379 | + pos = read_pci_config_byte(num, slot, func, | |
380 | + pos+PCI_CAP_LIST_NEXT); | |
381 | + } | |
382 | + return 0; | |
383 | +} | |
384 | + | |
385 | +static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func) | |
386 | +{ | |
387 | + u32 class; | |
388 | + | |
389 | + class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); | |
390 | + if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI) | |
391 | + return 0; | |
392 | + | |
393 | + return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); | |
394 | +} | |
395 | + | |
396 | +static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc) | |
397 | +{ | |
398 | + u32 bus, slot, func; | |
399 | + | |
400 | + for (bus = 0; bus < 256; bus++) { | |
401 | + for (slot = 0; slot < 32; slot++) { | |
402 | + for (func = 0; func < 8; func++) { | |
403 | + unsigned cap; | |
404 | + | |
405 | + cap = __find_dbgp(bus, slot, func); | |
406 | + | |
407 | + if (!cap) | |
408 | + continue; | |
409 | + if (ehci_num-- != 0) | |
410 | + continue; | |
411 | + *rbus = bus; | |
412 | + *rslot = slot; | |
413 | + *rfunc = func; | |
414 | + return cap; | |
415 | + } | |
416 | + } | |
417 | + } | |
418 | + return 0; | |
419 | +} | |
420 | + | |
421 | +static int ehci_reset_port(int port) | |
422 | +{ | |
423 | + u32 portsc; | |
424 | + u32 delay_time, delay; | |
425 | + int loop; | |
426 | + | |
427 | + /* Reset the usb debug port */ | |
428 | + portsc = readl(&ehci_regs->port_status[port - 1]); | |
429 | + portsc &= ~PORT_PE; | |
430 | + portsc |= PORT_RESET; | |
431 | + writel(portsc, &ehci_regs->port_status[port - 1]); | |
432 | + | |
433 | + delay = HUB_ROOT_RESET_TIME; | |
434 | + for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; | |
435 | + delay_time += delay) { | |
436 | + dbgp_mdelay(delay); | |
437 | + | |
438 | + portsc = readl(&ehci_regs->port_status[port - 1]); | |
439 | + if (portsc & PORT_RESET) { | |
440 | + /* force reset to complete */ | |
441 | + loop = 2; | |
442 | + writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), | |
443 | + &ehci_regs->port_status[port - 1]); | |
444 | + do { | |
445 | + portsc = readl(&ehci_regs->port_status[port-1]); | |
446 | + } while ((portsc & PORT_RESET) && (--loop > 0)); | |
447 | + } | |
448 | + | |
449 | + /* Device went away? */ | |
450 | + if (!(portsc & PORT_CONNECT)) | |
451 | + return -ENOTCONN; | |
452 | + | |
453 | + /* bomb out completely if something weird happend */ | |
454 | + if ((portsc & PORT_CSC)) | |
455 | + return -EINVAL; | |
456 | + | |
457 | + /* If we've finished resetting, then break out of the loop */ | |
458 | + if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) | |
459 | + return 0; | |
460 | + } | |
461 | + return -EBUSY; | |
462 | +} | |
463 | + | |
464 | +static int ehci_wait_for_port(int port) | |
465 | +{ | |
466 | + u32 status; | |
467 | + int ret, reps; | |
468 | + | |
469 | + for (reps = 0; reps < 3; reps++) { | |
470 | + dbgp_mdelay(100); | |
471 | + status = readl(&ehci_regs->status); | |
472 | + if (status & STS_PCD) { | |
473 | + ret = ehci_reset_port(port); | |
474 | + if (ret == 0) | |
475 | + return 0; | |
476 | + } | |
477 | + } | |
478 | + return -ENOTCONN; | |
479 | +} | |
480 | + | |
481 | +#ifdef DBGP_DEBUG | |
482 | +# define dbgp_printk early_printk | |
483 | +#else | |
484 | +static inline void dbgp_printk(const char *fmt, ...) { } | |
485 | +#endif | |
486 | + | |
487 | +typedef void (*set_debug_port_t)(int port); | |
488 | + | |
489 | +static void default_set_debug_port(int port) | |
490 | +{ | |
491 | +} | |
492 | + | |
493 | +static set_debug_port_t set_debug_port = default_set_debug_port; | |
494 | + | |
495 | +static void nvidia_set_debug_port(int port) | |
496 | +{ | |
497 | + u32 dword; | |
498 | + dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | |
499 | + 0x74); | |
500 | + dword &= ~(0x0f<<12); | |
501 | + dword |= ((port & 0x0f)<<12); | |
502 | + write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74, | |
503 | + dword); | |
504 | + dbgp_printk("set debug port to %d\n", port); | |
505 | +} | |
506 | + | |
507 | +static void __init detect_set_debug_port(void) | |
508 | +{ | |
509 | + u32 vendorid; | |
510 | + | |
511 | + vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, | |
512 | + 0x00); | |
513 | + | |
514 | + if ((vendorid & 0xffff) == 0x10de) { | |
515 | + dbgp_printk("using nvidia set_debug_port\n"); | |
516 | + set_debug_port = nvidia_set_debug_port; | |
517 | + } | |
518 | +} | |
519 | + | |
520 | +static int __init ehci_setup(void) | |
521 | +{ | |
522 | + struct usb_debug_descriptor dbgp_desc; | |
523 | + u32 cmd, ctrl, status, portsc, hcs_params; | |
524 | + u32 debug_port, new_debug_port = 0, n_ports; | |
525 | + u32 devnum; | |
526 | + int ret, i; | |
527 | + int loop; | |
528 | + int port_map_tried; | |
529 | + int playtimes = 3; | |
530 | + | |
531 | +try_next_time: | |
532 | + port_map_tried = 0; | |
533 | + | |
534 | +try_next_port: | |
535 | + | |
536 | + hcs_params = readl(&ehci_caps->hcs_params); | |
537 | + debug_port = HCS_DEBUG_PORT(hcs_params); | |
538 | + n_ports = HCS_N_PORTS(hcs_params); | |
539 | + | |
540 | + dbgp_printk("debug_port: %d\n", debug_port); | |
541 | + dbgp_printk("n_ports: %d\n", n_ports); | |
542 | + | |
543 | + for (i = 1; i <= n_ports; i++) { | |
544 | + portsc = readl(&ehci_regs->port_status[i-1]); | |
545 | + dbgp_printk("portstatus%d: %08x\n", i, portsc); | |
546 | + } | |
547 | + | |
548 | + if (port_map_tried && (new_debug_port != debug_port)) { | |
549 | + if (--playtimes) { | |
550 | + set_debug_port(new_debug_port); | |
551 | + goto try_next_time; | |
552 | + } | |
553 | + return -1; | |
554 | + } | |
555 | + | |
556 | + loop = 10; | |
557 | + /* Reset the EHCI controller */ | |
558 | + cmd = readl(&ehci_regs->command); | |
559 | + cmd |= CMD_RESET; | |
560 | + writel(cmd, &ehci_regs->command); | |
561 | + do { | |
562 | + cmd = readl(&ehci_regs->command); | |
563 | + } while ((cmd & CMD_RESET) && (--loop > 0)); | |
564 | + | |
565 | + if (!loop) { | |
566 | + dbgp_printk("can not reset ehci\n"); | |
567 | + return -1; | |
568 | + } | |
569 | + dbgp_printk("ehci reset done\n"); | |
570 | + | |
571 | + /* Claim ownership, but do not enable yet */ | |
572 | + ctrl = readl(&ehci_debug->control); | |
573 | + ctrl |= DBGP_OWNER; | |
574 | + ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); | |
575 | + writel(ctrl, &ehci_debug->control); | |
576 | + | |
577 | + /* Start the ehci running */ | |
578 | + cmd = readl(&ehci_regs->command); | |
579 | + cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); | |
580 | + cmd |= CMD_RUN; | |
581 | + writel(cmd, &ehci_regs->command); | |
582 | + | |
583 | + /* Ensure everything is routed to the EHCI */ | |
584 | + writel(FLAG_CF, &ehci_regs->configured_flag); | |
585 | + | |
586 | + /* Wait until the controller is no longer halted */ | |
587 | + loop = 10; | |
588 | + do { | |
589 | + status = readl(&ehci_regs->status); | |
590 | + } while ((status & STS_HALT) && (--loop > 0)); | |
591 | + | |
592 | + if (!loop) { | |
593 | + dbgp_printk("ehci can be started\n"); | |
594 | + return -1; | |
595 | + } | |
596 | + dbgp_printk("ehci started\n"); | |
597 | + | |
598 | + /* Wait for a device to show up in the debug port */ | |
599 | + ret = ehci_wait_for_port(debug_port); | |
600 | + if (ret < 0) { | |
601 | + dbgp_printk("No device found in debug port\n"); | |
602 | + goto next_debug_port; | |
603 | + } | |
604 | + dbgp_printk("ehci wait for port done\n"); | |
605 | + | |
606 | + /* Enable the debug port */ | |
607 | + ctrl = readl(&ehci_debug->control); | |
608 | + ctrl |= DBGP_CLAIM; | |
609 | + writel(ctrl, &ehci_debug->control); | |
610 | + ctrl = readl(&ehci_debug->control); | |
611 | + if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) { | |
612 | + dbgp_printk("No device in debug port\n"); | |
613 | + writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control); | |
614 | + goto err; | |
615 | + } | |
616 | + dbgp_printk("debug ported enabled\n"); | |
617 | + | |
618 | + /* Completely transfer the debug device to the debug controller */ | |
619 | + portsc = readl(&ehci_regs->port_status[debug_port - 1]); | |
620 | + portsc &= ~PORT_PE; | |
621 | + writel(portsc, &ehci_regs->port_status[debug_port - 1]); | |
622 | + | |
623 | + dbgp_mdelay(100); | |
624 | + | |
625 | + /* Find the debug device and make it device number 127 */ | |
626 | + for (devnum = 0; devnum <= 127; devnum++) { | |
627 | + ret = dbgp_control_msg(devnum, | |
628 | + USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
629 | + USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, | |
630 | + &dbgp_desc, sizeof(dbgp_desc)); | |
631 | + if (ret > 0) | |
632 | + break; | |
633 | + } | |
634 | + if (devnum > 127) { | |
635 | + dbgp_printk("Could not find attached debug device\n"); | |
636 | + goto err; | |
637 | + } | |
638 | + if (ret < 0) { | |
639 | + dbgp_printk("Attached device is not a debug device\n"); | |
640 | + goto err; | |
641 | + } | |
642 | + dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; | |
643 | + | |
644 | + /* Move the device to 127 if it isn't already there */ | |
645 | + if (devnum != USB_DEBUG_DEVNUM) { | |
646 | + ret = dbgp_control_msg(devnum, | |
647 | + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
648 | + USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); | |
649 | + if (ret < 0) { | |
650 | + dbgp_printk("Could not move attached device to %d\n", | |
651 | + USB_DEBUG_DEVNUM); | |
652 | + goto err; | |
653 | + } | |
654 | + devnum = USB_DEBUG_DEVNUM; | |
655 | + dbgp_printk("debug device renamed to 127\n"); | |
656 | + } | |
657 | + | |
658 | + /* Enable the debug interface */ | |
659 | + ret = dbgp_control_msg(USB_DEBUG_DEVNUM, | |
660 | + USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, | |
661 | + USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0); | |
662 | + if (ret < 0) { | |
663 | + dbgp_printk(" Could not enable the debug device\n"); | |
664 | + goto err; | |
665 | + } | |
666 | + dbgp_printk("debug interface enabled\n"); | |
667 | + | |
668 | + /* Perform a small write to get the even/odd data state in sync | |
669 | + */ | |
670 | + ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1); | |
671 | + if (ret < 0) { | |
672 | + dbgp_printk("dbgp_bulk_write failed: %d\n", ret); | |
673 | + goto err; | |
674 | + } | |
675 | + dbgp_printk("small write doned\n"); | |
676 | + | |
677 | + return 0; | |
678 | +err: | |
679 | + /* Things didn't work so remove my claim */ | |
680 | + ctrl = readl(&ehci_debug->control); | |
681 | + ctrl &= ~(DBGP_CLAIM | DBGP_OUT); | |
682 | + writel(ctrl, &ehci_debug->control); | |
683 | + return -1; | |
684 | + | |
685 | +next_debug_port: | |
686 | + port_map_tried |= (1<<(debug_port - 1)); | |
687 | + new_debug_port = ((debug_port-1+1)%n_ports) + 1; | |
688 | + if (port_map_tried != ((1<<n_ports) - 1)) { | |
689 | + set_debug_port(new_debug_port); | |
690 | + goto try_next_port; | |
691 | + } | |
692 | + if (--playtimes) { | |
693 | + set_debug_port(new_debug_port); | |
694 | + goto try_next_time; | |
695 | + } | |
696 | + | |
697 | + return -1; | |
698 | +} | |
699 | + | |
700 | +static int __init early_dbgp_init(char *s) | |
701 | +{ | |
702 | + u32 debug_port, bar, offset; | |
703 | + u32 bus, slot, func, cap; | |
704 | + void __iomem *ehci_bar; | |
705 | + u32 dbgp_num; | |
706 | + u32 bar_val; | |
707 | + char *e; | |
708 | + int ret; | |
709 | + u8 byte; | |
710 | + | |
711 | + if (!early_pci_allowed()) | |
712 | + return -1; | |
713 | + | |
714 | + dbgp_num = 0; | |
715 | + if (*s) | |
716 | + dbgp_num = simple_strtoul(s, &e, 10); | |
717 | + dbgp_printk("dbgp_num: %d\n", dbgp_num); | |
718 | + | |
719 | + cap = find_dbgp(dbgp_num, &bus, &slot, &func); | |
720 | + if (!cap) | |
721 | + return -1; | |
722 | + | |
723 | + dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot, | |
724 | + func); | |
725 | + | |
726 | + debug_port = read_pci_config(bus, slot, func, cap); | |
727 | + bar = (debug_port >> 29) & 0x7; | |
728 | + bar = (bar * 4) + 0xc; | |
729 | + offset = (debug_port >> 16) & 0xfff; | |
730 | + dbgp_printk("bar: %02x offset: %03x\n", bar, offset); | |
731 | + if (bar != PCI_BASE_ADDRESS_0) { | |
732 | + dbgp_printk("only debug ports on bar 1 handled.\n"); | |
733 | + | |
734 | + return -1; | |
735 | + } | |
736 | + | |
737 | + bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); | |
738 | + dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset); | |
739 | + if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) { | |
740 | + dbgp_printk("only simple 32bit mmio bars supported\n"); | |
741 | + | |
742 | + return -1; | |
743 | + } | |
744 | + | |
745 | + /* double check if the mem space is enabled */ | |
746 | + byte = read_pci_config_byte(bus, slot, func, 0x04); | |
747 | + if (!(byte & 0x2)) { | |
748 | + byte |= 0x02; | |
749 | + write_pci_config_byte(bus, slot, func, 0x04, byte); | |
750 | + dbgp_printk("mmio for ehci enabled\n"); | |
751 | + } | |
752 | + | |
753 | + /* | |
754 | + * FIXME I don't have the bar size so just guess PAGE_SIZE is more | |
755 | + * than enough. 1K is the biggest I have seen. | |
756 | + */ | |
757 | + set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); | |
758 | + ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); | |
759 | + ehci_bar += bar_val & ~PAGE_MASK; | |
760 | + dbgp_printk("ehci_bar: %p\n", ehci_bar); | |
761 | + | |
762 | + ehci_caps = ehci_bar; | |
763 | + ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase)); | |
764 | + ehci_debug = ehci_bar + offset; | |
765 | + ehci_dev.bus = bus; | |
766 | + ehci_dev.slot = slot; | |
767 | + ehci_dev.func = func; | |
768 | + | |
769 | + detect_set_debug_port(); | |
770 | + | |
771 | + ret = ehci_setup(); | |
772 | + if (ret < 0) { | |
773 | + dbgp_printk("ehci_setup failed\n"); | |
774 | + ehci_debug = 0; | |
775 | + | |
776 | + return -1; | |
777 | + } | |
778 | + | |
779 | + return 0; | |
780 | +} | |
781 | + | |
782 | +static void early_dbgp_write(struct console *con, const char *str, u32 n) | |
783 | +{ | |
784 | + int chunk, ret; | |
785 | + | |
786 | + if (!ehci_debug) | |
787 | + return; | |
788 | + while (n > 0) { | |
789 | + chunk = n; | |
790 | + if (chunk > DBGP_MAX_PACKET) | |
791 | + chunk = DBGP_MAX_PACKET; | |
792 | + ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, | |
793 | + dbgp_endpoint_out, str, chunk); | |
794 | + str += chunk; | |
795 | + n -= chunk; | |
796 | + } | |
797 | +} | |
798 | + | |
799 | +static struct console early_dbgp_console = { | |
800 | + .name = "earlydbg", | |
801 | + .write = early_dbgp_write, | |
802 | + .flags = CON_PRINTBUFFER, | |
803 | + .index = -1, | |
804 | +}; | |
805 | +#endif | |
806 | + | |
807 | /* Console interface to a host file on AMD's SimNow! */ | |
808 | ||
809 | static int simnow_fd; | |
810 | @@ -165,6 +889,7 @@ enum { | |
811 | static noinline long simnow(long cmd, long a, long b, long c) | |
812 | { | |
813 | long ret; | |
814 | + | |
815 | asm volatile("cpuid" : | |
816 | "=a" (ret) : | |
817 | "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); | |
818 | @@ -174,6 +899,7 @@ static noinline long simnow(long cmd, lo | |
819 | static void __init simnow_init(char *str) | |
820 | { | |
821 | char *fn = "klog"; | |
822 | + | |
823 | if (*str == '=') | |
824 | fn = ++str; | |
825 | /* error ignored */ | |
826 | @@ -208,10 +934,11 @@ asmlinkage void early_printk(const char | |
827 | va_end(ap); | |
828 | } | |
829 | ||
830 | -static int __initdata keep_early; | |
831 | ||
832 | static int __init setup_early_printk(char *buf) | |
833 | { | |
834 | + int keep_early; | |
835 | + | |
836 | if (!buf) | |
837 | return 0; | |
838 | ||
839 | @@ -219,8 +946,7 @@ static int __init setup_early_printk(cha | |
840 | return 0; | |
841 | early_console_initialized = 1; | |
842 | ||
843 | - if (strstr(buf, "keep")) | |
844 | - keep_early = 1; | |
845 | + keep_early = (strstr(buf, "keep") != NULL); | |
846 | ||
847 | if (!strncmp(buf, "serial", 6)) { | |
848 | early_serial_init(buf + 6); | |
849 | @@ -238,6 +964,17 @@ static int __init setup_early_printk(cha | |
850 | simnow_init(buf + 6); | |
851 | early_console = &simnow_console; | |
852 | keep_early = 1; | |
853 | +#ifdef CONFIG_EARLY_PRINTK_DBGP | |
854 | + } else if (!strncmp(buf, "dbgp", 4)) { | |
855 | + if (early_dbgp_init(buf+4) < 0) | |
856 | + return 0; | |
857 | + early_console = &early_dbgp_console; | |
858 | + /* | |
859 | + * usb subsys will reset ehci controller, so don't keep | |
860 | + * that early console | |
861 | + */ | |
862 | + keep_early = 0; | |
863 | +#endif | |
864 | #ifdef CONFIG_HVC_XEN | |
865 | } else if (!strncmp(buf, "xen", 3)) { | |
866 | early_console = &xenboot_console; | |
867 | @@ -251,4 +988,23 @@ static int __init setup_early_printk(cha | |
868 | register_console(early_console); | |
869 | return 0; | |
870 | } | |
871 | + | |
872 | +void __init enable_debug_console(char *buf) | |
873 | +{ | |
874 | +#ifdef DBGP_DEBUG | |
875 | + struct console *old_early_console = NULL; | |
876 | + | |
877 | + if (early_console_initialized && early_console) { | |
878 | + old_early_console = early_console; | |
879 | + unregister_console(early_console); | |
880 | + early_console_initialized = 0; | |
881 | + } | |
882 | + | |
883 | + setup_early_printk(buf); | |
884 | + | |
885 | + if (early_console == old_early_console && old_early_console) | |
886 | + register_console(old_early_console); | |
887 | +#endif | |
888 | +} | |
889 | + | |
890 | early_param("earlyprintk", setup_early_printk); | |
891 | --- a/Documentation/kernel-parameters.txt | |
892 | +++ b/Documentation/kernel-parameters.txt | |
893 | @@ -661,11 +661,12 @@ and is between 256 and 4096 characters. | |
894 | earlyprintk= [X86-32,X86-64,SH,BLACKFIN] | |
895 | earlyprintk=vga | |
896 | earlyprintk=serial[,ttySn[,baudrate]] | |
897 | + earlyprintk=dbgp | |
898 | ||
899 | Append ",keep" to not disable it when the real console | |
900 | takes over. | |
901 | ||
902 | - Only vga or serial at a time, not both. | |
903 | + Only vga or serial or usb debug port at a time. | |
904 | ||
905 | Currently only ttyS0 and ttyS1 are supported. | |
906 |