]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/etherwpi.c
kernel: cleanup makefile for $CONF.$O target
[plan9front.git] / sys / src / 9 / pc / etherwpi.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/netif.h"
9 #include "../port/etherif.h"
10 #include "../port/wifi.h"
11
12 enum {
13         MaxQueue        = 24*1024,      /* total buffer is 2*MaxQueue: 48k at 22Mbit ≅ 20ms */
14
15         Ntxlog          = 8,
16         Ntx             = 1<<Ntxlog,
17         Ntxqmax         = MaxQueue/1500,
18
19         Nrxlog          = 6,
20         Nrx             = 1<<Nrxlog,
21
22         Rbufsize        = 3*1024,
23         Rdscsize        = 8,
24
25         Tdscsize        = 64,
26         Tcmdsize        = 128,
27 };
28
29 /* registers */
30 enum {
31         Cfg             = 0x000,
32                 AlmMb           = 1<<8,
33                 AlmMm           = 1<<9,
34                 SkuMrc          = 1<<10,
35                 RevD            = 1<<11,
36                 TypeB           = 1<<12,
37         Isr             = 0x008,
38         Imr             = 0x00c,
39                 Ialive  = 1<<0,
40                 Iwakeup         = 1<<1,
41                 Iswrx           = 1<<3,
42                 Irftoggled      = 1<<7,
43                 Iswerr          = 1<<25,
44                 Ifhtx           = 1<<27,
45                 Ihwerr          = 1<<29,
46                 Ifhrx           = 1<<31,
47                 Ierr            = Iswerr | Ihwerr,
48                 Idefmask        = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Irftoggled,
49         FhIsr           = 0x010,
50         GpioIn          = 0x018,
51         Reset           = 0x020,
52                 Nevo    = 1<<0,
53                 SW      = 1<<7,
54                 MasterDisabled  = 1<<8,
55                 StopMaster      = 1<<9,
56
57         Gpc             = 0x024,
58                 MacAccessEna    = 1<<0,
59                 MacClockReady   = 1<<0,
60                 InitDone        = 1<<2,
61                 MacAccessReq    = 1<<3,
62                 NicSleep        = 1<<4,
63                 RfKill          = 1<<27,
64         Eeprom          = 0x02c,
65         EepromGp        = 0x030,
66
67         UcodeGp1Clr     = 0x05c,
68                 UcodeGp1RfKill          = 1<<1,
69                 UcodeGp1CmdBlocked      = 1<<2,
70         UcodeGp2        = 0x060,
71
72         GioChicken      = 0x100,
73                 L1AnoL0Srx      = 1<<23,
74         AnaPll          = 0x20c,
75                 Init            = 1<<24,
76
77         PrphWaddr       = 0x444,
78         PrphRaddr       = 0x448,
79         PrphWdata       = 0x44c,
80         PrphRdata       = 0x450,
81         HbusTargWptr    = 0x460,
82 };
83
84 /*
85  * Flow-Handler registers.
86  */
87 enum {
88         FhCbbcCtrl      = 0x940,
89         FhCbbcBase      = 0x944,
90         FhRxConfig      = 0xc00,
91                 FhRxConfigDmaEna        = 1<<31,
92                 FhRxConfigRdrbdEna      = 1<<29,
93                 FhRxConfigWrstatusEna   = 1<<27,
94                 FhRxConfigMaxfrag       = 1<<24,
95                 FhRxConfigIrqDstHost    = 1<<12,
96
97                 FhRxConfigNrdbShift     = 20,
98                 FhRxConfigIrqRbthShift  = 4,
99         FhRxBase        = 0xc04,
100         FhRxWptr        = 0xc20,
101         FhRxRptrAddr    = 0xc24,
102         FhRssrTbl       = 0xcc0,
103         FhRxStatus      = 0xcc4,
104         FhTxConfig      = 0xd00,        // +q*32
105         FhTxBase        = 0xe80,
106         FhMsgConfig     = 0xe88,
107         FhTxStatus      = 0xe90,
108 };
109
110 /*
111  * NIC internal memory offsets.
112  */
113 enum {
114         AlmSchedMode    = 0x2e00,
115         AlmSchedArastat = 0x2e04,
116         AlmSchedTxfact  = 0x2e10,
117         AlmSchedTxf4mf  = 0x2e14,
118         AlmSchedTxf5mf  = 0x2e20,
119         AlmSchedBP1     = 0x2e2c,
120         AlmSchedBP2     = 0x2e30,
121         ApmgClkEna      = 0x3004,
122         ApmgClkDis      = 0x3008,
123                 DmaClkRqt       = 1<<9,
124                 BsmClkRqt       = 1<<11,
125         ApmgPs          = 0x300c,
126                 PwrSrcVMain     = 0<<24,
127                 PwrSrcMask      = 3<<24,
128
129         ApmgPciStt      = 0x3010,
130
131         BsmWrCtrl       = 0x3400,
132         BsmWrMemSrc     = 0x3404,
133         BsmWrMemDst     = 0x3408,
134         BsmWrDwCount    = 0x340c,
135         BsmDramTextAddr = 0x3490,
136         BsmDramTextSize = 0x3494,
137         BsmDramDataAddr = 0x3498,
138         BsmDramDataSize = 0x349c,
139         BsmSramBase     = 0x3800,
140 };
141
142 enum {
143         FilterPromisc           = 1<<0,
144         FilterCtl               = 1<<1,
145         FilterMulticast         = 1<<2,
146         FilterNoDecrypt         = 1<<3,
147         FilterBSS               = 1<<5,
148 };
149
150 enum {
151         RFlag24Ghz              = 1<<0,
152         RFlagCCK                = 1<<1,
153         RFlagAuto               = 1<<2,
154         RFlagShSlot             = 1<<4,
155         RFlagShPreamble         = 1<<5,
156         RFlagNoDiversity        = 1<<7,
157         RFlagAntennaA           = 1<<8,
158         RFlagAntennaB           = 1<<9,
159         RFlagTSF                = 1<<15,
160 };
161
162 typedef struct FWSect FWSect;
163 typedef struct FWImage FWImage;
164
165 typedef struct TXQ TXQ;
166 typedef struct RXQ RXQ;
167
168 typedef struct Shared Shared;
169 typedef struct Sample Sample;
170 typedef struct Powergrp Powergrp;
171
172 typedef struct Ctlr Ctlr;
173
174 struct FWSect
175 {
176         uchar *data;
177         uint  size;
178 };
179
180 struct FWImage
181 {
182         struct {
183                 FWSect text;
184                 FWSect data;
185         } init, main, boot;
186
187         uint  version;
188         uchar data[];
189 };
190
191 struct TXQ
192 {
193         uint n;
194         uint i;
195         Block **b;
196         uchar *d;
197         uchar *c;
198
199         uint lastcmd;
200
201         Rendez;
202         QLock;
203 };
204
205 struct RXQ
206 {
207         uint   i;
208         Block  **b;
209         u32int *p;
210 };
211
212 struct Shared
213 {
214         u32int txbase[8];
215         u32int next;
216         u32int reserved[2];
217 };
218
219 struct Sample
220 {
221         uchar index;
222         char power;
223 };
224
225 struct Powergrp
226 {
227         uchar chan;
228         char maxpwr;
229         short temp;
230         Sample samples[5];
231 };
232
233 struct Ctlr {
234         Lock;
235         QLock;
236
237         Ctlr *link;
238         Pcidev *pdev;
239         Wifi *wifi;
240
241         int port;
242         int power;
243         int active;
244         int broken;
245         int attached;
246
247         int temp;
248         u32int ie;
249         u32int *nic;
250
251         /* assigned node ids in hardware node table or -1 if unassigned */
252         int bcastnodeid;
253         int bssnodeid;
254
255         /* current receiver settings */
256         uchar bssid[Eaddrlen];
257         int channel;
258         int prom;
259         int aid;
260
261         RXQ rx;
262         TXQ tx[8];
263
264         struct {
265                 Rendez;
266                 u32int  m;
267                 u32int  w;
268         } wait;
269
270         struct {
271                 uchar cap;
272                 u16int rev;
273                 uchar type;
274
275                 char regdom[4+1];
276
277                 Powergrp pwrgrps[5];
278         } eeprom;
279
280         char maxpwr[256];
281
282         Shared *shared;
283
284         FWImage *fw;
285 };
286
287 static void setled(Ctlr *ctlr, int which, int on, int off);
288
289 #define csr32r(c, r)    (*((c)->nic+((r)/4)))
290 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
291
292 static uint
293 get32(uchar *p){
294         return *((u32int*)p);
295 }
296 static uint
297 get16(uchar *p)
298 {
299         return *((u16int*)p);
300 }
301 static void
302 put32(uchar *p, uint v){
303         *((u32int*)p) = v;
304 }
305 static void
306 put16(uchar *p, uint v){
307         *((u16int*)p) = v;
308 };
309
310 static char*
311 niclock(Ctlr *ctlr)
312 {
313         int i;
314
315         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
316         for(i=0; i<1000; i++){
317                 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
318                         return 0;
319                 delay(10);
320         }
321         return "niclock: timeout";
322 }
323
324 static void
325 nicunlock(Ctlr *ctlr)
326 {
327         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
328 }
329
330 static u32int
331 prphread(Ctlr *ctlr, uint off)
332 {
333         csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
334         coherence();
335         return csr32r(ctlr, PrphRdata);
336 }
337 static void
338 prphwrite(Ctlr *ctlr, uint off, u32int data)
339 {
340         csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
341         coherence();
342         csr32w(ctlr, PrphWdata, data);
343 }
344
345 static char*
346 eepromread(Ctlr *ctlr, void *data, int count, uint off)
347 {
348         uchar *out = data;
349         char *err;
350         u32int w = 0;
351         int i;
352
353         if((err = niclock(ctlr)) != nil)
354                 return err;
355
356         for(; count > 0; count -= 2, off++){
357                 csr32w(ctlr, Eeprom, off << 2);
358                 csr32w(ctlr, Eeprom, csr32r(ctlr, Eeprom) & ~(1<<1));
359
360                 for(i = 0; i < 10; i++){
361                         w = csr32r(ctlr, Eeprom);
362                         if(w & 1)
363                                 break;
364                         delay(5);
365                 }
366                 if(i == 10)
367                         break;
368                 *out++ = w >> 16;
369                 if(count > 1)
370                         *out++ = w >> 24;
371         }
372         nicunlock(ctlr);
373
374         if(count > 0)
375                 return "eeprompread: timeout";
376         return nil;
377 }
378
379 static char*
380 clockwait(Ctlr *ctlr)
381 {
382         int i;
383
384         /* Set "initialization complete" bit. */
385         csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
386         for(i=0; i<2500; i++){
387                 if(csr32r(ctlr, Gpc) & MacClockReady)
388                         return nil;
389                 delay(10);
390         }
391         return "clockwait: timeout";
392 }
393
394 static char*
395 poweron(Ctlr *ctlr)
396 {
397         char *err;
398
399         if(ctlr->power)
400                 return nil;
401
402         csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | Init);
403         /* Disable L0s. */
404         csr32w(ctlr, GioChicken, csr32r(ctlr, GioChicken) | L1AnoL0Srx);
405
406         if((err = clockwait(ctlr)) != nil)
407                 return err;
408
409         if((err = niclock(ctlr)) != nil)
410                 return err;
411
412         prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
413         delay(20);
414
415         /* Disable L1. */
416         prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
417
418         nicunlock(ctlr);
419
420         ctlr->power = 1;
421
422         return nil;
423 }
424
425 static void
426 poweroff(Ctlr *ctlr)
427 {
428         int i, j;
429
430         csr32w(ctlr, Reset, Nevo);
431
432         /* Disable interrupts. */
433         csr32w(ctlr, Imr, 0);
434         csr32w(ctlr, Isr, ~0);
435         csr32w(ctlr, FhIsr, ~0);
436
437         if(niclock(ctlr) == nil){
438                 /* Stop TX scheduler. */
439                 prphwrite(ctlr, AlmSchedMode, 0);
440                 prphwrite(ctlr, AlmSchedTxfact, 0);
441
442                 /* Stop all DMA channels */
443                 for(i = 0; i < 6; i++){
444                         csr32w(ctlr, FhTxConfig + i*32, 0);
445                         for(j = 0; j < 100; j++){
446                                 if((csr32r(ctlr, FhTxStatus) & (0x1010000<<i)) == (0x1010000<<i))
447                                         break;
448                                 delay(10);
449                         }
450                 }
451                 nicunlock(ctlr);
452         }
453
454         /* Stop RX ring. */
455         if(niclock(ctlr) == nil){
456                 csr32w(ctlr, FhRxConfig, 0);
457                 for(j = 0; j < 100; j++){
458                         if(csr32r(ctlr, FhRxStatus) & (1<<24))
459                                 break;
460                         delay(10);
461                 }
462                 nicunlock(ctlr);
463         }
464
465         if(niclock(ctlr) == nil){
466                 prphwrite(ctlr, ApmgClkDis, DmaClkRqt);
467                 nicunlock(ctlr);
468         }
469         delay(5);
470
471         csr32w(ctlr, Reset, csr32r(ctlr, Reset) | StopMaster);
472
473         if((csr32r(ctlr, Gpc) & (7<<24)) != (4<<24)){
474                 for(j = 0; j < 100; j++){
475                         if(csr32r(ctlr, Reset) & MasterDisabled)
476                                 break;
477                         delay(10);
478                 }
479         }
480
481         csr32w(ctlr, Reset, csr32r(ctlr, Reset) | SW);
482
483         ctlr->power = 0;
484 }
485
486 static struct {
487         u32int  addr;   /* offset in EEPROM */
488         u8int   nchan;
489         u8int   chan[14];
490 } bands[5] = {
491         { 0x63, 14,
492             { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } },
493         { 0x72, 13,
494             { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } },
495         { 0x80, 12,
496             { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } },
497         { 0x8d, 11,
498             { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } },
499         { 0x99, 6,
500             { 145, 149, 153, 157, 161, 165 } }
501 };
502
503 static int
504 wpiinit(Ether *edev)
505 {
506         Ctlr *ctlr;
507         char *err;
508         uchar b[64];
509         int i, j;
510         Powergrp *g;
511
512         ctlr = edev->ctlr;
513         if((err = poweron(ctlr)) != nil)
514                 goto Err;
515         if((csr32r(ctlr, EepromGp) & 0x6) == 0){
516                 err = "bad rom signature";
517                 goto Err;
518         }
519         /* Clear HW ownership of EEPROM. */
520         csr32w(ctlr, EepromGp, csr32r(ctlr, EepromGp) & ~0x180);
521
522         if((err = eepromread(ctlr, b, 1, 0x45)) != nil)
523                 goto Err;
524         ctlr->eeprom.cap = b[0];
525         if((err = eepromread(ctlr, b, 2, 0x35)) != nil)
526                 goto Err;
527         ctlr->eeprom.rev = get16(b);
528         if((err = eepromread(ctlr, b, 1, 0x4a)) != nil)
529                 goto Err;
530         ctlr->eeprom.type = b[0];
531         if((err = eepromread(ctlr, b, 4, 0x60)) != nil)
532                 goto Err;
533         strncpy(ctlr->eeprom.regdom, (char*)b, 4);
534         ctlr->eeprom.regdom[4] = '\0';
535
536         print("wpi: %X %X %X %s\n", ctlr->eeprom.cap, ctlr->eeprom.rev, ctlr->eeprom.type, ctlr->eeprom.regdom);
537
538         if((err = eepromread(ctlr, b, 6, 0x15)) != nil)
539                 goto Err;
540         memmove(edev->ea, b, Eaddrlen);
541
542         memset(ctlr->maxpwr, 0, sizeof(ctlr->maxpwr));
543         for(i = 0; i < nelem(bands); i++){
544                 if((err = eepromread(ctlr, b, 2*bands[i].nchan, bands[i].addr)) != nil)
545                         goto Err;
546                 for(j = 0; j < bands[i].nchan; j++){
547                         if(!(b[j*2] & 1))
548                                 continue;
549                         ctlr->maxpwr[bands[i].chan[j]] = b[j*2+1];
550                 }
551         }
552
553         for(i = 0; i < nelem(ctlr->eeprom.pwrgrps); i++){
554                 if((err = eepromread(ctlr, b, 64, 0x100 + i*32)) != nil)
555                         goto Err;
556                 g = &ctlr->eeprom.pwrgrps[i];
557                 g->maxpwr = b[60];
558                 g->chan = b[61];
559                 g->temp = get16(b+62);
560                 for(j = 0; j < 5; j++){
561                         g->samples[j].index = b[j*4];
562                         g->samples[j].power = b[j*4+1];
563                 }
564         }
565
566         poweroff(ctlr);
567         return 0;
568 Err:
569         print("wpiinit: %s\n", err);
570         poweroff(ctlr);
571         return -1;
572 }
573
574 static char*
575 crackfw(FWImage *i, uchar *data, uint size)
576 {
577         uchar *p, *e;
578
579         memset(i, 0, sizeof(*i));
580         if(size < 4*6){
581 Tooshort:
582                 return "firmware image too short";
583         }
584         p = data;
585         e = p + size;
586         i->version = get32(p); p += 4;
587         i->main.text.size = get32(p); p += 4;
588         i->main.data.size = get32(p); p += 4;
589         i->init.text.size = get32(p); p += 4;
590         i->init.data.size = get32(p); p += 4;
591         i->boot.text.size = get32(p); p += 4;
592         i->main.text.data = p; p += i->main.text.size;
593         i->main.data.data = p; p += i->main.data.size;
594         i->init.text.data = p; p += i->init.text.size;
595         i->init.data.data = p; p += i->init.data.size;
596         i->boot.text.data = p; p += i->boot.text.size;
597         if(p > e)
598                 goto Tooshort;
599         return nil;
600 }
601
602 static FWImage*
603 readfirmware(void)
604 {
605         uchar dirbuf[sizeof(Dir)+100], *data;
606         char *err;
607         FWImage *fw;
608         int n, r;
609         Chan *c;
610         Dir d;
611
612         if(!iseve())
613                 error(Eperm);
614         if(!waserror()){
615                 c = namec("/boot/wpi-3945abg", Aopen, OREAD, 0);
616                 poperror();
617         }else
618                 c = namec("/lib/firmware/wpi-3945abg", Aopen, OREAD, 0);
619         if(waserror()){
620                 cclose(c);
621                 nexterror();
622         }
623         n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
624         if(n <= 0)
625                 error("can't stat firmware");
626         convM2D(dirbuf, n, &d, nil);
627         fw = smalloc(sizeof(*fw) + 16 + d.length);
628         data = (uchar*)(fw+1);
629         if(waserror()){
630                 free(fw);
631                 nexterror();
632         }
633         r = 0;
634         while(r < d.length){
635                 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
636                 if(n <= 0)
637                         break;
638                 r += n;
639         }
640         if((err = crackfw(fw, data, r)) != nil)
641                 error(err);
642         poperror();
643         poperror();
644         cclose(c);
645         return fw;
646 }
647
648 static int
649 gotirq(void *arg)
650 {
651         Ctlr *ctlr = arg;
652         return (ctlr->wait.m & ctlr->wait.w) != 0;
653 }
654
655 static u32int
656 irqwait(Ctlr *ctlr, u32int mask, int timeout)
657 {
658         u32int r;
659
660         ilock(ctlr);
661         r = ctlr->wait.m & mask;
662         if(r == 0){
663                 ctlr->wait.w = mask;
664                 iunlock(ctlr);
665                 if(!waserror()){
666                         tsleep(&ctlr->wait, gotirq, ctlr, timeout);
667                         poperror();
668                 }
669                 ilock(ctlr);
670                 ctlr->wait.w = 0;
671                 r = ctlr->wait.m & mask;
672         }
673         ctlr->wait.m &= ~r;
674         iunlock(ctlr);
675         return r;
676 }
677
678 static int
679 rbplant(Ctlr *ctlr, int i)
680 {
681         Block *b;
682
683         b = iallocb(Rbufsize+127);
684         if(b == nil)
685                 return -1;
686         b->rp = b->wp = (uchar*)((((uintptr)b->base+127)&~127));
687         memset(b->rp, 0, Rdscsize);
688         coherence();
689         ctlr->rx.b[i] = b;
690         ctlr->rx.p[i] = PCIWADDR(b->rp);
691         return 0;
692 }
693
694 static char*
695 initring(Ctlr *ctlr)
696 {
697         RXQ *rx;
698         TXQ *tx;
699         int i, q;
700
701         rx = &ctlr->rx;
702         if(rx->b == nil)
703                 rx->b = malloc(sizeof(Block*) * Nrx);
704         if(rx->p == nil)
705                 rx->p = mallocalign(sizeof(u32int) * Nrx, 16 * 1024, 0, 0);
706         if(rx->b == nil || rx->p == nil)
707                 return "no memory for rx ring";
708         for(i = 0; i<Nrx; i++){
709                 rx->p[i] = 0;
710                 if(rx->b[i] != nil){
711                         freeb(rx->b[i]);
712                         rx->b[i] = nil;
713                 }
714                 if(rbplant(ctlr, i) < 0)
715                         return "no memory for rx descriptors";
716         }
717         rx->i = 0;
718
719         if(ctlr->shared == nil)
720                 ctlr->shared = mallocalign(4096, 4096, 0, 0);
721         if(ctlr->shared == nil)
722                 return "no memory for shared buffer";
723         memset(ctlr->shared, 0, 4096);
724
725         for(q=0; q<nelem(ctlr->tx); q++){
726                 tx = &ctlr->tx[q];
727                 if(tx->b == nil)
728                         tx->b = malloc(sizeof(Block*) * Ntx);
729                 if(tx->d == nil)
730                         tx->d = mallocalign(Tdscsize * Ntx, 16 * 1024, 0, 0);
731                 if(tx->c == nil)
732                         tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
733                 if(tx->b == nil || tx->d == nil || tx->c == nil)
734                         return "no memory for tx ring";
735                 memset(tx->d, 0, Tdscsize * Ntx);
736                 memset(tx->c, 0, Tcmdsize * Ntx);
737                 for(i=0; i<Ntx; i++){
738                         if(tx->b[i] != nil){
739                                 freeb(tx->b[i]);
740                                 tx->b[i] = nil;
741                         }
742                 }
743                 ctlr->shared->txbase[q] = PCIWADDR(tx->d);
744                 tx->i = 0;
745                 tx->n = 0;
746                 tx->lastcmd = 0;
747         }
748         return nil;
749 }
750
751 static char*
752 reset(Ctlr *ctlr)
753 {
754         uchar rev;
755         char *err;
756         int i;
757
758         if(ctlr->power)
759                 poweroff(ctlr);
760         if((err = initring(ctlr)) != nil)
761                 return err;
762         if((err = poweron(ctlr)) != nil)
763                 return err;
764
765         /* Select VMAIN power source. */
766         if((err = niclock(ctlr)) != nil)
767                 return err;
768         prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
769         nicunlock(ctlr);
770         /* Spin until VMAIN gets selected. */
771         for(i = 0; i < 5000; i++){
772                 if(csr32r(ctlr, GpioIn) & (1 << 9))
773                         break;
774                 delay(10);
775         }
776
777         /* Perform adapter initialization. */
778         rev = ctlr->pdev->rid;
779         if((rev & 0xc0) == 0x40)
780                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | AlmMb);
781         else if(!(rev & 0x80))
782                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | AlmMm);
783
784         if(ctlr->eeprom.cap == 0x80)
785                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | SkuMrc);
786
787         if((ctlr->eeprom.rev & 0xf0) == 0xd0)
788                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RevD);
789         else
790                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~RevD);
791
792         if(ctlr->eeprom.type > 1)
793                 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | TypeB);
794
795         /* Initialize RX ring. */
796         if((err = niclock(ctlr)) != nil)
797                 return err;
798
799         coherence();
800         csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p));
801         csr32w(ctlr, FhRxRptrAddr, PCIWADDR(&ctlr->shared->next));
802         csr32w(ctlr, FhRxWptr, 0);
803         csr32w(ctlr, FhRxConfig,
804                 FhRxConfigDmaEna |
805                 FhRxConfigRdrbdEna |
806                 FhRxConfigWrstatusEna |
807                 FhRxConfigMaxfrag |
808                 (Nrxlog << FhRxConfigNrdbShift) |
809                 FhRxConfigIrqDstHost |
810                 (1 << FhRxConfigIrqRbthShift));
811         USED(csr32r(ctlr, FhRssrTbl));
812         csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
813         nicunlock(ctlr);
814
815         /* Initialize TX rings. */
816         if((err = niclock(ctlr)) != nil)
817                 return err;
818         prphwrite(ctlr, AlmSchedMode, 2);
819         prphwrite(ctlr, AlmSchedArastat, 1);
820         prphwrite(ctlr, AlmSchedTxfact, 0x3f);
821         prphwrite(ctlr, AlmSchedBP1, 0x10000);
822         prphwrite(ctlr, AlmSchedBP2, 0x30002);
823         prphwrite(ctlr, AlmSchedTxf4mf, 4);
824         prphwrite(ctlr, AlmSchedTxf5mf, 5);
825         csr32w(ctlr, FhTxBase, PCIWADDR(ctlr->shared));
826         csr32w(ctlr, FhMsgConfig, 0xffff05a5);
827         for(i = 0; i < 6; i++){
828                 csr32w(ctlr, FhCbbcCtrl+i*8, 0);
829                 csr32w(ctlr, FhCbbcBase+i*8, 0);
830                 csr32w(ctlr, FhTxConfig+i*32, 0x80200008);
831         }
832         nicunlock(ctlr);
833         USED(csr32r(ctlr, FhTxBase));
834
835         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
836         csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
837
838         ctlr->broken = 0;
839         ctlr->wait.m = 0;
840         ctlr->wait.w = 0;
841
842         ctlr->ie = Idefmask;
843         csr32w(ctlr, Imr, ctlr->ie);
844         csr32w(ctlr, Isr, ~0);
845
846         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
847         csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
848
849         return nil;
850 }
851
852 static char*
853 postboot(Ctlr *);
854
855 static char*
856 boot(Ctlr *ctlr)
857 {
858         int i, n, size;
859         uchar *dma, *p;
860         FWImage *fw;
861         char *err;
862
863         fw = ctlr->fw;
864         /* 16 byte padding may not be necessary. */
865         size = ROUND(fw->init.data.size, 16) + ROUND(fw->init.text.size, 16);
866         dma = mallocalign(size, 16, 0, 0);
867         if(dma == nil)
868                 return "no memory for dma";
869
870         if((err = niclock(ctlr)) != nil){
871                 free(dma);
872                 return err;
873         }
874
875         p = dma;
876         memmove(p, fw->init.data.data, fw->init.data.size);
877         coherence();
878         prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p));
879         prphwrite(ctlr, BsmDramDataSize, fw->init.data.size);
880         p += ROUND(fw->init.data.size, 16);
881         memmove(p, fw->init.text.data, fw->init.text.size);
882         coherence();
883         prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p));
884         prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
885
886         nicunlock(ctlr);
887         if((err = niclock(ctlr)) != nil){
888                 free(dma);
889                 return err;
890         }
891
892         /* Copy microcode image into NIC memory. */
893         p = fw->boot.text.data;
894         n = fw->boot.text.size/4;
895         for(i=0; i<n; i++, p += 4)
896                 prphwrite(ctlr, BsmSramBase+i*4, get32(p));
897
898         prphwrite(ctlr, BsmWrMemSrc, 0);
899         prphwrite(ctlr, BsmWrMemDst, 0);
900         prphwrite(ctlr, BsmWrDwCount, n);
901
902         /* Start boot load now. */
903         prphwrite(ctlr, BsmWrCtrl, 1<<31);
904
905         /* Wait for transfer to complete. */
906         for(i=0; i<1000; i++){
907                 if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
908                         break;
909                 delay(10);
910         }
911         if(i == 1000){
912                 nicunlock(ctlr);
913                 free(dma);
914                 return "bootcode timeout";
915         }
916
917         /* Enable boot after power up. */
918         prphwrite(ctlr, BsmWrCtrl, 1<<30);
919         nicunlock(ctlr);
920
921         /* Now press "execute". */
922         csr32w(ctlr, Reset, 0);
923
924         /* Wait at most one second for first alive notification. */
925         if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
926                 free(dma);
927                 return "init firmware boot failed";
928         }
929         free(dma);
930
931         size = ROUND(fw->main.data.size, 16) + ROUND(fw->main.text.size, 16);
932         dma = mallocalign(size, 16, 0, 0);
933         if(dma == nil)
934                 return "no memory for dma";
935         if((err = niclock(ctlr)) != nil){
936                 free(dma);
937                 return err;
938         }
939         p = dma;
940         memmove(p, fw->main.data.data, fw->main.data.size);
941         coherence();
942         prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p));
943         prphwrite(ctlr, BsmDramDataSize, fw->main.data.size);
944         p += ROUND(fw->main.data.size, 16);
945         memmove(p, fw->main.text.data, fw->main.text.size);
946         coherence();
947         prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p));
948         prphwrite(ctlr, BsmDramTextSize, fw->main.text.size | (1<<31));
949         nicunlock(ctlr);
950
951         if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
952                 free(dma);
953                 return "main firmware boot failed";
954         }
955         free(dma);
956         return postboot(ctlr);
957 }
958
959 static int
960 txqready(void *arg)
961 {
962         TXQ *q = arg;
963         return q->n < Ntxqmax;
964 }
965
966 static char*
967 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
968 {
969         uchar *d, *c;
970         int pad;
971         TXQ *q;
972
973         assert(qid < nelem(ctlr->tx));
974         assert(size <= Tcmdsize-4);
975
976         ilock(ctlr);
977         q = &ctlr->tx[qid];
978         while(q->n >= Ntxqmax && !ctlr->broken){
979                 iunlock(ctlr);
980                 qlock(q);
981                 if(!waserror()){
982                         tsleep(q, txqready, q, 5);
983                         poperror();
984                 }
985                 qunlock(q);
986                 ilock(ctlr);
987         }
988         if(ctlr->broken){
989                 iunlock(ctlr);
990                 return "qcmd: broken";
991         }
992         q->n++;
993
994         q->lastcmd = code;
995         q->b[q->i] = block;
996         c = q->c + q->i * Tcmdsize;
997         d = q->d + q->i * Tdscsize;
998
999         /* build command */
1000         c[0] = code;
1001         c[1] = 0;       /* flags */
1002         c[2] = q->i;
1003         c[3] = qid;
1004
1005         if(size > 0)
1006                 memmove(c+4, data, size);
1007         size += 4;
1008
1009         memset(d, 0, Tdscsize);
1010
1011         pad = size - 4;
1012         if(block != nil)
1013                 pad += BLEN(block);
1014         pad = ((pad + 3) & ~3) - pad;
1015
1016         put32(d, (pad << 28) | ((1 + (block != nil)) << 24)), d += 4;
1017         put32(d, PCIWADDR(c)), d += 4;
1018         put32(d, size), d += 4;
1019
1020         if(block != nil){
1021                 size = BLEN(block);
1022                 put32(d, PCIWADDR(block->rp)), d += 4;
1023                 put32(d, size), d += 4;
1024         }
1025
1026         USED(d);
1027
1028         coherence();
1029
1030         q->i = (q->i+1) % Ntx;
1031         csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
1032
1033         iunlock(ctlr);
1034
1035         return nil;
1036 }
1037
1038 static int
1039 txqempty(void *arg)
1040 {
1041         TXQ *q = arg;
1042         return q->n == 0;
1043 }
1044
1045 static char*
1046 flushq(Ctlr *ctlr, uint qid)
1047 {
1048         TXQ *q;
1049         int i;
1050
1051         q = &ctlr->tx[qid];
1052         qlock(q);
1053         for(i = 0; i < 200 && !ctlr->broken; i++){
1054                 if(txqempty(q)){
1055                         qunlock(q);
1056                         return nil;
1057                 }
1058                 if(islo() && !waserror()){
1059                         tsleep(q, txqempty, q, 10);
1060                         poperror();
1061                 }
1062         }
1063         qunlock(q);
1064         if(ctlr->broken)
1065                 return "flushq: broken";
1066         return "flushq: timeout";
1067 }
1068
1069 static char*
1070 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
1071 {
1072         char *err;
1073
1074         if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil)
1075                 return err;
1076         return flushq(ctlr, 4);
1077 }
1078
1079 static void
1080 setled(Ctlr *ctlr, int which, int on, int off)
1081 {
1082         uchar c[8];
1083
1084         memset(c, 0, sizeof(c));
1085         put32(c, 10000);
1086         c[4] = which;
1087         c[5] = on;
1088         c[6] = off;
1089         cmd(ctlr, 72, c, sizeof(c));
1090 }
1091
1092 static char*
1093 btcoex(Ctlr *ctlr)
1094 {
1095         uchar c[Tcmdsize], *p;
1096
1097         /* configure bluetooth coexistance. */
1098         p = c;
1099         *p++ = 3;               /* flags WPI_BT_COEX_MODE_4WIRE */
1100         *p++ = 30;              /* lead time */
1101         *p++ = 5;               /* max kill */
1102         *p++ = 0;               /* reserved */
1103         put32(p, 0), p += 4;    /* kill_ack */
1104         put32(p, 0), p += 4;    /* kill_cts */
1105         return cmd(ctlr, 155, c, p-c);
1106 }
1107
1108 static char*
1109 powermode(Ctlr *ctlr)
1110 {
1111         uchar c[Tcmdsize];
1112         int capoff, reg;
1113
1114         memset(c, 0, sizeof(c));
1115         capoff = pcicap(ctlr->pdev, PciCapPCIe);
1116         if(capoff >= 0){
1117                 reg = pcicfgr8(ctlr->pdev, capoff+1);
1118                 if((reg & 1) == 0)      /* PCI_PCIE_LCR_ASPM_L0S */
1119                         c[0] |= 1<<3;   /* WPI_PS_PCI_PMGT */
1120         }
1121         return cmd(ctlr, 119, c, 4*(3+5));
1122 }
1123
1124 static char*
1125 postboot(Ctlr *ctlr)
1126 {
1127         while((ctlr->temp = (int)csr32r(ctlr, UcodeGp2)) == 0)
1128                 delay(10);
1129
1130 if(0){
1131         char *err;
1132
1133         if((err = btcoex(ctlr)) != nil)
1134                 print("btcoex: %s\n", err);
1135         if((err = powermode(ctlr)) != nil)
1136                 print("powermode: %s\n", err);
1137 }
1138
1139         return nil;
1140 }
1141
1142 static uchar wpirates[] = {
1143         0x80 | 12,
1144         0x80 | 18,
1145         0x80 | 24,
1146         0x80 | 36,
1147         0x80 | 48,
1148         0x80 | 72,
1149         0x80 | 96,
1150         0x80 | 108,
1151
1152         0x80 | 2,
1153         0x80 | 4,
1154         0x80 | 11,
1155         0x80 | 22,
1156
1157         0
1158 };
1159
1160 static struct {
1161         uchar   rate;
1162         uchar   plcp;
1163 } ratetab[] = {
1164         {  12, 0xd },
1165         {  18, 0xf },
1166         {  24, 0x5 },
1167         {  36, 0x7 },
1168         {  48, 0x9 },
1169         {  72, 0xb },
1170         {  96, 0x1 },
1171         { 108, 0x3 },
1172
1173         {   2,  10 },
1174         {   4,  20 },
1175         {  11,  55 },
1176         {  22, 110 },
1177 };
1178
1179 static u8int rfgain_2ghz[] = {
1180         0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xbb, 0xbb,
1181         0xbb, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xd3, 0xd3, 0xb3, 0xb3, 0xb3,
1182         0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x73, 0xeb, 0xeb, 0xeb,
1183         0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xab, 0xab, 0xab, 0x8b,
1184         0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xa3,
1185         0xa3, 0xa3, 0xa3, 0x83, 0x83, 0x83, 0x83, 0x63, 0x63, 0x63, 0x63,
1186         0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, 0x03, 0x03, 0x03,
1187         0x03
1188 };
1189
1190 static  u8int dspgain_2ghz[] = {
1191         0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x6e, 0x69, 0x62, 0x7d, 0x73, 0x6c,
1192         0x63, 0x77, 0x6f, 0x69, 0x61, 0x5c, 0x6a, 0x64, 0x78, 0x71, 0x6b,
1193         0x7d, 0x77, 0x70, 0x6a, 0x65, 0x61, 0x5b, 0x6b, 0x79, 0x73, 0x6d,
1194         0x7f, 0x79, 0x73, 0x6c, 0x66, 0x60, 0x5c, 0x6e, 0x68, 0x62, 0x74,
1195         0x7d, 0x77, 0x71, 0x6b, 0x65, 0x60, 0x71, 0x6a, 0x66, 0x5f, 0x71,
1196         0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f,
1197         0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66,
1198         0x5f
1199 };
1200
1201 static int
1202 pwridx(Ctlr *ctlr, Powergrp *pwgr, int chan, int rate)
1203 {
1204 /* Fixed-point arithmetic division using a n-bit fractional part. */
1205 #define fdivround(a, b, n)      \
1206         ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n))
1207
1208 /* Linear interpolation. */
1209 #define interpolate(x, x1, y1, x2, y2, n)       \
1210         ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n))
1211
1212         int pwr;
1213         Sample *sample;
1214         int idx;
1215
1216         /* Default TX power is group maximum TX power minus 3dB. */
1217         pwr = pwgr->maxpwr / 2;
1218
1219         /* Decrease TX power for highest OFDM rates to reduce distortion. */
1220         switch(rate){
1221         case 5: /* WPI_RIDX_OFDM36 */
1222                 pwr -= 0;
1223                 break;
1224         case 6: /* WPI_RIDX_OFDM48 */
1225                 pwr -=7;
1226                 break;
1227         case 7: /* WPI_RIDX_OFDM54 */
1228                 pwr -= 9;
1229                 break;
1230         }
1231
1232         /* Never exceed the channel maximum allowed TX power. */
1233         pwr = MIN(pwr, ctlr->maxpwr[chan]);
1234
1235         /* Retrieve TX power index into gain tables from samples. */
1236         for(sample = pwgr->samples; sample < &pwgr->samples[3]; sample++)
1237                 if(pwr > sample[1].power)
1238                         break;
1239         /* Fixed-point linear interpolation using a 19-bit fractional part. */
1240         idx = interpolate(pwr, sample[0].power, sample[0].index,
1241             sample[1].power, sample[1].index, 19);
1242
1243         /*-
1244          * Adjust power index based on current temperature:
1245          * - if cooler than factory-calibrated: decrease output power
1246          * - if warmer than factory-calibrated: increase output power
1247          */
1248         idx -= (ctlr->temp - pwgr->temp) * 11 / 100;
1249
1250         /* Decrease TX power for CCK rates (-5dB). */
1251         if (rate >= 8)
1252                 idx += 10;
1253
1254         /* Make sure idx stays in a valid range. */
1255         if (idx < 0)
1256                 idx = 0;
1257         else if (idx >= nelem(rfgain_2ghz))
1258                 idx = nelem(rfgain_2ghz)-1;
1259         return idx;
1260 #undef fdivround
1261 #undef interpolate
1262 }
1263
1264 static void
1265 addnode(Ctlr *ctlr, uchar id, uchar *addr, int plcp, int antenna)
1266 {
1267         uchar c[Tcmdsize], *p;
1268
1269         memset(p = c, 0, sizeof(c));
1270         *p++ = 0;       /* control (1 = update) */
1271         p += 3;         /* reserved */
1272         memmove(p, addr, 6);
1273         p += 6;
1274         p += 2;         /* reserved */
1275         *p++ = id;      /* node id */
1276         p++;            /* flags */
1277         p += 2;         /* reserved */
1278         p += 2;         /* kflags */
1279         p++;            /* tcs2 */
1280         p++;            /* reserved */
1281         p += 5*2;       /* ttak */
1282         p += 2;         /* reserved */
1283         p += 16;        /* key */
1284         put32(p, 4);    /* action (4 = set_rate) */
1285         p += 4;         
1286         p += 4;         /* mask */
1287         p += 2;         /* tid */
1288         *p++ = plcp;    /* plcp */
1289         *p++ = antenna; /* antenna */
1290         p++;            /* add_imm */
1291         p++;            /* del_imm */
1292         p++;            /* add_imm_start */
1293         cmd(ctlr, 24, c, p - c);
1294 }
1295
1296 static void
1297 rxon(Ether *edev, Wnode *bss)
1298 {
1299         uchar c[Tcmdsize], *p;
1300         int filter, flags, rate;
1301         Ctlr *ctlr;
1302         char *err;
1303         int idx;
1304
1305         ctlr = edev->ctlr;
1306         filter = FilterNoDecrypt | FilterMulticast;
1307         if(ctlr->prom){
1308                 filter |= FilterPromisc;
1309                 if(bss != nil)
1310                         ctlr->channel = bss->channel;
1311                 bss = nil;
1312         }
1313         flags = RFlagTSF | RFlag24Ghz | RFlagAuto;
1314         if(bss != nil){
1315                 if(bss->cap & (1<<5))
1316                         flags |= RFlagShPreamble;
1317                 if(bss->cap & (1<<10))
1318                         flags |= RFlagShSlot;
1319                 ctlr->channel = bss->channel;
1320                 memmove(ctlr->bssid, bss->bssid, Eaddrlen);
1321                 ctlr->aid = bss->aid;
1322                 if(ctlr->aid != 0){
1323                         filter |= FilterBSS;
1324                         ctlr->bssnodeid = -1;
1325                 }else
1326                         ctlr->bcastnodeid = -1;
1327         }else{
1328                 memmove(ctlr->bssid, edev->bcast, Eaddrlen);
1329                 ctlr->aid = 0;
1330                 ctlr->bcastnodeid = -1;
1331                 ctlr->bssnodeid = -1;
1332         }
1333
1334         if(ctlr->aid != 0)
1335                 setled(ctlr, 2, 0, 1);          /* on when associated */
1336         else if(memcmp(ctlr->bssid, edev->bcast, Eaddrlen) != 0)
1337                 setled(ctlr, 2, 10, 10);        /* slow blink when connecting */
1338         else
1339                 setled(ctlr, 2, 5, 5);          /* fast blink when scanning */
1340
1341         memset(p = c, 0, sizeof(c));
1342         memmove(p, edev->ea, 6); p += 8;        /* myaddr */
1343         memmove(p, ctlr->bssid, 6); p += 16;    /* bssid */
1344         *p++ = 3;                               /* mode (STA) */
1345         p += 3;
1346         *p++ = 0xff;                            /* ofdm mask (not yet negotiated) */
1347         *p++ = 0x0f;                            /* cck mask (not yet negotiated) */
1348         put16(p, ctlr->aid & 0x3fff);           /* associd */
1349         p += 2;
1350         put32(p, flags);
1351         p += 4;
1352         put32(p, filter);
1353         p += 4;
1354         *p++ = ctlr->channel;
1355         p += 3;
1356
1357         if((err = cmd(ctlr, 16, c, p - c)) != nil){
1358                 print("rxon: %s\n", err);
1359                 return;
1360         }
1361
1362         if(ctlr->maxpwr[ctlr->channel] != 0){
1363                 /* tx power */
1364                 memset(p = c, 0, sizeof(c));
1365                 *p++ = 1;       /* band (0 = 5ghz) */
1366                 p++;            /* reserved */
1367                 put16(p, ctlr->channel), p += 2;
1368                 for(rate = 0; rate < nelem(ratetab); rate++){
1369                         idx = pwridx(ctlr, &ctlr->eeprom.pwrgrps[0], ctlr->channel, rate);
1370                         *p++ = ratetab[rate].plcp;
1371                         *p++ = rfgain_2ghz[idx];        /* rf_gain */
1372                         *p++ = dspgain_2ghz[idx];       /* dsp_gain */
1373                         p++;            /* reservd */
1374                 }
1375                 cmd(ctlr, 151, c, p - c);
1376         }
1377
1378         if(ctlr->bcastnodeid == -1){
1379                 ctlr->bcastnodeid = 24;
1380                 addnode(ctlr, ctlr->bcastnodeid, edev->bcast, ratetab[0].plcp, 3<<6);
1381         }
1382         if(ctlr->bssnodeid == -1 && bss != nil && ctlr->aid != 0){
1383                 ctlr->bssnodeid = 0;
1384                 addnode(ctlr, ctlr->bssnodeid, bss->bssid, ratetab[0].plcp, 3<<6);
1385         }
1386 }
1387
1388 enum {
1389         TFlagNeedRTS            = 1<<1,
1390         TFlagNeedCTS            = 1<<2,
1391         TFlagNeedACK            = 1<<3,
1392         TFlagFullTxOp           = 1<<7,
1393         TFlagBtDis              = 1<<12,
1394         TFlagAutoSeq            = 1<<13,
1395         TFlagInsertTs           = 1<<16,
1396 };
1397
1398 static void
1399 transmit(Wifi *wifi, Wnode *wn, Block *b)
1400 {
1401         uchar c[Tcmdsize], *p;
1402         Ether *edev;
1403         Ctlr *ctlr;
1404         Wifipkt *w;
1405         int flags, nodeid, rate, timeout;
1406         char *err;
1407
1408         edev = wifi->ether;
1409         ctlr = edev->ctlr;
1410
1411         qlock(ctlr);
1412         if(ctlr->attached == 0 || ctlr->broken){
1413                 qunlock(ctlr);
1414                 freeb(b);
1415                 return;
1416         }
1417
1418         if((wn->channel != ctlr->channel)
1419            || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)))
1420                 rxon(edev, wn);
1421
1422         if(b == nil){
1423                 /* association note has no data to transmit */
1424                 qunlock(ctlr);
1425                 return;
1426         }
1427
1428         flags = 0;
1429         timeout = 3;
1430         nodeid = ctlr->bcastnodeid;
1431         p = wn->minrate;
1432         w = (Wifipkt*)b->rp;
1433         if((w->a1[0] & 1) == 0){
1434                 flags |= TFlagNeedACK;
1435
1436                 if(BLEN(b) > 512-4)
1437                         flags |= TFlagNeedRTS|TFlagFullTxOp;
1438
1439                 if((w->fc[0] & 0x0c) == 0x08 && ctlr->bssnodeid != -1){
1440                         timeout = 0;
1441                         nodeid = ctlr->bssnodeid;
1442                         p = wn->actrate;
1443                 }
1444         }
1445         if(p >= wifi->rates)
1446                 rate = p - wifi->rates;
1447         else
1448                 rate = 0;
1449         qunlock(ctlr);
1450
1451         memset(p = c, 0, sizeof(c));
1452         put16(p, BLEN(b)), p += 2;
1453         put16(p, 0), p += 2;    /* lnext */
1454         put32(p, flags), p += 4;
1455         *p++ = ratetab[rate].plcp;
1456         *p++ = nodeid;
1457         *p++ = 0;       /* tid */
1458         *p++ = 0;       /* security */
1459         p += 16+8;      /* key/iv */
1460         put32(p, 0), p += 4;    /* fnext */
1461         put32(p, 0xffffffff), p += 4;   /* livetime infinite */
1462         *p++ = 0xff;
1463         *p++ = 0x0f;
1464         *p++ = 7;
1465         *p++ = 15;
1466         put16(p, timeout), p += 2;
1467         put16(p, 0), p += 2;    /* txop */
1468
1469         if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
1470                 print("transmit: %s\n", err);
1471                 freeb(b);
1472         }
1473 }
1474
1475 static long
1476 wpictl(Ether *edev, void *buf, long n)
1477 {
1478         Ctlr *ctlr;
1479
1480         ctlr = edev->ctlr;
1481         if(n >= 5 && memcmp(buf, "reset", 5) == 0){
1482                 ctlr->broken = 1;
1483                 return n;
1484         }
1485         if(ctlr->wifi)
1486                 return wifictl(ctlr->wifi, buf, n);
1487         return 0;
1488 }
1489
1490 static long
1491 wpiifstat(Ether *edev, void *buf, long n, ulong off)
1492 {
1493         Ctlr *ctlr;
1494
1495         ctlr = edev->ctlr;
1496         if(ctlr->wifi)
1497                 return wifistat(ctlr->wifi, buf, n, off);
1498         return 0;
1499 }
1500
1501 static void
1502 setoptions(Ether *edev)
1503 {
1504         Ctlr *ctlr;
1505         int i;
1506
1507         ctlr = edev->ctlr;
1508         for(i = 0; i < edev->nopt; i++)
1509                 wificfg(ctlr->wifi, edev->opt[i]);
1510 }
1511
1512 static void
1513 wpipromiscuous(void *arg, int on)
1514 {
1515         Ether *edev;
1516         Ctlr *ctlr;
1517
1518         edev = arg;
1519         ctlr = edev->ctlr;
1520         qlock(ctlr);
1521         ctlr->prom = on;
1522         rxon(edev, ctlr->wifi->bss);
1523         qunlock(ctlr);
1524 }
1525
1526 static void
1527 wpimulticast(void *, uchar*, int)
1528 {
1529 }
1530
1531 static void
1532 wpirecover(void *arg)
1533 {
1534         Ether *edev;
1535         Ctlr *ctlr;
1536
1537         edev = arg;
1538         ctlr = edev->ctlr;
1539         while(waserror())
1540                 ;
1541         for(;;){
1542                 tsleep(&up->sleep, return0, 0, 4000);
1543
1544                 qlock(ctlr);
1545                 for(;;){
1546                         if(ctlr->broken == 0)
1547                                 break;
1548
1549                         if(ctlr->power)
1550                                 poweroff(ctlr);
1551
1552                         if((csr32r(ctlr, Gpc) & RfKill) == 0)
1553                                 break;
1554
1555                         if(reset(ctlr) != nil)
1556                                 break;
1557                         if(boot(ctlr) != nil)
1558                                 break;
1559
1560                         ctlr->bcastnodeid = -1;
1561                         ctlr->bssnodeid = -1;
1562                         ctlr->aid = 0;
1563                         rxon(edev, ctlr->wifi->bss);
1564                         break;
1565                 }
1566                 qunlock(ctlr);
1567         }
1568 }
1569
1570 static void
1571 wpiattach(Ether *edev)
1572 {
1573         FWImage *fw;
1574         Ctlr *ctlr;
1575         char *err;
1576
1577         ctlr = edev->ctlr;
1578         eqlock(ctlr);
1579         if(waserror()){
1580                 print("#l%d: %s\n", edev->ctlrno, up->errstr);
1581                 if(ctlr->power)
1582                         poweroff(ctlr);
1583                 qunlock(ctlr);
1584                 nexterror();
1585         }
1586         if(ctlr->attached == 0){
1587                 if((csr32r(ctlr, Gpc) & RfKill) == 0)
1588                         error("wifi disabled by switch");
1589
1590                 if(ctlr->wifi == nil){
1591                         qsetlimit(edev->oq, MaxQueue);
1592
1593                         ctlr->wifi = wifiattach(edev, transmit);
1594                         ctlr->wifi->rates = wpirates;
1595                 }
1596
1597                 if(ctlr->fw == nil){
1598                         fw = readfirmware();
1599                         print("#l%d: firmware: %ux, size: %ux+%ux+%ux+%ux+%ux\n",
1600                                 edev->ctlrno, fw->version,
1601                                 fw->main.text.size, fw->main.data.size,
1602                                 fw->init.text.size, fw->init.data.size,
1603                                 fw->boot.text.size);
1604                         ctlr->fw = fw;
1605                 }
1606
1607                 if((err = reset(ctlr)) != nil)
1608                         error(err);
1609                 if((err = boot(ctlr)) != nil)
1610                         error(err);
1611
1612                 ctlr->bcastnodeid = -1;
1613                 ctlr->bssnodeid = -1;
1614                 ctlr->channel = 1;
1615                 ctlr->aid = 0;
1616
1617                 setoptions(edev);
1618
1619                 ctlr->attached = 1;
1620
1621                 kproc("wpirecover", wpirecover, edev);
1622         }
1623         qunlock(ctlr);
1624         poperror();
1625 }
1626
1627 static void
1628 receive(Ctlr *ctlr)
1629 {
1630         Block *b, *bb;
1631         uchar *d;
1632         RXQ *rx;
1633         TXQ *tx;
1634         u32int hw;
1635
1636         rx = &ctlr->rx;
1637         if(ctlr->broken || ctlr->shared == nil || rx->b == nil)
1638                 return;
1639
1640         bb = nil;
1641         for(hw = ctlr->shared->next % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
1642                 uchar type, flags, idx, qid;
1643                 u32int len;
1644
1645                 b = rx->b[rx->i];
1646                 if(b == nil)
1647                         continue;
1648
1649                 d = b->rp;
1650                 len = get32(d); d += 4;
1651                 type = *d++;
1652                 flags = *d++;
1653                 idx = *d++;
1654                 qid = *d++;
1655
1656                 USED(len);
1657                 USED(flags);
1658
1659 if(0) iprint("rxdesc[%d] type=%d len=%d idx=%d qid=%d\n", rx->i, type, len, idx, qid);
1660
1661                 if(bb != nil){
1662                         freeb(bb);
1663                         bb = nil;
1664                 }
1665                 if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
1666                         tx = &ctlr->tx[qid];
1667                         if(tx->n > 0){
1668                                 bb = tx->b[idx];
1669                                 tx->b[idx] = nil;
1670                                 tx->n--;
1671                                 wakeup(tx);
1672                         }
1673                 }
1674
1675                 switch(type){
1676                 case 1:         /* uc ready */
1677                         break;
1678
1679                 case 24:        /* add node done */
1680                         break;
1681
1682                 case 27:        /* rx done */
1683                         if(d + 1 > b->lim)
1684                                 break;
1685                         d += d[0];
1686                         d += 8;
1687                         if(d + 6 + 2 > b->lim){
1688                                 break;
1689                         }
1690                         len = get16(d+6);
1691                         d += 8;
1692                         if(d + len + 4 > b->lim){
1693                                 break;
1694                         }
1695                         if((get32(d + len) & 3) != 3){
1696                                 break;
1697                         }
1698                         if(ctlr->wifi == nil)
1699                                 break;
1700                         if(rbplant(ctlr, rx->i) < 0)
1701                                 break;
1702                         b->rp = d;
1703                         b->wp = d + len;
1704                         wifiiq(ctlr->wifi, b);
1705                         continue;
1706
1707                 case 28:        /* tx done */
1708                         if(len <= 8 || d[8] == 1)
1709                                 break;
1710                         wifitxfail(ctlr->wifi, bb);
1711                         break;
1712
1713                 case 130:       /* start scan */
1714                         break;
1715
1716                 case 132:       /* stop scan */
1717                         break;
1718
1719                 case 161:       /* state change */
1720                         break;
1721                 }
1722         }
1723         csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
1724         if(bb != nil)
1725                 freeb(bb);
1726 }
1727
1728 static void
1729 wpiinterrupt(Ureg*, void *arg)
1730 {
1731         u32int isr, fhisr;
1732         Ether *edev;
1733         Ctlr *ctlr;
1734
1735         edev = arg;
1736         ctlr = edev->ctlr;
1737         ilock(ctlr);
1738         csr32w(ctlr, Imr, 0);
1739         isr = csr32r(ctlr, Isr);
1740         fhisr = csr32r(ctlr, FhIsr);
1741         if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
1742                 iunlock(ctlr);
1743                 return;
1744         }
1745         if(isr == 0 && fhisr == 0)
1746                 goto done;
1747         csr32w(ctlr, Isr, isr);
1748         csr32w(ctlr, FhIsr, fhisr);
1749         if((isr & (Iswrx | Ifhrx)) || (fhisr & Ifhrx))
1750                 receive(ctlr);
1751         if(isr & Ierr){
1752                 ctlr->broken = 1;
1753                 iprint("#l%d: fatal firmware error, lastcmd %ud\n", edev->ctlrno, ctlr->tx[4].lastcmd);
1754         }
1755         ctlr->wait.m |= isr;
1756         if(ctlr->wait.m & ctlr->wait.w)
1757                 wakeup(&ctlr->wait);
1758 done:
1759         csr32w(ctlr, Imr, ctlr->ie);
1760         iunlock(ctlr);
1761 }
1762
1763 static void
1764 wpishutdown(Ether *edev)
1765 {
1766         Ctlr *ctlr;
1767
1768         ctlr = edev->ctlr;
1769         if(ctlr->power)
1770                 poweroff(ctlr);
1771         ctlr->broken = 0;
1772 }
1773
1774 static Ctlr *wpihead, *wpitail;
1775
1776 static void
1777 wpipci(void)
1778 {
1779         Pcidev *pdev;
1780
1781         pdev = nil;
1782         while(pdev = pcimatch(pdev, 0x8086, 0)){
1783                 Ctlr *ctlr;
1784                 void *mem;
1785                 switch(pdev->did){
1786                 default:
1787                         continue;
1788                 case 0x4227:
1789                         break;
1790                 }
1791
1792                 /* Clear device-specific "PCI retry timeout" register (41h). */
1793                 if(pcicfgr8(pdev, 0x41) != 0)
1794                         pcicfgw8(pdev, 0x41, 0);
1795
1796                 ctlr = malloc(sizeof(Ctlr));
1797                 if(ctlr == nil) {
1798                         print("wpi: unable to alloc Ctlr\n");
1799                         continue;
1800                 }
1801                 ctlr->port = pdev->mem[0].bar & ~0x0F;
1802                 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
1803                 if(mem == nil) {
1804                         print("wpi: can't map %8.8luX\n", pdev->mem[0].bar);
1805                         free(ctlr);
1806                         continue;
1807                 }
1808                 ctlr->nic = mem;
1809                 ctlr->pdev = pdev;
1810
1811                 if(wpihead != nil)
1812                         wpitail->link = ctlr;
1813                 else
1814                         wpihead = ctlr;
1815                 wpitail = ctlr;
1816         }
1817 }
1818
1819 static int
1820 wpipnp(Ether *edev)
1821 {
1822         Ctlr *ctlr;
1823
1824         if(wpihead == nil)
1825                 wpipci();
1826
1827 again:
1828         for(ctlr = wpihead; ctlr != nil; ctlr = ctlr->link){
1829                 if(ctlr->active)
1830                         continue;
1831                 if(edev->port == 0 || edev->port == ctlr->port){
1832                         ctlr->active = 1;
1833                         break;
1834                 }
1835         }
1836
1837         if(ctlr == nil)
1838                 return -1;
1839
1840         edev->ctlr = ctlr;
1841         edev->port = ctlr->port;
1842         edev->irq = ctlr->pdev->intl;
1843         edev->tbdf = ctlr->pdev->tbdf;
1844         edev->arg = edev;
1845         edev->attach = wpiattach;
1846         edev->ifstat = wpiifstat;
1847         edev->ctl = wpictl;
1848         edev->shutdown = wpishutdown;
1849         edev->promiscuous = wpipromiscuous;
1850         edev->multicast = wpimulticast;
1851         edev->mbps = 54;
1852
1853         pcienable(ctlr->pdev);
1854         if(wpiinit(edev) < 0){
1855                 pcidisable(ctlr->pdev);
1856                 edev->ctlr = nil;
1857                 goto again;
1858         }
1859         pcisetbme(ctlr->pdev);
1860         intrenable(edev->irq, wpiinterrupt, edev, edev->tbdf, edev->name);
1861
1862         return 0;
1863 }
1864
1865 void
1866 etherwpilink(void)
1867 {
1868         addethercard("wpi", wpipnp);
1869 }