diff options
author | Dan Williams <dan.j.williams@intel.com> | 2018-06-02 14:43:39 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2018-06-02 20:05:43 -0400 |
commit | d76401ade0bb6ab0a70dea317ec115d5425880cf (patch) | |
tree | 39897c699f5b0a7e467b5d63fa7a2c676b779b31 | |
parent | 3f46833df94eec3b7057181898e02cb9e4a49074 (diff) |
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>
-rw-r--r-- | drivers/nvdimm/e820.c | 41 | ||||
-rw-r--r-- | kernel/resource.c | 1 |
2 files changed, 23 insertions, 19 deletions
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 6f9a6ffd7cde..521eaf53a52a 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c | |||
@@ -38,12 +38,27 @@ static int e820_range_to_nid(resource_size_t addr) | |||
38 | } | 38 | } |
39 | #endif | 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 | static int e820_pmem_probe(struct platform_device *pdev) | 56 | static int e820_pmem_probe(struct platform_device *pdev) |
42 | { | 57 | { |
43 | static struct nvdimm_bus_descriptor nd_desc; | 58 | static struct nvdimm_bus_descriptor nd_desc; |
44 | struct device *dev = &pdev->dev; | 59 | struct device *dev = &pdev->dev; |
45 | struct nvdimm_bus *nvdimm_bus; | 60 | struct nvdimm_bus *nvdimm_bus; |
46 | struct resource *p; | 61 | int rc = -ENXIO; |
47 | 62 | ||
48 | nd_desc.attr_groups = e820_pmem_attribute_groups; | 63 | nd_desc.attr_groups = e820_pmem_attribute_groups; |
49 | nd_desc.provider_name = "e820"; | 64 | nd_desc.provider_name = "e820"; |
@@ -53,27 +68,15 @@ static int e820_pmem_probe(struct platform_device *pdev) | |||
53 | goto err; | 68 | goto err; |
54 | platform_set_drvdata(pdev, nvdimm_bus); | 69 | platform_set_drvdata(pdev, nvdimm_bus); |
55 | 70 | ||
56 | for (p = iomem_resource.child; p ; p = p->sibling) { | 71 | rc = walk_iomem_res_desc(IORES_DESC_PERSISTENT_MEMORY_LEGACY, |
57 | struct nd_region_desc ndr_desc; | 72 | IORESOURCE_MEM, 0, -1, nvdimm_bus, e820_register_one); |
58 | 73 | if (rc) | |
59 | if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY) | 74 | goto err; |
60 | continue; | ||
61 | |||
62 | memset(&ndr_desc, 0, sizeof(ndr_desc)); | ||
63 | ndr_desc.res = p; | ||
64 | ndr_desc.attr_groups = e820_pmem_region_attribute_groups; | ||
65 | ndr_desc.numa_node = e820_range_to_nid(p->start); | ||
66 | set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); | ||
67 | if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) | ||
68 | goto err; | ||
69 | } | ||
70 | |||
71 | return 0; | 75 | return 0; |
72 | 76 | err: | |
73 | err: | ||
74 | nvdimm_bus_unregister(nvdimm_bus); | 77 | nvdimm_bus_unregister(nvdimm_bus); |
75 | dev_err(dev, "failed to register legacy persistent memory ranges\n"); | 78 | dev_err(dev, "failed to register legacy persistent memory ranges\n"); |
76 | return -ENXIO; | 79 | return rc; |
77 | } | 80 | } |
78 | 81 | ||
79 | static struct platform_driver e820_pmem_driver = { | 82 | static struct platform_driver e820_pmem_driver = { |
diff --git a/kernel/resource.c b/kernel/resource.c index 2af6c03858b9..b85f59e8a4b8 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -448,6 +448,7 @@ int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, | |||
448 | 448 | ||
449 | return __walk_iomem_res_desc(&res, desc, false, arg, func); | 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 | * This function calls the @func callback against all memory ranges of type | 454 | * This function calls the @func callback against all memory ranges of type |