2 * Intel WiFi Link driver.
4 * Written without any documentation but Damien Bergaminis
5 * OpenBSD iwn(4) driver sources. Requires intel firmware
6 * to be present in /lib/firmware/iwn-* on attach.
10 #include "../port/lib.h"
15 #include "../port/error.h"
16 #include "../port/netif.h"
38 Cfg = 0x000, /* config register */
47 Isr = 0x008, /* interrupt status */
48 Imr = 0x00c, /* interrupt mask */
61 Ierr = Iswerr | Ihwerr,
62 Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled,
64 FhIsr = 0x010, /* second interrupt status */
68 Rev = 0x028, /* hardware revision */
70 EepromIo = 0x02c, /* EEPROM i/o register */
74 RelativeAccess = 1<<17,
76 EccUncorrStts = 1<<21,
78 Gpc = 0x024, /* gp cntrl */
95 UcodeGp1RfKill = 1<<1,
96 UcodeGp1CmdBlocked = 1<<2,
97 UcodeGp1CtempStopRf = 1<<3,
99 ShadowRegCtrl = 0x0a8,
119 HbusTargWptr = 0x460,
123 * Flow-Handler registers.
126 FhTfbdCtrl0 = 0x1900, // +q*8
127 FhTfbdCtrl1 = 0x1904, // +q*8
131 FhSramAddr = 0x19a4, // +q*4
132 FhCbbcQueue = 0x19d0, // +q*4
133 FhStatusWptr = 0x1bc0,
137 FhRxConfigEna = 1<<31,
138 FhRxConfigRbSize8K = 1<<16,
139 FhRxConfigSingleFrame = 1<<15,
140 FhRxConfigIrqDstHost = 1<<12,
141 FhRxConfigIgnRxfEmpty = 1<<2,
143 FhRxConfigNrbdShift = 20,
144 FhRxConfigRbTimeoutShift= 4,
148 FhTxConfig = 0x1d00, // +q*32
149 FhTxConfigDmaCreditEna = 1<<3,
150 FhTxConfigDmaEna = 1<<31,
151 FhTxConfigCirqHostEndTfd= 1<<20,
153 FhTxBufStatus = 0x1d08, // +q*32
154 FhTxBufStatusTbNumShift = 20,
155 FhTxBufStatusTbIdxShift = 12,
156 FhTxBufStatusTfbdValid = 3,
158 FhTxChicken = 0x1e98,
163 * NIC internal memory offsets.
166 ApmgClkCtrl = 0x3000,
173 EarlyPwroffDis = 1<<22,
179 ApmgDigitalSvr = 0x3058,
180 ApmgAnalogSvr = 0x306c,
183 BsmWrMemSrc = 0x3404,
184 BsmWrMemDst = 0x3408,
185 BsmWrDwCount = 0x340c,
186 BsmDramTextAddr = 0x3490,
187 BsmDramTextSize = 0x3494,
188 BsmDramDataAddr = 0x3498,
189 BsmDramDataSize = 0x349c,
190 BsmSramBase = 0x3800,
194 * TX scheduler registers.
197 SchedBase = 0xa02c00,
198 SchedSramAddr = SchedBase,
200 SchedDramAddr4965 = SchedBase+0x010,
201 SchedTxFact4965 = SchedBase+0x01c,
202 SchedQueueRdptr4965 = SchedBase+0x064, // +q*4
203 SchedQChainSel4965 = SchedBase+0x0d0,
204 SchedIntrMask4965 = SchedBase+0x0e4,
205 SchedQueueStatus4965 = SchedBase+0x104, // +q*4
207 SchedDramAddr5000 = SchedBase+0x008,
208 SchedTxFact5000 = SchedBase+0x010,
209 SchedQueueRdptr5000 = SchedBase+0x068, // +q*4
210 SchedQChainSel5000 = SchedBase+0x0e8,
211 SchedIntrMask5000 = SchedBase+0x108,
212 SchedQueueStatus5000 = SchedBase+0x10c, // +q*4
213 SchedAggrSel5000 = SchedBase+0x248,
217 SchedCtxOff4965 = 0x380,
218 SchedCtxLen4965 = 416,
220 SchedCtxOff5000 = 0x600,
221 SchedCtxLen5000 = 512,
225 FilterPromisc = 1<<0,
227 FilterMulticast = 1<<2,
228 FilterNoDecrypt = 1<<3,
238 RFlagShPreamble = 1<<5,
239 RFlagNoDiversity = 1<<7,
240 RFlagAntennaA = 1<<8,
241 RFlagAntennaB = 1<<9,
243 RFlagCTSToSelf = 1<<30,
246 typedef struct FWInfo FWInfo;
247 typedef struct FWImage FWImage;
248 typedef struct FWSect FWSect;
250 typedef struct TXQ TXQ;
251 typedef struct RXQ RXQ;
253 typedef struct Ctlr Ctlr;
325 /* assigned node ids in hardware node table or -1 if unassigned */
329 /* current receiver settings */
330 uchar bssid[Eaddrlen];
366 /* controller types */
379 static char *fwname[16] = {
380 [Type4965] "iwn-4965",
381 [Type5300] "iwn-5000",
382 [Type5350] "iwn-5000",
383 [Type5150] "iwn-5150",
384 [Type5100] "iwn-5000",
385 [Type1000] "iwn-1000",
386 [Type6000] "iwn-6000",
387 [Type6050] "iwn-6050",
388 [Type6005] "iwn-6005",
391 #define csr32r(c, r) (*((c)->nic+((r)/4)))
392 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
396 return *((u16int*)p);
400 return *((u32int*)p);
403 put32(uchar *p, uint v){
407 put16(uchar *p, uint v){
416 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
417 for(i=0; i<1000; i++){
418 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
422 return "niclock: timeout";
426 nicunlock(Ctlr *ctlr)
428 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
432 prphread(Ctlr *ctlr, uint off)
434 csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
436 return csr32r(ctlr, PrphRdata);
439 prphwrite(Ctlr *ctlr, uint off, u32int data)
441 csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
443 csr32w(ctlr, PrphWdata, data);
447 memread(Ctlr *ctlr, uint off)
449 csr32w(ctlr, MemRaddr, off);
451 return csr32r(ctlr, MemRdata);
454 memwrite(Ctlr *ctlr, uint off, u32int data)
456 csr32w(ctlr, MemWaddr, off);
458 csr32w(ctlr, MemWdata, data);
462 setfwinfo(Ctlr *ctlr, uchar *d, int len)
475 i->logptr = get32(d); d += 4;
476 i->errptr = get32(d); d += 4;
477 i->tstamp = get32(d); d += 4;
487 if(ctlr->fwinfo.errptr == 0){
488 print("no error pointer\n");
491 for(i=0; i<nelem(dump); i++)
492 dump[i] = memread(ctlr, ctlr->fwinfo.errptr + i*4);
493 print( "error:\tid %ux, pc %ux,\n"
494 "\tbranchlink %.8ux %.8ux, interruptlink %.8ux %.8ux,\n"
495 "\terrordata %.8ux %.8ux, srcline %ud, tsf %ux, time %ux\n",
497 dump[4], dump[3], dump[6], dump[5],
498 dump[7], dump[8], dump[9], dump[10], dump[11]);
502 eepromlock(Ctlr *ctlr)
506 for(i=0; i<100; i++){
507 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | EepromLocked);
508 for(j=0; j<100; j++){
509 if(csr32r(ctlr, Cfg) & EepromLocked)
514 return "eepromlock: timeout";
517 eepromunlock(Ctlr *ctlr)
519 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~EepromLocked);
522 eepromread(Ctlr *ctlr, void *data, int count, uint off)
529 for(; count > 0; count -= 2, off++){
530 csr32w(ctlr, EepromIo, off << 2);
532 w = csr32r(ctlr, EepromIo);
538 return "eepromread: timeout";
551 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
553 if(csr32r(ctlr, Cfg) & NicReady)
557 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
558 for(i=0; i<15000; i++){
559 if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
564 return "handover: timeout";
565 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
567 if(csr32r(ctlr, Cfg) & NicReady)
571 return "handover: timeout";
575 clockwait(Ctlr *ctlr)
579 /* Set "initialization complete" bit. */
580 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
581 for(i=0; i<2500; i++){
582 if(csr32r(ctlr, Gpc) & MacClockReady)
586 return "clockwait: timeout";
595 /* Disable L0s exit timer (NMI bug workaround). */
596 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | DisL0Stimer);
598 /* Don't wait for ICH L0s (ICH bug workaround). */
599 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | L1AnoL0Srx);
601 /* Set FH wait threshold to max (HW bug under stress workaround). */
602 csr32w(ctlr, Dbghpetmem, csr32r(ctlr, Dbghpetmem) | 0xffff0000);
604 /* Enable HAP INTA to move adapter from L1a to L0s. */
605 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | HapwakeL1A);
607 capoff = pcicap(ctlr->pdev, PciCapPCIe);
609 /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
610 if(pcicfgr16(ctlr->pdev, capoff + 0x10) & 0x2) /* LCSR -> L1 Entry enabled. */
611 csr32w(ctlr, Gio, csr32r(ctlr, Gio) | EnaL0S);
613 csr32w(ctlr, Gio, csr32r(ctlr, Gio) & ~EnaL0S);
616 if(ctlr->type != Type4965 && ctlr->type <= Type1000)
617 csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | 0x00880300);
619 /* Wait for clock stabilization before accessing prph. */
620 if((err = clockwait(ctlr)) != nil)
623 if((err = niclock(ctlr)) != nil)
626 /* Enable DMA and BSM (Bootstrap State Machine). */
627 if(ctlr->type == Type4965)
628 prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
630 prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
633 /* Disable L1-Active. */
634 prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
649 if((err = handover(ctlr)) != nil)
651 if((err = poweron(ctlr)) != nil)
653 if((csr32r(ctlr, EepromGp) & 0x7) == 0){
654 err = "bad rom signature";
657 if((err = eepromlock(ctlr)) != nil)
659 if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
663 if(ctlr->type != Type4965){
664 if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
669 ctlr->rfcfg.type = u & 3; u >>= 2;
670 ctlr->rfcfg.step = u & 3; u >>= 2;
671 ctlr->rfcfg.dash = u & 3; u >>= 4;
672 ctlr->rfcfg.txantmask = u & 15; u >>= 4;
673 ctlr->rfcfg.rxantmask = u & 15;
674 if((err = eepromread(ctlr, b, 4, 0x128)) != nil){
678 ctlr->eeprom.crystal = get32(b);
684 ctlr->rfcfg.txantmask = 3;
685 ctlr->rfcfg.rxantmask = 7;
688 ctlr->rfcfg.txantmask = 2;
689 ctlr->rfcfg.rxantmask = 3;
692 if(ctlr->pdev->did == 0x422c || ctlr->pdev->did == 0x4230){
693 ctlr->rfcfg.txantmask = 6;
694 ctlr->rfcfg.rxantmask = 6;
700 csr32w(ctlr, Isr, ~0); /* clear pending interrupts */
701 csr32w(ctlr, Imr, 0); /* no interrupts for now */
705 print("iwlinit: %s\n", err);
710 crackfw(FWImage *i, uchar *data, uint size, int alt)
715 memset(i, 0, sizeof(*i));
718 return "firmware image too short";
722 i->rev = get32(p); p += 4;
726 if(size < (4+64+4+4+8))
728 if(memcmp(p, "IWL\n", 4) != 0)
729 return "bad firmware signature";
731 strncpy(i->descr, (char*)p, 64);
734 i->rev = get32(p); p += 4;
735 i->build = get32(p); p += 4;
736 altmask = get32(p); p += 4;
737 altmask |= (uvlong)get32(p) << 32; p += 4;
738 while(alt > 0 && (altmask & (1ULL<<alt)) == 0)
746 case 1: s = &i->main.text; break;
747 case 2: s = &i->main.data; break;
748 case 3: s = &i->init.text; break;
749 case 4: s = &i->init.data; break;
750 case 5: s = &i->boot.text; break;
754 if(get16(p) != 0 && get16(p) != alt)
757 s->size = get32(p); p += 4;
759 if((p + s->size) > e)
761 p += (s->size + 3) & ~3;
764 if(((i->rev>>8) & 0xFF) < 2)
765 return "need firmware api >= 2";
766 if(((i->rev>>8) & 0xFF) >= 3){
767 i->build = get32(p); p += 4;
771 i->main.text.size = get32(p); p += 4;
772 i->main.data.size = get32(p); p += 4;
773 i->init.text.size = get32(p); p += 4;
774 i->init.data.size = get32(p); p += 4;
775 i->boot.text.size = get32(p); p += 4;
776 i->main.text.data = p; p += i->main.text.size;
777 i->main.data.data = p; p += i->main.data.size;
778 i->init.text.data = p; p += i->init.text.size;
779 i->init.data.data = p; p += i->init.data.size;
780 i->boot.text.data = p; p += i->boot.text.size;
788 readfirmware(char *name)
790 uchar dirbuf[sizeof(Dir)+100], *data;
800 snprint(buf, sizeof buf, "/boot/%s", name);
801 c = namec(buf, Aopen, OREAD, 0);
804 snprint(buf, sizeof buf, "/lib/firmware/%s", name);
805 c = namec(buf, Aopen, OREAD, 0);
811 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
813 error("can't stat firmware");
814 convM2D(dirbuf, n, &d, nil);
815 fw = smalloc(sizeof(*fw) + 16 + d.length);
816 data = (uchar*)(fw+1);
823 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
828 if((err = crackfw(fw, data, r, 1)) != nil)
836 typedef struct Irqwait Irqwait;
850 ctlr->wait.r = ctlr->wait.m & w->mask;
852 ctlr->wait.m &= ~ctlr->wait.r;
855 ctlr->wait.w = w->mask;
860 irqwait(Ctlr *ctlr, u32int mask, int timeout)
866 tsleep(&ctlr->wait, gotirq, &w, timeout);
868 return ctlr->wait.r & mask;
872 loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
877 dma = mallocalign(size, 16, 0, 0);
879 return "no memory for dma";
880 memmove(dma, data, size);
882 if((err = niclock(ctlr)) != 0){
886 csr32w(ctlr, FhTxConfig + 9*32, 0);
887 csr32w(ctlr, FhSramAddr + 9*4, dst);
888 csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
889 csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
890 csr32w(ctlr, FhTxBufStatus + 9*32,
891 (1<<FhTxBufStatusTbNumShift) |
892 (1<<FhTxBufStatusTbIdxShift) |
893 FhTxBufStatusTfbdValid);
894 csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
896 if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
898 return "dma error / timeout";
905 bootfirmware(Ctlr *ctlr)
915 if(fw->boot.text.size == 0){
916 if((err = loadfirmware1(ctlr, 0x00000000, fw->main.text.data, fw->main.text.size)) != nil)
918 if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
920 csr32w(ctlr, Reset, 0);
924 size = ROUND(fw->init.data.size, 16) + ROUND(fw->init.text.size, 16);
925 dma = mallocalign(size, 16, 0, 0);
927 return "no memory for dma";
929 if((err = niclock(ctlr)) != nil){
935 memmove(p, fw->init.data.data, fw->init.data.size);
937 prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
938 prphwrite(ctlr, BsmDramDataSize, fw->init.data.size);
939 p += ROUND(fw->init.data.size, 16);
940 memmove(p, fw->init.text.data, fw->init.text.size);
942 prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
943 prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
946 if((err = niclock(ctlr)) != nil){
951 p = fw->boot.text.data;
952 n = fw->boot.text.size/4;
953 for(i=0; i<n; i++, p += 4)
954 prphwrite(ctlr, BsmSramBase+i*4, get32(p));
956 prphwrite(ctlr, BsmWrMemSrc, 0);
957 prphwrite(ctlr, BsmWrMemDst, 0);
958 prphwrite(ctlr, BsmWrDwCount, n);
960 prphwrite(ctlr, BsmWrCtrl, 1<<31);
962 for(i=0; i<1000; i++){
963 if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
970 return "bootfirmware: bootcode timeout";
973 prphwrite(ctlr, BsmWrCtrl, 1<<30);
976 csr32w(ctlr, Reset, 0);
977 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
979 return "init firmware boot failed";
983 size = ROUND(fw->main.data.size, 16) + ROUND(fw->main.text.size, 16);
984 dma = mallocalign(size, 16, 0, 0);
986 return "no memory for dma";
987 if((err = niclock(ctlr)) != nil){
992 memmove(p, fw->main.data.data, fw->main.data.size);
994 prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
995 prphwrite(ctlr, BsmDramDataSize, fw->main.data.size);
996 p += ROUND(fw->main.data.size, 16);
997 memmove(p, fw->main.text.data, fw->main.text.size);
999 prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
1000 prphwrite(ctlr, BsmDramTextSize, fw->main.text.size | (1<<31));
1004 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
1006 return "main firmware boot failed";
1020 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
1025 assert(qid < nelem(ctlr->tx));
1026 assert(size <= Tcmdsize-4);
1034 tsleep(q, txqready, q, 10);
1043 c = q->c + q->i * Tcmdsize;
1044 d = q->d + q->i * Tdscsize;
1048 c[1] = 0; /* flags */
1052 memmove(c+4, data, size);
1056 /* build descriptor */
1060 *d++ = 1 + (block != nil); /* nsegs */
1061 put32(d, PCIWADDR(c)); d += 4;
1062 put16(d, size << 4); d += 2;
1067 put32(d, PCIWADDR(block->rp)); d += 4;
1068 put16(d, size << 4);
1073 q->i = (q->i+1) % Ntx;
1074 csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
1087 flushq(Ctlr *ctlr, uint qid)
1095 tsleep(q, txqempty, q, 10);
1104 flushcmd(Ctlr *ctlr)
1110 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
1112 qcmd(ctlr, 4, code, data, size, nil);
1117 setled(Ctlr *ctlr, int which, int on, int off)
1121 csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
1123 memset(c, 0, sizeof(c));
1128 cmd(ctlr, 72, c, sizeof(c));
1132 * initialization which runs after the firmware has been booted up
1135 postboot(Ctlr *ctlr)
1137 uint ctxoff, ctxlen, dramaddr, txfact;
1142 if((err = niclock(ctlr)) != nil)
1145 if(ctlr->type != Type4965){
1146 dramaddr = SchedDramAddr5000;
1147 ctxoff = SchedCtxOff5000;
1148 ctxlen = SchedCtxLen5000;
1149 txfact = SchedTxFact5000;
1151 dramaddr = SchedDramAddr4965;
1152 ctxoff = SchedCtxOff4965;
1153 ctxlen = SchedCtxLen4965;
1154 txfact = SchedTxFact4965;
1157 ctlr->sched.base = prphread(ctlr, SchedSramAddr);
1158 for(i=0; i < ctxlen; i += 4)
1159 memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
1161 prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
1163 csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
1165 if(ctlr->type != Type4965){
1166 /* Enable chain mode for all queues, except command queue 4. */
1167 prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
1168 prphwrite(ctlr, SchedAggrSel5000, 0);
1170 for(q=0; q<20; q++){
1171 prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
1172 csr32w(ctlr, HbusTargWptr, q << 8);
1174 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 0);
1175 /* Set scheduler window size and frame limit. */
1176 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16 | 64);
1178 /* Enable interrupts for all our 20 queues. */
1179 prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
1181 /* Disable chain mode for all our 16 queues. */
1182 prphwrite(ctlr, SchedQChainSel4965, 0);
1184 for(q=0; q<16; q++) {
1185 prphwrite(ctlr, SchedQueueRdptr4965 + q*4, 0);
1186 csr32w(ctlr, HbusTargWptr, q << 8);
1188 /* Set scheduler window size. */
1189 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 64);
1190 /* Set scheduler window size and frame limit. */
1191 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16);
1193 /* Enable interrupts for all our 16 queues. */
1194 prphwrite(ctlr, SchedIntrMask4965, 0xffff);
1197 /* Identify TX FIFO rings (0-7). */
1198 prphwrite(ctlr, txfact, 0xff);
1200 /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
1202 if(ctlr->type != Type4965){
1203 static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
1204 prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
1206 static uchar qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 };
1207 prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]<<1);
1212 if(ctlr->type != Type4965){
1213 if(ctlr->type != Type5150){
1214 memset(c, 0, sizeof(c));
1215 c[0] = 15; /* code */
1216 c[1] = 0; /* grup */
1217 c[2] = 1; /* ngroup */
1218 c[3] = 1; /* isvalid */
1219 put16(c+4, ctlr->eeprom.crystal);
1220 cmd(ctlr, 176, c, 8);
1222 put32(c, ctlr->rfcfg.txantmask & 7);
1223 cmd(ctlr, 152, c, 4);
1228 addnode(Ctlr *ctlr, uchar id, uchar *addr)
1230 uchar c[Tcmdsize], *p;
1232 memset(p = c, 0, sizeof(c));
1233 *p++ = 0; /* control (1 = update) */
1234 p += 3; /* reserved */
1235 memmove(p, addr, 6);
1237 p += 2; /* reserved */
1238 *p++ = id; /* node id */
1240 p += 2; /* reserved */
1241 p += 2; /* kflags */
1244 p += 5*2; /* ttak */
1248 if(ctlr->type != Type4965){
1253 p += 4; /* htflags */
1255 p += 2; /* disable tid */
1256 p += 2; /* reserved */
1257 p++; /* add ba tid */
1258 p++; /* del ba tid */
1259 p += 2; /* add ba ssn */
1260 p += 4; /* reserved */
1261 cmd(ctlr, 24, c, p - c);
1265 rxon(Ether *edev, Wnode *bss)
1267 uchar c[Tcmdsize], *p;
1272 filter = FilterMulticast | FilterBeacon;
1274 filter |= FilterPromisc;
1278 ctlr->channel = bss->channel;
1279 memmove(ctlr->bssid, bss->bssid, Eaddrlen);
1280 ctlr->aid = bss->aid;
1282 filter |= FilterBSS;
1283 filter &= ~FilterBeacon;
1284 ctlr->bssnodeid = -1;
1286 ctlr->bcastnodeid = -1;
1288 memmove(ctlr->bssid, edev->bcast, Eaddrlen);
1290 ctlr->bcastnodeid = -1;
1291 ctlr->bssnodeid = -1;
1293 flags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
1295 if(0) print("rxon: bssid %E, aid %x, channel %d, filter %x, flags %x\n",
1296 ctlr->bssid, ctlr->aid, ctlr->channel, filter, flags);
1298 memset(p = c, 0, sizeof(c));
1299 memmove(p, edev->ea, 6); p += 8; /* myaddr */
1300 memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
1301 memmove(p, edev->ea, 6); p += 8; /* wlap */
1302 *p++ = 3; /* mode (STA) */
1303 *p++ = 0; /* air (?) */
1305 put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
1307 *p++ = 0xff; /* ofdm mask (not yet negotiated) */
1308 *p++ = 0x0f; /* cck mask (not yet negotiated) */
1309 put16(p, ctlr->aid & 0x3fff);
1315 *p++ = ctlr->channel;
1317 *p++ = 0xff; /* ht single mask */
1318 *p++ = 0xff; /* ht dual mask */
1319 if(ctlr->type != Type4965){
1320 *p++ = 0xff; /* ht triple mask */
1322 put16(p, 0); p += 2; /* acquisition */
1323 p += 2; /* reserved */
1325 cmd(ctlr, 16, c, p - c);
1327 if(ctlr->bcastnodeid == -1){
1328 ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31;
1329 addnode(ctlr, ctlr->bcastnodeid, edev->bcast);
1331 if(ctlr->bssnodeid == -1 && bss != nil && ctlr->aid != 0){
1332 ctlr->bssnodeid = 0;
1333 addnode(ctlr, ctlr->bssnodeid, bss->bssid);
1338 static struct ratetab {
1343 { 2, 10, RFlagCCK },
1344 { 4, 20, RFlagCCK },
1345 { 11, 55, RFlagCCK },
1346 { 22, 110, RFlagCCK },
1359 TFlagNeedProtection = 1<<0,
1360 TFlagNeedRTS = 1<<1,
1361 TFlagNeedCTS = 1<<2,
1362 TFlagNeedACK = 1<<3,
1365 TFlagFullTxOp = 1<<7,
1367 TFlagAutoSeq = 1<<13,
1368 TFlagMoreFrag = 1<<14,
1369 TFlagInsertTs = 1<<16,
1370 TFlagNeedPadding = 1<<20,
1374 transmit(Wifi *wifi, Wnode *wn, Block *b)
1376 uchar c[Tcmdsize], *p;
1380 int flags, nodeid, rate;
1382 w = (Wifipkt*)b->rp;
1389 if(wn->aid != ctlr->aid
1390 || wn->channel != ctlr->channel
1391 || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)
1396 nodeid = ctlr->bcastnodeid;
1397 if((w->a1[0] & 1) == 0){
1398 flags |= TFlagNeedACK;
1401 flags |= TFlagNeedRTS;
1403 if((w->fc[0] & 0x0c) == 0x08 && ctlr->bssnodeid != -1){
1404 nodeid = ctlr->bssnodeid;
1405 rate = 2; /* BUG: hardcode 11Mbit */
1408 if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
1409 if(ctlr->type != Type4965){
1410 flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
1411 flags |= TFlagNeedProtection;
1413 flags |= TFlagFullTxOp;
1418 memset(p = c, 0, sizeof(c));
1425 p += 4; /* scratch */
1427 *p++ = ratetab[rate].plcp;
1428 *p++ = ratetab[rate].flags | (1<<6);
1430 p += 2; /* xflags */
1432 *p++ = 0; /* security */
1433 *p++ = 0; /* linkq */
1437 p += 2; /* reserved */
1438 put32(p, ~0); /* lifetime */
1441 /* BUG: scratch ptr? not clear what this is for */
1442 put32(p, PCIWADDR(ctlr->kwpage));
1445 *p++ = 60; /* rts ntries */
1446 *p++ = 15; /* data ntries */
1448 put16(p, 0); /* timeout */
1451 qcmd(ctlr, 0, 28, c, p - c, b);
1455 rbplant(Ctlr *ctlr, int i)
1459 b = iallocb(Rbufsize + 256);
1462 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
1463 memset(b->rp, 0, Rdscsize);
1465 ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
1470 iwlctl(Ether *edev, void *buf, long n)
1476 return wifictl(ctlr->wifi, buf, n);
1481 iwlifstat(Ether *edev, void *buf, long n, ulong off)
1487 return wifistat(ctlr->wifi, buf, n, off);
1492 setoptions(Ether *edev)
1499 for(i = 0; i < edev->nopt; i++){
1500 if(strncmp(edev->opt[i], "essid=", 6) == 0){
1501 snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
1503 wifictl(ctlr->wifi, buf, strlen(buf));
1511 iwlpromiscuous(void *arg, int on)
1520 rxon(edev, ctlr->wifi->bss);
1537 /* hop channels for catching beacons */
1538 setled(ctlr, 2, 5, 5);
1539 while(wifi->bss == nil){
1541 if(wifi->bss != nil){
1545 ctlr->channel = 1 + ctlr->channel % 11;
1549 tsleep(&up->sleep, return0, 0, 1000);
1552 /* wait for association */
1553 setled(ctlr, 2, 10, 10);
1554 while((bss = wifi->bss) != nil){
1557 tsleep(&up->sleep, return0, 0, 1000);
1563 /* wait for disassociation */
1565 setled(ctlr, 2, 0, 1);
1566 while((bss = wifi->bss) != nil){
1569 tsleep(&up->sleep, return0, 0, 1000);
1576 iwlattach(Ether *edev)
1592 if(ctlr->attached == 0){
1593 if((csr32r(ctlr, Gpc) & RfKill) == 0){
1594 print("#l%d: wifi disabled by switch\n", edev->ctlrno);
1595 error("wifi disabled by switch");
1598 if(ctlr->wifi == nil)
1599 ctlr->wifi = wifiattach(edev, transmit);
1601 if(ctlr->fw == nil){
1602 fw = readfirmware(fwname[ctlr->type]);
1603 print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
1607 fw->main.text.size, fw->main.data.size,
1608 fw->init.text.size, fw->init.data.size,
1609 fw->boot.text.size);
1616 rx->b = malloc(sizeof(Block*) * Nrx);
1618 rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
1620 rx->s = mallocalign(Rstatsize, 16, 0, 0);
1621 if(rx->b == nil || rx->p == nil || rx->s == nil)
1622 error("no memory for rx ring");
1623 memset(rx->s, 0, Rstatsize);
1624 for(i=0; i<Nrx; i++){
1626 if(rx->b[i] != nil){
1630 if(rbplant(ctlr, i) < 0)
1631 error("no memory for rx descriptors");
1634 for(q=0; q<nelem(ctlr->tx); q++){
1639 tx->b = malloc(sizeof(Block*) * Ntx);
1641 tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
1643 tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
1644 if(tx->b == nil || tx->d == nil || tx->c == nil)
1645 error("no memory for tx ring");
1646 memset(tx->d, 0, Tdscsize * Ntx);
1649 if(ctlr->sched.s == nil)
1650 ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
1651 if(ctlr->kwpage == nil)
1652 ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
1654 if((err = niclock(ctlr)) != nil)
1656 prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
1659 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
1661 if((err = niclock(ctlr)) != nil)
1663 prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
1666 if((err = niclock(ctlr)) != nil)
1668 csr32w(ctlr, FhRxConfig, 0);
1669 csr32w(ctlr, FhRxWptr, 0);
1670 csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
1671 csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
1672 csr32w(ctlr, FhRxConfig,
1674 FhRxConfigIgnRxfEmpty |
1675 FhRxConfigIrqDstHost |
1676 FhRxConfigSingleFrame |
1677 (Nrxlog << FhRxConfigNrbdShift));
1678 csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
1681 if((err = niclock(ctlr)) != nil)
1684 if(ctlr->type != Type4965)
1685 prphwrite(ctlr, SchedTxFact5000, 0);
1687 prphwrite(ctlr, SchedTxFact4965, 0);
1689 csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
1691 for(q = (ctlr->type != Type4965) ? 19 : 15; q >= 0; q--)
1692 csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
1696 for(i = (ctlr->type != Type4965) ? 7 : 6; i >= 0; i--)
1697 csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
1699 csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1700 csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
1702 ctlr->ie = Idefmask;
1703 csr32w(ctlr, Imr, ctlr->ie);
1704 csr32w(ctlr, Isr, ~0);
1706 if(ctlr->type >= Type6000)
1707 csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
1712 ctlr->bcastnodeid = -1;
1713 ctlr->bssnodeid = -1;
1719 snprint(name, sizeof(name), "#l%diwl", edev->ctlrno);
1720 kproc(name, iwlproc, edev);
1738 if(rx->s == nil || rx->b == nil)
1740 for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
1741 uchar type, flags, idx, qid;
1749 len = get32(d); d += 4;
1756 if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
1757 tx = &ctlr->tx[qid];
1764 /* paranoia: clear tx descriptors */
1765 dd = tx->d + idx*Tdscsize;
1766 cc = tx->c + idx*Tcmdsize;
1767 memset(dd, 0, Tdscsize);
1768 memset(cc, 0, Tcmdsize);
1776 if(len < 4 || type == 0)
1781 case 1: /* microcontroller ready */
1782 setfwinfo(ctlr, d, len);
1784 case 24: /* add node done */
1786 case 28: /* tx done */
1788 case 102: /* calibration result (Type5000 only) */
1790 case 103: /* calibration done (Type5000 only) */
1792 case 130: /* start scan */
1794 case 132: /* stop scan */
1796 case 156: /* rx statistics */
1798 case 157: /* beacon statistics */
1800 case 161: /* state changed */
1802 case 162: /* beacon missed */
1804 case 192: /* rx phy */
1806 case 195: /* rx done */
1811 case 193: /* mpdu rx done */
1814 len = get16(d); d += 4;
1815 if(d + len + 4 > b->lim)
1817 if((get32(d + len) & 3) != 3)
1819 if(ctlr->wifi == nil)
1821 if(rbplant(ctlr, rx->i) < 0)
1825 wifiiq(ctlr->wifi, b);
1827 case 197: /* rx compressed ba */
1830 /* paranoia: clear the descriptor */
1831 memset(b->rp, 0, Rdscsize);
1833 csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
1837 iwlinterrupt(Ureg*, void *arg)
1846 csr32w(ctlr, Imr, 0);
1847 isr = csr32r(ctlr, Isr);
1848 fhisr = csr32r(ctlr, FhIsr);
1849 if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
1853 if(isr == 0 && fhisr == 0)
1855 csr32w(ctlr, Isr, isr);
1856 csr32w(ctlr, FhIsr, fhisr);
1857 if((isr & (Iswrx | Ifhrx | Irxperiodic)) || (fhisr & Ifhrx))
1860 iprint("#l%d: fatal firmware error\n", edev->ctlrno);
1863 ctlr->wait.m |= isr;
1864 if(ctlr->wait.m & ctlr->wait.w){
1865 ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
1866 ctlr->wait.m &= ~ctlr->wait.r;
1867 wakeup(&ctlr->wait);
1870 csr32w(ctlr, Imr, ctlr->ie);
1874 static Ctlr *iwlhead, *iwltail;
1882 while(pdev = pcimatch(pdev, 0, 0)) {
1886 if(pdev->ccrb != 2 || pdev->ccru != 0x80)
1888 if(pdev->vid != 0x8086)
1894 case 0x4229: /* WiFi Link 4965 */
1895 case 0x4230: /* WiFi Link 4965 */
1896 case 0x4236: /* WiFi Link 5300 AGN */
1897 case 0x4237: /* Wifi Link 5100 AGN */
1901 /* Clear device-specific "PCI retry timeout" register (41h). */
1902 if(pcicfgr8(pdev, 0x41) != 0)
1903 pcicfgw8(pdev, 0x41, 0);
1905 /* Clear interrupt disable bit. Hardware bug workaround. */
1906 if(pdev->pcr & 0x400){
1907 pdev->pcr &= ~0x400;
1908 pcicfgw16(pdev, PciPCR, pdev->pcr);
1914 ctlr = malloc(sizeof(Ctlr));
1916 print("iwl: unable to alloc Ctlr\n");
1919 ctlr->port = pdev->mem[0].bar & ~0x0F;
1920 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
1922 print("iwl: can't map %8.8luX\n", pdev->mem[0].bar);
1928 ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
1930 if(fwname[ctlr->type] == nil){
1931 print("iwl: unsupported controller type %d\n", ctlr->type);
1932 vunmap(mem, pdev->mem[0].size);
1938 iwltail->link = ctlr;
1953 for(ctlr = iwlhead; ctlr != nil; ctlr = ctlr->link){
1956 if(edev->port == 0 || edev->port == ctlr->port){
1966 edev->port = ctlr->port;
1967 edev->irq = ctlr->pdev->intl;
1968 edev->tbdf = ctlr->pdev->tbdf;
1970 edev->interrupt = iwlinterrupt;
1971 edev->attach = iwlattach;
1972 edev->ifstat = iwlifstat;
1974 edev->promiscuous = iwlpromiscuous;
1975 edev->multicast = nil;
1978 if(iwlinit(edev) < 0){
1989 addethercard("iwl", iwlpnp);