summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-08-25 18:50:14 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-08-25 18:50:14 +0200
commit5e37e6361c8294da8bc311e626cad3fe781e3e67 (patch)
tree251f7a6d3e81143525754817fe5706b345996ad6
parent334054e0e7c80a8b6b817089214e5282174fc7c9 (diff)
etheriwl: recover from rfkill toggle or firmware crash
spawn a kernel process to check the broken state of the controller. if the firmware crashed, or rfkill was toggled we will reset and reboot the firmware. also power down the card when rfkill is off.
-rw-r--r--sys/src/9/pc/etheriwl.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/sys/src/9/pc/etheriwl.c b/sys/src/9/pc/etheriwl.c
index 72a577166..777de1512 100644
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -1990,6 +1990,46 @@ iwlpromiscuous(void *arg, int on)
}
static void
+iwlrecover(void *arg)
+{
+ Ether *edev;
+ Ctlr *ctlr;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+ for(;;){
+ while(waserror())
+ ;
+ tsleep(&up->sleep, return0, 0, 4000);
+ poperror();
+
+ qlock(ctlr);
+ for(;;){
+ if(ctlr->broken == 0)
+ break;
+
+ if(ctlr->power)
+ poweroff(ctlr);
+
+ if((csr32r(ctlr, Gpc) & RfKill) == 0)
+ break;
+
+ if(reset(ctlr) != nil)
+ break;
+ if(boot(ctlr) != nil)
+ break;
+
+ ctlr->bcastnodeid = -1;
+ ctlr->bssnodeid = -1;
+ ctlr->aid = 0;
+ rxon(edev, ctlr->wifi->bss);
+ break;
+ }
+ qunlock(ctlr);
+ }
+}
+
+static void
iwlattach(Ether *edev)
{
FWImage *fw;
@@ -2037,6 +2077,8 @@ iwlattach(Ether *edev)
setoptions(edev);
ctlr->attached = 1;
+
+ kproc("iwlrecover", iwlrecover, edev);
}
qunlock(ctlr);
poperror();
@@ -2188,7 +2230,7 @@ iwlinterrupt(Ureg*, void *arg)
receive(ctlr);
if(isr & Ierr){
ctlr->broken = 1;
- iprint("#l%d: fatal firmware error\n", edev->ctlrno);
+ print("#l%d: fatal firmware error\n", edev->ctlrno);
dumpctlr(ctlr);
}
ctlr->wait.m |= isr;