nvdimm/region: Move cache management to the region driver
[linux-2.6-microblaze.git] / drivers / nvdimm / region_devs.c
index e0875d3..83dbf39 100644 (file)
@@ -59,9 +59,51 @@ static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
        return 0;
 }
 
+static int nd_region_invalidate_memregion(struct nd_region *nd_region)
+{
+       int i, incoherent = 0;
+
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+               if (test_bit(NDD_INCOHERENT, &nvdimm->flags)) {
+                       incoherent++;
+                       break;
+               }
+       }
+
+       if (!incoherent)
+               return 0;
+
+       if (!cpu_cache_has_invalidate_memregion()) {
+               if (IS_ENABLED(CONFIG_NVDIMM_SECURITY_TEST)) {
+                       dev_warn(
+                               &nd_region->dev,
+                               "Bypassing cpu_cache_invalidate_memergion() for testing!\n");
+                       goto out;
+               } else {
+                       dev_err(&nd_region->dev,
+                               "Failed to synchronize CPU cache state\n");
+                       return -ENXIO;
+               }
+       }
+
+       cpu_cache_invalidate_memregion(IORES_DESC_PERSISTENT_MEMORY);
+out:
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+               clear_bit(NDD_INCOHERENT, &nvdimm->flags);
+       }
+
+       return 0;
+}
+
 int nd_region_activate(struct nd_region *nd_region)
 {
-       int i, j, num_flush = 0;
+       int i, j, rc, num_flush = 0;
        struct nd_region_data *ndrd;
        struct device *dev = &nd_region->dev;
        size_t flush_data_size = sizeof(void *);
@@ -85,6 +127,10 @@ int nd_region_activate(struct nd_region *nd_region)
        }
        nvdimm_bus_unlock(&nd_region->dev);
 
+       rc = nd_region_invalidate_memregion(nd_region);
+       if (rc)
+               return rc;
+
        ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
        if (!ndrd)
                return -ENOMEM;
@@ -1222,3 +1268,5 @@ int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
 
        return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict);
 }
+
+MODULE_IMPORT_NS(DEVMEM);