#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-
-#include "etherif.h"
-#include "wifi.h"
+#include "../port/etherif.h"
+#include "../port/wifi.h"
enum {
+ MaxQueue = 24*1024, /* total buffer is 2*MaxQueue: 48k at 22Mbit ≅ 20ms */
Ntxlog = 8,
Ntx = 1<<Ntxlog,
+ Ntxqmax = MaxQueue/1500,
+
Nrxlog = 8,
Nrx = 1<<Nrxlog,
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,
Gio = 0x03c,
EnaL0S = 1<<1,
+ GpDrv = 0x050,
+ GpDrvCalV6 = 1<<2,
+ GpDrv1X2 = 1<<3,
+ GpDrvRadioIqInvert = 1<<7,
+
Led = 0x094,
LedBsmCtrl = 1<<5,
LedOn = 0x38,
AnaPll = 0x20c,
Dbghpetmem = 0x240,
+ Dbglinkpwrmgmt = 0x250,
MemRaddr = 0x40c,
MemWaddr = 0x410,
enum {
SchedBase = 0xa02c00,
SchedSramAddr = SchedBase,
- SchedDramAddr5000 = SchedBase+0x008,
+
SchedDramAddr4965 = SchedBase+0x010,
- SchedTxFact5000 = SchedBase+0x010,
SchedTxFact4965 = SchedBase+0x01c,
SchedQueueRdptr4965 = SchedBase+0x064, // +q*4
- SchedQueueRdptr5000 = SchedBase+0x068, // +q*4
SchedQChainSel4965 = SchedBase+0x0d0,
SchedIntrMask4965 = SchedBase+0x0e4,
- SchedQChainSel5000 = SchedBase+0x0e8,
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,
- SchedTransTblOff4965 = 0x500,
SchedCtxOff5000 = 0x600,
SchedCtxLen5000 = 512,
- SchedTransTblOff5000 = 0x7e0,
};
-/* controller types */
enum {
- Type4965 = 0,
- Type5300 = 2,
- Type5350 = 3,
- Type5150 = 4,
- Type5100 = 5,
- Type1000 = 6,
- Type6000 = 7,
- Type6050 = 8,
- Type6005 = 11,
+ 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;
uchar *d;
uchar *c;
+ uint lastcmd;
+
Rendez;
QLock;
};
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];
Rendez;
u32int m;
u32int w;
- u32int r;
} wait;
struct {
} 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;
FWImage *fw;
};
+/* controller types */
+enum {
+ Type4965 = 0,
+ Type5300 = 2,
+ Type5350 = 3,
+ Type5150 = 4,
+ Type5100 = 5,
+ Type1000 = 6,
+ Type6000 = 7,
+ Type6050 = 8,
+ Type6005 = 11, /* also Centrino Advanced-N 6030, 6235 */
+ Type2030 = 12,
+ Type2000 = 16,
+};
+
+static char *fwname[32] = {
+ [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", /* see in iwlattach() below */
+ [Type2030] "iwn-2030",
+ [Type2000] "iwn-2000",
+};
+
+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))
u32int dump[13];
int i;
+ print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
if(ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
return;
eepromread(Ctlr *ctlr, void *data, int count, uint off)
{
uchar *out = data;
- u32int w;
+ u32int w, s;
int i;
w = 0;
+ off += ctlr->eeprom.off;
for(; count > 0; count -= 2, off++){
csr32w(ctlr, EepromIo, off << 2);
for(i=0; i<10; i++){
}
if(i == 10)
return "eepromread: timeout";
+ if(ctlr->eeprom.otp){
+ s = csr32r(ctlr, OtpromGp);
+ if(s & EccUncorrStts)
+ return "eepromread: otprom ecc error";
+ if(s & EccCorrStts)
+ csr32w(ctlr, OtpromGp, s);
+ }
*out++ = w >> 16;
if(count > 1)
*out++ = w >> 24;
prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
nicunlock(ctlr);
+
+ ctlr->power = 1;
+
return 0;
}
+static void
+poweroff(Ctlr *ctlr)
+{
+ int i, j;
+
+ csr32w(ctlr, Reset, 1);
+
+ /* Disable interrupts */
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ /* Stop scheduler */
+ if(ctlr->type != Type4965)
+ prphwrite(ctlr, SchedTxFact5000, 0);
+ else
+ prphwrite(ctlr, SchedTxFact4965, 0);
+
+ /* Stop TX ring */
+ if(niclock(ctlr) == nil){
+ for(i = (ctlr->type != Type4965) ? 7 : 6; i >= 0; i--){
+ csr32w(ctlr, FhTxConfig + i*32, 0);
+ for(j = 0; j < 200; j++){
+ if(csr32r(ctlr, FhTxStatus) & (0x10000<<i))
+ break;
+ delay(10);
+ }
+ }
+ nicunlock(ctlr);
+ }
+
+ /* Stop RX ring */
+ if(niclock(ctlr) == nil){
+ csr32w(ctlr, FhRxConfig, 0);
+ for(j = 0; j < 200; j++){
+ if(csr32r(ctlr, FhRxStatus) & 0x1000000)
+ break;
+ delay(10);
+ }
+ nicunlock(ctlr);
+ }
+
+ /* Disable DMA */
+ if(niclock(ctlr) == nil){
+ prphwrite(ctlr, ApmgClkDis, DmaClkRqt);
+ nicunlock(ctlr);
+ }
+ delay(5);
+
+ /* Stop busmaster DMA activity. */
+ csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<9));
+ for(j = 0; j < 100; j++){
+ if(csr32r(ctlr, Reset) & (1<<8))
+ break;
+ delay(10);
+ }
+
+ /* Reset the entire device. */
+ csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<7));
+ delay(10);
+
+ /* Clear "initialization complete" bit. */
+ csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~InitDone);
+
+ ctlr->power = 0;
+}
+
+static char*
+rominit(Ctlr *ctlr)
+{
+ uint prev, last;
+ uchar buf[2];
+ char *err;
+ int i;
+
+ ctlr->eeprom.otp = 0;
+ ctlr->eeprom.off = 0;
+ if(ctlr->type < Type1000 || (csr32r(ctlr, OtpromGp) & DevSelOtp) == 0)
+ return nil;
+
+ /* Wait for clock stabilization before accessing prph. */
+ if((err = clockwait(ctlr)) != nil)
+ return err;
+
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | ResetReq);
+ delay(5);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) & ~ResetReq);
+ nicunlock(ctlr);
+
+ /* Set auto clock gate disable bit for HW with OTP shadow RAM. */
+ if(ctlr->type != Type1000)
+ csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31));
+
+ csr32w(ctlr, EepromGp, csr32r(ctlr, EepromGp) & ~0x00000180);
+
+ /* Clear ECC status. */
+ csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) | (EccCorrStts | EccUncorrStts));
+
+ ctlr->eeprom.otp = 1;
+ if(ctlr->type != Type1000)
+ return nil;
+
+ /* Switch to absolute addressing mode. */
+ csr32w(ctlr, OtpromGp, csr32r(ctlr, OtpromGp) & ~RelativeAccess);
+
+ /*
+ * Find the block before last block (contains the EEPROM image)
+ * for HW without OTP shadow RAM.
+ */
+ prev = last = 0;
+ for(i=0; i<3; i++){
+ if((err = eepromread(ctlr, buf, 2, last)) != nil)
+ return err;
+ if(get16(buf) == 0)
+ break;
+ prev = last;
+ last = get16(buf);
+ }
+ if(i == 0 || i >= 3)
+ return "rominit: missing eeprom image";
+
+ ctlr->eeprom.off = prev+1;
+ return nil;
+}
+
static int
iwlinit(Ether *edev)
{
Ctlr *ctlr;
char *err;
- uchar b[2];
- uint u;
+ uchar b[4];
+ uint u, caloff, regoff;
ctlr = edev->ctlr;
+
+ /* Clear device-specific "PCI retry timeout" register (41h). */
+ if(pcicfgr8(ctlr->pdev, 0x41) != 0)
+ pcicfgw8(ctlr->pdev, 0x41, 0);
+
+ /* Clear interrupt disable bit. Hardware bug workaround. */
+ if(ctlr->pdev->pcr & 0x400){
+ ctlr->pdev->pcr &= ~0x400;
+ pcicfgw16(ctlr->pdev, PciPCR, ctlr->pdev->pcr);
+ }
+
+ ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0x1F;
+ if(fwname[ctlr->type] == nil){
+ print("iwl: unsupported controller type %d\n", ctlr->type);
+ return -1;
+ }
+
if((err = handover(ctlr)) != nil)
goto Err;
if((err = poweron(ctlr)) != nil)
}
if((err = eepromlock(ctlr)) != nil)
goto Err;
+ if((err = rominit(ctlr)) != nil)
+ goto Err2;
if((err = eepromread(ctlr, edev->ea, sizeof(edev->ea), 0x15)) != nil){
eepromunlock(ctlr);
goto Err;
}
if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
+ Err2:
eepromunlock(ctlr);
goto Err;
}
ctlr->rfcfg.dash = u & 3; u >>= 4;
ctlr->rfcfg.txantmask = u & 15; u >>= 4;
ctlr->rfcfg.rxantmask = u & 15;
- if((err = eepromread(ctlr, b, 4, 0x128)) != nil){
- eepromunlock(ctlr);
- goto Err;
+ if((err = eepromread(ctlr, b, 2, 0x66)) != nil)
+ goto Err2;
+ regoff = get16(b);
+ if((err = eepromread(ctlr, b, 4, regoff+1)) != nil)
+ goto Err2;
+ strncpy(ctlr->eeprom.regdom, (char*)b, 4);
+ ctlr->eeprom.regdom[4] = 0;
+ if((err = eepromread(ctlr, b, 2, 0x67)) != nil)
+ goto Err2;
+ caloff = get16(b);
+ if((err = eepromread(ctlr, b, 4, caloff)) != nil)
+ goto Err2;
+ ctlr->eeprom.version = b[0];
+ ctlr->eeprom.type = b[1];
+ ctlr->eeprom.volt = get16(b+2);
+
+ ctlr->eeprom.temp = 0;
+ ctlr->eeprom.rawtemp = 0;
+ if(ctlr->type == Type2030 || ctlr->type == Type2000){
+ if((err = eepromread(ctlr, b, 2, caloff + 0x12a)) != nil)
+ goto Err2;
+ ctlr->eeprom.temp = get16(b);
+ if((err = eepromread(ctlr, b, 2, caloff + 0x12b)) != nil)
+ goto Err2;
+ ctlr->eeprom.rawtemp = get16(b);
}
- ctlr->eeprom.crystal = get32(b);
- eepromunlock(ctlr);
- ctlr->ie = 0;
- csr32w(ctlr, Isr, ~0); /* clear pending interrupts */
- csr32w(ctlr, Imr, 0); /* no interrupts for now */
+ if(ctlr->type != Type4965 && ctlr->type != Type5150){
+ if((err = eepromread(ctlr, b, 4, caloff + 0x128)) != nil)
+ goto Err2;
+ ctlr->eeprom.crystal = get32(b);
+ }
+ eepromunlock(ctlr);
+ switch(ctlr->type){
+ case Type4965:
+ ctlr->rfcfg.txantmask = 3;
+ ctlr->rfcfg.rxantmask = 7;
+ break;
+ case Type5100:
+ ctlr->rfcfg.txantmask = 2;
+ ctlr->rfcfg.rxantmask = 3;
+ break;
+ case Type6000:
+ if(ctlr->pdev->did == 0x422c || ctlr->pdev->did == 0x4230){
+ ctlr->rfcfg.txantmask = 6;
+ ctlr->rfcfg.rxantmask = 6;
+ }
+ break;
+ }
+ poweroff(ctlr);
return 0;
Err:
print("iwlinit: %s\n", err);
+ poweroff(ctlr);
return -1;
}
return "bad firmware signature";
p += 4;
strncpy(i->descr, (char*)p, 64);
- i->descr[sizeof(i->descr)-1] = 0;
+ i->descr[64] = 0;
p += 64;
i->rev = get32(p); p += 4;
i->build = get32(p); p += 4;
default:s = &dummy;
}
p += 2;
- if(get16(p) != alt)
+ if(get16(p) != 0 && get16(p) != alt)
s = &dummy;
p += 2;
s->size = get32(p); p += 4;
return fw;
}
-typedef struct Irqwait Irqwait;
-struct Irqwait {
- Ctlr *ctlr;
- u32int mask;
-};
static int
gotirq(void *arg)
{
- Irqwait *w;
- Ctlr *ctlr;
-
- w = arg;
- ctlr = w->ctlr;
- ctlr->wait.r = ctlr->wait.m & w->mask;
- if(ctlr->wait.r){
- ctlr->wait.m &= ~ctlr->wait.r;
- return 1;
- }
- ctlr->wait.w = w->mask;
- return 0;
+ Ctlr *ctlr = arg;
+ return (ctlr->wait.m & ctlr->wait.w) != 0;
}
static u32int
irqwait(Ctlr *ctlr, u32int mask, int timeout)
{
- Irqwait w;
-
- w.ctlr = ctlr;
- w.mask = mask;
- tsleep(&ctlr->wait, gotirq, &w, timeout);
- ctlr->wait.w = 0;
- return ctlr->wait.r & mask;
-}
-
-static char*
-loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
-{
- uchar *dma;
- char *err;
+ u32int r;
- dma = mallocalign(size, 16, 0, 0);
- if(dma == nil)
- return "no memory for dma";
- memmove(dma, data, size);
- coherence();
- if((err = niclock(ctlr)) != 0){
- free(dma);
- return err;
- }
- csr32w(ctlr, FhTxConfig + 9*32, 0);
- csr32w(ctlr, FhSramAddr + 9*4, dst);
- csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
- csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
- csr32w(ctlr, FhTxBufStatus + 9*32,
- (1<<FhTxBufStatusTbNumShift) |
- (1<<FhTxBufStatusTbIdxShift) |
- FhTxBufStatusTfbdValid);
- csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
- nicunlock(ctlr);
- if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
- free(dma);
- return "dma error / timeout";
+ ilock(ctlr);
+ r = ctlr->wait.m & mask;
+ if(r == 0){
+ ctlr->wait.w = mask;
+ iunlock(ctlr);
+ if(!waserror()){
+ tsleep(&ctlr->wait, gotirq, ctlr, timeout);
+ poperror();
+ }
+ ilock(ctlr);
+ ctlr->wait.w = 0;
+ r = ctlr->wait.m & mask;
}
- free(dma);
- return 0;
+ ctlr->wait.m &= ~r;
+ iunlock(ctlr);
+ return r;
}
static int
-txqready(void *arg)
+rbplant(Ctlr *ctlr, int i)
{
- TXQ *q = arg;
- return q->n < Ntx;
+ Block *b;
+
+ b = iallocb(Rbufsize + 256);
+ if(b == nil)
+ return -1;
+ b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
+ memset(b->rp, 0, Rdscsize);
+ ctlr->rx.b[i] = b;
+ ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
+ return 0;
}
-static void
-qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
+static char*
+initring(Ctlr *ctlr)
{
- uchar *d, *c;
- TXQ *q;
-
- assert(qid < nelem(ctlr->tx));
- assert(size <= Tcmdsize-4);
+ RXQ *rx;
+ TXQ *tx;
+ int i, q;
- ilock(ctlr);
- q = &ctlr->tx[qid];
- while(q->n >= Ntx){
- iunlock(ctlr);
- eqlock(q);
- if(waserror()){
- qunlock(q);
- nexterror();
+ rx = &ctlr->rx;
+ if(rx->b == nil)
+ rx->b = malloc(sizeof(Block*) * Nrx);
+ if(rx->p == nil)
+ rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
+ if(rx->s == nil)
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
+ if(rx->b == nil || rx->p == nil || rx->s == nil)
+ return "no memory for rx ring";
+ memset(ctlr->rx.s, 0, Rstatsize);
+ for(i=0; i<Nrx; i++){
+ rx->p[i] = 0;
+ if(rx->b[i] != nil){
+ freeb(rx->b[i]);
+ rx->b[i] = nil;
}
- tsleep(q, txqready, q, 10);
- qunlock(q);
- ilock(ctlr);
+ if(rbplant(ctlr, i) < 0)
+ return "no memory for rx descriptors";
}
- q->n++;
-
- q->b[q->i] = block;
- c = q->c + q->i * Tcmdsize;
- d = q->d + q->i * Tdscsize;
-
- /* build command */
- c[0] = code;
- c[1] = 0; /* flags */
- c[2] = q->i;
- c[3] = qid;
-
- memmove(c+4, data, size);
+ rx->i = 0;
- size += 4;
+ if(ctlr->sched.s == nil)
+ ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
+ if(ctlr->sched.s == nil)
+ return "no memory for sched buffer";
+ memset(ctlr->sched.s, 0, 512 * nelem(ctlr->tx));
- /* build descriptor */
- *d++ = 0;
- *d++ = 0;
- *d++ = 0;
- *d++ = 1 + (block != nil); /* nsegs */
- put32(d, PCIWADDR(c)); d += 4;
- put16(d, size << 4); d += 2;
- if(block != nil){
- size = BLEN(block);
- if(size > Tbufsize)
- size = Tbufsize;
- put32(d, PCIWADDR(block->rp)); d += 4;
- put16(d, size << 4);
+ for(q=0; q<nelem(ctlr->tx); q++){
+ tx = &ctlr->tx[q];
+ if(tx->b == nil)
+ tx->b = malloc(sizeof(Block*) * Ntx);
+ if(tx->d == nil)
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
+ if(tx->c == nil)
+ tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
+ if(tx->b == nil || tx->d == nil || tx->c == nil)
+ return "no memory for tx ring";
+ memset(tx->d, 0, Tdscsize * Ntx);
+ memset(tx->c, 0, Tcmdsize * Ntx);
+ for(i=0; i<Ntx; i++){
+ if(tx->b[i] != nil){
+ freeb(tx->b[i]);
+ tx->b[i] = nil;
+ }
+ }
+ tx->i = 0;
+ tx->n = 0;
+ tx->lastcmd = 0;
}
- coherence();
-
- q->i = (q->i+1) % Ntx;
- csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
+ if(ctlr->kwpage == nil)
+ ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->kwpage == nil)
+ return "no memory for kwpage";
+ memset(ctlr->kwpage, 0, 4096);
- iunlock(ctlr);
+ return nil;
}
-static void
-cmd(Ctlr *ctlr, uint code, uchar *data, int size)
+static char*
+reset(Ctlr *ctlr)
{
- qcmd(ctlr, 4, code, data, size, nil);
-}
+ char *err;
+ int i, q;
-static void
-setled(Ctlr *ctlr, int which, int on, int off)
-{
- uchar c[8];
+ if(ctlr->power)
+ poweroff(ctlr);
+ if((err = initring(ctlr)) != nil)
+ return err;
+ if((err = poweron(ctlr)) != nil)
+ return err;
- csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
+ nicunlock(ctlr);
- memset(c, 0, sizeof(c));
- put32(c, 10000);
- c[4] = which;
- c[5] = on;
- c[6] = off;
- cmd(ctlr, 72, c, sizeof(c));
-}
+ csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
-/*
- * initialization which runs after the firmware has been booted up
- */
-static void
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ if(ctlr->type != Type4965)
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ if(ctlr->type == Type1000){
+ /*
+ * Select first Switching Voltage Regulator (1.32V) to
+ * solve a stability issue related to noisy DC2DC line
+ * in the silicon of 1000 Series.
+ */
+ prphwrite(ctlr, ApmgDigitalSvr,
+ (prphread(ctlr, ApmgDigitalSvr) & ~(0xf<<5)) | (3<<5));
+ }
+ nicunlock(ctlr);
+
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ if((ctlr->type == Type6005 || ctlr->type == Type6050) && ctlr->eeprom.version == 6)
+ csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrvCalV6);
+ if(ctlr->type == Type6005)
+ csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrv1X2);
+ if(ctlr->type == Type2030 || ctlr->type == Type2000)
+ csr32w(ctlr, GpDrv, csr32r(ctlr, GpDrv) | GpDrvRadioIqInvert);
+ nicunlock(ctlr);
+
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ csr32w(ctlr, FhRxConfig, 0);
+ csr32w(ctlr, FhRxWptr, 0);
+ csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
+ csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
+ csr32w(ctlr, FhRxConfig,
+ FhRxConfigEna |
+ FhRxConfigIgnRxfEmpty |
+ FhRxConfigIrqDstHost |
+ FhRxConfigSingleFrame |
+ (Nrxlog << FhRxConfigNrbdShift));
+ csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
+ nicunlock(ctlr);
+
+ if((err = niclock(ctlr)) != nil)
+ return err;
+ if(ctlr->type != Type4965)
+ prphwrite(ctlr, SchedTxFact5000, 0);
+ else
+ prphwrite(ctlr, SchedTxFact4965, 0);
+ csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
+ for(q = (ctlr->type != Type4965) ? 19 : 15; q >= 0; q--)
+ csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
+ nicunlock(ctlr);
+
+ for(i = (ctlr->type != Type4965) ? 7 : 6; i >= 0; i--)
+ csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
+
+ csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
+ csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
+
+ ctlr->broken = 0;
+ ctlr->wait.m = 0;
+ ctlr->wait.w = 0;
+
+ ctlr->ie = Idefmask;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+
+ if(ctlr->type >= Type6000)
+ csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
+
+ return nil;
+}
+
+static char*
+sendbtcoexadv(Ctlr *ctlr)
+{
+ static u32int btcoex3wire[12] = {
+ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+ 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa,
+ 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
+ };
+
+ uchar c[Tcmdsize], *p;
+ char *err;
+ int i;
+
+ /* set BT config */
+ memset(c, 0, sizeof(c));
+ p = c;
+
+ if(ctlr->type == Type2030){
+ *p++ = 145; /* flags */
+ p++; /* lead time */
+ *p++ = 5; /* max kill */
+ *p++ = 1; /* bt3 t7 timer */
+ put32(p, 0xffff0000); /* kill ack */
+ p += 4;
+ put32(p, 0xffff0000); /* kill cts */
+ p += 4;
+ *p++ = 2; /* sample time */
+ *p++ = 0xc; /* bt3 t2 timer */
+ p += 2; /* bt4 reaction */
+ for (i = 0; i < nelem(btcoex3wire); i++){
+ put32(p, btcoex3wire[i]);
+ p += 4;
+ }
+ p += 2; /* bt4 decision */
+ put16(p, 0xff); /* valid */
+ p += 2;
+ put32(p, 0xf0); /* prio boost */
+ p += 4;
+ p++; /* reserved */
+ p++; /* tx prio boost */
+ p += 2; /* rx prio boost */
+ }
+ if((err = cmd(ctlr, 155, c, p-c)) != nil)
+ return err;
+
+ /* set BT priority */
+ memset(c, 0, sizeof(c));
+ p = c;
+
+ *p++ = 0x6; /* init1 */
+ *p++ = 0x7; /* init2 */
+ *p++ = 0x2; /* periodic low1 */
+ *p++ = 0x3; /* periodic low2 */
+ *p++ = 0x4; /* periodic high1 */
+ *p++ = 0x5; /* periodic high2 */
+ *p++ = 0x6; /* dtim */
+ *p++ = 0x8; /* scan52 */
+ *p++ = 0xa; /* scan24 */
+ p += 7; /* reserved */
+ if((err = cmd(ctlr, 204, c, p-c)) != nil)
+ return err;
+
+ /* force BT state machine change */
+ memset(c, 0, sizeof(c));
+ p = c;
+
+ *p++ = 1; /* open */
+ *p++ = 1; /* type */
+ p += 2; /* reserved */
+ if((err = cmd(ctlr, 205, c, p-c)) != nil)
+ return err;
+
+ c[0] = 0; /* open */
+ return cmd(ctlr, 205, c, p-c);
+}
+
+static char*
postboot(Ctlr *ctlr)
{
- uchar c[8];
+ uint ctxoff, ctxlen, dramaddr;
char *err;
int i, q;
- /* main led turn on! (verify that firmware processes commands) */
- setled(ctlr, 2, 0, 1);
-
if((err = niclock(ctlr)) != nil)
- error(err);
+ return err;
+
+ if(ctlr->type != Type4965){
+ dramaddr = SchedDramAddr5000;
+ ctxoff = SchedCtxOff5000;
+ ctxlen = SchedCtxLen5000;
+ } else {
+ dramaddr = SchedDramAddr4965;
+ ctxoff = SchedCtxOff4965;
+ ctxlen = SchedCtxLen4965;
+ }
+
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
- for(i=0; i < SchedCtxLen5000/4; i++)
- memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + i*4, 0);
+ for(i=0; i < ctxlen; i += 4)
+ memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
+
+ prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- prphwrite(ctlr, SchedDramAddr5000, PCIWADDR(ctlr->sched.s)>>10);
csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
- /* Enable chain mode for all queues, except command queue. */
- prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
- prphwrite(ctlr, SchedAggrSel5000, 0);
+ if(ctlr->type != Type4965){
+ /* Enable chain mode for all queues, except command queue 4. */
+ prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
+ prphwrite(ctlr, SchedAggrSel5000, 0);
- for(q=0; q<nelem(ctlr->tx); q++){
- prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
- csr32w(ctlr, HbusTargWptr, q << 8);
- memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8, 0);
- /* Set scheduler window size and frame limit. */
- memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + q*8 + 4, 64<<16 | 64);
+ for(q=0; q<20; q++){
+ prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
+ csr32w(ctlr, HbusTargWptr, q << 8);
+
+ memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 0);
+ /* Set scheduler window size and frame limit. */
+ memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16 | 64);
+ }
+ /* Enable interrupts for all our 20 queues. */
+ prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
+
+ /* Identify TX FIFO rings (0-7). */
+ prphwrite(ctlr, SchedTxFact5000, 0xff);
+ } else {
+ /* Disable chain mode for all our 16 queues. */
+ prphwrite(ctlr, SchedQChainSel4965, 0);
+
+ for(q=0; q<16; q++) {
+ prphwrite(ctlr, SchedQueueRdptr4965 + q*4, 0);
+ csr32w(ctlr, HbusTargWptr, q << 8);
+
+ /* Set scheduler window size. */
+ memwrite(ctlr, ctlr->sched.base + ctxoff + q*8, 64);
+ /* Set scheduler window size and frame limit. */
+ memwrite(ctlr, ctlr->sched.base + ctxoff + q*8 + 4, 64<<16);
+ }
+ /* Enable interrupts for all our 16 queues. */
+ prphwrite(ctlr, SchedIntrMask4965, 0xffff);
+
+ /* Identify TX FIFO rings (0-7). */
+ prphwrite(ctlr, SchedTxFact4965, 0xff);
}
- /* Enable interrupts for all our 20 queues. */
- prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
- /* Identify TX FIFO rings (0-7). */
- prphwrite(ctlr, SchedTxFact5000, 0xff);
/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
for(q=0; q<7; q++){
- static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
- prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
+ if(ctlr->type != Type4965){
+ static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
+ prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
+ } else {
+ static uchar qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 };
+ prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]<<1);
+ }
}
nicunlock(ctlr);
- if(ctlr->type != Type5150){
+ if(ctlr->type != Type4965){
+ uchar c[Tcmdsize];
+
+ /* disable wimax coexistance */
memset(c, 0, sizeof(c));
- c[0] = 15; /* code */
- c[1] = 0; /* grup */
- c[2] = 1; /* ngroup */
- c[3] = 1; /* isvalid */
- put16(c+4, ctlr->eeprom.crystal);
- cmd(ctlr, 176, c, 8);
+ if((err = cmd(ctlr, 90, c, 4+4*16)) != nil)
+ return err;
+
+ if(ctlr->type != Type5150){
+ /* calibrate crystal */
+ memset(c, 0, sizeof(c));
+ c[0] = 15; /* code */
+ c[1] = 0; /* group */
+ c[2] = 1; /* ngroup */
+ c[3] = 1; /* isvalid */
+ c[4] = ctlr->eeprom.crystal;
+ c[5] = ctlr->eeprom.crystal>>16;
+ /* for some reason 8086:4238 needs a second try */
+ if(cmd(ctlr, 176, c, 8) != nil && (err = cmd(ctlr, 176, c, 8)) != nil)
+ return err;
+ }
+
+ if(ctlr->calib.done == 0){
+ /* query calibration (init firmware) */
+ memset(c, 0, sizeof(c));
+ put32(c + 0*(5*4) + 0, 0xffffffff);
+ put32(c + 0*(5*4) + 4, 0xffffffff);
+ put32(c + 0*(5*4) + 8, 0xffffffff);
+ put32(c + 2*(5*4) + 0, 0xffffffff);
+ if((err = cmd(ctlr, 101, c, (((2*(5*4))+4)*2)+4)) != nil)
+ return err;
+
+ /* wait to collect calibration records */
+ if(irqwait(ctlr, Ierr, 2000))
+ return "calibration failed";
+
+ if(ctlr->calib.done == 0){
+ print("iwl: no calibration results\n");
+ ctlr->calib.done = 1;
+ }
+ } else {
+ static uchar cmds[] = {8, 9, 11, 17, 16};
+
+ /* send calibration records (runtime firmware) */
+ for(q=0; q<nelem(cmds); q++){
+ Block *b;
+
+ i = cmds[q];
+ if(i == 8 && ctlr->type != Type5150 && ctlr->type != Type2030 &&
+ ctlr->type != Type2000)
+ continue;
+ if(i == 17 && (ctlr->type >= Type6000 || ctlr->type == Type5150) &&
+ ctlr->type != Type2030 && ctlr->type != Type2000)
+ continue;
+
+ if((b = ctlr->calib.cmd[i]) == nil)
+ continue;
+ b = copyblock(b, BLEN(b));
+ if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ freeb(b);
+ return err;
+ }
+ if((err = flushq(ctlr, 4)) != nil)
+ return err;
+ }
+
+ /* temperature sensor offset */
+ switch (ctlr->type){
+ case Type6005:
+ memset(c, 0, sizeof(c));
+ c[0] = 18;
+ c[1] = 0;
+ c[2] = 1;
+ c[3] = 1;
+ put16(c + 4, 2700);
+ if((err = cmd(ctlr, 176, c, 4+2+2)) != nil)
+ return err;
+ break;
+
+ case Type2030:
+ case Type2000:
+ memset(c, 0, sizeof(c));
+ c[0] = 18;
+ c[1] = 0;
+ c[2] = 1;
+ c[3] = 1;
+ if(ctlr->eeprom.rawtemp != 0){
+ put16(c + 4, ctlr->eeprom.temp);
+ put16(c + 6, ctlr->eeprom.rawtemp);
+ } else{
+ put16(c + 4, 2700);
+ put16(c + 6, 2700);
+ }
+ put16(c + 8, ctlr->eeprom.volt);
+ if((err = cmd(ctlr, 176, c, 4+2+2+2+2)) != nil)
+ return err;
+ break;
+ }
+
+ if(ctlr->type == Type6005 || ctlr->type == Type6050){
+ /* runtime DC calibration */
+ memset(c, 0, sizeof(c));
+ put32(c + 0*(5*4) + 0, 0xffffffff);
+ put32(c + 0*(5*4) + 4, 1<<1);
+ if((err = cmd(ctlr, 101, c, (((2*(5*4))+4)*2)+4)) != nil)
+ return err;
+ }
+
+ /* set tx antenna config */
+ put32(c, ctlr->rfcfg.txantmask & 7);
+ if((err = cmd(ctlr, 152, c, 4)) != nil)
+ return err;
+
+ if(ctlr->type == Type2030){
+ if((err = sendbtcoexadv(ctlr)) != nil)
+ return err;
+ }
+ }
}
- if(ctlr->type != Type4965){
- put32(c, ctlr->rfcfg.txantmask & 7);
- cmd(ctlr, 152, c, 4);
+ return nil;
+}
+
+static char*
+loadfirmware1(Ctlr *ctlr, u32int dst, uchar *data, int size)
+{
+ uchar *dma;
+ char *err;
+
+ dma = mallocalign(size, 16, 0, 0);
+ if(dma == nil)
+ return "no memory for dma";
+ memmove(dma, data, size);
+ coherence();
+ if((err = niclock(ctlr)) != 0){
+ free(dma);
+ return err;
+ }
+ csr32w(ctlr, FhTxConfig + 9*32, 0);
+ csr32w(ctlr, FhSramAddr + 9*4, dst);
+ csr32w(ctlr, FhTfbdCtrl0 + 9*8, PCIWADDR(dma));
+ csr32w(ctlr, FhTfbdCtrl1 + 9*8, size);
+ csr32w(ctlr, FhTxBufStatus + 9*32,
+ (1<<FhTxBufStatusTbNumShift) |
+ (1<<FhTxBufStatusTbIdxShift) |
+ FhTxBufStatusTfbdValid);
+ csr32w(ctlr, FhTxConfig + 9*32, FhTxConfigDmaEna | FhTxConfigCirqHostEndTfd);
+ nicunlock(ctlr);
+ if(irqwait(ctlr, Ifhtx|Ierr, 5000) != Ifhtx){
+ free(dma);
+ return "dma error / timeout";
}
+ free(dma);
+ return 0;
+}
+
+static char*
+boot(Ctlr *ctlr)
+{
+ int i, n, size;
+ uchar *p, *dma;
+ FWImage *fw;
+ char *err;
+
+ fw = ctlr->fw;
+
+ if(fw->boot.text.size == 0){
+ if(ctlr->calib.done == 0){
+ if((err = loadfirmware1(ctlr, 0x00000000, fw->init.text.data, fw->init.text.size)) != nil)
+ return err;
+ if((err = loadfirmware1(ctlr, 0x00800000, fw->init.data.data, fw->init.data.size)) != nil)
+ return err;
+ csr32w(ctlr, Reset, 0);
+ if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ return "init firmware boot failed";
+ if((err = postboot(ctlr)) != nil)
+ return err;
+ if((err = reset(ctlr)) != nil)
+ return err;
+ }
+ if((err = loadfirmware1(ctlr, 0x00000000, fw->main.text.data, fw->main.text.size)) != nil)
+ return err;
+ if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
+ return err;
+ csr32w(ctlr, Reset, 0);
+ if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ return "main firmware boot failed";
+ return postboot(ctlr);
+ }
+
+ size = ROUND(fw->init.data.size, 16) + ROUND(fw->init.text.size, 16);
+ dma = mallocalign(size, 16, 0, 0);
+ if(dma == nil)
+ return "no memory for dma";
+
+ if((err = niclock(ctlr)) != nil){
+ free(dma);
+ return err;
+ }
+
+ p = dma;
+ memmove(p, fw->init.data.data, fw->init.data.size);
+ coherence();
+ prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
+ prphwrite(ctlr, BsmDramDataSize, fw->init.data.size);
+ p += ROUND(fw->init.data.size, 16);
+ memmove(p, fw->init.text.data, fw->init.text.size);
+ coherence();
+ prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
+ prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
+
+ nicunlock(ctlr);
+ if((err = niclock(ctlr)) != nil){
+ free(dma);
+ return err;
+ }
+
+ p = fw->boot.text.data;
+ n = fw->boot.text.size/4;
+ for(i=0; i<n; i++, p += 4)
+ prphwrite(ctlr, BsmSramBase+i*4, get32(p));
+
+ prphwrite(ctlr, BsmWrMemSrc, 0);
+ prphwrite(ctlr, BsmWrMemDst, 0);
+ prphwrite(ctlr, BsmWrDwCount, n);
+
+ prphwrite(ctlr, BsmWrCtrl, 1<<31);
+
+ for(i=0; i<1000; i++){
+ if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
+ break;
+ delay(10);
+ }
+ if(i == 1000){
+ nicunlock(ctlr);
+ free(dma);
+ return "bootcode timeout";
+ }
+
+ prphwrite(ctlr, BsmWrCtrl, 1<<30);
+ nicunlock(ctlr);
+
+ csr32w(ctlr, Reset, 0);
+ if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
+ free(dma);
+ return "init firmware boot failed";
+ }
+ free(dma);
+
+ size = ROUND(fw->main.data.size, 16) + ROUND(fw->main.text.size, 16);
+ dma = mallocalign(size, 16, 0, 0);
+ if(dma == nil)
+ return "no memory for dma";
+ if((err = niclock(ctlr)) != nil){
+ free(dma);
+ return err;
+ }
+ p = dma;
+ memmove(p, fw->main.data.data, fw->main.data.size);
+ coherence();
+ prphwrite(ctlr, BsmDramDataAddr, PCIWADDR(p) >> 4);
+ prphwrite(ctlr, BsmDramDataSize, fw->main.data.size);
+ p += ROUND(fw->main.data.size, 16);
+ memmove(p, fw->main.text.data, fw->main.text.size);
+ coherence();
+ prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
+ prphwrite(ctlr, BsmDramTextSize, fw->main.text.size | (1<<31));
+ nicunlock(ctlr);
+
+ if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
+ free(dma);
+ return "main firmware boot failed";
+ }
+ free(dma);
+ return postboot(ctlr);
+}
+
+static int
+txqready(void *arg)
+{
+ TXQ *q = arg;
+ return q->n < Ntxqmax;
+}
+
+static char*
+qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
+{
+ uchar *d, *c;
+ TXQ *q;
+
+ assert(qid < nelem(ctlr->tx));
+ assert(size <= Tcmdsize-4);
+
+ ilock(ctlr);
+ q = &ctlr->tx[qid];
+ while(q->n >= Ntxqmax && !ctlr->broken){
+ iunlock(ctlr);
+ qlock(q);
+ if(!waserror()){
+ tsleep(q, txqready, q, 5);
+ poperror();
+ }
+ qunlock(q);
+ ilock(ctlr);
+ }
+ if(ctlr->broken){
+ iunlock(ctlr);
+ return "qcmd: broken";
+ }
+ q->n++;
+
+ q->lastcmd = code;
+ q->b[q->i] = block;
+ c = q->c + q->i * Tcmdsize;
+ d = q->d + q->i * Tdscsize;
+
+ /* build command */
+ c[0] = code;
+ c[1] = 0; /* flags */
+ c[2] = q->i;
+ c[3] = qid;
+
+ if(size > 0)
+ memmove(c+4, data, size);
+
+ size += 4;
+
+ /* build descriptor */
+ *d++ = 0;
+ *d++ = 0;
+ *d++ = 0;
+ *d++ = 1 + (block != nil); /* nsegs */
+ put32(d, PCIWADDR(c)); d += 4;
+ put16(d, size << 4); d += 2;
+ if(block != nil){
+ size = BLEN(block);
+ put32(d, PCIWADDR(block->rp)); d += 4;
+ put16(d, size << 4);
+ }
+
+ coherence();
+
+ q->i = (q->i+1) % Ntx;
+ csr32w(ctlr, HbusTargWptr, (qid<<8) | q->i);
+
+ iunlock(ctlr);
+
+ return nil;
+}
+
+static int
+txqempty(void *arg)
+{
+ TXQ *q = arg;
+ return q->n == 0;
+}
+
+static char*
+flushq(Ctlr *ctlr, uint qid)
+{
+ TXQ *q;
+ int i;
+
+ q = &ctlr->tx[qid];
+ qlock(q);
+ for(i = 0; i < 200 && !ctlr->broken; i++){
+ if(txqempty(q)){
+ qunlock(q);
+ return nil;
+ }
+ if(!waserror()){
+ tsleep(q, txqempty, q, 10);
+ poperror();
+ }
+ }
+ qunlock(q);
+ if(ctlr->broken)
+ return "flushq: broken";
+ return "flushq: timeout";
+}
+
+static char*
+cmd(Ctlr *ctlr, uint code, uchar *data, int size)
+{
+ char *err;
+
+ if(0) print("cmd %ud\n", code);
+ if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil)
+ return err;
+ return flushq(ctlr, 4);
+}
+
+static void
+setled(Ctlr *ctlr, int which, int on, int off)
+{
+ uchar c[8];
+
+ csr32w(ctlr, Led, csr32r(ctlr, Led) & ~LedBsmCtrl);
+
+ memset(c, 0, sizeof(c));
+ put32(c, 10000);
+ c[4] = which;
+ c[5] = on;
+ c[6] = off;
+ cmd(ctlr, 72, c, sizeof(c));
}
static void
p += 8; /* tcs */
p += 8; /* rxmic */
p += 8; /* txmic */
- p += 4; /* htflags */
- p += 4; /* mask */
- p += 2; /* disable tid */
- p += 2; /* reserved */
- p++; /* add ba tid */
- p++; /* del ba tid */
- p += 2; /* add ba ssn */
- p += 4; /* reserved */
}
+ p += 4; /* htflags */
+ p += 4; /* mask */
+ p += 2; /* disable tid */
+ p += 2; /* reserved */
+ p++; /* add ba tid */
+ p++; /* del ba tid */
+ p += 2; /* add ba ssn */
+ p += 4; /* reserved */
cmd(ctlr, 24, c, p - c);
}
-void
-rxon(Ether *edev)
+static void
+rxon(Ether *edev, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ int filter, flags;
Ctlr *ctlr;
+ char *err;
ctlr = edev->ctlr;
+ filter = FilterNoDecrypt | FilterMulticast | FilterBeacon;
+ if(ctlr->prom){
+ filter |= FilterPromisc;
+ if(bss != nil)
+ ctlr->channel = bss->channel;
+ bss = nil;
+ }
+ flags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss != nil){
+ if(bss->cap & (1<<5))
+ flags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ flags |= RFlagShSlot;
+ ctlr->channel = bss->channel;
+ memmove(ctlr->bssid, bss->bssid, Eaddrlen);
+ ctlr->aid = bss->aid;
+ if(ctlr->aid != 0){
+ filter |= FilterBSS;
+ filter &= ~FilterBeacon;
+ ctlr->bssnodeid = -1;
+ } else
+ ctlr->bcastnodeid = -1;
+ } else {
+ memmove(ctlr->bssid, edev->bcast, Eaddrlen);
+ ctlr->aid = 0;
+ ctlr->bcastnodeid = -1;
+ ctlr->bssnodeid = -1;
+ }
+
+ if(ctlr->aid != 0)
+ setled(ctlr, 2, 0, 1); /* on when associated */
+ else if(memcmp(ctlr->bssid, edev->bcast, Eaddrlen) != 0)
+ setled(ctlr, 2, 10, 10); /* slow blink when connecting */
+ else
+ setled(ctlr, 2, 5, 5); /* fast blink when scanning */
+
+ if(ctlr->wifi->debug)
+ print("#l%d: rxon: bssid %E, aid %x, channel %d, filter %x, flags %x\n",
+ edev->ctlrno, ctlr->bssid, ctlr->aid, ctlr->channel, filter, flags);
+
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
- p += 8; /* bssid */
+ memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
memmove(p, edev->ea, 6); p += 8; /* wlap */
- *p++ = 3; /* mode */
+ *p++ = 3; /* mode (STA) */
*p++ = 0; /* air (?) */
/* rxchain */
put16(p, ((ctlr->rfcfg.rxantmask & 7)<<1) | (2<<10) | (2<<12));
p += 2;
*p++ = 0xff; /* ofdm mask (not yet negotiated) */
*p++ = 0x0f; /* cck mask (not yet negotiated) */
- p += 2; /* associd (?) */
- put32(p, (1<<15)|(1<<30)|(1<<0)); /* flags (TSF | CTS_TO_SELF | 24GHZ) */
+ put16(p, ctlr->aid & 0x3fff);
+ p += 2; /* aid */
+ put32(p, flags);
p += 4;
- put32(p, 4|1); /* filter (MULTICAST|PROMISC) */
+ put32(p, filter);
p += 4;
- *p++ = ctlr->channel; /* chan */
+ *p++ = ctlr->channel;
p++; /* reserved */
*p++ = 0xff; /* ht single mask */
*p++ = 0xff; /* ht dual mask */
put16(p, 0); p += 2; /* acquisition */
p += 2; /* reserved */
}
- cmd(ctlr, 16, c, p - c);
+ if((err = cmd(ctlr, 16, c, p - c)) != nil){
+ print("rxon: %s\n", err);
+ return;
+ }
+
+ if(ctlr->bcastnodeid == -1){
+ ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31;
+ addnode(ctlr, ctlr->bcastnodeid, edev->bcast);
+ }
+ if(ctlr->bssnodeid == -1 && bss != nil && ctlr->aid != 0){
+ ctlr->bssnodeid = 0;
+ addnode(ctlr, ctlr->bssnodeid, bss->bssid);
+ }
}
static struct ratetab {
uchar plcp;
uchar flags;
} ratetab[] = {
- { 2, 10, 1<<1 },
- { 4, 20, 1<<1 },
- { 11, 55, 1<<1 },
- { 22, 110, 1<<1 },
+ { 2, 10, RFlagCCK },
+ { 4, 20, RFlagCCK },
+ { 11, 55, RFlagCCK },
+ { 22, 110, RFlagCCK },
+
{ 12, 0xd, 0 },
{ 18, 0xf, 0 },
{ 24, 0x5, 0 },
{ 120, 0x3, 0 }
};
+static uchar iwlrates[] = {
+ 0x80 | 2,
+ 0x80 | 4,
+ 0x80 | 11,
+ 0x80 | 22,
+
+ 0x80 | 12,
+ 0x80 | 18,
+ 0x80 | 24,
+ 0x80 | 36,
+ 0x80 | 48,
+ 0x80 | 72,
+ 0x80 | 96,
+ 0x80 | 108,
+ 0x80 | 120,
+
+ 0
+};
+
+enum {
+ TFlagNeedProtection = 1<<0,
+ TFlagNeedRTS = 1<<1,
+ TFlagNeedCTS = 1<<2,
+ TFlagNeedACK = 1<<3,
+ TFlagLinkq = 1<<4,
+ TFlagImmBa = 1<<6,
+ TFlagFullTxOp = 1<<7,
+ TFlagBtDis = 1<<12,
+ TFlagAutoSeq = 1<<13,
+ TFlagMoreFrag = 1<<14,
+ TFlagInsertTs = 1<<16,
+ TFlagNeedPadding = 1<<20,
+};
+
static void
-transmit(Wifi *wifi, Wnode *, Block *b)
+transmit(Wifi *wifi, Wnode *wn, Block *b)
{
+ int flags, nodeid, rate, ant;
uchar c[Tcmdsize], *p;
+ Ether *edev;
Ctlr *ctlr;
+ Wifipkt *w;
+ char *err;
+
+ edev = wifi->ether;
+ ctlr = edev->ctlr;
+
+ qlock(ctlr);
+ if(ctlr->attached == 0 || ctlr->broken){
+ qunlock(ctlr);
+ freeb(b);
+ return;
+ }
+
+ if((wn->channel != ctlr->channel)
+ || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)))
+ rxon(edev, wn);
+
+ if(b == nil){
+ /* association note has no data to transmit */
+ qunlock(ctlr);
+ return;
+ }
+
+ flags = 0;
+ nodeid = ctlr->bcastnodeid;
+ p = wn->minrate;
+ w = (Wifipkt*)b->rp;
+ if((w->a1[0] & 1) == 0){
+ flags |= TFlagNeedACK;
- ctlr = wifi->ether->ctlr;
+ if(BLEN(b) > 512-4)
+ flags |= TFlagNeedRTS;
+
+ if((w->fc[0] & 0x0c) == 0x08 && ctlr->bssnodeid != -1){
+ nodeid = ctlr->bssnodeid;
+ p = wn->actrate;
+ }
+
+ if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
+ if(ctlr->type != Type4965){
+ flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ flags |= TFlagNeedProtection;
+ } else
+ flags |= TFlagFullTxOp;
+ }
+ }
+ if(p >= wifi->rates)
+ rate = p - wifi->rates;
+ else
+ rate = 0;
+ qunlock(ctlr);
+
+ /* select first available antenna */
+ ant = ctlr->rfcfg.txantmask & 7;
+ ant |= (ant == 0);
+ ant = ((ant - 1) & ant) ^ ant;
memset(p = c, 0, sizeof(c));
put16(p, BLEN(b));
p += 2;
p += 2; /* lnext */
- put32(p, 0); /* flags */
+ put32(p, flags);
p += 4;
put32(p, 0);
p += 4; /* scratch */
- *p++ = ratetab[2].plcp; /* plcp */
- *p++ = ratetab[2].flags | (1<<6); /* rflags */
+
+ *p++ = ratetab[rate].plcp;
+ *p++ = ratetab[rate].flags | (ant<<6);
+
p += 2; /* xflags */
- *p++ = 15; /* id (5000 only) */
+ *p++ = nodeid;
*p++ = 0; /* security */
*p++ = 0; /* linkq */
p++; /* reserved */
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
- /* scratch ptr? not clear what this is for */
+
+ /* BUG: scratch ptr? not clear what this is for */
put32(p, PCIWADDR(ctlr->kwpage));
p += 5;
+
*p++ = 60; /* rts ntries */
*p++ = 15; /* data ntries */
*p++ = 0; /* tid */
put16(p, 0); /* timeout */
p += 2;
p += 2; /* txop */
- qcmd(ctlr, 0, 28, c, p - c, b);
-}
-
-static int
-rbplant(Ctlr *ctlr, int i)
-{
- Block *b;
-
- b = iallocb(Rbufsize + 256);
- if(b == nil)
- return -1;
- b->rp = b->wp = (uchar*)ROUND((uintptr)b->base, 256);
- memset(b->rp, 0, Rdscsize);
- ctlr->rx.b[i] = b;
- ctlr->rx.p[i] = PCIWADDR(b->rp) >> 8;
- return 0;
+ if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ print("transmit: %s\n", err);
+ freeb(b);
+ }
}
static long
Ctlr *ctlr;
ctlr = edev->ctlr;
+ if(n >= 5 && memcmp(buf, "reset", 5) == 0){
+ ctlr->broken = 1;
+ return n;
+ }
if(ctlr->wifi)
return wifictl(ctlr->wifi, buf, n);
return 0;
setoptions(Ether *edev)
{
Ctlr *ctlr;
- char buf[64];
int i;
ctlr = edev->ctlr;
- ctlr->channel = 3;
- for(i = 0; i < edev->nopt; i++){
- if(strncmp(edev->opt[i], "channel=", 8) == 0)
- ctlr->channel = atoi(edev->opt[i]+8);
- else
- if(strncmp(edev->opt[i], "essid=", 6) == 0){
- snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
- if(!waserror()){
- wifictl(ctlr->wifi, buf, strlen(buf));
- poperror();
- }
+ for(i = 0; i < edev->nopt; i++)
+ wificfg(ctlr->wifi, edev->opt[i]);
+}
+
+static void
+iwlpromiscuous(void *arg, int on)
+{
+ Ether *edev;
+ Ctlr *ctlr;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+ qlock(ctlr);
+ ctlr->prom = on;
+ rxon(edev, ctlr->wifi->bss);
+ qunlock(ctlr);
+}
+
+static void
+iwlmulticast(void *, uchar*, int)
+{
+}
+
+static void
+iwlrecover(void *arg)
+{
+ Ether *edev;
+ Ctlr *ctlr;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+ while(waserror())
+ ;
+ for(;;){
+ tsleep(&up->sleep, return0, 0, 4000);
+
+ qlock(ctlr);
+ for(;;){
+ if(ctlr->broken == 0)
+ break;
+
+ if(ctlr->power)
+ poweroff(ctlr);
+
+ if((csr32r(ctlr, Gpc) & RfKill) == 0)
+ break;
+
+ if(reset(ctlr) != nil)
+ break;
+ if(boot(ctlr) != nil)
+ break;
+
+ ctlr->bcastnodeid = -1;
+ ctlr->bssnodeid = -1;
+ ctlr->aid = 0;
+ rxon(edev, ctlr->wifi->bss);
+ break;
}
+ qunlock(ctlr);
}
}
FWImage *fw;
Ctlr *ctlr;
char *err;
- RXQ *rx;
- TXQ *tx;
- int i, q;
ctlr = edev->ctlr;
eqlock(ctlr);
if(waserror()){
+ print("#l%d: %s\n", edev->ctlrno, up->errstr);
+ if(ctlr->power)
+ poweroff(ctlr);
qunlock(ctlr);
nexterror();
}
if(ctlr->attached == 0){
- if(ctlr->wifi == nil)
+ if((csr32r(ctlr, Gpc) & RfKill) == 0)
+ error("wifi disabled by switch");
+
+ if(ctlr->wifi == nil){
+ qsetlimit(edev->oq, MaxQueue);
+
ctlr->wifi = wifiattach(edev, transmit);
+ /* tested with 2230, it has transmit issues using higher bit rates */
+ if(ctlr->type != Type2030)
+ ctlr->wifi->rates = iwlrates;
+ }
if(ctlr->fw == nil){
- fw = readfirmware("iwn-5000");
- print("#l%d: firmware: rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
- edev->ctlrno,
+ char *fn = fwname[ctlr->type];
+ if(ctlr->type == Type6005){
+ switch(ctlr->pdev->did){
+ case 0x0082: /* Centrino Advanced-N 6205 */
+ case 0x0085: /* Centrino Advanced-N 6205 */
+ break;
+ default: /* Centrino Advanced-N 6030, 6235 */
+ fn = "iwn-6030";
+ }
+ }
+ fw = readfirmware(fn);
+ print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
+ edev->ctlrno, fn,
fw->rev, fw->build,
fw->main.text.size, fw->main.data.size,
fw->init.text.size, fw->init.data.size,
ctlr->fw = fw;
}
- rx = &ctlr->rx;
- rx->i = 0;
- if(rx->b == nil)
- rx->b = malloc(sizeof(Block*) * Nrx);
- if(rx->p == nil)
- rx->p = mallocalign(sizeof(u32int) * Nrx, 256, 0, 0);
- if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 16, 0, 0);
- if(rx->b == nil || rx->p == nil || rx->s == nil)
- error("no memory for rx ring");
- memset(rx->s, 0, Rstatsize);
- for(i=0; i<Nrx; i++){
- rx->p[i] = 0;
- if(rx->b[i] != nil){
- freeb(rx->b[i]);
- rx->b[i] = nil;
- }
- if(rbplant(ctlr, i) < 0)
- error("no memory for rx descriptors");
- }
-
- for(q=0; q<nelem(ctlr->tx); q++){
- tx = &ctlr->tx[q];
- tx->i = 0;
- tx->n = 0;
- if(tx->b == nil)
- tx->b = malloc(sizeof(Block*) * Ntx);
- if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
- if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4, 0, 0);
- if(tx->b == nil || tx->d == nil || tx->c == nil)
- error("no memory for tx ring");
- memset(tx->d, 0, Tdscsize * Ntx);
- }
-
- if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign(512 * nelem(ctlr->tx) * 2, 1024, 0, 0);
- if(ctlr->kwpage == nil)
- ctlr->kwpage = mallocalign(4096, 4096, 0, 0);
-
- if((err = niclock(ctlr)) != nil)
- error(err);
- prphwrite(ctlr, ApmgPs, (prphread(ctlr, ApmgPs) & ~PwrSrcMask) | PwrSrcVMain);
- nicunlock(ctlr);
-
- csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
-
- if((err = niclock(ctlr)) != nil)
- error(err);
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
- nicunlock(ctlr);
-
- if((err = niclock(ctlr)) != nil)
- error(err);
- csr32w(ctlr, FhRxConfig, 0);
- csr32w(ctlr, FhRxWptr, 0);
- csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
- csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
- csr32w(ctlr, FhRxConfig,
- FhRxConfigEna |
- FhRxConfigIgnRxfEmpty |
- FhRxConfigIrqDstHost |
- FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
- csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
- nicunlock(ctlr);
-
- if((err = niclock(ctlr)) != nil)
- error(err);
- prphwrite(ctlr, SchedTxFact5000, 0);
- csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
- for(q=0; q<nelem(ctlr->tx); q++)
- csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
- nicunlock(ctlr);
- for(i=0; i<8; i++)
- csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
- csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
- csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
-
- ctlr->ie = Idefmask;
- csr32w(ctlr, Imr, ctlr->ie);
- csr32w(ctlr, Isr, ~0);
-
- if(ctlr->type >= Type6000)
- csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) | 0x800fffff);
-
- if((err = loadfirmware1(ctlr, 0x00000000, ctlr->fw->main.text.data, ctlr->fw->main.text.size)) != nil)
+ if((err = reset(ctlr)) != nil)
error(err);
- if((err = loadfirmware1(ctlr, 0x00800000, ctlr->fw->main.data.data, ctlr->fw->main.data.size)) != nil)
+ if((err = boot(ctlr)) != nil)
error(err);
- csr32w(ctlr, Reset, 0);
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
- error("firmware boot failed");
-
- postboot(ctlr);
+ ctlr->bcastnodeid = -1;
+ ctlr->bssnodeid = -1;
+ ctlr->channel = 1;
+ ctlr->aid = 0;
setoptions(edev);
- rxon(edev);
- addnode(ctlr, 15, edev->bcast);
-
- edev->prom = 1;
- edev->link = 1;
ctlr->attached = 1;
+
+ kproc("iwlrecover", iwlrecover, edev);
}
qunlock(ctlr);
poperror();
receive(Ctlr *ctlr)
{
Block *b, *bb;
- uchar *d, *dd, *cc;
+ uchar *d;
RXQ *rx;
TXQ *tx;
uint hw;
rx = &ctlr->rx;
- if(rx->s == nil || rx->b == nil)
+ if(ctlr->broken || rx->s == nil || rx->b == nil)
return;
+
+ bb = nil;
for(hw = get16(rx->s) % Nrx; rx->i != hw; rx->i = (rx->i + 1) % Nrx){
uchar type, flags, idx, qid;
u32int len;
idx = *d++;
qid = *d++;
+ if(bb != nil){
+ freeb(bb);
+ bb = nil;
+ }
if((qid & 0x80) == 0 && qid < nelem(ctlr->tx)){
tx = &ctlr->tx[qid];
if(tx->n > 0){
bb = tx->b[idx];
- if(bb != nil){
- tx->b[idx] = nil;
- freeb(bb);
- }
- /* paranoia: clear tx descriptors */
- dd = tx->d + idx*Tdscsize;
- cc = tx->c + idx*Tcmdsize;
- memset(dd, 0, Tdscsize);
- memset(cc, 0, Tcmdsize);
+ tx->b[idx] = nil;
tx->n--;
wakeup(tx);
case 24: /* add node done */
break;
case 28: /* tx done */
+ if(ctlr->type == Type4965){
+ if(len <= 20 || d[20] == 1 || d[20] == 2)
+ break;
+ } else {
+ if(len <= 32 || d[32] == 1 || d[32] == 2)
+ break;
+ }
+ wifitxfail(ctlr->wifi, bb);
break;
- case 102: /* calibration result (Type5000 only)
- break;
- case 103: /* calibration done (Type5000 only)
+ case 102: /* calibration result (Type5000 only) */
+ if(len < 4)
+ break;
+ idx = d[0];
+ if(idx >= nelem(ctlr->calib.cmd))
+ break;
+ if(rbplant(ctlr, rx->i) < 0)
+ break;
+ if(ctlr->calib.cmd[idx] != nil)
+ freeb(ctlr->calib.cmd[idx]);
+ b->rp = d;
+ b->wp = d + len;
+ ctlr->calib.cmd[idx] = b;
+ continue;
+ case 103: /* calibration done (Type5000 only) */
+ ctlr->calib.done = 1;
break;
case 130: /* start scan */
break;
case 192: /* rx phy */
break;
case 195: /* rx done */
- if(d + 60 > b->lim)
+ if(d + 2 > b->lim)
break;
- d += 60;
+ d += d[1];
+ d += 56;
case 193: /* mpdu rx done */
if(d + 4 > b->lim)
break;
case 197: /* rx compressed ba */
break;
}
- /* paranoia: clear the descriptor */
- memset(b->rp, 0, Rdscsize);
}
csr32w(ctlr, FhRxWptr, ((hw+Nrx-1) % Nrx) & ~7);
+ if(bb != nil)
+ freeb(bb);
}
static void
if((isr & (Iswrx | Ifhrx | Irxperiodic)) || (fhisr & Ifhrx))
receive(ctlr);
if(isr & Ierr){
- iprint("#l%d: fatal firmware error\n", edev->ctlrno);
+ ctlr->broken = 1;
+ print("#l%d: fatal firmware error\n", edev->ctlrno);
dumpctlr(ctlr);
}
ctlr->wait.m |= isr;
- if(ctlr->wait.m & ctlr->wait.w){
- ctlr->wait.r = ctlr->wait.m & ctlr->wait.w;
- ctlr->wait.m &= ~ctlr->wait.r;
+ if(ctlr->wait.m & ctlr->wait.w)
wakeup(&ctlr->wait);
- }
done:
csr32w(ctlr, Imr, ctlr->ie);
iunlock(ctlr);
}
+static void
+iwlshutdown(Ether *edev)
+{
+ Ctlr *ctlr;
+
+ ctlr = edev->ctlr;
+ if(ctlr->power)
+ poweroff(ctlr);
+ ctlr->broken = 0;
+}
+
static Ctlr *iwlhead, *iwltail;
static void
switch(pdev->did){
default:
continue;
+ case 0x0084: /* WiFi Link 1000 */
+ case 0x4229: /* WiFi Link 4965 */
+ case 0x4230: /* WiFi Link 4965 */
+ case 0x4232: /* Wifi Link 5100 */
+ case 0x4235: /* Intel Corporation Ultimate N WiFi Link 5300 */
case 0x4236: /* WiFi Link 5300 AGN */
+ case 0x4237: /* Wifi Link 5100 AGN */
+ case 0x4239: /* Centrino Advanced-N 6200 */
+ case 0x423d: /* Wifi Link 5150 */
+ case 0x423b: /* PRO/Wireless 5350 AGN */
+ case 0x0082: /* Centrino Advanced-N 6205 */
+ case 0x0085: /* Centrino Advanced-N 6205 */
+ case 0x422b: /* Centrino Ultimate-N 6300 variant 1 */
+ case 0x4238: /* Centrino Ultimate-N 6300 variant 2 */
+ case 0x08ae: /* Centrino Wireless-N 100 */
+ case 0x0083: /* Centrino Wireless-N 1000 */
+ case 0x008a: /* Centrino Wireless-N 1030 */
+ case 0x0891: /* Centrino Wireless-N 2200 */
+ case 0x0887: /* Centrino Wireless-N 2230 */
+ case 0x0888: /* Centrino Wireless-N 2230 */
+ case 0x0090: /* Centrino Advanced-N 6030 */
+ case 0x0091: /* Centrino Advanced-N 6030 */
+ case 0x088e: /* Centrino Advanced-N 6235 */
+ case 0x088f: /* Centrino Advanced-N 6235 */
break;
}
- /* Clear device-specific "PCI retry timeout" register (41h). */
- if(pcicfgr8(pdev, 0x41) != 0)
- pcicfgw8(pdev, 0x41, 0);
-
- /* Clear interrupt disable bit. Hardware bug workaround. */
- if(pdev->pcr & 0x400){
- pdev->pcr &= ~0x400;
- pcicfgw16(pdev, PciPCR, pdev->pcr);
- }
-
- pcisetbme(pdev);
- pcisetpms(pdev, 0);
-
ctlr = malloc(sizeof(Ctlr));
if(ctlr == nil) {
print("iwl: unable to alloc Ctlr\n");
}
ctlr->nic = mem;
ctlr->pdev = pdev;
- ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
if(iwlhead != nil)
iwltail->link = ctlr;
edev->irq = ctlr->pdev->intl;
edev->tbdf = ctlr->pdev->tbdf;
edev->arg = edev;
- edev->interrupt = iwlinterrupt;
edev->attach = iwlattach;
edev->ifstat = iwlifstat;
edev->ctl = iwlctl;
- edev->promiscuous = nil;
- edev->multicast = nil;
- edev->mbps = 10;
+ edev->shutdown = iwlshutdown;
+ edev->promiscuous = iwlpromiscuous;
+ edev->multicast = iwlmulticast;
+ edev->mbps = 54;
+ pcienable(ctlr->pdev);
if(iwlinit(edev) < 0){
+ pcidisable(ctlr->pdev);
edev->ctlr = nil;
goto again;
}
+
+ pcisetbme(ctlr->pdev);
+ intrenable(edev->irq, iwlinterrupt, edev, edev->tbdf, edev->name);
return 0;
}