Subject: [9front] driver for intel wireless 7260

From: kemal <[email-masked]>
Date: Sat, 21 Aug 2021 22:23:12 +0000

(due to ml shitting itself hard, i have to send this mail again.)

reviving this thread.

2021-08-14 17:50 GMT, kemal <[email-masked]>:
> 1- as driver reads 8 bytes from nvm instead of 6 so fw doesn't
> spit us an ADVANCED_SYSASSERT, it was reading 2 more
> extra bytes. apparently those 2 extra bytes were put to
> the first 2 bytes of our buffer, so we got to skip that.

some more thoughts on this, i think as 0x15*2 is not multiple
of 8, fw rounds the offset to 0x14*2. i have touched to code
to read data from 0x14*2 then ignore the first 2 bytes, just
so it's not confusing. if this causes mac to be read wrong again,
report.

also, some more changes:

1. set the fwname at iwlpci, just to align the behavior with 8000+.
this is a cosmetic change.

2. i have discovered that on device boot/reset/shutdown functions,
our driver slept way much more than it should. the reason for that is,
driver used the function delay() on places where it needs to use
microdelay() instead. i have modified the code to use microdelay().
wpi likely needs similar changes too. i hope that this does not
break the code.

3. zzz a bit more on tx/rx scheduler shutdowns and niclock.

4. openbsd's iwm and linux apparently does not check if ownership
was obtained anymore in their handover functions. instead they
just loop until the hw is ready. aligned the behavior.
see linux commit: 289e5501c3141191dd830957f1d764d3dc14a54f

5. don't take antenna masks from nvm. it's apparently empty
in some cards from 7k family. we will rely on what the fw file gives
us.

6. when the calibration is completed, wakeup the proc that runs
postboot. otherwise that thing sleeps for like 2 whole seconds
even if calibration completed earlier.

i honestly don't think any of these changes will fix 7260 not
being able to get calibration results, but i don't see anything
wrong at all in postboot7000 at this point. i will just hope
these changes somehow make it get calibration results.

new diff attached.
--- /sys/src/9/pc/etheriwl.c
+++ /sys/src/9/pc/etheriwl.c
@@ -329,7 +329,29 @@
 	SchedTransTblOff	= 0x7E0,		// +q*2
 };
 
+/*
+ * uCode TLV api
+ */
 enum {
+	/* api[0] */
+	UcodeApiSta	= 1<<30,
+};
+
+/*
+ * uCode capabilities
+ */
+enum {
+	/* capa[0] */
+	UcodeCapLar	= 1<<1,
+
+	/* capa[1] */
+	UcodeCapQuota	= 1<<12,
+	
+	/* capa[2] */
+	UcodeCapLar2	= 1<<9,
+};
+
+enum {
 	FilterPromisc		= 1<<0,
 	FilterCtl		= 1<<1,
 	FilterMulticast		= 1<<2,
@@ -418,6 +440,7 @@
 	uint	build;
 	char	descr[64+1];
 
+	u32int	flags;
 	u32int	capa[4];
 	u32int	api[4];
 
@@ -635,8 +658,7 @@
 	Type2030	= 12,
 	Type2000	= 16,
 
-	Type7260	= 30,
-	Type8265	= 35,
+	Type7260	= 20,
 };
 
 static struct ratetab {
@@ -690,7 +712,6 @@
 	[Type6005] "iwn-6005", /* see in iwlattach() below */
 	[Type2030] "iwn-2030",
 	[Type2000] "iwn-2000",
-	[Type7260] "iwm-7260-17",
 };
 
 static char *qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block);
@@ -728,10 +749,12 @@
 	int i;
 
 	csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq);
-	for(i=0; i<1000; i++){
+	if(ctlr->family >= 8000)
+		microdelay(2);
+	for(i=0; i<1500; i++){
 		if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna)
 			return 0;
-		delay(10);
+		microdelay(10);
 	}
 	return "niclock: timeout";
 }
