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"
39 Cfg = 0x000, /* config register */
48 Isr = 0x008, /* interrupt status */
49 Imr = 0x00c, /* interrupt mask */
62 Ierr = Iswerr | Ihwerr,
63 Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled,
65 FhIsr = 0x010, /* second interrupt status */
69 Rev = 0x028, /* hardware revision */
71 EepromIo = 0x02c, /* EEPROM i/o register */
75 RelativeAccess = 1<<17,
77 EccUncorrStts = 1<<21,
79 Gpc = 0x024, /* gp cntrl */
96 UcodeGp1RfKill = 1<<1,
97 UcodeGp1CmdBlocked = 1<<2,
98 UcodeGp1CtempStopRf = 1<<3,
100 ShadowRegCtrl = 0x0a8,
120 HbusTargWptr = 0x460,
124 * Flow-Handler registers.
127 FhTfbdCtrl0 = 0x1900, // +q*8
128 FhTfbdCtrl1 = 0x1904, // +q*8
132 FhSramAddr = 0x19a4, // +q*4
133 FhCbbcQueue = 0x19d0, // +q*4
134 FhStatusWptr = 0x1bc0,
138 FhRxConfigEna = 1<<31,
139 FhRxConfigRbSize8K = 1<<16,
140 FhRxConfigSingleFrame = 1<<15,
141 FhRxConfigIrqDstHost = 1<<12,
142 FhRxConfigIgnRxfEmpty = 1<<2,
144 FhRxConfigNrbdShift = 20,
145 FhRxConfigRbTimeoutShift= 4,
149 FhTxConfig = 0x1d00, // +q*32
150 FhTxConfigDmaCreditEna = 1<<3,
151 FhTxConfigDmaEna = 1<<31,
152 FhTxConfigCirqHostEndTfd= 1<<20,
154 FhTxBufStatus = 0x1d08, // +q*32
155 FhTxBufStatusTbNumShift = 20,
156 FhTxBufStatusTbIdxShift = 12,
157 FhTxBufStatusTfbdValid = 3,
159 FhTxChicken = 0x1e98,
164 * NIC internal memory offsets.
167 ApmgClkCtrl = 0x3000,
174 EarlyPwroffDis = 1<<22,
180 ApmgDigitalSvr = 0x3058,
181 ApmgAnalogSvr = 0x306c,
184 BsmWrMemSrc = 0x3404,
185 BsmWrMemDst = 0x3408,
186 BsmWrDwCount = 0x340c,
187 BsmDramTextAddr = 0x3490,
188 BsmDramTextSize = 0x3494,
189 BsmDramDataAddr = 0x3498,
190 BsmDramDataSize = 0x349c,
191 BsmSramBase = 0x3800,
195 * TX scheduler registers.
198 SchedBase = 0xa02c00,
199 SchedSramAddr = SchedBase,
200 SchedDramAddr5000 = SchedBase+0x008,
201 SchedDramAddr4965 = SchedBase+0x010,
202 SchedTxFact5000 = SchedBase+0x010,
203 SchedTxFact4965 = SchedBase+0x01c,
204 SchedQueueRdptr4965 = SchedBase+0x064, // +q*4
205 SchedQueueRdptr5000 = SchedBase+0x068, // +q*4
206 SchedQChainSel4965 = SchedBase+0x0d0,
207 SchedIntrMask4965 = SchedBase+0x0e4,
208 SchedQChainSel5000 = SchedBase+0x0e8,
209 SchedQueueStatus4965 = SchedBase+0x104, // +q*4
210 SchedIntrMask5000 = SchedBase+0x108,
211 SchedQueueStatus5000 = SchedBase+0x10c, // +q*4
212 SchedAggrSel5000 = SchedBase+0x248,
216 SchedCtxOff4965 = 0x380,
217 SchedCtxLen4965 = 416,
218 SchedTransTblOff4965 = 0x500,
220 SchedCtxOff5000 = 0x600,
221 SchedCtxLen5000 = 512,
222 SchedTransTblOff5000 = 0x7e0,
225 typedef struct FWInfo FWInfo;
226 typedef struct FWImage FWImage;
227 typedef struct FWSect FWSect;
229 typedef struct TXQ TXQ;
230 typedef struct RXQ RXQ;
232 typedef struct Ctlr Ctlr;
234 typedef struct Ctlrtype Ctlrtype;
339 /* controller types */
357 static Ctlrtype ctlrtype[16] = {
359 .fwname = "iwn-4965",
362 .fwname = "iwn-5000",
365 .fwname = "iwn-5000",
368 .fwname = "iwn-5150",
371 .fwname = "iwn-5000",
374 .fwname = "iwn-1000",
377 .fwname = "iwn-6000",
380 .fwname = "iwn-6050",
383 .fwname = "iwn-6005",
387 #define csr32r(c, r) (*((c)->nic+((r)/4)))
388 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
392 return *((u16int*)p);
396 return *((u32int*)p);
399 put32(uchar *p, uint v){
403 put16(uchar *p, uint v){
412 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
413 for(i=0; i<1000; i++){
414 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
418 return "niclock: timeout";
422 nicunlock(Ctlr *ctlr)
424 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
428 prphread(Ctlr *ctlr, uint off)
430 csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
432 return csr32r(ctlr, PrphRdata);
435 prphwrite(Ctlr *ctlr, uint off, u32int data)
437 csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
439 csr32w(ctlr, PrphWdata, data);
443 memread(Ctlr *ctlr, uint off)
445 csr32w(ctlr, MemRaddr, off);
447 return csr32r(ctlr, MemRdata);
450 memwrite(Ctlr *ctlr, uint off, u32int data)
452 csr32w(ctlr, MemWaddr, off);
454 csr32w(ctlr, MemWdata, data);
458 setfwinfo(Ctlr *ctlr, uchar *d, int len)
471 i->logptr = get32(d); d += 4;
472 i->errptr = get32(d); d += 4;
473 i->tstamp = get32(d); d += 4;
483 if(ctlr->fwinfo.errptr == 0){
484 print("no error pointer\n");
487 for(i=0; i<nelem(dump); i++)
488 dump[i] = memread(ctlr, ctlr->fwinfo.errptr + i*4);
489 print( "error:\tid %ux, pc %ux,\n"
490 "\tbranchlink %.8ux %.8ux, interruptlink %.8ux %.8ux,\n"
491 "\terrordata %.8ux %.8ux, srcline %ud, tsf %ux, time %ux\n",
493 dump[4], dump[3], dump[6], dump[5],
494 dump[7], dump[8], dump[9], dump[10], dump[11]);
498 eepromlock(Ctlr *ctlr)
502 for(i=0; i<100; i++){
503 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | EepromLocked);
504 for(j=0; j<100; j++){
505 if(csr32r(ctlr, Cfg) & EepromLocked)
510 return "eepromlock: timeout";
513 eepromunlock(Ctlr *ctlr)
515 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~EepromLocked);
518 eepromread(Ctlr *ctlr, void *data, int count, uint off)
525 for(; count > 0; count -= 2, off++){
526 csr32w(ctlr, EepromIo, off << 2);
528 w = csr32r(ctlr, EepromIo);
534 return "eepromread: timeout";
547 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
549 if(csr32r(ctlr, Cfg) & NicReady)
553 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
554 for(i=0; i<15000; i++){
555 if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
560 return "handover: timeout";
561 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
563 if(csr32r(ctlr, Cfg) & NicReady)
567 return "handover: timeout";
571 clockwait(Ctlr *ctlr)
575 /* Set "initialization complete" bit. */
576 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
577 for(i=0; i<2500; i++){
578 if(csr32r(ctlr, Gpc) & MacClockReady)
582 return "clockwait: timeout";
591 /* Disable L0s exit timer (NMI bug workaround). */
592 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | DisL0Stimer);
594 /* Don't wait for ICH L0s (ICH bug workaround). */
595 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | L1AnoL0Srx);
597 /* Set FH wait threshold to max (HW bug under stress workaround). */
598 csr32w(ctlr, Dbghpetmem, csr32r(ctlr, Dbghpetmem) | 0xffff0000);
600 /* Enable HAP INTA to move adapter from L1a to L0s. */
601 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | HapwakeL1A);
603 capoff = pcicap(ctlr->pdev, PciCapPCIe);
605 /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
606 if(pcicfgr16(ctlr->pdev, capoff + 0x10) & 0x2) /* LCSR -> L1 Entry enabled. */
607 csr32w(ctlr, Gio, csr32r(ctlr, Gio) | EnaL0S);
609 csr32w(ctlr, Gio, csr32r(ctlr, Gio) & ~EnaL0S);
612 if(ctlr->type != Type4965 && ctlr->type <= Type1000)
613 csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | 0x00880300);
615 /* Wait for clock stabilization before accessing prph. */
616 if((err = clockwait(ctlr)) != nil)
619 if((err = niclock(ctlr)) != nil)
622 /* Enable DMA and BSM (Bootstrap State Machine). */
623 if(ctlr->type == Type4965)
624 prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
626 prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
629 /* Disable L1-Active. */
630 prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
645 if((err = handover(ctlr)) != nil)
647 if((err = poweron(ctlr)) != nil)
649 if((csr32r(ctlr, EepromGp) & 0x7) == 0){
650 err = "bad rom signature";
653 if((err = eepromlock(ctlr)) != nil)
655 if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
659 if(ctlr->type != Type4965){
660 if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
665 ctlr->rfcfg.type = u & 3; u >>= 2;
666 ctlr->rfcfg.step = u & 3; u >>= 2;
667 ctlr->rfcfg.dash = u & 3; u >>= 4;
668 ctlr->rfcfg.txantmask = u & 15; u >>= 4;
669 ctlr->rfcfg.rxantmask = u & 15;
670 if((err = eepromread(ctlr, b, 4, 0x128)) != nil){
674 ctlr->eeprom.crystal = get32(b);
680 ctlr->rfcfg.txantmask = 3;
681 ctlr->rfcfg.rxantmask = 7;
684 ctlr->rfcfg.txantmask = 2;
685 ctlr->rfcfg.rxantmask = 3;
688 if(ctlr->pdev->did == 0x422c || ctlr->pdev->did == 0x4230){
689 ctlr->rfcfg.txantmask = 6;
690 ctlr->rfcfg.rxantmask = 6;
696 csr32w(ctlr, Isr, ~0); /* clear pending interrupts */
697 csr32w(ctlr, Imr, 0); /* no interrupts for now */
701 print("iwlinit: %s\n", err);
706 crackfw(FWImage *i, uchar *data, uint size, int alt)
711 memset(i, 0, sizeof(*i));
714 return "firmware image too short";
718 i->rev = get32(p); p += 4;
722 if(size < (4+64+4+4+8))
724 if(memcmp(p, "IWL\n", 4) != 0)
725 return "bad firmware signature";
727 strncpy(i->descr, (char*)p, 64);
728 i->descr[sizeof(i->descr)-1] = 0;
730 i->rev = get32(p); p += 4;
731 i->build = get32(p); p += 4;
732 altmask = get32(p); p += 4;
733 altmask |= (uvlong)get32(p) << 32; p += 4;
734 while(alt > 0 && (altmask & (1ULL<<alt)) == 0)
742 case 1: s = &i->main.text; break;
743 case 2: s = &i->main.data; break;
744 case 3: s = &i->init.text; break;
745 case 4: s = &i->init.data; break;
746 case 5: s = &i->boot.text; break;
753 s->size = get32(p); p += 4;
755 if((p + s->size) > e)
757 p += (s->size + 3) & ~3;
760 if(((i->rev>>8) & 0xFF) < 2)
761 return "need firmware api >= 2";
762 if(((i->rev>>8) & 0xFF) >= 3){
763 i->build = get32(p); p += 4;
767 i->main.text.size = get32(p); p += 4;
768 i->main.data.size = get32(p); p += 4;
769 i->init.text.size = get32(p); p += 4;
770 i->init.data.size = get32(p); p += 4;
771 i->boot.text.size = get32(p); p += 4;
772 i->main.text.data = p; p += i->main.text.size;
773 i->main.data.data = p; p += i->main.data.size;
774 i->init.text.data = p; p += i->init.text.size;
775 i->init.data.data = p; p += i->init.data.size;
776 i->boot.text.data = p; p += i->boot.text.size;
784 readfirmware(char *name)
786 uchar dirbuf[sizeof(Dir)+100], *data;
796 snprint(buf, sizeof buf, "/boot/%s", name);
797 c = namec(buf, Aopen, OREAD, 0);
800 snprint(buf, sizeof buf, "/lib/firmware/%s", name);
801 c = namec(buf, Aopen, OREAD, 0);
807 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
809 error("can't stat firmware");
810 convM2D(dirbuf, n, &d, nil);
811 fw = smalloc(sizeof(*fw) + 16 + d.length);
812 data = (uchar*)(fw+1);
819 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
824 if((err = crackfw(fw, data, r, 1)) != nil)
832 typedef struct Irqwait Irqwait;
846 ctlr->wait.r = ctlr->wait.m & w->mask;
848 ctlr->wait.m &= ~ctlr->wait.r;
851 ctlr->wait.w = w->mask;
856 irqwait(Ctlr *ctlr, u32int mask, int timeout)
862 tsleep(&ctlr->wait, gotirq, &w, timeout);
864 return ctlr->wait.r & mask;
868 loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
873 dma = mallocalign(size, 16, 0, 0);
875 return "no memory for dma";
876 memmove(dma, data, size);
878 if((err = niclock(ctlr)) != 0){
882 csr32w(ctlr, FhTxConfig + 9*32, 0);
883 csr32w(ctlr, FhSramAddr + 9*4, dst);
884 csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
885 csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
886 csr32w(ctlr, FhTxBufStatus + 9*32,
887 (1<<FhTxBufStatusTbNumShift) |
888 (1<<FhTxBufStatusTbIdxShift) |
889 FhTxBufStatusTfbdValid);
890 csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
892 if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
894 return "dma error / timeout";
901 bootfirmware(Ctlr *ctlr)
911 if(fw->boot.text.size == 0){
912 if((err = loadfirmware1(ctlr, 0x00000000, fw->main.text.data, fw->main.text.size)) != nil)
914 if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
919 size = ROUND(fw->init.data.size, 16) + ROUND(fw->init.text.size, 16);
920 dma = mallocalign(size, 16, 0, 0);
922 return "no memory for dma";
924 if((err = niclock(ctlr)) != nil){
930 memmove(p, fw->init.data.data, fw->init.data.size);
932 prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
933 prphwrite(ctlr, BsmDramDataSize, fw->init.data.size);
934 p += ROUND(fw->init.data.size, 16);
935 memmove(p, fw->init.text.data, fw->init.text.size);
937 prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
938 prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
940 p = fw->boot.text.data;
941 n = fw->boot.text.size/4;
942 for(i=0; i<n; i++, p += 4)
943 prphwrite(ctlr, BsmSramBase+i*4, get32(p));
945 prphwrite(ctlr, BsmWrMemSrc, 0);
946 prphwrite(ctlr, BsmWrMemDst, 0);
947 prphwrite(ctlr, BsmWrDwCount, n);
949 prphwrite(ctlr, BsmWrCtrl, 1<<31);
951 for(i=0; i<1000; i++){
952 if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
959 return "bootfirmware: bootcode timeout";
962 prphwrite(ctlr, BsmWrCtrl, 1<<30);
965 csr32w(ctlr, Reset, 0);
966 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
968 return "init firmware boot failed";
972 size = ROUND(fw->main.data.size, 16) + ROUND(fw->main.text.size, 16);
973 dma = mallocalign(size, 16, 0, 0);
975 return "no memory for dma";
976 if((err = niclock(ctlr)) != nil){
981 memmove(p, fw->main.data.data, fw->main.data.size);
983 prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
984 prphwrite(ctlr, BsmDramDataSize, fw->main.data.size);
985 p += ROUND(fw->main.data.size, 16);
986 memmove(p, fw->main.text.data, fw->main.text.size);
988 prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
989 prphwrite(ctlr, BsmDramTextSize, fw->main.text.size | (1<<31));
993 csr32w(ctlr, Reset, 0);
994 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
996 return "main firmware boot failed";
1010 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
1015 assert(qid < nelem(ctlr->tx));
1016 assert(size <= Tcmdsize-4);
1027 tsleep(q, txqready, q, 10);
1034 c = q->c + q->i * Tcmdsize;
1035 d = q->d + q->i * Tdscsize;
1039 c[1] = 0; /* flags */
1043 memmove(c+4, data, size);
1047 /* build descriptor */
1051 *d++ = 1 + (block != nil); /* nsegs */
1052 put32(d, PCIWADDR(c)); d += 4;
1053 put16(d, size << 4); d += 2;
1058 put32(d, PCIWADDR(block->rp)); d += 4;
1059 put16(d, size << 4);
1064 q->i = (q->i+1) % Ntx;
1065 csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
1071 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
1073 qcmd(ctlr, 4, code, data, size, nil);
1077 setled(Ctlr *ctlr, int which, int on, int off)
1081 csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
1083 memset(c, 0, sizeof(c));
1088 cmd(ctlr, 72, c, sizeof(c));
1092 * initialization which runs after the firmware has been booted up
1095 postboot(Ctlr *ctlr)
1097 uint ctxoff, ctxlen, dramaddr, txfact;
1102 /* main led turn on! (verify that firmware processes commands) */
1103 setled(ctlr, 2, 0, 1);
1105 if((err = niclock(ctlr)) != nil)
1108 if(ctlr->type != Type4965){
1109 dramaddr = SchedDramAddr5000;
1110 ctxoff = SchedCtxOff5000;
1111 ctxlen = SchedCtxLen5000;
1112 txfact = SchedTxFact5000;
1114 dramaddr = SchedDramAddr4965;
1115 ctxoff = SchedCtxOff4965;
1116 ctxlen = SchedCtxLen4965;
1117 txfact = SchedTxFact4965;
1120 ctlr->sched.base = prphread(ctlr, SchedSramAddr);
1121 for(i=0; i < ctxlen/4; i++)
1122 memwrite(ctlr, ctlr->sched.base + ctxoff + i*4, 0);
1124 prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
1126 csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
1128 if(ctlr->type != Type4965){
1129 /* Enable chain mode for all queues, except command queue 4. */
1130 prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
1131 prphwrite(ctlr, SchedAggrSel5000, 0);
1133 for(q=0; q<nelem(ctlr->tx); q++){
1134 prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
1135 csr32w(ctlr, HbusTargWptr, q << 8);
1137 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 0);
1138 /* Set scheduler window size and frame limit. */
1139 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16 | 64);
1141 /* Enable interrupts for all our 20 queues. */
1142 prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
1144 /* Disable chain mode for all our 16 queues. */
1145 prphwrite(ctlr, SchedQChainSel4965, 0);
1147 for(q=0; q<16; q++) {
1148 prphwrite(ctlr, SchedQueueRdptr4965 + q*4, 0);
1149 csr32w(ctlr, HbusTargWptr, q << 8);
1151 /* Set scheduler window size. */
1152 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 64);
1153 /* Set scheduler window size and frame limit. */
1154 memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16);
1156 /* Enable interrupts for all our 16 queues. */
1157 prphwrite(ctlr, SchedIntrMask4965, 0xffff);
1160 /* Identify TX FIFO rings (0-7). */
1161 prphwrite(ctlr, txfact, 0xff);
1163 /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
1165 static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
1166 if(ctlr->type != Type4965)
1167 prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
1169 prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]);
1173 if(ctlr->type != Type5150){
1174 memset(c, 0, sizeof(c));
1175 c[0] = 15; /* code */
1176 c[1] = 0; /* grup */
1177 c[2] = 1; /* ngroup */
1178 c[3] = 1; /* isvalid */
1179 put16(c+4, ctlr->eeprom.crystal);
1180 cmd(ctlr, 176, c, 8);
1183 if(ctlr->type != Type4965){
1184 put32(c, ctlr->rfcfg.txantmask & 7);
1185 cmd(ctlr, 152, c, 4);
1190 addnode(Ctlr *ctlr, uchar id, uchar *addr)
1192 uchar c[Tcmdsize], *p;
1194 memset(p = c, 0, sizeof(c));
1195 *p++ = 0; /* control (1 = update) */
1196 p += 3; /* reserved */
1197 memmove(p, addr, 6);
1199 p += 2; /* reserved */
1200 *p++ = id; /* node id */
1202 p += 2; /* reserved */
1203 p += 2; /* kflags */
1206 p += 5*2; /* ttak */
1210 if(ctlr->type != Type4965){
1214 p += 4; /* htflags */
1216 p += 2; /* disable tid */
1217 p += 2; /* reserved */
1218 p++; /* add ba tid */
1219 p++; /* del ba tid */
1220 p += 2; /* add ba ssn */
1221 p += 4; /* reserved */
1223 cmd(ctlr, 24, c, p - c);
1227 rxon(Ether *edev, Wnode *bss)
1229 uchar c[Tcmdsize], *p;
1233 memset(p = c, 0, sizeof(c));
1234 memmove(p, edev->ea, 6); p += 8; /* myaddr */
1235 memmove(p, (bss != nil) ? bss->bssid : edev->bcast, 6);
1237 memmove(p, edev->ea, 6); p += 8; /* wlap */
1238 *p++ = 3; /* mode (STA) */
1239 *p++ = 0; /* air (?) */
1241 put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
1243 *p++ = 0xff; /* ofdm mask (not yet negotiated) */
1244 *p++ = 0x0f; /* cck mask (not yet negotiated) */
1246 put16(p, bss->aid & ~0xc000);
1248 put32(p, (1<<15)|(1<<30)|(1<<0)); /* flags (TSF | CTS_TO_SELF | 24GHZ) */
1250 put32(p, 8|4|1); /* filter (NODECRYPT|MULTICAST|PROMISC) */
1252 *p++ = bss != nil ? bss->channel : ctlr->channel;
1254 *p++ = 0xff; /* ht single mask */
1255 *p++ = 0xff; /* ht dual mask */
1256 if(ctlr->type != Type4965){
1257 *p++ = 0xff; /* ht triple mask */
1259 put16(p, 0); p += 2; /* acquisition */
1260 p += 2; /* reserved */
1262 cmd(ctlr, 16, c, p - c);
1264 addnode(ctlr, (ctlr->type != Type4965) ? 15 : 31, edev->bcast);
1266 addnode(ctlr, 0, bss->bssid);
1269 static struct ratetab {
1290 transmit(Wifi *wifi, Wnode *, Block *b)
1292 uchar c[Tcmdsize], *p;
1295 ctlr = wifi->ether->ctlr;
1297 memset(p = c, 0, sizeof(c));
1301 put32(p, 0); /* flags */
1304 p += 4; /* scratch */
1306 /* BUG: hardcode 11Mbit */
1307 *p++ = ratetab[2].plcp; /* plcp */
1308 *p++ = ratetab[2].flags | (1<<6); /* rflags */
1310 p += 2; /* xflags */
1312 /* BUG: we always use broadcast node! */
1313 *p++ = (ctlr->type != Type4965) ? 15 : 31;
1315 *p++ = 0; /* security */
1316 *p++ = 0; /* linkq */
1320 p += 2; /* reserved */
1321 put32(p, ~0); /* lifetime */
1324 /* BUG: scratch ptr? not clear what this is for */
1325 put32(p, PCIWADDR(ctlr->kwpage));
1328 *p++ = 60; /* rts ntries */
1329 *p++ = 15; /* data ntries */
1331 put16(p, 0); /* timeout */
1334 qcmd(ctlr, 0, 28, c, p - c, b);
1338 rbplant(Ctlr *ctlr, int i)
1342 b = iallocb(Rbufsize + 256);
1345 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
1346 memset(b->rp, 0, Rdscsize);
1348 ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
1353 iwlctl(Ether *edev, void *buf, long n)
1359 return wifictl(ctlr->wifi, buf, n);
1364 iwlifstat(Ether *edev, void *buf, long n, ulong off)
1370 return wifistat(ctlr->wifi, buf, n, off);
1375 setoptions(Ether *edev)
1383 for(i = 0; i < edev->nopt; i++){
1384 if(strncmp(edev->opt[i], "channel=", 8) == 0)
1385 ctlr->channel = atoi(edev->opt[i]+8);
1387 if(strncmp(edev->opt[i], "essid=", 6) == 0){
1388 snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
1390 wifictl(ctlr->wifi, buf, strlen(buf));
1398 iwlattach(Ether *edev)
1413 if(ctlr->attached == 0){
1414 if((csr32r(ctlr, Gpc) & RfKill) == 0){
1415 print("#l%d: wifi disabled by switch\n", edev->ctlrno);
1416 error("wifi disabled by switch");
1419 if(ctlr->wifi == nil)
1420 ctlr->wifi = wifiattach(edev, transmit);
1422 if(ctlr->fw == nil){
1423 fw = readfirmware(ctlrtype[ctlr->type].fwname);
1424 print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
1426 ctlrtype[ctlr->type].fwname,
1428 fw->main.text.size, fw->main.data.size,
1429 fw->init.text.size, fw->init.data.size,
1430 fw->boot.text.size);
1437 rx->b = malloc(sizeof(Block*) * Nrx);
1439 rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
1441 rx->s = mallocalign(Rstatsize, 16, 0, 0);
1442 if(rx->b == nil || rx->p == nil || rx->s == nil)
1443 error("no memory for rx ring");
1444 memset(rx->s, 0, Rstatsize);
1445 for(i=0; i<Nrx; i++){
1447 if(rx->b[i] != nil){
1451 if(rbplant(ctlr, i) < 0)
1452 error("no memory for rx descriptors");
1455 for(q=0; q<nelem(ctlr->tx); q++){
1460 tx->b = malloc(sizeof(Block*) * Ntx);
1462 tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
1464 tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
1465 if(tx->b == nil || tx->d == nil || tx->c == nil)
1466 error("no memory for tx ring");
1467 memset(tx->d, 0, Tdscsize * Ntx);
1470 if(ctlr->sched.s == nil)
1471 ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
1472 if(ctlr->kwpage == nil)
1473 ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
1475 if((err = niclock(ctlr)) != nil)
1477 prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
1480 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
1482 if((err = niclock(ctlr)) != nil)
1484 prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
1487 if((err = niclock(ctlr)) != nil)
1489 csr32w(ctlr, FhRxConfig, 0);
1490 csr32w(ctlr, FhRxWptr, 0);
1491 csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
1492 csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
1493 csr32w(ctlr, FhRxConfig,
1495 FhRxConfigIgnRxfEmpty |
1496 FhRxConfigIrqDstHost |
1497 FhRxConfigSingleFrame |
1498 (Nrxlog << FhRxConfigNrbdShift));
1499 csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
1502 if((err = niclock(ctlr)) != nil)
1505 prphwrite(ctlr, SchedTxFact5000, 0);
1507 csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
1509 for(q=0; q<nelem(ctlr->tx); q++)
1510 if(q < 15 || ctlr->type != Type4965)
1511 csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
1515 if(i < 7 || ctlr->type != Type4965)
1516 csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
1518 csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1519 csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
1521 ctlr->ie = Idefmask;
1522 csr32w(ctlr, Imr, ctlr->ie);
1523 csr32w(ctlr, Isr, ~0);
1525 if(ctlr->type >= Type6000)
1526 csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
1553 if(rx->s == nil || rx->b == nil)
1555 for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
1556 uchar type, flags, idx, qid;
1564 len = get32(d); d += 4;
1571 if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
1572 tx = &ctlr->tx[qid];
1579 /* paranoia: clear tx descriptors */
1580 dd = tx->d + idx*Tdscsize;
1581 cc = tx->c + idx*Tcmdsize;
1582 memset(dd, 0, Tdscsize);
1583 memset(cc, 0, Tcmdsize);
1591 if(len < 4 || type == 0)
1596 case 1: /* microcontroller ready */
1597 setfwinfo(ctlr, d, len);
1599 case 24: /* add node done */
1601 case 28: /* tx done */
1603 case 102: /* calibration result (Type5000 only) */
1605 case 103: /* calibration done (Type5000 only) */
1607 case 130: /* start scan */
1609 case 132: /* stop scan */
1611 case 156: /* rx statistics */
1613 case 157: /* beacon statistics */
1615 case 161: /* state changed */
1617 case 162: /* beacon missed */
1619 case 192: /* rx phy */
1621 case 195: /* rx done */
1625 case 193: /* mpdu rx done */
1628 len = get16(d); d += 4;
1629 if(d + len + 4 > b->lim)
1631 if((get32(d + len) & 3) != 3)
1633 if(ctlr->wifi == nil)
1635 if(rbplant(ctlr, rx->i) < 0)
1639 wifiiq(ctlr->wifi, b);
1641 case 197: /* rx compressed ba */
1644 /* paranoia: clear the descriptor */
1645 memset(b->rp, 0, Rdscsize);
1647 csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
1651 iwlinterrupt(Ureg*, void *arg)
1660 csr32w(ctlr, Imr, 0);
1661 isr = csr32r(ctlr, Isr);
1662 fhisr = csr32r(ctlr, FhIsr);
1663 if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
1667 if(isr == 0 && fhisr == 0)
1669 csr32w(ctlr, Isr, isr);
1670 csr32w(ctlr, FhIsr, fhisr);
1671 if((isr & (Iswrx | Ifhrx | Irxperiodic)) || (fhisr & Ifhrx))
1674 iprint("#l%d: fatal firmware error\n", edev->ctlrno);
1677 ctlr->wait.m |= isr;
1678 if(ctlr->wait.m & ctlr->wait.w){
1679 ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
1680 ctlr->wait.m &= ~ctlr->wait.r;
1681 wakeup(&ctlr->wait);
1684 csr32w(ctlr, Imr, ctlr->ie);
1688 static Ctlr *iwlhead, *iwltail;
1696 while(pdev = pcimatch(pdev, 0, 0)) {
1700 if(pdev->ccrb != 2 || pdev->ccru != 0x80)
1702 if(pdev->vid != 0x8086)
1708 case 0x4236: /* WiFi Link 5300 AGN */
1709 case 0x4237: /* Wifi Link 5200 AGN */
1713 /* Clear device-specific "PCI retry timeout" register (41h). */
1714 if(pcicfgr8(pdev, 0x41) != 0)
1715 pcicfgw8(pdev, 0x41, 0);
1717 /* Clear interrupt disable bit. Hardware bug workaround. */
1718 if(pdev->pcr & 0x400){
1719 pdev->pcr &= ~0x400;
1720 pcicfgw16(pdev, PciPCR, pdev->pcr);
1726 ctlr = malloc(sizeof(Ctlr));
1728 print("iwl: unable to alloc Ctlr\n");
1731 ctlr->port = pdev->mem[0].bar & ~0x0F;
1732 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
1734 print("iwl: can't map %8.8luX\n", pdev->mem[0].bar);
1740 ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
1742 if(ctlrtype[ctlr->type].fwname == nil){
1743 print("iwl: unsupported controller type %d\n", ctlr->type);
1744 vunmap(mem, pdev->mem[0].size);
1750 iwltail->link = ctlr;
1765 for(ctlr = iwlhead; ctlr != nil; ctlr = ctlr->link){
1768 if(edev->port == 0 || edev->port == ctlr->port){
1778 edev->port = ctlr->port;
1779 edev->irq = ctlr->pdev->intl;
1780 edev->tbdf = ctlr->pdev->tbdf;
1782 edev->interrupt = iwlinterrupt;
1783 edev->attach = iwlattach;
1784 edev->ifstat = iwlifstat;
1786 edev->promiscuous = nil;
1787 edev->multicast = nil;
1790 if(iwlinit(edev) < 0){
1801 addethercard("iwl", iwlpnp);