[SeaBIOS] usb ohci pipe free fix

Kevin O'Connor kevin at koconnor.net
Mon Mar 5 21:41:34 CET 2012


On Mon, Mar 05, 2012 at 07:20:02PM +0100, Nils wrote:
> Op zondag 04-03-2012 om 19:04 uur [tijdzone -0500], schreef Kevin
> O'Connor:
> > Nothing looks wrong in the code.  I suppose one of the transfer
> > descriptors could have confused the controller.  You could try the
> > patch below (apply this on top of the "ohci pipe free fix" at the
> > start of this thread).  It would help if your logs had timing info
> > (via readserial.py).
> See attached log.

Nothing in the TD.  Can you try the patch below (again, on top of the
free pipe fix at the beginning of this thread).  This patch will also
dump the ED.

Another thing you could try is to post the log with the call to
set_idle() in usb-hid.c commented out.

-Kevin


diff --git a/src/usb-ohci.c b/src/usb-ohci.c
index 7a437ad..3670583 100644
--- a/src/usb-ohci.c
+++ b/src/usb-ohci.c
@@ -123,6 +123,8 @@ ohci_waittick(struct usb_ohci_s *cntl)
 {
     barrier();
     struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    dprintf(1, "ohci wait: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
     u32 startframe = hcca->frame_no;
     u64 end = calc_future_tsc(1000 * 5);
     for (;;) {
@@ -130,6 +132,8 @@ ohci_waittick(struct usb_ohci_s *cntl)
             break;
         if (check_tsc(end)) {
             warn_timeout();
+    dprintf(1, "ohci to: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
             return;
         }
         yield();
@@ -141,11 +145,16 @@ ohci_free_pipes(struct usb_ohci_s *cntl)
 {
     dprintf(7, "ohci_free_pipes %p\n", cntl);
 
+    struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    dprintf(1, "ohci fp: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
     u32 creg = readl(&cntl->regs->control);
     if (creg & (OHCI_CTRL_CLE|OHCI_CTRL_BLE)) {
         writel(&cntl->regs->control, creg & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
         ohci_waittick(cntl);
     }
+    dprintf(1, "ohci fp2: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
 
     u32 *pos = &cntl->regs->ed_controlhead;
     for (;;) {
@@ -214,6 +223,9 @@ start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca)
               | OHCI_USB_OPER | oldrwc));
     readl(&cntl->regs->control); // flush writes
 
+    dprintf(1, "ohci init: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
+
     return 0;
 }
 
@@ -322,6 +334,8 @@ wait_ed(struct ohci_ed *ed)
 void
 ohci_free_pipe(struct usb_pipe *pipe)
 {
+    if (! CONFIG_USB_OHCI)
+        return;
     // Add to controller's free list.
     struct usb_s *cntl = pipe->cntl;
     pipe->freenext = cntl->freelist;
@@ -463,6 +477,7 @@ ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
     if (!pipe || !tds || !data)
         goto err;
     memset(pipe, 0, sizeof(*pipe));
+    memset(tds, 0, sizeof(*tds) * count);
     memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
     pipe->data = data;
     pipe->count = count;
@@ -482,20 +497,37 @@ ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
     }
 
     // Add to interrupt schedule.
-    barrier();
     struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    dprintf(1, "add1: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
     if (frameexp == 0) {
         // Add to existing interrupt entry.
         struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
         ed->hwNextED = intr_ed->hwNextED;
+        barrier();
         intr_ed->hwNextED = (u32)ed;
     } else {
         int startpos = 1<<(frameexp-1);
         ed->hwNextED = hcca->int_table[startpos];
-        for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+        dprintf(1, "update h=%p s=%d ms=%d ed=%p %08x %08x %08x %08x\n"
+                , hcca, startpos, ms, ed
+                , ed->hwINFO, ed->hwTailP, ed->hwHeadP, ed->hwNextED);
+        barrier();
+        for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms) {
             hcca->int_table[i] = (u32)ed;
+            dprintf(1, "u i=%d o=%x n=%p f=%d\n"
+                    , i, hcca->int_table[i], ed, hcca->frame_no);
+        }
     }
 
+    msleep(100);
+    dprintf(1, "add2: c=%x h=%p f=%d s=%x  ed=%08x %08x %08x %08x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus
+            , ed->hwINFO, ed->hwTailP, ed->hwHeadP, ed->hwNextED);
+    for (i=0; i<count; i++)
+        dprintf(1, "td %d: %08x %08x %08x %08x\n"
+                , i, tds[i].hwINFO, tds[i].hwCBP, tds[i].hwNextTD, tds[i].hwBE);
+
     return &pipe->pipe;
 
 err:
@@ -522,6 +554,9 @@ ohci_poll_intr(struct usb_pipe *p, void *data)
     if (head == next)
         // No intrs found.
         return -1;
+    dprintf(1, "Got ohci data %d: %08x %08x %08x %08x\n"
+            , pos, GET_FLATPTR(next->hwINFO), GET_FLATPTR(next->hwCBP)
+            , GET_FLATPTR(next->hwNextTD), GET_FLATPTR(next->hwBE));
     // XXX - check for errors.
 
     // Copy data.



More information about the SeaBIOS mailing list