update usbehci to do a better job of handling nil ptrs, and remove a few races. Reference: /n/atom/patch/applied/usbehcinilptr Date: Thu Apr 3 01:45:46 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/port/usb.h Thu Apr 3 01:45:06 2014 +++ /sys/src/nix/port/usb.h Thu Apr 3 01:45:06 2014 @@ -22,7 +22,7 @@ /* tunable parameters */ Nhcis = 16, /* max nb. of HCIs */ Neps = 64, /* max nb. of endpoints */ - Maxctllen = 32*1024, /* max allowed sized for ctl. xfers; see Maxdevconf */ + Maxctllen = 32*1024, /* max allowed sized for ctl. xfers */ Xfertmout = 2000, /* default request time out (ms) */ /* transfer types. keep this order */ --- /sys/src/nix/port/usbehci.c Thu Apr 3 01:45:06 2014 +++ /sys/src/nix/port/usbehci.c Thu Apr 3 01:45:06 2014 @@ -1340,8 +1340,7 @@ Itd *tdi; tdi = iso->tdi; - assert(tdi != nil); - if(itdactive(tdi)) /* not all tds are done */ + if(tdi == nil || itdactive(tdi)) /* not all tds are done */ return 0; ctlr->nisointr++; ddiprint("isohsintr: iso %#p: tdi %#p tdu %#p\n", iso, tdi, iso->tdu); @@ -1411,8 +1410,7 @@ Sitd *stdi; stdi = iso->stdi; - assert(stdi != nil); - if((stdi->csw & Stdactive) != 0) /* nothing new done */ + if(stdi == nil || (stdi->csw & Stdactive) != 0) /* nothing new done */ return 0; ctlr->nisointr++; ddiprint("isofsintr: iso %#p: tdi %#p tdu %#p\n", iso, stdi, iso->stdu); @@ -1481,7 +1479,7 @@ panic("qhinterrupt: qh state"); td = qh->tds; if(td == nil) - panic("qhinterrupt: no tds"); + return 0; if((td->csw & Tdactive) == 0) ddqprint("qhinterrupt port %#p qh %#p\n", ctlr->capio, qh); for(; td != nil; td = td->next){ @@ -1585,8 +1583,8 @@ qh = ctlr->qhs; i = 0; do{ - if (qh == nil) - panic("ehciintr: nil qh"); + if(qh == nil) + break; if(qh->state == Qrun) some += qhinterrupt(ctlr, qh); qh = qh->next; @@ -2140,7 +2138,7 @@ epgettd(Qio *io, int flags, void *a, int count, int maxpkt) { Td *td; - ulong pa; + uintmem pa, pae; int i; if(count > Tdmaxpkt) @@ -2157,15 +2155,23 @@ if(count <= Align - sizeof(Td)){ td->data = td->sbuff; td->buff = nil; - }else - td->data = td->buff = smalloc(Tdmaxpkt); + }else if(count <= 0x4000){ + td->buff = td->data = smalloc(count); + }else{ + td->buff = smalloc(count + 0x1000); + td->data = (uchar*)ROUNDUP(PTR2UINT(td->buff), 0x1000); + } pa = PADDR(td->data); + pae = pa + count; + if(sizeof(uintptr)>4 && (uint)pae != pae) + panic("usbehci: pa above 4g"); for(i = 0; i < nelem(td->buffer); i++){ td->buffer[i] = pa; - if(i > 0) - td->buffer[i] &= ~0xFFF; + pa &= ~0xFFF; pa += 0x1000; + if(pa >= pae) + pa = 0; /* paranoid */ } td->ndata = count; if(a != nil && count > 0) @@ -2184,14 +2190,15 @@ { Td *td; - qh->state = Qdone; if(qh->sched >= 0 && (qh->eps0 & Qhspeedmask) != Qhhigh) qh->eps0 |= Qhint; /* inactivate on next pass */ + qh->csw = (qh->csw & ~Tdactive) | Tdhalt; coherence(); for(td = qh->tds; td != nil; td = td->next){ - if(td->csw & Tdactive) + if(td->csw & Tdactive){ td->ndata = 0; - td->csw |= Tdhalt; + td->csw |= Tdhalt; + } } coherence(); } @@ -2310,8 +2317,10 @@ }else if(qh->state != Qdone && qh->state != Qclose) panic("ehci: epio: queue state %d", qh->state); if(timedout){ - aborttds(io->qh); - io->err = "request timed out"; + aborttds(qh); + qh->state = Qdone; + if(io->err == nil) + io->err = "request timed out"; iunlock(ctlr); while(waserror()) ; @@ -2346,7 +2355,6 @@ Qh* qh; Td *td, *ltd, *td0, *ntd; - qh = io->qh; ctlr = ep->hp->aux; io->debug = ep->debug; tmout = ep->tmout; @@ -2366,7 +2374,8 @@ } io->err = nil; ilock(ctlr); - if(qh->state == Qclose){ /* Tds released by cancelio */ + qh = io->qh; + if(qh == nil || qh->state == Qclose){ /* Tds released by cancelio */ iunlock(ctlr); error(io->err ? io->err : Eio); } @@ -2423,6 +2432,7 @@ dumptd(td0, "epio: got: "); qhdump(qh); } + err = io->err; tot = 0; c = a; @@ -2444,16 +2454,19 @@ io->toggle = td->csw & Tddata1; coherence(); } - tot += td->ndata; - if(c != nil && (td->csw & Tdtok) == Tdtokin && td->ndata > 0){ - memmove(c, td->data, td->ndata); - c += td->ndata; + if(err == nil && (n = td->ndata) > 0 && tot < count){ + if((tot + n) > count) + n = count - tot; + if(c != nil && (td->csw & Tdtok) == Tdtokin){ + memmove(c, td->data, n); + c += n; + } + tot += n; } } ntd = td->next; tdfree(td); } - err = io->err; if(mustlock){ qunlock(io); poperror(); @@ -2464,8 +2477,6 @@ return 0; /* that's our convention */ if(err != nil) error(err); - if(tot < 0) - error(Eio); return tot; } @@ -2736,8 +2747,7 @@ pa = PADDR(td->data) & ~0xFFF; for(p = 0; p < 8; p++) td->buffer[i] = pa + p * 0x1000; - td->buffer[0] = PADDR(iso->data) & ~0xFFF | - ep->nb << Itdepshift | ep->dev->nb << Itddevshift; + td->buffer[0] |= ep->nb << Itdepshift | ep->dev->nb << Itddevshift; if(ep->mode == OREAD) td->buffer[1] |= Itdin; else @@ -2974,10 +2984,11 @@ wakeup(io); qlock(io); /* wait for epio if running */ + if(io->qh == qh) + io->qh = nil; qunlock(io); qhfree(ctlr, qh); - io->qh = nil; } static void