diff options
author | Dan Williams <dan.j.williams@intel.com> | 2015-08-19 00:34:34 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2015-08-19 00:34:34 -0400 |
commit | 7a67832c7e44c20935c5d6f2264035a0f7bf0d8f (patch) | |
tree | 1ace57d407ece741401f7b8878f1b2d85e990004 | |
parent | 6ec689542b5bc516187917d49b112847dfb75b0b (diff) |
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 <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | arch/x86/Kconfig | 6 | ||||
-rw-r--r-- | arch/x86/include/uapi/asm/e820.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/pmem.c | 79 | ||||
-rw-r--r-- | drivers/nvdimm/Makefile | 3 | ||||
-rw-r--r-- | drivers/nvdimm/e820.c | 86 | ||||
-rw-r--r-- | tools/testing/nvdimm/Kbuild | 4 |
7 files changed, 108 insertions, 74 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b3a1a5d77d92..76c61154ed50 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1426,10 +1426,14 @@ config ILLEGAL_POINTER_VALUE | |||
1426 | 1426 | ||
1427 | source "mm/Kconfig" | 1427 | source "mm/Kconfig" |
1428 | 1428 | ||
1429 | config X86_PMEM_LEGACY_DEVICE | ||
1430 | bool | ||
1431 | |||
1429 | config X86_PMEM_LEGACY | 1432 | config X86_PMEM_LEGACY |
1430 | bool "Support non-standard NVDIMMs and ADR protected memory" | 1433 | tristate "Support non-standard NVDIMMs and ADR protected memory" |
1431 | depends on PHYS_ADDR_T_64BIT | 1434 | depends on PHYS_ADDR_T_64BIT |
1432 | depends on BLK_DEV | 1435 | depends on BLK_DEV |
1436 | select X86_PMEM_LEGACY_DEVICE | ||
1433 | select LIBNVDIMM | 1437 | select LIBNVDIMM |
1434 | help | 1438 | help |
1435 | Treat memory marked using the non-standard e820 type of 12 as used | 1439 | Treat memory marked using the non-standard e820 type of 12 as used |
diff --git a/arch/x86/include/uapi/asm/e820.h b/arch/x86/include/uapi/asm/e820.h index 0f457e6eab18..9dafe59cf6e2 100644 --- a/arch/x86/include/uapi/asm/e820.h +++ b/arch/x86/include/uapi/asm/e820.h | |||
@@ -37,7 +37,7 @@ | |||
37 | /* | 37 | /* |
38 | * This is a non-standardized way to represent ADR or NVDIMM regions that | 38 | * This is a non-standardized way to represent ADR or NVDIMM regions that |
39 | * persist over a reboot. The kernel will ignore their special capabilities | 39 | * 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. |
41 | * | 41 | * |
42 | * ( Note that older platforms also used 6 for the same type of memory, | 42 | * ( Note that older platforms also used 6 for the same type of memory, |
43 | * but newer versions switched to 12 as 6 was assigned differently. Some | 43 | * but newer versions switched to 12 as 6 was assigned differently. Some |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 0f15af41bd80..ac2bb7e28ba2 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -92,7 +92,7 @@ obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o | |||
92 | obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o | 92 | obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o |
93 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o | 93 | obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o |
94 | obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o | 94 | obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o |
95 | obj-$(CONFIG_X86_PMEM_LEGACY) += pmem.o | 95 | obj-$(CONFIG_X86_PMEM_LEGACY_DEVICE) += pmem.o |
96 | 96 | ||
97 | obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o | 97 | obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o |
98 | 98 | ||
diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c index 64f90f53bb85..4f00b63d7ff3 100644 --- a/arch/x86/kernel/pmem.c +++ b/arch/x86/kernel/pmem.c | |||
@@ -3,80 +3,17 @@ | |||
3 | * Copyright (c) 2015, Intel Corporation. | 3 | * Copyright (c) 2015, Intel Corporation. |
4 | */ | 4 | */ |
5 | #include <linux/platform_device.h> | 5 | #include <linux/platform_device.h> |
6 | #include <linux/libnvdimm.h> | ||
7 | #include <linux/module.h> | 6 | #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 | }; | ||
36 | 7 | ||
37 | static __init int register_e820_pmem(void) | 8 | static __init int register_e820_pmem(void) |
38 | { | 9 | { |
39 | static struct nvdimm_bus_descriptor nd_desc; | 10 | struct platform_device *pdev; |
40 | struct device *dev = &e820_pmem.dev; | 11 | |
41 | struct nvdimm_bus *nvdimm_bus; | 12 | /* |
42 | int rc, i; | 13 | * See drivers/nvdimm/e820.c for the implementation, this is |
43 | 14 | * simply here to trigger the module to load on demand. | |
44 | rc = platform_device_register(&e820_pmem); | 15 | */ |
45 | if (rc) | 16 | pdev = platform_device_alloc("e820_pmem", -1); |
46 | return rc; | 17 | return platform_device_add(pdev); |
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; | ||
81 | } | 18 | } |
82 | device_initcall(register_e820_pmem); | 19 | device_initcall(register_e820_pmem); |
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 594bb97c867a..9bf15db52dee 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile | |||
@@ -2,6 +2,7 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o | |||
2 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | 2 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o |
3 | obj-$(CONFIG_ND_BTT) += nd_btt.o | 3 | obj-$(CONFIG_ND_BTT) += nd_btt.o |
4 | obj-$(CONFIG_ND_BLK) += nd_blk.o | 4 | obj-$(CONFIG_ND_BLK) += nd_blk.o |
5 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o | ||
5 | 6 | ||
6 | nd_pmem-y := pmem.o | 7 | nd_pmem-y := pmem.o |
7 | 8 | ||
@@ -9,6 +10,8 @@ nd_btt-y := btt.o | |||
9 | 10 | ||
10 | nd_blk-y := blk.o | 11 | nd_blk-y := blk.o |
11 | 12 | ||
13 | nd_e820-y := e820.o | ||
14 | |||
12 | libnvdimm-y := core.o | 15 | libnvdimm-y := core.o |
13 | libnvdimm-y += bus.o | 16 | libnvdimm-y += bus.o |
14 | libnvdimm-y += dimm_devs.o | 17 | libnvdimm-y += dimm_devs.o |
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c new file mode 100644 index 000000000000..1b5743ad92db --- /dev/null +++ b/drivers/nvdimm/e820.c | |||
@@ -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); | ||
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index f56914c7929b..d7c136a96346 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o | |||
15 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | 15 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o |
16 | obj-$(CONFIG_ND_BTT) += nd_btt.o | 16 | obj-$(CONFIG_ND_BTT) += nd_btt.o |
17 | obj-$(CONFIG_ND_BLK) += nd_blk.o | 17 | obj-$(CONFIG_ND_BLK) += nd_blk.o |
18 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o | ||
18 | obj-$(CONFIG_ACPI_NFIT) += nfit.o | 19 | obj-$(CONFIG_ACPI_NFIT) += nfit.o |
19 | 20 | ||
20 | nfit-y := $(ACPI_SRC)/nfit.o | 21 | nfit-y := $(ACPI_SRC)/nfit.o |
@@ -29,6 +30,9 @@ nd_btt-y += config_check.o | |||
29 | nd_blk-y := $(NVDIMM_SRC)/blk.o | 30 | nd_blk-y := $(NVDIMM_SRC)/blk.o |
30 | nd_blk-y += config_check.o | 31 | nd_blk-y += config_check.o |
31 | 32 | ||
33 | nd_e820-y := $(NVDIMM_SRC)/e820.o | ||
34 | nd_e820-y += config_check.o | ||
35 | |||
32 | libnvdimm-y := $(NVDIMM_SRC)/core.o | 36 | libnvdimm-y := $(NVDIMM_SRC)/core.o |
33 | libnvdimm-y += $(NVDIMM_SRC)/bus.o | 37 | libnvdimm-y += $(NVDIMM_SRC)/bus.o |
34 | libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o | 38 | libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o |