Skip to content

Commit 7171976

Browse files
oohaldjbw
authored andcommitted
libnvdimm: Add device-tree based driver
This patch adds peliminary device-tree bindings for persistent memory regions. The driver registers a libnvdimm bus for each pmem-region node and each address range under the node is converted to a region within that bus. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 1ff19f4 commit 7171976

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8035,6 +8035,13 @@ Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
80358035
S: Supported
80368036
F: drivers/nvdimm/pmem*
80378037

8038+
LIBNVDIMM: DEVICETREE BINDINGS
8039+
M: Oliver O'Halloran <oohall@gmail.com>
8040+
L: linux-nvdimm@lists.01.org
8041+
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
8042+
S: Supported
8043+
F: drivers/nvdimm/of_pmem.c
8044+
80388045
LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
80398046
M: Dan Williams <dan.j.williams@intel.com>
80408047
L: linux-nvdimm@lists.01.org

drivers/nvdimm/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,14 @@ config NVDIMM_DAX
102102

103103
Select Y if unsure
104104

105+
config OF_PMEM
106+
tristate "Device-tree support for persistent memory regions"
107+
depends on OF
108+
default LIBNVDIMM
109+
help
110+
Allows regions of persistent memory to be described in the
111+
device-tree.
112+
113+
Select Y if unsure.
114+
105115
endif

drivers/nvdimm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
44
obj-$(CONFIG_ND_BTT) += nd_btt.o
55
obj-$(CONFIG_ND_BLK) += nd_blk.o
66
obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
7+
obj-$(CONFIG_OF_PMEM) += of_pmem.o
78

89
nd_pmem-y := pmem.o
910

drivers/nvdimm/of_pmem.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
#define pr_fmt(fmt) "of_pmem: " fmt
4+
5+
#include <linux/of_platform.h>
6+
#include <linux/of_address.h>
7+
#include <linux/libnvdimm.h>
8+
#include <linux/module.h>
9+
#include <linux/ioport.h>
10+
#include <linux/slab.h>
11+
12+
static const struct attribute_group *region_attr_groups[] = {
13+
&nd_region_attribute_group,
14+
&nd_device_attribute_group,
15+
NULL,
16+
};
17+
18+
static const struct attribute_group *bus_attr_groups[] = {
19+
&nvdimm_bus_attribute_group,
20+
NULL,
21+
};
22+
23+
struct of_pmem_private {
24+
struct nvdimm_bus_descriptor bus_desc;
25+
struct nvdimm_bus *bus;
26+
};
27+
28+
static int of_pmem_region_probe(struct platform_device *pdev)
29+
{
30+
struct of_pmem_private *priv;
31+
struct device_node *np;
32+
struct nvdimm_bus *bus;
33+
bool is_volatile;
34+
int i;
35+
36+
np = dev_of_node(&pdev->dev);
37+
if (!np)
38+
return -ENXIO;
39+
40+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
41+
if (!priv)
42+
return -ENOMEM;
43+
44+
priv->bus_desc.attr_groups = bus_attr_groups;
45+
priv->bus_desc.provider_name = "of_pmem";
46+
priv->bus_desc.module = THIS_MODULE;
47+
priv->bus_desc.of_node = np;
48+
49+
priv->bus = bus = nvdimm_bus_register(&pdev->dev, &priv->bus_desc);
50+
if (!bus) {
51+
kfree(priv);
52+
return -ENODEV;
53+
}
54+
platform_set_drvdata(pdev, priv);
55+
56+
is_volatile = !!of_find_property(np, "volatile", NULL);
57+
dev_dbg(&pdev->dev, "Registering %s regions from %pOF\n",
58+
is_volatile ? "volatile" : "non-volatile", np);
59+
60+
for (i = 0; i < pdev->num_resources; i++) {
61+
struct nd_region_desc ndr_desc;
62+
struct nd_region *region;
63+
64+
/*
65+
* NB: libnvdimm copies the data from ndr_desc into it's own
66+
* structures so passing a stack pointer is fine.
67+
*/
68+
memset(&ndr_desc, 0, sizeof(ndr_desc));
69+
ndr_desc.attr_groups = region_attr_groups;
70+
ndr_desc.numa_node = of_node_to_nid(np);
71+
ndr_desc.res = &pdev->resource[i];
72+
ndr_desc.of_node = np;
73+
set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
74+
75+
if (is_volatile)
76+
region = nvdimm_volatile_region_create(bus, &ndr_desc);
77+
else
78+
region = nvdimm_pmem_region_create(bus, &ndr_desc);
79+
80+
if (!region)
81+
dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n",
82+
ndr_desc.res, np);
83+
else
84+
dev_dbg(&pdev->dev, "Registered region %pR from %pOF\n",
85+
ndr_desc.res, np);
86+
}
87+
88+
return 0;
89+
}
90+
91+
static int of_pmem_region_remove(struct platform_device *pdev)
92+
{
93+
struct of_pmem_private *priv = platform_get_drvdata(pdev);
94+
95+
nvdimm_bus_unregister(priv->bus);
96+
kfree(priv);
97+
98+
return 0;
99+
}
100+
101+
static const struct of_device_id of_pmem_region_match[] = {
102+
{ .compatible = "pmem-region" },
103+
{ },
104+
};
105+
106+
static struct platform_driver of_pmem_region_driver = {
107+
.probe = of_pmem_region_probe,
108+
.remove = of_pmem_region_remove,
109+
.driver = {
110+
.name = "of_pmem",
111+
.owner = THIS_MODULE,
112+
.of_match_table = of_pmem_region_match,
113+
},
114+
};
115+
116+
module_platform_driver(of_pmem_region_driver);
117+
MODULE_DEVICE_TABLE(of, of_pmem_region_match);
118+
MODULE_LICENSE("GPL");
119+
MODULE_AUTHOR("IBM Corporation");

0 commit comments

Comments
 (0)