etheriwl: work towards supporting other cards than 5300, gather channel information
This commit is contained in:
parent
ab6a2eb0b6
commit
3a697585f0
3 changed files with 202 additions and 68 deletions
|
@ -222,19 +222,6 @@ enum {
|
|||
SchedTransTblOff5000 = 0x7e0,
|
||||
};
|
||||
|
||||
/* controller types */
|
||||
enum {
|
||||
Type4965 = 0,
|
||||
Type5300 = 2,
|
||||
Type5350 = 3,
|
||||
Type5150 = 4,
|
||||
Type5100 = 5,
|
||||
Type1000 = 6,
|
||||
Type6000 = 7,
|
||||
Type6050 = 8,
|
||||
Type6005 = 11,
|
||||
};
|
||||
|
||||
typedef struct FWInfo FWInfo;
|
||||
typedef struct FWImage FWImage;
|
||||
typedef struct FWSect FWSect;
|
||||
|
@ -244,6 +231,8 @@ typedef struct RXQ RXQ;
|
|||
|
||||
typedef struct Ctlr Ctlr;
|
||||
|
||||
typedef struct Ctlrtype Ctlrtype;
|
||||
|
||||
struct FWSect
|
||||
{
|
||||
uchar *data;
|
||||
|
@ -347,6 +336,54 @@ struct Ctlr {
|
|||
FWImage *fw;
|
||||
};
|
||||
|
||||
/* controller types */
|
||||
enum {
|
||||
Type4965 = 0,
|
||||
Type5300 = 2,
|
||||
Type5350 = 3,
|
||||
Type5150 = 4,
|
||||
Type5100 = 5,
|
||||
Type1000 = 6,
|
||||
Type6000 = 7,
|
||||
Type6050 = 8,
|
||||
Type6005 = 11,
|
||||
};
|
||||
|
||||
struct Ctlrtype
|
||||
{
|
||||
char *fwname;
|
||||
};
|
||||
|
||||
static Ctlrtype ctlrtype[16] = {
|
||||
[Type4965] {
|
||||
.fwname = "iwn-4965",
|
||||
},
|
||||
[Type5300] {
|
||||
.fwname = "iwn-5000",
|
||||
},
|
||||
[Type5350] {
|
||||
.fwname = "iwn-5000",
|
||||
},
|
||||
[Type5150] {
|
||||
.fwname = "iwn-5150",
|
||||
},
|
||||
[Type5100] {
|
||||
.fwname = "iwn-5000",
|
||||
},
|
||||
[Type1000] {
|
||||
.fwname = "iwn-1000",
|
||||
},
|
||||
[Type6000] {
|
||||
.fwname = "iwn-6000",
|
||||
},
|
||||
[Type6050] {
|
||||
.fwname = "iwn-6050",
|
||||
},
|
||||
[Type6005] {
|
||||
.fwname = "iwn-6005",
|
||||
},
|
||||
};
|
||||
|
||||
#define csr32r(c, r) (*((c)->nic+((r)/4)))
|
||||
#define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
|
||||
|
||||
|
@ -619,23 +656,42 @@ iwlinit(Ether *edev)
|
|||
eepromunlock(ctlr);
|
||||
goto Err;
|
||||
}
|
||||
if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
|
||||
eepromunlock(ctlr);
|
||||
goto Err;
|
||||
if(ctlr->type != Type4965){
|
||||
if((err = eepromread(ctlr, b, 2, 0x048)) != nil){
|
||||
eepromunlock(ctlr);
|
||||
goto Err;
|
||||
}
|
||||
u = get16(b);
|
||||
ctlr->rfcfg.type = u & 3; u >>= 2;
|
||||
ctlr->rfcfg.step = u & 3; u >>= 2;
|
||||
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;
|
||||
}
|
||||
ctlr->eeprom.crystal = get32(b);
|
||||
}
|
||||
u = get16(b);
|
||||
ctlr->rfcfg.type = u & 3; u >>= 2;
|
||||
ctlr->rfcfg.step = u & 3; u >>= 2;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
ctlr->ie = 0;
|
||||
csr32w(ctlr, Isr, ~0); /* clear pending interrupts */
|
||||
csr32w(ctlr, Imr, 0); /* no interrupts for now */
|
||||
|
@ -936,6 +992,7 @@ setled(Ctlr *ctlr, int which, int on, int off)
|
|||
static void
|
||||
postboot(Ctlr *ctlr)
|
||||
{
|
||||
uint ctxoff, ctxlen, dramaddr, txfact;
|
||||
uchar c[8];
|
||||
char *err;
|
||||
int i, q;
|
||||
|
@ -945,33 +1002,69 @@ postboot(Ctlr *ctlr)
|
|||
|
||||
if((err = niclock(ctlr)) != nil)
|
||||
error(err);
|
||||
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
|
||||
for(i=0; i < SchedCtxLen5000/4; i++)
|
||||
memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + i*4, 0);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
if(ctlr->type != Type4965){
|
||||
dramaddr = SchedDramAddr5000;
|
||||
ctxoff = SchedCtxOff5000;
|
||||
ctxlen = SchedCtxLen5000;
|
||||
txfact = SchedTxFact5000;
|
||||
} else {
|
||||
dramaddr = SchedDramAddr4965;
|
||||
ctxoff = SchedCtxOff4965;
|
||||
ctxlen = SchedCtxLen4965;
|
||||
txfact = SchedTxFact4965;
|
||||
}
|
||||
|
||||
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
|
||||
for(i=0; i < ctxlen/4; i++)
|
||||
memwrite(ctlr, ctlr->sched.base + ctxoff + i*4, 0);
|
||||
|
||||
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
|
||||
|
||||
csr32w(ctlr, FhTxChicken, csr32r(ctlr, FhTxChicken) | 2);
|
||||
|
||||
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 + 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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
/* Enable interrupts for all our 20 queues. */
|
||||
prphwrite(ctlr, SchedIntrMask5000, 0xfffff);
|
||||
/* Identify TX FIFO rings (0-7). */
|
||||
prphwrite(ctlr, SchedTxFact5000, 0xff);
|
||||
prphwrite(ctlr, txfact, 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)
|
||||
prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
|
||||
else
|
||||
prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]);
|
||||
}
|
||||
nicunlock(ctlr);
|
||||
|
||||
|
@ -1029,7 +1122,7 @@ addnode(Ctlr *ctlr, uchar id, uchar *addr)
|
|||
}
|
||||
|
||||
void
|
||||
rxon(Ether *edev)
|
||||
rxon(Ether *edev, Wnode *bss)
|
||||
{
|
||||
uchar c[Tcmdsize], *p;
|
||||
Ctlr *ctlr;
|
||||
|
@ -1037,21 +1130,24 @@ rxon(Ether *edev)
|
|||
ctlr = edev->ctlr;
|
||||
memset(p = c, 0, sizeof(c));
|
||||
memmove(p, edev->ea, 6); p += 8; /* myaddr */
|
||||
memmove(p, (bss != nil) ? bss->bssid : edev->bcast, 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 (?) */
|
||||
if(bss != nil)
|
||||
put16(p, bss->aid & ~0xc000);
|
||||
p += 2; /* aid */
|
||||
put32(p, (1<<15)|(1<<30)|(1<<0)); /* flags (TSF | CTS_TO_SELF | 24GHZ) */
|
||||
p += 4;
|
||||
put32(p, 4|1); /* filter (MULTICAST|PROMISC) */
|
||||
put32(p, 8|4|1); /* filter (NODECRYPT|MULTICAST|PROMISC) */
|
||||
p += 4;
|
||||
*p++ = ctlr->channel; /* chan */
|
||||
*p++ = bss != nil ? bss->channel : ctlr->channel;
|
||||
p++; /* reserved */
|
||||
*p++ = 0xff; /* ht single mask */
|
||||
*p++ = 0xff; /* ht dual mask */
|
||||
|
@ -1062,6 +1158,10 @@ rxon(Ether *edev)
|
|||
p += 2; /* reserved */
|
||||
}
|
||||
cmd(ctlr, 16, c, p - c);
|
||||
|
||||
addnode(ctlr, (ctlr->type != Type4965) ? 15 : 31, edev->bcast);
|
||||
if(bss != nil)
|
||||
addnode(ctlr, 0, bss->bssid);
|
||||
}
|
||||
|
||||
static struct ratetab {
|
||||
|
@ -1100,10 +1200,16 @@ transmit(Wifi *wifi, Wnode *, Block *b)
|
|||
p += 4;
|
||||
put32(p, 0);
|
||||
p += 4; /* scratch */
|
||||
|
||||
/* BUG: hardcode 11Mbit */
|
||||
*p++ = ratetab[2].plcp; /* plcp */
|
||||
*p++ = ratetab[2].flags | (1<<6); /* rflags */
|
||||
|
||||
p += 2; /* xflags */
|
||||
*p++ = 15; /* id (5000 only) */
|
||||
|
||||
/* BUG: we always use broadcast node! */
|
||||
*p++ = (ctlr->type != Type4965) ? 15 : 31;
|
||||
|
||||
*p++ = 0; /* security */
|
||||
*p++ = 0; /* linkq */
|
||||
p++; /* reserved */
|
||||
|
@ -1112,9 +1218,11 @@ transmit(Wifi *wifi, Wnode *, Block *b)
|
|||
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 */
|
||||
|
@ -1205,9 +1313,10 @@ iwlattach(Ether *edev)
|
|||
ctlr->wifi = wifiattach(edev, transmit);
|
||||
|
||||
if(ctlr->fw == nil){
|
||||
fw = readfirmware("iwn-5000");
|
||||
print("#l%d: firmware: rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
|
||||
fw = readfirmware(ctlrtype[ctlr->type].fwname);
|
||||
print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
|
||||
edev->ctlrno,
|
||||
ctlrtype[ctlr->type].fwname,
|
||||
fw->rev, fw->build,
|
||||
fw->main.text.size, fw->main.data.size,
|
||||
fw->init.text.size, fw->init.data.size,
|
||||
|
@ -1285,13 +1394,20 @@ iwlattach(Ether *edev)
|
|||
|
||||
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);
|
||||
if(q < 15 || ctlr->type != Type4965)
|
||||
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);
|
||||
if(i < 7 || ctlr->type != Type4965)
|
||||
csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
|
||||
|
||||
csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
|
||||
csr32w(ctlr, UcodeGp1Clr, UcodeGp1CmdBlocked);
|
||||
|
||||
|
@ -1315,8 +1431,7 @@ iwlattach(Ether *edev)
|
|||
|
||||
setoptions(edev);
|
||||
|
||||
rxon(edev);
|
||||
addnode(ctlr, 15, edev->bcast);
|
||||
rxon(edev, nil);
|
||||
|
||||
edev->prom = 1;
|
||||
edev->link = 1;
|
||||
|
@ -1524,6 +1639,13 @@ iwlpci(void)
|
|||
ctlr->pdev = pdev;
|
||||
ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
|
||||
|
||||
if(ctlrtype[ctlr->type].fwname == nil){
|
||||
print("iwl: unsupported controller type %d\n", ctlr->type);
|
||||
vunmap(mem, pdev->mem[0].size);
|
||||
free(ctlr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(iwlhead != nil)
|
||||
iwltail->link = ctlr;
|
||||
else
|
||||
|
|
|
@ -185,7 +185,7 @@ sendassoc(Wifi *wifi, Wnode *bss)
|
|||
p += 1+*p;
|
||||
*p++ = 1; /* RATES */
|
||||
*p++ = 1;
|
||||
*p++ = 0x96;
|
||||
*p++ = 0x96; /* BUG: hardcoded 11Mbit (802.11b) */
|
||||
b->wp = p;
|
||||
wifitx(wifi, b);
|
||||
}
|
||||
|
@ -216,6 +216,7 @@ static void
|
|||
recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
|
||||
{
|
||||
uchar *e, *x;
|
||||
uchar t, m[256/8];
|
||||
|
||||
if(len < 8+2+2)
|
||||
return;
|
||||
|
@ -226,10 +227,18 @@ recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
|
|||
wn->cap = d[0] | d[1]<<8;
|
||||
d += 2;
|
||||
|
||||
memset(m, 0, sizeof(m));
|
||||
for(e = d + len; d+2 <= e; d = x){
|
||||
d += 2;
|
||||
x = d + d[-1];
|
||||
switch(d[-2]){
|
||||
t = d[-2];
|
||||
|
||||
/* skip double entries */
|
||||
if(m[t/8] & 1<<(t%8))
|
||||
continue;
|
||||
m[t/8] |= 1<<(t%8);
|
||||
|
||||
switch(t){
|
||||
case 0: /* SSID */
|
||||
len = 0;
|
||||
while(len < 32 && d+len < x && d[len] != 0)
|
||||
|
@ -245,7 +254,11 @@ recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
|
|||
sendauth(wifi, wn);
|
||||
}
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case 3: /* DSPARAMS */
|
||||
if(d != x)
|
||||
wn->channel = d[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,8 +428,8 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off)
|
|||
for(wn=wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
|
||||
if(wn->lastseen == 0)
|
||||
continue;
|
||||
p = seprint(p, e, "node: %E %.4x %d %ld %s\n",
|
||||
wn->bssid, wn->cap, wn->ival, TK2MS(now - wn->lastseen), wn->ssid);
|
||||
p = seprint(p, e, "node: %E %.4x %d %ld %d %s\n",
|
||||
wn->bssid, wn->cap, wn->ival, TK2MS(now - wn->lastseen), wn->channel, wn->ssid);
|
||||
}
|
||||
n = readstr(off, buf, n, s);
|
||||
free(s);
|
||||
|
|
|
@ -23,10 +23,9 @@ struct Wnode
|
|||
char ssid[32+2];
|
||||
int ival;
|
||||
int cap;
|
||||
|
||||
long lastseen;
|
||||
|
||||
int aid;
|
||||
int channel;
|
||||
long lastseen;
|
||||
};
|
||||
|
||||
struct Wifi
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue