-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libnvdimm, pmem: add libnvdimm support to the pmem driver
nd_pmem attaches to persistent memory regions and namespaces emitted by the libnvdimm subsystem, and, same as the original pmem driver, presents the system-physical-address range as a block device. The existing e820-type-12 to pmem setup is converted to an nvdimm_bus that emits an nd_namespace_io device. Note that the X in 'pmemX' is now derived from the parent region. This provides some stability to the pmem devices names from boot-to-boot. The minor numbers are also more predictable by passing 0 to alloc_disk(). Cc: Andy Lutomirski <luto@amacapital.net> Cc: Boaz Harrosh <boaz@plexistor.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Jens Axboe <axboe@fb.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com> Acked-by: Christoph Hellwig <hch@lst.de> Tested-by: Toshi Kani <toshi.kani@hp.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
- Loading branch information
Dan Williams
committed
Jun 25, 2015
1 parent
18da2c9
commit 9f53f9f
Showing
3 changed files
with
96 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,81 @@ | ||
/* | ||
* Copyright (c) 2015, Christoph Hellwig. | ||
* Copyright (c) 2015, Intel Corporation. | ||
*/ | ||
#include <linux/memblock.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/slab.h> | ||
#include <linux/libnvdimm.h> | ||
#include <linux/module.h> | ||
#include <asm/e820.h> | ||
#include <asm/page_types.h> | ||
#include <asm/setup.h> | ||
|
||
static __init void register_pmem_device(struct resource *res) | ||
static void e820_pmem_release(struct device *dev) | ||
{ | ||
struct platform_device *pdev; | ||
int error; | ||
struct nvdimm_bus *nvdimm_bus = dev->platform_data; | ||
|
||
pdev = platform_device_alloc("pmem", PLATFORM_DEVID_AUTO); | ||
if (!pdev) | ||
return; | ||
if (nvdimm_bus) | ||
nvdimm_bus_unregister(nvdimm_bus); | ||
} | ||
|
||
error = platform_device_add_resources(pdev, res, 1); | ||
if (error) | ||
goto out_put_pdev; | ||
static struct platform_device e820_pmem = { | ||
.name = "e820_pmem", | ||
.id = -1, | ||
.dev = { | ||
.release = e820_pmem_release, | ||
}, | ||
}; | ||
|
||
error = platform_device_add(pdev); | ||
if (error) | ||
goto out_put_pdev; | ||
return; | ||
static const struct attribute_group *e820_pmem_attribute_groups[] = { | ||
&nvdimm_bus_attribute_group, | ||
NULL, | ||
}; | ||
|
||
out_put_pdev: | ||
dev_warn(&pdev->dev, "failed to add 'pmem' (persistent memory) device!\n"); | ||
platform_device_put(pdev); | ||
} | ||
static const struct attribute_group *e820_pmem_region_attribute_groups[] = { | ||
&nd_region_attribute_group, | ||
&nd_device_attribute_group, | ||
NULL, | ||
}; | ||
|
||
static __init int register_pmem_devices(void) | ||
static __init int register_e820_pmem(void) | ||
{ | ||
int i; | ||
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; | ||
|
||
for (i = 0; i < e820.nr_map; i++) { | ||
struct e820entry *ei = &e820.map[i]; | ||
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; | ||
|
||
if (ei->type == E820_PRAM) { | ||
struct resource res = { | ||
.flags = IORESOURCE_MEM, | ||
.start = ei->addr, | ||
.end = ei->addr + ei->size - 1, | ||
}; | ||
register_pmem_device(&res); | ||
} | ||
memset(&ndr_desc, 0, sizeof(ndr_desc)); | ||
ndr_desc.res = &res; | ||
ndr_desc.attr_groups = e820_pmem_region_attribute_groups; | ||
if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) | ||
goto err; | ||
} | ||
|
||
return 0; | ||
|
||
err: | ||
dev_err(dev, "failed to register legacy persistent memory ranges\n"); | ||
platform_device_unregister(&e820_pmem); | ||
return -ENXIO; | ||
} | ||
device_initcall(register_pmem_devices); | ||
device_initcall(register_e820_pmem); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters