shithub: plan9front

Download patch

ref: f00fb547730cb40e6d3fdf9e660409ae6cb904af
parent: 74e56dbf3584ec61637d31618e171a18058f0946
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 15 14:45:35 EST 2023

sdmmc: implement boot partition access for emmc

We expose the boot partitions as separate units,
such as sdM0 is the user data partition and sdM1
is the first boot partition and sdM2 is the
second boot partition.

On access, we automatically switch the
BOOT_PARTITOIN_ACCESS bits in the EXT_CSD.

Also, the units ctl file contains "boot enabled"
or "boot disabled" if that unit is the active
or inactive boot partition.

--- a/sys/src/9/port/sdmmc.c
+++ b/sys/src/9/port/sdmmc.c
@@ -85,6 +85,8 @@
 
 typedef struct Card Card;
 struct Card {
+	QLock;
+
 	SDev	*dev;
 	SDio	*io;
 
@@ -102,6 +104,9 @@
 
 	u8int	ext_csd[512];
 
+	uvlong	sectors[3];
+	uint	secsize;
+
 	int	retry;
 };
 
@@ -159,12 +164,12 @@
 		if(more > 0)
 			isdio--;	/* try again */
 	}
+	card->dev = sdev;
+	card->io = io;
 	sdev->idno = 'M';
 	sdev->ifc = &sdmmcifc;
-	sdev->nunit = 1;
+	sdev->nunit = nelem(card->sectors);
 	sdev->ctlr = card;
-	card->dev = sdev;
-	card->io = io;
 	return sdev;
 }
 
@@ -229,9 +234,8 @@
 }
 
 static void
-identify(SDunit *unit)
+identify(Card *card)
 {
-	Card *card = unit->dev->ctlr;
 	uint csize, mult;
 	uvlong capacity;
 
@@ -238,8 +242,10 @@
 #define CSD(end, start)	rbits(card->csd, start, (end)-(start)+1)
 	mult = CSD(49, 47);
 	csize = CSD(73, 62);
-	unit->sectors = (csize+1) * (1<<(mult+2));
-	unit->secsize = 1 << CSD(83, 80);
+	card->secsize = 1 << CSD(83, 80);
+	card->sectors[0] = (csize+1) * (1<<(mult+2));
+	card->sectors[1] = 0;
+	card->sectors[2] = 0;
 
 	card->specver = 0;
 
@@ -299,7 +305,11 @@
 		if(card->specver >= 420) {
 			capacity = EXT_CSD(215, 212) * 512ULL;
 			if(capacity > 0x80000000ULL)
-				unit->sectors = capacity / unit->secsize;
+				card->sectors[0] = capacity / card->secsize;
+
+			capacity = EXT_CSD(226, 226) * 0x20000ULL;
+			card->sectors[1] = capacity / card->secsize;
+			card->sectors[2] = capacity / card->secsize;
 		}
 	} else {
 		switch(CSD(127, 126)){
@@ -310,14 +320,16 @@
 			card->specver = 200;
 			csize = CSD(69, 48);
 			capacity = (csize+1) * 0x80000ULL;
-			unit->sectors = capacity / unit->secsize;
+			card->sectors[0] = capacity / card->secsize;
 			break;
 		}
 	}
 
-	if(unit->secsize == 1024){
-		unit->sectors <<= 1;
-		unit->secsize = 512;
+	if(card->secsize == 1024){
+		card->secsize = 512;
+		card->sectors[0] <<= 1;
+		card->sectors[1] <<= 1;
+		card->sectors[2] <<= 1;
 	}
 }
 
@@ -328,7 +340,14 @@
 	SDio *io = card->io;
 	int n;
 
+	eqlock(card);
+	if(waserror()){
+		qunlock(card);
+		nexterror();
+	}
 	n = (*io->inquiry)(io, (char*)&unit->inquiry[8], sizeof(unit->inquiry)-8);
+	qunlock(card);
+	poperror();
 	if(n < 0)
 		return 0;
 	unit->inquiry[0] = 0x00;	/* direct access (disk) */
@@ -401,6 +420,11 @@
 	u32int r[4], ocr;
 	int i;
 
