Fixes the donehead changed before ack bug in usbohci by noting that donehead doesn't really change, just Wdh is not set and it's inappropriate to be doing anything with donehead. Also, disabling ohc interrupts during that routine (which presumably prevents the TD structure from changing. And a misunderstanding fix of how ohci->intrenable and ohci->interdisable work. Note, I don't have a pc that has this bug, just the OLPC. Reference: /n/sources/patch/applied/pc-usbohci-donehead Date: Mon Mar 12 02:59:05 CET 2012 Signed-off-by: 9@trstn.net --- /sys/src/9/pc/usbohci.c Mon Mar 12 02:54:23 2012 +++ /sys/src/9/pc/usbohci.c Mon Mar 12 02:54:21 2012 @@ -1252,7 +1252,7 @@ static void interrupt(Ureg *, void *arg) { - Td *td, *ntd, *td0; + Td *td, *ntd; Hci *hp; Ctlr *ctlr; ulong status, curred; @@ -1261,6 +1261,7 @@ hp = arg; ctlr = hp->aux; ilock(ctlr); + ctlr->ohci->intrdisable = Mie; status = ctlr->ohci->intrsts; status &= ctlr->ohci->intrenable; status &= Oc|Rhsc|Fno|Ue|Rd|Sf|Wdh|So; @@ -1268,29 +1269,25 @@ if((status & Wdh) != 0){ /* lsb of donehead has bit to flag other intrs. */ td = pa2ptr(ctlr->hcca->donehead & ~0xF); - }else - td = nil; - td0 = td; - for(i = 0; td != nil && i < 1024; i++){ - if(0)ddprint("ohci tdinterrupt: td %#p\n", td); - ntd = pa2ptr(td->nexttd & ~0xF); - td->nexttd = 0; - if(td->ep == nil || td->io == nil) - panic("ohci: interrupt: ep %#p io %#p", td->ep, td->io); - ohciinterrupts[td->ep->ttype]++; - if(td->ep->ttype == Tiso) - isointerrupt(ctlr, td->ep, td->io, td, frno); - else - qhinterrupt(ctlr, td->ep, td->io, td, frno); - td = ntd; - } - if(i == 1024) - print("ohci: bug: more than 1024 done Tds?\n"); + for(i = 0; td != nil && i < 1024; i++){ + if(0)ddprint("ohci tdinterrupt: td %#p\n", td); + ntd = pa2ptr(td->nexttd & ~0xF); + td->nexttd = 0; + if(td->ep == nil || td->io == nil) + panic("ohci: interrupt: ep %#p io %#p", td->ep, td->io); + ohciinterrupts[td->ep->ttype]++; + if(td->ep->ttype == Tiso) + isointerrupt(ctlr, td->ep, td->io, td, frno); + else + qhinterrupt(ctlr, td->ep, td->io, td, frno); + td = ntd; + } + if(i == 1024) + print("ohci: bug: more than 1024 done Tds?\n"); - if(pa2ptr(ctlr->hcca->donehead & ~0xF) != td0) - print("ohci: bug: donehead changed before ack\n"); - ctlr->hcca->donehead = 0; + ctlr->hcca->donehead = 0; + } ctlr->ohci->intrsts = status; status &= ~Wdh; @@ -1313,6 +1310,7 @@ } if(status != 0) print("ohci interrupt: unhandled sts 0x%.8lux\n", status); + ctlr->ohci->intrenable = Mie | Wdh | Ue; iunlock(ctlr); } @@ -2496,7 +2494,7 @@ ctlr = hp->aux; ilock(ctlr); - ctlr->ohci->intrenable = 0; + ctlr->ohci->intrdisable = Mie; ctlr->ohci->control = 0; delay(100); iunlock(ctlr);