xref: /openbmc/linux/tools/testing/nvdimm/test/ndtest.c (revision 9399ab61ad82154911563dd8635c585e3f24b16a)
19a27e109SSantosh Sivaraj // SPDX-License-Identifier: GPL-2.0-only
29a27e109SSantosh Sivaraj #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
39a27e109SSantosh Sivaraj 
49a27e109SSantosh Sivaraj #include <linux/platform_device.h>
59a27e109SSantosh Sivaraj #include <linux/device.h>
69a27e109SSantosh Sivaraj #include <linux/module.h>
79a27e109SSantosh Sivaraj #include <linux/genalloc.h>
89a27e109SSantosh Sivaraj #include <linux/vmalloc.h>
99a27e109SSantosh Sivaraj #include <linux/dma-mapping.h>
109a27e109SSantosh Sivaraj #include <linux/list_sort.h>
119a27e109SSantosh Sivaraj #include <linux/libnvdimm.h>
129a27e109SSantosh Sivaraj #include <linux/ndctl.h>
139a27e109SSantosh Sivaraj #include <nd-core.h>
149a27e109SSantosh Sivaraj #include <linux/printk.h>
159a27e109SSantosh Sivaraj #include <linux/seq_buf.h>
169a27e109SSantosh Sivaraj 
179a27e109SSantosh Sivaraj #include "../watermark.h"
189a27e109SSantosh Sivaraj #include "nfit_test.h"
199a27e109SSantosh Sivaraj #include "ndtest.h"
209a27e109SSantosh Sivaraj 
219a27e109SSantosh Sivaraj enum {
229a27e109SSantosh Sivaraj 	DIMM_SIZE = SZ_32M,
239a27e109SSantosh Sivaraj 	LABEL_SIZE = SZ_128K,
249a27e109SSantosh Sivaraj 	NUM_INSTANCES = 2,
259a27e109SSantosh Sivaraj 	NUM_DCR = 4,
269a27e109SSantosh Sivaraj };
279a27e109SSantosh Sivaraj 
28*9399ab61SSantosh Sivaraj #define NDTEST_SCM_DIMM_CMD_MASK	   \
29*9399ab61SSantosh Sivaraj 	((1ul << ND_CMD_GET_CONFIG_SIZE) | \
30*9399ab61SSantosh Sivaraj 	 (1ul << ND_CMD_GET_CONFIG_DATA) | \
31*9399ab61SSantosh Sivaraj 	 (1ul << ND_CMD_SET_CONFIG_DATA) | \
32*9399ab61SSantosh Sivaraj 	 (1ul << ND_CMD_CALL))
33*9399ab61SSantosh Sivaraj 
34*9399ab61SSantosh Sivaraj #define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm)			\
35*9399ab61SSantosh Sivaraj 	(((node & 0xfff) << 16) | ((socket & 0xf) << 12)		\
36*9399ab61SSantosh Sivaraj 	 | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))
37*9399ab61SSantosh Sivaraj 
38*9399ab61SSantosh Sivaraj static DEFINE_SPINLOCK(ndtest_lock);
399a27e109SSantosh Sivaraj static struct ndtest_priv *instances[NUM_INSTANCES];
409a27e109SSantosh Sivaraj static struct class *ndtest_dimm_class;
41*9399ab61SSantosh Sivaraj static struct gen_pool *ndtest_pool;
42*9399ab61SSantosh Sivaraj 
43*9399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group1[] = {
44*9399ab61SSantosh Sivaraj 	{
45*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
46*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0),
47*9399ab61SSantosh Sivaraj 		.uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72",
48*9399ab61SSantosh Sivaraj 		.physical_id = 0,
49*9399ab61SSantosh Sivaraj 		.num_formats = 2,
50*9399ab61SSantosh Sivaraj 	},
51*9399ab61SSantosh Sivaraj 	{
52*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
53*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
54*9399ab61SSantosh Sivaraj 		.uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72",
55*9399ab61SSantosh Sivaraj 		.physical_id = 1,
56*9399ab61SSantosh Sivaraj 		.num_formats = 2,
57*9399ab61SSantosh Sivaraj 	},
58*9399ab61SSantosh Sivaraj 	{
59*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
60*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
61*9399ab61SSantosh Sivaraj 		.uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72",
62*9399ab61SSantosh Sivaraj 		.physical_id = 2,
63*9399ab61SSantosh Sivaraj 		.num_formats = 2,
64*9399ab61SSantosh Sivaraj 	},
65*9399ab61SSantosh Sivaraj 	{
66*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
67*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
68*9399ab61SSantosh Sivaraj 		.uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72",
69*9399ab61SSantosh Sivaraj 		.physical_id = 3,
70*9399ab61SSantosh Sivaraj 		.num_formats = 2,
71*9399ab61SSantosh Sivaraj 	},
72*9399ab61SSantosh Sivaraj 	{
73*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
74*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
75*9399ab61SSantosh Sivaraj 		.uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72",
76*9399ab61SSantosh Sivaraj 		.physical_id = 4,
77*9399ab61SSantosh Sivaraj 		.num_formats = 2,
78*9399ab61SSantosh Sivaraj 	},
79*9399ab61SSantosh Sivaraj };
80*9399ab61SSantosh Sivaraj 
81*9399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group2[] = {
82*9399ab61SSantosh Sivaraj 	{
83*9399ab61SSantosh Sivaraj 		.size = DIMM_SIZE,
84*9399ab61SSantosh Sivaraj 		.handle = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),
85*9399ab61SSantosh Sivaraj 		.uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72",
86*9399ab61SSantosh Sivaraj 		.physical_id = 0,
87*9399ab61SSantosh Sivaraj 		.num_formats = 1,
88*9399ab61SSantosh Sivaraj 	},
89*9399ab61SSantosh Sivaraj };
90*9399ab61SSantosh Sivaraj 
91*9399ab61SSantosh Sivaraj static struct ndtest_config bus_configs[NUM_INSTANCES] = {
92*9399ab61SSantosh Sivaraj 	/* bus 1 */
93*9399ab61SSantosh Sivaraj 	{
94*9399ab61SSantosh Sivaraj 		.dimm_start = 0,
95*9399ab61SSantosh Sivaraj 		.dimm_count = ARRAY_SIZE(dimm_group1),
96*9399ab61SSantosh Sivaraj 		.dimms = dimm_group1,
97*9399ab61SSantosh Sivaraj 	},
98*9399ab61SSantosh Sivaraj 	/* bus 2 */
99*9399ab61SSantosh Sivaraj 	{
100*9399ab61SSantosh Sivaraj 		.dimm_start = ARRAY_SIZE(dimm_group1),
101*9399ab61SSantosh Sivaraj 		.dimm_count = ARRAY_SIZE(dimm_group2),
102*9399ab61SSantosh Sivaraj 		.dimms = dimm_group2,
103*9399ab61SSantosh Sivaraj 	},
104*9399ab61SSantosh Sivaraj };
1059a27e109SSantosh Sivaraj 
1069a27e109SSantosh Sivaraj static inline struct ndtest_priv *to_ndtest_priv(struct device *dev)
1079a27e109SSantosh Sivaraj {
1089a27e109SSantosh Sivaraj 	struct platform_device *pdev = to_platform_device(dev);
1099a27e109SSantosh Sivaraj 
1109a27e109SSantosh Sivaraj 	return container_of(pdev, struct ndtest_priv, pdev);
1119a27e109SSantosh Sivaraj }
1129a27e109SSantosh Sivaraj 
1139a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc,
1149a27e109SSantosh Sivaraj 		      struct nvdimm *nvdimm, unsigned int cmd, void *buf,
1159a27e109SSantosh Sivaraj 		      unsigned int buf_len, int *cmd_rc)
1169a27e109SSantosh Sivaraj {
1179a27e109SSantosh Sivaraj 	struct ndtest_dimm *dimm;
1189a27e109SSantosh Sivaraj 	int _cmd_rc;
1199a27e109SSantosh Sivaraj 
1209a27e109SSantosh Sivaraj 	if (!cmd_rc)
1219a27e109SSantosh Sivaraj 		cmd_rc = &_cmd_rc;
1229a27e109SSantosh Sivaraj 
1239a27e109SSantosh Sivaraj 	*cmd_rc = 0;
1249a27e109SSantosh Sivaraj 
1259a27e109SSantosh Sivaraj 	if (!nvdimm)
1269a27e109SSantosh Sivaraj 		return -EINVAL;
1279a27e109SSantosh Sivaraj 
1289a27e109SSantosh Sivaraj 	dimm = nvdimm_provider_data(nvdimm);
1299a27e109SSantosh Sivaraj 	if (!dimm)
1309a27e109SSantosh Sivaraj 		return -EINVAL;
1319a27e109SSantosh Sivaraj 
1329a27e109SSantosh Sivaraj 	switch (cmd) {
1339a27e109SSantosh Sivaraj 	case ND_CMD_GET_CONFIG_SIZE:
1349a27e109SSantosh Sivaraj 	case ND_CMD_GET_CONFIG_DATA:
1359a27e109SSantosh Sivaraj 	case ND_CMD_SET_CONFIG_DATA:
1369a27e109SSantosh Sivaraj 	default:
1379a27e109SSantosh Sivaraj 		return -EINVAL;
1389a27e109SSantosh Sivaraj 	}
1399a27e109SSantosh Sivaraj 
1409a27e109SSantosh Sivaraj 	return 0;
1419a27e109SSantosh Sivaraj }
1429a27e109SSantosh Sivaraj 
143*9399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data)
144*9399ab61SSantosh Sivaraj {
145*9399ab61SSantosh Sivaraj 	struct nfit_test_resource *res  = data;
146*9399ab61SSantosh Sivaraj 
147*9399ab61SSantosh Sivaraj 	spin_lock(&ndtest_lock);
148*9399ab61SSantosh Sivaraj 	list_del(&res->list);
149*9399ab61SSantosh Sivaraj 	spin_unlock(&ndtest_lock);
150*9399ab61SSantosh Sivaraj 
151*9399ab61SSantosh Sivaraj 	if (resource_size(&res->res) >= DIMM_SIZE)
152*9399ab61SSantosh Sivaraj 		gen_pool_free(ndtest_pool, res->res.start,
153*9399ab61SSantosh Sivaraj 				resource_size(&res->res));
154*9399ab61SSantosh Sivaraj 	vfree(res->buf);
155*9399ab61SSantosh Sivaraj 	kfree(res);
156*9399ab61SSantosh Sivaraj }
157*9399ab61SSantosh Sivaraj 
158*9399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size,
159*9399ab61SSantosh Sivaraj 				   dma_addr_t *dma)
160*9399ab61SSantosh Sivaraj {
161*9399ab61SSantosh Sivaraj 	dma_addr_t __dma;
162*9399ab61SSantosh Sivaraj 	void *buf;
163*9399ab61SSantosh Sivaraj 	struct nfit_test_resource *res;
164*9399ab61SSantosh Sivaraj 	struct genpool_data_align data = {
165*9399ab61SSantosh Sivaraj 		.align = SZ_128M,
166*9399ab61SSantosh Sivaraj 	};
167*9399ab61SSantosh Sivaraj 
168*9399ab61SSantosh Sivaraj 	res = kzalloc(sizeof(*res), GFP_KERNEL);
169*9399ab61SSantosh Sivaraj 	if (!res)
170*9399ab61SSantosh Sivaraj 		return NULL;
171*9399ab61SSantosh Sivaraj 
172*9399ab61SSantosh Sivaraj 	buf = vmalloc(size);
173*9399ab61SSantosh Sivaraj 	if (size >= DIMM_SIZE)
174*9399ab61SSantosh Sivaraj 		__dma = gen_pool_alloc_algo(ndtest_pool, size,
175*9399ab61SSantosh Sivaraj 					    gen_pool_first_fit_align, &data);
176*9399ab61SSantosh Sivaraj 	else
177*9399ab61SSantosh Sivaraj 		__dma = (unsigned long) buf;
178*9399ab61SSantosh Sivaraj 
179*9399ab61SSantosh Sivaraj 	if (!__dma)
180*9399ab61SSantosh Sivaraj 		goto buf_err;
181*9399ab61SSantosh Sivaraj 
182*9399ab61SSantosh Sivaraj 	INIT_LIST_HEAD(&res->list);
183*9399ab61SSantosh Sivaraj 	res->dev = &p->pdev.dev;
184*9399ab61SSantosh Sivaraj 	res->buf = buf;
185*9399ab61SSantosh Sivaraj 	res->res.start = __dma;
186*9399ab61SSantosh Sivaraj 	res->res.end = __dma + size - 1;
187*9399ab61SSantosh Sivaraj 	res->res.name = "NFIT";
188*9399ab61SSantosh Sivaraj 	spin_lock_init(&res->lock);
189*9399ab61SSantosh Sivaraj 	INIT_LIST_HEAD(&res->requests);
190*9399ab61SSantosh Sivaraj 	spin_lock(&ndtest_lock);
191*9399ab61SSantosh Sivaraj 	list_add(&res->list, &p->resources);
192*9399ab61SSantosh Sivaraj 	spin_unlock(&ndtest_lock);
193*9399ab61SSantosh Sivaraj 
194*9399ab61SSantosh Sivaraj 	if (dma)
195*9399ab61SSantosh Sivaraj 		*dma = __dma;
196*9399ab61SSantosh Sivaraj 
197*9399ab61SSantosh Sivaraj 	if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res))
198*9399ab61SSantosh Sivaraj 		return res->buf;
199*9399ab61SSantosh Sivaraj 
200*9399ab61SSantosh Sivaraj buf_err:
201*9399ab61SSantosh Sivaraj 	if (__dma && size >= DIMM_SIZE)
202*9399ab61SSantosh Sivaraj 		gen_pool_free(ndtest_pool, __dma, size);
203*9399ab61SSantosh Sivaraj 	if (buf)
204*9399ab61SSantosh Sivaraj 		vfree(buf);
205*9399ab61SSantosh Sivaraj 	kfree(res);
206*9399ab61SSantosh Sivaraj 
207*9399ab61SSantosh Sivaraj 	return NULL;
208*9399ab61SSantosh Sivaraj }
209*9399ab61SSantosh Sivaraj 
210*9399ab61SSantosh Sivaraj static void put_dimms(void *data)
211*9399ab61SSantosh Sivaraj {
212*9399ab61SSantosh Sivaraj 	struct ndtest_priv *p = data;
213*9399ab61SSantosh Sivaraj 	int i;
214*9399ab61SSantosh Sivaraj 
215*9399ab61SSantosh Sivaraj 	for (i = 0; i < p->config->dimm_count; i++)
216*9399ab61SSantosh Sivaraj 		if (p->config->dimms[i].dev) {
217*9399ab61SSantosh Sivaraj 			device_unregister(p->config->dimms[i].dev);
218*9399ab61SSantosh Sivaraj 			p->config->dimms[i].dev = NULL;
219*9399ab61SSantosh Sivaraj 		}
220*9399ab61SSantosh Sivaraj }
221*9399ab61SSantosh Sivaraj 
222*9399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv,
223*9399ab61SSantosh Sivaraj 				struct ndtest_dimm *dimm, int id)
224*9399ab61SSantosh Sivaraj {
225*9399ab61SSantosh Sivaraj 	struct device *dev = &priv->pdev.dev;
226*9399ab61SSantosh Sivaraj 	unsigned long dimm_flags = dimm->flags;
227*9399ab61SSantosh Sivaraj 
228*9399ab61SSantosh Sivaraj 	if (dimm->num_formats > 1) {
229*9399ab61SSantosh Sivaraj 		set_bit(NDD_ALIASING, &dimm_flags);
230*9399ab61SSantosh Sivaraj 		set_bit(NDD_LABELING, &dimm_flags);
231*9399ab61SSantosh Sivaraj 	}
232*9399ab61SSantosh Sivaraj 
233*9399ab61SSantosh Sivaraj 	dimm->nvdimm = nvdimm_create(priv->bus, dimm, NULL, dimm_flags,
234*9399ab61SSantosh Sivaraj 				    NDTEST_SCM_DIMM_CMD_MASK, 0, NULL);
235*9399ab61SSantosh Sivaraj 	if (!dimm->nvdimm) {
236*9399ab61SSantosh Sivaraj 		dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn);
237*9399ab61SSantosh Sivaraj 		return -ENXIO;
238*9399ab61SSantosh Sivaraj 	}
239*9399ab61SSantosh Sivaraj 
240*9399ab61SSantosh Sivaraj 	dimm->dev = device_create_with_groups(ndtest_dimm_class,
241*9399ab61SSantosh Sivaraj 					     &priv->pdev.dev,
242*9399ab61SSantosh Sivaraj 					     0, dimm, NULL,
243*9399ab61SSantosh Sivaraj 					     "test_dimm%d", id);
244*9399ab61SSantosh Sivaraj 	if (!dimm->dev) {
245*9399ab61SSantosh Sivaraj 		pr_err("Could not create dimm device attributes\n");
246*9399ab61SSantosh Sivaraj 		return -ENOMEM;
247*9399ab61SSantosh Sivaraj 	}
248*9399ab61SSantosh Sivaraj 
249*9399ab61SSantosh Sivaraj 	return 0;
250*9399ab61SSantosh Sivaraj }
251*9399ab61SSantosh Sivaraj 
252*9399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p)
253*9399ab61SSantosh Sivaraj {
254*9399ab61SSantosh Sivaraj 	struct ndtest_dimm *d;
255*9399ab61SSantosh Sivaraj 	void *res;
256*9399ab61SSantosh Sivaraj 	int i, id;
257*9399ab61SSantosh Sivaraj 
258*9399ab61SSantosh Sivaraj 	for (i = 0; i < p->config->dimm_count; i++) {
259*9399ab61SSantosh Sivaraj 		d = &p->config->dimms[i];
260*9399ab61SSantosh Sivaraj 		d->id = id = p->config->dimm_start + i;
261*9399ab61SSantosh Sivaraj 		res = ndtest_alloc_resource(p, LABEL_SIZE, NULL);
262*9399ab61SSantosh Sivaraj 		if (!res)
263*9399ab61SSantosh Sivaraj 			return -ENOMEM;
264*9399ab61SSantosh Sivaraj 
265*9399ab61SSantosh Sivaraj 		d->label_area = res;
266*9399ab61SSantosh Sivaraj 		sprintf(d->label_area, "label%d", id);
267*9399ab61SSantosh Sivaraj 		d->config_size = LABEL_SIZE;
268*9399ab61SSantosh Sivaraj 
269*9399ab61SSantosh Sivaraj 		if (!ndtest_alloc_resource(p, d->size,
270*9399ab61SSantosh Sivaraj 					   &p->dimm_dma[id]))
271*9399ab61SSantosh Sivaraj 			return -ENOMEM;
272*9399ab61SSantosh Sivaraj 
273*9399ab61SSantosh Sivaraj 		if (!ndtest_alloc_resource(p, LABEL_SIZE,
274*9399ab61SSantosh Sivaraj 					   &p->label_dma[id]))
275*9399ab61SSantosh Sivaraj 			return -ENOMEM;
276*9399ab61SSantosh Sivaraj 
277*9399ab61SSantosh Sivaraj 		if (!ndtest_alloc_resource(p, LABEL_SIZE,
278*9399ab61SSantosh Sivaraj 					   &p->dcr_dma[id]))
279*9399ab61SSantosh Sivaraj 			return -ENOMEM;
280*9399ab61SSantosh Sivaraj 
281*9399ab61SSantosh Sivaraj 		d->address = p->dimm_dma[id];
282*9399ab61SSantosh Sivaraj 
283*9399ab61SSantosh Sivaraj 		ndtest_dimm_register(p, d, id);
284*9399ab61SSantosh Sivaraj 	}
285*9399ab61SSantosh Sivaraj 
286*9399ab61SSantosh Sivaraj 	return 0;
287*9399ab61SSantosh Sivaraj }
288*9399ab61SSantosh Sivaraj 
289107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev,
290107b04e9SSantosh Sivaraj 			       struct device_attribute *attr, char *buf)
291107b04e9SSantosh Sivaraj {
292107b04e9SSantosh Sivaraj 	return sprintf(buf, "nvdimm_test");
293107b04e9SSantosh Sivaraj }
294107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible);
295107b04e9SSantosh Sivaraj 
296107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = {
297107b04e9SSantosh Sivaraj 	&dev_attr_compatible.attr,
298107b04e9SSantosh Sivaraj 	NULL
299107b04e9SSantosh Sivaraj };
300107b04e9SSantosh Sivaraj 
301107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = {
302107b04e9SSantosh Sivaraj 	.name = "of_node",
303107b04e9SSantosh Sivaraj 	.attrs = of_node_attributes,
304107b04e9SSantosh Sivaraj };
305107b04e9SSantosh Sivaraj 
306107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = {
307107b04e9SSantosh Sivaraj 	&of_node_attribute_group,
308107b04e9SSantosh Sivaraj 	NULL,
309107b04e9SSantosh Sivaraj };
310107b04e9SSantosh Sivaraj 
3119a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p)
3129a27e109SSantosh Sivaraj {
313*9399ab61SSantosh Sivaraj 	p->config = &bus_configs[p->pdev.id];
314*9399ab61SSantosh Sivaraj 
3159a27e109SSantosh Sivaraj 	p->bus_desc.ndctl = ndtest_ctl;
3169a27e109SSantosh Sivaraj 	p->bus_desc.module = THIS_MODULE;
3179a27e109SSantosh Sivaraj 	p->bus_desc.provider_name = NULL;
318107b04e9SSantosh Sivaraj 	p->bus_desc.attr_groups = ndtest_attribute_groups;
3199a27e109SSantosh Sivaraj 
3209a27e109SSantosh Sivaraj 	p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc);
3219a27e109SSantosh Sivaraj 	if (!p->bus) {
3229a27e109SSantosh Sivaraj 		dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn);
3239a27e109SSantosh Sivaraj 		return -ENOMEM;
3249a27e109SSantosh Sivaraj 	}
3259a27e109SSantosh Sivaraj 
3269a27e109SSantosh Sivaraj 	return 0;
3279a27e109SSantosh Sivaraj }
3289a27e109SSantosh Sivaraj 
3299a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev)
3309a27e109SSantosh Sivaraj {
3319a27e109SSantosh Sivaraj 	struct ndtest_priv *p = to_ndtest_priv(&pdev->dev);
3329a27e109SSantosh Sivaraj 
3339a27e109SSantosh Sivaraj 	nvdimm_bus_unregister(p->bus);
3349a27e109SSantosh Sivaraj 	return 0;
3359a27e109SSantosh Sivaraj }
3369a27e109SSantosh Sivaraj 
3379a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev)
3389a27e109SSantosh Sivaraj {
3399a27e109SSantosh Sivaraj 	struct ndtest_priv *p;
340*9399ab61SSantosh Sivaraj 	int rc;
3419a27e109SSantosh Sivaraj 
3429a27e109SSantosh Sivaraj 	p = to_ndtest_priv(&pdev->dev);
3439a27e109SSantosh Sivaraj 	if (ndtest_bus_register(p))
3449a27e109SSantosh Sivaraj 		return -ENOMEM;
3459a27e109SSantosh Sivaraj 
346*9399ab61SSantosh Sivaraj 	p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
347*9399ab61SSantosh Sivaraj 				 sizeof(dma_addr_t), GFP_KERNEL);
348*9399ab61SSantosh Sivaraj 	p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
349*9399ab61SSantosh Sivaraj 				   sizeof(dma_addr_t), GFP_KERNEL);
350*9399ab61SSantosh Sivaraj 	p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,
351*9399ab61SSantosh Sivaraj 				  sizeof(dma_addr_t), GFP_KERNEL);
352*9399ab61SSantosh Sivaraj 
353*9399ab61SSantosh Sivaraj 	rc = ndtest_nvdimm_init(p);
354*9399ab61SSantosh Sivaraj 	if (rc)
355*9399ab61SSantosh Sivaraj 		goto err;
356*9399ab61SSantosh Sivaraj 
357*9399ab61SSantosh Sivaraj 	rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p);
358*9399ab61SSantosh Sivaraj 	if (rc)
359*9399ab61SSantosh Sivaraj 		goto err;
360*9399ab61SSantosh Sivaraj 
3619a27e109SSantosh Sivaraj 	platform_set_drvdata(pdev, p);
3629a27e109SSantosh Sivaraj 
3639a27e109SSantosh Sivaraj 	return 0;
364*9399ab61SSantosh Sivaraj 
365*9399ab61SSantosh Sivaraj err:
366*9399ab61SSantosh Sivaraj 	pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__);
367*9399ab61SSantosh Sivaraj 	return rc;
3689a27e109SSantosh Sivaraj }
3699a27e109SSantosh Sivaraj 
3709a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = {
3719a27e109SSantosh Sivaraj 	{ KBUILD_MODNAME },
3729a27e109SSantosh Sivaraj 	{ },
3739a27e109SSantosh Sivaraj };
3749a27e109SSantosh Sivaraj 
3759a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = {
3769a27e109SSantosh Sivaraj 	.probe = ndtest_probe,
3779a27e109SSantosh Sivaraj 	.remove = ndtest_remove,
3789a27e109SSantosh Sivaraj 	.driver = {
3799a27e109SSantosh Sivaraj 		.name = KBUILD_MODNAME,
3809a27e109SSantosh Sivaraj 	},
3819a27e109SSantosh Sivaraj 	.id_table = ndtest_id,
3829a27e109SSantosh Sivaraj };
3839a27e109SSantosh Sivaraj 
3849a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev)
3859a27e109SSantosh Sivaraj {
3869a27e109SSantosh Sivaraj 	struct ndtest_priv *p = to_ndtest_priv(dev);
3879a27e109SSantosh Sivaraj 
3889a27e109SSantosh Sivaraj 	kfree(p);
3899a27e109SSantosh Sivaraj }
3909a27e109SSantosh Sivaraj 
3919a27e109SSantosh Sivaraj static void cleanup_devices(void)
3929a27e109SSantosh Sivaraj {
3939a27e109SSantosh Sivaraj 	int i;
3949a27e109SSantosh Sivaraj 
3959a27e109SSantosh Sivaraj 	for (i = 0; i < NUM_INSTANCES; i++)
3969a27e109SSantosh Sivaraj 		if (instances[i])
3979a27e109SSantosh Sivaraj 			platform_device_unregister(&instances[i]->pdev);
3989a27e109SSantosh Sivaraj 
3999a27e109SSantosh Sivaraj 	nfit_test_teardown();
4009a27e109SSantosh Sivaraj 
401*9399ab61SSantosh Sivaraj 	if (ndtest_pool)
402*9399ab61SSantosh Sivaraj 		gen_pool_destroy(ndtest_pool);
403*9399ab61SSantosh Sivaraj 
404*9399ab61SSantosh Sivaraj 
4059a27e109SSantosh Sivaraj 	if (ndtest_dimm_class)
4069a27e109SSantosh Sivaraj 		class_destroy(ndtest_dimm_class);
4079a27e109SSantosh Sivaraj }
4089a27e109SSantosh Sivaraj 
4099a27e109SSantosh Sivaraj static __init int ndtest_init(void)
4109a27e109SSantosh Sivaraj {
4119a27e109SSantosh Sivaraj 	int rc, i;
4129a27e109SSantosh Sivaraj 
4139a27e109SSantosh Sivaraj 	pmem_test();
4149a27e109SSantosh Sivaraj 	libnvdimm_test();
4159a27e109SSantosh Sivaraj 	device_dax_test();
4169a27e109SSantosh Sivaraj 	dax_pmem_test();
4179a27e109SSantosh Sivaraj 	dax_pmem_core_test();
4189a27e109SSantosh Sivaraj #ifdef CONFIG_DEV_DAX_PMEM_COMPAT
4199a27e109SSantosh Sivaraj 	dax_pmem_compat_test();
4209a27e109SSantosh Sivaraj #endif
4219a27e109SSantosh Sivaraj 
4229a27e109SSantosh Sivaraj 	ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm");
4239a27e109SSantosh Sivaraj 	if (IS_ERR(ndtest_dimm_class)) {
4249a27e109SSantosh Sivaraj 		rc = PTR_ERR(ndtest_dimm_class);
4259a27e109SSantosh Sivaraj 		goto err_register;
4269a27e109SSantosh Sivaraj 	}
4279a27e109SSantosh Sivaraj 
428*9399ab61SSantosh Sivaraj 	ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE);
429*9399ab61SSantosh Sivaraj 	if (!ndtest_pool) {
430*9399ab61SSantosh Sivaraj 		rc = -ENOMEM;
431*9399ab61SSantosh Sivaraj 		goto err_register;
432*9399ab61SSantosh Sivaraj 	}
433*9399ab61SSantosh Sivaraj 
434*9399ab61SSantosh Sivaraj 	if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) {
435*9399ab61SSantosh Sivaraj 		rc = -ENOMEM;
436*9399ab61SSantosh Sivaraj 		goto err_register;
437*9399ab61SSantosh Sivaraj 	}
438*9399ab61SSantosh Sivaraj 
4399a27e109SSantosh Sivaraj 	/* Each instance can be taken as a bus, which can have multiple dimms */
4409a27e109SSantosh Sivaraj 	for (i = 0; i < NUM_INSTANCES; i++) {
4419a27e109SSantosh Sivaraj 		struct ndtest_priv *priv;
4429a27e109SSantosh Sivaraj 		struct platform_device *pdev;
4439a27e109SSantosh Sivaraj 
4449a27e109SSantosh Sivaraj 		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
4459a27e109SSantosh Sivaraj 		if (!priv) {
4469a27e109SSantosh Sivaraj 			rc = -ENOMEM;
4479a27e109SSantosh Sivaraj 			goto err_register;
4489a27e109SSantosh Sivaraj 		}
4499a27e109SSantosh Sivaraj 
4509a27e109SSantosh Sivaraj 		INIT_LIST_HEAD(&priv->resources);
4519a27e109SSantosh Sivaraj 		pdev = &priv->pdev;
4529a27e109SSantosh Sivaraj 		pdev->name = KBUILD_MODNAME;
4539a27e109SSantosh Sivaraj 		pdev->id = i;
4549a27e109SSantosh Sivaraj 		pdev->dev.release = ndtest_release;
4559a27e109SSantosh Sivaraj 		rc = platform_device_register(pdev);
4569a27e109SSantosh Sivaraj 		if (rc) {
4579a27e109SSantosh Sivaraj 			put_device(&pdev->dev);
4589a27e109SSantosh Sivaraj 			goto err_register;
4599a27e109SSantosh Sivaraj 		}
4609a27e109SSantosh Sivaraj 		get_device(&pdev->dev);
4619a27e109SSantosh Sivaraj 
4629a27e109SSantosh Sivaraj 		instances[i] = priv;
4639a27e109SSantosh Sivaraj 	}
4649a27e109SSantosh Sivaraj 
4659a27e109SSantosh Sivaraj 	rc = platform_driver_register(&ndtest_driver);
4669a27e109SSantosh Sivaraj 	if (rc)
4679a27e109SSantosh Sivaraj 		goto err_register;
4689a27e109SSantosh Sivaraj 
4699a27e109SSantosh Sivaraj 	return 0;
4709a27e109SSantosh Sivaraj 
4719a27e109SSantosh Sivaraj err_register:
4729a27e109SSantosh Sivaraj 	pr_err("Error registering platform device\n");
4739a27e109SSantosh Sivaraj 	cleanup_devices();
4749a27e109SSantosh Sivaraj 
4759a27e109SSantosh Sivaraj 	return rc;
4769a27e109SSantosh Sivaraj }
4779a27e109SSantosh Sivaraj 
4789a27e109SSantosh Sivaraj static __exit void ndtest_exit(void)
4799a27e109SSantosh Sivaraj {
4809a27e109SSantosh Sivaraj 	cleanup_devices();
4819a27e109SSantosh Sivaraj 	platform_driver_unregister(&ndtest_driver);
4829a27e109SSantosh Sivaraj }
4839a27e109SSantosh Sivaraj 
4849a27e109SSantosh Sivaraj module_init(ndtest_init);
4859a27e109SSantosh Sivaraj module_exit(ndtest_exit);
4869a27e109SSantosh Sivaraj MODULE_LICENSE("GPL");
4879a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation");
488