@@ -944,7 +967,7 @@
 		for(j=0; j<100; j++){
 			if(csr32r(ctlr, Cfg) & EepromLocked)
 				return 0;
-			delay(10);
+			microdelay(10);
 		}
 	}
 	return "eepromlock: timeout";
@@ -969,7 +992,7 @@
 			w = csr32r(ctlr, EepromIo);
 			if(w & 1)
 				break;
-			delay(5);
+			microdelay(5);
 		}
 		if(i == 10)
 			return "eepromread: timeout";
@@ -990,14 +1013,15 @@
 static char*
 handover(Ctlr *ctlr)
 {
-	int i;
+	int i, j;
 
 	csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
 	for(i=0; i<5; i++){
 		if(csr32r(ctlr, Cfg) & NicReady)
 			goto Ready;
-		delay(10);
+		microdelay(10);
 	}
+
 	if(ctlr->family >= 7000){
 		csr32w(ctlr, Dbglinkpwrmgmt, csr32r(ctlr, Dbglinkpwrmgmt) | (1<<31));
 		delay(1);
@@ -1004,20 +1028,16 @@
 	}
 
 	csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | Prepare);
-	for(i=0; i<15000; i++){
-		if((csr32r(ctlr, Cfg) & PrepareDone) == 0)
-			break;
-		delay(10);
+	for(i=0; i<750; i++){
+		csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
+		for(j=0; j<5; j++){
+			if(csr32r(ctlr, Cfg) & NicReady)
+				goto Ready;
+			microdelay(10);
+		}
+		microdelay(200);
 	}
-	if(i >= 15000)
-		return "handover: timeout";
 
-	csr32w(ctlr, Cfg, csr32r(ctlr, Cfg) | NicReady);
-	for(i=0; i<5; i++){
-		if(csr32r(ctlr, Cfg) & NicReady)
-			goto Ready;
-		delay(10);
-	}
 	return "handover: timeout";
 Ready:
 	if(ctlr->family >= 7000)
@@ -1035,7 +1055,7 @@
 	for(i=0; i<2500; i++){
 		if(csr32r(ctlr, Gpc) & MacClockReady)
 			return 0;
-		delay(10);
+		microdelay(10);
 	}
 	return "clockwait: timeout";
 }
@@ -1046,7 +1066,6 @@
 	int capoff;
 	char *err;
 
-
 	if(ctlr->family >= 7000){
 		/* Reset entire device */
 		csr32w(ctlr, Reset, (1<<7));
@@ -1100,7 +1119,7 @@
 
 		prphread(ctlr, OscClk);
 		prphread(ctlr, OscClk);
-		delay(20);
+		microdelay(20);
 
 		prphwrite(ctlr, OscClk, prphread(ctlr, OscClk) | OscClkCtrl);
 
@@ -1119,7 +1138,7 @@
 			prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt);
 		else
 			prphwrite(ctlr, ApmgClkEna, DmaClkRqt);
-		delay(20);
+		microdelay(20);
 
 		/* Disable L1-Active. */
 		prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11));
@@ -1158,7 +1177,7 @@
 			for(j = 0; j < 200; j++){
 				if(csr32r(ctlr, FhTxStatus) & (0x10000<<i))
 					break;
-				delay(10);
+				microdelay(20);
 			}
 		}
 		nicunlock(ctlr);
@@ -1168,17 +1187,17 @@
 	if(niclock(ctlr) == nil){
 		if(ctlr->mqrx){
 			prphwrite(ctlr, RfhDmaCfg, 0);
-			for(j = 0; j < 200; j++){
+			for(j = 0; j < 1000; j++){
 				if(prphread(ctlr, RfhGenStatus) & RfhGenStatusDmaIdle)
 					break;
-				delay(10);
+				microdelay(10);
 			}
 		} else {
 			csr32w(ctlr, FhRxConfig, 0);
-			for(j = 0; j < 200; j++){
+			for(j = 0; j < 1000; j++){
 				if(csr32r(ctlr, FhRxStatus) & 0x1000000)
 					break;
-				delay(10);
+				microdelay(10);
 			}
 		}
 		nicunlock(ctlr);
@@ -1190,7 +1209,7 @@
 			prphwrite(ctlr, ApmgClkDis, DmaClkRqt);
 			nicunlock(ctlr);
 		}
-		delay(5);
+		microdelay(5);
 	}
 
 	if(ctlr->family >= 7000){
@@ -1206,12 +1225,12 @@
 	for(j = 0; j < 100; j++){
 		if(csr32r(ctlr, Reset) & (1<<8))
 			break;
-		delay(10);
+		microdelay(10);
 	}
 
 	/* Reset the entire device. */
 	csr32w(ctlr, Reset, csr32r(ctlr, Reset) | (1<<7));
-	delay(10);
+	delay(5);
 
 	/* Clear "initialization complete" bit. */
 	csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) & ~InitDone);
