diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-08-25 18:50:14 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-08-25 18:50:14 +0200 |
commit | 5e37e6361c8294da8bc311e626cad3fe781e3e67 (patch) | |
tree | 251f7a6d3e81143525754817fe5706b345996ad6 | |
parent | 334054e0e7c80a8b6b817089214e5282174fc7c9 (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.c | 44 |
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; |