1 // SPDX-License-Identifier: GPL-2.0+
3 #define pr_fmt(fmt) "of_pmem: " fmt
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>
12 static const struct attribute_group
*region_attr_groups
[] = {
13 &nd_region_attribute_group
,
14 &nd_device_attribute_group
,
18 static const struct attribute_group
*bus_attr_groups
[] = {
19 &nvdimm_bus_attribute_group
,
23 struct of_pmem_private
{
24 struct nvdimm_bus_descriptor bus_desc
;
25 struct nvdimm_bus
*bus
;
28 static int of_pmem_region_probe(struct platform_device
*pdev
)
30 struct of_pmem_private
*priv
;
31 struct device_node
*np
;
32 struct nvdimm_bus
*bus
;
36 np
= dev_of_node(&pdev
->dev
);
40 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
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
;
49 priv
->bus
= bus
= nvdimm_bus_register(&pdev
->dev
, &priv
->bus_desc
);
54 platform_set_drvdata(pdev
, priv
);
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
);
60 for (i
= 0; i
< pdev
->num_resources
; i
++) {
61 struct nd_region_desc ndr_desc
;
62 struct nd_region
*region
;
65 * NB: libnvdimm copies the data from ndr_desc into it's own
66 * structures so passing a stack pointer is fine.
68 memset(&ndr_desc
, 0, sizeof(ndr_desc
));
69 ndr_desc
.attr_groups
= region_attr_groups
;
70 ndr_desc
.numa_node
= dev_to_node(&pdev
->dev
);
71 ndr_desc
.res
= &pdev
->resource
[i
];
72 ndr_desc
.of_node
= np
;
73 set_bit(ND_REGION_PAGEMAP
, &ndr_desc
.flags
);
76 region
= nvdimm_volatile_region_create(bus
, &ndr_desc
);
78 region
= nvdimm_pmem_region_create(bus
, &ndr_desc
);
81 dev_warn(&pdev
->dev
, "Unable to register region %pR from %pOF\n",
84 dev_dbg(&pdev
->dev
, "Registered region %pR from %pOF\n",
91 static int of_pmem_region_remove(struct platform_device
*pdev
)
93 struct of_pmem_private
*priv
= platform_get_drvdata(pdev
);
95 nvdimm_bus_unregister(priv
->bus
);
101 static const struct of_device_id of_pmem_region_match
[] = {
102 { .compatible
= "pmem-region" },
106 static struct platform_driver of_pmem_region_driver
= {
107 .probe
= of_pmem_region_probe
,
108 .remove
= of_pmem_region_remove
,
111 .owner
= THIS_MODULE
,
112 .of_match_table
= of_pmem_region_match
,
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");