usb: fix isowrite putsamples race

This commit is contained in:
cinap_lenrek 2012-09-03 01:54:34 +02:00
parent 1be10947ba
commit cfd25faa28
3 changed files with 51 additions and 42 deletions

View file

@ -1762,25 +1762,23 @@ epctlio(Ep *ep, Ctlio *cio, void *a, long count)
/* /*
* Put new samples in the dummy Td. * Put new samples in the dummy Td.
* BUG: This does only a transfer per Td. We could do up to 8.
*/ */
static long static long
putsamples(Ctlr *ctlr, Ep *ep, Isoio *iso, uchar *b, long count) putsamples(Ctlr *ctlr, Ep *ep, Isoio *iso, uchar *b, long n)
{ {
Td *td; Td *td;
ulong n;
td = pa2ptr(iso->ed->tail); td = pa2ptr(iso->ed->tail);
n = count;
if(n > td->nbytes - BLEN(td->bp)) if(n > td->nbytes - BLEN(td->bp))
n = td->nbytes - BLEN(td->bp); n = td->nbytes - BLEN(td->bp);
assert(td->bp->wp + n <= td->bp->lim); assert(td->bp->wp + n <= td->bp->lim);
iunlock(ctlr); /* We could page fault here */
memmove(td->bp->wp, b, n); memmove(td->bp->wp, b, n);
td->bp->wp += n; ilock(ctlr);
if(BLEN(td->bp) == td->nbytes){ /* full Td: activate it */ if(td == pa2ptr(iso->ed->tail)){
ilock(ctlr); td->bp->wp += n;
isoadvance(ep, iso, td); if(BLEN(td->bp) == td->nbytes) /* full Td: activate it */
iunlock(ctlr); isoadvance(ep, iso, td);
} }
return n; return n;
} }
@ -1834,9 +1832,7 @@ episowrite(Ep *ep, void *a, long count)
} }
if(iso->state != Qrun) if(iso->state != Qrun)
panic("episowrite: iso not running"); panic("episowrite: iso not running");
iunlock(ctlr); /* We could page fault here */
nw = putsamples(ctlr, ep, iso, b+tot, count-tot); nw = putsamples(ctlr, ep, iso, b+tot, count-tot);
ilock(ctlr);
} }
while(isodelay(iso) == 0){ while(isodelay(iso) == 0){
iunlock(ctlr); iunlock(ctlr);

View file

@ -993,21 +993,27 @@ interrupt(Ureg*, void *a)
* it is activated and tdu advanced. * it is activated and tdu advanced.
*/ */
static long static long
putsamples(Isoio *iso, uchar *b, long count) putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
{ {
long tot; long n, tot, left;
long n; Td *tdu;
for(tot = 0; isocanwrite(iso) && tot < count; tot += n){ for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
n = count-tot; n = count-tot;
if(n > maxtdlen(iso->tdu) - iso->nleft) tdu = iso->tdu;
n = maxtdlen(iso->tdu) - iso->nleft; left = iso->nleft;
memmove(iso->tdu->data+iso->nleft, b+tot, n); if(n > maxtdlen(tdu) - left)
n = maxtdlen(tdu) - left;
iunlock(ctlr); /* can pagefault here */
memmove(tdu->data+left, b+tot, n);
ilock(ctlr);
if(tdu != iso->tdu)
continue;
iso->nleft += n; iso->nleft += n;
if(iso->nleft == maxtdlen(iso->tdu)){ if(iso->nleft == maxtdlen(tdu)){
tdisoinit(iso, iso->tdu, iso->nleft); tdisoinit(iso, tdu, iso->nleft);
iso->tdu = tdu->next;
iso->nleft = 0; iso->nleft = 0;
iso->tdu = iso->tdu->next;
} }
} }
return tot; return tot;
@ -1065,9 +1071,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count)
} }
if(iso->state != Qrun) if(iso->state != Qrun)
panic("episowrite: iso not running"); panic("episowrite: iso not running");
iunlock(ctlr); /* We could page fault here */ nw = putsamples(ctlr, iso, b+tot, count-tot);
nw = putsamples(iso, b+tot, count-tot);
ilock(ctlr);
} }
while(isodelay(iso) == 0){ while(isodelay(iso) == 0){
iunlock(ctlr); iunlock(ctlr);

View file

@ -1996,33 +1996,44 @@ episoread(Ep *ep, Isoio *iso, void *a, long count)
* it is activated and tdu advanced. * it is activated and tdu advanced.
*/ */
static long static long
putsamples(Isoio *iso, uchar *b, long count) putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
{ {
long tot, n; long left, tot, n;
Sitd *stdu;
Itd *tdu;
for(tot = 0; isocanwrite(iso) && tot < count; tot += n){ for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
n = count-tot; n = count-tot;
left = iso->nleft;
if(iso->hs != 0){ if(iso->hs != 0){
if(n > iso->tdu->mdata - iso->nleft) tdu = iso->tdu;
n = iso->tdu->mdata - iso->nleft; if(n > tdu->mdata - left)
memmove(iso->tdu->data + iso->nleft, b + tot, n); n = tdu->mdata - left;
coherence(); iunlock(ctlr); /* We could page fault here */
memmove(tdu->data + left, b + tot, n);
ilock(ctlr);
if(iso->tdu != tdu)
continue;
iso->nleft += n; iso->nleft += n;
if(iso->nleft == iso->tdu->mdata){ if(iso->nleft == tdu->mdata){
itdinit(iso, iso->tdu); itdinit(iso, tdu);
iso->tdu = tdu->next;
iso->nleft = 0; iso->nleft = 0;
iso->tdu = iso->tdu->next;
} }
}else{ }else{
if(n > iso->stdu->mdata - iso->nleft) stdu = iso->stdu;
n = iso->stdu->mdata - iso->nleft; if(n > stdu->mdata - left)
memmove(iso->stdu->data + iso->nleft, b + tot, n); n = stdu->mdata - left;
coherence(); iunlock(ctlr); /* We could page fault here */
memmove(stdu->data + left, b + tot, n);
ilock(ctlr);
if(iso->stdu != stdu)
continue;
iso->nleft += n; iso->nleft += n;
if(iso->nleft == iso->stdu->mdata){ if(iso->nleft == stdu->mdata){
sitdinit(iso, iso->stdu); sitdinit(iso, stdu);
iso->stdu = stdu->next;
iso->nleft = 0; iso->nleft = 0;
iso->stdu = iso->stdu->next;
} }
} }
} }
@ -2081,9 +2092,7 @@ episowrite(Ep *ep, Isoio *iso, void *a, long count)
} }
if(iso->state != Qrun) if(iso->state != Qrun)
panic("episowrite: iso not running"); panic("episowrite: iso not running");
iunlock(ctlr); /* We could page fault here */ nw = putsamples(ctlr, iso, b+tot, count-tot);
nw = putsamples(iso, b+tot, count-tot);
ilock(ctlr);
} }
while(isodelay(iso) == 0){ while(isodelay(iso) == 0){
iunlock(ctlr); iunlock(ctlr);