[PATCH 1/2] mtd: mtd_intel_dg: add survivability partition

Alexander Usyskin <[email protected]>
Newsgroups org.infradead.lists.linux-mtd,org.freedesktop.lists.dri-devel,org.freedesktop.lists.intel-xe,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add option to expose additional fixed-sized partition starting
from the beginning of storage.
Xe driver can request this partition exposure if firmware or hardware
have detected failure that may involve corrupted partition table.
Fixed-sized partition allows full storage re-write in this situation.

Signed-off-by: Alexander Usyskin <[email protected]>
---
 drivers/mtd/devices/mtd_intel_dg.c | 80 +++++++++++++++++++++++++++-----------
 include/linux/intel_dg_nvm_aux.h   |  1 +
 2 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c
index f2fa8f68d190..d11ddc687c4a 100644
--- a/drivers/mtd/devices/mtd_intel_dg.c
+++ b/drivers/mtd/devices/mtd_intel_dg.c
@@ -31,6 +31,7 @@ struct intel_dg_nvm {
 	void __iomem *base;
 	void __iomem *base2;
 	bool non_posted_erase;
+	bool survivability_enabled;
 
 	size_t size;
 	unsigned int nregions;
@@ -205,6 +206,13 @@ static unsigned int idg_nvm_get_region(const struct intel_dg_nvm *nvm, loff_t fr
 {
 	unsigned int i;
 
+	/*
+	 * When survivability region is enabled it positioned on index 0 and has region_id = 0
+	 * Region 0 is special, via this region whole device memory can be accessed.
+	 */
+	if (nvm->survivability_enabled)
+		return 0;
+
 	for (i = 0; i < nvm->nregions; i++) {
 		if ((nvm->regions[i].offset + nvm->regions[i].size - 1) >= from &&
 		    nvm->regions[i].offset <= from &&
@@ -443,32 +451,39 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device,
 		u32 address, base, limit, region;
 		u8 id = nvm->regions[i].id;
 
-		address = NVM_FLREG(id);
-		region = idg_nvm_read32(nvm, address);
+		if (nvm->regions[i].size) { /* pre-defined survivability region */
+			limit = nvm->regions[i].offset + nvm->regions[i].size - 1;
 
-		base = FIELD_GET(NVM_FREG_BASE_MASK, region) << NVM_FREG_ADDR_SHIFT;
-		limit = (FIELD_GET(NVM_FREG_ADDR_MASK, region) << NVM_FREG_ADDR_SHIFT) |
-			NVM_FREG_MIN_REGION_SIZE;
+			if (nvm->size < limit)
+				nvm->size = limit;
+		} else {
+			address = NVM_FLREG(id);
+			region = idg_nvm_read32(nvm, address);
 
-		dev_dbg(device, "[%d] %s: region: 0x%08X base: 0x%08x limit: 0x%08x\n",
-			id, nvm->regions[i].name, region, base, limit);
+			base = FIELD_GET(NVM_FREG_BASE_MASK, region) << NVM_FREG_ADDR_SHIFT;
+			limit = (FIELD_GET(NVM_FREG_ADDR_MASK, region) << NVM_FREG_ADDR_SHIFT) |
+				NVM_FREG_MIN_REGION_SIZE;
 
-		if (base >= limit || (i > 0 && limit == 0)) {
-			dev_dbg(device, "[%d] %s: disabled\n",
-				id, nvm->regions[i].name);
-			nvm->regions[i].is_readable = 0;
-			continue;
-		}
+			dev_dbg(device, "[%d] %s: region: 0x%08X base: 0x%08x limit: 0x%08x\n",
+				id, nvm->regions[i].name, region, base, limit);
 
-		if (nvm->size < limit)
-			nvm->size = limit;
+			if (base >= limit || (i > 0 && limit == 0)) {
+				dev_dbg(device, "[%d] %s: disabled\n",
+					id, nvm->regions[i].name);
+				nvm->regions[i].is_readable = 0;
+				continue;
+			}
 
-		nvm->regions[i].offset = base;
-		nvm->regions[i].size = limit - base + 1;
-		/* No write access to descriptor; mask it out*/
-		nvm->regions[i].is_writable = idg_nvm_region_writable(access_map, id);
+			if (nvm->size < limit)
+				nvm->size = limit;
 
-		nvm->regions[i].is_readable = idg_nvm_region_readable(access_map, id);
+			nvm->regions[i].offset = base;
+			nvm->regions[i].size = limit - base + 1;
+			/* No write access to descriptor; mask it out*/
+			nvm->regions[i].is_writable = idg_nvm_region_writable(access_map, id);
+
+			nvm->regions[i].is_readable = idg_nvm_region_readable(access_map, id);
+		}
 		dev_dbg(device, "Registered, %s id=%d offset=%lld size=%lld rd=%d wr=%d\n",
 			nvm->regions[i].name,
 			nvm->regions[i].id,
@@ -748,7 +763,7 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
 	struct intel_dg_nvm *nvm;
 	struct device *device;
 	unsigned int nregions;
-	unsigned int i, n;
+	unsigned int i, n = 0;
 	int ret;
 
 	device = &aux_dev->dev;
@@ -764,6 +779,9 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
 		return -ENODEV;
 	}
 
+	if (invm->survivability_size)
+		nregions++;
+
 	nvm = kzalloc_flex(*nvm, regions, nregions);
 	if (!nvm)
 		return -ENOMEM;
@@ -771,8 +789,26 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
 	kref_init(&nvm->refcnt);
 	mutex_init(&nvm->lock);
 	nvm->nregions = nregions;
+	nvm->survivability_enabled = !!invm->survivability_size;
+
+	if (invm->survivability_size) { /* this partition should be at idx 0 */
+		char *name = kasprintf(GFP_KERNEL, "%s.%s",
+				       dev_name(&aux_dev->dev), "DATA");
+		if (!name) {
+			ret = -ENOMEM;
+			goto err_norpm;
+		}
+
+		nvm->regions[n].name = name;
+		nvm->regions[n].id = 0;
+		nvm->regions[n].offset  = 0;
+		nvm->regions[n].size = invm->survivability_size;
+		nvm->regions[n].is_readable = true;
+		nvm->regions[n].is_writable = true;
+		n++;
+	}
 
-	for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
+	for (i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
 		if (!invm->regions[i].name)
 			continue;
 
diff --git a/include/linux/intel_dg_nvm_aux.h b/include/linux/intel_dg_nvm_aux.h
index 625d46a6b96e..84b5b6e0c4ea 100644
--- a/include/linux/intel_dg_nvm_aux.h
+++ b/include/linux/intel_dg_nvm_aux.h
@@ -21,6 +21,7 @@ struct intel_dg_nvm_dev {
 	struct auxiliary_device aux_dev;
 	bool writable_override;
 	bool non_posted_erase;
+	size_t survivability_size;
 	struct resource bar;
 	struct resource bar2;
 	const struct intel_dg_nvm_region *regions;

-- 
2.53.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.