In ACPI 6.2a the platform capability structure has been added to the NFIT
tables. That provides software the ability to determine whether a system
supports the auto flushing of CPU caches on power loss. If the capability
is supported, we do not need to do dax_write_cache(). Plumbing the path
to set the property on per region from the NFTI tables.

This patch depends on the ACPI NFIT 6.2a platform capabilities support code
in include/acpi/actbl1.h.

Signed-off-by: Dave Jiang <dave.ji...@intel.com>
---
 drivers/acpi/nfit/core.c     |   20 ++++++++++++++++++++
 drivers/acpi/nfit/nfit.h     |    1 +
 drivers/nvdimm/pmem.c        |    4 +++-
 drivers/nvdimm/region_devs.c |    1 +
 include/linux/libnvdimm.h    |    5 +++++
 5 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index ff2580e7611d..c08b3da61b93 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -838,6 +838,18 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
        return true;
 }
 
+static bool add_platform_cap(struct acpi_nfit_desc *acpi_desc,
+               struct acpi_nfit_capabilities *pcap)
+{
+       struct device *dev = acpi_desc->dev;
+       u8 mask;
+
+       mask = pcap->highest_capability - 1 + pcap->highest_capability;
+       acpi_desc->platform_cap = pcap->capabilities & (u32)mask;
+       dev_dbg(dev, "%s: cap: %#x\n", __func__, acpi_desc->platform_cap);
+       return true;
+}
+
 static void *add_table(struct acpi_nfit_desc *acpi_desc,
                struct nfit_table_prev *prev, void *table, const void *end)
 {
@@ -883,6 +895,10 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc,
        case ACPI_NFIT_TYPE_SMBIOS:
                dev_dbg(dev, "%s: smbios\n", __func__);
                break;
+       case ACPI_NFIT_TYPE_CAPABILITIES:
+               if (!add_platform_cap(acpi_desc, table))
+                       return err;
+               break;
        default:
                dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type);
                break;
@@ -2649,6 +2665,9 @@ static int acpi_nfit_register_region(struct 
acpi_nfit_desc *acpi_desc,
        else
                ndr_desc->numa_node = NUMA_NO_NODE;
 
+       if(acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_CACHE_FLUSH)
+               set_bit(ND_REGION_PERSIST_CACHE, &ndr_desc->flags);
+
        list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
                struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev;
                struct nd_mapping_desc *mapping;
@@ -3457,6 +3476,7 @@ static __init int nfit_init(void)
        BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9);
        BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
        BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
+       BUILD_BUG_ON(sizeof(struct acpi_nfit_capabilities) != 16);
 
        guid_parse(UUID_VOLATILE_MEMORY, &nfit_uuid[NFIT_SPA_VOLATILE]);
        guid_parse(UUID_PERSISTENT_MEMORY, &nfit_uuid[NFIT_SPA_PM]);
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index f0cf18b2da8b..50d36e166d70 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -202,6 +202,7 @@ struct acpi_nfit_desc {
        unsigned long dimm_cmd_force_en;
        unsigned long bus_cmd_force_en;
        unsigned long bus_nfit_cmd_force_en;
+       unsigned int platform_cap;
        int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
                        void *iobuf, u64 len, int rw);
 };
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 7fbc5c5dc8e1..13f2ed80899e 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -35,6 +35,7 @@
 #include "pmem.h"
 #include "pfn.h"
 #include "nd.h"
+#include "nd-core.h"
 
 static struct device *to_dev(struct pmem_device *pmem)
 {
@@ -334,7 +335,8 @@ static int pmem_attach_disk(struct device *dev,
                dev_warn(dev, "unable to guarantee persistence of writes\n");
                fua = 0;
        }
-       wbc = nvdimm_has_cache(nd_region);
+       wbc = nvdimm_has_cache(nd_region) &
+               !test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags);
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
                                dev_name(&ndns->dev))) {
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index abaf38c61220..87e8cd10de05 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -994,6 +994,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus 
*nvdimm_bus,
        dev->groups = ndr_desc->attr_groups;
        nd_region->ndr_size = resource_size(ndr_desc->res);
        nd_region->ndr_start = ndr_desc->res->start;
+
        nd_device_register(dev);
 
        return nd_region;
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index f8109ddb5ef1..f2fc0da4da04 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -47,6 +47,11 @@ enum {
 
        /* region flag indicating to direct-map persistent memory by default */
        ND_REGION_PAGEMAP = 0,
+       /*
+        * Platform ensures entire CPU store data path is flushed to pmem on
+        * system power loss.
+        */
+       ND_REGION_PERSIST_CACHE = 1,
 
        /* mark newly adjusted resources as requiring a label update */
        DPA_RESOURCE_ADJUSTED = 1 << 0,

_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to