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.

Acked-by: Miquel Raynal <[email protected]>
Signed-off-by: Alexander Usyskin <[email protected]>
---
 drivers/mtd/devices/mtd_intel_dg.c | 65 ++++++++++++++++++++++++++++----------
 include/linux/intel_dg_nvm_aux.h   |  1 +
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/devices/mtd_intel_dg.c 
b/drivers/mtd/devices/mtd_intel_dg.c
index a566e86eb5e3..976246e94e79 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;
@@ -430,6 +431,15 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, 
struct device *device,
        /* clean error register, previous errors are ignored */
        idg_nvm_error(nvm);
 
+       if (nvm->survivability_enabled) {
+               nvm->size = nvm->regions[0].offset + nvm->regions[0].size - 1;
+               dev_dbg(device, "Registered survivability region %s 
size=%lld\n",
+                       nvm->regions[0].name,
+                       nvm->regions[0].size);
+               n = 1;
+               goto out;
+       }
+
        ret = idg_nvm_is_valid(nvm);
        if (ret) {
                dev_err(device, "The MEM is not valid %d\n", ret);
@@ -481,6 +491,7 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, 
struct device *device,
                        n++;
        }
 
+out:
        nvm->non_posted_erase = non_posted_erase;
 
        dev_dbg(device, "Registered %d regions\n", n);
@@ -753,15 +764,19 @@ static int intel_dg_mtd_probe(struct auxiliary_device 
*aux_dev,
 
        device = &aux_dev->dev;
 
-       /* count available regions */
-       for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
-               if (invm->regions[i].name)
-                       nregions++;
-       }
+       if (invm->survivability_size) {
+               nregions = 1;
+       } else {
+               /* count available regions */
+               for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
+                       if (invm->regions[i].name)
+                               nregions++;
+               }
 
-       if (!nregions) {
-               dev_err(device, "no regions defined\n");
-               return -ENODEV;
+               if (!nregions) {
+                       dev_err(device, "no regions defined\n");
+                       return -ENODEV;
+               }
        }
 
        nvm = kzalloc_flex(*nvm, regions, nregions);
@@ -771,21 +786,39 @@ 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;
 
-       for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
-               if (!invm->regions[i].name)
-                       continue;
-
+       if (invm->survivability_size) { /* survivability partition */
                char *name = kasprintf(GFP_KERNEL, "%s.%s",
-                                      dev_name(&aux_dev->dev), 
invm->regions[i].name);
+                                      dev_name(&aux_dev->dev), "DATA");
                if (!name) {
                        ret = -ENOMEM;
                        goto err_norpm;
                }
 
-               nvm->regions[n].name = name;
-               nvm->regions[n].id = i;
-               n++;
+               nvm->regions[0].name = name;
+               nvm->regions[0].id = 0;
+               nvm->regions[0].offset  = 0;
+               nvm->regions[0].size = invm->survivability_size;
+               nvm->regions[0].is_readable = true;
+               nvm->regions[0].is_writable = true;
+               n = 1;
+       } else {
+               for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
+                       if (!invm->regions[i].name)
+                               continue;
+
+                       char *name = kasprintf(GFP_KERNEL, "%s.%s",
+                                              dev_name(&aux_dev->dev), 
invm->regions[i].name);
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_norpm;
+                       }
+
+                       nvm->regions[n].name = name;
+                       nvm->regions[n].id = i;
+                       n++;
+               }
        }
 
        ret = devm_pm_runtime_enable(device);
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

Reply via email to