Check out a review of the official Pinco Casino website <a href="https://xn--31-dlchfb3bxd.xn--p1ai">https://xn--31-dlchfb3bxd.xn--p1ai</a>
Wed Nov 5 13:22:16 EST 2025
MBR...pbs.................ok *e820=1 0x0000000000000000 0x000000000009d000 2 0x000000000009d000 0x00000000000 a0000 2 0x00000000000e0000 0x0000000000100000 1 0x0000000000100000 0x00000000b01 54000 2 0x00000000b0154000 0x00000000c301f000 4 0x00000000c301f000 0x00000000c30 20000 2 0x00000000c3020000 0x00000000cff76000 4 0x00000000cff76000 0x00000000cff 78000 2 0x00000000cff78000 0x00000000cff79000 4 0x00000000cff79000 0x00000000cff c6000 3 0x00000000cffc6000 0x00000000cfffe000 2 0x00000000cfffe000 0x00000000d80 00000 2 0x00000000d8600000 0x00000000dc800000 2 0x00000000f8000000 0x00000000fc0 00000 2 0x00000000fd000000 0x00000000fe800000 2 0x00000000fec00000 0x00000000fec 01000 2 0x00000000fed00000 0x00000000fed01000 2 0x00000000fed10000 0x00000000fed 18000 2 0x00000000fed18000 0x00000000fed19000 2 0x00000000fed19000 0x00000000fed 1a000 2 0x00000000fed84000 0x00000000fed85000 2 0x00000000fee00000 0x00000000fee 01000 2 0x00000000ff800000 0x0000000100000000 1 0x0000000100000000 0x00000003218 00000 bootfile=9pc64 bootargs=local!/dev/sdE0/fs -A mouseport=ps2 monitor=vesa vgasize=2560x1440x32 tiltscreen=none boot Plan 9 HPET: fed00000 8086a701 24 MHz 125 holes free 0x00021000 0x0009c000 503808 0x00100000 0x00110000 65536 0x0060c000 0x7ffff000 2141138944 2141708288 bytes free pcirouting: ignoring south bridge PCI.0.31.0 8086/9D48 cpu0: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) LAPIC: fee00000 0xfffffe80fee00000 ec: cmd 66, data 62 ELCR: 0800 cpu0: lapic clock at 24MHz cpu2: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) cpu1: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) cpu3: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) #l0: i219: 1000Mbps port 0xF1200000 irq 11 ea 54e1ad391502 #l1: iwl: 54Mbps port 0xF1000000 irq 11 ea 000000000000 #S/sdE: ahci: sata-II with 1 ports #A0: hda mem f1240000 irq 11 #A0: codec #0, vendor 10ec0293, rev 00100003 #A0: codec #2, vendor 80862809, rev 00100000 usbxhci: 0x8086 0x9d2f: port f1220000 size 65536 irq 11 11228M memory: 2048M kernel data, 9180M user, 10430M swap pc64.bootfs: Fri Oct 31 23:38:21 GMT 2025 fingerprint: a3f80a5b02e5d5ff45fc8e673960a3f120c984b3 #l0: i219: phy 1 wedged 08210000 #l0: i219: phy 2 wedged 08410000 #l0: i219: no phy #l1: file does not exist: '/lib/firmware/iwm-8000C-36' sdE0: LLBA 500,118,192 sectors LITEONIT LGT-256M6G 1G85202 S45N7160Z1ZSX8028244 [newdrive] /dev/sdE0: LITEONIT LGT-256M6G /dev/sdE0/9fat dos /dev/sdE0/data /dev/sdE0/fs gefs /dev/sdE0/nvram /dev/sdE0/plan9 bootargs is (tcp, tls, il, local!device)[local!/dev/sdE0/fs -A] user[glenda]: load /dev/sdE0/fs: snaptree: (76a218000,3ff1bae877a0332d,-1) narenas: 8 features: 0 nextqid: 27672 lastqgen: 227082 nextgen: 24425 blocksize: 16384 cachesz: 2884 MiB init: starting /bin/rc ip/ipconfig: recvra6: no router advs after 3 sols on /net/ether0 ip/ipconfig: recvra6: no router advs after 3 sols on /net/ether0 ip/ipconfig: no success with DHCP #l1: firmware: iwm-8000C-36, rev 24, build 3370705220, size [12] 2b8+18000 + [13] 2c8+18000 + 0 iwl: cmd 335 144 iwl: cmd 136 8 iwl: cmd 136 8 iwl: cmd 136 8 iwl: cmd 152 4 iwl: cmd 106 12 iwl: cmd 335 144 iwl: cmd 152 4 iwl: cmd 106 12 iwl: cmd 155 8 iwl: cmd 1280 4 iwl: cmd 1028 20 iwl: cmd 119 4 iwl: cmd 200 28 iwl: cmd 29 12 iwl: cmd 29 12 iwl: cmd 210 44 iwl: cmd 44 64 iwl: cmd 8 36 iwl: cmd 40 148 iwl: cmd 43 24 iwl: cmd 209 92 iwl: cmd 169 40 iwl: cmd 44 64 iwl: cmd 24 48 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 44 64 iwl: cmd 25 4 iwl: cmd 43 24 iwl: cmd 40 148 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 40 148 iwl: cmd 43 24 iwl: cmd 209 92 iwl: cmd 169 40 iwl: cmd 44 64 iwl: cmd 24 48 iwl: cmd 41 36 can't flush queue 5: flushq: timeout iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken #l0: i219: phy2 oui 0x5500 #l0: i219: link up: 1000Mbps iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00039aa2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken iwl: cmd 335 144 #l1: fatal firmware error lastcmd: 335 (0x14f) error: id 71, trm_hw_status 000002f0 00000000, branchlink2 0002440c, interruptlink 00039aa2 00005ba2, errordata 00000000 00001000 07830000 #l1: cmd 335: flushq: broken
Wed Nov 5 13:17:07 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 2); // mac type 2 = listener
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,34 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2570,22 +2652,31 @@
put32(p, ctlr->rxfilter);
p += 4;
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 1, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+44, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3626,10 +3834,10 @@
{
char *err;
- if(0) print("cmd %ud\n", code);
+ print("iwl: cmd %ud %d\n", code, size);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,13 +4061,13 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
StaTypeGeneralPurpose,
edev->bcast,
&ctlr->bcast)) != nil)
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];
Wed Nov 5 13:14:18 EST 2025
MBR...pbs.................ok *e820=1 0x0000000000000000 0x000000000009d000 2 0x000000000009d000 0x00000000000 a0000 2 0x00000000000e0000 0x0000000000100000 1 0x0000000000100000 0x00000000b01 54000 2 0x00000000b0154000 0x00000000c301f000 4 0x00000000c301f000 0x00000000c30 20000 2 0x00000000c3020000 0x00000000cff76000 4 0x00000000cff76000 0x00000000cff 78000 2 0x00000000cff78000 0x00000000cff79000 4 0x00000000cff79000 0x00000000cff c6000 3 0x00000000cffc6000 0x00000000cfffe000 2 0x00000000cfffe000 0x00000000d80 00000 2 0x00000000d8600000 0x00000000dc800000 2 0x00000000f8000000 0x00000000fc0 00000 2 0x00000000fd000000 0x00000000fe800000 2 0x00000000fec00000 0x00000000fec 01000 2 0x00000000fed00000 0x00000000fed01000 2 0x00000000fed10000 0x00000000fed 18000 2 0x00000000fed18000 0x00000000fed19000 2 0x00000000fed19000 0x00000000fed 1a000 2 0x00000000fed84000 0x00000000fed85000 2 0x00000000fee00000 0x00000000fee 01000 2 0x00000000ff800000 0x0000000100000000 1 0x0000000100000000 0x00000003218 00000 bootfile=9pc64 bootargs=local!/dev/sdE0/fs -A mouseport=ps2 monitor=vesa vgasize=2560x1440x32 tiltscreen=none boot Plan 9 HPET: fed00000 8086a701 24 MHz 125 holes free 0x00021000 0x0009c000 503808 0x00100000 0x00110000 65536 0x0060c000 0x7ffff000 2141138944 2141708288 bytes free pcirouting: ignoring south bridge PCI.0.31.0 8086/9D48 cpu0: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) LAPIC: fee00000 0xfffffe80fee00000 ec: cmd 66, data 62 ELCR: 0800 cpu0: lapic clock at 24MHz cpu2: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) cpu1: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) cpu3: 2809MHz GenuineIntel P6 (AX 000406E3 CX 77FAFBFF DX BFEBFBFF) #l0: i219: 1000Mbps port 0xF1200000 irq 11 ea 54e1ad391502 #l1: iwl: 54Mbps port 0xF1000000 irq 11 ea 000000000000 #S/sdE: ahci: sata-II with 1 ports #A0: hda mem f1240000 irq 11 #A0: codec #0, vendor 10ec0293, rev 00100003 #A0: codec #2, vendor 80862809, rev 00100000 usbxhci: 0x8086 0x9d2f: port f1220000 size 65536 irq 11 11228M memory: 2048M kernel data, 9180M user, 10430M swap pc64.bootfs: Fri Oct 31 23:38:21 GMT 2025 fingerprint: a3f80a5b02e5d5ff45fc8e673960a3f120c984b3 #l0: i219: phy 1 wedged 08210000 #l0: i219: phy 2 wedged 08410000 #l0: i219: no phy #l1: file does not exist: '/lib/firmware/iwm-8000C-36' sdE0: LLBA 500,118,192 sectors LITEONIT LGT-256M6G 1G85202 S45N7160Z1ZSX8028244 [newdrive] /dev/sdE0: LITEONIT LGT-256M6G /dev/sdE0/9fat dos /dev/sdE0/data /dev/sdE0/fs gefs /dev/sdE0/nvram /dev/sdE0/plan9 bootargs is (tcp, tls, il, local!device)[local!/dev/sdE0/fs -A] user[glenda]: load /dev/sdE0/fs: snaptree: (76a300000,70f63924d1bd11e5,-1) narenas: 8 features: 0 nextqid: 27668 lastqgen: 226991 nextgen: 24409 blocksize: 16384 cachesz: 2884 MiB init: starting /bin/rc ip/ipconfig: recvra6: no router advs after 3 sols on /net/ether0 ip/ipconfig: recvra6: no router advs after 3 sols on /net/ether0 ip/ipconfig: no success with DHCP #l1: firmware: iwm-8000C-36, rev 24, build 3370705220, size [12] 2b8+18000 + [13] 2c8+18000 + 0 iwl: cmd 335 144 iwl: cmd 136 8 iwl: cmd 136 8 iwl: cmd 136 8 iwl: cmd 152 4 iwl: cmd 106 12 iwl: cmd 335 144 iwl: cmd 152 4 iwl: cmd 106 12 iwl: cmd 155 8 iwl: cmd 1280 4 iwl: cmd 1028 20 iwl: cmd 119 4 iwl: cmd 200 28 iwl: cmd 29 12 iwl: cmd 29 12 iwl: cmd 210 44 iwl: cmd 44 64 iwl: cmd 8 36 iwl: cmd 40 148 iwl: cmd 43 24 iwl: cmd 209 92 iwl: cmd 169 40 iwl: cmd 44 64 iwl: cmd 24 48 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 #l0: i219: phy2 oui 0x5500 iwl: cmd 8 36 iwl: cmd 41 36 #l0: i219: link up: 1000Mbps iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 8 36 iwl: cmd 41 36
Wed Nov 5 13:10:04 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 2); // mac type 2 = listener
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,37 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2573,19 +2658,25 @@
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 1, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+44, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3626,10 +3834,10 @@
{
char *err;
- if(0) print("cmd %ud\n", code);
+ print("iwl: cmd %ud %d\n", code, size);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,13 +4061,13 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
StaTypeGeneralPurpose,
edev->bcast,
&ctlr->bcast)) != nil)
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];
Wed Nov 5 13:06:49 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 2); // mac type 2 = listener
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,37 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2573,19 +2658,25 @@
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 1, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+44, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3628,8 +3836,8 @@
if(0) print("cmd %ud\n", code);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,13 +4061,13 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
StaTypeGeneralPurpose,
edev->bcast,
&ctlr->bcast)) != nil)
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];
Wed Nov 5 13:00:08 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 2); // mac type 2 = listener
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,37 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2573,19 +2658,25 @@
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 5, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+44, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3628,8 +3836,8 @@
if(0) print("cmd %ud\n", code);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,13 +4061,13 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
StaTypeGeneralPurpose,
edev->bcast,
&ctlr->bcast)) != nil)
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];
Wed Nov 5 13:00:03 EST 2025
Wed Nov 5 12:59:56 EST 2025
Wed Nov 5 12:44:11 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 1); // mac type 1 = aux
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,37 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2573,19 +2658,25 @@
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 5, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+44, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3628,8 +3836,8 @@
if(0) print("cmd %ud\n", code);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,14 +4061,14 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
- StaTypeGeneralPurpose,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
+ StaTypeAux,
edev->bcast,
&ctlr->bcast)) != nil)
goto Out;
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];
Wed Nov 5 12:42:45 EST 2025
diff b9d3ca5753cc1922236fc733605bc8b3caabc8c1 uncommitted
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -71,6 +71,7 @@
Iclsc = 0x004, /* interrupt coalescing */
ClscDis = 1<<31,
+ Iperiodic = 0x005, /* periodic interrupt */
Isr = 0x008, /* interrupt status */
Imr = 0x00c, /* interrupt mask */
Ialive = 1<<0,
@@ -81,9 +82,11 @@
Iswerr = 1<<25,
Isched = 1<<26,
Ifhtx = 1<<27,
+ Ifhtxmsk = 1<<1|1<<0,
Irxperiodic = 1<<28,
Ihwerr = 1<<29,
Ifhrx = 1<<31,
+ Ifhrxmsk = 1<<30|1<<17|1<<16,
Ierr = Iswerr | Ihwerr,
Idefmask = Ierr | Ifhtx | Ifhrx | Ialive | Iwakeup | Iswrx |
Ictreached | Irftoggled,
@@ -129,6 +132,11 @@
UcodeGp1CmdBlocked = 1<<2,
UcodeGp1CtempStopRf = 1<<3,
+ DramIntTbl = 0x0a0,
+ DramTblEnable = 1<<31,
+ DramTblWritePtr = 1<<28,
+ DramTblWrapChk = 1<<27,
+
ShadowRegCtrl = 0x0a8,
MboxSet = 0x088,
@@ -176,6 +184,7 @@
FhStatusWptr = 0x1bc0,
FhRxBase = 0x1bc4,
FhRxWptr = 0x1bc8,
+ FhRxRptr = 0x1bcc,
FhRxConfig = 0x1c00,
FhRxConfigEna = 1<<31,
FhRxConfigRbSize8K = 1<<16,
@@ -185,6 +194,8 @@
FhRxConfigNrbdShift = 20,
FhRxConfigRbTimeoutShift= 4,
+ FhRxRbdcbWptr = 0x1c08,
+ FhRxFlushRbReq = 0x1c10,
FhRxStatus = 0x1c44,
@@ -332,26 +343,23 @@
SchedTransTblOff = 0x7E0, // +q*2
};
-/*
- * uCode TLV api
- */
+/* uCode TLV api */
enum {
- /* api[0] */
- UcodeApiSta = 1<<30,
+ UcodeApiSta = 1<<30,
+ ///
+ UcodeApiQuotaLowLat = 1<<6,
};
-/*
- * uCode capabilities
- */
+/* uCode capabilities */
enum {
- /* capa[0] */
- UcodeCapLar = 1<<1,
-
- /* capa[1] */
- UcodeCapQuota = 1<<12,
-
- /* capa[2] */
- UcodeCapLar2 = 1<<9,
+ UcodeCapLar = 1<<1,
+ //
+ UcodeCapBindingCdb = 1<<7,
+ UcodeCapQuota = 1<<12,
+ UcodeCapUltraHbChs = 1<<16,
+ //
+ UcodeCapLar2 = 1<<9,
+ UcodeCapCtKillByFw = 1<<10,
};
enum {
@@ -368,6 +376,7 @@
RFlag24Ghz = 1<<0,
RFlagCCK = 1<<1,
RFlagAuto = 1<<2,
+ RFlagTggProt = 1<<3,
RFlagShSlot = 1<<4,
RFlagShPreamble = 1<<5,
RFlagNoDiversity = 1<<7,
@@ -565,9 +574,11 @@
/* current receiver settings */
uchar bssid[Eaddrlen];
+ int dtimperiod;
int channel;
int prom;
int aid;
+ int cap, erp;
struct {
Rendez;
@@ -582,6 +593,9 @@
int ndma;
int ntxq;
+ int cmdqid;
+ int datqid;
+ int auxqid;
struct {
Rendez;
@@ -643,6 +657,11 @@
uchar *s;
} sched;
+ struct {
+ u32int *p;
+ int i;
+ } ict;
+
FWInfo fwinfo;
FWImage *fw;
@@ -681,8 +700,7 @@
{ 48, 0x9, 0 },
{ 72, 0xb, 0 },
{ 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ { 108, 0x3, 0 }
};
static uchar iwlrates[] = {
@@ -699,7 +717,6 @@
0x80 | 72,
0x80 | 96,
0x80 | 108,
- 0x80 | 120,
0
};
@@ -935,7 +952,9 @@
u32int dump[13];
int i;
- print("lastcmd: %ud (0x%ux)\n", ctlr->tx[4].lastcmd, ctlr->tx[4].lastcmd);
+ print("lastcmd: %ud (0x%ux)\n",
+ ctlr->tx[ctlr->cmdqid].lastcmd,
+ ctlr->tx[ctlr->cmdqid].lastcmd);
if(!ctlr->fwinfo.valid || ctlr->fwinfo.errptr == 0){
print("no error pointer\n");
@@ -1164,12 +1183,13 @@
/* Disable interrupts */
ctlr->ie = 0;
+ ctlr->ict.i = -1;
csr32w(ctlr, Imr, 0);
csr32w(ctlr, Isr, ~0);
csr32w(ctlr, FhIsr, ~0);
/* Stop scheduler */
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
@@ -1726,17 +1746,19 @@
if(ctlr->fwmem.block[i].p == nil)
return "no memory for firmware block";
}
+ memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
}
if(ctlr->fwmem.css == nil){
if((ctlr->fwmem.css = mallocalign(FWPagesize,
FWPagesize, 0, 0)) == nil)
return "no memory for firmware css page";
}
+ memset(ctlr->fwmem.css, 0, FWPagesize);
}
rx = &ctlr->rx;
if(ctlr->mqrx){
if(rx->u == nil)
- rx->u = mallocalign(4 * Nrx, 4096, 0, 0);
+ rx->u = mallocalign(4 * Nrx, 256, 0, 0);
if(rx->u == nil)
return "no memory for rx rings";
memset(rx->u, 0, 4 * Nrx);
@@ -1747,9 +1769,9 @@
rx->psz = 4;
}
if(rx->p == nil)
- rx->p = mallocalign(rx->psz*Nrx, 4096, 0, 0);
+ rx->p = mallocalign(rx->psz*Nrx, 256, 0, 0);
if(rx->s == nil)
- rx->s = mallocalign(Rstatsize, 4096, 0, 0);
+ rx->s = mallocalign(Rstatsize, 16, 0, 0);
if(rx->b == nil)
rx->b = malloc(sizeof(Block*) * Nrx);
if(rx->p == nil || rx->b == nil || rx->s == nil)
@@ -1772,8 +1794,13 @@
ctlr->ndma = 8;
ctlr->ntxq = 20;
+ ctlr->cmdqid = 4;
+ ctlr->datqid = ctlr->auxqid = 0;
if(ctlr->family >= 7000) {
ctlr->ntxq = 31;
+ ctlr->cmdqid = 0;
+ ctlr->auxqid = 1;
+ ctlr->datqid = 5;
} else {
if(ctlr->type == Type4965) {
ctlr->ndma = 7;
@@ -1782,7 +1809,7 @@
}
if(ctlr->sched.s == nil)
- ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 4096, 0, 0);
+ ctlr->sched.s = mallocalign((256+64)*2 * ctlr->ntxq, 1024, 0, 0);
if(ctlr->sched.s == nil)
return "no memory for sched buffer";
memset(ctlr->sched.s, 0, (256+64)*2 * ctlr->ntxq);
@@ -1793,9 +1820,9 @@
if(tx->b == nil)
tx->b = malloc(sizeof(Block*) * Ntx);
if(tx->d == nil)
- tx->d = mallocalign(Tdscsize * Ntx, 4096, 0, 0);
+ tx->d = mallocalign(Tdscsize * Ntx, 256, 0, 0);
if(tx->c == nil)
- tx->c = mallocalign(Tcmdsize * Ntx, 4096, 0, 0);
+ tx->c = malloc(Tcmdsize * Ntx);
if(tx->b == nil || tx->d == nil || tx->c == nil)
return "no memory for tx ring";
memset(tx->d, 0, Tdscsize * Ntx);
@@ -1820,6 +1847,16 @@
memset(ctlr->kwpage, 0, 4096);
dmaflush(1, ctlr->kwpage, 4096);
+ ctlr->ict.i = -1;
+ if(ctlr->type != Type4965){
+ if(ctlr->ict.p == nil)
+ ctlr->ict.p = mallocalign(4096, 4096, 0, 0);
+ if(ctlr->ict.p == nil)
+ return "no memory for ict";
+ memset(ctlr->ict.p, 0, 4096);
+ dmaflush(1, ctlr->ict.p, 4096);
+ }
+
return nil;
}
@@ -1863,11 +1900,10 @@
csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | RadioSi | MacSi);
}
- if(ctlr->family < 8000){
+ if(ctlr->family < 8000 && ctlr->type != Type4965){
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family == 7000 || ctlr->type != Type4965)
- prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
+ prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | EarlyPwroffDis);
nicunlock(ctlr);
}
if(ctlr->family < 7000){
@@ -1935,6 +1971,11 @@
delay(1);
} else {
csr32w(ctlr, FhRxConfig, 0);
+ if(ctlr->type != Type4965){
+ csr32w(ctlr, FhRxRbdcbWptr, 0);
+ csr32w(ctlr, FhRxFlushRbReq, 0);
+ csr32w(ctlr, FhRxRptr, 0);
+ }
csr32w(ctlr, FhRxWptr, 0);
csr32w(ctlr, FhRxBase, PCIWADDR(ctlr->rx.p) >> 8);
csr32w(ctlr, FhStatusWptr, PCIWADDR(ctlr->rx.s) >> 4);
@@ -1943,7 +1984,9 @@
FhRxConfigIgnRxfEmpty |
FhRxConfigIrqDstHost |
FhRxConfigSingleFrame |
- (Nrxlog << FhRxConfigNrbdShift));
+ Nrxlog << FhRxConfigNrbdShift |
+ /* setting this value may stall rx on 4965 */
+ (ctlr->type == Type4965? 0 :17) << FhRxConfigRbTimeoutShift); /*
17*32=544 us */
csr8w(ctlr, Iclsc, 64); /* 64*32=2048 usec */
/* hardware bug */
@@ -1953,22 +1996,14 @@
csr32w(ctlr, FhRxWptr, (Nrx-1) & ~7);
}
- for(i = 0; i < ctlr->ndma; i++)
- csr32w(ctlr, FhTxConfig + i*32, 0);
-
- if(ctlr->family >= 7000 || ctlr->type != Type4965)
+ if(ctlr->type != Type4965)
prphwrite(ctlr, SchedTxFact, 0);
else
prphwrite(ctlr, SchedTxFact4965, 0);
- if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 0);
- prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
- | Enable31Queues*(ctlr->ntxq == 31)
- | AutoActiveMode);
- for(q = 0; q < ctlr->ntxq; q++)
- prphwrite(ctlr, (q<20? SchedQueueStatus: SchedQueueStatus20) + q*4, 1
<< 19);
- }
+ if(ctlr->family < 7000)
+ for(i = 0; i < ctlr->ndma; i++)
+ csr32w(ctlr, FhTxConfig + i*32, 0);
csr32w(ctlr, FhKwAddr, PCIWADDR(ctlr->kwpage) >> 4);
for(q = 0; q < ctlr->ntxq; q++){
@@ -1981,6 +2016,11 @@
csr32w(ctlr, FhCbbcQueue20 + (q-20)*4,
PCIWADDR(ctlr->tx[i].d) >> 8);
}
+ if(ctlr->family >= 7000)
+ prphwrite(ctlr, SchedGpCtrl, prphread(ctlr, SchedGpCtrl)
+ | Enable31Queues*(ctlr->ntxq == 31)
+ | AutoActiveMode);
+
if(ctlr->family >= 7000 || ctlr->type >= Type6000)
csr32w(ctlr, ShadowRegCtrl, csr32r(ctlr, ShadowRegCtrl) |
0x800fffff);
@@ -2004,6 +2044,7 @@
ctlr->te.id = -1;
ctlr->te.active = 0;
ctlr->aid = 0;
+ memset(ctlr->bssid, 0, 6);
if(ctlr->family >= 9000)
csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | 0x4000000);
@@ -2156,19 +2197,11 @@
enablepaging(Ctlr *ctlr)
{
FWSect *sect;
- int nsect;
- int i, j, o, n;
+ int i, j, o, n, nsect;
if(ctlr->fwmem.css == nil)
return nil;
- if(1){
- /* clear everything */
- memset(ctlr->fwmem.css, 0, FWPagesize);
- for(i = 0; i < ctlr->fwmem.nblock; i++)
- memset(ctlr->fwmem.block[i].p, 0, ctlr->fwmem.block[i].size);
- }
-
if(ctlr->calib.done == 0){
sect = ctlr->fw->init.sect;
nsect = ctlr->fw->init.nsect;
@@ -2294,8 +2327,12 @@
ctlr->rfcfg.dash = (u >> 4) & 15;
ctlr->rfcfg.pnum = (u >> 6) & 3;
- ctlr->rfcfg.txantmask = (u >> 24) & 15;
- ctlr->rfcfg.rxantmask = (u >> 28) & 15;
+ u >>= 24;
+ if(u & 15)
+ ctlr->rfcfg.txantmask &= u & 15;
+ u >>= 4;
+ if(u)
+ ctlr->rfcfg.rxantmask &= u;
}
if(ctlr->family >= 8000){
if(readnvmsect(ctlr, 11, ea, Eaddrlen, 0x01<<1) !=
Eaddrlen){
@@ -2428,7 +2465,10 @@
p += 2; /* beamform flags */
- put32(p, 1<<0);
+ if(type == StaTypeLink)
+ put32(p, 1<<ctlr->datqid);
+ else
+ put32(p, 1<<ctlr->auxqid);
p += 4; /* tfd_queue_mask */
if(ctlr->fw->api[0] & UcodeApiSta){
@@ -2479,6 +2519,13 @@
return nil;
amr = CmdAdd;
phyid = 0;
+ } else if(0 && amr == CmdModify &&
+ (ctlr->fw->capa[1] & UcodeCapBindingCdb)) {
+ /* results in a fw error, do a rxon here */
+ if(err = setphycontext(ctlr, CmdRemove))
+ return err;
+ amr = CmdAdd;
+ phyid = 0;
} else if(amr == CmdAdd)
amr = CmdModify;
@@ -2492,10 +2539,19 @@
put32(p, 0); // tx param color ????
p += 4;
- *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
- *p++ = ctlr->channel; // channel number
- *p++ = 0; // channel width (20MHz<<val)
- *p++ = 0; // pos1 below
+ if(ctlr->fw->capa[1] & UcodeCapUltraHbChs){
+ put32(p, ctlr->channel);
+ p += 4;
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ *p++ = 0; // reserved
+ } else {
+ *p++ = (ctlr->rxflags & RFlag24Ghz) != 0;
+ *p++ = ctlr->channel;
+ *p++ = 0; // channel width (20MHz<<val)
+ *p++ = 0; // pos1 below
+ }
put32(p, ctlr->rfcfg.txantmask);
p += 4;
@@ -2525,6 +2581,7 @@
setmaccontext(Ether *edev, Ctlr *ctlr, int amr, Wnode *bss)
{
uchar c[4+4 + 4+4 + 8+8 + 4+4+4+4+4+4+4 + 5*8 + 12*4], *p;
+ ulong rates;
int macid, i;
char *err;
@@ -2543,7 +2600,10 @@
put32(p, amr);
p += 4;
- put32(p, 5); // mac type 5 = bss
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ put32(p, 1); // mac type 1 = aux
+ else
+ put32(p, 5); // mac type 5 = bss
p += 4;
put32(p, 0); // tsf id ???
@@ -2555,12 +2615,37 @@
memmove(p, ctlr->bssid, 6);
p += 8;
- put32(p, bss == nil? 0xF : (bss->validrates & 0xF));
+ if(memcmp(ctlr->bssid, edev->bcast, 6) == 0)
+ goto Cmd;
+
+ /*
+ * when we send a ACK or CTS, if there is no basic
+ * rate lower or equal to the previous frames
+ * rate, then we pick the highest mandatory rate
+ * with the same modulation of the previous frames
+ * rate to send the ACK. (802.11-2012 9.7.6.5.2)
+ * we'll set all mandatory rates the bss supports
+ * mandatory rates: 1-2-5.5-11-6-12-24
+ * also always set 1m for cck and 6m for ofdm
+ */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
+ put32(p, rates & 0xF); // cck basic rates
p += 4;
- put32(p, bss == nil? 0xFF : (bss->validrates >> 4));
+ put32(p, rates >> 4); // ofdm basic rates
p += 4;
- put32(p, 0); // protection flags
+ put32(p, ctlr->rxflags & RFlagTggProt); // protection flags
p += 4;
put32(p, ctlr->rxflags & RFlagShPreamble);
@@ -2573,19 +2658,25 @@
put32(p, 0); // qos flags
p += 4;
+ /* set values for legacy DCF for now */
for(i = 0; i < 4; i++){
- put16(p, 0x07); // cw_min
+ put16(p, 15); // cw_min
p += 2;
- put16(p, 0x0f); // cw_max
+ put16(p, 1023); // cw_max
p += 2;
*p++ = 2; // aifsn
- *p++ = (1<<i); // fifos_mask
- put16(p, 102*32); // edca_txop
+ if(i == 0) // AC_BE
+ *p++ = 1<<1;
+ else if(i == 1) // AC_BK
+ *p++ = 1<<0;
+ else
+ *p++ = 1<<i; // fifos_mask
+ put16(p, 0); // edca_txop
p += 2;
}
p += 8;
- if(bss != nil){
+ if(bss != nil && bss->dtimperiod){
int dtimoff = bss->ival * (int)bss->dtimcount * 1024;
/* is assoc */
@@ -2625,7 +2716,7 @@
p += 4;
}
USED(p);
-
+Cmd:
if((err = cmd(ctlr, 40, c, sizeof(c))) != nil)
return err;
@@ -2676,6 +2767,10 @@
}
put32(p, ctlr->phyid);
p += 4;
+ if(ctlr->fw->capa[1] & UcodeCapBindingCdb){
+ put32(p, 0); // lmac id
+ p += 4;
+ }
if((err = cmd(ctlr, 43, c, p - c)) != nil)
return err;
@@ -2762,10 +2857,10 @@
static char*
setbindingquotas(Ctlr *ctlr, int bindid)
{
- uchar c[4*(3*4)], *p;
+ uchar c[4*(4*4)], *p;
int i;
- if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+ if(ctlr->fw->capa[1] & UcodeCapQuota)
return nil;
i = 0;
@@ -2778,6 +2873,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
i++;
}
for(; i < 4; i++){
@@ -2787,6 +2886,10 @@
p += 4;
put32(p, 0);
p += 4;
+ if(ctlr->fw->api[1] & UcodeApiQuotaLowLat){
+ put32(p, 0);
+ p += 4;
+ }
}
return cmd(ctlr, 44, c, p - c);
@@ -2799,6 +2902,9 @@
char *err;
Block *b;
+ if(memcmp(ctlr->bssid, ctlr->edev->bcast, 6) == 0)
+ return nil;
+
b = allocb(4+6+2);
p = b->rp;
@@ -2813,11 +2919,11 @@
*p++ = 0;
b->wp = p;
- if((err = qcmd(ctlr, 4, 208, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 208, nil, 0, b)) != nil){
freeb(b);
return err;
}
- return flushq(ctlr, 4);
+ return flushq(ctlr, ctlr->cmdqid);
}
static char*
@@ -2902,6 +3008,87 @@
}
static char*
+sfconfig(Ctlr *ctlr, int state)
+{
+ uchar c[4 + 4*2 + 4*5*2 + 4*5*2], *p;
+ int i;
+
+ p = c;
+ put32(p, state); // 1 -> FULL_ON, 3 -> INIT_OFF
+ p += 4;
+
+ // default watermark values
+ put32(p, 4096); // LONG_DELAY_ON
+ p += 4;
+ put32(p, 4096); // FULL_ON
+ p += 4;
+
+ // idle and aging timer values in long delay state
+ for(i = 0; i < 5*2; i++){
+ put32(p, 1000000);
+ p += 4;
+ }
+ // in normal state
+ if(ctlr->aid != 0 && state == 1){
+ for(i = 0; i < 5; i++){
+ put32(p, i == 2 ? 2016 : 320); // idle
+ p += 4;
+ put32(p, i == 2 ? 10016 : 2016); // aging
+ p += 4;
+ }
+ }else{
+ for(i = 0; i < 5; i++){
+ put32(p, 160); // idle
+ p += 4;
+ put32(p, 400); // aging
+ p += 4;
+ }
+ }
+
+ return cmd(ctlr, 209, c, sizeof(c));
+}
+
+static char*
+schedqueuecfg(Ctlr *ctlr, int id, int qid, int fifo, int tid)
+{
+ uchar c[1+1+1+1+1+1+1+1+2+2], *p;
+
+ p = c;
+ *p++ = 0; // token
+ *p++ = id; // sta id
+ *p++ = tid;
+ *p++ = qid;
+ *p++ = 1; // enable
+ *p++ = 0; // aggregate
+ *p++ = fifo;
+ *p++ = 64; // window
+ put16(p, 0); // ssn
+ p += 2;
+ put16(p, 0); // reserved
+ p += 2;
+
+ return cmd(ctlr, 29, c, p-c);
+}
+
+static char*
+enabledqa(Ctlr *ctlr)
+{
+ uchar c[4];
+
+ put32(c, ctlr->cmdqid);
+ return cmd(ctlr, 5<<8 | 0, c, sizeof(c));
+}
+
+static char*
+tempreportthscmd(Ctlr *ctlr)
+{
+ uchar c[4+2*8];
+
+ memset(c, 0, sizeof(c));
+ return cmd(ctlr, 4<<8 | 4, c, sizeof(c));
+}
+
+static char*
postboot7000(Ctlr *ctlr)
{
char *err;
@@ -2940,11 +3127,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((qcmd(ctlr, 4, 108, nil, 0, b)) != nil){
+ if((qcmd(ctlr, ctlr->cmdqid, 108, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -2957,11 +3144,17 @@
if((err = sendbtcoexadv(ctlr)) != nil)
return err;
+ if((err = enabledqa(ctlr)) != nil)
+ return err;
+
/* Initialize tx backoffs to the minimum. */
if(ctlr->family == 7000)
if((err = tttxbackoff(ctlr)) != nil)
return err;
+ if(ctlr->fw->capa[2] & UcodeCapCtKillByFw)
+ if((err = tempreportthscmd(ctlr)) != nil)
+ return err;
if((err = updatedevicepower(ctlr)) != nil){
print("can't update device power: %s\n", err);
return err;
@@ -2969,6 +3162,10 @@
if(ctlr->fw->capa[0] & UcodeCapLar)
if((err = sendmccupdate(ctlr, "ZZ")) != nil)
return err;
+ if((err = schedqueuecfg(ctlr, 0, ctlr->datqid, 1, 0)) != nil)
+ return err;
+ if((err = schedqueuecfg(ctlr, 1, ctlr->auxqid, 5, 8)) != nil)
+ return err;
if((err = disablebeaconfilter(ctlr)) != nil){
print("can't disable beacon filter: %s\n", err);
return err;
@@ -3043,11 +3240,11 @@
if((b = ctlr->calib.cmd[i]) == nil)
continue;
b = copyblock(b, BLEN(b));
- if((err = qcmd(ctlr, 4, 176, nil, 0, b)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, 176, nil, 0, b)) != nil){
freeb(b);
return err;
}
- if((err = flushq(ctlr, 4)) != nil)
+ if((err = flushq(ctlr, ctlr->cmdqid)) != nil)
return err;
}
@@ -3109,7 +3306,7 @@
{
csr32w(ctlr, HbusTargWptr, (qid << 8) | 0);
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 1 << 19);
@@ -3126,11 +3323,10 @@
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8, 0);
memwrite(ctlr, ctlr->sched.base + SchedCtxOff + qid*8 + 4,
window<<16 | window);
- if(ctlr->family >= 7000){
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x017f0018 |
fifo);
- } else {
+ else
prphwrite(ctlr, SchedQueueStatus + qid*4, 0x00ff0018 |
fifo);
- }
} else {
if(chainmode)
prphwrite(ctlr, SchedQChainSel4965, prphread(ctlr,
SchedQChainSel4965) | (1<<qid));
@@ -3157,7 +3353,7 @@
if((err = niclock(ctlr)) != nil)
return err;
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
dramaddr = SchedDramAddr;
ctxoff = SchedCtxOff;
ctxlen = (SchedTransTblOff + 2*ctlr->ntxq) - ctxoff;
@@ -3168,31 +3364,54 @@
}
ctlr->sched.base = prphread(ctlr, SchedSramAddr);
+
+ if(ctlr->ict.p){
+ ctlr->ie = 0;
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Isr, ~0);
+ csr32w(ctlr, FhIsr, ~0);
+
+ csr32w(ctlr, DramIntTbl,
+ DramTblEnable |
+ DramTblWritePtr |
+ DramTblWrapChk |
+ PCIWADDR(ctlr->ict.p)>>12);
+
+ ctlr->ie = Idefmask;
+ ctlr->ict.i = 0;
+ csr32w(ctlr, Imr, ctlr->ie);
+ csr32w(ctlr, Isr, ~0);
+ }
+
for(i=0; i < ctxlen; i += 4)
memwrite(ctlr, ctlr->sched.base + ctxoff + i, 0);
prphwrite(ctlr, dramaddr, PCIWADDR(ctlr->sched.s)>>10);
- if(ctlr->family >= 7000) {
+ if(ctlr->family >= 7000)
prphwrite(ctlr, SchedEnCtrl, 0);
+ else if(ctlr->type != Type4965)
prphwrite(ctlr, SchedChainExtEn, 0);
- }
for(i = 0; i < nelem(ctlr->tx); i++){
- if(i == 4 && ctlr->family < 7000 && ctlr->type == Type4965)
+ if(ctlr->family >= 7000){
+ initqueue(ctlr, ctlr->cmdqid, 7, 0, 64);
+ break;
+ }
+ if(i == ctlr->cmdqid && ctlr->type == Type4965)
f = 4;
else {
static char qid2fifo[] = {
- 3, 2, 1, 0, 7, 5, 6,
+ 1, 0, 2, 3, 7, 5, 6,
};
f = qid2fifo[i];
}
- initqueue(ctlr, i, f, i != 4 && ctlr->type != Type4965, 64);
+ initqueue(ctlr, i, f, i != ctlr->cmdqid && ctlr->type != Type4965, 64);
}
/* Enable interrupts for all queues. */
if(ctlr->family >= 7000){
- prphwrite(ctlr, SchedEnCtrl, 1 << 4);
+ prphwrite(ctlr, SchedEnCtrl, 1 << ctlr->cmdqid);
} else if(ctlr->type != Type4965) {
prphwrite(ctlr, SchedIntrMask, (1<<ctlr->ntxq)-1);
} else {
@@ -3200,7 +3419,7 @@
}
/* Identify TX FIFO rings (0-7). */
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
prphwrite(ctlr, SchedTxFact, 0xff);
} else {
prphwrite(ctlr, SchedTxFact4965, 0xff);
@@ -3215,10 +3434,8 @@
nicunlock(ctlr);
- if((err = enablepaging(ctlr)) != nil){
- ctlr->calib.done = 0;
+ if((err = enablepaging(ctlr)) != nil)
return err;
- }
if(ctlr->family >= 7000)
return postboot7000(ctlr);
@@ -3303,6 +3520,8 @@
int i, num;
char *err;
+ memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
+ coherence();
if(ctlr->family >= 8000){
if((err = niclock(ctlr)) != nil)
return err;
@@ -3312,11 +3531,12 @@
num = 0;
for(i = 0; i < nsect; i++){
- if(sect[i].addr == 0xAAAABBBB)
- break;
- if(sect[i].addr == 0xFFFFCCCC)
+ if(sect[i].addr == 0xAAAABBBB){
+ num = 32;
+ i = nsect;
+ } else if(sect[i].addr == 0xFFFFCCCC){
num = 16;
- else {
+ } else {
if(sect[i].data == nil || sect[i].size == 0)
return "bad load section";
if((err = loadfirmware1(ctlr, sect[i].addr, sect[i].data,
sect[i].size)) != nil)
@@ -3327,21 +3547,12 @@
&& (err = setloadstatus(ctlr, (1ULL << num)-1)) != nil)
return err;
}
+ if(ctlr->family < 8000)
+ csr32w(ctlr, Reset, 0);
return nil;
}
static char*
-ucodestart(Ctlr *ctlr)
-{
- memset(&ctlr->fwinfo, 0, sizeof(ctlr->fwinfo));
- coherence();
- if(ctlr->family >= 8000)
- return setloadstatus(ctlr, -1);
- csr32w(ctlr, Reset, 0);
- return nil;
-}
-
-static char*
boot(Ctlr *ctlr)
{
int i, n, size;
@@ -3355,15 +3566,11 @@
if(ctlr->calib.done == 0){
if((err = loadsections(ctlr, fw->init.sect,
fw->init.nsect)) != nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "init firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid fw info";
+ return "init firmware boot timed out";
if((err = postboot(ctlr)) != nil)
return err;
@@ -3373,15 +3580,11 @@
if((err = loadsections(ctlr, fw->main.sect, fw->main.nsect))
!= nil)
return err;
- if((err = ucodestart(ctlr)) != nil)
- return err;
- tsleep(&up->sleep, return0, 0, 100);
-
- if(irqwait(ctlr, Ierr|Ialive, 5000) != Ialive)
+ if(irqwait(ctlr, Ierr, 1000))
return "main firmware boot failed";
if(!ctlr->fwinfo.valid)
- return "invalid main fw info";
+ return "main firmware boot timed out";
return postboot(ctlr);
}
@@ -3525,7 +3728,7 @@
return "qcmd: broken";
}
/* wake up the nic (just needed for 7k) */
- if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && q->n == 0)
if((err = niclock(ctlr)) != nil){
iunlock(ctlr);
return err;
@@ -3559,8 +3762,13 @@
c[2] = q->i;
c[3] = qid;
}
- if(size > 0)
+ if(size > 0){
memmove(c+hdrlen, data, size);
+ /* scratch ptr */
+ if(code == 28)
+ put32(c+hdrlen+26, PCIWADDR(c+hdrlen+8));
+ }
+
size += hdrlen;
/* build descriptor */
@@ -3628,8 +3836,8 @@
if(0) print("cmd %ud\n", code);
- if((err = qcmd(ctlr, 4, code, data, size, nil)) != nil
- || (err = flushq(ctlr, 4)) != nil){
+ if((err = qcmd(ctlr, ctlr->cmdqid, code, data, size, nil)) != nil
+ || (err = flushq(ctlr, ctlr->cmdqid)) != nil){
print("#l%d: cmd %ud: %s\n", ctlr->edev->ctlrno, code, err);
return err;
}
@@ -3714,6 +3922,10 @@
print("adding bindingcontext: %s\n", err);
return err;
}
+ if((err = sfconfig(ctlr, ctlr->aid != 0 ? 1 : 3)) != nil){
+ print("sfconfig: %s\n", err);
+ return err;
+ }
if((err = setmcastfilter(ctlr)) != nil){
print("can't set mcast filter: %s\n", err);
return err;
@@ -3730,11 +3942,25 @@
}
static char*
-rxon6000(Ether *edev, Ctlr *ctlr)
+rxon6000(Ether *edev, Ctlr *ctlr, Wnode *bss)
{
uchar c[Tcmdsize], *p;
+ ulong rates;
char *err;
+ /* see setmaccontext() */
+ if(bss){
+ rates = bss->basicrates | 1<<0 | 1<<4;
+ if(bss->basicrates >= 1<<7)
+ rates |= 1<<5|1<<6;
+ else if(bss->basicrates & 1<<6)
+ rates |= 1<<5;
+ if(bss->basicrates & 1<<3)
+ rates |= 1<<2|1<<1;
+ else if(bss->basicrates & 1<<2)
+ rates |= 1<<1;
+ }else
+ rates = 1<<0 | 1<<4;
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
memmove(p, ctlr->bssid, 6); p += 8; /* bssid */
@@ -3744,8 +3970,8 @@
/* 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++ = rates >> 4; /* ofdm basic rates */
+ *p++ = rates & 0xf; /* cck basic rates */
put16(p, ctlr->aid & 0x3fff);
p += 2; /* aid */
put32(p, ctlr->rxflags);
@@ -3769,6 +3995,20 @@
return nil;
}
+static void
+updaterxflags(Ctlr *ctlr, Wnode *bss)
+{
+ ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ if(bss == nil)
+ return;
+ if(bss->cap & (1<<5) && !(bss->erp & (1<<2)))
+ ctlr->rxflags |= RFlagShPreamble;
+ if(bss->cap & (1<<10))
+ ctlr->rxflags |= RFlagShSlot;
+ if(bss->erp & (1<<1))
+ ctlr->rxflags |= RFlagTggProt;
+}
+
static char*
rxon(Ether *edev, Wnode *bss)
{
@@ -3785,15 +4025,14 @@
if(ctlr->prom)
ctlr->rxfilter |= FilterPromisc;
- ctlr->rxflags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
+ updaterxflags(ctlr, bss);
if(bss != nil){
ctlr->aid = bss->aid;
ctlr->channel = bss->channel;
+ ctlr->dtimperiod = bss->dtimperiod;
+ ctlr->erp = bss->erp;
+ ctlr->cap = bss->cap;
memmove(ctlr->bssid, bss->bssid, sizeof(ctlr->bssid));
- if(bss->cap & (1<<5))
- ctlr->rxflags |= RFlagShPreamble;
- if(bss->cap & (1<<10))
- ctlr->rxflags |= RFlagShSlot;
if(ctlr->aid != 0){
ctlr->rxfilter |= FilterBSS;
ctlr->rxfilter &= ~FilterBeacon;
@@ -3822,14 +4061,14 @@
if(ctlr->family >= 7000)
err = rxon7000(edev, ctlr, bss);
else
- err = rxon6000(edev, ctlr);
+ err = rxon6000(edev, ctlr, bss);
if(err != nil)
goto Out;
if(ctlr->bcast.id == -1){
if((err = setstation(ctlr,
- (ctlr->type != Type4965)? 15: 31,
- StaTypeGeneralPurpose,
+ ctlr->family >= 7000 ? 1: (ctlr->type != Type4965? 15: 31),
+ StaTypeAux,
edev->bcast,
&ctlr->bcast)) != nil)
goto Out;
@@ -3853,7 +4092,7 @@
static void
transmit(Wifi *wifi, Wnode *wn, Block *b)
{
- int flags, rate, ant;
+ int flags, rate, ant, qid, tid;
uchar c[Tcmdsize], *p;
Ether *edev;
Station *sta;
@@ -3872,10 +4111,31 @@
return;
}
- if((wn->channel != ctlr->channel)
- || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0))){
+ if(!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid,
ctlr->bssid, Eaddrlen) != 0)){
if(rxon(edev, wn) != nil)
goto Broken;
+ } else {
+ if(ctlr->family >= 7000){
+ if(wn->channel != ctlr->channel){
+ ctlr->channel = wn->channel;
+ if(setphycontext(ctlr, CmdModify) != nil)
+ goto Broken;
+ }
+ if(wn->dtimperiod != ctlr->dtimperiod ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap){
+ updaterxflags(ctlr, wn);
+ ctlr->dtimperiod = wn->dtimperiod;
+ ctlr->erp = wn->erp;
+ ctlr->cap = wn->cap;
+ if(setmaccontext(edev, ctlr, CmdModify, wn) != nil)
+ goto Broken;
+ }
+ } else if(wn->channel != ctlr->channel ||
+ wn->erp != ctlr->erp ||
+ wn->cap != ctlr->cap)
+ if(rxon(edev, wn) != nil)
+ goto Broken;
}
/*
@@ -3892,38 +4152,42 @@
qunlock(ctlr);
return;
}
+
+
flags = 0;
sta = &ctlr->bcast;
- p = wn->minrate;
+ rate = 0;
+ tid = 8;
w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
+ qid = ctlr->datqid;
flags |= TFlagNeedACK;
- if(BLEN(b) > 512-4)
- flags |= TFlagNeedRTS;
-
if((w->fc[0] & 0x0c) == 0x08 && ctlr->bss.id != -1){
sta = &ctlr->bss;
+
p = wn->actrate;
+ if(p > wifi->rates)
+ rate = p - wifi->rates;
+ tid = 0;
}
+ if((ctlr->rxflags & RFlagTggProt) && !(ratetab[rate].flags & RFlagCCK))
+ flags |= TFlagNeedCTS;
if(flags & (TFlagNeedRTS|TFlagNeedCTS)){
- if(ctlr->family >= 7000 || ctlr->type != Type4965){
+ if(ctlr->type != Type4965){
flags &= ~(TFlagNeedRTS|TFlagNeedCTS);
+ /* depends on the mode set in rxon */
flags |= TFlagNeedProtection;
} else
flags |= TFlagFullTxOp;
}
- }
+ }else
+ qid = ctlr->auxqid;
if(sta->id == -1)
goto Broken;
- if(p >= wifi->rates)
- rate = p - wifi->rates;
- else
- rate = 0;
-
/* select first available antenna */
ant = ctlr->rfcfg.txantmask & 7;
ant |= (ant == 0);
@@ -3951,23 +4215,24 @@
p += 2; /* reserved */
put32(p, ~0); /* lifetime */
p += 4;
-
- /*
- * the device makes accesses to this page
- * to prevent host RAM going into sleep
- */
- put32(p, PCIWADDR(ctlr->kwpage));
+ /* ptr to scratch, set in qcmd() */
p += 5;
- *p++ = 60; /* rts ntries */
- *p++ = 15; /* data ntries */
- *p++ = 0; /* tid */
- put16(p, 0); /* timeout */
+ *p++ = 3; /* rts ntries */
+ if((w->fc[0] & 0x0c) == 0x00){
+ *p++ = 3; /* data ntries */
+ *p++ = tid;
+ put16(p, w->fc[0] == 0x00 || w->fc[0] == 0x20? 3 :2); /* timeout */
+ } else {
+ *p++ = 7; /* data ntries */
+ *p++ = tid;
+ put16(p, 0); /* timeout */
+ }
p += 2;
p += 2; /* txop */
qunlock(ctlr);
- if((err = qcmd(ctlr, 0, 28, c, p - c, b)) != nil){
+ if((err = qcmd(ctlr, qid, 28, c, p - c, b)) != nil){
print("#l%d: transmit %s\n", edev->ctlrno, err);
freeb(b);
}
@@ -4192,7 +4457,15 @@
if(len >= 0) switch(type){
case 1: /* microcontroller ready */
setfwinfo(ctlr, d, len);
+ if(ctlr->wait.w == Ierr)
+ wakeup(&ctlr->wait);
break;
+ case 2: /* firmware error */
+ if(len < 5)
+ break;
+ print("#l%d: firmware error 0x%ux cmd %d",
+ ctlr->edev->ctlrno, get32(d), d[4]);
+ break;
case 24: /* add node done */
if(len < 4)
break;
@@ -4362,6 +4635,11 @@
break;
case 197: /* rx compressed ba */
break;
+ case 4<<8|254: /* critical tempature notif */
+ print("#l%d: critical tempature, resetting device",
+ ctlr->edev->ctlrno);
+ ctlr->broken = 1;
+ break;
}
freeblist(bb);
if(tx != nil && tx->n > 0){
@@ -4368,7 +4646,7 @@
tx->n--;
wakeup(tx);
/* unlock 7k family nics as the command is done */
- if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
+ if(ctlr->family == 7000 && qid == ctlr->cmdqid && tx->n == 0)
nicunlock(ctlr);
}
}
@@ -4382,7 +4660,7 @@
static void
iwlinterrupt(Ureg*, void *arg)
{
- u32int isr, fhisr;
+ u32int isr, fhisr, tmp;
Ether *edev;
Ctlr *ctlr;
@@ -4390,8 +4668,25 @@
ctlr = edev->ctlr;
ilock(ctlr);
csr32w(ctlr, Imr, 0);
- isr = csr32r(ctlr, Isr);
- fhisr = csr32r(ctlr, FhIsr);
+ if(ctlr->ict.i >= 0){
+ isr = fhisr = 0;
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ while(tmp){
+ isr |= tmp;
+ ctlr->ict.p[ctlr->ict.i] = 0;
+ ctlr->ict.i = (ctlr->ict.i+1) % (4096/4);
+ tmp = ctlr->ict.p[ctlr->ict.i];
+ }
+ if(isr == 0xffffffff)
+ isr = 0;
+ /* workaround for cleared rx bit bug */
+ if(isr & 0xc0000)
+ isr |= 0x8000;
+ isr = isr&0xff | (isr&0xff00)<<16;
+ }else{
+ isr = csr32r(ctlr, Isr);
+ fhisr = csr32r(ctlr, FhIsr);
+ }
if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){
iunlock(ctlr);
return;
@@ -4399,10 +4694,27 @@
if(isr == 0 && fhisr == 0)
goto done;
csr32w(ctlr, Isr, isr);
- csr32w(ctlr, FhIsr, fhisr);
-
- if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx))
+ if(fhisr != 0)
+ csr32w(ctlr, FhIsr, fhisr);
+ if((isr & Ifhtx) && fhisr == 0)
+ csr32w(ctlr, FhIsr, Ifhtxmsk);
+ if((isr & (Iswrx | Ifhrx | Irxperiodic | Ialive)) || (fhisr & Ifhrx)){
+ if(ctlr->ict.i >= 0){
+ if(isr & (Iswrx | Ifhrx))
+ csr32w(ctlr, FhIsr, Ifhrxmsk);
+ if(isr & Irxperiodic)
+ csr32w(ctlr, Isr, Irxperiodic);
+ csr8w(ctlr, Iperiodic, 0);
+ /*
+ * generate an intr after 8ms, in case we got
+ * sent an ict interrupt before the rx dma got
+ * updated
+ */
+ if(isr & (Iswrx | Ifhrx))
+ csr8w(ctlr, Iperiodic, 255);
+ }
receive(ctlr);
+ }
if(isr & Ierr){
ctlr->broken = 1;
print("#l%d: fatal firmware error\n", edev->ctlrno);
@@ -4495,7 +4807,7 @@
break;
case 0x24f3: /* Wireless AC 8260 */
family = 8000;
- fwname = "iwm-8000C-34";
+ fwname = "iwm-8000C-36";
break;
case 0x24fb: /* Wireless AC 3168 */
family = 7000;
@@ -4503,11 +4815,11 @@
break;
case 0x24fd: /* Wireless AC 8265 */
family = 8000;
- fwname = "iwm-8265-34";
+ fwname = "iwm-8265-36";
break;
case 0x2526: /* Wireless AC 9260 */
family = 9000;
- fwname = "iwm-9260-34";
+ fwname = "iwm-9260-46";
break;
}
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -311,8 +311,11 @@
int n;
n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
+ if(n == 0 || wn->channel > 11){
+ /*
+ * no specific essid, just tell driver to tune channel
+ * or a channel thats not allowed globally
+ */
(*wifi->transmit)(wifi, wn, nil);
return;
}
@@ -481,7 +484,7 @@
d += 2;
wn->dtimcount = 0;
- wn->dtimperiod = 1;
+ wn->dtimperiod = 0;
rsnset = 0;
for(e = d + len; d+2 <= e; d = x){
@@ -547,6 +550,10 @@
wn->brsnelen = len;
rsnset = 1;
break;
+ case 42: /* ERP */
+ if(x - d > 0)
+ wn->erp = d[0];
+ break;
}
}
}
--- a/sys/src/9/port/wifi.h
+++ b/sys/src/9/port/wifi.h
@@ -54,6 +54,7 @@
uchar dtimperiod;
int ival;
int cap;
+ int erp;
int channel;
int brsnelen;
uchar brsne[258];