Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libnvdimm, pmem: direct map legacy pmem by default

The expectation is that the legacy / non-standard pmem discovery method
(e820 type-12) will only ever be used to describe small quantities of
persistent memory. Larger capacities will be described via the ACPI
NFIT. When "allocate struct page from pmem" support is added this default
policy can be overridden by assigning a legacy pmem namespace to a pfn
device, however this would be only be necessary if a platform used the
legacy mechanism to define a very large range.

Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+50 -8
+1
drivers/nvdimm/e820.c
··· 49 49 ndr_desc.res = p; 50 50 ndr_desc.attr_groups = e820_pmem_region_attribute_groups; 51 51 ndr_desc.numa_node = NUMA_NO_NODE; 52 + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); 52 53 if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) 53 54 goto err; 54 55 }
+30 -5
drivers/nvdimm/namespace_devs.c
··· 13 13 #include <linux/module.h> 14 14 #include <linux/device.h> 15 15 #include <linux/slab.h> 16 + #include <linux/pmem.h> 16 17 #include <linux/nd.h> 17 18 #include "nd-core.h" 18 19 #include "nd.h" ··· 77 76 return dev ? dev->type == &namespace_io_device_type : false; 78 77 } 79 78 79 + bool pmem_should_map_pages(struct device *dev) 80 + { 81 + struct nd_region *nd_region = to_nd_region(dev->parent); 82 + 83 + if (!IS_ENABLED(CONFIG_ZONE_DEVICE)) 84 + return false; 85 + 86 + if (!test_bit(ND_REGION_PAGEMAP, &nd_region->flags)) 87 + return false; 88 + 89 + if (is_nd_pfn(dev) || is_nd_btt(dev)) 90 + return false; 91 + 92 + #ifdef ARCH_MEMREMAP_PMEM 93 + return ARCH_MEMREMAP_PMEM == MEMREMAP_WB; 94 + #else 95 + return false; 96 + #endif 97 + } 98 + EXPORT_SYMBOL(pmem_should_map_pages); 99 + 80 100 const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, 81 101 char *name) 82 102 { 83 103 struct nd_region *nd_region = to_nd_region(ndns->dev.parent); 84 - const char *suffix = ""; 104 + const char *suffix = NULL; 85 105 86 106 if (ndns->claim) { 87 107 if (is_nd_btt(ndns->claim)) ··· 115 93 dev_name(ndns->claim)); 116 94 } 117 95 118 - if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) 119 - sprintf(name, "pmem%d%s", nd_region->id, suffix); 120 - else if (is_namespace_blk(&ndns->dev)) { 96 + if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) { 97 + if (!suffix && pmem_should_map_pages(&ndns->dev)) 98 + suffix = "m"; 99 + sprintf(name, "pmem%d%s", nd_region->id, suffix ? suffix : ""); 100 + } else if (is_namespace_blk(&ndns->dev)) { 121 101 struct nd_namespace_blk *nsblk; 122 102 123 103 nsblk = to_nd_namespace_blk(&ndns->dev); 124 - sprintf(name, "ndblk%d.%d%s", nd_region->id, nsblk->id, suffix); 104 + sprintf(name, "ndblk%d.%d%s", nd_region->id, nsblk->id, 105 + suffix ? suffix : ""); 125 106 } else { 126 107 return NULL; 127 108 }
+2
drivers/nvdimm/nd.h
··· 100 100 struct ida ns_ida; 101 101 struct ida btt_ida; 102 102 struct ida pfn_ida; 103 + unsigned long flags; 103 104 struct device *ns_seed; 104 105 struct device *btt_seed; 105 106 struct device *pfn_seed; ··· 277 276 void nd_iostat_end(struct bio *bio, unsigned long start); 278 277 resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk); 279 278 const u8 *nd_dev_to_uuid(struct device *dev); 279 + bool pmem_should_map_pages(struct device *dev); 280 280 #endif /* __ND_H__ */
+12 -3
drivers/nvdimm/pmem.c
··· 148 148 return ERR_PTR(-EBUSY); 149 149 } 150 150 151 - pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr, pmem->size); 152 - if (!pmem->virt_addr) 153 - return ERR_PTR(-ENXIO); 151 + if (pmem_should_map_pages(dev)) { 152 + void *addr = devm_memremap_pages(dev, res); 153 + 154 + if (IS_ERR(addr)) 155 + return addr; 156 + pmem->virt_addr = (void __pmem *) addr; 157 + } else { 158 + pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr, 159 + pmem->size); 160 + if (!pmem->virt_addr) 161 + return ERR_PTR(-ENXIO); 162 + } 154 163 155 164 return pmem; 156 165 }
+1
drivers/nvdimm/region_devs.c
··· 758 758 nd_region->provider_data = ndr_desc->provider_data; 759 759 nd_region->nd_set = ndr_desc->nd_set; 760 760 nd_region->num_lanes = ndr_desc->num_lanes; 761 + nd_region->flags = ndr_desc->flags; 761 762 nd_region->ro = ro; 762 763 nd_region->numa_node = ndr_desc->numa_node; 763 764 ida_init(&nd_region->ns_ida);
+4
include/linux/libnvdimm.h
··· 31 31 ND_CMD_ARS_STATUS_MAX = SZ_4K, 32 32 ND_MAX_MAPPINGS = 32, 33 33 34 + /* region flag indicating to direct-map persistent memory by default */ 35 + ND_REGION_PAGEMAP = 0, 36 + 34 37 /* mark newly adjusted resources as requiring a label update */ 35 38 DPA_RESOURCE_ADJUSTED = 1 << 0, 36 39 }; ··· 94 91 void *provider_data; 95 92 int num_lanes; 96 93 int numa_node; 94 + unsigned long flags; 97 95 }; 98 96 99 97 struct nvdimm_bus;