summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-07-26 04:37:32 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-07-26 04:37:32 +0200
commit2009d55643b87d6d0618c2fcfce5c440147138eb (patch)
tree9634647b7ed4f9960f8d54c5c9c83a83474b05da
parentac52599eef2ab79a64c30a8046a51b62501ca9ab (diff)
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.
-rw-r--r--sys/src/9/pc/ether82563.c2
-rw-r--r--sys/src/9/pc/etheriwl.c50
-rw-r--r--sys/src/9/pc/pmmc.c7
3 files changed, 27 insertions, 32 deletions
diff --git a/sys/src/9/pc/ether82563.c b/sys/src/9/pc/ether82563.c
index f4eab6a0f..bd3690288 100644
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -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;
}
diff --git a/sys/src/9/pc/etheriwl.c b/sys/src/9/pc/etheriwl.c
index 9bf90ef07..72a577166 100644
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -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);
diff --git a/sys/src/9/pc/pmmc.c b/sys/src/9/pc/pmmc.c
index 7c95d74bb..2d2cd8af6 100644
--- a/sys/src/9/pc/pmmc.c
+++ b/sys/src/9/pc/pmmc.c
@@ -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;
}