UHCI: improved debugging checks for the frame list
authorAlan Stern <stern@rowland.harvard.edu>
Mon, 8 Jan 2007 17:00:28 +0000 (12:00 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Feb 2007 23:44:35 +0000 (15:44 -0800)
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>
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c

index e345f15b7d87b5e545c4d1ea0a5c9416cf38ef20..b40bc1ac9b8cd75233231408f3e07ba789f38986 100644 (file)
@@ -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");
@@ -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");
 
index e0d4c2358b39653dc52fb06fde98e12d312a1775..49b9d390b95f4f2082a0164ad110f7e1bd3bce25 100644 (file)
@@ -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"
@@ -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);
        }
 
        /*