/* * Intel WiFi Link driver. * * Written without any documentation but Damien Bergaminis * OpenBSD iwn(4) driver sources. Requires intel firmware * to be present in /lib/firmware/iwn-* on attach. */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "../port/netif.h" #include "etherif.h"#include "wifi.h" enum { Ntxlog = 8, Ntx = 1<<Ntxlog, Nrxlog = 8, Nrx = 1<<Nrxlog, Rstatsize = 16, Rbufsize = 4*1024, Rdscsize = 8, Tbufsize = 4*1024, Tdscsize = 128, Tcmdsize = 140,}; /* registers */enum { Cfg = 0x000, /* config register */ MacSi = 1<<8, RadioSi = 1<<9, EepromLocked = 1<<21, NicReady = 1<<22, HapwakeL1A = 1<<23, PrepareDone = 1<<25, Prepare = 1<<27, Isr = 0x008, /* interrupt status */ Imr = 0x00c, /* interrupt mask */ Ialive = 1<<0, Iwakeup = 1<<1, Iswrx = 1<<3, Ictreached = 1<<6, Irftoggled = 1<<7, Iswerr = 1<<25, Isched = 1<<26, Ifhtx = 1<<27, Irxperiodic = 1<<28, Ihwerr = 1<<29, Ifhrx = 1<<31, Ierr = Iswerr | Ihwerr, Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled, FhIsr = 0x010, /* second interrupt status */ Reset = 0x020, Rev = 0x028, /* hardware revision */ EepromIo = 0x02c, /* EEPROM i/o register */ EepromGp = 0x030, OtpromGp = 0x034, DevSelOtp = 1<<16, RelativeAccess = 1<<17, EccCorrStts = 1<<20, EccUncorrStts = 1<<21, Gpc = 0x024, /* gp cntrl */ MacAccessEna = 1<<0, MacClockReady = 1<<0, InitDone = 1<<2, MacAccessReq = 1<<3, NicSleep = 1<<4, RfKill = 1<<27, Gio = 0x03c, EnaL0S = 1<<1, GpDrv = 0x050, GpDrvCalV6 = 1<<2, GpDrv1X2 = 1<<3, GpDrvRadioIqInvert = 1<<7, Led = 0x094, LedBsmCtrl = 1<<5, LedOn = 0x38, LedOff = 0x78, UcodeGp1Clr = 0x05c, UcodeGp1RfKill = 1<<1, UcodeGp1CmdBlocked = 1<<2, UcodeGp1CtempStopRf = 1<<3, ShadowRegCtrl = 0x0a8, Giochicken = 0x100, L1AnoL0Srx = 1<<23, DisL0Stimer = 1<<29, AnaPll = 0x20c, Dbghpetmem = 0x240, Dbglinkpwrmgmt = 0x250, MemRaddr = 0x40c, MemWaddr = 0x410, MemWdata = 0x418, MemRdata = 0x41c, PrphWaddr = 0x444, PrphRaddr = 0x448, PrphWdata = 0x44c, PrphRdata = 0x450, HbusTargWptr = 0x460,}; /* * Flow-Handler registers. */enum { FhTfbdCtrl0 = 0x1900, // +q*8 FhTfbdCtrl1 = 0x1904, // +q*8 FhKwAddr = 0x197c, FhSramAddr = 0x19a4, // +q*4 FhCbbcQueue = 0x19d0, // +q*4 FhStatusWptr = 0x1bc0, FhRxBase = 0x1bc4, FhRxWptr = 0x1bc8, FhRxConfig = 0x1c00, FhRxConfigEna = 1<<31, FhRxConfigRbSize8K = 1<<16, FhRxConfigSingleFrame = 1<<15, FhRxConfigIrqDstHost = 1<<12, FhRxConfigIgnRxfEmpty = 1<<2, FhRxConfigNrbdShift = 20, FhRxConfigRbTimeoutShift= 4, FhRxStatus = 0x1c44, FhTxConfig = 0x1d00, // +q*32 FhTxConfigDmaCreditEna = 1<<3, FhTxConfigDmaEna = 1<<31, FhTxConfigCirqHostEndTfd= 1<<20, FhTxBufStatus = 0x1d08, // +q*32 FhTxBufStatusTbNumShift = 20, FhTxBufStatusTbIdxShift = 12, FhTxBufStatusTfbdValid = 3, FhTxChicken = 0x1e98, FhTxStatus = 0x1eb0,}; /* * NIC internal memory offsets. */enum { ApmgClkCtrl = 0x3000, ApmgClkEna = 0x3004, ApmgClkDis = 0x3008, DmaClkRqt = 1<<9, BsmClkRqt = 1<<11, ApmgPs = 0x300c, EarlyPwroffDis = 1<<22, PwrSrcVMain = 0<<24, PwrSrcVAux = 2<<24, PwrSrcMask = 3<<24, ResetReq = 1<<26, ApmgDigitalSvr = 0x3058, ApmgAnalogSvr = 0x306c, ApmgPciStt = 0x3010, BsmWrCtrl = 0x3400, BsmWrMemSrc = 0x3404, BsmWrMemDst = 0x3408, BsmWrDwCount = 0x340c, BsmDramTextAddr = 0x3490, BsmDramTextSize = 0x3494, BsmDramDataAddr = 0x3498, BsmDramDataSize = 0x349c, BsmSramBase = 0x3800,}; /* * TX scheduler registers. */enum { SchedBase = 0xa02c00, SchedSramAddr = SchedBase, SchedDramAddr4965 = SchedBase+0x010, SchedTxFact4965 = SchedBase+0x01c, SchedQueueRdptr4965 = SchedBase+0x064, // +q*4 SchedQChainSel4965 = SchedBase+0x0d0, SchedIntrMask4965 = SchedBase+0x0e4, SchedQueueStatus4965 = SchedBase+0x104, // +q*4 SchedDramAddr5000 = SchedBase+0x008, SchedTxFact5000 = SchedBase+0x010, SchedQueueRdptr5000 = SchedBase+0x068, // +q*4 SchedQChainSel5000 = SchedBase+0x0e8, SchedIntrMask5000 = SchedBase+0x108, SchedQueueStatus5000 = SchedBase+0x10c, // +q*4 SchedAggrSel5000 = SchedBase+0x248,}; enum { SchedCtxOff4965 = 0x380, SchedCtxLen4965 = 416, SchedCtxOff5000 = 0x600, SchedCtxLen5000 = 512,}; enum { FilterPromisc = 1<<0, FilterCtl = 1<<1, FilterMulticast = 1<<2, FilterNoDecrypt = 1<<3, FilterBSS = 1<<5, FilterBeacon = 1<<6,}; enum { RFlag24Ghz = 1<<0, RFlagCCK = 1<<1, RFlagAuto = 1<<2, RFlagShSlot = 1<<4, RFlagShPreamble = 1<<5, RFlagNoDiversity = 1<<7, RFlagAntennaA = 1<<8, RFlagAntennaB = 1<<9, RFlagTSF = 1<<15, RFlagCTSToSelf = 1<<30,}; typedef struct FWInfo FWInfo;typedef struct FWImage FWImage;typedef struct FWSect FWSect; typedef struct TXQ TXQ;typedef struct RXQ RXQ; typedef struct Ctlr Ctlr; struct FWSect{ uchar *data; uint size;}; struct FWImage{ struct { FWSect text; FWSect data; } init, main, boot; uint rev; uint build; char descr[64+1]; uchar data[];}; struct FWInfo{ uchar major; uchar minjor; uchar type; uchar subtype; u32int logptr; u32int errptr; u32int tstamp; u32int valid;}; struct TXQ{ uint n; uint i; Block **b; uchar *d; uchar *c; uint lastcmd; Rendez; QLock;}; struct RXQ{ uint i; Block **b; u32int *p; uchar *s;}; struct Ctlr { Lock; QLock; Ctlr *link; Pcidev *pdev; Wifi *wifi; int type; int port; int power; int active; int broken; int attached; u32int ie; u32int *nic; uchar *kwpage; /* assigned node ids in hardware node table or -1 if unassigned */ int bcastnodeid; int bssnodeid; /* current receiver settings */ uchar bssid[Eaddrlen]; int channel; int prom; int aid; RXQ rx; TXQ tx[20]; struct { Rendez; u32int m; u32int w; } wait; struct { uchar type; uchar step; uchar dash; uchar txantmask; uchar rxantmask; } rfcfg; struct { int otp; uint off; uchar version; uchar type; u16int volt; u16int temp; u16int rawtemp; char regdom[4+1]; u32int crystal; } eeprom; struct { Block *cmd[21]; int done; } calib; struct { u32int base; uchar *s; } sched; FWInfo fwinfo; FWImage *fw;}; /* controller types */enum { Type4965 = 0, Type5300 = 2, Type5350 = 3, Type5150 = 4, Type5100 = 5, Type1000 = 6, Type6000 = 7, Type6050 = 8, Type6005 = 11, Type2030 = 12,}; static char *fwname[16] = { [Type4965] "iwn-4965", [Type5300] "iwn-5000", [Type5350] "iwn-5000", [Type5150] "iwn-5150", [Type5100] "iwn-5000", [Type1000] "iwn-1000", [Type6000] "iwn-6000", [Type6050] "iwn-6050", [Type6005] "iwn-6005", [Type2030] "iwn-2030",}; static char *qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block);static char *flushq(Ctlr *ctlr, uint qid);static char *cmd(Ctlr *ctlr, uint code, uchar *data, int size); #define csr32r(c, r) (*((c)->nic+((r)/4)))#define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v)) static uintget16(uchar *p){ return *((u16int*)p);}static uintget32(uchar *p){ return *((u32int*)p);}static voidput32(uchar *p, uint v){ *((u32int*)p) = v;}static voidput16(uchar *p, uint v){ *((u16int*)p) = v;}; static char*niclock(Ctlr *ctlr){ int i; csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq); for(i=0; i<1000; i++){ if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna) return 0; delay(10); } return "niclock: timeout";} static voidnicunlock(Ctlr *ctlr){ csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq);} static u32intprphread(Ctlr *ctlr, uint off){ csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); return csr32r(ctlr, PrphRdata);}static voidprphwrite(Ctlr *ctlr, uint off, u32int data){ csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); csr32w(ctlr, PrphWdata, data);} static u32intmemread(Ctlr *ctlr, uint off){ csr32w(ctlr, MemRaddr, off); coherence(); return csr32r(ctlr, MemRdata);}static voidmemwrite(Ctlr *ctlr, uint off, u32int data){ csr32w(ctlr, MemWaddr, off); coherence(); csr32w(ctlr, MemWdata, data);} static voidsetfwinfo(Ctlr *ctlr, uchar *d, int len){ FWInfo *i; if(len < 32) return; i = &ctlr->fwinfo;Lines 1–500 of 2530. Load more
/* * Intel WiFi Link driver. * * Written without any documentation but Damien Bergaminis * OpenBSD iwn(4) driver sources. Requires intel firmware * to be present in /lib/firmware/iwn-* on attach. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "../port/netif.h" #include "etherif.h" #include "wifi.h" enum { Ntxlog = 8, Ntx = 1<<Ntxlog, Nrxlog = 8, Nrx = 1<<Nrxlog, Rstatsize = 16, Rbufsize = 4*1024, Rdscsize = 8, Tbufsize = 4*1024, Tdscsize = 128, Tcmdsize = 140, }; /* registers */ enum { Cfg = 0x000, /* config register */ MacSi = 1<<8, RadioSi = 1<<9, EepromLocked = 1<<21, NicReady = 1<<22, HapwakeL1A = 1<<23, PrepareDone = 1<<25, Prepare = 1<<27, Isr = 0x008, /* interrupt status */ Imr = 0x00c, /* interrupt mask */ Ialive = 1<<0, Iwakeup = 1<<1, Iswrx = 1<<3, Ictreached = 1<<6, Irftoggled = 1<<7, Iswerr = 1<<25, Isched = 1<<26, Ifhtx = 1<<27, Irxperiodic = 1<<28, Ihwerr = 1<<29, Ifhrx = 1<<31, Ierr = Iswerr | Ihwerr, Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx | Ictreached | Irftoggled, FhIsr = 0x010, /* second interrupt status */ Reset = 0x020, Rev = 0x028, /* hardware revision */ EepromIo = 0x02c, /* EEPROM i/o register */ EepromGp = 0x030, OtpromGp = 0x034, DevSelOtp = 1<<16, RelativeAccess = 1<<17, EccCorrStts = 1<<20, EccUncorrStts = 1<<21, Gpc = 0x024, /* gp cntrl */ MacAccessEna = 1<<0, MacClockReady = 1<<0, InitDone = 1<<2, MacAccessReq = 1<<3, NicSleep = 1<<4, RfKill = 1<<27, Gio = 0x03c, EnaL0S = 1<<1, GpDrv = 0x050, GpDrvCalV6 = 1<<2, GpDrv1X2 = 1<<3, GpDrvRadioIqInvert = 1<<7, Led = 0x094, LedBsmCtrl = 1<<5, LedOn = 0x38, LedOff = 0x78, UcodeGp1Clr = 0x05c, UcodeGp1RfKill = 1<<1, UcodeGp1CmdBlocked = 1<<2, UcodeGp1CtempStopRf = 1<<3, ShadowRegCtrl = 0x0a8, Giochicken = 0x100, L1AnoL0Srx = 1<<23, DisL0Stimer = 1<<29, AnaPll = 0x20c, Dbghpetmem = 0x240, Dbglinkpwrmgmt = 0x250, MemRaddr = 0x40c, MemWaddr = 0x410, MemWdata = 0x418, MemRdata = 0x41c, PrphWaddr = 0x444, PrphRaddr = 0x448, PrphWdata = 0x44c, PrphRdata = 0x450, HbusTargWptr = 0x460, }; /* * Flow-Handler registers. */ enum { FhTfbdCtrl0 = 0x1900, // +q*8 FhTfbdCtrl1 = 0x1904, // +q*8 FhKwAddr = 0x197c, FhSramAddr = 0x19a4, // +q*4 FhCbbcQueue = 0x19d0, // +q*4 FhStatusWptr = 0x1bc0, FhRxBase = 0x1bc4, FhRxWptr = 0x1bc8, FhRxConfig = 0x1c00, FhRxConfigEna = 1<<31, FhRxConfigRbSize8K = 1<<16, FhRxConfigSingleFrame = 1<<15, FhRxConfigIrqDstHost = 1<<12, FhRxConfigIgnRxfEmpty = 1<<2, FhRxConfigNrbdShift = 20, FhRxConfigRbTimeoutShift= 4, FhRxStatus = 0x1c44, FhTxConfig = 0x1d00, // +q*32 FhTxConfigDmaCreditEna = 1<<3, FhTxConfigDmaEna = 1<<31, FhTxConfigCirqHostEndTfd= 1<<20, FhTxBufStatus = 0x1d08, // +q*32 FhTxBufStatusTbNumShift = 20, FhTxBufStatusTbIdxShift = 12, FhTxBufStatusTfbdValid = 3, FhTxChicken = 0x1e98, FhTxStatus = 0x1eb0, }; /* * NIC internal memory offsets. */ enum { ApmgClkCtrl = 0x3000, ApmgClkEna = 0x3004, ApmgClkDis = 0x3008, DmaClkRqt = 1<<9, BsmClkRqt = 1<<11, ApmgPs = 0x300c, EarlyPwroffDis = 1<<22, PwrSrcVMain = 0<<24, PwrSrcVAux = 2<<24, PwrSrcMask = 3<<24, ResetReq = 1<<26, ApmgDigitalSvr = 0x3058, ApmgAnalogSvr = 0x306c, ApmgPciStt = 0x3010, BsmWrCtrl = 0x3400, BsmWrMemSrc = 0x3404, BsmWrMemDst = 0x3408, BsmWrDwCount = 0x340c, BsmDramTextAddr = 0x3490, BsmDramTextSize = 0x3494, BsmDramDataAddr = 0x3498, BsmDramDataSize = 0x349c, BsmSramBase = 0x3800, }; /* * TX scheduler registers. */ enum { SchedBase = 0xa02c00, SchedSramAddr = SchedBase, SchedDramAddr4965 = SchedBase+0x010, SchedTxFact4965 = SchedBase+0x01c, SchedQueueRdptr4965 = SchedBase+0x064, // +q*4 SchedQChainSel4965 = SchedBase+0x0d0, SchedIntrMask4965 = SchedBase+0x0e4, SchedQueueStatus4965 = SchedBase+0x104, // +q*4 SchedDramAddr5000 = SchedBase+0x008, SchedTxFact5000 = SchedBase+0x010, SchedQueueRdptr5000 = SchedBase+0x068, // +q*4 SchedQChainSel5000 = SchedBase+0x0e8, SchedIntrMask5000 = SchedBase+0x108, SchedQueueStatus5000 = SchedBase+0x10c, // +q*4 SchedAggrSel5000 = SchedBase+0x248, }; enum { SchedCtxOff4965 = 0x380, SchedCtxLen4965 = 416, SchedCtxOff5000 = 0x600, SchedCtxLen5000 = 512, }; enum { FilterPromisc = 1<<0, FilterCtl = 1<<1, FilterMulticast = 1<<2, FilterNoDecrypt = 1<<3, FilterBSS = 1<<5, FilterBeacon = 1<<6, }; enum { RFlag24Ghz = 1<<0, RFlagCCK = 1<<1, RFlagAuto = 1<<2, RFlagShSlot = 1<<4, RFlagShPreamble = 1<<5, RFlagNoDiversity = 1<<7, RFlagAntennaA = 1<<8, RFlagAntennaB = 1<<9, RFlagTSF = 1<<15, RFlagCTSToSelf = 1<<30, }; typedef struct FWInfo FWInfo; typedef struct FWImage FWImage; typedef struct FWSect FWSect; typedef struct TXQ TXQ; typedef struct RXQ RXQ; typedef struct Ctlr Ctlr; struct FWSect { uchar *data; uint size; }; struct FWImage { struct { FWSect text; FWSect data; } init, main, boot; uint rev; uint build; char descr[64+1]; uchar data[]; }; struct FWInfo { uchar major; uchar minjor; uchar type; uchar subtype; u32int logptr; u32int errptr; u32int tstamp; u32int valid; }; struct TXQ { uint n; uint i; Block **b; uchar *d; uchar *c; uint lastcmd; Rendez; QLock; }; struct RXQ { uint i; Block **b; u32int *p; uchar *s; }; struct Ctlr { Lock; QLock; Ctlr *link; Pcidev *pdev; Wifi *wifi; int type; int port; int power; int active; int broken; int attached; u32int ie; u32int *nic; uchar *kwpage; /* assigned node ids in hardware node table or -1 if unassigned */ int bcastnodeid; int bssnodeid; /* current receiver settings */ uchar bssid[Eaddrlen]; int channel; int prom; int aid; RXQ rx; TXQ tx[20]; struct { Rendez; u32int m; u32int w; } wait; struct { uchar type; uchar step; uchar dash; uchar txantmask; uchar rxantmask; } rfcfg; struct { int otp; uint off; uchar version; uchar type; u16int volt; u16int temp; u16int rawtemp; char regdom[4+1]; u32int crystal; } eeprom; struct { Block *cmd[21]; int done; } calib; struct { u32int base; uchar *s; } sched; FWInfo fwinfo; FWImage *fw; }; /* controller types */ enum { Type4965 = 0, Type5300 = 2, Type5350 = 3, Type5150 = 4, Type5100 = 5, Type1000 = 6, Type6000 = 7, Type6050 = 8, Type6005 = 11, Type2030 = 12, }; static char *fwname[16] = { [Type4965] "iwn-4965", [Type5300] "iwn-5000", [Type5350] "iwn-5000", [Type5150] "iwn-5150", [Type5100] "iwn-5000", [Type1000] "iwn-1000", [Type6000] "iwn-6000", [Type6050] "iwn-6050", [Type6005] "iwn-6005", [Type2030] "iwn-2030", }; static char *qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block); static char *flushq(Ctlr *ctlr, uint qid); static char *cmd(Ctlr *ctlr, uint code, uchar *data, int size); #define csr32r(c, r) (*((c)->nic+((r)/4))) #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v)) static uint get16(uchar *p){ return *((u16int*)p); } static uint get32(uchar *p){ return *((u32int*)p); } static void put32(uchar *p, uint v){ *((u32int*)p) = v; } static void put16(uchar *p, uint v){ *((u16int*)p) = v; }; static char* niclock(Ctlr *ctlr) { int i; csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq); for(i=0; i<1000; i++){ if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna) return 0; delay(10); } return "niclock: timeout"; } static void nicunlock(Ctlr *ctlr) { csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~MacAccessReq); } static u32int prphread(Ctlr *ctlr, uint off) { csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); return csr32r(ctlr, PrphRdata); } static void prphwrite(Ctlr *ctlr, uint off, u32int data) { csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); csr32w(ctlr, PrphWdata, data); } static u32int memread(Ctlr *ctlr, uint off) { csr32w(ctlr, MemRaddr, off); coherence(); return csr32r(ctlr, MemRdata); } static void memwrite(Ctlr *ctlr, uint off, u32int data) { csr32w(ctlr, MemWaddr, off); coherence(); csr32w(ctlr, MemWdata, data); } static void setfwinfo(Ctlr *ctlr, uchar *d, int len) { FWInfo *i; if(len < 32) return; i = &ctlr->fwinfo;