]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etheriwl.c
etheriwl: fix command queue handling
[plan9front.git] / sys / src / 9 / pc / etheriwl.c
1 /*
2  * Intel WiFi Link driver.
3  *
4  * Written without any documentation but Damien Bergaminis
5  * OpenBSD iwn(4) driver sources. Requires intel firmware
6  * to be present in /lib/firmware/iwn-* on attach.
7  */
8
9 #include "u.h"
10 #include "../port/lib.h"
11 #include "mem.h"
12 #include "dat.h"
13 #include "fns.h"
14 #include "io.h"
15 #include "../port/error.h"
16 #include "../port/netif.h"
17
18 #include "etherif.h"
19 #include "wifi.h"
20
21 enum {
22
23         Ntxlog          = 8,
24         Ntx             = 1<<Ntxlog,
25         Nrxlog          = 8,
26         Nrx             = 1<<Nrxlog,
27
28         Rstatsize       = 16,
29         Rbufsize        = 4*1024,
30         Rdscsize        = 8,
31
32         Tbufsize        = 4*1024,
33         Tdscsize        = 128,
34         Tcmdsize        = 140,
35 };
36
37 /* registers */
38 enum {
39         Cfg             = 0x000,        /* config register */
40                 MacSi           = 1<<8,
41                 RadioSi         = 1<<9,
42                 EepromLocked    = 1<<21,
43                 NicReady        = 1<<22,
44                 HapwakeL1A      = 1<<23,
45                 PrepareDone     = 1<<25,
46                 Prepare         = 1<<27,
47
48         Isr             = 0x008,        /* interrupt status */
49         Imr             = 0x00c,        /* interrupt mask */
50                 Ialive          = 1<<0,
51                 Iwakeup         = 1<<1,
52                 Iswrx           = 1<<3,
53                 Ictreached      = 1<<6,
54                 Irftoggled      = 1<<7,
55                 Iswerr          = 1<<25,
56                 Isched          = 1<<26,
57                 Ifhtx           = 1<<27,
58                 Irxperiodic     = 1<<28,
59                 Ihwerr          = 1<<29,
60                 Ifhrx           = 1<<31,
61
62                 Ierr            = Iswerr | Ihwerr,
63                 Idefmask        = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled,
64
65         FhIsr           = 0x010,        /* second interrupt status */
66
67         Reset           = 0x020,
68
69         Rev             = 0x028,        /* hardware revision */
70
71         EepromIo        = 0x02c,        /* EEPROM i/o register */
72         EepromGp        = 0x030,
73         OtpromGp        = 0x034,
74                 DevSelOtp       = 1<<16,
75                 RelativeAccess  = 1<<17,
76                 EccCorrStts     = 1<<20,
77                 EccUncorrStts   = 1<<21,
78
79         Gpc             = 0x024,        /* gp cntrl */
80                 MacAccessEna    = 1<<0,
81                 MacClockReady   = 1<<0,
82                 InitDone        = 1<<2,
83                 MacAccessReq    = 1<<3,
84                 NicSleep        = 1<<4,
85                 RfKill          = 1<<27,
86
87         Gio             = 0x03c,
88                 EnaL0S          = 1<<1,
89
90         Led             = 0x094,
91                 LedBsmCtrl      = 1<<5,
92                 LedOn           = 0x38,
93                 LedOff          = 0x78,
94
95         UcodeGp1Clr     = 0x05c,
96                 UcodeGp1RfKill          = 1<<1,
97                 UcodeGp1CmdBlocked      = 1<<2,
98                 UcodeGp1CtempStopRf     = 1<<3,
99
100         ShadowRegCtrl   = 0x0a8,
101
102         Giochicken      = 0x100,
103                 L1AnoL0Srx      = 1<<23,
104                 DisL0Stimer     = 1<<29,
105
106         AnaPll          = 0x20c,
107
108         Dbghpetmem      = 0x240,
109
110         MemRaddr        = 0x40c,
111         MemWaddr        = 0x410,
112         MemWdata        = 0x418,
113         MemRdata        = 0x41c,
114
115         PrphWaddr       = 0x444,
116         PrphRaddr       = 0x448,
117         PrphWdata       = 0x44c,
118         PrphRdata       = 0x450,
119
120         HbusTargWptr    = 0x460,
121 };
122
123 /*
124  * Flow-Handler registers.
125  */
126 enum {
127         FhTfbdCtrl0     = 0x1900,       // +q*8
128         FhTfbdCtrl1     = 0x1904,       // +q*8
129
130         FhKwAddr        = 0x197c,
131
132         FhSramAddr      = 0x19a4,       // +q*4
133         FhCbbcQueue     = 0x19d0,       // +q*4
134         FhStatusWptr    = 0x1bc0,
135         FhRxBase        = 0x1bc4,
136         FhRxWptr        = 0x1bc8,
137         FhRxConfig      = 0x1c00,
138                 FhRxConfigEna           = 1<<31,
139                 FhRxConfigRbSize8K      = 1<<16,
140                 FhRxConfigSingleFrame   = 1<<15,
141                 FhRxConfigIrqDstHost    = 1<<12,
142                 FhRxConfigIgnRxfEmpty   = 1<<2,
143
144                 FhRxConfigNrbdShift     = 20,
145                 FhRxConfigRbTimeoutShift= 4,
146
147         FhRxStatus      = 0x1c44,
148
149         FhTxConfig      = 0x1d00,       // +q*32
150                 FhTxConfigDmaCreditEna  = 1<<3,
151                 FhTxConfigDmaEna        = 1<<31,
152                 FhTxConfigCirqHostEndTfd= 1<<20,
153
154         FhTxBufStatus   = 0x1d08,       // +q*32
155                 FhTxBufStatusTbNumShift = 20,
156                 FhTxBufStatusTbIdxShift = 12,
157                 FhTxBufStatusTfbdValid  = 3,
158
159         FhTxChicken     = 0x1e98,
160         FhTxStatus      = 0x1eb0,
161 };
162
163 /*
164  * NIC internal memory offsets.
165  */
166 enum {
167         ApmgClkCtrl     = 0x3000,
168         ApmgClkEna      = 0x3004,
169         ApmgClkDis      = 0x3008,
170                 DmaClkRqt       = 1<<9,
171                 BsmClkRqt       = 1<<11,
172
173         ApmgPs          = 0x300c,
174                 EarlyPwroffDis  = 1<<22,
175                 PwrSrcVMain     = 0<<24,
176                 PwrSrcVAux      = 2<<24,
177                 PwrSrcMask      = 3<<24,
178                 ResetReq        = 1<<26,
179
180         ApmgDigitalSvr  = 0x3058,
181         ApmgAnalogSvr   = 0x306c,
182         ApmgPciStt      = 0x3010,
183         BsmWrCtrl       = 0x3400,
184         BsmWrMemSrc     = 0x3404,
185         BsmWrMemDst     = 0x3408,
186         BsmWrDwCount    = 0x340c,
187         BsmDramTextAddr = 0x3490,
188         BsmDramTextSize = 0x3494,
189         BsmDramDataAddr = 0x3498,
190         BsmDramDataSize = 0x349c,
191         BsmSramBase     = 0x3800,
192 };
193
194 /*
195  * TX scheduler registers.
196  */
197 enum {
198         SchedBase               = 0xa02c00,
199         SchedSramAddr           = SchedBase,
200         SchedDramAddr5000       = SchedBase+0x008,
201         SchedDramAddr4965       = SchedBase+0x010,
202         SchedTxFact5000         = SchedBase+0x010,
203         SchedTxFact4965         = SchedBase+0x01c,
204         SchedQueueRdptr4965     = SchedBase+0x064,      // +q*4
205         SchedQueueRdptr5000     = SchedBase+0x068,      // +q*4
206         SchedQChainSel4965      = SchedBase+0x0d0,
207         SchedIntrMask4965       = SchedBase+0x0e4,
208         SchedQChainSel5000      = SchedBase+0x0e8,
209         SchedQueueStatus4965    = SchedBase+0x104,      // +q*4
210         SchedIntrMask5000       = SchedBase+0x108,
211         SchedQueueStatus5000    = SchedBase+0x10c,      // +q*4
212         SchedAggrSel5000        = SchedBase+0x248,
213 };
214
215 enum {
216         SchedCtxOff4965         = 0x380,
217         SchedCtxLen4965         = 416,
218         SchedTransTblOff4965    = 0x500,
219
220         SchedCtxOff5000         = 0x600,
221         SchedCtxLen5000         = 512,
222         SchedTransTblOff5000    = 0x7e0,
223 };
224
225 /* controller types */
226 enum {
227         Type4965        = 0,
228         Type5300        = 2,
229         Type5350        = 3,
230         Type5150        = 4,
231         Type5100        = 5,
232         Type1000        = 6,
233         Type6000        = 7,
234         Type6050        = 8,
235         Type6005        = 11,
236 };
237
238 typedef struct FWInfo FWInfo;
239 typedef struct FWImage FWImage;
240 typedef struct FWSect FWSect;
241
242 typedef struct TXQ TXQ;
243 typedef struct RXQ RXQ;
244
245 typedef struct Ctlr Ctlr;
246
247 struct FWSect
248 {
249         uchar   *data;
250         uint    size;
251 };
252
253 struct FWImage
254 {
255         struct {
256                 FWSect  text;
257                 FWSect  data;
258         } init, main, boot;
259
260         uint    rev;
261         uint    build;
262         char    descr[64+1];
263         uchar   data[];
264 };
265
266 struct FWInfo
267 {
268         uchar   major;
269         uchar   minjor;
270         uchar   type;
271         uchar   subtype;
272
273         u32int  logptr;
274         u32int  errptr;
275         u32int  tstamp;
276         u32int  valid;
277 };
278
279 struct TXQ
280 {
281         uint    n;
282         uint    i;
283         Block   **b;
284         uchar   *d;
285         uchar   *c;
286
287         Rendez;
288         QLock;
289 };
290
291 struct RXQ
292 {
293         uint    i;
294         Block   **b;
295         u32int  *p;
296         uchar   *s;
297 };
298
299 struct Ctlr {
300         Lock;
301         QLock;
302
303         Ctlr *link;
304         Pcidev *pdev;
305         Wifi *wifi;
306
307         int type;
308         int port;
309         int active;
310         int attached;
311
312         u32int ie;
313
314         u32int *nic;
315         uchar *kwpage;
316
317         int channel;
318
319         RXQ rx;
320         TXQ tx[20];
321
322         struct {
323                 Rendez;
324                 u32int  m;
325                 u32int  w;
326                 u32int  r;
327         } wait;
328
329         struct {
330                 uchar   type;
331                 uchar   step;
332                 uchar   dash;
333                 uchar   txantmask;
334                 uchar   rxantmask;
335         } rfcfg;
336
337         struct {
338                 u32int  crystal;
339         } eeprom;
340
341         struct {
342                 u32int  base;
343                 uchar   *s;
344         } sched;
345
346         FWInfo fwinfo;
347         FWImage *fw;
348 };
349
350 #define csr32r(c, r)    (*((c)->nic+((r)/4)))
351 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
352
353 static uint
354 get16(uchar *p){
355         return *((u16int*)p);
356 }
357 static uint
358 get32(uchar *p){
359         return *((u32int*)p);
360 }
361 static void
362 put32(uchar *p, uint v){
363         *((u32int*)p) = v;
364 }
365 static void
366 put16(uchar *p, uint v){
367         *((u16int*)p) = v;
368 };
369
370 static char*
371 niclock(Ctlr *ctlr)
372 {
373         int i;
374
375         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
376         for(i=0; i<1000; i++){
377                 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
378                         return 0;
379                 delay(10);
380         }
381         return "niclock: timeout";
382 }
383
384 static void
385 nicunlock(Ctlr *ctlr)
386 {
387         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
388 }
389
390 static u32int
391 prphread(Ctlr *ctlr, uint off)
392 {
393         csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
394         coherence();
395         return csr32r(ctlr, PrphRdata);
396 }
397 static void
398 prphwrite(Ctlr *ctlr, uint off, u32int data)
399 {
400         csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
401         coherence();
402         csr32w(ctlr, PrphWdata, data);
403 }
404
405 static u32int
406 memread(Ctlr *ctlr, uint off)
407 {
408         csr32w(ctlr, MemRaddr, off);
409         coherence();
410         return csr32r(ctlr, MemRdata);
411 }
412 static void
413 memwrite(Ctlr *ctlr, uint off, u32int data)
414 {
415         csr32w(ctlr, MemWaddr, off);
416         coherence();
417         csr32w(ctlr, MemWdata, data);
418 }
419
420 static void
421 setfwinfo(Ctlr *ctlr, uchar *d, int len)
422 {
423         FWInfo *i;
424
425         if(len < 32)
426                 return;
427         i = &ctlr->fwinfo;
428         i->minjor = *d++;
429         i->major = *d++;
430         d += 2+8;
431         i->type = *d++;
432         i->subtype = *d++;
433         d += 2;
434         i->logptr = get32(d); d += 4;
435         i->errptr = get32(d); d += 4;
436         i->tstamp = get32(d); d += 4;
437         i->valid = get32(d);
438 };
439
440 static void
441 dumpctlr(Ctlr *ctlr)
442 {
443         u32int dump[13];
444         int i;
445
446         if(ctlr->fwinfo.errptr == 0){
447                 print("no error pointer\n");
448                 return;
449         }
450         for(i=0; i<nelem(dump); i++)
451                 dump[i] = memread(ctlr, ctlr->fwinfo.errptr + i*4);
452         print(  "error:\tid %ux, pc %ux,\n"
453                 "\tbranchlink %.8ux %.8ux, interruptlink %.8ux %.8ux,\n"
454                 "\terrordata %.8ux %.8ux, srcline %ud, tsf %ux, time %ux\n",
455                 dump[1], dump[2],
456                 dump[4], dump[3], dump[6], dump[5],
457                 dump[7], dump[8], dump[9], dump[10], dump[11]);
458 }
459
460 static char*
461 eepromlock(Ctlr *ctlr)
462 {
463         int i, j;
464
465         for(i=0; i<100; i++){
466                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | EepromLocked);
467                 for(j=0; j<100; j++){
468                         if(csr32r(ctlr, Cfg) & EepromLocked)
469                                 return 0;
470                         delay(10);
471                 }
472         }
473         return "eepromlock: timeout";
474 }
475 static void
476 eepromunlock(Ctlr *ctlr)
477 {
478         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~EepromLocked);
479 }
480 static char*
481 eepromread(Ctlr *ctlr, void *data, int count, uint off)
482 {
483         uchar *out = data;
484         u32int w;
485         int i;
486
487         w = 0;
488         for(; count > 0; count -= 2, off++){
489                 csr32w(ctlr, EepromIo, off << 2);
490                 for(i=0; i<10; i++){
491                         w = csr32r(ctlr, EepromIo);
492                         if(w & 1)
493                                 break;
494                         delay(5);
495                 }
496                 if(i == 10)
497                         return "eepromread: timeout";
498                 *out++ = w >> 16;
499                 if(count > 1)
500                         *out++ = w >> 24;
501         }
502         return 0;
503 }
504
505 static char*
506 handover(Ctlr *ctlr)
507 {
508         int i;
509
510         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
511         for(i=0; i<5; i++){
512                 if(csr32r(ctlr, Cfg) & NicReady)
513                         return 0;
514                 delay(10);
515         }
516         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
517         for(i=0; i<15000; i++){
518                 if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
519                         break;
520                 delay(10);
521         }
522         if(i >= 15000)
523                 return "handover: timeout";
524         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
525         for(i=0; i<5; i++){
526                 if(csr32r(ctlr, Cfg) & NicReady)
527                         return 0;
528                 delay(10);
529         }
530         return "handover: timeout";
531 }
532
533 static char*
534 clockwait(Ctlr *ctlr)
535 {
536         int i;
537
538         /* Set "initialization complete" bit. */
539         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
540         for(i=0; i<2500; i++){
541                 if(csr32r(ctlr, Gpc) & MacClockReady)
542                         return 0;
543                 delay(10);
544         }
545         return "clockwait: timeout";
546 }
547
548 static char*
549 poweron(Ctlr *ctlr)
550 {
551         int capoff;
552         char *err;
553
554         /* Disable L0s exit timer (NMI bug workaround). */
555         csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | DisL0Stimer);
556
557         /* Don't wait for ICH L0s (ICH bug workaround). */
558         csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | L1AnoL0Srx);
559
560         /* Set FH wait threshold to max (HW bug under stress workaround). */
561         csr32w(ctlr, Dbghpetmem, csr32r(ctlr, Dbghpetmem) | 0xffff0000);
562
563         /* Enable HAP INTA to move adapter from L1a to L0s. */
564         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | HapwakeL1A);
565
566         capoff = pcicap(ctlr->pdev, PciCapPCIe);
567         if(capoff != -1){
568                 /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
569                 if(pcicfgr16(ctlr->pdev, capoff + 0x10) & 0x2)  /* LCSR -> L1 Entry enabled. */
570                         csr32w(ctlr, Gio, csr32r(ctlr, Gio) | EnaL0S);
571                 else
572                         csr32w(ctlr, Gio, csr32r(ctlr, Gio) & ~EnaL0S);
573         }
574
575         if(ctlr->type != Type4965 && ctlr->type <= Type1000)
576                 csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | 0x00880300);
577
578         /* Wait for clock stabilization before accessing prph. */
579         if((err = clockwait(ctlr)) != nil)
580                 return err;
581
582         if((err = niclock(ctlr)) != nil)
583                 return err;
584
585         /* Enable DMA and BSM (Bootstrap State Machine). */
586         if(ctlr->type == Type4965)
587                 prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
588         else
589                 prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
590         delay(20);
591
592         /* Disable L1-Active. */
593         prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
594
595         nicunlock(ctlr);
596         return 0;
597 }
598
599 static int
600 iwlinit(Ether *edev)
601 {
602         Ctlr *ctlr;
603         char *err;
604         uchar b[2];
605         uint u;
606
607         ctlr = edev->ctlr;
608         if((err = handover(ctlr)) != nil)
609                 goto Err;
610         if((err = poweron(ctlr)) != nil)
611                 goto Err;
612         if((csr32r(ctlr, EepromGp) & 0x7) == 0){
613                 err = "bad rom signature";
614                 goto Err;
615         }
616         if((err = eepromlock(ctlr)) != nil)
617                 goto Err;
618         if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
619                 eepromunlock(ctlr);
620                 goto Err;
621         }
622         if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
623                 eepromunlock(ctlr);
624                 goto Err;
625         }
626         u = get16(b);
627         ctlr->rfcfg.type = u & 3;       u >>= 2;
628         ctlr->rfcfg.step = u & 3;       u >>= 2;
629         ctlr->rfcfg.dash = u & 3;       u >>= 4;
630         ctlr->rfcfg.txantmask = u & 15; u >>= 4;
631         ctlr->rfcfg.rxantmask = u & 15;
632         if((err = eepromread(ctlr, b, 4, 0x128)) != nil){
633                 eepromunlock(ctlr);
634                 goto Err;
635         }
636         ctlr->eeprom.crystal = get32(b);
637         eepromunlock(ctlr);
638
639         ctlr->ie = 0;
640         csr32w(ctlr, Isr, ~0);  /* clear pending interrupts */
641         csr32w(ctlr, Imr, 0);   /* no interrupts for now */
642
643         return 0;
644 Err:
645         print("iwlinit: %s\n", err);
646         return -1;
647 }
648
649 static char*
650 crackfw(FWImage *i, uchar *data, uint size, int alt)
651 {
652         uchar *p, *e;
653         FWSect *s;
654
655         memset(i, 0, sizeof(*i));
656         if(size < 4){
657 Tooshort:
658                 return "firmware image too short";
659         }
660         p = data;
661         e = p + size;
662         i->rev = get32(p); p += 4;
663         if(i->rev == 0){
664                 uvlong altmask;
665
666                 if(size < (4+64+4+4+8))
667                         goto Tooshort;
668                 if(memcmp(p, "IWL\n", 4) != 0)
669                         return "bad firmware signature";
670                 p += 4;
671                 strncpy(i->descr, (char*)p, 64);
672                 i->descr[sizeof(i->descr)-1] = 0;
673                 p += 64;
674                 i->rev = get32(p); p += 4;
675                 i->build = get32(p); p += 4;
676                 altmask = get32(p); p += 4;
677                 altmask |= (uvlong)get32(p) << 32; p += 4;
678                 while(alt > 0 && (altmask & (1ULL<<alt)) == 0)
679                         alt--;
680                 while(p < e){
681                         FWSect dummy;
682
683                         if((p + 2+2+4) > e)
684                                 goto Tooshort;
685                         switch(get16(p)){
686                         case 1: s = &i->main.text; break;
687                         case 2: s = &i->main.data; break;
688                         case 3: s = &i->init.text; break;
689                         case 4: s = &i->init.data; break;
690                         case 5: s = &i->boot.text; break;
691                         default:s = &dummy;
692                         }
693                         p += 2;
694                         if(get16(p) != alt)
695                                 s = &dummy;
696                         p += 2;
697                         s->size = get32(p); p += 4;
698                         s->data = p;
699                         if((p + s->size) > e)
700                                 goto Tooshort;
701                         p += (s->size + 3) & ~3;
702                 }
703         } else {
704                 if(((i->rev>>8) & 0xFF) < 2)
705                         return "need firmware api >= 2";
706                 if(((i->rev>>8) & 0xFF) >= 3){
707                         i->build = get32(p); p += 4;
708                 }
709                 if((p + 5*4) > e)
710                         goto Tooshort;
711                 i->main.text.size = get32(p); p += 4;
712                 i->main.data.size = get32(p); p += 4;
713                 i->init.text.size = get32(p); p += 4;
714                 i->init.data.size = get32(p); p += 4;
715                 i->boot.text.size = get32(p); p += 4;
716                 i->main.text.data = p; p += i->main.text.size;
717                 i->main.data.data = p; p += i->main.data.size;
718                 i->init.text.data = p; p += i->init.text.size;
719                 i->init.data.data = p; p += i->init.data.size;
720                 i->boot.text.data = p; p += i->boot.text.size;
721                 if(p > e)
722                         goto Tooshort;
723         }
724         return 0;
725 }
726
727 static FWImage*
728 readfirmware(char *name)
729 {
730         uchar dirbuf[sizeof(Dir)+100], *data;
731         char buf[128], *err;
732         FWImage *fw;
733         int n, r;
734         Chan *c;
735         Dir d;
736
737         if(!iseve())
738                 error(Eperm);
739         if(!waserror()){
740                 snprint(buf, sizeof buf, "/boot/%s", name);
741                 c = namec(buf, Aopen, OREAD, 0);
742                 poperror();
743         } else {
744                 snprint(buf, sizeof buf, "/lib/firmware/%s", name);
745                 c = namec(buf, Aopen, OREAD, 0);
746         }
747         if(waserror()){
748                 cclose(c);
749                 nexterror();
750         }
751         n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
752         if(n <= 0)
753                 error("can't stat firmware");
754         convM2D(dirbuf, n, &d, nil);
755         fw = smalloc(sizeof(*fw) + 16 + d.length);
756         data = (uchar*)(fw+1);
757         if(waserror()){
758                 free(fw);
759                 nexterror();
760         }
761         r = 0;
762         while(r < d.length){
763                 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
764                 if(n <= 0)
765                         break;
766                 r += n;
767         }
768         if((err = crackfw(fw, data, r, 1)) != nil)
769                 error(err);
770         poperror();
771         poperror();
772         cclose(c);
773         return fw;
774 }
775
776 typedef struct Irqwait Irqwait;
777 struct Irqwait {
778         Ctlr    *ctlr;
779         u32int  mask;
780 };
781
782 static int
783 gotirq(void *arg)
784 {
785         Irqwait *w;
786         Ctlr *ctlr;
787
788         w = arg;
789         ctlr = w->ctlr;
790         ctlr->wait.r = ctlr->wait.m & w->mask;
791         if(ctlr->wait.r){
792                 ctlr->wait.m &= ~ctlr->wait.r;
793                 return 1;
794         }
795         ctlr->wait.w = w->mask;
796         return 0;
797 }
798
799 static u32int
800 irqwait(Ctlr *ctlr, u32int mask, int timeout)
801 {
802         Irqwait w;
803
804         w.ctlr = ctlr;
805         w.mask = mask;
806         tsleep(&ctlr->wait, gotirq, &w, timeout);
807         ctlr->wait.w = 0;
808         return ctlr->wait.r & mask;
809 }
810
811 static char*
812 loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
813 {
814         uchar *dma;
815         char *err;
816
817         dma = mallocalign(size, 16, 0, 0);
818         if(dma == nil)
819                 return "no memory for dma";
820         memmove(dma, data, size);
821         coherence();
822         if((err = niclock(ctlr)) != 0){
823                 free(dma);
824                 return err;
825         }
826         csr32w(ctlr, FhTxConfig + 9*32, 0);
827         csr32w(ctlr, FhSramAddr + 9*4, dst);
828         csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
829         csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
830         csr32w(ctlr, FhTxBufStatus + 9*32,
831                 (1<<FhTxBufStatusTbNumShift) |
832                 (1<<FhTxBufStatusTbIdxShift) |
833                 FhTxBufStatusTfbdValid);
834         csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
835         nicunlock(ctlr);
836         if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
837                 free(dma);
838                 return "dma error / timeout";
839         }
840         free(dma);
841         return 0;
842 }
843
844 static int
845 txqready(void *arg)
846 {
847         TXQ *q = arg;
848         return q->n < Ntx;
849 }
850
851 static void
852 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
853 {
854         uchar *d, *c;
855         TXQ *q;
856
857         assert(qid < nelem(ctlr->tx));
858         assert(size <= Tcmdsize-4);
859
860         ilock(ctlr);
861         q = &ctlr->tx[qid];
862         while(q->n >= Ntx){
863                 iunlock(ctlr);
864                 eqlock(q);
865                 if(waserror()){
866                         qunlock(q);
867                         nexterror();
868                 }
869                 tsleep(q, txqready, q, 10);
870                 qunlock(q);
871                 ilock(ctlr);
872         }
873         q->n++;
874
875         q->b[q->i] = block;
876         c = q->c + q->i * Tcmdsize;
877         d = q->d + q->i * Tdscsize;
878
879         /* build command */
880         c[0] = code;
881         c[1] = 0;       /* flags */
882         c[2] = q->i;
883         c[3] = qid;
884
885         memmove(c+4, data, size);
886
887         size += 4;
888
889         /* build descriptor */
890         *d++ = 0;
891         *d++ = 0;
892         *d++ = 0;
893         *d++ = 1 + (block != nil); /* nsegs */
894         put32(d, PCIWADDR(c));  d += 4;
895         put16(d, size << 4); d += 2;
896         if(block != nil){
897                 size = BLEN(block);
898                 if(size > Tbufsize)
899                         size = Tbufsize;
900                 put32(d, PCIWADDR(block->rp)); d += 4;
901                 put16(d, size << 4);
902         }
903
904         coherence();
905
906         q->i = (q->i+1) % Ntx;
907         csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
908
909         iunlock(ctlr);
910 }
911
912 static void
913 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
914 {
915         qcmd(ctlr, 4, code, data, size, nil);
916 }
917
918 static void
919 setled(Ctlr *ctlr, int which, int on, int off)
920 {
921         uchar c[8];
922
923         csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
924
925         memset(c, 0, sizeof(c));
926         put32(c, 10000);
927         c[4] = which;
928         c[5] = on;
929         c[6] = off;
930         cmd(ctlr, 72, c, sizeof(c));
931 }
932
933 /*
934  * initialization which runs after the firmware has been booted up
935  */
936 static void
937 postboot(Ctlr *ctlr)
938 {
939         uchar c[8];
940         char *err;
941         int i, q;
942
943         /* main led turn on! (verify that firmware processes commands) */
944         setled(ctlr, 2, 0, 1);
945
946         if((err = niclock(ctlr)) != nil)
947                 error(err);
948         ctlr->sched.base = prphread(ctlr, SchedSramAddr);
949         for(i=0; i < SchedCtxLen5000/4; i++)
950                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + i*4, 0);
951
952         prphwrite(ctlr, SchedDramAddr5000, PCIWADDR(ctlr->sched.s)>>10);
953         csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
954
955         /* Enable chain mode for all queues, except command queue. */
956         prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
957         prphwrite(ctlr, SchedAggrSel5000, 0);
958
959         for(q=0; q<nelem(ctlr->tx); q++){
960                 prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
961                 csr32w(ctlr, HbusTargWptr, q << 8);
962                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8, 0);
963                 /* Set scheduler window size and frame limit. */
964                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8 + 4, 64<<16 | 64);
965         }
966
967         /* Enable interrupts for all our 20 queues. */
968         prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
969         /* Identify TX FIFO rings (0-7). */
970         prphwrite(ctlr, SchedTxFact5000, 0xff);
971         /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
972         for(q=0; q<7; q++){
973                 static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
974                 prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
975         }
976         nicunlock(ctlr);
977
978         if(ctlr->type != Type5150){
979                 memset(c, 0, sizeof(c));
980                 c[0] = 15;      /* code */
981                 c[1] = 0;       /* grup */
982                 c[2] = 1;       /* ngroup */
983                 c[3] = 1;       /* isvalid */
984                 put16(c+4, ctlr->eeprom.crystal);
985                 cmd(ctlr, 176, c, 8);
986         }
987
988         if(ctlr->type != Type4965){
989                 put32(c, ctlr->rfcfg.txantmask & 7);
990                 cmd(ctlr, 152, c, 4);
991         }
992 }
993
994 static void
995 addnode(Ctlr *ctlr, uchar id, uchar *addr)
996 {
997         uchar c[Tcmdsize], *p;
998
999         memset(p = c, 0, sizeof(c));
1000         *p++ = 0;       /* control (1 = update) */
1001         p += 3;         /* reserved */
1002         memmove(p, addr, 6);
1003         p += 6;
1004         p += 2;         /* reserved */
1005         *p++ = id;      /* node id */
1006         p++;            /* flags */
1007         p += 2;         /* reserved */
1008         p += 2;         /* kflags */
1009         p++;            /* tcs2 */
1010         p++;            /* reserved */
1011         p += 5*2;       /* ttak */
1012         p++;            /* kid */
1013         p++;            /* reserved */
1014         p += 16;        /* key */
1015         if(ctlr->type != Type4965){
1016                 p += 8;         /* tcs */
1017                 p += 8;         /* rxmic */
1018                 p += 8;         /* txmic */
1019                 p += 4;         /* htflags */
1020                 p += 4;         /* mask */
1021                 p += 2;         /* disable tid */
1022                 p += 2;         /* reserved */
1023                 p++;            /* add ba tid */
1024                 p++;            /* del ba tid */
1025                 p += 2;         /* add ba ssn */
1026                 p += 4;         /* reserved */
1027         }
1028         cmd(ctlr, 24, c, p - c);
1029 }
1030
1031 void
1032 rxon(Ether *edev)
1033 {
1034         uchar c[Tcmdsize], *p;
1035         Ctlr *ctlr;
1036
1037         ctlr = edev->ctlr;
1038         memset(p = c, 0, sizeof(c));
1039         memmove(p, edev->ea, 6); p += 8;        /* myaddr */
1040         p += 8;                                 /* bssid */
1041         memmove(p, edev->ea, 6); p += 8;        /* wlap */
1042         *p++ = 3;                               /* mode */
1043         *p++ = 0;                               /* air (?) */
1044         /* rxchain */
1045         put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
1046         p += 2;
1047         *p++ = 0xff;                            /* ofdm mask (not yet negotiated) */
1048         *p++ = 0x0f;                            /* cck mask (not yet negotiated) */
1049         p += 2;                                 /* associd (?) */
1050         put32(p, (1<<15)|(1<<30)|(1<<0));       /* flags (TSF | CTS_TO_SELF | 24GHZ) */
1051         p += 4;
1052         put32(p, 4|1);                          /* filter (MULTICAST|PROMISC) */
1053         p += 4;
1054         *p++ = ctlr->channel;                   /* chan */
1055         p++;                                    /* reserved */
1056         *p++ = 0xff;                            /* ht single mask */
1057         *p++ = 0xff;                            /* ht dual mask */
1058         if(ctlr->type != Type4965){
1059                 *p++ = 0xff;                    /* ht triple mask */
1060                 p++;                            /* reserved */
1061                 put16(p, 0); p += 2;            /* acquisition */
1062                 p += 2;                         /* reserved */
1063         }
1064         cmd(ctlr, 16, c, p - c);
1065 }
1066
1067 static struct ratetab {
1068         uchar   rate;
1069         uchar   plcp;
1070         uchar   flags;
1071 } ratetab[] = {
1072         {   2,  10, 1<<1 },
1073         {   4,  20, 1<<1 },
1074         {  11,  55, 1<<1 },
1075         {  22, 110, 1<<1 },
1076         {  12, 0xd, 0 },
1077         {  18, 0xf, 0 },
1078         {  24, 0x5, 0 },
1079         {  36, 0x7, 0 },
1080         {  48, 0x9, 0 },
1081         {  72, 0xb, 0 },
1082         {  96, 0x1, 0 },
1083         { 108, 0x3, 0 },
1084         { 120, 0x3, 0 }
1085 };
1086
1087 static void
1088 transmit(Wifi *wifi, Wnode *, Block *b)
1089 {
1090         uchar c[Tcmdsize], *p;
1091         Ctlr *ctlr;
1092
1093         ctlr = wifi->ether->ctlr;
1094
1095         memset(p = c, 0, sizeof(c));
1096         put16(p, BLEN(b));
1097         p += 2;
1098         p += 2;         /* lnext */
1099         put32(p, 0);    /* flags */
1100         p += 4;
1101         put32(p, 0);
1102         p += 4;         /* scratch */
1103         *p++ = ratetab[2].plcp;                 /* plcp */
1104         *p++ = ratetab[2].flags | (1<<6);       /* rflags */
1105         p += 2;         /* xflags */
1106         *p++ = 15;      /* id (5000 only) */
1107         *p++ = 0;       /* security */
1108         *p++ = 0;       /* linkq */
1109         p++;            /* reserved */
1110         p += 16;        /* key */
1111         p += 2;         /* fnext */
1112         p += 2;         /* reserved */
1113         put32(p, ~0);   /* lifetime */
1114         p += 4;
1115         /* scratch ptr? not clear what this is for */
1116         put32(p, PCIWADDR(ctlr->kwpage));
1117         p += 5;
1118         *p++ = 60;      /* rts ntries */
1119         *p++ = 15;      /* data ntries */
1120         *p++ = 0;       /* tid */
1121         put16(p, 0);    /* timeout */
1122         p += 2;
1123         p += 2;         /* txop */
1124         qcmd(ctlr, 0, 28, c, p - c, b);
1125 }
1126
1127 static int
1128 rbplant(Ctlr *ctlr, int i)
1129 {
1130         Block *b;
1131
1132         b = iallocb(Rbufsize + 256);
1133         if(b == nil)
1134                 return -1;
1135         b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
1136         memset(b->rp, 0, Rdscsize);
1137         ctlr->rx.b[i] = b;
1138         ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
1139         return 0;
1140 }
1141
1142 static long
1143 iwlctl(Ether *edev, void *buf, long n)
1144 {
1145         Ctlr *ctlr;
1146
1147         ctlr = edev->ctlr;
1148         if(ctlr->wifi)
1149                 return wifictl(ctlr->wifi, buf, n);
1150         return 0;
1151 }
1152
1153 static long
1154 iwlifstat(Ether *edev, void *buf, long n, ulong off)
1155 {
1156         Ctlr *ctlr;
1157
1158         ctlr = edev->ctlr;
1159         if(ctlr->wifi)
1160                 return wifistat(ctlr->wifi, buf, n, off);
1161         return 0;
1162 }
1163
1164 static void
1165 setoptions(Ether *edev)
1166 {
1167         Ctlr *ctlr;
1168         char buf[64];
1169         int i;
1170
1171         ctlr = edev->ctlr;
1172         ctlr->channel = 3;
1173         for(i = 0; i < edev->nopt; i++){
1174                 if(strncmp(edev->opt[i], "channel=", 8) == 0)
1175                         ctlr->channel = atoi(edev->opt[i]+8);
1176                 else
1177                 if(strncmp(edev->opt[i], "essid=", 6) == 0){
1178                         snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
1179                         if(!waserror()){
1180                                 wifictl(ctlr->wifi, buf, strlen(buf));
1181                                 poperror();
1182                         }
1183                 }
1184         }
1185 }
1186
1187 static void
1188 iwlattach(Ether *edev)
1189 {
1190         FWImage *fw;
1191         Ctlr *ctlr;
1192         char *err;
1193         RXQ *rx;
1194         TXQ *tx;
1195         int i, q;
1196
1197         ctlr = edev->ctlr;
1198         eqlock(ctlr);
1199         if(waserror()){
1200                 qunlock(ctlr);
1201                 nexterror();
1202         }
1203         if(ctlr->attached == 0){
1204                 if(ctlr->wifi == nil)
1205                         ctlr->wifi = wifiattach(edev, transmit);
1206
1207                 if(ctlr->fw == nil){
1208                         fw = readfirmware("iwn-5000");
1209                         print("#l%d: firmware: rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
1210                                 edev->ctlrno,
1211                                 fw->rev, fw->build,
1212                                 fw->main.text.size, fw->main.data.size,
1213                                 fw->init.text.size, fw->init.data.size,
1214                                 fw->boot.text.size);
1215                         ctlr->fw = fw;
1216                 }
1217
1218                 rx = &ctlr->rx;
1219                 rx->i = 0;
1220                 if(rx->b == nil)
1221                         rx->b = malloc(sizeof(Block*) * Nrx);
1222                 if(rx->p == nil)
1223                         rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
1224                 if(rx->s == nil)
1225                         rx->s = mallocalign(Rstatsize, 16, 0, 0);
1226                 if(rx->b == nil || rx->p == nil || rx->s == nil)
1227                         error("no memory for rx ring");
1228                 memset(rx->s, 0, Rstatsize);
1229                 for(i=0; i<Nrx; i++){
1230                         rx->p[i] = 0;
1231                         if(rx->b[i] != nil){
1232                                 freeb(rx->b[i]);
1233                                 rx->b[i] = nil;
1234                         }
1235                         if(rbplant(ctlr, i) < 0)
1236                                 error("no memory for rx descriptors");
1237                 }
1238
1239                 for(q=0; q<nelem(ctlr->tx); q++){
1240                         tx = &ctlr->tx[q];
1241                         tx->i = 0;
1242                         tx->n = 0;
1243                         if(tx->b == nil)
1244                                 tx->b = malloc(sizeof(Block*) * Ntx);
1245                         if(tx->d == nil)
1246                                 tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
1247                         if(tx->c == nil)
1248                                 tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
1249                         if(tx->b == nil || tx->d == nil || tx->c == nil)
1250                                 error("no memory for tx ring");
1251                         memset(tx->d, 0, Tdscsize * Ntx);
1252                 }
1253
1254                 if(ctlr->sched.s == nil)
1255                         ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
1256                 if(ctlr->kwpage == nil)
1257                         ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
1258
1259                 if((err = niclock(ctlr)) != nil)
1260                         error(err);
1261                 prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
1262                 nicunlock(ctlr);
1263
1264                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
1265
1266                 if((err = niclock(ctlr)) != nil)
1267                         error(err);
1268                 prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
1269                 nicunlock(ctlr);
1270
1271                 if((err = niclock(ctlr)) != nil)
1272                         error(err);
1273                 csr32w(ctlr, FhRxConfig, 0);
1274                 csr32w(ctlr, FhRxWptr, 0);
1275                 csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
1276                 csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
1277                 csr32w(ctlr, FhRxConfig,
1278                         FhRxConfigEna | 
1279                         FhRxConfigIgnRxfEmpty |
1280                         FhRxConfigIrqDstHost | 
1281                         FhRxConfigSingleFrame |
1282                         (Nrxlog << FhRxConfigNrbdShift));
1283                 csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
1284                 nicunlock(ctlr);
1285
1286                 if((err = niclock(ctlr)) != nil)
1287                         error(err);
1288                 prphwrite(ctlr, SchedTxFact5000, 0);
1289                 csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
1290                 for(q=0; q<nelem(ctlr->tx); q++)
1291                         csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
1292                 nicunlock(ctlr);
1293                 for(i=0; i<8; i++)
1294                         csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
1295                 csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1296                 csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
1297
1298                 ctlr->ie = Idefmask;
1299                 csr32w(ctlr, Imr, ctlr->ie);
1300                 csr32w(ctlr, Isr, ~0);
1301
1302                 if(ctlr->type >= Type6000)
1303                         csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
1304
1305                 if((err = loadfirmware1(ctlr, 0x00000000, ctlr->fw->main.text.data, ctlr->fw->main.text.size)) != nil)
1306                         error(err);
1307                 if((err = loadfirmware1(ctlr, 0x00800000, ctlr->fw->main.data.data, ctlr->fw->main.data.size)) != nil)
1308                         error(err);
1309
1310                 csr32w(ctlr, Reset, 0);
1311                 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
1312                         error("firmware boot failed");
1313
1314                 postboot(ctlr);
1315
1316                 setoptions(edev);
1317
1318                 rxon(edev);
1319                 addnode(ctlr, 15, edev->bcast);
1320
1321                 edev->prom = 1;
1322                 edev->link = 1;
1323                 ctlr->attached = 1;
1324         }
1325         qunlock(ctlr);
1326         poperror();
1327 }
1328
1329 static void
1330 receive(Ctlr *ctlr)
1331 {
1332         Block *b, *bb;
1333         uchar *d, *dd, *cc;
1334         RXQ *rx;
1335         TXQ *tx;
1336         uint hw;
1337
1338         rx = &ctlr->rx;
1339         if(rx->s == nil || rx->b == nil)
1340                 return;
1341         for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
1342                 uchar type, flags, idx, qid;
1343                 u32int len;
1344
1345                 b = rx->b[rx->i];
1346                 if(b == nil)
1347                         continue;
1348
1349                 d = b->rp;
1350                 len = get32(d); d += 4;
1351                 type = *d++;
1352                 flags = *d++;
1353                 USED(flags);
1354                 idx = *d++;
1355                 qid = *d++;
1356
1357                 if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
1358                         tx = &ctlr->tx[qid];
1359                         if(tx->n > 0){
1360                                 bb = tx->b[idx];
1361                                 if(bb != nil){
1362                                         tx->b[idx] = nil;
1363                                         freeb(bb);
1364                                 }
1365                                 /* paranoia: clear tx descriptors */
1366                                 dd = tx->d + idx*Tdscsize;
1367                                 cc = tx->c + idx*Tcmdsize;
1368                                 memset(dd, 0, Tdscsize);
1369                                 memset(cc, 0, Tcmdsize);
1370                                 tx->n--;
1371
1372                                 wakeup(tx);
1373                         }
1374                 }
1375
1376                 len &= 0x3fff;
1377                 if(len < 4 || type == 0)
1378                         continue;
1379
1380                 len -= 4;
1381                 switch(type){
1382                 case 1:         /* microcontroller ready */
1383                         setfwinfo(ctlr, d, len);
1384                         break;
1385                 case 24:        /* add node done */
1386                         break;
1387                 case 28:        /* tx done */
1388                         break;
1389                 case 102:       /* calibration result (Type5000 only)
1390                         break;
1391                 case 103:       /* calibration done (Type5000 only)
1392                         break;
1393                 case 130:       /* start scan */
1394                         break;
1395                 case 132:       /* stop scan */
1396                         break;
1397                 case 156:       /* rx statistics */
1398                         break;
1399                 case 157:       /* beacon statistics */
1400                         break;
1401                 case 161:       /* state changed */
1402                         break;
1403                 case 162:       /* beacon missed */
1404                         break;
1405                 case 192:       /* rx phy */
1406                         break;
1407                 case 195:       /* rx done */
1408                         if(d + 60 > b->lim)
1409                                 break;
1410                         d += 60;
1411                 case 193:       /* mpdu rx done */
1412                         if(d + 4 > b->lim)
1413                                 break;
1414                         len = get16(d); d += 4;
1415                         if(d + len + 4 > b->lim)
1416                                 break;
1417                         if((get32(d + len) & 3) != 3)
1418                                 break;
1419                         if(ctlr->wifi == nil)
1420                                 break;
1421                         if(rbplant(ctlr, rx->i) < 0)
1422                                 break;
1423                         b->rp = d;
1424                         b->wp = d + len;
1425                         wifiiq(ctlr->wifi, b);
1426                         continue;
1427                 case 197:       /* rx compressed ba */
1428                         break;
1429                 }
1430                 /* paranoia: clear the descriptor */
1431                 memset(b->rp, 0, Rdscsize);
1432         }
1433         csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
1434 }
1435
1436 static void
1437 iwlinterrupt(Ureg*, void *arg)
1438 {
1439         u32int isr, fhisr;
1440         Ether *edev;
1441         Ctlr *ctlr;
1442
1443         edev = arg;
1444         ctlr = edev->ctlr;
1445         ilock(ctlr);
1446         csr32w(ctlr, Imr, 0);
1447         isr = csr32r(ctlr, Isr);
1448         fhisr = csr32r(ctlr, FhIsr);
1449         if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
1450                 iunlock(ctlr);
1451                 return;
1452         }
1453         if(isr == 0 && fhisr == 0)
1454                 goto done;
1455         csr32w(ctlr, Isr, isr);
1456         csr32w(ctlr, FhIsr, fhisr);
1457         if((isr & (Iswrx | Ifhrx | Irxperiodic)) || (fhisr & Ifhrx))
1458                 receive(ctlr);
1459         if(isr & Ierr){
1460                 iprint("#l%d: fatal firmware error\n", edev->ctlrno);
1461                 dumpctlr(ctlr);
1462         }
1463         ctlr->wait.m |= isr;
1464         if(ctlr->wait.m & ctlr->wait.w){
1465                 ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
1466                 ctlr->wait.m &= ~ctlr->wait.r;
1467                 wakeup(&ctlr->wait);
1468         }
1469 done:
1470         csr32w(ctlr, Imr, ctlr->ie);
1471         iunlock(ctlr);
1472 }
1473
1474 static Ctlr *iwlhead, *iwltail;
1475
1476 static void
1477 iwlpci(void)
1478 {
1479         Pcidev *pdev;
1480         
1481         pdev = nil;
1482         while(pdev = pcimatch(pdev, 0, 0)) {
1483                 Ctlr *ctlr;
1484                 void *mem;
1485                 
1486                 if(pdev->ccrb != 2 || pdev->ccru != 0x80)
1487                         continue;
1488                 if(pdev->vid != 0x8086)
1489                         continue;
1490
1491                 switch(pdev->did){
1492                 default:
1493                         continue;
1494                 case 0x4236:    /* WiFi Link 5300 AGN */
1495                         break;
1496                 }
1497
1498                 /* Clear device-specific "PCI retry timeout" register (41h). */
1499                 if(pcicfgr8(pdev, 0x41) != 0)
1500                         pcicfgw8(pdev, 0x41, 0);
1501
1502                 /* Clear interrupt disable bit. Hardware bug workaround. */
1503                 if(pdev->pcr & 0x400){
1504                         pdev->pcr &= ~0x400;
1505                         pcicfgw16(pdev, PciPCR, pdev->pcr);
1506                 }
1507
1508                 pcisetbme(pdev);
1509                 pcisetpms(pdev, 0);
1510
1511                 ctlr = malloc(sizeof(Ctlr));
1512                 if(ctlr == nil) {
1513                         print("iwl: unable to alloc Ctlr\n");
1514                         continue;
1515                 }
1516                 ctlr->port = pdev->mem[0].bar & ~0x0F;
1517                 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
1518                 if(mem == nil) {
1519                         print("iwl: can't map %8.8luX\n", pdev->mem[0].bar);
1520                         free(ctlr);
1521                         continue;
1522                 }
1523                 ctlr->nic = mem;
1524                 ctlr->pdev = pdev;
1525                 ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
1526
1527                 if(iwlhead != nil)
1528                         iwltail->link = ctlr;
1529                 else
1530                         iwlhead = ctlr;
1531                 iwltail = ctlr;
1532         }
1533 }
1534
1535 static int
1536 iwlpnp(Ether* edev)
1537 {
1538         Ctlr *ctlr;
1539         
1540         if(iwlhead == nil)
1541                 iwlpci();
1542 again:
1543         for(ctlr = iwlhead; ctlr != nil; ctlr = ctlr->link){
1544                 if(ctlr->active)
1545                         continue;
1546                 if(edev->port == 0 || edev->port == ctlr->port){
1547                         ctlr->active = 1;
1548                         break;
1549                 }
1550         }
1551
1552         if(ctlr == nil)
1553                 return -1;
1554
1555         edev->ctlr = ctlr;
1556         edev->port = ctlr->port;
1557         edev->irq = ctlr->pdev->intl;
1558         edev->tbdf = ctlr->pdev->tbdf;
1559         edev->arg = edev;
1560         edev->interrupt = iwlinterrupt;
1561         edev->attach = iwlattach;
1562         edev->ifstat = iwlifstat;
1563         edev->ctl = iwlctl;
1564         edev->promiscuous = nil;
1565         edev->multicast = nil;
1566         edev->mbps = 10;
1567
1568         if(iwlinit(edev) < 0){
1569                 edev->ctlr = nil;
1570                 goto again;
1571         }
1572         
1573         return 0;
1574 }
1575
1576 void
1577 etheriwllink(void)
1578 {
1579         addethercard("iwl", iwlpnp);
1580 }