The UEFI 2.7 specification defines an updated BTT metadata format,
bumping the revision to 2.0. Add support for the new format, while
retaining compatibility for the old 1.1 format.

Cc: Toshi Kani <[email protected]>
Cc: Linda Knippers <[email protected]>
Cc: Dan Williams <[email protected]>
Signed-off-by: Vishal Verma <[email protected]>
---

v2:
 - Don't enforce new BTTs being v2, base that decision on the holder class (Dan)
 - Refactor nd_btt_version slightly, and get rid of the version enum.

 drivers/nvdimm/btt.c      | 28 ++++++++++++++++++++--------
 drivers/nvdimm/btt.h      |  2 ++
 drivers/nvdimm/btt_devs.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 drivers/nvdimm/nd.h       |  3 +++
 4 files changed, 66 insertions(+), 13 deletions(-)

diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 983718b..7ca11df 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -37,8 +37,8 @@ static int arena_read_bytes(struct arena_info *arena, 
resource_size_t offset,
        struct nd_btt *nd_btt = arena->nd_btt;
        struct nd_namespace_common *ndns = nd_btt->ndns;
 
-       /* arena offsets are 4K from the base of the device */
-       offset += SZ_4K;
+       /* arena offsets may be shifted from the base of the device */
+       offset += arena->nd_btt->initial_offset;
        return nvdimm_read_bytes(ndns, offset, buf, n, flags);
 }
 
@@ -48,8 +48,8 @@ static int arena_write_bytes(struct arena_info *arena, 
resource_size_t offset,
        struct nd_btt *nd_btt = arena->nd_btt;
        struct nd_namespace_common *ndns = nd_btt->ndns;
 
-       /* arena offsets are 4K from the base of the device */
-       offset += SZ_4K;
+       /* arena offsets may be shifted from the base of the device */
+       offset += arena->nd_btt->initial_offset;
        return nvdimm_write_bytes(ndns, offset, buf, n, flags);
 }
 
@@ -576,8 +576,8 @@ static struct arena_info *alloc_arena(struct btt *btt, 
size_t size,
        arena->internal_lbasize = roundup(arena->external_lbasize,
                                        INT_LBASIZE_ALIGNMENT);
        arena->nfree = BTT_DEFAULT_NFREE;
-       arena->version_major = 1;
-       arena->version_minor = 1;
+       arena->version_major = btt->nd_btt->version_major;
+       arena->version_minor = btt->nd_btt->version_minor;
 
        if (available % BTT_PG_SIZE)
                available -= (available % BTT_PG_SIZE);
@@ -1425,6 +1425,7 @@ int nvdimm_namespace_attach_btt(struct 
nd_namespace_common *ndns)
 {
        struct nd_btt *nd_btt = to_nd_btt(ndns->claim);
        struct nd_region *nd_region;
+       struct btt_sb *btt_sb;
        struct btt *btt;
        size_t rawsize;
 
@@ -1433,10 +1434,21 @@ int nvdimm_namespace_attach_btt(struct 
nd_namespace_common *ndns)
                return -ENODEV;
        }
 
-       rawsize = nvdimm_namespace_capacity(ndns) - SZ_4K;
+       btt_sb = devm_kzalloc(&nd_btt->dev, sizeof(*btt_sb), GFP_KERNEL);
+
+       /*
+        * If this returns < 0, that is ok as it just means there wasn't
+        * an existing BTT, and we're creating a new one. We still need to
+        * call this as we need the version dependent fields in nd_btt to be
+        * set correctly based on the holder class
+        */
+       nd_btt_version(nd_btt, ndns, btt_sb);
+
+       rawsize = nvdimm_namespace_capacity(ndns) - nd_btt->initial_offset;
        if (rawsize < ARENA_MIN_SIZE) {
                dev_dbg(&nd_btt->dev, "%s must be at least %ld bytes\n",
-                               dev_name(&ndns->dev), ARENA_MIN_SIZE + SZ_4K);
+                               dev_name(&ndns->dev),
+                               ARENA_MIN_SIZE + nd_btt->initial_offset);
                return -ENXIO;
        }
        nd_region = to_nd_region(nd_btt->dev.parent);
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index b2f8651..888e862 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -184,5 +184,7 @@ struct btt {
 };
 
 bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super);
+int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
+               struct btt_sb *btt_sb);
 
 #endif
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index 31d875a..cd0718e 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -260,20 +260,56 @@ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct 
btt_sb *super)
 }
 EXPORT_SYMBOL(nd_btt_arena_is_valid);
 
+int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
+               struct btt_sb *btt_sb)
+{
+       /*
+        * At this point, the claim class can only be 'BTT' or 'NONE'. BTT
+        * implies a BTT v2.0 and none implies v1.1
+        */
+       if (ndns->claim_class == NVDIMM_CCLASS_BTT) {
+               /* Probe/setup for BTT v2.0 */
+               nd_btt->initial_offset = 0;
+               nd_btt->version_major = 2;
+               nd_btt->version_minor = 0;
+               if (nvdimm_read_bytes(ndns, 0, btt_sb, sizeof(*btt_sb), 0))
+                       return -ENXIO;
+               if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
+                       return -ENODEV;
+               if ((le16_to_cpu(btt_sb->version_major) != 2) ||
+                               (le16_to_cpu(btt_sb->version_minor) != 0))
+                       return -ENODEV;
+       } else {
+               /* Probe/setup for BTT v1.1 */
+               nd_btt->initial_offset = SZ_4K;
+               nd_btt->version_major = 1;
+               nd_btt->version_minor = 1;
+               if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
+                       return -ENXIO;
+               if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
+                       return -ENODEV;
+               if ((le16_to_cpu(btt_sb->version_major) != 1) ||
+                               (le16_to_cpu(btt_sb->version_minor) != 1))
+                       return -ENODEV;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(nd_btt_version);
+
 static int __nd_btt_probe(struct nd_btt *nd_btt,
                struct nd_namespace_common *ndns, struct btt_sb *btt_sb)
 {
+       int btt_ver;
+
        if (!btt_sb || !ndns || !nd_btt)
                return -ENODEV;
 
-       if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
-               return -ENXIO;
-
        if (nvdimm_namespace_capacity(ndns) < SZ_16M)
                return -ENXIO;
 
-       if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
-               return -ENODEV;
+       btt_ver = nd_btt_version(nd_btt, ndns, btt_sb);
+       if (btt_ver < 0)
+               return btt_ver;
 
        nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize);
        nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 8cabd83..1496ef9 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -194,6 +194,9 @@ struct nd_btt {
        u64 size;
        u8 *uuid;
        int id;
+       int initial_offset;
+       u16 version_major;
+       u16 version_minor;
 };
 
 enum nd_pfn_mode {
-- 
2.9.3

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to