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"
enum {
Ntxlog = 8,
Ntx = 1<<Ntxlog,
Nrxlog = 8,
@ -197,16 +196,18 @@ enum {
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,
@ -215,11 +216,9 @@ enum {
enum {
SchedCtxOff4965 = 0x380,
SchedCtxLen4965 = 416,
SchedTransTblOff4965 = 0x500,
SchedCtxOff5000 = 0x600,
SchedCtxLen5000 = 512,
SchedTransTblOff5000 = 0x7e0,
};
enum {
@ -253,8 +252,6 @@ typedef struct RXQ RXQ;
typedef struct Ctlr Ctlr;
typedef struct Ctlrtype Ctlrtype;
struct FWSect
{
uchar *data;
@ -378,39 +375,16 @@ enum {
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",
},
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",
};
#define csr32r(c, r) (*((c)->nic+((r)/4)))
@ -754,7 +728,7 @@ Tooshort:
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;
@ -776,7 +750,7 @@ Tooshort:
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;
@ -942,6 +916,7 @@ bootfirmware(Ctlr *ctlr)
return err;
if((err = loadfirmware1(ctlr, 0x00800000, fw->main.data.data, fw->main.data.size)) != nil)
return err;
csr32w(ctlr, Reset, 0);
goto bootmain;
}
@ -966,6 +941,12 @@ bootfirmware(Ctlr *ctlr)
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)
@ -1019,7 +1000,6 @@ bootfirmware(Ctlr *ctlr)
nicunlock(ctlr);
bootmain:
csr32w(ctlr, Reset, 0);
if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive){
free(dma);
return "main firmware boot failed";
@ -1119,17 +1099,18 @@ flushq(Ctlr *ctlr, uint qid)
}
static void
flushcmd(Ctlr *ctlr)
{
flushq(ctlr, 4);
}
static void
cmd(Ctlr *ctlr, uint code, uchar *data, int size)
{
qcmd(ctlr, 4, code, data, size, nil);
}
static void
flushcmd(Ctlr *ctlr)
{
flushq(ctlr, 4);
}
static void
setled(Ctlr *ctlr, int which, int on, int off)
@ -1173,8 +1154,8 @@ postboot(Ctlr *ctlr)
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
for(i=0; i < ctxlen/4; i++)
memwrite(ctlr, ctlr->sched.base + ctxoff + 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);
@ -1185,7 +1166,7 @@ postboot(Ctlr *ctlr)
prphwrite(ctlr, SchedQChainSel5000, 0xfffef);
prphwrite(ctlr, SchedAggrSel5000, 0);
for(q=0; q<nelem(ctlr->tx); q++){
for(q=0; q<20; q++){
prphwrite(ctlr, SchedQueueRdptr5000 + q*4, 0);
csr32w(ctlr, HbusTargWptr, q << 8);
@ -1217,25 +1198,26 @@ postboot(Ctlr *ctlr)
/* 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 };
if(ctlr->type != Type4965)
if(ctlr->type != Type4965){
static uchar qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
prphwrite(ctlr, SchedQueueStatus5000 + q*4, 0x00ff0018 | qid2fifo[q]);
else
prphwrite(ctlr, SchedQueueStatus4965 + q*4, 0x0007fc01 | 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){
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(ctlr->type != Type4965){
if(ctlr->type != Type5150){
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);
}
put32(c, ctlr->rfcfg.txantmask & 7);
cmd(ctlr, 152, c, 4);
}
@ -1266,15 +1248,15 @@ addnode(Ctlr *ctlr, uchar id, uchar *addr)
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);
}
@ -1344,6 +1326,7 @@ rxon(Ether *edev, Wnode *bss)
p += 2; /* reserved */
}
cmd(ctlr, 16, c, p - c);
if(ctlr->bcastnodeid == -1){
ctlr->bcastnodeid = (ctlr->type != Type4965) ? 15 : 31;
addnode(ctlr, ctlr->bcastnodeid, edev->bcast);
@ -1617,10 +1600,10 @@ iwlattach(Ether *edev)
ctlr->wifi = wifiattach(edev, transmit);
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",
edev->ctlrno,
ctlrtype[ctlr->type].fwname,
fwname[ctlr->type],
fw->rev, fw->build,
fw->main.text.size, fw->main.data.size,
fw->init.text.size, fw->init.data.size,
@ -1699,18 +1682,20 @@ iwlattach(Ether *edev)
if((err = niclock(ctlr)) != nil)
error(err);
prphwrite(ctlr, SchedTxFact5000, 0);
if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact5000, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q=0; q<nelem(ctlr->tx); q++)
if(q < 15 || ctlr->type != Type4965)
csr32w(ctlr, FhCbbcQueue + q*4, PCIWADDR(ctlr->tx[q].d) >> 8);
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=0; i<8; i++)
if(i < 7 || ctlr->type != Type4965)
csr32w(ctlr, FhTxConfig + i*32, FhTxConfigDmaEna | FhTxConfigDmaCreditEna);
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);
@ -1820,9 +1805,10 @@ receive(Ctlr *ctlr)
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;
@ -1906,6 +1892,8 @@ iwlpci(void)
switch(pdev->did){
default:
continue;
case 0x4229: /* WiFi Link 4965 */
case 0x4230: /* WiFi Link 4965 */
case 0x4236: /* WiFi Link 5300 AGN */
case 0x4237: /* Wifi Link 5100 AGN */
break;
@ -1940,7 +1928,7 @@ iwlpci(void)
ctlr->pdev = pdev;
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);
vunmap(mem, pdev->mem[0].size);
free(ctlr);