ether82563, etheriwl, pmmc: fix potential multiprocessor races with wakeup

make sure that the wakeup enable conditions
are seen by different processors before sleep
is called.

the problems havnt been observed so far.
This commit is contained in:
cinap_lenrek 2013-07-26 04:37:32 +02:00
parent ac52599eef
commit 2009d55643
3 changed files with 27 additions and 32 deletions

View file

@ -1053,7 +1053,9 @@ i82563replenish(Ctlr *ctlr, int maysleep)
print("i82563%d: no rx buffers\n", ctlr->pool);
if(maysleep == 0)
return -1;
ilock(p);
p->starve = 1;
iunlock(p);
sleep(p, icansleep, p);
goto redux;
}

View file

@ -349,7 +349,6 @@ struct Ctlr {
Rendez;
u32int m;
u32int w;
u32int r;
} wait;
struct {
@ -1014,39 +1013,35 @@ readfirmware(char *name)
return fw;
}
typedef struct Irqwait Irqwait;
struct Irqwait {
Ctlr *ctlr;
u32int mask;
};
static int
gotirq(void *arg)
{
Irqwait *w;
Ctlr *ctlr;
w = arg;
ctlr = w->ctlr;
ctlr->wait.r = ctlr->wait.m & w->mask;
if(ctlr->wait.r){
ctlr->wait.m &= ~ctlr->wait.r;
return 1;
}
ctlr->wait.w = w->mask;
return 0;
Ctlr *ctlr = arg;
return (ctlr->wait.m & ctlr->wait.w) != 0;
}
static u32int
irqwait(Ctlr *ctlr, u32int mask, int timeout)
{
Irqwait w;
u32int r;
w.ctlr = ctlr;
w.mask = mask;
tsleep(&ctlr->wait, gotirq, &w, timeout);
ctlr->wait.w = 0;
return ctlr->wait.r & mask;
ilock(ctlr);
r = ctlr->wait.m & mask;
if(r == 0){
ctlr->wait.w = mask;
iunlock(ctlr);
if(!waserror()){
tsleep(&ctlr->wait, gotirq, ctlr, timeout);
poperror();
}
ilock(ctlr);
ctlr->wait.w = 0;
r = ctlr->wait.m & mask;
}
ctlr->wait.m &= ~r;
iunlock(ctlr);
return r;
}
static int
@ -1206,7 +1201,7 @@ reset(Ctlr *ctlr)
csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
ctlr->broken = 0;
ctlr->wait.r = 0;
ctlr->wait.m = 0;
ctlr->wait.w = 0;
ctlr->ie = Idefmask;
@ -2197,11 +2192,8 @@ iwlinterrupt(Ureg*, void *arg)
dumpctlr(ctlr);
}
ctlr->wait.m |= isr;
if(ctlr->wait.m & ctlr->wait.w){
ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
ctlr->wait.m &= ~ctlr->wait.r;
if(ctlr->wait.m & ctlr->wait.w)
wakeup(&ctlr->wait);
}
done:
csr32w(ctlr, Imr, ctlr->ie);
iunlock(ctlr);

View file

@ -362,7 +362,9 @@ intrwait(Ctlr *c, u32int mask, int tmo)
{
u32int status;
ilock(c);
c->waitmsk = Seint | mask;
iunlock(c);
do {
if(!waserror()){
tsleep(&c->r, waitcond, c, 100);
@ -373,11 +375,10 @@ intrwait(Ctlr *c, u32int mask, int tmo)
break;
tmo -= 100;
} while(tmo > 0);
ilock(c);
c->waitmsk = 0;
status = c->waitsts;
c->waitsts &= ~(status & mask);
c->waitmsk = 0;
if((status & mask) == 0 || (status & Seint) != 0){
/* abort command on timeout/error interrupt */
softreset(c, 0);
@ -386,7 +387,7 @@ intrwait(Ctlr *c, u32int mask, int tmo)
}
iunlock(c);
return status;
return status & mask;
}