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