@@ -1239,7 +1258,7 @@
 	if((err = niclock(ctlr)) != nil)
 		return err;
 	prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) | ResetReq);
-	delay(5);
+	microdelay(5);
 	prphwrite(ctlr, ApmgPs, prphread(ctlr, ApmgPs) & ~ResetReq);
 	nicunlock(ctlr);
 
@@ -1308,7 +1327,7 @@
 		ctlr->type &= 0x1FF;
 		ctlr->dash = ctlr->type & 3, ctlr->type >>= 2;
 		ctlr->step = ctlr->type & 3, ctlr->type >>= 2;
-		if(fwname[ctlr->type] == nil){
+		if(ctlr->fwname == nil && fwname[ctlr->type] == nil){
 			print("iwl: unsupported controller type %d\n", ctlr->type);
 			return -1;
 		}
@@ -1478,6 +1497,11 @@
 				s = &i->boot.text;
 				s->addr = 0x00000000;
 				goto Sect;
+			case 18:
+				if(l < 4)
+					goto Tooshort;
+				i->flags = get32(p);
+				break;
 			case 19:
 				if(i->main.nsect >= nelem(i->main.sect))
 					return "too many main sections";
@@ -1984,7 +2008,7 @@
 	*p++ = mcc[0];
 	*p++ = 0;
 	*p++ = 0;	// reserved
-	if(1){
+	if(ctlr->fw->capa[2] & UcodeCapLar2){
 		p += 4;
 		p += 5*4;
 	}
@@ -2236,10 +2260,6 @@
 		ctlr->rfcfg.step = (u >> 2) & 3;
 		ctlr->rfcfg.dash = (u >> 0) & 3;
 		ctlr->rfcfg.pnum = (u >> 6) & 3;
-
-		ctlr->rfcfg.txantmask = (u >> 8) & 15;
-		ctlr->rfcfg.rxantmask = (u >> 12) & 15;
-
 	} else {
 		if(readnvmsect(ctlr, 12, buf, 8, 0) != 8)
 			return "can't read nvm phy config";
@@ -2272,7 +2292,20 @@
 			ea[5] = a1 >> 0;
 		}
 	} else {
-		readnvmsect(ctlr, 0, ea, Eaddrlen, 0x15<<1);
+		/*
+		 * 7260 gets angry if we read 6 bytes from 0x15*2.
+		 * reading 8 bytes from 0x14*2 works fine.
+		 */
+		if(readnvmsect(ctlr, 0, buf, 8, 0x14<<1) != 8)
+			return "can't read ea from nvm";
+
+		/* byte order is 16 bit little endian. */
+		ea[0] = buf[3];
+		ea[1] = buf[2];
+		ea[2] = buf[5];
+		ea[3] = buf[4];
+		ea[4] = buf[7];
+		ea[5] = buf[6];
 	}
 	memmove(ctlr->edev->addr, ea, Eaddrlen);
 
@@ -2366,7 +2399,7 @@
 		p += 2;			/* sleep_tx_count */
 		p++;			/* sleep state flags */
 
-		*p++ = (ctlr->fw->api[0] & (1<<30)) != 0 ? type : 0;		/* station_type */
+		*p++ = ctlr->fw->api[0] & UcodeApiSta ? type : 0;		/* station_type */
 
 		p += 2;			/* assoc id */
 
