Merge tag 'libnvdimm-for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw...
[cascardo/linux.git] / arch / x86 / kernel / pmem.c
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);