[SeaBIOS] usb ohci pipe free fix

Kevin O'Connor kevin at koconnor.net
Mon Mar 5 01:04:59 CET 2012


On Sun, Mar 04, 2012 at 10:42:45PM +0100, Nils wrote:
> Hi kevin,
> Op zaterdag 03-03-2012 om 22:33 uur [tijdzone -0500], schreef Kevin
> O'Connor:
> 
> > I don't see anything wrong with the above code.  (The barrier() should
> > be moved, but I don't see that causing the problems you're seeing.)
> > 
> > Getting more info may help.  Something like the below.
> See ohci_test2.log
> 
> > Another thing you could try is forcing the "if (frameexp == 0)" branch
> > (by, for example, changing it to "if (1 || frameexp == 0)".
> With that branch forced i get the same timeout as before. 
> See ohci_test3.log

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).

I'm really just guessing at this point.  I'm pretty much at a loss for
why your controller just shuts down.

-Kevin


diff --git a/src/usb-ohci.c b/src/usb-ohci.c
index 7a437ad..4e020cb 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,33 @@ 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\n", hcca, startpos, ms, ed);
+        barrier();
+        for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms) {
+            dprintf(1, "u i=%d o=%x n=%p\n", i, hcca->int_table[i], ed);
             hcca->int_table[i] = (u32)ed;
+        }
     }
 
+    msleep(100);
+    dprintf(1, "add2: c=%x h=%p f=%d s=%x\n"
+            , cntl->regs->control, hcca, hcca->frame_no, cntl->regs->intrstatus);
+    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 +550,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