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