xref: /openbmc/linux/tools/testing/nvdimm/test/ndtest.c (revision 107b04e9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 
4 #include <linux/platform_device.h>
5 #include <linux/device.h>
6 #include <linux/module.h>
7 #include <linux/genalloc.h>
8 #include <linux/vmalloc.h>
9 #include <linux/dma-mapping.h>
10 #include <linux/list_sort.h>
11 #include <linux/libnvdimm.h>
12 #include <linux/ndctl.h>
13 #include <nd-core.h>
14 #include <linux/printk.h>
15 #include <linux/seq_buf.h>
16 
17 #include "../watermark.h"
18 #include "nfit_test.h"
19 #include "ndtest.h"
20 
21 enum {
22 	DIMM_SIZE = SZ_32M,
23 	LABEL_SIZE = SZ_128K,
24 	NUM_INSTANCES = 2,
25 	NUM_DCR = 4,
26 };
27 
28 static struct ndtest_priv *instances[NUM_INSTANCES];
29 static struct class *ndtest_dimm_class;
30 
31 static inline struct ndtest_priv *to_ndtest_priv(struct device *dev)
32 {
33 	struct platform_device *pdev = to_platform_device(dev);
34 
35 	return container_of(pdev, struct ndtest_priv, pdev);
36 }
37 
38 static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc,
39 		      struct nvdimm *nvdimm, unsigned int cmd, void *buf,
40 		      unsigned int buf_len, int *cmd_rc)
41 {
42 	struct ndtest_dimm *dimm;
43 	int _cmd_rc;
44 
45 	if (!cmd_rc)
46 		cmd_rc = &_cmd_rc;
47 
48 	*cmd_rc = 0;
49 
50 	if (!nvdimm)
51 		return -EINVAL;
52 
53 	dimm = nvdimm_provider_data(nvdimm);
54 	if (!dimm)
55 		return -EINVAL;
56 
57 	switch (cmd) {
58 	case ND_CMD_GET_CONFIG_SIZE:
59 	case ND_CMD_GET_CONFIG_DATA:
60 	case ND_CMD_SET_CONFIG_DATA:
61 	default:
62 		return -EINVAL;
63 	}
64 
65 	return 0;
66 }
67 
68 static ssize_t compatible_show(struct device *dev,
69 			       struct device_attribute *attr, char *buf)
70 {
71 	return sprintf(buf, "nvdimm_test");
72 }
73 static DEVICE_ATTR_RO(compatible);
74 
75 static struct attribute *of_node_attributes[] = {
76 	&dev_attr_compatible.attr,
77 	NULL
78 };
79 
80 static const struct attribute_group of_node_attribute_group = {
81 	.name = "of_node",
82 	.attrs = of_node_attributes,
83 };
84 
85 static const struct attribute_group *ndtest_attribute_groups[] = {
86 	&of_node_attribute_group,
87 	NULL,
88 };
89 
90 static int ndtest_bus_register(struct ndtest_priv *p)
91 {
92 	p->bus_desc.ndctl = ndtest_ctl;
93 	p->bus_desc.module = THIS_MODULE;
94 	p->bus_desc.provider_name = NULL;
95 	p->bus_desc.attr_groups = ndtest_attribute_groups;
96 
97 	p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc);
98 	if (!p->bus) {
99 		dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn);
100 		return -ENOMEM;
101 	}
102 
103 	return 0;
104 }
105 
106 static int ndtest_remove(struct platform_device *pdev)
107 {
108 	struct ndtest_priv *p = to_ndtest_priv(&pdev->dev);
109 
110 	nvdimm_bus_unregister(p->bus);
111 	return 0;
112 }
113 
114 static int ndtest_probe(struct platform_device *pdev)
115 {
116 	struct ndtest_priv *p;
117 
118 	p = to_ndtest_priv(&pdev->dev);
119 	if (ndtest_bus_register(p))
120 		return -ENOMEM;
121 
122 	platform_set_drvdata(pdev, p);
123 
124 	return 0;
125 }
126 
127 static const struct platform_device_id ndtest_id[] = {
128 	{ KBUILD_MODNAME },
129 	{ },
130 };
131 
132 static struct platform_driver ndtest_driver = {
133 	.probe = ndtest_probe,
134 	.remove = ndtest_remove,
135 	.driver = {
136 		.name = KBUILD_MODNAME,
137 	},
138 	.id_table = ndtest_id,
139 };
140 
141 static void ndtest_release(struct device *dev)
142 {
143 	struct ndtest_priv *p = to_ndtest_priv(dev);
144 
145 	kfree(p);
146 }
147 
148 static void cleanup_devices(void)
149 {
150 	int i;
151 
152 	for (i = 0; i < NUM_INSTANCES; i++)
153 		if (instances[i])
154 			platform_device_unregister(&instances[i]->pdev);
155 
156 	nfit_test_teardown();
157 
158 	if (ndtest_dimm_class)
159 		class_destroy(ndtest_dimm_class);
160 }
161 
162 static __init int ndtest_init(void)
163 {
164 	int rc, i;
165 
166 	pmem_test();
167 	libnvdimm_test();
168 	device_dax_test();
169 	dax_pmem_test();
170 	dax_pmem_core_test();
171 #ifdef CONFIG_DEV_DAX_PMEM_COMPAT
172 	dax_pmem_compat_test();
173 #endif
174 
175 	ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm");
176 	if (IS_ERR(ndtest_dimm_class)) {
177 		rc = PTR_ERR(ndtest_dimm_class);
178 		goto err_register;
179 	}
180 
181 	/* Each instance can be taken as a bus, which can have multiple dimms */
182 	for (i = 0; i < NUM_INSTANCES; i++) {
183 		struct ndtest_priv *priv;
184 		struct platform_device *pdev;
185 
186 		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
187 		if (!priv) {
188 			rc = -ENOMEM;
189 			goto err_register;
190 		}
191 
192 		INIT_LIST_HEAD(&priv->resources);
193 		pdev = &priv->pdev;
194 		pdev->name = KBUILD_MODNAME;
195 		pdev->id = i;
196 		pdev->dev.release = ndtest_release;
197 		rc = platform_device_register(pdev);
198 		if (rc) {
199 			put_device(&pdev->dev);
200 			goto err_register;
201 		}
202 		get_device(&pdev->dev);
203 
204 		instances[i] = priv;
205 	}
206 
207 	rc = platform_driver_register(&ndtest_driver);
208 	if (rc)
209 		goto err_register;
210 
211 	return 0;
212 
213 err_register:
214 	pr_err("Error registering platform device\n");
215 	cleanup_devices();
216 
217 	return rc;
218 }
219 
220 static __exit void ndtest_exit(void)
221 {
222 	cleanup_devices();
223 	platform_driver_unregister(&ndtest_driver);
224 }
225 
226 module_init(ndtest_init);
227 module_exit(ndtest_exit);
228 MODULE_LICENSE("GPL");
229 MODULE_AUTHOR("IBM Corporation");
230