Skip to content

Commit 7a67832

Browse files
committed
libnvdimm, e820: make CONFIG_X86_PMEM_LEGACY a tristate option
We currently register a platform device for e820 type-12 memory and register a nvdimm bus beneath it. Registering the platform device triggers the device-core machinery to probe for a driver, but that search currently comes up empty. Building the nvdimm-bus registration into the e820_pmem platform device registration in this way forces libnvdimm to be built-in. Instead, convert the built-in portion of CONFIG_X86_PMEM_LEGACY to simply register a platform device and move the rest of the logic to the driver for e820_pmem, for the following reasons: 1/ Letting e820_pmem support be a module allows building and testing libnvdimm.ko changes without rebooting 2/ All the normal policy around modules can be applied to e820_pmem (unbind to disable and/or blacklisting the module from loading by default) 3/ Moving the driver to a generic location and converting it to scan "iomem_resource" rather than "e820.map" means any other architecture can take advantage of this simple nvdimm resource discovery mechanism by registering a resource named "Persistent Memory (legacy)" Cc: Christoph Hellwig <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent 6ec6895 commit 7a67832

File tree

7 files changed

+108
-74
lines changed

7 files changed

+108
-74
lines changed

arch/x86/Kconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,10 +1426,14 @@ config ILLEGAL_POINTER_VALUE
14261426

14271427
source "mm/Kconfig"
14281428

1429+
config X86_PMEM_LEGACY_DEVICE
1430+
bool
1431+
14291432
config X86_PMEM_LEGACY
1430-
bool "Support non-standard NVDIMMs and ADR protected memory"
1433+
tristate "Support non-standard NVDIMMs and ADR protected memory"
14311434
depends on PHYS_ADDR_T_64BIT
14321435
depends on BLK_DEV
1436+
select X86_PMEM_LEGACY_DEVICE
14331437
select LIBNVDIMM
14341438
help
14351439
Treat memory marked using the non-standard e820 type of 12 as used

arch/x86/include/uapi/asm/e820.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/*
3838
* This is a non-standardized way to represent ADR or NVDIMM regions that
3939
* persist over a reboot. The kernel will ignore their special capabilities
40-
* unless the CONFIG_X86_PMEM_LEGACY=y option is set.
40+
* unless the CONFIG_X86_PMEM_LEGACY option is set.
4141
*
4242
* ( Note that older platforms also used 6 for the same type of memory,
4343
* but newer versions switched to 12 as 6 was assigned differently. Some

arch/x86/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o
9292
obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o
9393
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o
9494
obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o
95-
obj-$(CONFIG_X86_PMEM_LEGACY) += pmem.o
95+
obj-$(CONFIG_X86_PMEM_LEGACY_DEVICE) += pmem.o
9696

9797
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
9898

arch/x86/kernel/pmem.c

Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,80 +3,17 @@
33
* Copyright (c) 2015, Intel Corporation.
44
*/
55
#include <linux/platform_device.h>
6-
#include <linux/libnvdimm.h>
76
#include <linux/module.h>
8-
#include <asm/e820.h>
9-
10-
static void e820_pmem_release(struct device *dev)
11-
{
12-
struct nvdimm_bus *nvdimm_bus = dev->platform_data;
13-
14-
if (nvdimm_bus)
15-
nvdimm_bus_unregister(nvdimm_bus);
16-
}
17-
18-
static struct platform_device e820_pmem = {
19-
.name = "e820_pmem",
20-
.id = -1,
21-
.dev = {
22-
.release = e820_pmem_release,
23-
},
24-
};
25-
26-
static const struct attribute_group *e820_pmem_attribute_groups[] = {
27-
&nvdimm_bus_attribute_group,
28-
NULL,
29-
};
30-
31-
static const struct attribute_group *e820_pmem_region_attribute_groups[] = {
32-
&nd_region_attribute_group,
33-
&nd_device_attribute_group,
34-
NULL,
35-
};
367

378
static __init int register_e820_pmem(void)
389
{
39-
static struct nvdimm_bus_descriptor nd_desc;
40-
struct device *dev = &e820_pmem.dev;
41-
struct nvdimm_bus *nvdimm_bus;
42-
int rc, i;
43-
44-
rc = platform_device_register(&e820_pmem);
45-
if (rc)
46-
return rc;
47-
48-
nd_desc.attr_groups = e820_pmem_attribute_groups;
49-
nd_desc.provider_name = "e820";
50-
nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
51-
if (!nvdimm_bus)
52-
goto err;
53-
dev->platform_data = nvdimm_bus;
54-
55-
for (i = 0; i < e820.nr_map; i++) {
56-
struct e820entry *ei = &e820.map[i];
57-
struct resource res = {
58-
.flags = IORESOURCE_MEM,
59-
.start = ei->addr,
60-
.end = ei->addr + ei->size - 1,
61-
};
62-
struct nd_region_desc ndr_desc;
63-
64-
if (ei->type != E820_PRAM)
65-
continue;
66-
67-
memset(&ndr_desc, 0, sizeof(ndr_desc));
68-
ndr_desc.res = &res;
69-
ndr_desc.attr_groups = e820_pmem_region_attribute_groups;
70-
ndr_desc.numa_node = NUMA_NO_NODE;
71-
if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
72-
goto err;
73-
}
74-
75-
return 0;
76-
77-
err:
78-
dev_err(dev, "failed to register legacy persistent memory ranges\n");
79-
platform_device_unregister(&e820_pmem);
80-
return -ENXIO;
10+
struct platform_device *pdev;
11+
12+
/*
13+
* See drivers/nvdimm/e820.c for the implementation, this is
14+
* simply here to trigger the module to load on demand.
15+
*/
16+
pdev = platform_device_alloc("e820_pmem", -1);
17+
return platform_device_add(pdev);
8118
}
8219
device_initcall(register_e820_pmem);

