etheriwl: support for WiFi Link 4965

This commit is contained in:
cinap_lenrek 2013-02-12 14:28:22 +01:00
parent 8d271549cd
commit 78fc90ec86

View file

@ -19,7 +19,6 @@
#include "wifi.h" #include "wifi.h"
enum { enum {
Ntxlog = 8, Ntxlog = 8,
Ntx = 1<<Ntxlog, Ntx = 1<<Ntxlog,
Nrxlog = 8, Nrxlog = 8,
@ -197,16 +196,18 @@ enum {
enum { enum {
SchedBase = 0xa02c00, SchedBase = 0xa02c00,
SchedSramAddr = SchedBase, SchedSramAddr = SchedBase,
SchedDramAddr5000 = SchedBase+0x008,
SchedDramAddr4965 = SchedBase+0x010, SchedDramAddr4965 = SchedBase+0x010,
SchedTxFact5000 = SchedBase+0x010,
SchedTxFact4965 = SchedBase+0x01c, SchedTxFact4965 = SchedBase+0x01c,
SchedQueueRdptr4965 = SchedBase+0x064, // +q*4 SchedQueueRdptr4965 = SchedBase+0x064, // +q*4
SchedQueueRdptr5000 = SchedBase+0x068, // +q*4
SchedQChainSel4965 = SchedBase+0x0d0, SchedQChainSel4965 = SchedBase+0x0d0,
SchedIntrMask4965 = SchedBase+0x0e4, SchedIntrMask4965 = SchedBase+0x0e4,
SchedQChainSel5000 = SchedBase+0x0e8,
SchedQueueStatus4965 = SchedBase+0x104, // +q*4 SchedQueueStatus4965 = SchedBase+0x104, // +q*4
SchedDramAddr5000 = SchedBase+0x008,
SchedTxFact5000 = SchedBase+0x010,
SchedQueueRdptr5000 = SchedBase+0x068, // +q*4
SchedQChainSel5000 = SchedBase+0x0e8,
SchedIntrMask5000 = SchedBase+0x108, SchedIntrMask5000 = SchedBase+0x108,
SchedQueueStatus5000 = SchedBase+0x10c, // +q*4 SchedQueueStatus5000 = SchedBase+0x10c, // +q*4
SchedAggrSel5000 = SchedBase+0x248, SchedAggrSel5000 = SchedBase+0x248,
@ -215,11 +216,9 @@ enum {
enum { enum {
SchedCtxOff4965 = 0x380, SchedCtxOff4965 = 0x380,
SchedCtxLen4965 = 416, SchedCtxLen4965 = 416,
SchedTransTblOff4965 = 0x500,
SchedCtxOff5000 = 0x600, SchedCtxOff5000 = 0x600,
SchedCtxLen5000 = 512, SchedCtxLen5000 = 512,
SchedTransTblOff5000 = 0x7e0,
}; };
enum { enum {
@ -253,8 +252,6 @@ typedef struct RXQ RXQ;
typedef struct Ctlr Ctlr; typedef struct Ctlr Ctlr;
typedef struct Ctlrtype Ctlrtype;
struct FWSect struct FWSect
{ {
uchar *data; uchar *data;
@ -378,39 +375,16 @@ enum {
Type6005 = 11, Type6005 = 11,
}; };
struct Ctlrtype static char *fwname[16] = {
{ [Type4965] "iwn-4965",
char *fwname; [Type5300] "iwn-5000",
}; [Type5350] "iwn-5000",
[Type5150] "iwn-5150",
static Ctlrtype ctlrtype[16] = { [Type5100] "iwn-5000",
[Type4965] { [Type1000] "iwn-1000",
.fwname = "iwn-4965", [Type6000] "iwn-6000",
}, [Type6050] "iwn-6050",
[Type5300] { [Type6005] "iwn-6005",
.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 csr32r(c, r) (*((c)->nic+((r)/4)))
@ -754,7 +728,7 @@ Tooshort:
return "bad firmware signature"; return "bad firmware signature";
p += 4; p += 4;
strncpy(i->descr, (char*)p, 64); strncpy(i->descr, (char*)p, 64);
i->descr[sizeof(i->descr)-1] = 0; i->descr[64] = 0;
p += 64; p += 64;
i->rev = get32(p); p += 4; i->rev = get32(p); p += 4;
i->build = get32(p); p += 4; i->build = get32(p); p += 4;
@ -776,7 +750,7 @@ Tooshort:
default:s = &dummy; default:s = &dummy;
} }
p += 2; p += 2;
if(get16(p) != alt) if(get16(p) != 0 && get16(p) != alt)
s = &dummy; s = &dummy;
p += 2; p += 2;
s->size = get32(p); p += 4; s->size = get32(p); p += 4;
@ -942,6 +916,7 @@ bootfirmware(Ctlr *ctlr)
return err; return err;
if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil) if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
return err; return err;
csr32w(ctlr, Reset, 0);
goto bootmain; goto bootmain;
} }
@ -966,6 +941,12 @@ bootfirmware(Ctlr *ctlr)
prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4); prphwrite(ctlr, BsmDramTextAddr, PCIWADDR(p) >> 4);
prphwrite(ctlr, BsmDramTextSize, fw->init.text.size); prphwrite(ctlr, BsmDramTextSize, fw->init.text.size);
nicunlock(ctlr);
if((err = niclock(ctlr)) != nil){
free(dma);
return err;
}
p = fw->boot.text.data; p = fw->boot.text.data;
n = fw->boot.text.size/4; n = fw->boot.text.size/4;
for(i=0; i<n; i++, p += 4) for(i=0; i<n; i++, p += 4)
@ -1019,7 +1000,6 @@ bootfirmware(Ctlr *ctlr)
nicunlock(ctlr); nicunlock(ctlr);
bootmain: bootmain:
csr32w(ctlr, Reset, 0);
if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){ if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
free(dma); free(dma);
return "main firmware boot failed"; return "main firmware boot failed";
@ -1119,17 +1099,18 @@ flushq(Ctlr *ctlr, uint qid)
} }
static void
flushcmd(Ctlr *ctlr)
{
flushq(ctlr, 4);
}
static void static void
cmd(Ctlr *ctlr, uint code, uchar *data, int size) cmd(Ctlr *ctlr, uint code, uchar *data, int size)
{ {
qcmd(ctlr, 4, code, data, size, nil); qcmd(ctlr, 4, code, data, size, nil);
} }
static void
flushcmd(Ctlr *ctlr)
{
flushq(ctlr, 4);
}
static void static void
setled(Ctlr *ctlr, int which, int on, int off) setled(Ctlr *ctlr, int which, int on, int off)
@ -1173,8 +1154,8 @@ postboot(Ctlr *ctlr)
} }
ctlr->sched.base = prphread(ctlr, SchedSramAddr); ctlr->sched.base = prphread(ctlr, SchedSramAddr);
for(i=0; i < ctxlen/4; i++) for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i*4, 0); memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10); prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
@ -1185,7 +1166,7 @@ postboot(Ctlr *ctlr)
prphwrite(ctlr, SchedQChainSel5000, 0xfffef); prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
prphwrite(ctlr, SchedAggrSel5000, 0); prphwrite(ctlr, SchedAggrSel5000, 0);
for(q=0; q<nelem(ctlr->tx); q++){ for(q=0; q<20; q++){
prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0); prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
csr32w(ctlr, HbusTargWptr, q << 8); csr32w(ctlr, HbusTargWptr, q << 8);
@ -1217,14 +1198,17 @@ postboot(Ctlr *ctlr)
/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
for(q=0; q<7; q++){ for(q=0; q<7; q++){
if(ctlr->type != Type4965){
static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 }; static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
if(ctlr->type != Type4965)
prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]); prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
else } else {
prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]); static uchar qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 };
prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | qid2fifo[q]<<1);
}
} }
nicunlock(ctlr); nicunlock(ctlr);
if(ctlr->type != Type4965){
if(ctlr->type != Type5150){ if(ctlr->type != Type5150){
memset(c, 0, sizeof(c)); memset(c, 0, sizeof(c));
c[0] = 15; /* code */ c[0] = 15; /* code */
@ -1234,8 +1218,6 @@ postboot(Ctlr *ctlr)
put16(c+4, ctlr->eeprom.crystal); put16(c+4, ctlr->eeprom.crystal);
cmd(ctlr, 176, c, 8); cmd(ctlr, 176, c, 8);
} }
if(ctlr->type != Type4965){
put32(c, ctlr->rfcfg.txantmask & 7); put32(c, ctlr->rfcfg.txantmask & 7);
cmd(ctlr, 152, c, 4); cmd(ctlr, 152, c, 4);
} }
@ -1266,6 +1248,7 @@ addnode(Ctlr *ctlr, uchar id, uchar *addr)
p += 8; /* tcs */ p += 8; /* tcs */
p += 8; /* rxmic */ p += 8; /* rxmic */
p += 8; /* txmic */ p += 8; /* txmic */
}
p += 4; /* htflags */ p += 4; /* htflags */
p += 4; /* mask */ p += 4; /* mask */
p += 2; /* disable tid */ p += 2; /* disable tid */
@ -1274,7 +1257,6 @@ addnode(Ctlr *ctlr, uchar id, uchar *addr)
p++; /* del ba tid */ p++; /* del ba tid */
p += 2; /* add ba ssn */ p += 2; /* add ba ssn */
p += 4; /* reserved */ p += 4; /* reserved */
}
cmd(ctlr, 24, c, p - c); cmd(ctlr, 24, c, p - c);
} }
@ -1344,6 +1326,7 @@ rxon(Ether *edev, Wnode *bss)
p += 2; /* reserved */ p += 2; /* reserved */
} }
cmd(ctlr, 16, c, p - c); cmd(ctlr, 16, c, p - c);
if(ctlr->bcastnodeid == -1){ if(ctlr->bcastnodeid == -1){
ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31; ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31;
addnode(ctlr, ctlr->bcastnodeid, edev->bcast); addnode(ctlr, ctlr->bcastnodeid, edev->bcast);
@ -1617,10 +1600,10 @@ iwlattach(Ether *edev)
ctlr->wifi = wifiattach(edev, transmit); ctlr->wifi = wifiattach(edev, transmit);
if(ctlr->fw == nil){ if(ctlr->fw == nil){
fw = readfirmware(ctlrtype[ctlr->type].fwname); fw = readfirmware(fwname[ctlr->type]);
print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n", print("#l%d: firmware: %s, rev %ux, build %ud, size %ux+%ux+%ux+%ux+%ux\n",
edev->ctlrno, edev->ctlrno,
ctlrtype[ctlr->type].fwname, fwname[ctlr->type],
fw->rev, fw->build, fw->rev, fw->build,
fw->main.text.size, fw->main.data.size, fw->main.text.size, fw->main.data.size,
fw->init.text.size, fw->init.data.size, fw->init.text.size, fw->init.data.size,
@ -1699,17 +1682,19 @@ iwlattach(Ether *edev)
if((err = niclock(ctlr)) != nil) if((err = niclock(ctlr)) != nil)
error(err); error(err);
if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact5000, 0); prphwrite(ctlr, SchedTxFact5000, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4); csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q=0; q<nelem(ctlr->tx); q++) for(q = (ctlr->type != Type4965) ? 19 : 15; q >= 0; q--)
if(q < 15 || ctlr->type != Type4965)
csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8); csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
nicunlock(ctlr); nicunlock(ctlr);
for(i=0; i<8; i++) for(i = (ctlr->type != Type4965) ? 7 : 6; i >= 0; i--)
if(i < 7 || ctlr->type != Type4965)
csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna); csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill); csr32w(ctlr, UcodeGp1Clr, UcodeGp1RfKill);
@ -1820,9 +1805,10 @@ receive(Ctlr *ctlr)
case 192: /* rx phy */ case 192: /* rx phy */
break; break;
case 195: /* rx done */ case 195: /* rx done */
if(d + 60 > b->lim) if(d + 2 > b->lim)
break; break;
d += 60; d += d[1];
d += 56;
case 193: /* mpdu rx done */ case 193: /* mpdu rx done */
if(d + 4 > b->lim) if(d + 4 > b->lim)
break; break;
@ -1906,6 +1892,8 @@ iwlpci(void)
switch(pdev->did){ switch(pdev->did){
default: default:
continue; continue;
case 0x4229: /* WiFi Link 4965 */
case 0x4230: /* WiFi Link 4965 */
case 0x4236: /* WiFi Link 5300 AGN */ case 0x4236: /* WiFi Link 5300 AGN */
case 0x4237: /* Wifi Link 5100 AGN */ case 0x4237: /* Wifi Link 5100 AGN */
break; break;
@ -1940,7 +1928,7 @@ iwlpci(void)
ctlr->pdev = pdev; ctlr->pdev = pdev;
ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF; ctlr->type = (csr32r(ctlr, Rev) >> 4) & 0xF;
if(ctlrtype[ctlr->type].fwname == nil){ if(fwname[ctlr->type] == nil){
print("iwl: unsupported controller type %d\n", ctlr->type); print("iwl: unsupported controller type %d\n", ctlr->type);
vunmap(mem, pdev->mem[0].size); vunmap(mem, pdev->mem[0].size);
free(ctlr); free(ctlr);