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

libnvdimm, e820: Register all pmem resources

There is currently a mismatch between the resources that will trigger
the e820_pmem driver to register/load and the resources that will
actually be surfaced as pmem ranges. register_e820_pmem() uses
walk_iomem_res_desc() which includes children and siblings. In contrast,
e820_pmem_probe() only considers top level resources. For example the
following resource tree results in the driver being loaded, but no
resources being registered:

398000000000-39bfffffffff : PCI Bus 0000:ae
39be00000000-39bf07ffffff : PCI Bus 0000:af
39be00000000-39beffffffff : 0000:af:00.0
39be10000000-39beffffffff : Persistent Memory (legacy)

Fix this up to allow definitions of "legacy" pmem ranges anywhere in
system-physical address space. Not that it is a recommended or safe to
define a pmem range in PCI space, but it is useful for debug /
experimentation, and the restriction on being a top-level resource was
arbitrary.

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

+23 -19
+22 -19
drivers/nvdimm/e820.c
··· 38 38 } 39 39 #endif 40 40 41 + static int e820_register_one(struct resource *res, void *data) 42 + { 43 + struct nd_region_desc ndr_desc; 44 + struct nvdimm_bus *nvdimm_bus = data; 45 + 46 + memset(&ndr_desc, 0, sizeof(ndr_desc)); 47 + ndr_desc.res = res; 48 + ndr_desc.attr_groups = e820_pmem_region_attribute_groups; 49 + ndr_desc.numa_node = e820_range_to_nid(res->start); 50 + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); 51 + if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) 52 + return -ENXIO; 53 + return 0; 54 + } 55 + 41 56 static int e820_pmem_probe(struct platform_device *pdev) 42 57 { 43 58 static struct nvdimm_bus_descriptor nd_desc; 44 59 struct device *dev = &pdev->dev; 45 60 struct nvdimm_bus *nvdimm_bus; 46 - struct resource *p; 61 + int rc = -ENXIO; 47 62 48 63 nd_desc.attr_groups = e820_pmem_attribute_groups; 49 64 nd_desc.provider_name = "e820"; ··· 68 53 goto err; 69 54 platform_set_drvdata(pdev, nvdimm_bus); 70 55 71 - for (p = iomem_resource.child; p ; p = p->sibling) { 72 - struct nd_region_desc ndr_desc; 73 - 74 - if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY) 75 - continue; 76 - 77 - memset(&ndr_desc, 0, sizeof(ndr_desc)); 78 - ndr_desc.res = p; 79 - ndr_desc.attr_groups = e820_pmem_region_attribute_groups; 80 - ndr_desc.numa_node = e820_range_to_nid(p->start); 81 - set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); 82 - if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) 83 - goto err; 84 - } 85 - 56 + rc = walk_iomem_res_desc(IORES_DESC_PERSISTENT_MEMORY_LEGACY, 57 + IORESOURCE_MEM, 0, -1, nvdimm_bus, e820_register_one); 58 + if (rc) 59 + goto err; 86 60 return 0; 87 - 88 - err: 61 + err: 89 62 nvdimm_bus_unregister(nvdimm_bus); 90 63 dev_err(dev, "failed to register legacy persistent memory ranges\n"); 91 - return -ENXIO; 64 + return rc; 92 65 } 93 66 94 67 static struct platform_driver e820_pmem_driver = {
+1
kernel/resource.c
··· 448 448 449 449 return __walk_iomem_res_desc(&res, desc, false, arg, func); 450 450 } 451 + EXPORT_SYMBOL_GPL(walk_iomem_res_desc); 451 452 452 453 /* 453 454 * This function calls the @func callback against all memory ranges of type