diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/uhci-debug.c | 48 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 51 |
2 files changed, 72 insertions, 27 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e345f15b7d87..b40bc1ac9b8c 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
@@ -347,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
347 | struct uhci_qh *qh; | 347 | struct uhci_qh *qh; |
348 | struct uhci_td *td; | 348 | struct uhci_td *td; |
349 | struct list_head *tmp, *head; | 349 | struct list_head *tmp, *head; |
350 | int nframes, nerrs; | ||
350 | 351 | ||
351 | out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); | 352 | out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); |
352 | out += sprintf(out, "HC status\n"); | 353 | out += sprintf(out, "HC status\n"); |
@@ -355,23 +356,60 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) | |||
355 | return out - buf; | 356 | return out - buf; |
356 | 357 | ||
357 | out += sprintf(out, "Frame List\n"); | 358 | out += sprintf(out, "Frame List\n"); |
359 | nframes = 10; | ||
360 | nerrs = 0; | ||
358 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { | 361 | for (i = 0; i < UHCI_NUMFRAMES; ++i) { |
362 | __le32 link, qh_dma; | ||
363 | |||
364 | j = 0; | ||
359 | td = uhci->frame_cpu[i]; | 365 | td = uhci->frame_cpu[i]; |
366 | link = uhci->frame[i]; | ||
360 | if (!td) | 367 | if (!td) |
361 | continue; | 368 | goto check_link; |
362 | 369 | ||
363 | out += sprintf(out, "- Frame %d\n", i); \ | 370 | if (nframes > 0) { |
364 | if (td->dma_handle != (dma_addr_t)uhci->frame[i]) | 371 | out += sprintf(out, "- Frame %d -> (%08x)\n", |
365 | out += sprintf(out, " frame list does not match td->dma_handle!\n"); | 372 | i, le32_to_cpu(link)); |
373 | j = 1; | ||
374 | } | ||
366 | 375 | ||
367 | head = &td->fl_list; | 376 | head = &td->fl_list; |
368 | tmp = head; | 377 | tmp = head; |
369 | do { | 378 | do { |
370 | td = list_entry(tmp, struct uhci_td, fl_list); | 379 | td = list_entry(tmp, struct uhci_td, fl_list); |
371 | tmp = tmp->next; | 380 | tmp = tmp->next; |
372 | out += uhci_show_td(td, out, len - (out - buf), 4); | 381 | if (cpu_to_le32(td->dma_handle) != link) { |
382 | if (nframes > 0) | ||
383 | out += sprintf(out, " link does " | ||
384 | "not match list entry!\n"); | ||
385 | else | ||
386 | ++nerrs; | ||
387 | } | ||
388 | if (nframes > 0) | ||
389 | out += uhci_show_td(td, out, | ||
390 | len - (out - buf), 4); | ||
391 | link = td->link; | ||
373 | } while (tmp != head); | 392 | } while (tmp != head); |
393 | |||
394 | check_link: | ||
395 | qh_dma = uhci_frame_skel_link(uhci, i); | ||
396 | if (link != qh_dma) { | ||
397 | if (nframes > 0) { | ||
398 | if (!j) { | ||
399 | out += sprintf(out, | ||
400 | "- Frame %d -> (%08x)\n", | ||
401 | i, le32_to_cpu(link)); | ||
402 | j = 1; | ||
403 | } | ||
404 | out += sprintf(out, " link does not match " | ||
405 | "QH (%08x)!\n", le32_to_cpu(qh_dma)); | ||
406 | } else | ||
407 | ++nerrs; | ||
408 | } | ||
409 | nframes -= j; | ||
374 | } | 410 | } |
411 | if (nerrs > 0) | ||
412 | out += sprintf(out, "Skipped %d bad links\n", nerrs); | ||
375 | 413 | ||
376 | out += sprintf(out, "Skeleton QHs\n"); | 414 | out += sprintf(out, "Skeleton QHs\n"); |
377 | 415 | ||
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e0d4c2358b39..49b9d390b95f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); | |||
92 | static void wakeup_rh(struct uhci_hcd *uhci); | 92 | static void wakeup_rh(struct uhci_hcd *uhci); |
93 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); | 93 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); |
94 | 94 | ||
95 | /* | ||
96 | * Calculate the link pointer DMA value for the first Skeleton QH in a frame. | ||
97 | */ | ||
98 | static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) | ||
99 | { | ||
100 | int skelnum; | ||
101 | |||
102 | /* | ||
103 | * The interrupt queues will be interleaved as evenly as possible. | ||
104 | * There's not much to be done about period-1 interrupts; they have | ||
105 | * to occur in every frame. But we can schedule period-2 interrupts | ||
106 | * in odd-numbered frames, period-4 interrupts in frames congruent | ||
107 | * to 2 (mod 4), and so on. This way each frame only has two | ||
108 | * interrupt QHs, which will help spread out bandwidth utilization. | ||
109 | * | ||
110 | * ffs (Find First bit Set) does exactly what we need: | ||
111 | * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], | ||
112 | * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. | ||
113 | * ffs >= 7 => not on any high-period queue, so use | ||
114 | * skel_int1_qh = skelqh[9]. | ||
115 | * Add in UHCI_NUMFRAMES to insure at least one bit is set. | ||
116 | */ | ||
117 | skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); | ||
118 | if (skelnum <= 1) | ||
119 | skelnum = 9; | ||
120 | return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle); | ||
121 | } | ||
122 | |||
95 | #include "uhci-debug.c" | 123 | #include "uhci-debug.c" |
96 | #include "uhci-q.c" | 124 | #include "uhci-q.c" |
97 | #include "uhci-hub.c" | 125 | #include "uhci-hub.c" |
@@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd) | |||
631 | /* | 659 | /* |
632 | * Fill the frame list: make all entries point to the proper | 660 | * Fill the frame list: make all entries point to the proper |
633 | * interrupt queue. | 661 | * interrupt queue. |
634 | * | ||
635 | * The interrupt queues will be interleaved as evenly as possible. | ||
636 | * There's not much to be done about period-1 interrupts; they have | ||
637 | * to occur in every frame. But we can schedule period-2 interrupts | ||
638 | * in odd-numbered frames, period-4 interrupts in frames congruent | ||
639 | * to 2 (mod 4), and so on. This way each frame only has two | ||
640 | * interrupt QHs, which will help spread out bandwidth utilization. | ||
641 | */ | 662 | */ |
642 | for (i = 0; i < UHCI_NUMFRAMES; i++) { | 663 | for (i = 0; i < UHCI_NUMFRAMES; i++) { |
643 | int irq; | ||
644 | |||
645 | /* | ||
646 | * ffs (Find First bit Set) does exactly what we need: | ||
647 | * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], | ||
648 | * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. | ||
649 | * ffs >= 7 => not on any high-period queue, so use | ||
650 | * skel_int1_qh = skelqh[9]. | ||
651 | * Add UHCI_NUMFRAMES to insure at least one bit is set. | ||
652 | */ | ||
653 | irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); | ||
654 | if (irq <= 1) | ||
655 | irq = 9; | ||
656 | 664 | ||
657 | /* Only place we don't use the frame list routines */ | 665 | /* Only place we don't use the frame list routines */ |
658 | uhci->frame[i] = UHCI_PTR_QH | | 666 | uhci->frame[i] = uhci_frame_skel_link(uhci, i); |
659 | cpu_to_le32(uhci->skelqh[irq]->dma_handle); | ||
660 | } | 667 | } |
661 | 668 | ||
662 | /* | 669 | /* |