2015-04-01 15:12:18 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015, Christoph Hellwig.
|
2015-06-10 03:33:45 +08:00
|
|
|
* Copyright (c) 2015, Intel Corporation.
|
2015-04-01 15:12:18 +08:00
|
|
|
*/
|
|
|
|
#include <linux/platform_device.h>
|
2015-06-10 03:33:45 +08:00
|
|
|
#include <linux/libnvdimm.h>
|
|
|
|
#include <linux/module.h>
|
2015-04-01 15:12:18 +08:00
|
|
|
#include <asm/e820.h>
|
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
static void e820_pmem_release(struct device *dev)
|
2015-04-01 15:12:18 +08:00
|
|
|
{
|
2015-06-10 03:33:45 +08:00
|
|
|
struct nvdimm_bus *nvdimm_bus = dev->platform_data;
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
if (nvdimm_bus)
|
|
|
|
nvdimm_bus_unregister(nvdimm_bus);
|
|
|
|
}
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
static struct platform_device e820_pmem = {
|
|
|
|
.name = "e820_pmem",
|
|
|
|
.id = -1,
|
|
|
|
.dev = {
|
|
|
|
.release = e820_pmem_release,
|
|
|
|
},
|
|
|
|
};
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
static const struct attribute_group *e820_pmem_attribute_groups[] = {
|
|
|
|
&nvdimm_bus_attribute_group,
|
|
|
|
NULL,
|
|
|
|
};
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
static const struct attribute_group *e820_pmem_region_attribute_groups[] = {
|
|
|
|
&nd_region_attribute_group,
|
|
|
|
&nd_device_attribute_group,
|
|
|
|
NULL,
|
|
|
|
};
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
static __init int register_e820_pmem(void)
|
2015-04-01 15:12:18 +08:00
|
|
|
{
|
2015-06-10 03:33:45 +08:00
|
|
|
static struct nvdimm_bus_descriptor nd_desc;
|
|
|
|
struct device *dev = &e820_pmem.dev;
|
|
|
|
struct nvdimm_bus *nvdimm_bus;
|
|
|
|
int rc, i;
|
|
|
|
|
|
|
|
rc = platform_device_register(&e820_pmem);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
nd_desc.attr_groups = e820_pmem_attribute_groups;
|
|
|
|
nd_desc.provider_name = "e820";
|
|
|
|
nvdimm_bus = nvdimm_bus_register(dev, &nd_desc);
|
|
|
|
if (!nvdimm_bus)
|
|
|
|
goto err;
|
|
|
|
dev->platform_data = nvdimm_bus;
|
2015-04-01 15:12:18 +08:00
|
|
|
|
|
|
|
for (i = 0; i < e820.nr_map; i++) {
|
|
|
|
struct e820entry *ei = &e820.map[i];
|
2015-06-10 03:33:45 +08:00
|
|
|
struct resource res = {
|
|
|
|
.flags = IORESOURCE_MEM,
|
|
|
|
.start = ei->addr,
|
|
|
|
.end = ei->addr + ei->size - 1,
|
|
|
|
};
|
|
|
|
struct nd_region_desc ndr_desc;
|
|
|
|
|
|
|
|
if (ei->type != E820_PRAM)
|
|
|
|
continue;
|
2015-04-01 15:12:18 +08:00
|
|
|
|
2015-06-10 03:33:45 +08:00
|
|
|
memset(&ndr_desc, 0, sizeof(ndr_desc));
|
|
|
|
ndr_desc.res = &res;
|
|
|
|
ndr_desc.attr_groups = e820_pmem_region_attribute_groups;
|
2015-06-20 02:18:33 +08:00
|
|
|
ndr_desc.numa_node = NUMA_NO_NODE;
|
2015-06-10 03:33:45 +08:00
|
|
|
if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
|
|
|
|
goto err;
|
2015-04-01 15:12:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2015-06-10 03:33:45 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
dev_err(dev, "failed to register legacy persistent memory ranges\n");
|
|
|
|
platform_device_unregister(&e820_pmem);
|
|
|
|
return -ENXIO;
|
2015-04-01 15:12:18 +08:00
|
|
|
}
|
2015-06-10 03:33:45 +08:00
|
|
|
device_initcall(register_e820_pmem);
|