summaryrefslogtreecommitdiff
path: root/sys/src
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 /sys/src
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.
Diffstat (limited to 'sys/src')
-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;
}