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 /* controller types */
238 typedef struct FWInfo FWInfo;
239 typedef struct FWImage FWImage;
240 typedef struct FWSect FWSect;
242 typedef struct TXQ TXQ;
243 typedef struct RXQ RXQ;
245 typedef struct Ctlr Ctlr;
350 #define csr32r(c, r) (*((c)->nic+((r)/4)))
351 #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
355 return *((u16int*)p);
359 return *((u32int*)p);
362 put32(uchar *p, uint v){
366 put16(uchar *p, uint v){
375 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
376 for(i=0; i<1000; i++){
377 if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
381 return "niclock: timeout";
385 nicunlock(Ctlr *ctlr)
387 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);
391 prphread(Ctlr *ctlr, uint off)
393 csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off);
395 return csr32r(ctlr, PrphRdata);
398 prphwrite(Ctlr *ctlr, uint off, u32int data)
400 csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off);
402 csr32w(ctlr, PrphWdata, data);
406 memread(Ctlr *ctlr, uint off)
408 csr32w(ctlr, MemRaddr, off);
410 return csr32r(ctlr, MemRdata);
413 memwrite(Ctlr *ctlr, uint off, u32int data)
415 csr32w(ctlr, MemWaddr, off);
417 csr32w(ctlr, MemWdata, data);
421 setfwinfo(Ctlr *ctlr, uchar *d, int len)
434 i->logptr = get32(d); d += 4;
435 i->errptr = get32(d); d += 4;
436 i->tstamp = get32(d); d += 4;
446 if(ctlr->fwinfo.errptr == 0){
447 print("no error pointer\n");
450 for(i=0; i<nelem(dump); i++)
451 dump[i] = memread(ctlr, ctlr->fwinfo.errptr + i*4);
452 print( "error:\tid %ux, pc %ux,\n"
453 "\tbranchlink %.8ux %.8ux, interruptlink %.8ux %.8ux,\n"
454 "\terrordata %.8ux %.8ux, srcline %ud, tsf %ux, time %ux\n",
456 dump[4], dump[3], dump[6], dump[5],
457 dump[7], dump[8], dump[9], dump[10], dump[11]);
461 eepromlock(Ctlr *ctlr)
465 for(i=0; i<100; i++){
466 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | EepromLocked);
467 for(j=0; j<100; j++){
468 if(csr32r(ctlr, Cfg) & EepromLocked)
473 return "eepromlock: timeout";
476 eepromunlock(Ctlr *ctlr)
478 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) & ~EepromLocked);
481 eepromread(Ctlr *ctlr, void *data, int count, uint off)
488 for(; count > 0; count -= 2, off++){
489 csr32w(ctlr, EepromIo, off << 2);
491 w = csr32r(ctlr, EepromIo);
497 return "eepromread: timeout";
510 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
512 if(csr32r(ctlr, Cfg) & NicReady)
516 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
517 for(i=0; i<15000; i++){
518 if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
523 return "handover: timeout";
524 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
526 if(csr32r(ctlr, Cfg) & NicReady)
530 return "handover: timeout";
534 clockwait(Ctlr *ctlr)
538 /* Set "initialization complete" bit. */
539 csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone);
540 for(i=0; i<2500; i++){
541 if(csr32r(ctlr, Gpc) & MacClockReady)
545 return "clockwait: timeout";
554 /* Disable L0s exit timer (NMI bug workaround). */
555 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | DisL0Stimer);
557 /* Don't wait for ICH L0s (ICH bug workaround). */
558 csr32w(ctlr, Giochicken, csr32r(ctlr, Giochicken) | L1AnoL0Srx);
560 /* Set FH wait threshold to max (HW bug under stress workaround). */
561 csr32w(ctlr, Dbghpetmem, csr32r(ctlr, Dbghpetmem) | 0xffff0000);
563 /* Enable HAP INTA to move adapter from L1a to L0s. */
564 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | HapwakeL1A);
566 capoff = pcicap(ctlr->pdev, PciCapPCIe);
568 /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
569 if(pcicfgr16(ctlr->pdev, capoff + 0x10) & 0x2) /* LCSR -> L1 Entry enabled. */
570 csr32w(ctlr, Gio, csr32r(ctlr, Gio) | EnaL0S);
572 csr32w(ctlr, Gio, csr32r(ctlr, Gio) & ~EnaL0S);
575 if(ctlr->type != Type4965 && ctlr->type <= Type1000)
576 csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | 0x00880300);
578 /* Wait for clock stabilization before accessing prph. */
579 if((err = clockwait(ctlr)) != nil)
582 if((err = niclock(ctlr)) != nil)
585 /* Enable DMA and BSM (Bootstrap State Machine). */
586 if(ctlr->type == Type4965)
587 prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
589 prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
592 /* Disable L1-Active. */
593 prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
608 if((err = handover(ctlr)) != nil)
610 if((err = poweron(ctlr)) != nil)
612 if((csr32r(ctlr, EepromGp) & 0x7) == 0){
613 err = "bad rom signature";
616 if((err = eepromlock(ctlr)) != nil)
618 if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
622 if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
627 ctlr->rfcfg.type = u & 3; u >>= 2;
628 ctlr->rfcfg.step = u & 3; u >>= 2;
629 ctlr->rfcfg.dash = u & 3; u >>= 4;
630 ctlr->rfcfg.txantmask = u & 15; u >>= 4;
631 ctlr->rfcfg.rxantmask = u & 15;
632 if((err = eepromread(ctlr, b, 4, 0x128)) != nil){
636 ctlr->eeprom.crystal = get32(b);
640 csr32w(ctlr, Isr, ~0); /* clear pending interrupts */
641 csr32w(ctlr, Imr, 0); /* no interrupts for now */
645 print("iwlinit: %s\n", err);
650 crackfw(FWImage *i, uchar *data, uint size, int alt)
655 memset(i, 0, sizeof(*i));
658 return "firmware image too short";
662 i->rev = get32(p); p += 4;
666 if(size < (4+64+4+4+8))
668 if(memcmp(p, "IWL\n", 4) != 0)
669 return "bad firmware signature";
671 strncpy(i->descr, (char*)p, 64);
672 i->descr[sizeof(i->descr)-1] = 0;
674 i->rev = get32(p); p += 4;
675 i->build = get32(p); p += 4;
676 altmask = get32(p); p += 4;
677 altmask |= (uvlong)get32(p) << 32; p += 4;
678 while(alt > 0 && (altmask & (1ULL<<alt)) == 0)
686 case 1: s = &i->main.text; break;
687 case 2: s = &i->main.data; break;
688 case 3: s = &i->init.text; break;
689 case 4: s = &i->init.data; break;
690 case 5: s = &i->boot.text; break;
697 s->size = get32(p); p += 4;
699 if((p + s->size) > e)
701 p += (s->size + 3) & ~3;
704 if(((i->rev>>8) & 0xFF) < 2)
705 return "need firmware api >= 2";
706 if(((i->rev>>8) & 0xFF) >= 3){
707 i->build = get32(p); p += 4;
711 i->main.text.size = get32(p); p += 4;
712 i->main.data.size = get32(p); p += 4;
713 i->init.text.size = get32(p); p += 4;
714 i->init.data.size = get32(p); p += 4;
715 i->boot.text.size = get32(p); p += 4;
716 i->main.text.data = p; p += i->main.text.size;
717 i->main.data.data = p; p += i->main.data.size;
718 i->init.text.data = p; p += i->init.text.size;
719 i->init.data.data = p; p += i->init.data.size;
720 i->boot.text.data = p; p += i->boot.text.size;
728 readfirmware(char *name)
730 uchar dirbuf[sizeof(Dir)+100], *data;
740 snprint(buf, sizeof buf, "/boot/%s", name);
741 c = namec(buf, Aopen, OREAD, 0);
744 snprint(buf, sizeof buf, "/lib/firmware/%s", name);
745 c = namec(buf, Aopen, OREAD, 0);
751 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
753 error("can't stat firmware");
754 convM2D(dirbuf, n, &d, nil);
755 fw = smalloc(sizeof(*fw) + 16 + d.length);
756 data = (uchar*)(fw+1);
763 n = devtab[c->type]->read(c, data+r, d.length-r, (vlong)r);
768 if((err = crackfw(fw, data, r, 1)) != nil)
776 typedef struct Irqwait Irqwait;
790 ctlr->wait.r = ctlr->wait.m & w->mask;
792 ctlr->wait.m &= ~ctlr->wait.r;
795 ctlr->wait.w = w->mask;
800 irqwait(Ctlr *ctlr, u32int mask, int timeout)
806 tsleep(&ctlr->wait, gotirq, &w, timeout);
808 return ctlr->wait.r & mask;
812 loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
817 dma = mallocalign(size, 16, 0, 0);
819 return "no memory for dma";
820 memmove(dma, data, size);
822 if((err = niclock(ctlr)) != 0){
826 csr32w(ctlr, FhTxConfig + 9*32, 0);
827 csr32w(ctlr, FhSramAddr + 9*4, dst);
828 csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
829 csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
830 csr32w(ctlr, FhTxBufStatus + 9*32,
831 (1<<FhTxBufStatusTbNumShift) |
832 (1<<FhTxBufStatusTbIdxShift) |
833 FhTxBufStatusTfbdValid);
834 csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
836 if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
838 return "dma error / timeout";
852 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
857 assert(qid < nelem(ctlr->tx));
858 assert(size <= Tcmdsize-4);
869 tsleep(q, txqready, q, 10);
876 c = q->c + q->i * Tcmdsize;
877 d = q->d + q->i * Tdscsize;
881 c[1] = 0; /* flags */
885 memmove(c+4, data, size);
889 /* build descriptor */
893 *d++ = 1 + (block != nil); /* nsegs */
894 put32(d, PCIWADDR(c)); d += 4;
895 put16(d, size << 4); d += 2;
900 put32(d, PCIWADDR(block->rp)); d += 4;
906 q->i = (q->i+1) % Ntx;
907 csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
913 cmd(Ctlr *ctlr, uint code, uchar *data, int size)
915 qcmd(ctlr, 4, code, data, size, nil);
919 setled(Ctlr *ctlr, int which, int on, int off)
923 csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
925 memset(c, 0, sizeof(c));
930 cmd(ctlr, 72, c, sizeof(c));
934 * initialization which runs after the firmware has been booted up
943 /* main led turn on! (verify that firmware processes commands) */
944 setled(ctlr, 2, 0, 1);
946 if((err = niclock(ctlr)) != nil)
948 ctlr->sched.base = prphread(ctlr, SchedSramAddr);
949 for(i=0; i < SchedCtxLen5000/4; i++)
950 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + i*4, 0);
952 prphwrite(ctlr, SchedDramAddr5000, PCIWADDR(ctlr->sched.s)>>10);
953 csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
955 /* Enable chain mode for all queues, except command queue. */
956 prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
957 prphwrite(ctlr, SchedAggrSel5000, 0);
959 for(q=0; q<nelem(ctlr->tx); q++){
960 prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
961 csr32w(ctlr, HbusTargWptr, q << 8);
962 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8, 0);
963 /* Set scheduler window size and frame limit. */
964 memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8 + 4, 64<<16 | 64);
967 /* Enable interrupts for all our 20 queues. */
968 prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
969 /* Identify TX FIFO rings (0-7). */
970 prphwrite(ctlr, SchedTxFact5000, 0xff);
971 /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
973 static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
974 prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
978 if(ctlr->type != Type5150){
979 memset(c, 0, sizeof(c));
980 c[0] = 15; /* code */
982 c[2] = 1; /* ngroup */
983 c[3] = 1; /* isvalid */
984 put16(c+4, ctlr->eeprom.crystal);
985 cmd(ctlr, 176, c, 8);
988 if(ctlr->type != Type4965){
989 put32(c, ctlr->rfcfg.txantmask & 7);
990 cmd(ctlr, 152, c, 4);
995 addnode(Ctlr *ctlr, uchar id, uchar *addr)
997 uchar c[Tcmdsize], *p;
999 memset(p = c, 0, sizeof(c));
1000 *p++ = 0; /* control (1 = update) */
1001 p += 3; /* reserved */
1002 memmove(p, addr, 6);
1004 p += 2; /* reserved */
1005 *p++ = id; /* node id */
1007 p += 2; /* reserved */
1008 p += 2; /* kflags */
1011 p += 5*2; /* ttak */
1015 if(ctlr->type != Type4965){
1019 p += 4; /* htflags */
1021 p += 2; /* disable tid */
1022 p += 2; /* reserved */
1023 p++; /* add ba tid */
1024 p++; /* del ba tid */
1025 p += 2; /* add ba ssn */
1026 p += 4; /* reserved */
1028 cmd(ctlr, 24, c, p - c);
1034 uchar c[Tcmdsize], *p;
1038 memset(p = c, 0, sizeof(c));
1039 memmove(p, edev->ea, 6); p += 8; /* myaddr */
1041 memmove(p, edev->ea, 6); p += 8; /* wlap */
1042 *p++ = 3; /* mode */
1043 *p++ = 0; /* air (?) */
1045 put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
1047 *p++ = 0xff; /* ofdm mask (not yet negotiated) */
1048 *p++ = 0x0f; /* cck mask (not yet negotiated) */
1049 p += 2; /* associd (?) */
1050 put32(p, (1<<15)|(1<<30)|(1<<0)); /* flags (TSF | CTS_TO_SELF | 24GHZ) */
1052 put32(p, 4|1); /* filter (MULTICAST|PROMISC) */
1054 *p++ = ctlr->channel; /* chan */
1056 *p++ = 0xff; /* ht single mask */
1057 *p++ = 0xff; /* ht dual mask */
1058 if(ctlr->type != Type4965){
1059 *p++ = 0xff; /* ht triple mask */
1061 put16(p, 0); p += 2; /* acquisition */
1062 p += 2; /* reserved */
1064 cmd(ctlr, 16, c, p - c);
1067 static struct ratetab {
1088 transmit(Wifi *wifi, Wnode *, Block *b)
1090 uchar c[Tcmdsize], *p;
1093 ctlr = wifi->ether->ctlr;
1095 memset(p = c, 0, sizeof(c));
1099 put32(p, 0); /* flags */
1102 p += 4; /* scratch */
1103 *p++ = ratetab[2].plcp; /* plcp */
1104 *p++ = ratetab[2].flags | (1<<6); /* rflags */
1105 p += 2; /* xflags */
1106 *p++ = 15; /* id (5000 only) */
1107 *p++ = 0; /* security */
1108 *p++ = 0; /* linkq */
1112 p += 2; /* reserved */
1113 put32(p, ~0); /* lifetime */
1115 /* scratch ptr? not clear what this is for */
1116 put32(p, PCIWADDR(ctlr->kwpage));
1118 *p++ = 60; /* rts ntries */
1119 *p++ = 15; /* data ntries */
1121 put16(p, 0); /* timeout */
1124 qcmd(ctlr, 0, 28, c, p - c, b);
1128 rbplant(Ctlr *ctlr, int i)
1132 b = iallocb(Rbufsize + 256);
1135 b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
1136 memset(b->rp, 0, Rdscsize);
1138 ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
1143 iwlctl(Ether *edev, void *buf, long n)
1149 return wifictl(ctlr->wifi, buf, n);
1154 iwlifstat(Ether *edev, void *buf, long n, ulong off)
1160 return wifistat(ctlr->wifi, buf, n, off);
1165 setoptions(Ether *edev)
1173 for(i = 0; i < edev->nopt; i++){
1174 if(strncmp(edev->opt[i], "channel=", 8) == 0)
1175 ctlr->channel = atoi(edev->opt[i]+8);
1177 if(strncmp(edev->opt[i], "essid=", 6) == 0){
1178 snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
1180 wifictl(ctlr->wifi, buf, strlen(buf));
1188 iwlattach(Ether *edev)
1203 if(ctlr->attached == 0){
1204 if(ctlr->wifi == nil)
1205 ctlr->wifi = wifiattach(edev, transmit);
1207 if(ctlr->fw == nil){
1208 fw = readfirmware("iwn-5000");
1209 print("#l%d: firmware: rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
1212 fw->main.text.size, fw->main.data.size,
1213 fw->init.text.size, fw->init.data.size,
1214 fw->boot.text.size);
1221 rx->b = malloc(sizeof(Block*) * Nrx);
1223 rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
1225 rx->s = mallocalign(Rstatsize, 16, 0, 0);
1226 if(rx->b == nil || rx->p == nil || rx->s == nil)
1227 error("no memory for rx ring");
1228 memset(rx->s, 0, Rstatsize);
1229 for(i=0; i<Nrx; i++){
1231 if(rx->b[i] != nil){
1235 if(rbplant(ctlr, i) < 0)
1236 error("no memory for rx descriptors");
1239 for(q=0; q<nelem(ctlr->tx); q++){
1244 tx->b = malloc(sizeof(Block*) * Ntx);
1246 tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
1248 tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
1249 if(tx->b == nil || tx->d == nil || tx->c == nil)
1250 error("no memory for tx ring");
1251 memset(tx->d, 0, Tdscsize * Ntx);
1254 if(ctlr->sched.s == nil)
1255 ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
1256 if(ctlr->kwpage == nil)
1257 ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
1259 if((err = niclock(ctlr)) != nil)
1261 prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
1264 csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
1266 if((err = niclock(ctlr)) != nil)
1268 prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
1271 if((err = niclock(ctlr)) != nil)
1273 csr32w(ctlr, FhRxConfig, 0);
1274 csr32w(ctlr, FhRxWptr, 0);
1275 csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
1276 csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
1277 csr32w(ctlr, FhRxConfig,
1279 FhRxConfigIgnRxfEmpty |
1280 FhRxConfigIrqDstHost |
1281 FhRxConfigSingleFrame |
1282 (Nrxlog << FhRxConfigNrbdShift));
1283 csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
1286 if((err = niclock(ctlr)) != nil)
1288 prphwrite(ctlr, SchedTxFact5000, 0);
1289 csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
1290 for(q=0; q<nelem(ctlr->tx); q++)
1291 csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
1294 csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
1295 csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
1296 csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
1298 ctlr->ie = Idefmask;
1299 csr32w(ctlr, Imr, ctlr->ie);
1300 csr32w(ctlr, Isr, ~0);
1302 if(ctlr->type >= Type6000)
1303 csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
1305 if((err = loadfirmware1(ctlr, 0x00000000, ctlr->fw->main.text.data, ctlr->fw->main.text.size)) != nil)
1307 if((err = loadfirmware1(ctlr, 0x00800000, ctlr->fw->main.data.data, ctlr->fw->main.data.size)) != nil)
1310 csr32w(ctlr, Reset, 0);
1311 if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
1312 error("firmware boot failed");
1319 addnode(ctlr, 15, edev->bcast);
1339 if(rx->s == nil || rx->b == nil)
1341 for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
1342 uchar type, flags, idx, qid;
1350 len = get32(d); d += 4;
1357 if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
1358 tx = &ctlr->tx[qid];
1365 /* paranoia: clear tx descriptors */
1366 dd = tx->d + idx*Tdscsize;
1367 cc = tx->c + idx*Tcmdsize;
1368 memset(dd, 0, Tdscsize);
1369 memset(cc, 0, Tcmdsize);
1377 if(len < 4 || type == 0)
1382 case 1: /* microcontroller ready */
1383 setfwinfo(ctlr, d, len);
1385 case 24: /* add node done */
1387 case 28: /* tx done */
1389 case 102: /* calibration result (Type5000 only)
1391 case 103: /* calibration done (Type5000 only)
1393 case 130: /* start scan */
1395 case 132: /* stop scan */
1397 case 156: /* rx statistics */
1399 case 157: /* beacon statistics */
1401 case 161: /* state changed */
1403 case 162: /* beacon missed */
1405 case 192: /* rx phy */
1407 case 195: /* rx done */
1411 case 193: /* mpdu rx done */
1414 len = get16(d); d += 4;
1415 if(d + len + 4 > b->lim)
1417 if((get32(d + len) & 3) != 3)
1419 if(ctlr->wifi == nil)
1421 if(rbplant(ctlr, rx->i) < 0)
1425 wifiiq(ctlr->wifi, b);
1427 case 197: /* rx compressed ba */
1430 /* paranoia: clear the descriptor */
1431 memset(b->rp, 0, Rdscsize);
1433 csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
1437 iwlinterrupt(Ureg*, void *arg)
1446 csr32w(ctlr, Imr, 0);
1447 isr = csr32r(ctlr, Isr);
1448 fhisr = csr32r(ctlr, FhIsr);
1449 if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
1453 if(isr == 0 && fhisr == 0)
1455 csr32w(ctlr, Isr, isr);
1456 csr32w(ctlr, FhIsr, fhisr);
1457 if((isr & (Iswrx | Ifhrx | Irxperiodic)) || (fhisr & Ifhrx))
1460 iprint("#l%d: fatal firmware error\n", edev->ctlrno);
1463 ctlr->wait.m |= isr;
1464 if(ctlr->wait.m & ctlr->wait.w){
1465 ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
1466 ctlr->wait.m &= ~ctlr->wait.r;
1467 wakeup(&ctlr->wait);
1470 csr32w(ctlr, Imr, ctlr->ie);
1474 static Ctlr *iwlhead, *iwltail;
1482 while(pdev = pcimatch(pdev, 0, 0)) {
1486 if(pdev->ccrb != 2 || pdev->ccru != 0x80)
1488 if(pdev->vid != 0x8086)
1494 case 0x4236: /* WiFi Link 5300 AGN */
1498 /* Clear device-specific "PCI retry timeout" register (41h). */
1499 if(pcicfgr8(pdev, 0x41) != 0)
1500 pcicfgw8(pdev, 0x41, 0);
1502 /* Clear interrupt disable bit. Hardware bug workaround. */
1503 if(pdev->pcr & 0x400){
1504 pdev->pcr &= ~0x400;
1505 pcicfgw16(pdev, PciPCR, pdev->pcr);
1511 ctlr = malloc(sizeof(Ctlr));
1513 print("iwl: unable to alloc Ctlr\n");
1516 ctlr->port = pdev->mem[0].bar & ~0x0F;
1517 mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
1519 print("iwl: can't map %8.8luX\n", pdev->mem[0].bar);
1525 ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
1528 iwltail->link = ctlr;
1543 for(ctlr = iwlhead; ctlr != nil; ctlr = ctlr->link){
1546 if(edev->port == 0 || edev->port == ctlr->port){
1556 edev->port = ctlr->port;
1557 edev->irq = ctlr->pdev->intl;
1558 edev->tbdf = ctlr->pdev->tbdf;
1560 edev->interrupt = iwlinterrupt;
1561 edev->attach = iwlattach;
1562 edev->ifstat = iwlifstat;
1564 edev->promiscuous = nil;
1565 edev->multicast = nil;
1568 if(iwlinit(edev) < 0){
1579 addethercard("iwl", iwlpnp);