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