]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etheriwl.c
f003b5da7160b138366345decf87b4213b121d69
[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) and iwm(4) driver sources. Requires intel
6  * firmware 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/pci.h"
16 #include "../port/error.h"
17 #include "../port/netif.h"
18 #include "../port/etherif.h"
19 #include "../port/wifi.h"
20
21 enum {
22         MaxQueue        = 24*1024,      /* total buffer is 2*MaxQueue: 48k at 22Mbit ≅ 20ms */
23
24         Ntxlog          = 8,
25         Ntx             = 1<<Ntxlog,
26         Ntxqmax         = MaxQueue/1500,
27
28         Nrxlog          = 8,
29         Nrx             = 1<<Nrxlog,
30
31         Rstatsize       = 16,
32
33         Rbufsize        = 4*1024,
34         Rdscsize        = 8,
35
36         Tdscsize        = 128,
37         Tcmdsize        = 140,
38
39         FWPageshift     = 12,
40         FWPagesize      = 1<<FWPageshift,
41         FWBlockshift    = 3,
42         FWBlockpages    = 1<<FWBlockshift,
43         FWBlocksize     = 1<<(FWBlockshift + FWPageshift),
44 };
45
46 /* registers */
47 enum {
48         Cfg             = 0x000,        /* config register */
49                 CfgMacDashShift = 0,
50                 CfgMacDashMask  = 3<<CfgMacDashShift,
51                 CfgMacStepShift = 2,
52                 CfgMacStepMask  = 3<<CfgMacStepShift,
53
54                 MacSi           = 1<<8,
55                 RadioSi         = 1<<9,
56
57                 CfgPhyTypeShift = 10,
58                 CfgPhyTypeMask  = 3<<CfgPhyTypeShift,
59                 CfgPhyDashShift = 12,
60                 CfgPhyDashMask  = 3<<CfgPhyDashShift,
61                 CfgPhyStepShift = 14,
62                 CfgPhyStepMask  = 3<<CfgPhyStepShift,
63
64                 EepromLocked    = 1<<21,
65                 NicReady        = 1<<22,
66                 HapwakeL1A      = 1<<23,
67                 PrepareDone     = 1<<25,
68                 Prepare         = 1<<27,
69                 EnablePme       = 1<<28,
70
71         Isr             = 0x008,        /* interrupt status */
72         Imr             = 0x00c,        /* interrupt mask */
73                 Ialive          = 1<<0,
74                 Iwakeup         = 1<<1,
75                 Iswrx           = 1<<3,
76                 Ictreached      = 1<<6,
77                 Irftoggled      = 1<<7,
78                 Iswerr          = 1<<25,
79                 Isched          = 1<<26,
80                 Ifhtx           = 1<<27,
81                 Irxperiodic     = 1<<28,
82                 Ihwerr          = 1<<29,
83                 Ifhrx           = 1<<31,
84
85                 Ierr            = Iswerr | Ihwerr,
86                 Idefmask        = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled,
87
88         FhIsr           = 0x010,        /* second interrupt status */
89
90         Reset           = 0x020,
91                 
92         Rev             = 0x028,        /* hardware revision */
93
94         EepromIo        = 0x02c,        /* EEPROM i/o register */
95         EepromGp        = 0x030,
96                 
97         OtpromGp        = 0x034,
98                 DevSelOtp       = 1<<16,
99                 RelativeAccess  = 1<<17,
100                 EccCorrStts     = 1<<20,
101                 EccUncorrStts   = 1<<21,
102
103         Gpc             = 0x024,        /* gp cntrl */
104                 MacAccessEna    = 1<<0,
105                 MacClockReady   = 1<<0,
106                 InitDone        = 1<<2,
107                 MacAccessReq    = 1<<3,
108                 NicSleep        = 1<<4,
109                 RfKill          = 1<<27,
110
111         Gio             = 0x03c,
112                 EnaL0S          = 1<<1,
113
114         GpDrv   = 0x050,
115                 GpDrvCalV6      = 1<<2,
116                 GpDrv1X2        = 1<<3,
117                 GpDrvRadioIqInvert      = 1<<7, 
118
119         Led             = 0x094,
120                 LedBsmCtrl      = 1<<5,
121                 LedOn           = 0x38,
122                 LedOff          = 0x78,
123
124         UcodeGp1Clr     = 0x05c,
125                 UcodeGp1RfKill          = 1<<1,
126                 UcodeGp1CmdBlocked      = 1<<2,
127                 UcodeGp1CtempStopRf     = 1<<3,
128
129         ShadowRegCtrl   = 0x0a8,
130
131         MboxSet = 0x088,
132                 MboxSetOsAlive  = 1<<5,
133
134         Giochicken      = 0x100,
135                 L1AnoL0Srx      = 1<<23,
136                 DisL0Stimer     = 1<<29,
137
138         AnaPll          = 0x20c,
139
140         Dbghpetmem      = 0x240,
141         Dbglinkpwrmgmt  = 0x250,
142
143         MemRaddr        = 0x40c,
144         MemWaddr        = 0x410,
145         MemWdata        = 0x418,
146         MemRdata        = 0x41c,
147
148         PrphWaddr       = 0x444,
149         PrphRaddr       = 0x448,
150         PrphWdata       = 0x44c,
151         PrphRdata       = 0x450,
152
153         HbusTargWptr    = 0x460,
154
155         UcodeLoadStatus = 0x1af0,
156 };
157
158 /*
159  * Flow-Handler registers.
160  */
161 enum {
162         FhTfbdCtrl0     = 0x1900,       // +q*8
163         FhTfbdCtrl1     = 0x1904,       // +q*8
164
165         FhKwAddr        = 0x197c,
166
167         FhSramAddr      = 0x19a4,       // +q*4
168
169         FhCbbcQueue0    = 0x19d0,       // +q*4
170         FhCbbcQueue16   = 0x1bf0,       // +q*4
171         FhCbbcQueue20   = 0x1b20,       // +q*4
172
173         FhStatusWptr    = 0x1bc0,
174         FhRxBase        = 0x1bc4,
175         FhRxWptr        = 0x1bc8,
176         FhRxConfig      = 0x1c00,
177                 FhRxConfigEna           = 1<<31,
178                 FhRxConfigRbSize8K      = 1<<16,
179                 FhRxConfigSingleFrame   = 1<<15,
180                 FhRxConfigIrqDstHost    = 1<<12,
181                 FhRxConfigIgnRxfEmpty   = 1<<2,
182
183                 FhRxConfigNrbdShift     = 20,
184                 FhRxConfigRbTimeoutShift= 4,
185
186         FhRxStatus      = 0x1c44,
187
188         FhRxQ0Wptr      = 0x1c80,       // +q*4 (9000 mqrx)
189
190         FhTxConfig      = 0x1d00,       // +q*32
191                 FhTxConfigDmaCreditEna  = 1<<3,
192                 FhTxConfigDmaEna        = 1<<31,
193                 FhTxConfigCirqHostEndTfd= 1<<20,
194
195         FhTxBufStatus   = 0x1d08,       // +q*32
196                 FhTxBufStatusTbNumShift = 20,
197                 FhTxBufStatusTbIdxShift = 12,
198                 FhTxBufStatusTfbdValid  = 3,
199
200         FhTxChicken     = 0x1e98,
201
202         FhTxStatus      = 0x1eb0,
203         FhTxErrors      = 0x1eb8,
204 };
205
206 /*
207  * NIC internal memory offsets.
208  */
209 enum {
210         ApmgClkCtrl     = 0x3000,
211         ApmgClkEna      = 0x3004,
212         ApmgClkDis      = 0x3008,
213                 DmaClkRqt       = 1<<9,
214                 BsmClkRqt       = 1<<11,
215
216         ApmgPs          = 0x300c,
217                 EarlyPwroffDis  = 1<<22,
218                 PwrSrcVMain     = 0<<24,
219                 PwrSrcVAux      = 2<<24,
220                 PwrSrcMask      = 3<<24,
221                 ResetReq        = 1<<26,
222
223         ApmgDigitalSvr  = 0x3058,
224         ApmgAnalogSvr   = 0x306c,
225         ApmgPciStt      = 0x3010,
226         BsmWrCtrl       = 0x3400,
227         BsmWrMemSrc     = 0x3404,
228         BsmWrMemDst     = 0x3408,
229         BsmWrDwCount    = 0x340c,
230         BsmDramTextAddr = 0x3490,
231         BsmDramTextSize = 0x3494,
232         BsmDramDataAddr = 0x3498,
233         BsmDramDataSize = 0x349c,
234         BsmSramBase     = 0x3800,
235
236         /* 8000 family */
237         ReleaseCpuReset = 0x300c,
238                 CpuResetBit = 0x1000000,
239
240         LmpmChick       = 0xa01ff8,
241                 ExtAddr = 1,
242
243         SbCpu1Status    = 0xa01e30,
244         SbCpu2Status    = 0xa01e34,
245         UregChick       = 0xa05c00,
246                 UregChickMsiEnable      = 1<<24,
247
248         FhUcodeLoadStatus=0xa05c40,
249 };
250
251 /*
252  * RX ring for mqrx 9000
253 */
254 enum {
255         RfhQ0FreeBase   = 0xa08000,     // +q*8
256         RfhQ0FreeWptr   = 0xa08080,     // +q*4
257         RfhQ0FreeRptr   = 0xa080c0,     // +q*4
258
259         RfhQ0UsedBase   = 0xa08100,     // +q*8
260         RfhQ0UsedWptr   = 0xa08180,     // +q*4
261
262         RfhQ0SttsBase   = 0xa08200,     // +q*8
263
264         RfhGenCfg       = 0xa09800,
265                 RfhGenServiceDmaSnoop   = 1<<0,
266                 RfhGenRfhDmaSnoop       = 1<<1,
267                 RfhGenRbChunkSize64     = 0<<4,
268                 RfhGenRbChunkSize128    = 1<<4,
269
270         RfhGenStatus    = 0xa09808,
271                 RfhGenStatusDmaIdle     = 1<<31,
272
273         RfhRxqActive    = 0xa0980c,
274
275         RfhDmaCfg       = 0xa09820,
276                 RfhDma1KSizeShift       = 16,
277                 RfhDmaNrbdShift         = 20,
278                 RfhDmaMinRbSizeShift    = 24,
279                 RfhDmaDropTooLarge      = 1<<26,
280                 RfhDmaEnable            = 1<<31,
281 };
282
283 /*
284  * TX scheduler registers.
285  */
286 enum {
287         SchedBase               = 0xa02c00,
288         SchedSramAddr           = SchedBase,
289
290         SchedDramAddr4965       = SchedBase+0x010,
291         SchedTxFact4965         = SchedBase+0x01c,
292         SchedQueueRdptr4965     = SchedBase+0x064,      // +q*4
293         SchedQChainSel4965      = SchedBase+0x0d0,
294         SchedIntrMask4965       = SchedBase+0x0e4,
295         SchedQueueStatus4965    = SchedBase+0x104,      // +q*4
296
297         SchedDramAddr           = SchedBase+0x008,
298         SchedTxFact             = SchedBase+0x010,
299         SchedQueueWrptr         = SchedBase+0x018,      // +q*4
300         SchedQueueRdptr         = SchedBase+0x068,      // +q*4
301         SchedQChainSel          = SchedBase+0x0e8,
302         SchedIntrMask           = SchedBase+0x108,
303
304         SchedQueueStatus        = SchedBase+0x10c,      // +q*4
305
306         SchedGpCtrl             = SchedBase+0x1a8,
307                 Enable31Queues  = 1<<0,
308                 AutoActiveMode  = 1<<18,
309
310         SchedChainExtEn         = SchedBase+0x244,
311         SchedAggrSel            = SchedBase+0x248,
312         SchedEnCtrl             = SchedBase+0x254,
313
314         SchedQueueRdptr20       = SchedBase+0x2b4,      // +q*4
315         SchedQueueStatus20      = SchedBase+0x334,      // +q*4
316 };
317
318 enum {
319         SchedCtxOff4965         = 0x380,
320         SchedCtxLen4965         = 416,
321
322         SchedCtxOff             = 0x600,                // +q*8
323
324         SchedSttsOff            = 0x6A0,                // +q*16
325
326         SchedTransTblOff        = 0x7E0,                // +q*2
327 };
328
329 enum {
330         FilterPromisc           = 1<<0,
331         FilterCtl               = 1<<1,
332         FilterMulticast         = 1<<2,
333         FilterNoDecrypt         = 1<<3,
334         FilterNoDecryptMcast    = 1<<4,
335         FilterBSS               = 1<<5,
336         FilterBeacon            = 1<<6,
337 };
338
339 enum {
340         RFlag24Ghz              = 1<<0,
341         RFlagCCK                = 1<<1,
342         RFlagAuto               = 1<<2,
343         RFlagShSlot             = 1<<4,
344         RFlagShPreamble         = 1<<5,
345         RFlagNoDiversity        = 1<<7,
346         RFlagAntennaA           = 1<<8,
347         RFlagAntennaB           = 1<<9,
348         RFlagTSF                = 1<<15,
349         RFlagCTSToSelf          = 1<<30,
350 };
351
352 enum {
353         TFlagNeedProtection     = 1<<0,
354                 TFlagNeedRTS            = 1<<1,
355                 TFlagNeedCTS            = 1<<2,
356         TFlagNeedACK            = 1<<3,
357         TFlagLinkq              = 1<<4,
358         TFlagImmBa              = 1<<6,
359         TFlagFullTxOp           = 1<<7,
360         TFlagBtDis              = 1<<12,
361         TFlagAutoSeq            = 1<<13,
362         TFlagMoreFrag           = 1<<14,
363         TFlagInsertTs           = 1<<16,
364         TFlagNeedPadding        = 1<<20,
365 };
366
367 enum {
368         CmdAdd = 1,
369         CmdModify,
370         CmdRemove,
371 };
372
373 typedef struct FWInfo FWInfo;
374 typedef struct FWImage FWImage;
375 typedef struct FWSect FWSect;
376 typedef struct FWBlock FWBlock;
377 typedef struct FWMem FWMem;
378
379 typedef struct TXQ TXQ;
380 typedef struct RXQ RXQ;
381
382 typedef struct Station Station;
383
384 typedef struct Ctlr Ctlr;
385
386 struct FWSect
387 {
388         uchar   *data;
389         uint    addr;
390         uint    size;
391 };
392
393 struct FWImage
394 {
395         struct {
396                 int     nsect;
397                 union {
398                         struct {
399                                 FWSect  text;
400                                 FWSect  data;
401                         };
402                         FWSect  sect[16];
403                 };
404                 struct {
405                         u32int  flowmask;
406                         u32int  eventmask;
407                 } defcalib;
408         } init, main;
409
410         struct {
411                 FWSect  text;
412         } boot;
413
414         uint    rev;
415         uint    build;
416         char    descr[64+1];
417
418         u32int  capa[4];
419         u32int  api[4];
420
421         u32int  physku;
422
423         u32int  pagedmemsize;
424
425         uchar   data[];
426 };
427
428 struct FWInfo
429 {
430         int     valid;
431
432         u16int  status;
433         u16int  flags;
434
435         u32int  major;
436         u32int  minor;
437         uchar   type;
438         uchar   subtype;
439
440         u32int  scdptr;
441         u32int  regptr;
442         u32int  logptr;
443         u32int  errptr;
444         u32int  tstamp;
445
446         struct {
447                 u32int  major;
448                 u32int  minor;
449                 u32int  errptr;
450                 u32int  logptr;
451         } umac;
452 };
453
454 struct FWBlock
455 {
456         uint    size;
457         uchar   *p;
458 };
459
460 struct FWMem
461 {
462         uchar   *css;
463
464         uint    npage;
465         uint    nblock;
466
467         FWBlock block[32];
468 };
469
470 struct TXQ
471 {
472         uint    n;
473         uint    i;
474         Block   **b;
475         uchar   *d;
476         uchar   *c;
477
478         uint    lastcmd;
479
480         Rendez;
481         QLock;
482 };
483
484 struct RXQ
485 {
486         uint    i;
487         Block   **b;
488         uchar   *s;
489         uchar   *p;
490         uchar   *u;
491 };
492
493 struct Station
494 {
495         int     id;
496 };
497
498 struct Ctlr {
499         Lock;
500         QLock;
501
502         Ctlr *link;
503         uvlong port;
504         Pcidev *pdev;
505         Ether *edev;
506         Wifi *wifi;
507
508         char *fwname;
509         int mqrx;
510         int family;
511         int type;
512         uint step;
513         uint dash;
514
515         int power;
516         int broken;
517         int attached;
518
519         u32int ie;
520
521         u32int *nic;
522         uchar *kwpage;
523
524         /* assigned sta ids in hardware sta table or -1 if unassigned */
525         Station bcast;
526         Station bss;
527
528         u32int rxflags;
529         u32int rxfilter;
530
531         int phyid;
532         int macid;
533         int bindid;
534
535         /* current receiver settings */
536         uchar bssid[Eaddrlen];
537         int channel;
538         int prom;
539         int aid;
540
541         struct {
542                 Rendez;
543                 int id;
544                 int active;
545         } te;
546
547         uvlong systime;
548
549         RXQ rx;
550         TXQ tx[7];
551
552         int ndma;
553         int ntxq;
554
555         struct {
556                 Rendez;
557                 u32int  m;
558                 u32int  w;
559         } wait;
560
561         struct {
562                 uchar   type;
563                 uchar   step;
564                 uchar   dash;
565                 uchar   pnum;
566                 uchar   txantmask;
567                 uchar   rxantmask;
568         } rfcfg;
569
570         struct {
571                 int     otp;
572                 uint    off;
573
574                 uchar   version;
575                 uchar   type;
576                 u16int  volt;
577                 u16int  temp;
578                 u16int  rawtemp;
579
580                 char    regdom[4+1];
581
582                 u32int  crystal;
583         } eeprom;
584
585         struct {
586                 u32int  version;
587
588                 void    *buf;
589                 int     len;
590
591                 int     off;
592                 int     ret;
593                 int     type;
594                 int     sts;
595         } nvm;
596
597         struct {
598                 union {
599                         Block   *cmd[21];
600                         struct {
601                                 Block *cfg;
602                                 Block *nch;
603                                 Block *papd[9];
604                                 Block *txp[9];
605                         };
606                 };
607                 int     done;
608         } calib;
609
610         struct {
611                 u32int  base;
612                 uchar   *s;
613         } sched;
614
615         FWInfo fwinfo;
616         FWImage *fw;
617
618         FWMem fwmem;
619 };
620
621 /* controller types */
622 enum {
623         Type4965        = 0,
624         Type5300        = 2,
625         Type5350        = 3,
626         Type5150        = 4,
627         Type5100        = 5,
628         Type1000        = 6,
629         Type6000        = 7,
630         Type6050        = 8,
631         Type6005        = 11,   /* also Centrino Advanced-N 6030, 6235 */
632         Type2030        = 12,
633         Type2000        = 16,
634
635         Type8265        = 35,
636 };
637
638 static struct ratetab {
639         uchar   rate;
640         uchar   plcp;
641         uchar   flags;
642 } ratetab[] = {
643         {   2,  10, RFlagCCK },
644         {   4,  20, RFlagCCK },
645         {  11,  55, RFlagCCK },
646         {  22, 110, RFlagCCK },
647
648         {  12, 0xd, 0 },
649         {  18, 0xf, 0 },
650         {  24, 0x5, 0 },
651         {  36, 0x7, 0 },
652         {  48, 0x9, 0 },
653         {  72, 0xb, 0 },
654         {  96, 0x1, 0 },
655         { 108, 0x3, 0 },
656         { 120, 0x3, 0 }
657 };
658
659 static uchar iwlrates[] = {
660         0x80 | 2,
661         0x80 | 4,
662         0x80 | 11,
663         0x80 | 22,
664
665         0x80 | 12,
666         0x80 | 18,
667         0x80 | 24,
668         0x80 | 36,
669         0x80 | 48,
670         0x80 | 72,
671         0x80 | 96,
672         0x80 | 108,
673         0x80 | 120,
674         0
675 };
676
677 static char *fwname[32] = {
678         [Type4965] "iwn-4965",
679         [Type5300] "iwn-5000",
680         [Type5350] "iwn-5000",
681         [Type5150] "iwn-5150",
682         [Type5100] "iwn-5000",
683         [Type1000] "iwn-1000",
684         [Type6000] "iwn-6000",
685         [Type6050] "iwn-6050",
686         [Type6005] "iwn-6005", /* see in iwlattach() below */
687         [Type2030] "iwn-2030",
688         [Type2000] "iwn-2000",
689 };
690
691 static char *qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block);
692 static char *flushq(Ctlr *ctlr, uint qid);
693 static char *cmd(Ctlr *ctlr, uint code, uchar *data, int size);
694
695 #define csr32r(c, r)    (*((c)->nic+((r)/4)))
696 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
697
698 static uint
699 get16(uchar *p){
700         return *((u16int*)p);
701 }
702 static uint
703 get32(uchar *p){
704         return *((u32int*)p);
705 }
706 static void
707 put32(uchar *p, uint v){
708         *((u32int*)p) = v;
709 }
710 static void
711 put64(uchar *p, uvlong v)
712 {
713         *((u64int*)p) = v;
714 }
715 static void
716 put16(uchar *p, uint v){
717         *((u16int*)p) = v;
718 };
719
720 static char*
721 niclock(Ctlr *ctlr)
722 {
723         int i;
724
725         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
726         for(i=0; i<1000; i++){
727                 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
728                         return 0;
729                 delay(10);
730         }
731         return "niclock: timeout";
732 }
733
734 static void
735 nicunlock(Ctlr *ctlr)
736 {
737         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
738 }
739
740 static u32int
741 prphread(Ctlr *ctlr, uint off)
742 {
743         off &= 0xfffff;
744         csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
745         coherence();
746         return csr32r(ctlr, PrphRdata);
747 }
748 static void
749 prphwrite(Ctlr *ctlr, uint off, u32int data)
750 {
751         off &= 0xfffff;
752         csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
753         coherence();
754         csr32w(ctlr, PrphWdata, data);
755 }
756
757 static void
758 prphwrite64(Ctlr *ctlr, uint off, u64int data)
759 {
760         prphwrite(ctlr, off, data & 0xFFFFFFFF);
761         prphwrite(ctlr, off+4, data >> 32);
762 }
763
764 static u32int
765 memread(Ctlr *ctlr, uint off)
766 {
767         csr32w(ctlr, MemRaddr, off);
768         coherence();
769         return csr32r(ctlr, MemRdata);
770 }
771 static void
772 memwrite(Ctlr *ctlr, uint off, u32int data)
773 {
774         csr32w(ctlr, MemWaddr, off);
775         coherence();
776         csr32w(ctlr, MemWdata, data);
777 }
778
779 static void
780 setfwinfo(Ctlr *ctlr, uchar *d, int len)
781 {
782         FWInfo *i;
783
784         i = &ctlr->fwinfo;
785         switch(len){
786         case 2+2 + 1+1+2+1+1 + 1+1 + 1+1 + 2 + 4+4+4+4+4+4 + 4:
787         case 2+2 + 1+1+2+1+1 + 1+1 + 1+1 + 2 + 4+4+4+4+4+4 + 4 + 4+4 + 1+1 + 2 + 4+4:
788                 i->status = get16(d); d += 2;
789                 i->flags = get16(d); d += 2;
790
791                 i->minor = *d++;
792                 i->major = *d++;
793                 d += 2;                                 // id
794                 d++;                                    // api minor
795                 d++;                                    // api major
796                 i->subtype = *d++;
797                 i->type = *d++;
798                 d++;                                    // mac
799                 d++;                                    // opt
800                 d += 2;                                 // reserved2
801
802                 i->tstamp = get32(d); d += 4;
803                 i->errptr = get32(d); d += 4;
804                 i->logptr = get32(d); d += 4;
805                 i->regptr = get32(d); d += 4;
806                 d += 4;                                 // dbgm_config_ptr
807                 d += 4;                                 // alive counter ptr
808
809                 i->scdptr = get32(d); d += 4;
810
811                 if(len < 1+1+2+1+1+1+1+1+1+2+4+4+4+4+4 + 4+4+4+1+1+2+4+4)
812                         break;
813
814                 d += 4;                                 // fwrd addr
815                 d += 4;                                 // fwrd size
816
817                 i->umac.minor = *d++;
818                 i->umac.major = *d++;
819                 d++;                                    // id
820                 d += 2;
821                 i->umac.errptr = get32(d); d += 4;
822                 i->umac.logptr = get32(d); d += 4;
823
824                 i->valid = (i->status == 0xcafe);
825                 break;
826
827         case 2+2 + 4+4 + 1+1 + 1+1 + 4+4+4+4+4+4 + 4 + 4+4 + 4+4+4+4:
828                 i->status = get16(d); d += 2;
829                 i->flags = get16(d); d += 2;
830
831                 i->minor = get32(d);
832                 d += 4;
833                 i->major = get32(d);
834                 d += 4;
835                 i->subtype = *d++;
836                 i->type = *d++;
837                 d++;                                    // mac
838                 d++;                                    // opt
839
840                 i->tstamp = get32(d); d += 4;
841                 i->errptr = get32(d); d += 4;
842                 i->logptr = get32(d); d += 4;
843                 i->regptr = get32(d); d += 4;
844                 d += 4;                                 // dbgm_config_ptr
845                 d += 4;                                 // alive counter ptr
846
847                 i->scdptr = get32(d);
848                 d += 4;
849
850                 d += 4;                                 // fwrd addr
851                 d += 4;                                 // fwrd size
852
853                 i->umac.minor = get32(d); d += 4;
854                 i->umac.major = get32(d); d += 4;
855                 i->umac.errptr = get32(d); d += 4;
856                 i->umac.logptr = get32(d); d += 4;
857
858                 i->valid = (i->status == 0xcafe);
859                 break;
860         
861         default:
862                 if(len < 32)
863                         break;
864                 i->minor = *d++;
865                 i->major = *d++;
866                 d += 2+8;
867                 i->type = *d++;
868                 i->subtype = *d++;
869                 d += 2;
870                 i->logptr = get32(d); d += 4;
871                 i->errptr = get32(d); d += 4;
872                 i->tstamp = get32(d); d += 4;
873                 i->valid = 1;
874         }
875         USED(d);
876 }
877
878 static void
879 printfwinfo(Ctlr *ctlr)
880 {
881         FWInfo *i = &ctlr->fwinfo;
882
883         print("fwinfo: status=%.4ux flags=%.4ux\n",
884                 i->status, i->flags);
885
886         print("fwinfo: ver %ud.%ud type %ud.%ud\n",
887                 i->major, i->minor, i->type, i->subtype);
888         print("fwinfo: scdptr=%.8ux\n", i->scdptr);
889         print("fwinfo: regptr=%.8ux\n", i->regptr);
890         print("fwinfo: logptr=%.8ux\n", i->logptr);
891         print("fwinfo: errptr=%.8ux\n", i->errptr);
892
893         print("fwinfo: ts=%.8ux\n", i->tstamp);
894
895         print("fwinfo: umac ver %ud.%ud\n", i->umac.major, i->umac.minor);
896         print("fwinfo: umac errptr %.8ux\n", i->umac.errptr);
897         print("fwinfo: umac logptr %.8ux\n", i->umac.logptr);
898 }
899
900 static void
901 dumpctlr(Ctlr *ctlr)
902 {
903         u32int dump[13];
904         int i;
905
906         print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd,  ctlr->tx[4].lastcmd);
907
908         if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
909                 print("no error pointer\n");
910                 return;
911         }
912         for(i=0; i<nelem(dump); i++)
913                 dump[i] = memread(ctlr, ctlr->fwinfo.errptr + i*4);
914
915         if(ctlr->family >= 7000){
916                 print(  "error:\tid %ux, trm_hw_status %.8ux %.8ux,\n"
917                         "\tbranchlink2 %.8ux, interruptlink %.8ux %.8ux,\n"
918                         "\terrordata %.8ux %.8ux %.8ux\n",
919                         dump[1], dump[2], dump[3],
920                         dump[4], dump[5], dump[6],
921                         dump[7], dump[8], dump[9]);
922         } else {
923                 print(  "error:\tid %ux, pc %ux,\n"
924                         "\tbranchlink %.8ux %.8ux, interruptlink %.8ux %.8ux,\n"
925                         "\terrordata %.8ux %.8ux, srcline %ud, tsf %ux, time %ux\n",
926                         dump[1], dump[2],
927                         dump[4], dump[3], dump[6], dump[5],
928                         dump[7], dump[8], dump[9], dump[10], dump[11]);
929         }
930 }
931
932 static char*
933 eepromlock(Ctlr *ctlr)
934 {
935         int i, j;
936
937         for(i=0; i<100; i++){
938                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | EepromLocked);
939                 for(j=0; j<100; j++){
940                         if(csr32r(ctlr, Cfg) & EepromLocked)
941                                 return 0;
942                         delay(10);
943                 }
944         }
945         return "eepromlock: timeout";
946 }
947 static void
948 eepromunlock(Ctlr *ctlr)
949 {
950         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~EepromLocked);
951 }
952 static char*
953 eepromread(Ctlr *ctlr, void *data, int count, uint off)
954 {
955         uchar *out = data;
956         u32int w, s;
957         int i;
958
959         w = 0;
960         off += ctlr->eeprom.off;
961         for(; count > 0; count -= 2, off++){
962                 csr32w(ctlr, EepromIo, off << 2);
963                 for(i=0; i<10; i++){
964                         w = csr32r(ctlr, EepromIo);
965                         if(w & 1)
966                                 break;
967                         delay(5);
968                 }
969                 if(i == 10)
970                         return "eepromread: timeout";
971                 if(ctlr->eeprom.otp){
972                         s = csr32r(ctlr, OtpromGp);
973                         if(s & EccUncorrStts)
974                                 return "eepromread: otprom ecc error";
975                         if(s & EccCorrStts)
976                                 csr32w(ctlr, OtpromGp, s);
977                 }
978                 *out++ = w >> 16;
979                 if(count > 1)
980                         *out++ = w >> 24;
981         }
982         return 0;
983 }
984
985 static char*
986 handover(Ctlr *ctlr)
987 {
988         int i;
989
990         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
991         for(i=0; i<5; i++){
992                 if(csr32r(ctlr, Cfg) & NicReady)
993                         goto Ready;
994                 delay(10);
995         }
996         if(ctlr->family >= 7000){
997                 csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31));
998                 delay(1);
999         }
1000
1001         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
1002         for(i=0; i<15000; i++){
1003                 if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
1004                         break;
1005                 delay(10);
1006         }
1007         if(i >= 15000)
1008                 return "handover: timeout";
1009
1010         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
1011         for(i=0; i<5; i++){
1012                 if(csr32r(ctlr, Cfg) & NicReady)
1013                         goto Ready;
1014                 delay(10);
1015         }
1016         return "handover: timeout";
1017 Ready:
1018         if(ctlr->family >= 7000)
1019                 csr32w(ctlr, MboxSet, csr32r(ctlr, MboxSet) | MboxSetOsAlive);
1020         return nil;
1021 }
1022
1023 static char*
1024 clockwait(Ctlr *ctlr)
1025 {
1026         int i;
1027
1028         /* Set "initialization complete" bit. */
1029         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
1030         for(i=0; i<2500; i++){
1031                 if(csr32r(ctlr, Gpc) & MacClockReady)
1032                         return 0;
1033                 delay(10);
1034         }
1035         return "clockwait: timeout";
1036 }
1037
1038 static char*
1039 poweron(Ctlr *ctlr)
1040 {
1041         int capoff;
1042         char *err;
1043
1044
1045         if(ctlr->family >= 7000){
1046                 /* Reset entire device */
1047                 csr32w(ctlr, Reset, (1<<7));
1048                 delay(5);
1049         }
1050
1051         if(ctlr->family < 8000){
1052                 /* Disable L0s exit timer (NMI bug workaround). */
1053                 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | DisL0Stimer);
1054         }
1055
1056         /* Don't wait for ICH L0s (ICH bug workaround). */
1057         csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | L1AnoL0Srx);
1058
1059         /* Set FH wait threshold to max (HW bug under stress workaround). */
1060         csr32w(ctlr, Dbghpetmem, csr32r(ctlr, Dbghpetmem) | 0xffff0000);
1061
1062         /* Enable HAP INTA to move adapter from L1a to L0s. */
1063         csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | HapwakeL1A);
1064
1065         capoff = pcicap(ctlr->pdev, PciCapPCIe);
1066         if(capoff != -1){
1067                 /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
1068                 if(pcicfgr16(ctlr->pdev, capoff + 0x10) & 0x2)  /* LCSR -> L1 Entry enabled. */
1069                         csr32w(ctlr, Gio, csr32r(ctlr, Gio) | EnaL0S);
1070                 else
1071                         csr32w(ctlr, Gio, csr32r(ctlr, Gio) & ~EnaL0S);
1072         }
1073
1074         if(ctlr->family < 7000){
1075                 if(ctlr->type != Type4965 && ctlr->type <= Type1000)
1076                         csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | 0x00880300);
1077         }
1078
1079         /* Wait for clock stabilization before accessing prph. */
1080         if((err = clockwait(ctlr)) != nil)
1081                 return err;
1082
1083         if(ctlr->mqrx){
1084                 /* Newer cards default to MSIX? */
1085                 if((err = niclock(ctlr)) != nil)
1086                         return err;
1087                 prphwrite(ctlr, UregChick, UregChickMsiEnable);
1088                 nicunlock(ctlr);
1089         }
1090
1091         if(ctlr->family < 8000){
1092                 if((err = niclock(ctlr)) != nil)
1093                         return err;
1094
1095                 /* Enable DMA and BSM (Bootstrap State Machine). */
1096                 if(ctlr->type == Type4965)
1097                         prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
1098                 else
1099                         prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
1100                 delay(20);
1101
1102                 /* Disable L1-Active. */
1103                 prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
1104
1105                 nicunlock(ctlr);
1106         }
1107
1108         ctlr->power = 1;
1109
1110         return 0;
1111 }
1112
1113 static void
1114 poweroff(Ctlr *ctlr)
1115 {
1116         int i, j;
1117
1118         csr32w(ctlr, Reset, 1);
1119
1120         /* Disable interrupts */
1121         ctlr->ie = 0;
1122         csr32w(ctlr, Imr, 0);
1123         csr32w(ctlr, Isr, ~0);
1124         csr32w(ctlr, FhIsr, ~0);
1125
1126         /* Stop scheduler */
1127         if(ctlr->family >= 7000 || ctlr->type != Type4965)
1128                 prphwrite(ctlr, SchedTxFact, 0);
1129         else
1130                 prphwrite(ctlr, SchedTxFact4965, 0);
1131
1132         /* Stop TX ring */
1133         if(niclock(ctlr) == nil){
1134                 for(i = 0; i < ctlr->ndma; i++){
1135                         csr32w(ctlr, FhTxConfig + i*32, 0);
1136                         for(j = 0; j < 200; j++){
1137                                 if(csr32r(ctlr, FhTxStatus) & (0x10000<<i))
1138                                         break;
1139                                 delay(10);
1140                         }
1141                 }
1142                 nicunlock(ctlr);
1143         }
1144
1145         /* Stop RX ring */
1146         if(niclock(ctlr) == nil){
1147                 if(ctlr->mqrx){
1148                         prphwrite(ctlr, RfhDmaCfg, 0);
1149                         for(j = 0; j < 200; j++){
1150                                 if(prphread(ctlr, RfhGenStatus) & RfhGenStatusDmaIdle)
1151                                         break;
1152                                 delay(10);
1153                         }
1154                 } else {
1155                         csr32w(ctlr, FhRxConfig, 0);
1156                         for(j = 0; j < 200; j++){
1157                                 if(csr32r(ctlr, FhRxStatus) & 0x1000000)
1158                                         break;
1159                                 delay(10);
1160                         }
1161                 }
1162                 nicunlock(ctlr);
1163         }
1164
1165         if(ctlr->family <= 7000){
1166                 /* Disable DMA */
1167                 if(niclock(ctlr) == nil){
1168                         prphwrite(ctlr, ApmgClkDis, DmaClkRqt);
1169                         nicunlock(ctlr);
1170                 }
1171                 delay(5);
1172         }
1173
1174         if(ctlr->family >= 7000){
1175                 csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31));
1176                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare|EnablePme);
1177                 delay(1);
1178                 csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) & ~(1<<31));
1179                 delay(5);
1180         }
1181
1182         /* Stop busmaster DMA activity. */
1183         csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<9));
1184         for(j = 0; j < 100; j++){
1185                 if(csr32r(ctlr, Reset) & (1<<8))
1186                         break;
1187                 delay(10);
1188         }
1189
1190         /* Reset the entire device. */
1191         csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<7));
1192         delay(10);
1193
1194         /* Clear "initialization complete" bit. */
1195         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~InitDone);
1196
1197         ctlr->power = 0;
1198 }
1199
1200 static char*
1201 rominit(Ctlr *ctlr)
1202 {
1203         uint prev, last;
1204         uchar buf[2];
1205         char *err;
1206         int i;
1207
1208         ctlr->eeprom.otp = 0;
1209         ctlr->eeprom.off = 0;
1210         if(ctlr->type < Type1000 || (csr32r(ctlr, OtpromGp) & DevSelOtp) == 0)
1211                 return nil;
1212
1213         /* Wait for clock stabilization before accessing prph. */
1214         if((err = clockwait(ctlr)) != nil)
1215                 return err;
1216
1217         if((err = niclock(ctlr)) != nil)
1218                 return err;
1219         prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | ResetReq);
1220         delay(5);
1221         prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) & ~ResetReq);
1222         nicunlock(ctlr);
1223
1224         /* Set auto clock gate disable bit for HW with OTP shadow RAM. */
1225         if(ctlr->type != Type1000)
1226                 csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31));
1227
1228         csr32w(ctlr, EepromGp, csr32r(ctlr, EepromGp) & ~0x00000180);
1229
1230         /* Clear ECC status. */
1231         csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) | (EccCorrStts | EccUncorrStts));
1232
1233         ctlr->eeprom.otp = 1;
1234         if(ctlr->type != Type1000)
1235                 return nil;
1236
1237         /* Switch to absolute addressing mode. */
1238         csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) & ~RelativeAccess);
1239
1240         /*
1241          * Find the block before last block (contains the EEPROM image)
1242          * for HW without OTP shadow RAM.
1243          */
1244         prev = last = 0;
1245         for(i=0; i<3; i++){
1246                 if((err = eepromread(ctlr, buf, 2, last)) != nil)
1247                         return err;
1248                 if(get16(buf) == 0)
1249                         break;
1250                 prev = last;
1251                 last = get16(buf);
1252         }
1253         if(i == 0 || i >= 3)
1254                 return "rominit: missing eeprom image";
1255
1256         ctlr->eeprom.off = prev+1;
1257         return nil;
1258 }
1259
1260 static int
1261 iwlinit(Ether *edev)
1262 {
1263         Ctlr *ctlr;
1264         char *err;
1265         uchar b[4];
1266         uint u, caloff, regoff;
1267
1268         ctlr = edev->ctlr;
1269
1270         /* Clear device-specific "PCI retry timeout" register (41h). */
1271         if(pcicfgr8(ctlr->pdev, 0x41) != 0)
1272                 pcicfgw8(ctlr->pdev, 0x41, 0);
1273
1274         /* Clear interrupt disable bit. Hardware bug workaround. */
1275         if(ctlr->pdev->pcr & 0x400){
1276                 ctlr->pdev->pcr &= ~0x400;
1277                 pcicfgw16(ctlr->pdev, PciPCR, ctlr->pdev->pcr);
1278         }
1279
1280         ctlr->type = csr32r(ctlr, Rev);
1281         if(ctlr->family >= 8000){
1282                 ctlr->type &= 0xFFFF;
1283                 ctlr->dash = 0;
1284                 ctlr->step = ctlr->type & 15, ctlr->type >>= 4;
1285         } else {
1286                 ctlr->type &= 0x1FF;
1287                 ctlr->dash = ctlr->type & 3, ctlr->type >>= 2;
1288                 ctlr->step = ctlr->type & 3, ctlr->type >>= 2;
1289                 if(fwname[ctlr->type] == nil){
1290                         print("iwl: unsupported controller type %d\n", ctlr->type);
1291                         return -1;
1292                 }
1293         }
1294
1295         if((err = handover(ctlr)) != nil)
1296                 goto Err;
1297
1298         /* >= 7000 family needs firmware loaded to access NVM */
1299         if(ctlr->family >= 7000)
1300                 return 0;
1301
1302         if((err = poweron(ctlr)) != nil)
1303                 goto Err;
1304
1305         if((csr32r(ctlr, EepromGp) & 0x7) == 0){
1306                 err = "bad rom signature";
1307                 goto Err;
1308         }
1309         if((err = eepromlock(ctlr)) != nil)
1310                 goto Err;
1311         if((err = rominit(ctlr)) != nil)
1312                 goto Err2;
1313         if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
1314                 eepromunlock(ctlr);
1315                 goto Err;
1316         }
1317         if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
1318         Err2:
1319                 eepromunlock(ctlr);
1320                 goto Err;
1321         }
1322         u = get16(b);
1323         ctlr->rfcfg.type = u & 3;       u >>= 2;
1324         ctlr->rfcfg.step = u & 3;       u >>= 2;
1325         ctlr->rfcfg.dash = u & 3;       u >>= 4;
1326         ctlr->rfcfg.txantmask = u & 15; u >>= 4;
1327         ctlr->rfcfg.rxantmask = u & 15;
1328         if((err = eepromread(ctlr, b, 2, 0x66)) != nil)
1329                 goto Err2;
1330         regoff = get16(b);
1331         if((err = eepromread(ctlr, b, 4, regoff+1)) != nil)
1332                 goto Err2;
1333         strncpy(ctlr->eeprom.regdom, (char*)b, 4);
1334         ctlr->eeprom.regdom[4] = 0;
1335         if((err = eepromread(ctlr, b, 2, 0x67)) != nil)
1336                 goto Err2;
1337         caloff = get16(b);
1338         if((err = eepromread(ctlr, b, 4, caloff)) != nil)
1339                 goto Err2;
1340         ctlr->eeprom.version = b[0];
1341         ctlr->eeprom.type = b[1];
1342         ctlr->eeprom.volt = get16(b+2);
1343
1344         ctlr->eeprom.temp = 0;
1345         ctlr->eeprom.rawtemp = 0;
1346         if(ctlr->type == Type2030 || ctlr->type == Type2000){
1347                 if((err = eepromread(ctlr, b, 2, caloff + 0x12a)) != nil)
1348                         goto Err2;
1349                 ctlr->eeprom.temp = get16(b);
1350                 if((err = eepromread(ctlr, b, 2, caloff + 0x12b)) != nil)
1351                         goto Err2;
1352                 ctlr->eeprom.rawtemp = get16(b);
1353         }
1354
1355         if(ctlr->type != Type4965 && ctlr->type != Type5150){
1356                 if((err = eepromread(ctlr, b, 4, caloff + 0x128)) != nil)
1357                         goto Err2;
1358                 ctlr->eeprom.crystal = get32(b);
1359         }
1360         eepromunlock(ctlr);
1361
1362         switch(ctlr->type){
1363         case Type4965:
1364                 ctlr->rfcfg.txantmask = 3;
1365                 ctlr->rfcfg.rxantmask = 7;
1366                 break;
1367         case Type5100:
1368                 ctlr->rfcfg.txantmask = 2;
1369                 ctlr->rfcfg.rxantmask = 3;
1370                 break;
1371         case Type6000:
1372                 if(ctlr->pdev->did == 0x422c || ctlr->pdev->did == 0x4230){
1373                         ctlr->rfcfg.txantmask = 6;
1374                         ctlr->rfcfg.rxantmask = 6;
1375                 }
1376                 break;
1377         }
1378         poweroff(ctlr);
1379         return 0;
1380 Err:
1381         print("iwlinit: %s\n", err);
1382         poweroff(ctlr);
1383         return -1;
1384 }
1385
1386 static char*
1387 crackfw(FWImage *i, uchar *data, uint size, int alt)
1388 {
1389         uchar *p, *e;
1390         FWSect *s;
1391         uint t, l;
1392
1393         memset(i, 0, sizeof(*i));
1394         if(size < 4){
1395 Tooshort:
1396                 return "firmware image too short";
1397         }
1398         p = data;
1399         e = p + size;
1400         i->rev = get32(p); p += 4;
1401         if(i->rev == 0){
1402                 uvlong altmask;
1403
1404                 if(size < (4+64+4+4+8))
1405                         goto Tooshort;
1406                 if(memcmp(p, "IWL\n", 4) != 0)
1407                         return "bad firmware signature";
1408                 p += 4;
1409                 strncpy(i->descr, (char*)p, 64);
1410                 i->descr[64] = 0;
1411                 p += 64;
1412                 i->rev = get32(p); p += 4;
1413                 i->build = get32(p); p += 4;
1414                 altmask = get32(p); p += 4;
1415                 altmask |= (uvlong)get32(p) << 32; p += 4;
1416                 while(alt > 0 && (altmask & (1ULL<<alt)) == 0)
1417                         alt--;
1418                 for(;p < e; p += (l + 3) & ~3){
1419                         if(p + 8 > e)
1420                                 goto Tooshort;
1421
1422                         t = get32(p), p += 4;
1423                         l = get32(p), p += 4;
1424                         if(p + l > e)
1425                                 goto Tooshort;
1426
1427                         if((t >> 16) != 0 && (t >> 16) != alt)
1428                                 continue;
1429
1430                         switch(t & 0xFFFF){
1431                         case 1:
1432                                 s = &i->main.text;
1433                                 if(i->main.nsect < 1)
1434                                         i->main.nsect = 1;
1435                                 s->addr = 0x00000000;
1436                                 goto Sect;
1437                         case 2:
1438                                 s = &i->main.data;
1439                                 if(i->main.nsect < 2)
1440                                         i->main.nsect = 2;
1441                                 s->addr = 0x00800000;
1442                                 goto Sect;
1443                         case 3:
1444                                 s = &i->init.text;
1445                                 if(i->init.nsect < 1)
1446                                         i->init.nsect = 1;
1447                                 s->addr = 0x00000000;
1448                                 goto Sect;
1449                         case 4:
1450                                 s = &i->init.data;
1451                                 if(i->init.nsect < 2)
1452                                         i->init.nsect = 2;
1453                                 s->addr = 0x00800000;
1454                                 goto Sect;
1455                         case 5:
1456                                 s = &i->boot.text;
1457                                 s->addr = 0x00000000;
1458                                 goto Sect;
1459                         case 19:
1460                                 if(i->main.nsect >= nelem(i->main.sect))
1461                                         return "too many main sections";
1462                                 s = &i->main.sect[i->main.nsect++];
1463                                 goto Chunk;
1464                         case 20:
1465                                 if(i->init.nsect >= nelem(i->init.sect))
1466                                         return "too many init sections";
1467                                 s = &i->init.sect[i->init.nsect++];
1468                         Chunk:
1469                                 if(l < 4)
1470                                         goto Tooshort;
1471                                 s->addr = get32(p);
1472                                 p += 4, l -= 4;
1473                         Sect:
1474                                 s->size = l;
1475                                 s->data = p;
1476                                 break;
1477                         case 22:
1478                                 if(l < 12)
1479                                         goto Tooshort;
1480                                 switch(get32(p)){
1481                                 case 0:
1482                                         i->main.defcalib.flowmask = get32(p+4);
1483                                         i->main.defcalib.eventmask = get32(p+8);
1484                                         break;
1485                                 case 1:
1486                                         i->init.defcalib.flowmask = get32(p+4);
1487                                         i->init.defcalib.eventmask = get32(p+8);
1488                                         break;
1489                                 }
1490                                 break;
1491                         case 23:
1492                                 if(l < 4)
1493                                         goto Tooshort;
1494                                 i->physku = get32(p);
1495                                 break;
1496                         case 29:
1497                                 if(l < 8)
1498                                         goto Tooshort;
1499                                 t = get32(p);
1500                                 if(t >= nelem(i->api))
1501                                         goto Tooshort;
1502                                 i->api[t] = get32(p+4);
1503                                 break;
1504                         case 30:
1505                                 if(l < 8)
1506                                         goto Tooshort;
1507                                 t = get32(p);
1508                                 if(t >= nelem(i->capa))
1509                                         goto Tooshort;
1510                                 i->capa[t] = get32(p+4);
1511                                 break;
1512                         case 32:
1513                                 if(l < 4)
1514                                         goto Tooshort;
1515                                 i->pagedmemsize = get32(p) & -FWPagesize;
1516                                 break;
1517                         }
1518                 }
1519         } else {
1520                 if(((i->rev>>8) & 0xFF) < 2)
1521                         return "need firmware api >= 2";
1522                 if(((i->rev>>8) & 0xFF) >= 3){
1523                         i->build = get32(p); p += 4;
1524                 }
1525                 if((p + 5*4) > e)
1526                         goto Tooshort;
1527
1528                 i->main.text.size = get32(p); p += 4;
1529                 i->main.data.size = get32(p); p += 4;
1530                 i->init.text.size = get32(p); p += 4;
1531                 i->init.data.size = get32(p); p += 4;
1532                 i->boot.text.size = get32(p); p += 4;
1533
1534                 i->main.text.data = p; p += i->main.text.size;
1535                 i->main.data.data = p; p += i->main.data.size;
1536                 i->init.text.data = p; p += i->init.text.size;
1537                 i->init.data.data = p; p += i->init.data.size;
1538                 i->boot.text.data = p; p += i->boot.text.size;
1539                 if(p > e)
1540                         goto Tooshort;
1541
1542                 i->main.nsect = 2;
1543                 i->init.nsect = 2;
1544                 i->main.text.addr = 0x00000000;
1545                 i->main.data.addr = 0x00800000;
1546                 i->init.text.addr = 0x00000000;
1547                 i->init.data.addr = 0x00800000;
1548         }
1549         return 0;
1550 }
1551
1552 static FWImage*
1553 readfirmware(char *name)
1554 {
1555         uchar dirbuf[sizeof(Dir)+100], *data;
1556         char buf[128], *err;
1557         FWImage *fw;
1558         int n, r;
1559         Chan *c;
1560         Dir d;
1561
1562         if(!iseve())
1563                 error(Eperm);
1564         if(!waserror()){
1565                 snprint(buf, sizeof buf, "/boot/%s", name);
1566                 c = namec(buf, Aopen, OREAD, 0);
1567                 poperror();
1568         } else {
1569                 snprint(buf, sizeof buf, "/lib/firmware/%s", name);
1570                 c = namec(buf, Aopen, OREAD, 0);
1571         }
1572         if(waserror()){
1573                 cclose(c);
1574                 nexterror();
1575         }
1576         n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
1577         if(n <= 0)
1578                 error("can't stat firmware");
1579         convM2D(dirbuf, n, &d, nil);
1580         fw = smalloc(sizeof(*fw) + 16 + d.length);
1581         data = (uchar*)(fw+1);
1582         if(waserror()){
1583                 free(fw);
1584                 nexterror();
1585         }
1586         r = 0;
1587         while(r < d.length){
1588                 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
1589                 if(n <= 0)
1590                         break;
1591                 r += n;
1592         }
1593         if((err = crackfw(fw, data, r, 1)) != nil)
1594                 error(err);
1595         poperror();
1596         poperror();
1597         cclose(c);
1598         return fw;
1599 }
1600
1601
1602 static int
1603 gotirq(void *arg)
1604 {
1605         Ctlr *ctlr = arg;
1606         return (ctlr->wait.m & ctlr->wait.w) != 0;
1607 }
1608
1609 static u32int
1610 irqwait(Ctlr *ctlr, u32int mask, int timeout)
1611 {
1612         u32int r;
1613
1614         ilock(ctlr);
1615         r = ctlr->wait.m & mask;
1616         if(r == 0){
1617                 ctlr->wait.w = mask;
1618                 iunlock(ctlr);
1619                 if(!waserror()){
1620                         tsleep(&ctlr->wait, gotirq, ctlr, timeout);
1621                         poperror();
1622                 }
1623                 ilock(ctlr);
1624                 ctlr->wait.w = 0;
1625                 r = ctlr->wait.m & mask;
1626         }
1627         ctlr->wait.m &= ~r;
1628         iunlock(ctlr);
1629         return r;
1630 }
1631
1632 static int
1633 rbplant(Ctlr *ctlr, uint i)
1634 {
1635         Block *b;
1636
1637         assert(i < Nrx);
1638
1639         b = iallocb(Rbufsize*2);
1640         if(b == nil)
1641                 return -1;
1642         b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, Rbufsize);
1643         memset(b->rp, 0, Rdscsize);
1644
1645         ctlr->rx.b[i] = b;
1646
1647         if(ctlr->mqrx)
1648                 put64(ctlr->rx.p + (i<<3), PCIWADDR(b->rp));
1649         else
1650                 put32(ctlr->rx.p + (i<<2), PCIWADDR(b->rp) >> 8);
1651
1652         return 0;
1653 }
1654
1655 static char*
1656 initmem(Ctlr *ctlr)
1657 {
1658         RXQ *rx;
1659         TXQ *tx;
1660         int i, q;
1661
1662         if(ctlr->fw->pagedmemsize > 0){
1663                 ctlr->fwmem.npage = ctlr->fw->pagedmemsize >> FWPageshift;
1664                 ctlr->fwmem.nblock = ctlr->fwmem.npage >> FWBlockshift;
1665                 if(ctlr->fwmem.nblock >= nelem(ctlr->fwmem.block)-1)
1666                         return "paged memory size too big";
1667                 for(i = 0; i < ctlr->fwmem.nblock; i++)
1668                         ctlr->fwmem.block[i].size = FWBlocksize;
1669                 ctlr->fwmem.block[i].size = (ctlr->fwmem.npage % FWBlockpages) << FWPageshift;
1670                 if(ctlr->fwmem.block[i].size != 0)
1671                         ctlr->fwmem.nblock++;
1672                 for(i = 0; i < ctlr->fwmem.nblock; i++){
1673                         if(ctlr->fwmem.block[i].p == nil){
1674                                 ctlr->fwmem.block[i].p = mallocalign(ctlr->fwmem.block[i].size, FWPagesize, 0, 0);
1675                                 if(ctlr->fwmem.block[i].p == nil)
1676                                         return "no memory for firmware block";
1677                         }
1678                 }
1679                 if(ctlr->fwmem.css == nil){
1680                         if((ctlr->fwmem.css = mallocalign(FWPagesize, FWPagesize, 0, 0)) == nil)
1681                                 return "no memory for firmware css page";
1682                 }
1683         }
1684
1685         rx = &ctlr->rx;
1686         if(ctlr->mqrx){
1687                 if(rx->u == nil)
1688                         rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
1689                 if(rx->p == nil)
1690                         rx->p = mallocalign(8 * Nrx, 4096, 0, 0);
1691                 if(rx->u == nil || rx->p == nil)
1692                         return "no memory for rx rings";
1693                 memset(rx->u, 0, 4 * Nrx);
1694                 memset(rx->p, 0, 8 * Nrx);
1695         } else {
1696                 rx->u = nil;
1697                 if(rx->p == nil)
1698                         rx->p = mallocalign(4 * Nrx, 256, 0, 0);
1699                 if(rx->p == nil)
1700                         return "no memory for rx rings";
1701                 memset(rx->p, 0, 4 * Nrx);
1702         }
1703         if(rx->s == nil)
1704                 rx->s = mallocalign(Rstatsize, 4096, 0, 0);
1705         if(rx->b == nil)
1706                 rx->b = malloc(sizeof(Block*) * Nrx);
1707         if(rx->b == nil || rx->s == nil)
1708                 return "no memory for rx ring";
1709         memset(rx->s, 0, Rstatsize);
1710         for(i=0; i<Nrx; i++){
1711                 if(rx->b[i] != nil){
1712                         freeb(rx->b[i]);
1713                         rx->b[i] = nil;
1714                 }
1715                 if(rbplant(ctlr, i) < 0)
1716                         return "no memory for rx descriptors";
1717         }
1718         rx->i = 0;
1719
1720         ctlr->ndma = 8;
1721         ctlr->ntxq = 20;
1722         if(ctlr->family >= 7000) {
1723                 ctlr->ntxq = 31;
1724         } else {
1725                 if(ctlr->type == Type4965) {
1726                         ctlr->ndma = 7;
1727                         ctlr->ntxq = 16;
1728                 }
1729         }
1730
1731         if(ctlr->sched.s == nil)
1732                 ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
1733         if(ctlr->sched.s == nil)
1734                 return "no memory for sched buffer";
1735         memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
1736
1737         for(q=0; q < nelem(ctlr->tx); q++){
1738                 tx = &ctlr->tx[q];
1739                 if(tx->b == nil)
1740                         tx->b = malloc(sizeof(Block*) * Ntx);
1741                 if(tx->d == nil)
1742                         tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
1743                 if(tx->c == nil)
1744                         tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
1745                 if(tx->b == nil || tx->d == nil || tx->c == nil)
1746                         return "no memory for tx ring";
1747                 memset(tx->d, 0, Tdscsize * Ntx);
1748                 memset(tx->c, 0, Tcmdsize * Ntx);
1749                 for(i=0; i<Ntx; i++){
1750                         if(tx->b[i] != nil){
1751                                 freeblist(tx->b[i]);
1752                                 tx->b[i] = nil;
1753                         }
1754                 }
1755                 tx->i = 0;
1756                 tx->n = 0;
1757                 tx->lastcmd = 0;
1758         }
1759
1760         if(ctlr->kwpage == nil)
1761                 ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
1762         if(ctlr->kwpage == nil)
1763                 return "no memory for kwpage";          
1764         memset(ctlr->kwpage, 0, 4096);
1765
1766         return nil;
1767 }
1768
1769 static char*
1770 reset(Ctlr *ctlr)
1771 {
1772         char *err;
1773         int q, i;
1774
1775         if(ctlr->power)
1776                 poweroff(ctlr);
1777         if((err = initmem(ctlr)) != nil)
1778                 return err;
1779         if((err = poweron(ctlr)) != nil)
1780                 return err;
1781
1782         if(ctlr->family <= 7000){
1783                 if((err = niclock(ctlr)) != nil)
1784                         return err;
1785                 prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
1786                 nicunlock(ctlr);
1787         }
1788
1789         if(ctlr->family >= 7000){
1790                 u32int u;
1791
1792                 u = csr32r(ctlr, Cfg);
1793
1794                 u &= ~(RadioSi|MacSi|CfgMacDashMask|CfgMacStepMask|CfgPhyTypeMask|CfgPhyStepMask|CfgPhyDashMask);
1795
1796                 u |= (ctlr->step << CfgMacStepShift) & CfgMacStepMask;
1797                 u |= (ctlr->dash << CfgMacDashShift) & CfgMacDashMask;
1798
1799                 u |= ctlr->rfcfg.type << CfgPhyTypeShift;
1800                 u |= ctlr->rfcfg.step << CfgPhyStepShift;
1801                 u |= ctlr->rfcfg.dash << CfgPhyDashShift;
1802
1803                 csr32w(ctlr, Cfg, u);
1804
1805         } else {
1806                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
1807         }
1808
1809         if(ctlr->family < 8000){
1810                 if((err = niclock(ctlr)) != nil)
1811                         return err;
1812                 if(ctlr->family == 7000 || ctlr->type != Type4965)
1813                         prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
1814                 nicunlock(ctlr);
1815         }
1816         if(ctlr->family < 7000){
1817                 if((err = niclock(ctlr)) != nil)
1818                         return err;
1819                 if(ctlr->type == Type1000){
1820                         /*
1821                          * Select first Switching Voltage Regulator (1.32V) to
1822                          * solve a stability issue related to noisy DC2DC line
1823                          * in the silicon of 1000 Series.
1824                          */
1825                         prphwrite(ctlr, ApmgDigitalSvr, 
1826                                 (prphread(ctlr, ApmgDigitalSvr) & ~(0xf<<5)) | (3<<5));
1827                 }
1828                 if((ctlr->type == Type6005 || ctlr->type == Type6050) && ctlr->eeprom.version == 6)
1829                         csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrvCalV6);
1830                 if(ctlr->type == Type6005)
1831                         csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrv1X2);
1832                 if(ctlr->type == Type2030 || ctlr->type == Type2000)
1833                         csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrvRadioIqInvert);
1834                 nicunlock(ctlr);
1835         }
1836
1837         if((err = niclock(ctlr)) != nil)
1838                 return err;
1839
1840         if(ctlr->mqrx){
1841                 /* Stop RX DMA. */
1842                 prphwrite(ctlr, RfhDmaCfg, 0);
1843                 /* Disable RX used and free queue operation. */
1844                 prphwrite(ctlr, RfhRxqActive, 0);
1845
1846                 prphwrite64(ctlr, RfhQ0SttsBase, PCIWADDR(ctlr->rx.s));
1847                 prphwrite64(ctlr, RfhQ0FreeBase, PCIWADDR(ctlr->rx.p));
1848                 prphwrite64(ctlr, RfhQ0UsedBase, PCIWADDR(ctlr->rx.u));
1849
1850                 prphwrite(ctlr, RfhQ0FreeWptr, 0);
1851                 prphwrite(ctlr, RfhQ0FreeRptr, 0);
1852                 prphwrite(ctlr, RfhQ0UsedWptr, 0);
1853
1854                 /* Enable RX DMA */
1855                 prphwrite(ctlr, RfhDmaCfg,
1856                         RfhDmaEnable |
1857                         RfhDmaDropTooLarge |
1858                         ((Rbufsize/1024) << RfhDma1KSizeShift) |
1859                         (3 << RfhDmaMinRbSizeShift) |
1860                         (Nrxlog << RfhDmaNrbdShift));
1861
1862                 /* Enable RX DMA snooping. */
1863                 prphwrite(ctlr, RfhGenCfg,
1864                         RfhGenServiceDmaSnoop |
1865                         RfhGenRfhDmaSnoop |
1866                         RfhGenRbChunkSize128);
1867
1868                 /* Enable Q0 */
1869                 prphwrite(ctlr, RfhRxqActive, (1 << 16) | 1);
1870                 delay(1);
1871
1872                 csr32w(ctlr, FhRxQ0Wptr, (Nrx-1) & ~7);
1873                 delay(1);
1874         } else {
1875                 csr32w(ctlr, FhRxConfig, 0);
1876                 csr32w(ctlr, FhRxWptr, 0);
1877                 csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
1878                 csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
1879                 csr32w(ctlr, FhRxConfig,
1880                         FhRxConfigEna | 
1881                         FhRxConfigIgnRxfEmpty |
1882                         FhRxConfigIrqDstHost | 
1883                         FhRxConfigSingleFrame |
1884                         (Nrxlog << FhRxConfigNrbdShift));
1885
1886                 csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
1887         }
1888
1889         for(i = 0; i < ctlr->ndma; i++)
1890                 csr32w(ctlr, FhTxConfig + i*32, 0);
1891
1892         if(ctlr->family >= 7000 || ctlr->type != Type4965)
1893                 prphwrite(ctlr, SchedTxFact, 0);
1894         else
1895                 prphwrite(ctlr, SchedTxFact4965, 0);
1896
1897         if(ctlr->family >= 7000){
1898                 prphwrite(ctlr, SchedEnCtrl, 0);
1899                 prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
1900                         | Enable31Queues*(ctlr->ntxq == 31)
1901                         | AutoActiveMode);
1902                 for(q = 0; q < ctlr->ntxq; q++)
1903                         prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1 << 19);
1904         }
1905
1906         csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
1907         for(q = 0; q < ctlr->ntxq; q++){
1908                 i = q < nelem(ctlr->tx) ? q : nelem(ctlr->tx)-1;
1909                 if(q < 16)
1910                         csr32w(ctlr, FhCbbcQueue0 + q*4, PCIWADDR(ctlr->tx[i].d) >> 8);
1911                 else if(q < 20)
1912                         csr32w(ctlr, FhCbbcQueue16 + (q-16)*4, PCIWADDR(ctlr->tx[i].d) >> 8);
1913                 else
1914                         csr32w(ctlr, FhCbbcQueue20 + (q-20)*4, PCIWADDR(ctlr->tx[i].d) >> 8);
1915         }
1916
1917         if(ctlr->family >= 7000 || ctlr->type >= Type6000)
1918                 csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
1919
1920         nicunlock(ctlr);
1921
1922         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1923         csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
1924
1925         ctlr->systime = 0;
1926
1927         ctlr->broken = 0;
1928         ctlr->wait.m = 0;
1929         ctlr->wait.w = 0;
1930
1931         ctlr->bcast.id = -1;
1932         ctlr->bss.id = -1;
1933
1934         ctlr->phyid = -1;
1935         ctlr->macid = -1;
1936         ctlr->bindid = -1;
1937         ctlr->te.id = -1;
1938         ctlr->te.active = 0;
1939         ctlr->aid = 0;
1940
1941         if(ctlr->family >= 9000)
1942                 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
1943
1944         ctlr->ie = Idefmask;
1945         csr32w(ctlr, Imr, ctlr->ie);
1946         csr32w(ctlr, Isr, ~0);
1947
1948         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1949         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1950         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1951
1952         return nil;
1953 }
1954
1955 static char*
1956 sendmccupdate(Ctlr *ctlr, char *mcc)
1957 {
1958         uchar c[2+1+1+4+5*4], *p;
1959
1960         memset(p = c, 0, sizeof(c));
1961         *p++ = mcc[1];
1962         *p++ = mcc[0];
1963         *p++ = 0;
1964         *p++ = 0;       // reserved
1965         if(1){
1966                 p += 4;
1967                 p += 5*4;
1968         }
1969         return cmd(ctlr, 200, c, p - c);
1970 }
1971
1972 static char*
1973 sendbtcoexadv(Ctlr *ctlr)
1974 {
1975         static u32int btcoex3wire[12] = {
1976                 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
1977                 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa,
1978                 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
1979         };
1980
1981         uchar c[Tcmdsize], *p;
1982         char *err;
1983         int i;
1984
1985         /* set BT config */
1986         memset(c, 0, sizeof(c));
1987         p = c;
1988
1989         if(ctlr->family >= 7000){
1990                 put32(p, 3);
1991                 p += 4;
1992                 put32(p, (1<<4));
1993                 p += 4;
1994         } else if(ctlr->type == Type2030){
1995                 *p++ = 145; /* flags */
1996                 p++; /* lead time */
1997                 *p++ = 5; /* max kill */
1998                 *p++ = 1; /* bt3 t7 timer */
1999                 put32(p, 0xffff0000); /* kill ack */
2000                 p += 4;
2001                 put32(p, 0xffff0000); /* kill cts */
2002                 p += 4;
2003                 *p++ = 2; /* sample time */
2004                 *p++ = 0xc; /* bt3 t2 timer */
2005                 p += 2; /* bt4 reaction */
2006                 for (i = 0; i < nelem(btcoex3wire); i++){
2007                         put32(p, btcoex3wire[i]);
2008                         p += 4;
2009                 }
2010                 p += 2; /* bt4 decision */
2011                 put16(p, 0xff); /* valid */
2012                 p += 2;
2013                 put32(p, 0xf0); /* prio boost */
2014                 p += 4;
2015                 p++; /* reserved */
2016                 p++; /* tx prio boost */
2017                 p += 2; /* rx prio boost */
2018         }
2019         if((err = cmd(ctlr, 155, c, p-c)) != nil)
2020                 return err;
2021
2022         if(ctlr->family >= 7000)
2023                 return nil;
2024
2025         /* set BT priority */
2026         memset(c, 0, sizeof(c));
2027         p = c;
2028
2029         *p++ = 0x6; /* init1 */
2030         *p++ = 0x7; /* init2 */
2031         *p++ = 0x2; /* periodic low1 */
2032         *p++ = 0x3; /* periodic low2 */
2033         *p++ = 0x4; /* periodic high1 */
2034         *p++ = 0x5; /* periodic high2 */
2035         *p++ = 0x6; /* dtim */
2036         *p++ = 0x8; /* scan52 */
2037         *p++ = 0xa; /* scan24 */
2038         p += 7; /* reserved */
2039         if((err = cmd(ctlr, 204, c, p-c)) != nil)
2040                 return err;
2041
2042         /* force BT state machine change */
2043         memset(c, 0, sizeof(c));
2044         p = c;
2045
2046         *p++ = 1; /* open */
2047         *p++ = 1; /* type */
2048         p += 2; /* reserved */
2049         if((err = cmd(ctlr, 205, c, p-c)) != nil)
2050                 return err;
2051
2052         c[0] = 0; /* open */
2053         return cmd(ctlr, 205, c, p-c);
2054 }
2055
2056 static char*
2057 sendpagingcmd(Ctlr *ctlr)
2058 {
2059         uchar c[3*4 + 4 + 32*4], *p;
2060         int i;
2061
2062         p = c;
2063         put32(p, (3<<8) | (ctlr->fwmem.npage % FWBlockpages));
2064         p += 4;
2065         put32(p, FWPageshift + FWBlockshift);
2066         p += 4;
2067         put32(p, ctlr->fwmem.nblock);
2068         p += 4;
2069
2070         put32(p, PCIWADDR(ctlr->fwmem.css) >> FWPageshift);
2071         p += 4;
2072
2073         for(i = 0; i < ctlr->fwmem.nblock; i++){
2074                 put32(p, PCIWADDR(ctlr->fwmem.block[i].p) >> FWPageshift);
2075                 p += 4;
2076         }
2077
2078         for(; i < 32; i++){
2079                 put32(p, 0);
2080                 p += 4;
2081         }
2082
2083         return cmd(ctlr, 79 | (1<<8), c, p-c);
2084 }
2085
2086 static char*
2087 enablepaging(Ctlr *ctlr)
2088 {
2089         FWSect *sect;
2090         int nsect;
2091         int i, j, o, n;
2092
2093         if(ctlr->fwmem.css == nil)
2094                 return nil;
2095
2096         if(1){
2097                 /* clear everything */
2098                 memset(ctlr->fwmem.css, 0, FWPagesize);
2099                 for(i = 0; i < ctlr->fwmem.nblock; i++)
2100                         memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
2101         }
2102
2103         if(ctlr->calib.done == 0){
2104                 sect = ctlr->fw->init.sect;
2105                 nsect = ctlr->fw->init.nsect;
2106         } else {
2107                 sect = ctlr->fw->main.sect;
2108                 nsect = ctlr->fw->main.nsect;
2109         }
2110
2111         /* first CSS segment */
2112         for(i = 0; i < nsect; i++) {
2113                 if(sect[i].addr == 0xAAAABBBB){
2114                         i++;
2115                         break;
2116                 }
2117         }
2118
2119         if(i+1 >= nsect)
2120                 return "firmware misses CSS+paging sections";
2121
2122         if(sect[i].size > FWPagesize)
2123                 return "CSS section too big";
2124         if(sect[i+1].size > (ctlr->fwmem.npage << FWPageshift))
2125                 return "paged section too big";
2126
2127         memmove(ctlr->fwmem.css, sect[i].data, sect[i].size);
2128
2129         for(j = 0, o = 0; o < sect[i+1].size; o += n, j++){
2130                 n = sect[i+1].size - o;
2131                 if(n > ctlr->fwmem.block[j].size)
2132                         n = ctlr->fwmem.block[j].size;
2133                 memmove(ctlr->fwmem.block[j].p, sect[i+1].data + o, n);
2134         }
2135
2136         return sendpagingcmd(ctlr);
2137 }
2138
2139 static int
2140 readnvmsect1(Ctlr *ctlr, int type, void *data, int len, int off)
2141 {
2142         uchar c[2+2+2+2], *p;
2143         char *err;
2144
2145         p = c;
2146         *p++ = 0; // read op
2147         *p++ = 0; // target
2148         put16(p, type);
2149         p += 2;
2150         put16(p, off);
2151         p += 2;
2152         put16(p, len);
2153         p += 2;
2154
2155         ctlr->nvm.off = -1;
2156         ctlr->nvm.ret = -1;
2157         ctlr->nvm.type = -1;
2158         ctlr->nvm.sts = -1;
2159
2160         ctlr->nvm.buf = data;
2161         ctlr->nvm.len = len;
2162
2163         if((err = cmd(ctlr, 136, c, p - c)) != nil){
2164                 ctlr->nvm.buf = nil;
2165                 ctlr->nvm.len = 0;
2166                 print("readnvmsect: %s\n", err);
2167                 return -1;
2168         }
2169
2170         if(ctlr->nvm.ret < len)
2171                 len = ctlr->nvm.ret;
2172
2173         if(ctlr->nvm.sts != 0 || ctlr->nvm.off != off || (ctlr->nvm.type & 0xFF) != type)
2174                 return -1;
2175
2176         return len;
2177 }
2178
2179 static int
2180 readnvmsect(Ctlr *ctlr, int type, void *data, int len, int off)
2181 {
2182         int n, r, o;
2183
2184         for(o = 0; o < len; o += n){
2185                 r = len - o;
2186                 if(r > 256)
2187                         r = 256;
2188                 if((n = readnvmsect1(ctlr, type, (char*)data + o, r, o+off)) < 0)
2189                         return -1;
2190                 if(n < r){
2191                         o += n;
2192                         break;
2193                 }
2194         }
2195         return o;
2196 }
2197
2198 static char*
2199 readnvmconfig(Ctlr *ctlr)
2200 {
2201         uchar *ea = ctlr->edev->ea;
2202         uchar buf[8];
2203         uint u;
2204         char *err;
2205
2206         if(readnvmsect(ctlr, 1, buf, 8, 0) != 8)
2207                 return "can't read nvm version";
2208
2209         ctlr->nvm.version = get16(buf);
2210         if (ctlr->family == 7000) {
2211                 u = get16(buf + 2);
2212
2213                 ctlr->rfcfg.type = (u >> 4) & 3;
2214                 ctlr->rfcfg.step = (u >> 2) & 3;
2215                 ctlr->rfcfg.dash = (u >> 0) & 3;
2216                 ctlr->rfcfg.pnum = (u >> 6) & 3;
2217
2218                 ctlr->rfcfg.txantmask = (u >> 8) & 15;
2219                 ctlr->rfcfg.rxantmask = (u >> 12) & 15;
2220
2221         } else {
2222                 if(readnvmsect(ctlr, 12, buf, 8, 0) != 8)
2223                         return "can't read nvm phy config";
2224
2225                 u = get32(buf);
2226
2227                 ctlr->rfcfg.type = (u >> 12) & 0xFFF;
2228                 ctlr->rfcfg.step = (u >> 8) & 15;
2229                 ctlr->rfcfg.dash = (u >> 4) & 15;
2230                 ctlr->rfcfg.pnum = (u >> 6) & 3;
2231
2232                 ctlr->rfcfg.txantmask = (u >> 24) & 15;
2233                 ctlr->rfcfg.rxantmask = (u >> 28) & 15;
2234         }
2235         if(ctlr->family >= 8000){
2236                 if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) != Eaddrlen){
2237                         u32int a0, a1;
2238
2239                         if((err = niclock(ctlr)) != nil)
2240                                 return err;
2241                         a0 = prphread(ctlr, 0xa03080);
2242                         a1 = prphread(ctlr, 0xa03084);
2243                         nicunlock(ctlr);
2244
2245                         ea[0] = a0 >> 24;
2246                         ea[1] = a0 >> 16;
2247                         ea[2] = a0 >> 8;
2248                         ea[3] = a0 >> 0;
2249                         ea[4] = a1 >> 8;
2250                         ea[5] = a1 >> 0;
2251                 }
2252         } else {
2253                 readnvmsect(ctlr, 0, ea, Eaddrlen, 0x15<<1);
2254         }
2255         memmove(ctlr->edev->addr, ea, Eaddrlen);
2256
2257         return nil;
2258 }
2259
2260 static char*
2261 sendtxantconfig(Ctlr *ctlr, uint val)
2262 {
2263         uchar c[4];
2264
2265         put32(c, val);
2266         return cmd(ctlr, 152, c, 4);
2267 }
2268
2269 static char*
2270 sendphyconfig(Ctlr *ctlr, u32int physku, u32int flowmask, u32int eventmask)
2271 {
2272         uchar c[3*4];
2273
2274         put32(c+0, physku);
2275         put32(c+4, flowmask);
2276         put32(c+8, eventmask);
2277         return cmd(ctlr, 106, c, 3*4);
2278 }
2279
2280 static char*
2281 delstation(Ctlr *ctlr, Station *sta)
2282 {
2283         uchar c[4], *p;
2284         char *err;
2285
2286         if(sta->id < 0)
2287                 return nil;
2288
2289         memset(p = c, 0, sizeof(c));
2290         *p = sta->id;
2291
2292         if((err = cmd(ctlr, 25, c, 4)) != nil)
2293                 return err;
2294
2295         sta->id = -1;
2296         return nil;
2297 }
2298
2299 enum {
2300         StaTypeLink = 0,
2301         StaTypeGeneralPurpose,
2302         StaTypeMulticast,
2303         StaTypeTdlsLink,
2304         StaTypeAux,
2305 };
2306
2307 static char*
2308 setstation(Ctlr *ctlr, int id, int type, uchar addr[6], Station *sta)
2309 {
2310         uchar c[Tcmdsize], *p;
2311         char *err;
2312
2313         memset(p = c, 0, sizeof(c));
2314
2315         *p++ = 0;                       /* control (1 = update) */
2316         p++;                            /* reserved */
2317         if(ctlr->family >= 7000){
2318                 put16(p, 0xffff);
2319                 p += 2;
2320                 put32(p, ctlr->macid);
2321                 p += 4;
2322         } else {
2323                 p += 2;                 /* reserved */
2324         }
2325
2326         memmove(p, addr, 6);
2327         p += 8;
2328
2329         *p++ = id;                      /* sta id */
2330
2331         if(ctlr->family >= 7000){
2332                 *p++ = 1 << 1;          /* modify mask */
2333                 p += 2;                 /* reserved */
2334
2335                 put32(p, 0<<26 | 0<<28);
2336                 p += 4;                 /* station_flags */
2337
2338                 put32(p, 3<<26 | 3<<28);
2339                 p += 4;                 /* station_flags_mask */
2340
2341                 p++;                    /* add_immediate_ba_tid */
2342                 p++;                    /* remove_immediate_ba_tid */
2343                 p += 2;                 /* add_immediate_ba_ssn */
2344                 p += 2;                 /* sleep_tx_count */
2345                 p++;                    /* sleep state flags */
2346
2347                 *p++ = (ctlr->fw->api[0] & (1<<30)) != 0 ? type : 0;            /* station_type */
2348
2349                 p += 2;                 /* assoc id */
2350
2351                 p += 2;                 /* beamform flags */
2352
2353                 put32(p, 1<<0);
2354                 p += 4;                 /* tfd_queue_mask */
2355
2356                 if(1){
2357                         p += 2;         /* rx_ba_window */
2358                         p++;            /* sp_length */
2359                         p++;            /* uapsd_acs */
2360                 }
2361         } else {
2362                 p += 3;
2363                 p += 2;                 /* kflags */
2364                 p++;                    /* tcs2 */
2365                 p++;                    /* reserved */
2366                 p += 5*2;               /* ttak */
2367                 p++;                    /* kid */
2368                 p++;                    /* reserved */
2369                 p += 16;                /* key */
2370                 if(ctlr->type != Type4965){
2371                         p += 8;         /* tcs */
2372                         p += 8;         /* rxmic */
2373                         p += 8;         /* txmic */
2374                 }
2375                 p += 4;                 /* htflags */
2376                 p += 4;                 /* mask */
2377                 p += 2;                 /* disable tid */
2378                 p += 2;                 /* reserved */
2379                 p++;                    /* add ba tid */
2380                 p++;                    /* del ba tid */
2381                 p += 2;                 /* add ba ssn */
2382                 p += 4;                 /* reserved */
2383         }
2384
2385         if((err = cmd(ctlr, 24, c, p - c)) != nil)
2386                 return err;
2387         sta->id = id;
2388         return nil;
2389 }
2390
2391 static char*
2392 setphycontext(Ctlr *ctlr, int amr)
2393 {
2394         uchar c[Tcmdsize], *p;
2395         int phyid;
2396         char *err;
2397
2398         phyid = ctlr->phyid;
2399         if(phyid < 0){
2400                 if(amr == CmdRemove)
2401                         return nil;
2402                 amr = CmdAdd;
2403                 phyid = 0;
2404         } else if(amr == CmdAdd)
2405                 amr = CmdModify;
2406
2407         memset(p = c, 0, sizeof(c));
2408         put32(p, phyid);        // id and color
2409         p += 4;
2410         put32(p, amr);
2411         p += 4;
2412         put32(p, 0);            // apply time 0 = immediate
2413         p += 4;
2414         put32(p, 0);            // tx param color ????
2415         p += 4;
2416
2417         *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
2418         *p++ = ctlr->channel;   // channel number
2419         *p++ = 0;               // channel width (20MHz<<val)
2420         *p++ = 0;               // pos1 below 
2421
2422         put32(p, ctlr->rfcfg.txantmask);
2423         p += 4;
2424         put32(p, ctlr->rfcfg.rxantmask<<1 | (1<<10) | (1<<12));
2425         p += 4;
2426         put32(p, 0);            // acquisition_data ????
2427         p += 4;
2428         put32(p, 0);            // dsp_cfg_flags
2429         p += 4;
2430
2431         if((err = cmd(ctlr, 8, c, p - c)) != nil)
2432                 return err;
2433
2434         if(amr == CmdRemove)
2435                 phyid = -1;
2436         ctlr->phyid = phyid;
2437         return nil;
2438 }
2439
2440 static u32int
2441 reciprocal(u32int v)
2442 {
2443         return v != 0 ? 0xFFFFFFFFU / v : 0;
2444 }
2445
2446 static char*
2447 setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
2448 {
2449         uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
2450         int macid, i;
2451         char *err;
2452
2453         macid = ctlr->macid;
2454         if(macid < 0){
2455                 if(amr == CmdRemove)
2456                         return nil;
2457                 amr = CmdAdd;
2458                 macid = 0;
2459         } else if(amr == CmdAdd)
2460                 amr = CmdModify;
2461
2462         memset(p = c, 0, sizeof(c));
2463         put32(p, macid);
2464         p += 4;
2465         put32(p, amr);
2466         p += 4;
2467
2468         put32(p, 5);    // mac type 5 = bss
2469         p += 4;
2470
2471         put32(p, 0);    // tsf id ???
2472         p += 4;
2473
2474         memmove(p, edev->ea, 6);
2475         p += 8;
2476
2477         memmove(p, ctlr->bssid, 6);
2478         p += 8;
2479
2480         put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
2481         p += 4;
2482         put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
2483         p += 4;
2484
2485         put32(p, 0);    // protection flags
2486         p += 4;
2487
2488         put32(p, ctlr->rxflags & RFlagShPreamble);
2489         p += 4;
2490         put32(p, ctlr->rxflags & RFlagShSlot);
2491         p += 4;
2492         put32(p, ctlr->rxfilter);
2493         p += 4;
2494
2495         put32(p, 0);    // qos flags
2496         p += 4;
2497
2498         for(i = 0; i < 4; i++){
2499                 put16(p, 0x07);         // cw_min
2500                 p += 2;
2501                 put16(p, 0x0f);         // cw_max
2502                 p += 2;
2503                 *p++ = 2;               // aifsn
2504                 *p++ = (1<<i);          // fifos_mask
2505                 put16(p, 102*32);       // edca_txop
2506                 p += 2;
2507         }
2508         p += 8;
2509
2510         if(bss != nil){
2511                 int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
2512
2513                 /* is assoc */
2514                 put32(p, bss->aid != 0);
2515                 p += 4;
2516
2517                 /* dtim time (system time) */
2518                 put32(p, bss->rs + dtimoff);
2519                 p += 4;
2520
2521                 /* dtim tsf */
2522                 put64(p, bss->ts + dtimoff);
2523                 p += 8;
2524
2525                 /* beacon interval */
2526                 put32(p, bss->ival);
2527                 p += 4;
2528                 put32(p, reciprocal(bss->ival));
2529                 p += 4;
2530
2531                 /* dtim interval */
2532                 put32(p, bss->ival * bss->dtimperiod);
2533                 p += 4;
2534                 put32(p, reciprocal(bss->ival * bss->dtimperiod));
2535                 p += 4;
2536
2537                 /* listen interval */
2538                 put32(p, 10);
2539                 p += 4;
2540
2541                 /* assoc id */
2542                 put32(p, bss->aid & 0x3fff);
2543                 p += 4;
2544
2545                 /* assoc beacon arrive time */
2546                 put32(p, bss->rs);
2547                 p += 4;
2548         }
2549         USED(p);
2550
2551         if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
2552                 return err;
2553
2554         if(amr == CmdRemove)
2555                 macid = -1;
2556         ctlr->macid = macid;
2557
2558         return nil;
2559 }
2560
2561 static char*
2562 setbindingcontext(Ctlr *ctlr, int amr)
2563 {
2564         uchar c[Tcmdsize], *p;
2565         int bindid;
2566         char *err;
2567         int i;
2568
2569         bindid = ctlr->bindid;
2570         if(bindid < 0){
2571                 if(amr == CmdRemove)
2572                         return nil;
2573                 amr = CmdAdd;
2574                 bindid = 0;
2575         } else if(amr == CmdAdd)
2576                 amr = CmdModify;
2577
2578         if(ctlr->phyid < 0)
2579                 return "setbindingcontext: no phyid";
2580         if(ctlr->macid < 0)
2581                 return "setbindingcontext: no macid";
2582
2583         p = c;
2584         put32(p, bindid);
2585         p += 4;
2586         put32(p, amr);
2587         p += 4;
2588
2589         i = 0;
2590         if(amr != CmdRemove){
2591                 put32(p, ctlr->macid);
2592                 p += 4;
2593                 i++;
2594         }
2595         for(; i < 3; i++){
2596                 put32(p, -1);
2597                 p += 4;
2598         }
2599         put32(p, ctlr->phyid);
2600         p += 4;
2601
2602         if((err = cmd(ctlr, 43, c, p - c)) != nil)
2603                 return err;
2604
2605         if(amr == CmdRemove)
2606                 bindid = -1;
2607         ctlr->bindid = bindid;
2608         return nil;
2609 }
2610
2611 static int
2612 timeeventdone(void *arg)
2613 {
2614         Ctlr *ctlr = arg;
2615         return ctlr->te.id == -1 || ctlr->te.active != 0;
2616 }
2617
2618 static char*
2619 settimeevent(Ctlr *ctlr, int amr, int ival)
2620 {
2621         int duration, delay, timeid;
2622         uchar c[9*4], *p;
2623         char *err;
2624
2625         switch(amr){
2626         case CmdAdd:
2627                 timeid = ctlr->te.id;
2628                 if(timeid == -1)
2629                         timeid = 0;
2630                 else {
2631                         if(ctlr->te.active)
2632                                 return nil;
2633                         amr = CmdModify;
2634                 }
2635                 break;
2636         default:
2637                 timeid = ctlr->te.id;
2638                 if(timeid == -1)
2639                         return nil;
2640                 break;
2641         }
2642
2643         if(ival){
2644                 duration = ival*2;
2645                 delay = ival/2;
2646         } else {
2647                 duration = 1024;
2648                 delay = 0;
2649         }
2650
2651         memset(p = c, 0, sizeof(c));
2652         put32(p, ctlr->macid);
2653         p += 4;
2654         put32(p, amr);
2655         p += 4;
2656         put32(p, timeid);
2657         p += 4;
2658
2659         put32(p, 0);    // apply time
2660         p += 4;
2661         put32(p, delay);
2662         p += 4;
2663         put32(p, 0);    // depends on
2664         p += 4;
2665         put32(p, 1);    // interval
2666         p += 4;
2667         put32(p, duration);
2668         p += 4;
2669         *p++ = 1;       // repeat
2670         *p++ = 0;       // max frags
2671         put16(p, 1<<0 | 1<<1 | 1<<11);  // policy
2672         p += 2;
2673
2674         ctlr->te.active = 0;
2675         if((err =  cmd(ctlr, 41, c, p - c)) != nil)
2676                 return err;
2677
2678         if(amr == CmdRemove){
2679                 ctlr->te.active = 0;
2680                 ctlr->te.id = -1;
2681                 return nil;
2682         }
2683         tsleep(&ctlr->te, timeeventdone, ctlr, 100);
2684         return ctlr->te.active? nil: "timeevent did not start";
2685 }
2686
2687
2688 static char*
2689 setbindingquotas(Ctlr *ctlr, int bindid)
2690 {
2691         uchar c[4*(3*4)], *p;
2692         int i;
2693
2694         i = 0;
2695         p = c;
2696
2697         if(bindid != -1){
2698                 put32(p, bindid);
2699                 p += 4;
2700                 put32(p, 128);
2701                 p += 4;
2702                 put32(p, 0);
2703                 p += 4;
2704                 i++;
2705         }
2706         for(; i < 4; i++){
2707                 put32(p, -1);
2708                 p += 4;
2709                 put32(p, 0);
2710                 p += 4;
2711                 put32(p, 0);
2712                 p += 4;
2713         }
2714
2715         return cmd(ctlr, 44, c, p - c);
2716 }
2717
2718 static char*
2719 setmcastfilter(Ctlr *ctlr)
2720 {
2721         uchar *p;
2722         char *err;
2723         Block *b;
2724
2725         b = allocb(4+6+2);
2726         p = b->rp;
2727
2728         *p++ = 1;       // filter own
2729         *p++ = 0;       // port id
2730         *p++ = 0;       // count
2731         *p++ = 1;       // pass all
2732
2733         memmove(p, ctlr->bssid, 6);
2734         p += 6;
2735         *p++ = 0;
2736         *p++ = 0;
2737
2738         b->wp = p;
2739         if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
2740                 freeb(b);
2741                 return err;
2742         }
2743         return flushq(ctlr, 4);
2744 }
2745
2746 static char*
2747 setmacpowermode(Ctlr *ctlr)
2748 {
2749         uchar c[4 + 2+2 + 4+4+4+4 + 1+1 + 2+2 + 1+1+1+1 + 1+1+1+1 + 1+1], *p;
2750
2751         p = c;
2752         put32(p, ctlr->macid);
2753         p += 4;
2754
2755         put16(p, 0);    // flags
2756         p += 2;
2757         put16(p, 5);    // keep alive seconds
2758         p += 2;
2759
2760         put32(p, 0);    // rx data timeout
2761         p += 4;
2762         put32(p, 0);    // tx data timeout
2763         p += 4;
2764         put32(p, 0);    // rx data timeout uapsd
2765         p += 4;
2766         put32(p, 0);    // tx data timeout uapsd
2767         p += 4;
2768
2769         *p++ = 0;       // lprx rssi threshold
2770         *p++ = 0;       // skip dtim periods
2771
2772         put16(p, 0);    // snooze interval
2773         p += 2;
2774         put16(p, 0);    // snooze window
2775         p += 2;
2776
2777         *p++ = 0;       // snooze step
2778         *p++ = 0;       // qndp tid
2779         *p++ = 0;       // uapsd ac flags
2780         *p++ = 0;       // uapsd max sp
2781
2782         *p++ = 0;       // heavy tx thld packets
2783         *p++ = 0;       // heavy rx thld packets
2784
2785         *p++ = 0;       // heavy tx thld percentage
2786         *p++ = 0;       // heavy rx thld percentage
2787
2788         *p++ = 0;       // limited ps threshold
2789         *p++ = 0;       // reserved
2790
2791         return cmd(ctlr, 169, c, p - c);
2792 }
2793
2794 static char*
2795 disablebeaconfilter(Ctlr *ctlr)
2796 {
2797         uchar c[11*4];
2798
2799         memset(c, 0, sizeof(c));
2800         return cmd(ctlr, 210, c, 11*4);
2801 }
2802
2803 static char*
2804 updatedevicepower(Ctlr *ctlr)
2805 {
2806         uchar c[4];
2807
2808         memset(c, 0, sizeof(c));
2809         put16(c, 0<<13 | 1<<0); // cont active off, pm enable
2810
2811         return cmd(ctlr, 119, c, 4);
2812 }
2813
2814 static char*
2815 postboot7000(Ctlr *ctlr)
2816 {
2817         char *err;
2818
2819         if(ctlr->calib.done == 0){
2820                 if((err = readnvmconfig(ctlr)) != nil)
2821                         return err;
2822         }
2823
2824         if((err = sendtxantconfig(ctlr, ctlr->rfcfg.txantmask)) != nil)
2825                 return err;
2826
2827         if(ctlr->calib.done == 0){
2828                 if((err = sendphyconfig(ctlr,
2829                         ctlr->fw->physku,
2830                         ctlr->fw->init.defcalib.flowmask,
2831                         ctlr->fw->init.defcalib.eventmask)) != nil)
2832                         return err;
2833
2834                 /* wait to collect calibration records */
2835                 if(irqwait(ctlr, Ierr, 2000))
2836                         return "calibration failed";
2837
2838                 if(ctlr->calib.done == 0){
2839                         print("iwl: no calibration results\n");
2840                         ctlr->calib.done = 1;
2841                 }
2842         } else {
2843                 Block *b;
2844                 int i;
2845
2846                 for(i = 0; i < nelem(ctlr->calib.cmd); i++){
2847                         if((b = ctlr->calib.cmd[i]) == nil)
2848                                 continue;
2849                         b = copyblock(b, BLEN(b));
2850                         if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
2851                                 freeb(b);
2852                                 return err;
2853                         }
2854                         if((err = flushq(ctlr, 4)) != nil)
2855                                 return err;
2856                 }
2857
2858                 if((err = sendphyconfig(ctlr,
2859                         ctlr->fw->physku,
2860                         ctlr->fw->main.defcalib.flowmask,
2861                         ctlr->fw->main.defcalib.eventmask)) != nil)
2862                         return err;
2863
2864                 if((err = sendbtcoexadv(ctlr)) != nil)
2865                         return err;
2866
2867                 if((err = updatedevicepower(ctlr)) != nil){
2868                         print("can't update device power: %s\n", err);
2869                         return err;
2870                 }
2871                 if((err = sendmccupdate(ctlr, "ZZ")) != nil){
2872                         print("can't disable beacon filter: %s\n", err);
2873                         return err;
2874                 }
2875                 if((err = disablebeaconfilter(ctlr)) != nil){
2876                         print("can't disable beacon filter: %s\n", err);
2877                         return err;
2878                 }
2879         }
2880
2881         return nil;
2882 }
2883
2884 static char*
2885 postboot6000(Ctlr *ctlr)
2886 {
2887         uchar c[Tcmdsize];
2888         char *err;
2889
2890         /* disable wimax coexistance */
2891         memset(c, 0, sizeof(c));
2892         if((err = cmd(ctlr, 90, c, 4+4*16)) != nil)
2893                 return err;
2894
2895         /* 6235 times out if we calibrate the crystal immediately */
2896         tsleep(&up->sleep, return0, nil, 10);
2897         if(ctlr->type != Type5150){
2898                 /* calibrate crystal */
2899                 memset(c, 0, sizeof(c));
2900                 c[0] = 15;      /* code */
2901                 c[1] = 0;       /* group */
2902                 c[2] = 1;       /* ngroup */
2903                 c[3] = 1;       /* isvalid */
2904                 c[4] = ctlr->eeprom.crystal;
2905                 c[5] = ctlr->eeprom.crystal>>16;
2906                 /* for some reason 8086:4238 needs a second try */
2907                 if(cmd(ctlr, 176, c, 8) != nil && (err = cmd(ctlr, 176, c, 8)) != nil)
2908                         return err;
2909         }
2910
2911         if(ctlr->calib.done == 0){
2912                 /* query calibration (init firmware) */
2913                 memset(c, 0, sizeof(c));
2914                 put32(c + 0*(5*4) + 0, 0xffffffff);
2915                 put32(c + 0*(5*4) + 4, 0xffffffff);
2916                 put32(c + 0*(5*4) + 8, 0xffffffff);
2917                 put32(c + 2*(5*4) + 0, 0xffffffff);
2918                 if((err = cmd(ctlr, 101, c, (((2*(5*4))+4)*2)+4)) != nil)
2919                         return err;
2920
2921                 /* wait to collect calibration records */
2922                 if(irqwait(ctlr, Ierr, 2000))
2923                         return "calibration failed";
2924
2925                 if(ctlr->calib.done == 0){
2926                         print("iwl: no calibration results\n");
2927                         ctlr->calib.done = 1;
2928                 }
2929         } else {
2930                 static uchar cmds[] = {8, 9, 11, 17, 16};
2931                 int q;
2932
2933                 /* send calibration records (runtime firmware) */
2934                 for(q=0; q<nelem(cmds); q++){
2935                         Block *b;
2936                         int i;
2937
2938                         i = cmds[q];
2939                         if(i == 8 && ctlr->type != Type5150 && ctlr->type != Type2030 &&
2940                                 ctlr->type != Type2000)
2941                                 continue;
2942                         if(i == 17 && (ctlr->type >= Type6000 || ctlr->type == Type5150) &&
2943                                 ctlr->type != Type2030 && ctlr->type != Type2000)
2944                                 continue;
2945
2946                         if((b = ctlr->calib.cmd[i]) == nil)
2947                                 continue;
2948                         b = copyblock(b, BLEN(b));
2949                         if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
2950                                 freeb(b);
2951                                 return err;
2952                         }
2953                         if((err = flushq(ctlr, 4)) != nil)
2954                                 return err;
2955                 }
2956
2957                 /* temperature sensor offset */
2958                 switch (ctlr->type){
2959                 case Type6005:
2960                         memset(c, 0, sizeof(c));
2961                         c[0] = 18;
2962                         c[1] = 0;
2963                         c[2] = 1;
2964                         c[3] = 1;
2965                         put16(c + 4, 2700);
2966                         if((err = cmd(ctlr, 176, c, 4+2+2)) != nil)
2967                                 return err;
2968                         break;
2969
2970                 case Type2030:
2971                 case Type2000:
2972                         memset(c, 0, sizeof(c));
2973                         c[0] = 18;
2974                         c[1] = 0;
2975                         c[2] = 1;
2976                         c[3] = 1;
2977                         if(ctlr->eeprom.rawtemp != 0){
2978                                 put16(c + 4, ctlr->eeprom.temp);
2979                                 put16(c + 6, ctlr->eeprom.rawtemp);
2980                         } else{
2981                                 put16(c + 4, 2700);
2982                                 put16(c + 6, 2700);
2983                         }
2984                         put16(c + 8, ctlr->eeprom.volt);
2985                         if((err = cmd(ctlr, 176, c, 4+2+2+2+2)) != nil)
2986                                 return err;
2987                         break;
2988                 }
2989
2990                 if(ctlr->type == Type6005 || ctlr->type == Type6050){
2991                         /* runtime DC calibration */
2992                         memset(c, 0, sizeof(c));
2993                         put32(c + 0*(5*4) + 0, 0xffffffff);
2994                         put32(c + 0*(5*4) + 4, 1<<1);
2995                         if((err = cmd(ctlr, 101, c, (((2*(5*4))+4)*2)+4)) != nil)
2996                                 return err;
2997                 }
2998
2999                 if((err = sendtxantconfig(ctlr, ctlr->rfcfg.txantmask & 7)) != nil)
3000                         return err;
3001
3002                 if(ctlr->type == Type2030){
3003                         if((err = sendbtcoexadv(ctlr)) != nil)
3004                                 return err;
3005                 }
3006         }
3007         return nil;
3008 }
3009
3010 static void
3011 initqueue(Ctlr *ctlr, int qid, int fifo, int chainmode, int window)
3012 {
3013         csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
3014
3015         if(ctlr->family >= 7000 || ctlr->type != Type4965){
3016                 if(ctlr->family >= 7000)
3017                         prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
3018
3019                 if(chainmode)
3020                         prphwrite(ctlr, SchedQChainSel, prphread(ctlr, SchedQChainSel) | (1<<qid));
3021                 else
3022                         prphwrite(ctlr, SchedQChainSel, prphread(ctlr, SchedQChainSel) & ~(1<<qid));
3023
3024                 prphwrite(ctlr, SchedAggrSel, prphread(ctlr, SchedAggrSel) & ~(1<<qid));
3025
3026                 prphwrite(ctlr, SchedQueueRdptr + qid*4, 0);
3027
3028                 /* Set scheduler window size and frame limit. */
3029                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
3030                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4, window<<16 | window);
3031
3032                 if(ctlr->family >= 7000){
3033                         prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 | fifo);
3034                 } else {
3035                         prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 | fifo);
3036                 }
3037         } else {
3038                 if(chainmode)
3039                         prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr, SchedQChainSel4965) | (1<<qid));
3040                 else
3041                         prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr, SchedQChainSel4965) & ~(1<<qid));
3042
3043                 prphwrite(ctlr, SchedQueueRdptr4965 + qid*4, 0);
3044
3045                 /* Set scheduler window size and frame limit. */
3046                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff4965 + qid*8, window);
3047                 memwrite(ctlr, ctlr->sched.base + SchedCtxOff4965 + qid*8 + 4, window<<16);
3048
3049                 prphwrite(ctlr, SchedQueueStatus4965 + qid*4, 0x0007fc01 | fifo<<1);
3050         }
3051 }
3052
3053 static char*
3054 postboot(Ctlr *ctlr)
3055 {
3056         uint ctxoff, ctxlen, dramaddr;
3057         char *err;
3058         int i, f;
3059
3060         if((err = niclock(ctlr)) != nil)
3061                 return err;
3062
3063         if(ctlr->family >= 7000 || ctlr->type != Type4965){
3064                 dramaddr = SchedDramAddr;
3065                 ctxoff = SchedCtxOff;
3066                 ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
3067         } else {
3068                 dramaddr = SchedDramAddr4965;
3069                 ctxoff = SchedCtxOff4965;
3070                 ctxlen = SchedCtxLen4965;
3071         }
3072
3073         ctlr->sched.base = prphread(ctlr, SchedSramAddr);
3074         for(i=0; i < ctxlen; i += 4)
3075                 memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
3076
3077         prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
3078
3079         if(ctlr->family >= 7000) {
3080                 prphwrite(ctlr, SchedEnCtrl, 0);
3081                 prphwrite(ctlr, SchedChainExtEn, 0);
3082         }
3083
3084         for(i = 0; i < nelem(ctlr->tx); i++){
3085                 if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
3086                         f = 4;
3087                 else {
3088                         static char qid2fifo[] = {
3089                                  3, 2, 1, 0, 7, 5, 6,
3090                         };
3091                         f = qid2fifo[i];
3092                 }
3093                 initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
3094         }
3095
3096         /* Enable interrupts for all queues. */
3097         if(ctlr->family >= 7000){
3098                 prphwrite(ctlr, SchedEnCtrl, 1 << 4);
3099         } else if(ctlr->type != Type4965) {
3100                 prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
3101         } else {
3102                 prphwrite(ctlr, SchedIntrMask4965, (1<<ctlr->ntxq)-1);
3103         }
3104
3105         /* Identify TX FIFO rings (0-7). */
3106         if(ctlr->family >= 7000 || ctlr->type != Type4965){
3107                 prphwrite(ctlr, SchedTxFact, 0xff);
3108         } else {
3109                 prphwrite(ctlr, SchedTxFact4965, 0xff);
3110         }
3111
3112         /* Enable DMA channels */
3113         for(i = 0; i < ctlr->ndma; i++)
3114                 csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
3115
3116         /* Auto Retry Enable */
3117         csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
3118
3119         nicunlock(ctlr);
3120
3121         if((err = enablepaging(ctlr)) != nil){
3122                 ctlr->calib.done = 0;
3123                 return err;
3124         }
3125
3126         if(ctlr->family >= 7000)
3127                 return postboot7000(ctlr);
3128         else if(ctlr->type != Type4965)
3129                 return postboot6000(ctlr);
3130
3131         return nil;
3132 }
3133
3134 static char*
3135 loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
3136 {
3137         enum { Maxchunk = 0x20000 };
3138         uchar *dma;
3139         char *err;
3140
3141         while(size > Maxchunk){
3142                 if((err = loadfirmware1(ctlr, dst, data, Maxchunk)) != nil)
3143                         return err;
3144                 size -= Maxchunk;
3145                 data += Maxchunk;
3146                 dst += Maxchunk;
3147         }
3148
3149         dma = mallocalign(size, 16, 0, 0);
3150         if(dma == nil)
3151                 return "no memory for dma";
3152         memmove(dma, data, size);
3153         coherence();
3154         
3155         if((err = niclock(ctlr)) != nil){
3156                 free(dma);
3157                 return err;
3158         }
3159
3160         if(ctlr->family >= 7000 && dst >= 0x40000 && dst < 0x57fff)
3161                 prphwrite(ctlr, LmpmChick, prphread(ctlr, LmpmChick) | ExtAddr);
3162         else
3163                 prphwrite(ctlr, LmpmChick, prphread(ctlr, LmpmChick) & ~ExtAddr);
3164
3165         csr32w(ctlr, FhTxConfig + 9*32, 0);
3166         csr32w(ctlr, FhSramAddr + 9*4, dst);
3167         csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
3168         csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
3169         csr32w(ctlr, FhTxBufStatus + 9*32,
3170                 (1<<FhTxBufStatusTbNumShift) |
3171                 (1<<FhTxBufStatusTbIdxShift) |
3172                 FhTxBufStatusTfbdValid);
3173         csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
3174         nicunlock(ctlr);
3175
3176         err = nil;
3177         if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx)
3178                 err = "dma error / timeout";
3179
3180         if(niclock(ctlr) == nil){
3181                 prphwrite(ctlr, LmpmChick, prphread(ctlr, LmpmChick) & ~ExtAddr);
3182                 nicunlock(ctlr);
3183         }
3184
3185         free(dma);
3186
3187         return err;
3188 }
3189
3190 static char*
3191 setloadstatus(Ctlr *ctlr, u32int val)
3192 {
3193         char *err;
3194
3195         if((err = niclock(ctlr)) != nil)
3196                 return err;
3197         csr32w(ctlr, UcodeLoadStatus, val);
3198         nicunlock(ctlr);
3199         return nil;
3200 }
3201
3202 static char*
3203 loadsections(Ctlr *ctlr, FWSect *sect, int nsect)
3204 {
3205         int i, num;
3206         char *err;
3207
3208         if(ctlr->family >= 8000){
3209                 if((err = niclock(ctlr)) != nil)
3210                         return err;
3211                 prphwrite(ctlr, ReleaseCpuReset, CpuResetBit);
3212                 nicunlock(ctlr);
3213         }
3214
3215         num = 0;
3216         for(i = 0; i < nsect; i++){
3217                 if(sect[i].addr == 0xAAAABBBB)
3218                         break;
3219                 if(sect[i].addr == 0xFFFFCCCC)
3220                         num = 16;
3221                 else {
3222                         if(sect[i].data == nil || sect[i].size == 0)
3223                                 return "bad load section";
3224                         if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data, sect[i].size)) != nil)
3225                                 return err;
3226                         num++;
3227                 }
3228                 if(ctlr->family >= 8000
3229                 && (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
3230                         return err;
3231         }
3232         return nil;
3233 }
3234
3235 static char*
3236 ucodestart(Ctlr *ctlr)
3237 {
3238         memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
3239         if(ctlr->family >= 8000)
3240                 return setloadstatus(ctlr, -1);
3241         csr32w(ctlr, Reset, 0);
3242         return nil;
3243 }
3244
3245 static char*
3246 boot(Ctlr *ctlr)
3247 {
3248         int i, n, size;
3249         uchar *p, *dma;
3250         FWImage *fw;
3251         char *err;
3252
3253         fw = ctlr->fw;
3254
3255         if(fw->boot.text.size == 0){
3256                 if(ctlr->calib.done == 0){
3257                         if((err = loadsections(ctlr, fw->init.sect, fw->init.nsect)) != nil)
3258                                 return err;
3259                         if((err = ucodestart(ctlr)) != nil)
3260                                 return err;
3261
3262                         tsleep(&up->sleep, return0, 0, 100);
3263
3264                         if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive|| !ctlr->fwinfo.valid){
3265                                 return "init firmware boot failed";
3266                         }
3267                         if((err = postboot(ctlr)) != nil)
3268                                 return err;
3269                         if((err = reset(ctlr)) != nil)
3270                                 return err;
3271                 }
3272
3273                 if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect)) != nil)
3274                         return err;
3275                 if((err= ucodestart(ctlr)) != nil)
3276                         return err;
3277
3278                 tsleep(&up->sleep, return0, 0, 100);
3279
3280                 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive || !ctlr->fwinfo.valid)
3281                         return "main firmware boot failed";
3282
3283                 return postboot(ctlr);
3284         }
3285
3286         if(ctlr->family >= 7000)
3287                 return "wrong firmware image";
3288
3289         size = ROUND(fw->init.data.size, 16) + ROUND(fw->init.text.size, 16);
3290         dma = mallocalign(size, 16, 0, 0);
3291         if(dma == nil)
3292                 return "no memory for dma";
3293
3294         if((err = niclock(ctlr)) != nil){
3295                 free(dma);
3296                 return err;
3297         }
3298
3299         p = dma;
3300         memmove(p, fw->init.data.data, fw->init.data.size);
3301         coherence();
3302         prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
3303         prphwrite(ctlr, BsmDramDataSize, fw->init.data.size);
3304         p += ROUND(fw->init.data.size, 16);
3305         memmove(p, fw->init.text.data, fw->init.text.size);
3306         coherence();
3307         prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
3308         prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
3309
3310         nicunlock(ctlr);
3311         if((err = niclock(ctlr)) != nil){
3312                 free(dma);
3313                 return err;
3314         }
3315
3316         p = fw->boot.text.data;
3317         n = fw->boot.text.size/4;
3318         for(i=0; i<n; i++, p += 4)
3319                 prphwrite(ctlr, BsmSramBase+i*4, get32(p));
3320
3321         prphwrite(ctlr, BsmWrMemSrc, 0);
3322         prphwrite(ctlr, BsmWrMemDst, 0);
3323         prphwrite(ctlr, BsmWrDwCount, n);
3324
3325         prphwrite(ctlr, BsmWrCtrl, 1<<31);
3326
3327         for(i=0; i<1000; i++){
3328                 if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
3329                         break;
3330                 delay(10);
3331         }
3332         if(i == 1000){
3333                 nicunlock(ctlr);
3334                 free(dma);
3335                 return "bootcode timeout";
3336         }
3337
3338         prphwrite(ctlr, BsmWrCtrl, 1<<30);
3339         nicunlock(ctlr);
3340
3341         csr32w(ctlr, Reset, 0);
3342         if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
3343                 free(dma);
3344                 return "boot firmware boot failed";
3345         }
3346         free(dma);
3347
3348         size = ROUND(fw->main.data.size, 16) + ROUND(fw->main.text.size, 16);
3349         dma = mallocalign(size, 16, 0, 0);
3350         if(dma == nil)
3351                 return "no memory for dma";
3352         if((err = niclock(ctlr)) != nil){
3353                 free(dma);
3354                 return err;
3355         }
3356         p = dma;
3357         memmove(p, fw->main.data.data, fw->main.data.size);
3358         coherence();
3359         prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
3360         prphwrite(ctlr, BsmDramDataSize, fw->main.data.size);
3361         p += ROUND(fw->main.data.size, 16);
3362         memmove(p, fw->main.text.data, fw->main.text.size);
3363         coherence();
3364         prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
3365         prphwrite(ctlr, BsmDramTextSize, fw->main.text.size | (1<<31));
3366         nicunlock(ctlr);
3367
3368         if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
3369                 free(dma);
3370                 return "main firmware boot failed";
3371         }
3372         free(dma);
3373         return postboot(ctlr);
3374 }
3375
3376 static int
3377 txqready(void *arg)
3378 {
3379         TXQ *q = arg;
3380         return q->n < Ntxqmax;
3381 }
3382
3383 static char*
3384 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
3385 {
3386         int hdrlen;
3387         Block *bcmd;
3388         uchar *d, *c;
3389         TXQ *q;
3390
3391         assert(qid < ctlr->ntxq);
3392
3393         if((code & 0xFF00) != 0)
3394                 hdrlen = 8;
3395         else
3396                 hdrlen = 4;
3397
3398         if(hdrlen+size > Tcmdsize)
3399                 bcmd = allocb(hdrlen + size);
3400         else
3401                 bcmd = nil;
3402
3403         ilock(ctlr);
3404         q = &ctlr->tx[qid];
3405         while(q->n >= Ntxqmax && !ctlr->broken){
3406                 iunlock(ctlr);
3407                 qlock(q);
3408                 if(!waserror()){
3409                         tsleep(q, txqready, q, 5);
3410                         poperror();
3411                 }
3412                 qunlock(q);
3413                 ilock(ctlr);
3414         }
3415         if(ctlr->broken){
3416                 iunlock(ctlr);
3417                 return "qcmd: broken";
3418         }
3419         q->n++;
3420         q->lastcmd = code;
3421
3422         q->b[q->i] = block;
3423         if(bcmd != nil){
3424                 bcmd->next = q->b[q->i];
3425                 q->b[q->i] = bcmd;
3426
3427                 c = bcmd->rp;
3428                 bcmd->wp = c + hdrlen + size;
3429         } else {
3430                 c = q->c + q->i * Tcmdsize;
3431         }
3432
3433         /* build command */
3434         if(hdrlen == 8){
3435                 c[0] = code;
3436                 c[1] = code>>8; /* group id */
3437                 c[2] = q->i;
3438                 c[3] = qid;
3439                 put16(c+4, size);
3440                 c[6] = 0;
3441                 c[7] = code>>16;
3442         } else {
3443                 c[0] = code;
3444                 c[1] = 0;       /* flags */
3445                 c[2] = q->i;
3446                 c[3] = qid;
3447         }
3448         if(size > 0)
3449                 memmove(c+hdrlen, data, size);
3450         size += hdrlen;
3451
3452         /* build descriptor */
3453         d = q->d + q->i * Tdscsize;
3454         *d++ = 0;
3455         *d++ = 0;
3456         *d++ = 0;
3457         *d++ = 1 + (block != nil); /* nsegs */
3458         put32(d, PCIWADDR(c));  d += 4;
3459         put16(d, size << 4); d += 2;
3460         if(block != nil){
3461                 size = BLEN(block);
3462                 put32(d, PCIWADDR(block->rp)); d += 4;
3463                 put16(d, size << 4); d += 2;
3464         }
3465         USED(d);
3466
3467         coherence();
3468
3469         q->i = (q->i+1) % Ntx;
3470         csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
3471
3472         iunlock(ctlr);
3473
3474         return nil;
3475 }
3476
3477 static int
3478 txqempty(void *arg)
3479 {
3480         TXQ *q = arg;
3481         return q->n == 0;
3482 }
3483
3484 static char*
3485 flushq(Ctlr *ctlr, uint qid)
3486 {
3487         TXQ *q;
3488         int i;
3489
3490         q = &ctlr->tx[qid];
3491         qlock(q);
3492         for(i = 0; i < 200 && !ctlr->broken; i++){
3493                 if(txqempty(q)){
3494                         qunlock(q);
3495                         return nil;
3496                 }
3497                 if(!waserror()){
3498                         tsleep(q, txqempty, q, 10);
3499                         poperror();
3500                 }
3501         }
3502         qunlock(q);
3503         if(ctlr->broken)
3504                 return "flushq: broken";
3505         ctlr->broken = 1;
3506         return "flushq: timeout";
3507 }
3508
3509 static char*
3510 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
3511 {
3512         char *err;
3513
3514         if(0) print("cmd %ud\n", code);
3515
3516         if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
3517         || (err = flushq(ctlr, 4)) != nil){
3518                 print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
3519                 return err;
3520         }
3521         return nil;
3522 }
3523
3524 static void
3525 setled(Ctlr *ctlr, int which, int on, int off)
3526 {
3527         uchar c[8];
3528
3529         if(ctlr->family >= 7000)
3530                 return; // TODO
3531
3532         csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
3533         put32(c, 10000);
3534         c[4] = which;
3535         c[5] = on;
3536         c[6] = off;
3537         c[7] = 0;
3538         cmd(ctlr, 72, c, sizeof(c));
3539 }
3540
3541 static char*
3542 rxoff7000(Ether *edev, Ctlr *ctlr)
3543 {
3544         char *err;
3545         int i;
3546
3547         for(i = 0; i < nelem(ctlr->tx); i++)
3548                 flushq(ctlr, i);
3549         settimeevent(ctlr, CmdRemove, 0);
3550
3551         if((err = setbindingquotas(ctlr, -1)) != nil){
3552                 print("can't disable quotas: %s\n", err);
3553                 return err;
3554         }
3555         if((err = delstation(ctlr, &ctlr->bss)) != nil){
3556                 print("can't remove bss station: %s\n", err);
3557                 return err;
3558         }
3559         if((err = delstation(ctlr, &ctlr->bcast)) != nil){
3560                 print("can't remove bcast station: %s\n", err);
3561                 return err;
3562         }
3563         if((err = setbindingcontext(ctlr, CmdRemove)) != nil){
3564                 print("removing bindingcontext: %s\n", err);
3565                 return err;
3566         }
3567         if((err = setmaccontext(edev, ctlr, CmdRemove, nil)) != nil){
3568                 print("removing maccontext: %s\n", err);
3569                 return err;
3570         }
3571         if((err = setphycontext(ctlr, CmdRemove)) != nil){
3572                 print("setphycontext: %s\n", err);
3573                 return err;
3574         }
3575         return nil;
3576 }
3577
3578 static char*
3579 rxon7000(Ether *edev, Ctlr *ctlr)
3580 {
3581         char *err;
3582
3583         if((err = setphycontext(ctlr, CmdAdd)) != nil){
3584                 print("setphycontext: %s\n", err);
3585                 return err;
3586         }
3587         if((err = setmaccontext(edev, ctlr, CmdAdd, nil)) != nil){
3588                 print("setmaccontext: %s\n", err);
3589                 return err;
3590         }
3591         if((err = setbindingcontext(ctlr, CmdAdd)) != nil){
3592                 print("removing bindingcontext: %s\n", err);
3593                 return err;
3594         }
3595         if((err = setmcastfilter(ctlr)) != nil){
3596                 print("can't set mcast filter: %s\n", err);
3597                 return err;
3598         }
3599         if((err = setmacpowermode(ctlr)) != nil){
3600                 print("can't set mac power: %s\n", err);
3601                 return err;
3602         }
3603         if((err = setbindingquotas(ctlr, ctlr->aid != 0 ? ctlr->bindid : -1)) != nil){
3604                 print("can't set binding quotas: %s\n", err);
3605                 return err;
3606         }
3607         return nil;
3608 }
3609
3610 static char*
3611 rxon6000(Ether *edev, Ctlr *ctlr)
3612 {
3613         uchar c[Tcmdsize], *p;
3614         char *err;
3615
3616         memset(p = c, 0, sizeof(c));
3617         memmove(p, edev->ea, 6); p += 8;        /* myaddr */
3618         memmove(p, ctlr->bssid, 6); p += 8;     /* bssid */
3619         memmove(p, edev->ea, 6); p += 8;        /* wlap */
3620         *p++ = 3;                               /* mode (STA) */
3621         *p++ = 0;                               /* air (?) */
3622         /* rxchain */
3623         put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
3624         p += 2;
3625         *p++ = 0xff;                            /* ofdm mask (not yet negotiated) */
3626         *p++ = 0x0f;                            /* cck mask (not yet negotiated) */
3627         put16(p, ctlr->aid & 0x3fff);
3628         p += 2;                                 /* aid */
3629         put32(p, ctlr->rxflags);
3630         p += 4;
3631         put32(p, ctlr->rxfilter);
3632         p += 4;
3633         *p++ = ctlr->channel;
3634         p++;                                    /* reserved */
3635         *p++ = 0xff;                            /* ht single mask */
3636         *p++ = 0xff;                            /* ht dual mask */
3637         if(ctlr->type != Type4965){
3638                 *p++ = 0xff;                    /* ht triple mask */
3639                 p++;                            /* reserved */
3640                 put16(p, 0); p += 2;            /* acquisition */
3641                 p += 2;                         /* reserved */
3642         }
3643         if((err = cmd(ctlr, 16, c, p - c)) != nil){
3644                 print("rxon6000: %s\n", err);
3645                 return err;
3646         }
3647         return nil;
3648 }
3649
3650 static char*
3651 rxon(Ether *edev, Wnode *bss)
3652 {
3653         Ctlr *ctlr = edev->ctlr;
3654         char *err;
3655
3656         if(ctlr->family >= 7000)
3657                 if((err = rxoff7000(edev, ctlr)) != nil)
3658                         goto Out;
3659
3660         ctlr->rxfilter = FilterNoDecrypt | FilterMulticast | FilterBeacon;
3661         if(ctlr->family >= 7000)
3662                 ctlr->rxfilter |= FilterNoDecryptMcast;
3663         if(ctlr->prom)
3664                 ctlr->rxfilter |= FilterPromisc;
3665
3666         ctlr->rxflags =  RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
3667         if(bss != nil){
3668                 ctlr->aid = bss->aid;
3669                 ctlr->channel = bss->channel;
3670                 memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
3671                 if(bss->cap & (1<<5))
3672                         ctlr->rxflags |= RFlagShPreamble;
3673                 if(bss->cap & (1<<10))
3674                         ctlr->rxflags |= RFlagShSlot;
3675                 if(ctlr->aid != 0){
3676                         ctlr->rxfilter |= FilterBSS;
3677                         ctlr->rxfilter &= ~FilterBeacon;
3678                         ctlr->bss.id = -1;
3679                 } else {
3680                         ctlr->bcast.id = -1;
3681                 }
3682         } else {
3683                 ctlr->aid = 0;
3684                 memmove(ctlr->bssid, edev->bcast, sizeof(ctlr->bssid));
3685                 ctlr->bcast.id = -1;
3686                 ctlr->bss.id = -1;
3687         }
3688
3689         if(ctlr->aid != 0)
3690                 setled(ctlr, 2, 0, 1);          /* on when associated */
3691         else if(memcmp(ctlr->bssid, edev->bcast, sizeof(ctlr->bssid)) != 0)
3692                 setled(ctlr, 2, 10, 10);        /* slow blink when connecting */
3693         else
3694                 setled(ctlr, 2, 5, 5);          /* fast blink when scanning */
3695
3696         if(ctlr->wifi->debug)
3697                 print("#l%d: rxon: bssid %E, aid %x, channel %d, rxfilter %ux, rxflags %ux\n",
3698                         edev->ctlrno, ctlr->bssid, ctlr->aid, ctlr->channel, ctlr->rxfilter, ctlr->rxflags);
3699
3700         if(ctlr->family >= 7000)
3701                 err = rxon7000(edev, ctlr);
3702         else
3703                 err = rxon6000(edev, ctlr);
3704         if(err != nil)
3705                 goto Out;
3706
3707         if(ctlr->bcast.id == -1){
3708                 if((err = setstation(ctlr,
3709                         (ctlr->type != Type4965)? 15: 31,
3710                         StaTypeGeneralPurpose,
3711                         edev->bcast,
3712                         &ctlr->bcast)) != nil)
3713                         goto Out;
3714         }
3715         if(ctlr->bss.id == -1 && bss != nil && ctlr->aid != 0){
3716                 if((err = setstation(ctlr,
3717                         0,
3718                         StaTypeLink,
3719                         bss->bssid,
3720                         &ctlr->bss)) != nil)
3721                         goto Out;
3722
3723                 if(ctlr->family >= 7000)
3724                         if((err = setmaccontext(edev, ctlr, CmdModify, bss)) != nil)
3725                                 goto Out;
3726         }
3727 Out:
3728         return err;
3729 }
3730
3731 static void
3732 transmit(Wifi *wifi, Wnode *wn, Block *b)
3733 {
3734         int flags, rate, ant;
3735         uchar c[Tcmdsize], *p;
3736         Ether *edev;
3737         Station *sta;
3738         Ctlr *ctlr;
3739         Wifipkt *w;
3740         char *err;
3741
3742         edev = wifi->ether;
3743         ctlr = edev->ctlr;
3744
3745         qlock(ctlr);
3746         if(ctlr->attached == 0 || ctlr->broken){
3747 Broken:
3748                 qunlock(ctlr);
3749                 freeb(b);
3750                 return;
3751         }
3752
3753         if((wn->channel != ctlr->channel)
3754         || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0))){
3755                 if(rxon(edev, wn) != nil)
3756                         goto Broken;
3757         }
3758
3759         /*
3760          * unless authenticated, the firmware will hop
3761          * channels unless we force it onto a channel using
3762          * a timeevent.
3763          */
3764         if(ctlr->aid == 0 && ctlr->family >= 7000)
3765                 if(settimeevent(ctlr, CmdAdd, wn->ival) != nil)
3766                         goto Broken;
3767
3768         if(b == nil){
3769                 /* association note has no data to transmit */
3770                 qunlock(ctlr);
3771                 return;
3772         }
3773         flags = 0;
3774         sta = &ctlr->bcast;
3775         p = wn->minrate;
3776         w = (Wifipkt*)b->rp;
3777         if((w->a1[0] & 1) == 0){
3778                 flags |= TFlagNeedACK;
3779
3780                 if(BLEN(b) > 512-4)
3781                         flags |= TFlagNeedRTS;
3782
3783                 if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
3784                         sta = &ctlr->bss;
3785                         p = wn->actrate;
3786                 }
3787
3788                 if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
3789                         if(ctlr->family >= 7000 || ctlr->type != Type4965){
3790                                 flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
3791                                 flags |= TFlagNeedProtection;
3792                         } else
3793                                 flags |= TFlagFullTxOp;
3794                 }
3795         }
3796
3797         if(sta->id == -1)
3798                 goto Broken;
3799
3800         if(p >= wifi->rates)
3801                 rate = p - wifi->rates;
3802         else
3803                 rate = 0;
3804
3805         /* select first available antenna */
3806         ant = ctlr->rfcfg.txantmask & 7;
3807         ant |= (ant == 0);
3808         ant = ((ant - 1) & ant) ^ ant;
3809
3810         memset(p = c, 0, sizeof(c));
3811         put16(p, BLEN(b));
3812         p += 2;
3813         p += 2;         /* lnext */
3814         put32(p, flags);
3815         p += 4;
3816         put32(p, 0);
3817         p += 4;         /* scratch */
3818
3819         *p++ = ratetab[rate].plcp;
3820         *p++ = ratetab[rate].flags | (ant<<6);
3821
3822         p += 2;         /* xflags */
3823         *p++ = sta->id; /* station id */
3824         *p++ = 0;       /* security */
3825         *p++ = 0;       /* linkq */
3826         p++;            /* reserved */
3827         p += 16;        /* key */
3828         p += 2;         /* fnext */
3829         p += 2;         /* reserved */
3830         put32(p, ~0);   /* lifetime */
3831         p += 4;
3832
3833         /* BUG: scratch ptr? not clear what this is for */
3834         put32(p, PCIWADDR(ctlr->kwpage));
3835         p += 5;
3836
3837         *p++ = 60;      /* rts ntries */
3838         *p++ = 15;      /* data ntries */
3839         *p++ = 0;       /* tid */
3840         put16(p, 0);    /* timeout */
3841         p += 2;
3842         p += 2;         /* txop */
3843         qunlock(ctlr);
3844
3845         if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
3846                 print("#l%d: transmit %s\n", edev->ctlrno, err);
3847                 freeb(b);
3848         }
3849 }
3850
3851 static long
3852 iwlctl(Ether *edev, void *buf, long n)
3853 {
3854         Ctlr *ctlr;
3855
3856         ctlr = edev->ctlr;
3857         if(n >= 5 && memcmp(buf, "reset", 5) == 0){
3858                 ctlr->broken = 1;
3859                 return n;
3860         }
3861         if(ctlr->wifi)
3862                 return wifictl(ctlr->wifi, buf, n);
3863         return 0;
3864 }
3865
3866 static long
3867 iwlifstat(Ether *edev, void *buf, long n, ulong off)
3868 {
3869         Ctlr *ctlr;
3870
3871         ctlr = edev->ctlr;
3872         if(ctlr->wifi)
3873                 return wifistat(ctlr->wifi, buf, n, off);
3874         return 0;
3875 }
3876
3877 static void
3878 setoptions(Ether *edev)
3879 {
3880         Ctlr *ctlr;
3881         int i;
3882
3883         ctlr = edev->ctlr;
3884         for(i = 0; i < edev->nopt; i++)
3885                 wificfg(ctlr->wifi, edev->opt[i]);
3886 }
3887
3888 static void
3889 iwlpromiscuous(void *arg, int on)
3890 {
3891         Ether *edev;
3892         Ctlr *ctlr;
3893
3894         edev = arg;
3895         ctlr = edev->ctlr;
3896         qlock(ctlr);
3897         ctlr->prom = on;
3898         rxon(edev, ctlr->wifi->bss);
3899         qunlock(ctlr);
3900 }
3901
3902 static void
3903 iwlmulticast(void *, uchar*, int)
3904 {
3905 }
3906
3907 static void
3908 iwlrecover(void *arg)
3909 {
3910         Ether *edev;
3911         Ctlr *ctlr;
3912
3913         edev = arg;
3914         ctlr = edev->ctlr;
3915         while(waserror())
3916                 ;
3917         for(;;){
3918                 tsleep(&up->sleep, return0, 0, 4000);
3919
3920                 qlock(ctlr);
3921                 for(;;){
3922                         if(ctlr->broken == 0)
3923                                 break;
3924
3925                         if(ctlr->power)
3926                                 poweroff(ctlr);
3927
3928                         if((csr32r(ctlr, Gpc) & RfKill) == 0)
3929                                 break;
3930
3931                         if(reset(ctlr) != nil)
3932                                 break;
3933                         if(boot(ctlr) != nil)
3934                                 break;
3935
3936                         rxon(edev, ctlr->wifi->bss);
3937                         break;
3938                 }
3939                 qunlock(ctlr);
3940         }
3941 }
3942
3943 static void
3944 iwlattach(Ether *edev)
3945 {
3946         FWImage *fw;
3947         Ctlr *ctlr;
3948         char *err;
3949
3950         ctlr = edev->ctlr;
3951         eqlock(ctlr);
3952         if(waserror()){
3953                 print("#l%d: %s\n", edev->ctlrno, up->errstr);
3954                 if(ctlr->power)
3955                         poweroff(ctlr);
3956                 qunlock(ctlr);
3957                 nexterror();
3958         }
3959         if(ctlr->attached == 0){
3960                 if((csr32r(ctlr, Gpc) & RfKill) == 0)
3961                         error("wifi disabled by switch");
3962
3963                 if(ctlr->fw == nil){
3964                         char *fn;
3965
3966                         fn = ctlr->fwname;
3967                         if(fn == nil){
3968                                 fn = fwname[ctlr->type];
3969                                 if(ctlr->type == Type6005){
3970                                         switch(ctlr->pdev->did){
3971                                         case 0x0082:    /* Centrino Advanced-N 6205 */
3972                                         case 0x0085:    /* Centrino Advanced-N 6205 */
3973                                                 break;
3974                                         default:        /* Centrino Advanced-N 6030, 6235 */
3975                                                 fn = "iwn-6030";
3976                                         }
3977                                 }
3978                         }
3979                         fw = readfirmware(fn);
3980                         print("#l%d: firmware: %s, rev %ux, build %ud, size [%d] %ux+%ux + [%d] %ux+%ux + %ux\n",
3981                                 edev->ctlrno, fn,
3982                                 fw->rev, fw->build,
3983                                 fw->main.nsect, fw->main.text.size, fw->main.data.size,
3984                                 fw->init.nsect, fw->init.text.size, fw->init.data.size,
3985                                 fw->boot.text.size);
3986                         ctlr->fw = fw;
3987                 }
3988
3989                 if(ctlr->family >= 7000){
3990                         u32int u = ctlr->fw->physku;
3991
3992                         ctlr->rfcfg.type = u & 3;       u >>= 2;
3993                         ctlr->rfcfg.step = u & 3;       u >>= 2;
3994                         ctlr->rfcfg.dash = u & 3;       u >>= 12;
3995
3996                         ctlr->rfcfg.txantmask = u & 15; u >>= 4;
3997                         ctlr->rfcfg.rxantmask = u & 15;
3998                 }
3999
4000                 if((err = reset(ctlr)) != nil)
4001                         error(err);
4002                 if((err = boot(ctlr)) != nil)
4003                         error(err);
4004
4005                 if(ctlr->wifi == nil){
4006                         qsetlimit(edev->oq, MaxQueue);
4007
4008                         ctlr->wifi = wifiattach(edev, transmit);
4009                         /* tested with 2230, it has transmit issues using higher bit rates */
4010                         if(ctlr->family >= 7000 || ctlr->type != Type2030)
4011                                 ctlr->wifi->rates = iwlrates;
4012                 }
4013
4014                 setoptions(edev);
4015
4016                 ctlr->attached = 1;
4017
4018                 kproc("iwlrecover", iwlrecover, edev);
4019         }
4020         qunlock(ctlr);
4021         poperror();
4022 }
4023
4024 static void
4025 updatesystime(Ctlr *ctlr, u32int ts)
4026 {
4027         u32int dt = ts - (u32int)ctlr->systime;
4028         ctlr->systime += dt;
4029 }
4030
4031 static void
4032 receive(Ctlr *ctlr)
4033 {
4034         Block *b, *bb;
4035         uchar *d;
4036         RXQ *rx;
4037         TXQ *tx;
4038         uint hw;
4039
4040         rx = &ctlr->rx;
4041         if(ctlr->broken || rx->s == nil || rx->b == nil)
4042                 return;
4043
4044         for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
4045                 int type, flags, idx, qid, len;
4046
4047                 b = rx->b[rx->i];
4048                 if(b == nil)
4049                         continue;
4050
4051                 d = b->rp;
4052                 len = get32(d); d += 4;
4053                 type = *d++;
4054                 flags = *d++;
4055                 USED(flags);
4056                 idx = *d++;
4057                 qid = *d++;
4058
4059                 tx = nil;
4060                 bb = nil;
4061                 if((qid & 0x80) == 0 && qid < ctlr->ntxq){
4062                         tx = &ctlr->tx[qid];
4063                         bb = tx->b[idx];
4064                         tx->b[idx] = nil;
4065                 }
4066
4067                 len &= 0x3fff;
4068                 len -= 4;
4069                 if(len >= 0) switch(type){
4070                 case 1:         /* microcontroller ready */
4071                         setfwinfo(ctlr, d, len);
4072                         break;
4073                 case 24:        /* add node done */
4074                         if(len < 4)
4075                                 break;
4076                         break;
4077                 case 28:        /* tx done */
4078                         if(ctlr->family >= 7000){
4079                                 if(len <= 36 || d[36] == 1 || d[36] == 2)
4080                                         break;
4081                         } else if(ctlr->type == Type4965){
4082                                 if(len <= 20 || d[20] == 1 || d[20] == 2)
4083                                         break;
4084                         } else {
4085                                 if(len <= 32 || d[32] == 1 || d[32] == 2)
4086                                         break;
4087                         }
4088                         if(ctlr->wifi != nil)
4089                                 wifitxfail(ctlr->wifi, bb);
4090                         break;
4091                 case 41:
4092                         if(len < 2*4)
4093                                 break;
4094                         if(get32(d) != 0)
4095                                 break;
4096                         if(ctlr->te.id == -1)
4097                                 ctlr->te.id = get32(d+8);
4098                         break;
4099                 case 42:
4100                         if(len < 6*4)
4101                                 break;
4102                         if(ctlr->te.id == -1 || get32(d+8) != ctlr->te.id)
4103                                 break;
4104                         switch(get32(d+16)){
4105                         case 1:
4106                                 ctlr->te.active = 1;
4107                                 wakeup(&ctlr->te);
4108                                 break;
4109                         case 2:
4110                                 ctlr->te.active = 0;
4111                                 ctlr->te.id = -1;
4112                                 wakeup(&ctlr->te);
4113                         }
4114                         break;
4115                 case 102:       /* calibration result (Type5000 only) */
4116                         if(ctlr->family >= 7000)
4117                                 break;
4118                         if(len < 4)
4119                                 break;
4120                         idx = d[0];
4121                 Calib:
4122                         if(idx < 0 || idx >= nelem(ctlr->calib.cmd))
4123                                 break;
4124                         if(rbplant(ctlr, rx->i) < 0)
4125                                 break;
4126                         if(ctlr->calib.cmd[idx] != nil)
4127                                 freeb(ctlr->calib.cmd[idx]);
4128                         b->rp = d;
4129                         b->wp = d + len;
4130                         ctlr->calib.cmd[idx] = b;
4131                         break;
4132                 case 4:         /* init complete (>= 7000 family) */
4133                         if(ctlr->family < 7000)
4134                                 break;
4135                         /* wet floor */
4136                 case 103:       /* calibration done (Type5000 only) */
4137                         ctlr->calib.done = 1;
4138                         break;
4139                 case 107:       /* calibration result (>= 7000 family) */
4140                         if(ctlr->family < 7000)
4141                                 break;
4142                         len -= 4;
4143                         if(len < 0)
4144                                 break;
4145                         idx = get16(d+2);
4146                         if(idx < len)
4147                                 len = idx;
4148                         idx = -1;
4149                         switch(get16(d)){
4150                         case 1:
4151                                 idx = &ctlr->calib.cfg - &ctlr->calib.cmd[0];
4152                                 break;
4153                         case 2:
4154                                 idx = &ctlr->calib.nch - &ctlr->calib.cmd[0];
4155                                 break;
4156                         case 4:
4157                                 if(len < 2)
4158                                         break;
4159                                 idx = &ctlr->calib.papd[get16(d+4) % nelem(ctlr->calib.papd)] - &ctlr->calib.cmd[0];
4160                                 break;
4161                         case 5:
4162                                 if(len < 2)
4163                                         break;
4164                                 idx = &ctlr->calib.txp[get16(d+4) % nelem(ctlr->calib.txp)] - &ctlr->calib.cmd[0];
4165                                 break;
4166                         }
4167                         len += 4;
4168                         goto Calib;
4169                 case 130:       /* start scan */
4170                 case 132:       /* stop scan */
4171                         break;
4172                 case 136:       /* NVM access (>= 7000 family) */
4173                         if(ctlr->family < 7000)
4174                                 break;
4175                         len -= 8;
4176                         if(len < 0)
4177                                 break;
4178                         if(ctlr->nvm.len < len)
4179                                 len = ctlr->nvm.len;
4180                         ctlr->nvm.off = get16(d + 0);
4181                         ctlr->nvm.ret = get16(d + 2);
4182                         ctlr->nvm.type= get16(d + 4);
4183                         ctlr->nvm.sts = get16(d + 6);
4184                         d += 8;
4185                         if(ctlr->nvm.ret < len)
4186                                 len = ctlr->nvm.ret;
4187                         if(ctlr->nvm.buf != nil && len > 0)
4188                                 memmove(ctlr->nvm.buf, d, len);
4189                         ctlr->nvm.buf = nil;
4190                         ctlr->nvm.len = 0;
4191                         break;
4192                 case 156:       /* rx statistics */
4193                 case 157:       /* beacon statistics */
4194                 case 161:       /* state changed */
4195                 case 162:       /* beacon missed */
4196                 case 177:       /* mduart load notification */
4197                         break;
4198                 case 192:       /* rx phy */
4199                         if(len >= 8)
4200                                 updatesystime(ctlr, get32(d+4));
4201                         break;
4202                 case 195:       /* rx done */
4203                         if(d + 2 > b->lim)
4204                                 break;
4205                         d += d[1];
4206                         d += 56;
4207                         /* wet floor */
4208                 case 193:       /* mpdu rx done */
4209                         if(d + 4 > b->lim)
4210                                 break;
4211                         len = get16(d);
4212                         if(ctlr->mqrx){
4213                                 if(d + 48 + len > b->lim)
4214                                         break;
4215                                 updatesystime(ctlr, get32(d+36));
4216                                 if((d[12] & 3) != 3)
4217                                         break;
4218                                 d += 48;
4219                         } else {
4220                                 d += 4;
4221                                 if(d + len + 4 > b->lim)
4222                                         break;
4223                                 if((d[len] & 3) != 3)
4224                                         break;
4225                         }
4226                         if(ctlr->wifi == nil)
4227                                 break;
4228                         if(rbplant(ctlr, rx->i) < 0)
4229                                 break;
4230                         b->rp = d;
4231                         b->wp = d + len;
4232
4233                         put64(d - 8, ctlr->systime);
4234                         b->flag |= Btimestamp;
4235
4236                         wifiiq(ctlr->wifi, b);
4237                         break;
4238                 case 197:       /* rx compressed ba */
4239                         break;
4240                 }
4241                 freeblist(bb);
4242                 if(tx != nil && tx->n > 0){
4243                         tx->n--;
4244                         wakeup(tx);
4245                 }
4246         }
4247
4248         if(ctlr->mqrx){
4249                 csr32w(ctlr, FhRxQ0Wptr, ((hw+Nrx-1) % Nrx) & ~7);
4250         }else
4251                 csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
4252 }
4253
4254 static void
4255 iwlinterrupt(Ureg*, void *arg)
4256 {
4257         u32int isr, fhisr;
4258         Ether *edev;
4259         Ctlr *ctlr;
4260
4261         edev = arg;
4262         ctlr = edev->ctlr;
4263         ilock(ctlr);
4264         csr32w(ctlr, Imr, 0);
4265         isr = csr32r(ctlr, Isr);
4266         fhisr = csr32r(ctlr, FhIsr);
4267         if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
4268                 iunlock(ctlr);
4269                 return;
4270         }
4271         if(isr == 0 && fhisr == 0)
4272                 goto done;
4273         csr32w(ctlr, Isr, isr);
4274         csr32w(ctlr, FhIsr, fhisr);
4275
4276         if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
4277                 receive(ctlr);
4278         if(isr & Ierr){
4279                 ctlr->broken = 1;
4280                 print("#l%d: fatal firmware error\n", edev->ctlrno);
4281                 dumpctlr(ctlr);
4282         }
4283         ctlr->wait.m |= isr;
4284         if(ctlr->wait.m & ctlr->wait.w)
4285                 wakeup(&ctlr->wait);
4286 done:
4287         csr32w(ctlr, Imr, ctlr->ie);
4288         iunlock(ctlr);
4289 }
4290
4291 static void
4292 iwlshutdown(Ether *edev)
4293 {
4294         Ctlr *ctlr;
4295
4296         ctlr = edev->ctlr;
4297         if(ctlr->power)
4298                 poweroff(ctlr);
4299         ctlr->broken = 0;
4300         pcidisable(ctlr->pdev);
4301 }
4302
4303 static Ctlr *iwlhead, *iwltail;
4304
4305 static void
4306 iwlpci(void)
4307 {
4308         Pcidev *pdev;
4309         char *fwname;
4310         int family;
4311         
4312         pdev = nil;
4313         while(pdev = pcimatch(pdev, 0, 0)) {
4314                 Ctlr *ctlr;
4315                 void *mem;
4316                 
4317                 if(pdev->ccrb != 2 || pdev->ccru != 0x80)
4318                         continue;
4319                 if(pdev->vid != 0x8086)
4320                         continue;
4321                 if(pdev->mem[0].bar & 1)
4322                         continue;
4323
4324                 switch(pdev->did){
4325                 default:
4326                         continue;
4327                 case 0x0084:    /* WiFi Link 1000 */
4328                 case 0x4229:    /* WiFi Link 4965 */
4329                 case 0x4230:    /* WiFi Link 4965 */
4330                 case 0x4232:    /* Wifi Link 5100 */
4331                 case 0x4235:    /* Intel Corporation Ultimate N WiFi Link 5300 */
4332                 case 0x4236:    /* WiFi Link 5300 AGN */
4333                 case 0x4237:    /* Wifi Link 5100 AGN */
4334                 case 0x4239:    /* Centrino Advanced-N 6200 */
4335                 case 0x423d:    /* Wifi Link 5150 */
4336                 case 0x423b:    /* PRO/Wireless 5350 AGN */
4337                 case 0x0082:    /* Centrino Advanced-N 6205 */
4338                 case 0x0085:    /* Centrino Advanced-N 6205 */
4339                 case 0x422b:    /* Centrino Ultimate-N 6300 variant 1 */
4340                 case 0x4238:    /* Centrino Ultimate-N 6300 variant 2 */
4341                 case 0x08ae:    /* Centrino Wireless-N 100 */
4342                 case 0x0083:    /* Centrino Wireless-N 1000 */
4343                 case 0x008a:    /* Centrino Wireless-N 1030 */
4344                 case 0x0891:    /* Centrino Wireless-N 2200 */
4345                 case 0x0887:    /* Centrino Wireless-N 2230 */
4346                 case 0x0888:    /* Centrino Wireless-N 2230 */
4347                 case 0x0090:    /* Centrino Advanced-N 6030 */
4348                 case 0x0091:    /* Centrino Advanced-N 6030 */
4349                 case 0x088e:    /* Centrino Advanced-N 6235 */
4350                 case 0x088f:    /* Centrino Advanced-N 6235 */
4351                         family = 0;
4352                         fwname = nil;
4353                         break;
4354                 case 0x24f3:    /* Wireless AC 8260 */
4355                         family = 8000;
4356                         fwname = "iwm-8000C-34";
4357                         break;
4358                 case 0x24fd:    /* Wireless AC 8265 */
4359                         family = 8000;
4360                         fwname = "iwm-8265-34";
4361                         break;
4362                 case 0x2526:    /* Wireless AC 9260 */
4363                         family = 9000;
4364                         fwname = "iwm-9260-34";
4365                         break;
4366                 }
4367
4368                 ctlr = malloc(sizeof(Ctlr));
4369                 if(ctlr == nil) {
4370                         print("iwl: unable to alloc Ctlr\n");
4371                         continue;
4372                 }
4373                 ctlr->port = pdev->mem[0].bar & ~0xF;
4374                 mem = vmap(ctlr->port, pdev->mem[0].size);
4375                 if(mem == nil) {
4376                         print("iwl: can't map %llux\n", ctlr->port);
4377                         free(ctlr);
4378                         continue;
4379                 }
4380                 ctlr->nic = mem;
4381                 ctlr->pdev = pdev;
4382                 ctlr->fwname = fwname;
4383                 ctlr->family = family;
4384                 ctlr->mqrx = family >= 9000;
4385
4386                 if(iwlhead != nil)
4387                         iwltail->link = ctlr;
4388                 else
4389                         iwlhead = ctlr;
4390                 iwltail = ctlr;
4391         }
4392 }
4393
4394 static int
4395 iwlpnp(Ether* edev)
4396 {
4397         Ctlr *ctlr;
4398         
4399         if(iwlhead == nil)
4400                 iwlpci();
4401 again:
4402         for(ctlr = iwlhead; ctlr != nil; ctlr = ctlr->link){
4403                 if(ctlr->edev != nil)
4404                         continue;
4405                 if(edev->port == 0 || edev->port == ctlr->port){
4406                         ctlr->edev = edev;
4407                         break;
4408                 }
4409         }
4410
4411         if(ctlr == nil)
4412                 return -1;
4413
4414         edev->ctlr = ctlr;
4415         edev->port = ctlr->port;
4416         edev->irq = ctlr->pdev->intl;
4417         edev->tbdf = ctlr->pdev->tbdf;
4418         edev->arg = edev;
4419         edev->attach = iwlattach;
4420         edev->ifstat = iwlifstat;
4421         edev->ctl = iwlctl;
4422         edev->shutdown = iwlshutdown;
4423         edev->promiscuous = iwlpromiscuous;
4424         edev->multicast = iwlmulticast;
4425         edev->mbps = 54;
4426
4427         pcienable(ctlr->pdev);
4428         if(iwlinit(edev) < 0){
4429                 pcidisable(ctlr->pdev);
4430                 ctlr->edev = (void*)-1;
4431                 edev->ctlr = nil;
4432                 goto again;
4433         }
4434
4435         pcisetbme(ctlr->pdev);
4436         intrenable(edev->irq, iwlinterrupt, edev, edev->tbdf, edev->name);
4437         
4438         return 0;
4439 }
4440
4441 void
4442 etheriwllink(void)
4443 {
4444         addethercard("iwl", iwlpnp);
4445 }