Skip to content

Commit

Permalink
UHCI: improved debugging checks for the frame list
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Feb 7, 2007
1 parent f38649f commit f3fe239
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 27 deletions.
48 changes: 43 additions & 5 deletions drivers/usb/host/uhci-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
int nframes, nerrs;

out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
Expand All @@ -355,23 +356,60 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
return out - buf;

out += sprintf(out, "Frame List\n");
nframes = 10;
nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
__le32 link, qh_dma;

j = 0;
td = uhci->frame_cpu[i];
link = uhci->frame[i];
if (!td)
continue;
goto check_link;

out += sprintf(out, "- Frame %d\n", i); \
if (td->dma_handle != (dma_addr_t)uhci->frame[i])
out += sprintf(out, " frame list does not match td->dma_handle!\n");
if (nframes > 0) {
out += sprintf(out, "- Frame %d -> (%08x)\n",
i, le32_to_cpu(link));
j = 1;
}

head = &td->fl_list;
tmp = head;
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
out += uhci_show_td(td, out, len - (out - buf), 4);
if (cpu_to_le32(td->dma_handle) != link) {
if (nframes > 0)
out += sprintf(out, " link does "
"not match list entry!\n");
else
++nerrs;
}
if (nframes > 0)
out += uhci_show_td(td, out,
len - (out - buf), 4);
link = td->link;
} while (tmp != head);

check_link:
qh_dma = uhci_frame_skel_link(uhci, i);
if (link != qh_dma) {
if (nframes > 0) {
if (!j) {
out += sprintf(out,
"- Frame %d -> (%08x)\n",
i, le32_to_cpu(link));
j = 1;
}
out += sprintf(out, " link does not match "
"QH (%08x)!\n", le32_to_cpu(qh_dma));
} else
++nerrs;
}
nframes -= j;
}
if (nerrs > 0)
out += sprintf(out, "Skipped %d bad links\n", nerrs);

out += sprintf(out, "Skeleton QHs\n");

Expand Down
51 changes: 29 additions & 22 deletions drivers/usb/host/uhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);

/*
* Calculate the link pointer DMA value for the first Skeleton QH in a frame.
*/
static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
{
int skelnum;

/*
* The interrupt queues will be interleaved as evenly as possible.
* There's not much to be done about period-1 interrupts; they have
* to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*
* ffs (Find First bit Set) does exactly what we need:
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
* ffs >= 7 => not on any high-period queue, so use
* skel_int1_qh = skelqh[9].
* Add in UHCI_NUMFRAMES to insure at least one bit is set.
*/
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
if (skelnum <= 1)
skelnum = 9;
return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
}

#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
Expand Down Expand Up @@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
/*
* Fill the frame list: make all entries point to the proper
* interrupt queue.
*
* The interrupt queues will be interleaved as evenly as possible.
* There's not much to be done about period-1 interrupts; they have
* to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
int irq;

/*
* ffs (Find First bit Set) does exactly what we need:
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
* ffs >= 7 => not on any high-period queue, so use
* skel_int1_qh = skelqh[9].
* Add UHCI_NUMFRAMES to insure at least one bit is set.
*/
irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
if (irq <= 1)
irq = 9;

/* Only place we don't use the frame list routines */
uhci->frame[i] = UHCI_PTR_QH |
cpu_to_le32(uhci->skelqh[irq]->dma_handle);
uhci->frame[i] = uhci_frame_skel_link(uhci, i);
}

/*
Expand Down

0 comments on commit f3fe239

Please sign in to comment.