shithub: riscv

Download patch

ref: 2009d55643b87d6d0618c2fcfce5c440147138eb
parent: ac52599eef2ab79a64c30a8046a51b62501ca9ab
author: cinap_lenrek <[email protected]>
date: Fri Jul 26 00:37:32 EDT 2013

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.

--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -1053,7 +1053,9 @@
 			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;
 		}
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -349,7 +349,6 @@
 		Rendez;
 		u32int	m;
 		u32int	w;
-		u32int	r;
 	} wait;
 
 	struct {
@@ -1014,39 +1013,35 @@
 	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 @@
 	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 @@
 		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);
--- a/sys/src/9/pc/pmmc.c
+++ b/sys/src/9/pc/pmmc.c
@@ -362,7 +362,9 @@
 {
 	u32int status;
 
+	ilock(c);
 	c->waitmsk = Seint | mask;
+	iunlock(c);
 	do {
 		if(!waserror()){
 			tsleep(&c->r, waitcond, c, 100);
@@ -373,11 +375,10 @@
 			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 @@
 	}
 	iunlock(c);
 
-	return status;
+	return status & mask;
 }