xref: /openbmc/linux/arch/x86/kernel/pmem.c (revision e2f1cf25)
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 #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 
37 static __init int register_e820_pmem(void)
38 {
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;
81 }
82 device_initcall(register_e820_pmem);
83