aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-01-08 12:00:28 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:44:35 -0500
commitf3fe239b67424d88104e32076aec902c0642925f (patch)
treed7b3986dcdcb434111c0570eb2a129b2570e3bfa /drivers/usb/host
parentf38649fee955c19f4df9b9e7267f87702712d973 (diff)
UHCI: improved debugging checks for the frame list
This patch (as768) improves the debugging checks for the uhci-hcd frame list. The number of entries displayed is limited to 10, and the driver now checks for the correct Skeleton QH link value at the end of each chain of Isochronous TDs. The code to compute these link values is now used in two spots, so it is moved into its own separate subroutine. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-debug.c48
-rw-r--r--drivers/usb/host/uhci-hcd.c51
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
394check_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);
92static void wakeup_rh(struct uhci_hcd *uhci); 92static void wakeup_rh(struct uhci_hcd *uhci);
93static void uhci_get_current_frame_number(struct uhci_hcd *uhci); 93static 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 */
98static __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 /*