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