drivers/nvdimm/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
22
obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
33
obj-$(CONFIG_ND_BTT) += nd_btt.o
44
obj-$(CONFIG_ND_BLK) += nd_blk.o
5+
obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
56

67
nd_pmem-y := pmem.o
78

89
nd_btt-y := btt.o
910

1011
nd_blk-y := blk.o
1112

13+
nd_e820-y := e820.o
14+
1215
libnvdimm-y := core.o
1316
libnvdimm-y += bus.o
1417
libnvdimm-y += dimm_devs.o

drivers/nvdimm/e820.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2015, Christoph Hellwig.
3+
* Copyright (c) 2015, Intel Corporation.
4+
*/
5+
#include <linux/platform_device.h>
6+
#include <linux/libnvdimm.h>
7+
#include <linux/module.h>
8+
9+
static const struct attribute_group *e820_pmem_attribute_groups[] = {
10+
&nvdimm_bus_attribute_group,
11+
NULL,
12+
};
13+
14+
static const struct attribute_group *e820_pmem_region_attribute_groups[] = {
15+
&nd_region_attribute_group,
16+
&nd_device_attribute_group,
17+
NULL,
18+
};
19+
20+
static int e820_pmem_remove(struct platform_device *pdev)
21+
{
22+
struct nvdimm_bus *nvdimm_bus = platform_get_drvdata(pdev);
23+
24+
nvdimm_bus_unregister(nvdimm_bus);
25+
return 0;
26+
}
27+
28+
static int e820_pmem_probe(struct platform_device *pdev)
29+
{
30+
static struct nvdimm_bus_descriptor nd_desc;
31+
struct device *dev = &pdev->dev;
32+
struct nvdimm_bus *nvdimm_bus;
33+
struct resource *p;
34+
35+
nd_desc.attr_groups = e820_pmem_attribute_groups;
36+
nd_desc.provider_name = "e820";
37+
nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
38+
if (!nvdimm_bus)
39+
goto err;
40+
platform_set_drvdata(pdev, nvdimm_bus);
41+
42+
for (p = iomem_resource.child; p ; p = p->sibling) {
43+
struct nd_region_desc ndr_desc;
44+
45+
if (strncmp(p->name, "Persistent Memory (legacy)", 26) != 0)
46+
continue;
47+
48+
memset(&ndr_desc, 0, sizeof(ndr_desc));
49+
ndr_desc.res = p;
50+
ndr_desc.attr_groups = e820_pmem_region_attribute_groups;
51+
ndr_desc.numa_node = NUMA_NO_NODE;
52+
if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
53+
goto err;
54+
}
55+
56+
return 0;
57+
58+
err:
59+
nvdimm_bus_unregister(nvdimm_bus);
60+
dev_err(dev, "failed to register legacy persistent memory ranges\n");
61+
return -ENXIO;
62+
}
63+
64+
static struct platform_driver e820_pmem_driver = {
65+
.probe = e820_pmem_probe,
66+
.remove = e820_pmem_remove,
67+
.driver = {
68+
.name = "e820_pmem",
69+
},
70+
};
71+
72+
static __init int e820_pmem_init(void)
73+
{
74+
return platform_driver_register(&e820_pmem_driver);
75+
}
76+
77+
static __exit void e820_pmem_exit(void)
78+
{
79+
platform_driver_unregister(&e820_pmem_driver);
80+
}
81+
82+
MODULE_ALIAS("platform:e820_pmem*");
83+
MODULE_LICENSE("GPL v2");
84+
MODULE_AUTHOR("Intel Corporation");
85+
module_init(e820_pmem_init);
86+
module_exit(e820_pmem_exit);

tools/testing/nvdimm/Kbuild

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
1515
obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
1616
obj-$(CONFIG_ND_BTT) += nd_btt.o
1717
obj-$(CONFIG_ND_BLK) += nd_blk.o
18+
obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
1819
obj-$(CONFIG_ACPI_NFIT) += nfit.o
1920

2021
nfit-y := $(ACPI_SRC)/nfit.o
@@ -29,6 +30,9 @@ nd_btt-y += config_check.o
2930
nd_blk-y := $(NVDIMM_SRC)/blk.o
3031
nd_blk-y += config_check.o
3132

33+
nd_e820-y := $(NVDIMM_SRC)/e820.o
34+
nd_e820-y += config_check.o
35+
3236
libnvdimm-y := $(NVDIMM_SRC)/core.o
3337
libnvdimm-y += $(NVDIMM_SRC)/bus.o
3438
libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o

0 commit comments

Comments
 (0)