+	card->secsize = 0;
+	card->sectors[0] = 0;
+	card->sectors[1] = 0;
+	card->sectors[2] = 0;
+
 	card->buswidth = 1;
 	card->busspeed = Initfreq;
 	(*io->bus)(io, card->buswidth, card->busspeed);
@@ -471,6 +495,7 @@
 	Card *card = arg;
 	int i = 0;
 
+	qlock(card);
 	while(waserror())
 		;
 	if(i++ < card->retry)
@@ -477,6 +502,8 @@
 		cardinit(card);
 	USED(i);
 	card->retry = 0;
+	qunlock(card);
+
 	pexit("", 1);
 }
 
@@ -487,21 +514,32 @@
 	SDio *io = card->io;
 	u32int r[4];
 
-	assert(unit->subno == 0);
 	if(card->retry)
 		return 0;
+
+	eqlock(card);
 	if(waserror()){
 		unit->sectors = 0;
 		if(card->retry++ == 0)
 			kproc(unit->name, retryproc, card);
+		qunlock(card);
 		return 0;
 	}
-	if(unit->sectors != 0){
+	if(card->secsize != 0 && card->sectors[0] != 0){
+		unit->secsize = card->secsize;
+		unit->sectors = card->sectors[unit->subno];
+		if(unit->sectors == 0){
+			qunlock(card);
+			poperror();
+			return 0;
+		}
 		(*io->cmd)(io, &SEND_STATUS, card->rca<<Rcashift, r);
+		qunlock(card);
 		poperror();
 		return 1;
 	}
 	if(cardinit(card) != 1){
+		qunlock(card);
 		poperror();
 		return 2;
 	}
@@ -511,9 +549,12 @@
 	(*io->bus)(io, 0, card->busspeed = SDfreq);
 	tsleep(&up->sleep, return0, nil, 10);
 
-	identify(unit);
-	(*io->cmd)(io, &SET_BLOCKLEN, unit->secsize, r);	
+	identify(card);
+	unit->secsize = card->secsize;
+	unit->sectors = card->sectors[unit->subno];
 
+	(*io->cmd)(io, &SET_BLOCKLEN, card->secsize, r);
+
 	if(card->ismmc && card->specver >= 400){
 		if(!waserror()){
 			mmcswitch(card, MMCSetHSTiming);
@@ -551,6 +592,7 @@
 			poperror();
 		}
 	}
+	qunlock(card);
 	poperror();
 	return 1;
 }
@@ -562,12 +604,11 @@
 	char *s = p, *e = s + l;
 	int i;
 
-	assert(unit->subno == 0);
-	if(unit->sectors == 0){
+	if(card->sectors[0] == 0)
 		mmconline(unit);
-		if(unit->sectors == 0)
-			return 0;
-	}
+	if(unit->sectors == 0)
+		return 0;
+
 	p = seprint(p, e, "version %s %d.%2.2d\n", card->ismmc? "MMC": "SD",
 		card->specver/100, card->specver%100);
 
@@ -581,6 +622,11 @@
 	for(i = nelem(card->csd)-1; i >= 0; i--)
 		p = seprint(p, e, "%8.8ux", card->csd[i]);
 
+	if(card->ismmc)
+		p = seprint(p, e, "\nboot %s",
+			((card->ext_csd[179]>>3)&7) == (unit->subno==0? 7: unit->subno)?
+			"enabled": "disabled" );
+
 	p = seprint(p, e, "\ngeometry %llud %ld\n",
 		unit->sectors, unit->secsize);
 	return p - s;
@@ -597,9 +643,21 @@
 	ulong b;
 
 	USED(lun);
-	assert(unit->subno == 0);
 	if(unit->sectors == 0)
 		error(Echange);
+
+	eqlock(card);
+	if(waserror()){
+		qunlock(card);
+		nexterror();
+	}
+
+	if(card->ismmc && unit->subno != (card->ext_csd[179]&7)){
+		b = (card->ext_csd[179] & ~7) | unit->subno;
+		mmcswitch(card, 3<<24 | 179<<16 | b<<8);
+		card->ext_csd[179] = b;
+	}
+
 	buf = data;
 	len = unit->secsize;
 	if(Multiblock && (!write || !io->nomultiwrite)){
@@ -629,6 +687,10 @@
 			buf += len;
 		}
 	}
+
+	qunlock(card);
+	poperror();
+
 	return (b - bno) * len;
 }