diff 8f4842d3465e96d264f5c2f7fa2d61db871aae9f uncommitted --- a/sys/src/9/pc/etheriwl.c +++ b/sys/src/9/pc/etheriwl.c @@ -3,7 +3,7 @@ * * Written without any documentation but Damien Bergamini's * iwn(4) and Stefan Sperling's iwm(4) OpenBSD driver sources. - * Requires Intel firmware to be present in /lib/firmware/iw[nm]-* + * Requires Intel firmware to be present in /lib/firmware/ * on attach. */ @@ -329,7 +329,27 @@ SchedTransTblOff = 0x7E0, // +q*2 }; +/* + * uCode capabilities + */ enum { + /* flags */ + UcodeFlgDwBc = 1<<4, + + /* api[0] */ + UcodeApiSta = 1<<30, + + /* capa[0] */ + UcodeCapLar = 1<<1, + + /* capa[1] */ + UcodeCapQuota = 1<<12, + + /* capa[2] */ + UcodeCapLar2 = 1<<9, +}; + +enum { FilterPromisc = 1<<0, FilterCtl = 1<<1, FilterMulticast = 1<<2, @@ -418,6 +438,7 @@ uint build; char descr[64+1]; + u32int flags; u32int capa[4]; u32int api[4]; @@ -565,7 +586,6 @@ uchar type; uchar step; uchar dash; - uchar pnum; uchar txantmask; uchar rxantmask; } rfcfg; @@ -586,7 +606,7 @@ } eeprom; struct { - u32int version; + int read; void *buf; int len; @@ -635,8 +655,7 @@ Type2030 = 12, Type2000 = 16, - Type7260 = 30, - Type8265 = 35, + Type7260 = 20, }; static struct ratetab { @@ -690,7 +709,6 @@ [Type6005] "iwn-6005", /* see in iwlattach() below */ [Type2030] "iwn-2030", [Type2000] "iwn-2000", - [Type7260] "iwm-7260-17", }; static char *qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block); @@ -728,10 +746,12 @@ int i; csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq); - for(i=0; i<1000; i++){ + if(ctlr->family >= 8000) + microdelay(2); + for(i=0; i<1500; i++){ if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna) return 0; - delay(10); + microdelay(10); } return "niclock: timeout"; } @@ -944,7 +964,7 @@ for(j=0; j<100; j++){ if(csr32r(ctlr, Cfg) & EepromLocked) return 0; - delay(10); + microdelay(10); } } return "eepromlock: timeout"; @@ -969,7 +989,7 @@ w = csr32r(ctlr, EepromIo); if(w & 1) break; - delay(5); + microdelay(5); } if(i == 10) return "eepromread: timeout"; @@ -990,34 +1010,35 @@ static char* handover(Ctlr *ctlr) { - int i; + int n, i, j; csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady); for(i=0; i<5; i++){ if(csr32r(ctlr, Cfg) & NicReady) goto Ready; - delay(10); + microdelay(10); } + if(ctlr->family >= 7000){ csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31)); delay(1); } - csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare); - for(i=0; i<15000; i++){ - if((csr32r(ctlr, Cfg) & PrepareDone) == 0) - break; - delay(10); - } - if(i >= 15000) - return "handover: timeout"; + for(n=0; n<10; n++){ + csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare); - csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady); - for(i=0; i<5; i++){ - if(csr32r(ctlr, Cfg) & NicReady) - goto Ready; - delay(10); + for(i=0; i<750; i++){ + csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady); + for(j=0; j<5; j++){ + if(csr32r(ctlr, Cfg) & NicReady) + goto Ready; + microdelay(10); + } + microdelay(200); + } + delay(25); } + return "handover: timeout"; Ready: if(ctlr->family >= 7000) @@ -1035,7 +1056,7 @@ for(i=0; i<2500; i++){ if(csr32r(ctlr, Gpc) & MacClockReady) return 0; - delay(10); + microdelay(10); } return "clockwait: timeout"; } @@ -1046,7 +1067,6 @@ int capoff; char *err; - if(ctlr->family >= 7000){ /* Reset entire device */ csr32w(ctlr, Reset, (1<<7)); @@ -1100,7 +1120,6 @@ prphread(ctlr, OscClk); prphread(ctlr, OscClk); - delay(20); prphwrite(ctlr, OscClk, prphread(ctlr, OscClk) | OscClkCtrl); @@ -1119,7 +1138,7 @@ prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt); else prphwrite(ctlr, ApmgClkEna, DmaClkRqt); - delay(20); + microdelay(20); /* Disable L1-Active. */ prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11)); @@ -1158,7 +1177,7 @@ for(j = 0; j < 200; j++){ if(csr32r(ctlr, FhTxStatus) & (0x10000<mqrx){ prphwrite(ctlr, RfhDmaCfg, 0); - for(j = 0; j < 200; j++){ + for(j = 0; j < 1000; j++){ if(prphread(ctlr, RfhGenStatus) & RfhGenStatusDmaIdle) break; - delay(10); + microdelay(10); } } else { csr32w(ctlr, FhRxConfig, 0); - for(j = 0; j < 200; j++){ + for(j = 0; j < 1000; j++){ if(csr32r(ctlr, FhRxStatus) & 0x1000000) break; - delay(10); + microdelay(10); } } nicunlock(ctlr); @@ -1190,7 +1209,7 @@ prphwrite(ctlr, ApmgClkDis, DmaClkRqt); nicunlock(ctlr); } - delay(5); + microdelay(5); } if(ctlr->family >= 7000){ @@ -1206,12 +1225,12 @@ for(j = 0; j < 100; j++){ if(csr32r(ctlr, Reset) & (1<<8)) break; - delay(10); + microdelay(10); } /* Reset the entire device. */ csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<7)); - delay(10); + delay(5); /* Clear "initialization complete" bit. */ csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~InitDone); @@ -1239,7 +1258,7 @@ if((err = niclock(ctlr)) != nil) return err; prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | ResetReq); - delay(5); + microdelay(5); prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) & ~ResetReq); nicunlock(ctlr); @@ -1308,7 +1327,7 @@ ctlr->type &= 0x1FF; ctlr->dash = ctlr->type & 3, ctlr->type >>= 2; ctlr->step = ctlr->type & 3, ctlr->type >>= 2; - if(fwname[ctlr->type] == nil){ + if(ctlr->fwname == nil && fwname[ctlr->type] == nil){ print("iwl: unsupported controller type %d\n", ctlr->type); return -1; } @@ -1478,6 +1497,11 @@ s = &i->boot.text; s->addr = 0x00000000; goto Sect; + case 18: + if(l < 4) + goto Tooshort; + i->flags = get32(p); + break; case 19: if(i->main.nsect >= nelem(i->main.sect)) return "too many main sections"; @@ -1984,7 +2008,7 @@ *p++ = mcc[0]; *p++ = 0; *p++ = 0; // reserved - if(1){ + if(ctlr->fw->capa[2] & UcodeCapLar2){ p += 4; p += 5*4; } @@ -2217,45 +2241,40 @@ return o; } +static int +validea(uchar *ea) +{ + static uchar reservedea[] = {0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00}, zeros[Eaddrlen]; + + if(ea[0] & 1 || + memcmp(ea, reservedea, Eaddrlen) == 0 || + memcmp(ea, zeros, Eaddrlen) == 0) + return 0; + return 1; +} + static char* readnvmconfig(Ctlr *ctlr) { uchar *ea = ctlr->edev->ea; uchar buf[8]; - uint u; char *err; - if(readnvmsect(ctlr, 1, buf, 8, 0) != 8) - return "can't read nvm version"; + if(ctlr->nvm.read) + return nil; - ctlr->nvm.version = get16(buf); - if (ctlr->family == 7000) { - u = get16(buf + 2); - - ctlr->rfcfg.type = (u >> 4) & 3; - ctlr->rfcfg.step = (u >> 2) & 3; - ctlr->rfcfg.dash = (u >> 0) & 3; - ctlr->rfcfg.pnum = (u >> 6) & 3; - - ctlr->rfcfg.txantmask = (u >> 8) & 15; - ctlr->rfcfg.rxantmask = (u >> 12) & 15; - - } else { - if(readnvmsect(ctlr, 12, buf, 8, 0) != 8) - return "can't read nvm phy config"; - - u = get32(buf); - - ctlr->rfcfg.type = (u >> 12) & 0xFFF; - ctlr->rfcfg.step = (u >> 8) & 15; - ctlr->rfcfg.dash = (u >> 4) & 15; - ctlr->rfcfg.pnum = (u >> 6) & 3; - - ctlr->rfcfg.txantmask = (u >> 24) & 15; - ctlr->rfcfg.rxantmask = (u >> 28) & 15; - } + if(readnvmsect(ctlr, ctlr->family >= 8000 ? 12 : 1, buf, 2, 0x01<<1) != 2) + return "can't read antenna data from nvm"; + if(buf[1] & 15 & ctlr->rfcfg.txantmask) + ctlr->rfcfg.txantmask &= buf[1] & 15; + if(buf[1] >> 4 & ctlr->rfcfg.rxantmask) + ctlr->rfcfg.rxantmask &= buf[1] >> 4; + ctlr->fw->physku &= 0xff00ffffUL; + ctlr->fw->physku |= ctlr->rfcfg.txantmask << 16; + ctlr->fw->physku |= ctlr->rfcfg.rxantmask << 20; + if(ctlr->family >= 8000){ - if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) != Eaddrlen){ + if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) != Eaddrlen || !validea(ea)){ u32int a0, a1; if((err = niclock(ctlr)) != nil) @@ -2270,12 +2289,23 @@ ea[3] = a0 >> 0; ea[4] = a1 >> 8; ea[5] = a1 >> 0; - } - } else { - readnvmsect(ctlr, 0, ea, Eaddrlen, 0x15<<1); + } + }else{ + /* reading 6 bytes from 0x15 seems to cause an ADVANCED_SYSASSERT. */ + if(readnvmsect(ctlr, 0, buf, 8, 0x14<<1) != 8) + return "can't read ea from nvm"; + + /* byte order is 16 bit little endian. */ + ea[0] = buf[3]; + ea[1] = buf[2]; + ea[2] = buf[5]; + ea[3] = buf[4]; + ea[4] = buf[7]; + ea[5] = buf[6]; } memmove(ctlr->edev->addr, ea, Eaddrlen); + ctlr->nvm.read = 1; return nil; } @@ -2366,7 +2396,7 @@ p += 2; /* sleep_tx_count */ p++; /* sleep state flags */ - *p++ = (ctlr->fw->api[0] & (1<<30)) != 0 ? type : 0; /* station_type */ + *p++ = ctlr->fw->api[0] & UcodeApiSta ? type : 0; /* station_type */ p += 2; /* assoc id */ @@ -2375,7 +2405,7 @@ put32(p, 1<<0); p += 4; /* tfd_queue_mask */ - if(1){ + if(ctlr->fw->api[0] & UcodeApiSta){ p += 2; /* rx_ba_window */ p++; /* sp_length */ p++; /* uapsd_acs */ @@ -2640,7 +2670,7 @@ static char* settimeevent(Ctlr *ctlr, int amr, int ival) { - int duration, delay, timeid; + int timeid; uchar c[9*4], *p; char *err; @@ -2662,14 +2692,6 @@ break; } - if(ival){ - duration = ival*2; - delay = ival/2; - } else { - duration = 1024; - delay = 0; - } - memset(p = c, 0, sizeof(c)); put32(p, ctlr->macid); p += 4; @@ -2678,23 +2700,27 @@ put32(p, timeid); p += 4; - put32(p, 0); // apply time - p += 4; - put32(p, delay); - p += 4; - put32(p, 0); // depends on - p += 4; - put32(p, 1); // interval - p += 4; - put32(p, duration); - p += 4; - *p++ = 1; // repeat - *p++ = 0; // max frags - put16(p, 1<<0 | 1<<1 | 1<<11); // policy - p += 2; + if(amr == CmdRemove) + p += 6*4; + else{ + put32(p, 0); // apply time + p += 4; + put32(p, ival/2); // max delay + p += 4; + put32(p, 0); // depends on + p += 4; + put32(p, 1); // interval + p += 4; + put32(p, ival? ival*2: 1024); // duration + p += 4; + *p++ = 1; // repeat + *p++ = 0; // max frags + put16(p, 1<<0 | 1<<1 | 1<<11); // policy + p += 2; + } ctlr->te.active = 0; - if((err = cmd(ctlr, 41, c, p - c)) != nil) + if((err = cmd(ctlr, 41, c, p - c)) != nil) return err; if(amr == CmdRemove){ @@ -2713,6 +2739,9 @@ uchar c[4*(3*4)], *p; int i; + if((ctlr->fw->capa[1] & UcodeCapQuota) == 0) + return nil; + i = 0; p = c; @@ -2822,13 +2851,13 @@ return cmd(ctlr, 210, c, 11*4); } -static void +static char* tttxbackoff(Ctlr *ctlr) { uchar c[4]; put32(c, 0); - cmd(ctlr, 126, c, sizeof(c)); + return cmd(ctlr, 126, c, sizeof(c)); } static char* @@ -2848,6 +2877,9 @@ char *err; if(ctlr->calib.done == 0){ + if(ctlr->family == 7000) + if((err = sendbtcoexadv(ctlr)) != nil) + return err; if((err = readnvmconfig(ctlr)) != nil) return err; } @@ -2897,16 +2929,16 @@ /* Initialize tx backoffs to the minimum. */ if(ctlr->family == 7000) - tttxbackoff(ctlr); + if((err = tttxbackoff(ctlr)) != nil) + return err; if((err = updatedevicepower(ctlr)) != nil){ print("can't update device power: %s\n", err); return err; } - if((err = sendmccupdate(ctlr, "ZZ")) != nil){ - print("can't disable beacon filter: %s\n", err); - return err; - } + if(ctlr->fw->capa[0] & UcodeCapLar) + if((err = sendmccupdate(ctlr, "ZZ")) != nil) + return err; if((err = disablebeaconfilter(ctlr)) != nil){ print("can't disable beacon filter: %s\n", err); return err; @@ -3121,7 +3153,7 @@ f = 4; else { static char qid2fifo[] = { - 3, 2, 1, 0, 7, 5, 6, + 3, 2, 1, 7, 4, 5, 6, }; f = qid2fifo[i]; } @@ -3362,7 +3394,7 @@ for(i=0; i<1000; i++){ if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0) break; - delay(10); + microdelay(10); } if(i == 1000){ nicunlock(ctlr); @@ -3418,6 +3450,7 @@ static char* qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block) { + char *err; int hdrlen; Block *bcmd; uchar *d, *c; @@ -3451,12 +3484,6 @@ iunlock(ctlr); return "qcmd: broken"; } - /* wake up the nic (just needed for 7k) */ - if(ctlr->family == 7000 && q->n == 0) - if(niclock(ctlr) != nil){ - iunlock(ctlr); - return "qcmd: busy"; - } q->n++; q->lastcmd = code; @@ -3507,6 +3534,12 @@ coherence(); + if(ctlr->family == 7000 && qid == 4 && q->n == 0) + if((err = niclock(ctlr)) != nil){ + iunlock(ctlr); + return err; + } + q->i = (q->i+1) % Ntx; csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i); @@ -3586,9 +3619,16 @@ int i; for(i = 0; i < nelem(ctlr->tx); i++) - flushq(ctlr, i); - settimeevent(ctlr, CmdRemove, 0); + if((err = flushq(ctlr, i)) != nil){ + print("can't flush queue %d: %s\n", i, err); + return err; + } + if((err = settimeevent(ctlr, CmdRemove, 0)) != nil){ + print("can't remove time event: %s\n", err); + return err; + } + if((err = setbindingquotas(ctlr, -1)) != nil){ print("can't disable quotas: %s\n", err); return err; @@ -3630,7 +3670,7 @@ return err; } if((err = setbindingcontext(ctlr, CmdAdd)) != nil){ - print("removing bindingcontext: %s\n", err); + print("adding bindingcontext: %s\n", err); return err; } if((err = setmcastfilter(ctlr)) != nil){ @@ -4283,8 +4323,8 @@ if(tx != nil && tx->n > 0){ tx->n--; wakeup(tx); - /* unlock 7k family nics as all commands are done */ - if(ctlr->family == 7000 && tx->n == 0) + /* unlock 7k family nics as the command is done */ + if(ctlr->family == 7000 && qid == 4 && tx->n == 0) nicunlock(ctlr); } } @@ -4354,14 +4394,12 @@ int family; pdev = nil; - while(pdev = pcimatch(pdev, 0, 0)) { + while(pdev = pcimatch(pdev, 0x8086, 0)){ Ctlr *ctlr; void *mem; if(pdev->ccrb != 2 || pdev->ccru != 0x80) continue; - if(pdev->vid != 0x8086) - continue; if(pdev->mem[0].bar & 1) continue; @@ -4399,9 +4437,10 @@ case 0x08b1: /* Wireless AC 7260 */ case 0x08b2: /* Wireless AC 7260 */ family = 7000; - fwname = nil; + fwname = "iwm-7260-17"; break; case 0x24f3: /* Wireless AC 8260 */ + case 0x24f4: /* Wireless AC 8260 */ family = 8000; fwname = "iwm-8000C-34"; break;