OK, turing.

<- leave blank

Wed Nov 5 13:37:11 EST 2025

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];


next