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