@@ -2375,7 +2408,7 @@
 		put32(p, 1<<0);
 		p += 4;			/* tfd_queue_mask */
 
-		if(1){
+		if(ctlr->fw->api[0] & UcodeApiSta){
 			p += 2;		/* rx_ba_window */
 			p++;		/* sp_length */
 			p++;		/* uapsd_acs */
@@ -2640,7 +2673,7 @@
 static char*
 settimeevent(Ctlr *ctlr, int amr, int ival)
 {
-	int duration, delay, timeid;
+	int timeid;
 	uchar c[9*4], *p;
 	char *err;
 
@@ -2662,14 +2695,6 @@
 		break;
 	}
 
-	if(ival){
-		duration = ival*2;
-		delay = ival/2;
-	} else {
-		duration = 1024;
-		delay = 0;
-	}
-
 	memset(p = c, 0, sizeof(c));
 	put32(p, ctlr->macid);
 	p += 4;
@@ -2678,23 +2703,27 @@
 	put32(p, timeid);
 	p += 4;
 
-	put32(p, 0);	// apply time
-	p += 4;
-	put32(p, delay);
-	p += 4;
-	put32(p, 0);	// depends on
-	p += 4;
-	put32(p, 1);	// interval
-	p += 4;
-	put32(p, duration);
-	p += 4;
-	*p++ = 1;	// repeat
-	*p++ = 0;	// max frags
-	put16(p, 1<<0 | 1<<1 | 1<<11);	// policy
-	p += 2;
+	if(amr == CmdRemove)
+		p += 6*4;
+	else{
+		put32(p, 0);			// apply time
+		p += 4;
+		put32(p, ival/2);		// max delay
+		p += 4;
+		put32(p, 0);			// depends on
+		p += 4;
+		put32(p, 1);			// interval
+		p += 4;
+		put32(p, ival? ival*2: 1024);	// duration
+		p += 4;
+		*p++ = 1;			// repeat
+		*p++ = 0;			// max frags
+		put16(p, 1<<0 | 1<<1 | 1<<11);	// policy
+		p += 2;
+	}
 
 	ctlr->te.active = 0;
-	if((err =  cmd(ctlr, 41, c, p - c)) != nil)
+	if((err = cmd(ctlr, 41, c, p - c)) != nil)
 		return err;
 
 	if(amr == CmdRemove){
@@ -2713,6 +2742,9 @@
 	uchar c[4*(3*4)], *p;
 	int i;
 
+	if((ctlr->fw->capa[1] & UcodeCapQuota) == 0)
+		return nil;
+
 	i = 0;
 	p = c;
 
@@ -2822,13 +2854,13 @@
 	return cmd(ctlr, 210, c, 11*4);
 }
 
-static void
+static char*
 tttxbackoff(Ctlr *ctlr)
 {
 	uchar c[4];
 	
 	put32(c, 0);
-	cmd(ctlr, 126, c, sizeof(c));
+	return cmd(ctlr, 126, c, sizeof(c));
 }
 
 static char*
@@ -2848,6 +2880,9 @@
 	char *err;
 
 	if(ctlr->calib.done == 0){
+		if(ctlr->family == 7000)
+			if((err = sendbtcoexadv(ctlr)) != nil)
+				return err;
 		if((err = readnvmconfig(ctlr)) != nil)
 			return err;
 	}
@@ -2897,16 +2932,16 @@
 
 		/* Initialize tx backoffs to the minimum. */
 		if(ctlr->family == 7000)
-			tttxbackoff(ctlr);
+			if((err = tttxbackoff(ctlr)) != nil)
+				return err;
 
 		if((err = updatedevicepower(ctlr)) != nil){
 			print("can't update device power: %s\n", err);
 			return err;
 		}
-		if((err = sendmccupdate(ctlr, "ZZ")) != nil){
-			print("can't disable beacon filter: %s\n", err);
-			return err;
-		}
+		if(ctlr->fw->capa[0] & UcodeCapLar)
+			if((err = sendmccupdate(ctlr, "ZZ")) != nil)
+				return err;
 		if((err = disablebeaconfilter(ctlr)) != nil){
 			print("can't disable beacon filter: %s\n", err);
 			return err;
@@ -3362,7 +3397,7 @@
 	for(i=0; i<1000; i++){
 		if((prphread(ctlr, BsmWrCtrl) & (1<<31)) == 0)
 			break;
-		delay(10);
+		microdelay(10);
 	}
 	if(i == 1000){
 		nicunlock(ctlr);
@@ -3418,6 +3453,7 @@
 static char*
 qcmd(Ctlr *ctlr, uint qid, uint code, uchar *data, int size, Block *block)
 {
+	char *err;
 	int hdrlen;
 	Block *bcmd;
 	uchar *d, *c;
@@ -3452,10 +3488,10 @@
 		return "qcmd: broken";
 	}
 	/* wake up the nic (just needed for 7k) */
-	if(ctlr->family == 7000 && q->n == 0)
-		if(niclock(ctlr) != nil){
+	if(ctlr->family == 7000 && qid == 4 && q->n == 0)
+		if((err = niclock(ctlr)) != nil){
 			iunlock(ctlr);
-			return "qcmd: busy";
+			return err;
 		}
 	q->n++;
 	q->lastcmd = code;
@@ -3586,9 +3622,16 @@
 	int i;
 
 	for(i = 0; i < nelem(ctlr->tx); i++)
-		flushq(ctlr, i);
-	settimeevent(ctlr, CmdRemove, 0);
+		if((err = flushq(ctlr, i)) != nil){
+			print("can't flush queue %d: %s\n", i, err);
+			return err;
+		}
 
+	if((err = settimeevent(ctlr, CmdRemove, 0)) != nil){
+		print("can't remove time event: %s\n", err);
+		return err;
+	}
+
 	if((err = setbindingquotas(ctlr, -1)) != nil){
 		print("can't disable quotas: %s\n", err);
 		return err;
@@ -3630,7 +3673,7 @@
 		return err;
 	}
 	if((err = setbindingcontext(ctlr, CmdAdd)) != nil){
-		print("removing bindingcontext: %s\n", err);
+		print("adding bindingcontext: %s\n", err);
 		return err;
 	}
 	if((err = setmcastfilter(ctlr)) != nil){
@@ -4176,6 +4219,8 @@
 			/* wet floor */
 		case 103:	/* calibration done (Type5000 only) */
 			ctlr->calib.done = 1;
+			if(ctlr->wait.w == Ierr)
+				wakeup(&ctlr->wait);
 			break;
 		case 107:	/* calibration result (>= 7000 family) */
 			if(ctlr->family < 7000)
@@ -4283,8 +4328,8 @@
 		if(tx != nil && tx->n > 0){
 			tx->n--;
 			wakeup(tx);
-			/* unlock 7k family nics as all commands are done */
-			if(ctlr->family == 7000 && tx->n == 0)
+			/* unlock 7k family nics as the command is done */
+			if(ctlr->family == 7000 && qid == 4 && tx->n == 0)
 				nicunlock(ctlr);
 		}
 	}
@@ -4354,14 +4399,12 @@
 	int family;
 	
 	pdev = nil;
-	while(pdev = pcimatch(pdev, 0, 0)) {
+	while(pdev = pcimatch(pdev, Vintel, 0)) {
 		Ctlr *ctlr;
 		void *mem;
 		
 		if(pdev->ccrb != 2 || pdev->ccru != 0x80)
 			continue;
-		if(pdev->vid != 0x8086)
-			continue;
 		if(pdev->mem[0].bar & 1)
 			continue;
 
@@ -4398,7 +4441,7 @@
 		case 0x08b1:	/* Wireless AC 7260 */
 		case 0x08b2:	/* Wireless AC 7260 */
 			family = 7000;
-			fwname = nil;
+			fwname = "iwm-7260-17";
 			break;
 		case 0x24f3:	/* Wireless AC 8260 */
 			family = 8000;