]> git.lizzy.rs Git - plan9front.git/commitdiff
etheriwl: work towards supporting other cards than 5300, gather channel information
authorcinap_lenrek <cinap_lenrek@gmx.de>
Sun, 10 Feb 2013 22:02:21 +0000 (23:02 +0100)
committercinap_lenrek <cinap_lenrek@gmx.de>
Sun, 10 Feb 2013 22:02:21 +0000 (23:02 +0100)
sys/src/9/pc/etheriwl.c
sys/src/9/pc/wifi.c
sys/src/9/pc/wifi.h

index f5b793c869dbc01dcbaf0880a0f757df0091abdf..a059be558f3d0fa0530cec3bde8f6f5038d0e1ed 100644 (file)
@@ -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;
-       }
-       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;
+       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);
        }
-       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);
+
+       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 < SchedCtxLen5000/4; i++)
-               memwrite(ctlr, ctlr->sched.base + SchedCtxOff5000 + i*4, 0);
+       for(i=0; i < ctxlen/4; i++)
+               memwrite(ctlr, ctlr->sched.base + ctxoff + i*4, 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<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
index 3864c6b14d5dda60de2cc9cf6810ca53468b0ed0..04042052966d3d765ea62f5899afb62ea239a28c 100644 (file)
@@ -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);
index 363722a8ff5ba95cfe67de3f4af2485b9aafa14c..25a290d6cd0441df29489aa72e6110ffe6725164 100644 (file)
@@ -23,10 +23,9 @@ struct Wnode
        char    ssid[32+2];
        int     ival;
        int     cap;
-
-       long    lastseen;
-
        int     aid;
+       int     channel;
+       long    lastseen;
 };
 
 struct Wifi