#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,
GpDrv = 0x050,
GpDrvCalV6 = 1<<2,
GpDrv1X2 = 1<<3,
+ GpDrvRadioIqInvert = 1<<7,
Led = 0x094,
LedBsmCtrl = 1<<5,
uchar version;
uchar type;
u16int volt;
+ u16int temp;
+ u16int rawtemp;
char regdom[4+1];
Type1000 = 6,
Type6000 = 7,
Type6050 = 8,
- Type6005 = 11,
+ Type6005 = 11, /* also Centrino Advanced-N 6030, 6235 */
+ Type2030 = 12,
+ Type2000 = 16,
};
-static char *fwname[16] = {
+static char *fwname[32] = {
[Type4965] "iwn-4965",
[Type5300] "iwn-5000",
[Type5350] "iwn-5000",
[Type1000] "iwn-1000",
[Type6000] "iwn-6000",
[Type6050] "iwn-6050",
- [Type6005] "iwn-6005",
+ [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);
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)
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);
+ }
+
if(ctlr->type != Type4965 && ctlr->type != Type5150){
if((err = eepromread(ctlr, b, 4, caloff + 0x128)) != nil)
goto Err2;
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 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)
{
Block *b;
i = cmds[q];
- if(i == 8 && ctlr->type != Type5150)
+ if(i == 8 && ctlr->type != Type5150 && ctlr->type != Type2030 &&
+ ctlr->type != Type2000)
continue;
- if(i == 17 && (ctlr->type >= Type6000 || ctlr->type == Type5150))
+ 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));
return err;
}
- if(ctlr->type == Type6005){
- /* temperature sensor offset */
+ /* temperature sensor offset */
+ switch (ctlr->type){
+ case Type6005:
memset(c, 0, sizeof(c));
c[0] = 18;
c[1] = 0;
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){
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;
+ }
}
}
txqready(void *arg)
{
TXQ *q = arg;
- return q->n < Ntx;
+ return q->n < Ntxqmax;
}
static char*
ilock(ctlr);
q = &ctlr->tx[qid];
- while(q->n >= Ntx && !ctlr->broken){
+ while(q->n >= Ntxqmax && !ctlr->broken){
iunlock(ctlr);
qlock(q);
if(!waserror()){
- tsleep(q, txqready, q, 10);
+ tsleep(q, txqready, q, 5);
poperror();
}
qunlock(q);
cmd(ctlr, 24, c, p - c);
}
-void
+static void
rxon(Ether *edev, Wnode *bss)
{
uchar c[Tcmdsize], *p;
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;
ctlr->bcastnodeid = -1;
ctlr->bssnodeid = -1;
}
- flags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
if(ctlr->aid != 0)
setled(ctlr, 2, 0, 1); /* on when associated */
{ 4, 20, RFlagCCK },
{ 11, 55, RFlagCCK },
{ 22, 110, RFlagCCK },
+
{ 12, 0xd, 0 },
{ 18, 0xf, 0 },
{ 24, 0x5, 0 },
0x80 | 4,
0x80 | 11,
0x80 | 22,
+
0x80 | 12,
0x80 | 18,
0x80 | 24,
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bssnodeid != -1){
nodeid = ctlr->bssnodeid;
- p = wn->maxrate;
+ p = wn->actrate;
}
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
flags |= TFlagFullTxOp;
}
}
+ if(p >= wifi->rates)
+ rate = p - wifi->rates;
+ else
+ rate = 0;
qunlock(ctlr);
- rate = 0;
- if(p >= iwlrates && p < &iwlrates[nelem(ratetab)])
- rate = p - iwlrates;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
static void
setoptions(Ether *edev)
{
- char buf[64], *p;
Ctlr *ctlr;
int i;
ctlr = edev->ctlr;
- for(i = 0; i < edev->nopt; i++){
- snprint(buf, sizeof(buf), "%s", edev->opt[i]);
- p = strchr(buf, '=');
- if(p != nil)
- *p = 0;
- if(strcmp(buf, "debug") == 0
- || strcmp(buf, "essid") == 0
- || strcmp(buf, "bssid") == 0){
- if(p != nil)
- *p = ' ';
- if(!waserror()){
- wifictl(ctlr->wifi, buf, strlen(buf));
- poperror();
- }
- }
- }
+ for(i = 0; i < edev->nopt; i++)
+ wificfg(ctlr->wifi, edev->opt[i]);
}
static void
qunlock(ctlr);
}
+static void
+iwlmulticast(void *, uchar*, int)
+{
+}
+
static void
iwlrecover(void *arg)
{
error("wifi disabled by switch");
if(ctlr->wifi == nil){
+ qsetlimit(edev->oq, MaxQueue);
+
ctlr->wifi = wifiattach(edev, transmit);
- ctlr->wifi->rates = iwlrates;
+ /* 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(fwname[ctlr->type]);
+ 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,
- fwname[ctlr->type],
+ edev->ctlrno, fn,
fw->rev, fw->build,
fw->main.text.size, fw->main.data.size,
fw->init.text.size, fw->init.data.size,
receive(Ctlr *ctlr)
{
Block *b, *bb;
- uchar *d, *dd, *cc;
+ uchar *d;
RXQ *rx;
TXQ *tx;
uint hw;
rx = &ctlr->rx;
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) */
if(len < 4)
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
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(fwname[ctlr->type] == 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;
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->shutdown = iwlshutdown;
edev->promiscuous = iwlpromiscuous;
- edev->multicast = nil;
+ 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;
}