brintos

brintos / linux-shallow public Read only

0
0
Text · 21.7 KiB · 892e990 Raw
993 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt3 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#include <linux/papr_scm.h>17#include <uapi/linux/papr_pdsm.h>18 19#include "../watermark.h"20#include "nfit_test.h"21#include "ndtest.h"22 23enum {24	DIMM_SIZE = SZ_32M,25	LABEL_SIZE = SZ_128K,26	NUM_INSTANCES = 2,27	NUM_DCR = 4,28	NDTEST_MAX_MAPPING = 6,29};30 31#define NDTEST_SCM_DIMM_CMD_MASK	   \32	((1ul << ND_CMD_GET_CONFIG_SIZE) | \33	 (1ul << ND_CMD_GET_CONFIG_DATA) | \34	 (1ul << ND_CMD_SET_CONFIG_DATA) | \35	 (1ul << ND_CMD_CALL))36 37#define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm)			\38	(((node & 0xfff) << 16) | ((socket & 0xf) << 12)		\39	 | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))40 41static DEFINE_SPINLOCK(ndtest_lock);42static struct ndtest_priv *instances[NUM_INSTANCES];43 44static const struct class ndtest_dimm_class = {45	.name = "nfit_test_dimm",46};47 48static struct gen_pool *ndtest_pool;49 50static struct ndtest_dimm dimm_group1[] = {51	{52		.size = DIMM_SIZE,53		.handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0),54		.uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72",55		.physical_id = 0,56		.num_formats = 2,57	},58	{59		.size = DIMM_SIZE,60		.handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),61		.uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72",62		.physical_id = 1,63		.num_formats = 2,64	},65	{66		.size = DIMM_SIZE,67		.handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),68		.uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72",69		.physical_id = 2,70		.num_formats = 2,71	},72	{73		.size = DIMM_SIZE,74		.handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),75		.uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72",76		.physical_id = 3,77		.num_formats = 2,78	},79	{80		.size = DIMM_SIZE,81		.handle = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),82		.uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72",83		.physical_id = 4,84		.num_formats = 2,85	},86};87 88static struct ndtest_dimm dimm_group2[] = {89	{90		.size = DIMM_SIZE,91		.handle = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),92		.uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72",93		.physical_id = 0,94		.num_formats = 1,95		.flags = PAPR_PMEM_UNARMED | PAPR_PMEM_EMPTY |96			 PAPR_PMEM_SAVE_FAILED | PAPR_PMEM_SHUTDOWN_DIRTY |97			 PAPR_PMEM_HEALTH_FATAL,98	},99};100 101static struct ndtest_mapping region0_mapping[] = {102	{103		.dimm = 0,104		.position = 0,105		.start = 0,106		.size = SZ_16M,107	},108	{109		.dimm = 1,110		.position = 1,111		.start = 0,112		.size = SZ_16M,113	}114};115 116static struct ndtest_mapping region1_mapping[] = {117	{118		.dimm = 0,119		.position = 0,120		.start = SZ_16M,121		.size = SZ_16M,122	},123	{124		.dimm = 1,125		.position = 1,126		.start = SZ_16M,127		.size = SZ_16M,128	},129	{130		.dimm = 2,131		.position = 2,132		.start = SZ_16M,133		.size = SZ_16M,134	},135	{136		.dimm = 3,137		.position = 3,138		.start = SZ_16M,139		.size = SZ_16M,140	},141};142 143static struct ndtest_region bus0_regions[] = {144	{145		.type = ND_DEVICE_NAMESPACE_PMEM,146		.num_mappings = ARRAY_SIZE(region0_mapping),147		.mapping = region0_mapping,148		.size = DIMM_SIZE,149		.range_index = 1,150	},151	{152		.type = ND_DEVICE_NAMESPACE_PMEM,153		.num_mappings = ARRAY_SIZE(region1_mapping),154		.mapping = region1_mapping,155		.size = DIMM_SIZE * 2,156		.range_index = 2,157	},158};159 160static struct ndtest_mapping region6_mapping[] = {161	{162		.dimm = 0,163		.position = 0,164		.start = 0,165		.size = DIMM_SIZE,166	},167};168 169static struct ndtest_region bus1_regions[] = {170	{171		.type = ND_DEVICE_NAMESPACE_IO,172		.num_mappings = ARRAY_SIZE(region6_mapping),173		.mapping = region6_mapping,174		.size = DIMM_SIZE,175		.range_index = 1,176	},177};178 179static struct ndtest_config bus_configs[NUM_INSTANCES] = {180	/* bus 1 */181	{182		.dimm_start = 0,183		.dimm_count = ARRAY_SIZE(dimm_group1),184		.dimms = dimm_group1,185		.regions = bus0_regions,186		.num_regions = ARRAY_SIZE(bus0_regions),187	},188	/* bus 2 */189	{190		.dimm_start = ARRAY_SIZE(dimm_group1),191		.dimm_count = ARRAY_SIZE(dimm_group2),192		.dimms = dimm_group2,193		.regions = bus1_regions,194		.num_regions = ARRAY_SIZE(bus1_regions),195	},196};197 198static inline struct ndtest_priv *to_ndtest_priv(struct device *dev)199{200	struct platform_device *pdev = to_platform_device(dev);201 202	return container_of(pdev, struct ndtest_priv, pdev);203}204 205static int ndtest_config_get(struct ndtest_dimm *p, unsigned int buf_len,206			     struct nd_cmd_get_config_data_hdr *hdr)207{208	unsigned int len;209 210	if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE)211		return -EINVAL;212 213	hdr->status = 0;214	len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset);215	memcpy(hdr->out_buf, p->label_area + hdr->in_offset, len);216 217	return buf_len - len;218}219 220static int ndtest_config_set(struct ndtest_dimm *p, unsigned int buf_len,221			     struct nd_cmd_set_config_hdr *hdr)222{223	unsigned int len;224 225	if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE)226		return -EINVAL;227 228	len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset);229	memcpy(p->label_area + hdr->in_offset, hdr->in_buf, len);230 231	return buf_len - len;232}233 234static int ndtest_get_config_size(struct ndtest_dimm *dimm, unsigned int buf_len,235				  struct nd_cmd_get_config_size *size)236{237	size->status = 0;238	size->max_xfer = 8;239	size->config_size = dimm->config_size;240 241	return 0;242}243 244static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc,245		      struct nvdimm *nvdimm, unsigned int cmd, void *buf,246		      unsigned int buf_len, int *cmd_rc)247{248	struct ndtest_dimm *dimm;249	int _cmd_rc;250 251	if (!cmd_rc)252		cmd_rc = &_cmd_rc;253 254	*cmd_rc = 0;255 256	if (!nvdimm)257		return -EINVAL;258 259	dimm = nvdimm_provider_data(nvdimm);260	if (!dimm)261		return -EINVAL;262 263	switch (cmd) {264	case ND_CMD_GET_CONFIG_SIZE:265		*cmd_rc = ndtest_get_config_size(dimm, buf_len, buf);266		break;267	case ND_CMD_GET_CONFIG_DATA:268		*cmd_rc = ndtest_config_get(dimm, buf_len, buf);269		break;270	case ND_CMD_SET_CONFIG_DATA:271		*cmd_rc = ndtest_config_set(dimm, buf_len, buf);272		break;273	default:274		return -EINVAL;275	}276 277	/* Failures for a DIMM can be injected using fail_cmd and278	 * fail_cmd_code, see the device attributes below279	 */280	if ((1 << cmd) & dimm->fail_cmd)281		return dimm->fail_cmd_code ? dimm->fail_cmd_code : -EIO;282 283	return 0;284}285 286static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr)287{288	int i;289 290	for (i = 0; i < NUM_INSTANCES; i++) {291		struct nfit_test_resource *n, *nfit_res = NULL;292		struct ndtest_priv *t = instances[i];293 294		if (!t)295			continue;296		spin_lock(&ndtest_lock);297		list_for_each_entry(n, &t->resources, list) {298			if (addr >= n->res.start && (addr < n->res.start299						+ resource_size(&n->res))) {300				nfit_res = n;301				break;302			} else if (addr >= (unsigned long) n->buf303					&& (addr < (unsigned long) n->buf304						+ resource_size(&n->res))) {305				nfit_res = n;306				break;307			}308		}309		spin_unlock(&ndtest_lock);310		if (nfit_res)311			return nfit_res;312	}313 314	pr_warn("Failed to get resource\n");315 316	return NULL;317}318 319static void ndtest_release_resource(void *data)320{321	struct nfit_test_resource *res  = data;322 323	spin_lock(&ndtest_lock);324	list_del(&res->list);325	spin_unlock(&ndtest_lock);326 327	if (resource_size(&res->res) >= DIMM_SIZE)328		gen_pool_free(ndtest_pool, res->res.start,329				resource_size(&res->res));330	vfree(res->buf);331	kfree(res);332}333 334static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size,335				   dma_addr_t *dma)336{337	dma_addr_t __dma;338	void *buf;339	struct nfit_test_resource *res;340	struct genpool_data_align data = {341		.align = SZ_128M,342	};343 344	res = kzalloc(sizeof(*res), GFP_KERNEL);345	if (!res)346		return NULL;347 348	buf = vmalloc(size);349	if (size >= DIMM_SIZE)350		__dma = gen_pool_alloc_algo(ndtest_pool, size,351					    gen_pool_first_fit_align, &data);352	else353		__dma = (unsigned long) buf;354 355	if (!__dma)356		goto buf_err;357 358	INIT_LIST_HEAD(&res->list);359	res->dev = &p->pdev.dev;360	res->buf = buf;361	res->res.start = __dma;362	res->res.end = __dma + size - 1;363	res->res.name = "NFIT";364	spin_lock_init(&res->lock);365	INIT_LIST_HEAD(&res->requests);366	spin_lock(&ndtest_lock);367	list_add(&res->list, &p->resources);368	spin_unlock(&ndtest_lock);369 370	if (dma)371		*dma = __dma;372 373	if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res))374		return res->buf;375 376buf_err:377	if (__dma && size >= DIMM_SIZE)378		gen_pool_free(ndtest_pool, __dma, size);379	if (buf)380		vfree(buf);381	kfree(res);382 383	return NULL;384}385 386static ssize_t range_index_show(struct device *dev,387		struct device_attribute *attr, char *buf)388{389	struct nd_region *nd_region = to_nd_region(dev);390	struct ndtest_region *region = nd_region_provider_data(nd_region);391 392	return sprintf(buf, "%d\n", region->range_index);393}394static DEVICE_ATTR_RO(range_index);395 396static struct attribute *ndtest_region_attributes[] = {397	&dev_attr_range_index.attr,398	NULL,399};400 401static const struct attribute_group ndtest_region_attribute_group = {402	.name = "papr",403	.attrs = ndtest_region_attributes,404};405 406static const struct attribute_group *ndtest_region_attribute_groups[] = {407	&ndtest_region_attribute_group,408	NULL,409};410 411static int ndtest_create_region(struct ndtest_priv *p,412				struct ndtest_region *region)413{414	struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING];415	struct nd_region_desc *ndr_desc, _ndr_desc;416	struct nd_interleave_set *nd_set;417	struct resource res;418	int i, ndimm = region->mapping[0].dimm;419	u64 uuid[2];420 421	memset(&res, 0, sizeof(res));422	memset(&mappings, 0, sizeof(mappings));423	memset(&_ndr_desc, 0, sizeof(_ndr_desc));424	ndr_desc = &_ndr_desc;425 426	if (!ndtest_alloc_resource(p, region->size, &res.start))427		return -ENOMEM;428 429	res.end = res.start + region->size - 1;430	ndr_desc->mapping = mappings;431	ndr_desc->res = &res;432	ndr_desc->provider_data = region;433	ndr_desc->attr_groups = ndtest_region_attribute_groups;434 435	if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) {436		pr_err("failed to parse UUID\n");437		return -ENXIO;438	}439 440	nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL);441	if (!nd_set)442		return -ENOMEM;443 444	nd_set->cookie1 = cpu_to_le64(uuid[0]);445	nd_set->cookie2 = cpu_to_le64(uuid[1]);446	nd_set->altcookie = nd_set->cookie1;447	ndr_desc->nd_set = nd_set;448 449	for (i = 0; i < region->num_mappings; i++) {450		ndimm = region->mapping[i].dimm;451		mappings[i].start = region->mapping[i].start;452		mappings[i].size = region->mapping[i].size;453		mappings[i].position = region->mapping[i].position;454		mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm;455	}456 457	ndr_desc->num_mappings = region->num_mappings;458	region->region = nvdimm_pmem_region_create(p->bus, ndr_desc);459 460	if (!region->region) {461		dev_err(&p->pdev.dev, "Error registering region %pR\n",462			ndr_desc->res);463		return -ENXIO;464	}465 466	return 0;467}468 469static int ndtest_init_regions(struct ndtest_priv *p)470{471	int i, ret = 0;472 473	for (i = 0; i < p->config->num_regions; i++) {474		ret = ndtest_create_region(p, &p->config->regions[i]);475		if (ret)476			return ret;477	}478 479	return 0;480}481 482static void put_dimms(void *data)483{484	struct ndtest_priv *p = data;485	int i;486 487	for (i = 0; i < p->config->dimm_count; i++)488		if (p->config->dimms[i].dev) {489			device_unregister(p->config->dimms[i].dev);490			p->config->dimms[i].dev = NULL;491		}492}493 494static ssize_t handle_show(struct device *dev, struct device_attribute *attr,495		char *buf)496{497	struct ndtest_dimm *dimm = dev_get_drvdata(dev);498 499	return sprintf(buf, "%#x\n", dimm->handle);500}501static DEVICE_ATTR_RO(handle);502 503static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr,504		char *buf)505{506	struct ndtest_dimm *dimm = dev_get_drvdata(dev);507 508	return sprintf(buf, "%#x\n", dimm->fail_cmd);509}510 511static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr,512		const char *buf, size_t size)513{514	struct ndtest_dimm *dimm = dev_get_drvdata(dev);515	unsigned long val;516	ssize_t rc;517 518	rc = kstrtol(buf, 0, &val);519	if (rc)520		return rc;521 522	dimm->fail_cmd = val;523 524	return size;525}526static DEVICE_ATTR_RW(fail_cmd);527 528static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr,529		char *buf)530{531	struct ndtest_dimm *dimm = dev_get_drvdata(dev);532 533	return sprintf(buf, "%d\n", dimm->fail_cmd_code);534}535 536static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr,537		const char *buf, size_t size)538{539	struct ndtest_dimm *dimm = dev_get_drvdata(dev);540	unsigned long val;541	ssize_t rc;542 543	rc = kstrtol(buf, 0, &val);544	if (rc)545		return rc;546 547	dimm->fail_cmd_code = val;548	return size;549}550static DEVICE_ATTR_RW(fail_cmd_code);551 552static struct attribute *dimm_attributes[] = {553	&dev_attr_handle.attr,554	&dev_attr_fail_cmd.attr,555	&dev_attr_fail_cmd_code.attr,556	NULL,557};558 559static struct attribute_group dimm_attribute_group = {560	.attrs = dimm_attributes,561};562 563static const struct attribute_group *dimm_attribute_groups[] = {564	&dimm_attribute_group,565	NULL,566};567 568static ssize_t phys_id_show(struct device *dev,569		struct device_attribute *attr, char *buf)570{571	struct nvdimm *nvdimm = to_nvdimm(dev);572	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);573 574	return sprintf(buf, "%#x\n", dimm->physical_id);575}576static DEVICE_ATTR_RO(phys_id);577 578static ssize_t vendor_show(struct device *dev,579			   struct device_attribute *attr, char *buf)580{581	return sprintf(buf, "0x1234567\n");582}583static DEVICE_ATTR_RO(vendor);584 585static ssize_t id_show(struct device *dev,586		       struct device_attribute *attr, char *buf)587{588	struct nvdimm *nvdimm = to_nvdimm(dev);589	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);590 591	return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd,592		       0xa, 2016, ~(dimm->handle));593}594static DEVICE_ATTR_RO(id);595 596static ssize_t nvdimm_handle_show(struct device *dev,597				  struct device_attribute *attr, char *buf)598{599	struct nvdimm *nvdimm = to_nvdimm(dev);600	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);601 602	return sprintf(buf, "%#x\n", dimm->handle);603}604 605static struct device_attribute dev_attr_nvdimm_show_handle =  {606	.attr	= { .name = "handle", .mode = 0444 },607	.show	= nvdimm_handle_show,608};609 610static ssize_t subsystem_vendor_show(struct device *dev,611		struct device_attribute *attr, char *buf)612{613	return sprintf(buf, "0x%04x\n", 0);614}615static DEVICE_ATTR_RO(subsystem_vendor);616 617static ssize_t dirty_shutdown_show(struct device *dev,618		struct device_attribute *attr, char *buf)619{620	return sprintf(buf, "%d\n", 42);621}622static DEVICE_ATTR_RO(dirty_shutdown);623 624static ssize_t formats_show(struct device *dev,625		struct device_attribute *attr, char *buf)626{627	struct nvdimm *nvdimm = to_nvdimm(dev);628	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);629 630	return sprintf(buf, "%d\n", dimm->num_formats);631}632static DEVICE_ATTR_RO(formats);633 634static ssize_t format_show(struct device *dev,635		struct device_attribute *attr, char *buf)636{637	struct nvdimm *nvdimm = to_nvdimm(dev);638	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);639 640	if (dimm->num_formats > 1)641		return sprintf(buf, "0x201\n");642 643	return sprintf(buf, "0x101\n");644}645static DEVICE_ATTR_RO(format);646 647static ssize_t format1_show(struct device *dev, struct device_attribute *attr,648			    char *buf)649{650	return sprintf(buf, "0x301\n");651}652static DEVICE_ATTR_RO(format1);653 654static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj,655					struct attribute *a, int n)656{657	struct device *dev = container_of(kobj, struct device, kobj);658	struct nvdimm *nvdimm = to_nvdimm(dev);659	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);660 661	if (a == &dev_attr_format1.attr && dimm->num_formats <= 1)662		return 0;663 664	return a->mode;665}666 667static ssize_t flags_show(struct device *dev,668			  struct device_attribute *attr, char *buf)669{670	struct nvdimm *nvdimm = to_nvdimm(dev);671	struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm);672	struct seq_buf s;673	u64 flags;674 675	flags = dimm->flags;676 677	seq_buf_init(&s, buf, PAGE_SIZE);678	if (flags & PAPR_PMEM_UNARMED_MASK)679		seq_buf_printf(&s, "not_armed ");680 681	if (flags & PAPR_PMEM_BAD_SHUTDOWN_MASK)682		seq_buf_printf(&s, "flush_fail ");683 684	if (flags & PAPR_PMEM_BAD_RESTORE_MASK)685		seq_buf_printf(&s, "restore_fail ");686 687	if (flags & PAPR_PMEM_SAVE_MASK)688		seq_buf_printf(&s, "save_fail ");689 690	if (flags & PAPR_PMEM_SMART_EVENT_MASK)691		seq_buf_printf(&s, "smart_notify ");692 693 694	if (seq_buf_used(&s))695		seq_buf_printf(&s, "\n");696 697	return seq_buf_used(&s);698}699static DEVICE_ATTR_RO(flags);700 701static struct attribute *ndtest_nvdimm_attributes[] = {702	&dev_attr_nvdimm_show_handle.attr,703	&dev_attr_vendor.attr,704	&dev_attr_id.attr,705	&dev_attr_phys_id.attr,706	&dev_attr_subsystem_vendor.attr,707	&dev_attr_dirty_shutdown.attr,708	&dev_attr_formats.attr,709	&dev_attr_format.attr,710	&dev_attr_format1.attr,711	&dev_attr_flags.attr,712	NULL,713};714 715static const struct attribute_group ndtest_nvdimm_attribute_group = {716	.name = "papr",717	.attrs = ndtest_nvdimm_attributes,718	.is_visible = ndtest_nvdimm_attr_visible,719};720 721static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = {722	&ndtest_nvdimm_attribute_group,723	NULL,724};725 726static int ndtest_dimm_register(struct ndtest_priv *priv,727				struct ndtest_dimm *dimm, int id)728{729	struct device *dev = &priv->pdev.dev;730	unsigned long dimm_flags = dimm->flags;731 732	if (dimm->num_formats > 1)733		set_bit(NDD_LABELING, &dimm_flags);734 735	if (dimm->flags & PAPR_PMEM_UNARMED_MASK)736		set_bit(NDD_UNARMED, &dimm_flags);737 738	dimm->nvdimm = nvdimm_create(priv->bus, dimm,739				    ndtest_nvdimm_attribute_groups, dimm_flags,740				    NDTEST_SCM_DIMM_CMD_MASK, 0, NULL);741	if (!dimm->nvdimm) {742		dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn);743		return -ENXIO;744	}745 746	dimm->dev = device_create_with_groups(&ndtest_dimm_class,747					     &priv->pdev.dev,748					     0, dimm, dimm_attribute_groups,749					     "test_dimm%d", id);750	if (!dimm->dev) {751		pr_err("Could not create dimm device attributes\n");752		return -ENOMEM;753	}754 755	return 0;756}757 758static int ndtest_nvdimm_init(struct ndtest_priv *p)759{760	struct ndtest_dimm *d;761	void *res;762	int i, id;763 764	for (i = 0; i < p->config->dimm_count; i++) {765		d = &p->config->dimms[i];766		d->id = id = p->config->dimm_start + i;767		res = ndtest_alloc_resource(p, LABEL_SIZE, NULL);768		if (!res)769			return -ENOMEM;770 771		d->label_area = res;772		sprintf(d->label_area, "label%d", id);773		d->config_size = LABEL_SIZE;774 775		if (!ndtest_alloc_resource(p, d->size,776					   &p->dimm_dma[id]))777			return -ENOMEM;778 779		if (!ndtest_alloc_resource(p, LABEL_SIZE,780					   &p->label_dma[id]))781			return -ENOMEM;782 783		if (!ndtest_alloc_resource(p, LABEL_SIZE,784					   &p->dcr_dma[id]))785			return -ENOMEM;786 787		d->address = p->dimm_dma[id];788 789		ndtest_dimm_register(p, d, id);790	}791 792	return 0;793}794 795static ssize_t compatible_show(struct device *dev,796			       struct device_attribute *attr, char *buf)797{798	return sprintf(buf, "nvdimm_test");799}800static DEVICE_ATTR_RO(compatible);801 802static struct attribute *of_node_attributes[] = {803	&dev_attr_compatible.attr,804	NULL805};806 807static const struct attribute_group of_node_attribute_group = {808	.name = "of_node",809	.attrs = of_node_attributes,810};811 812static const struct attribute_group *ndtest_attribute_groups[] = {813	&of_node_attribute_group,814	NULL,815};816 817static int ndtest_bus_register(struct ndtest_priv *p)818{819	p->config = &bus_configs[p->pdev.id];820 821	p->bus_desc.ndctl = ndtest_ctl;822	p->bus_desc.module = THIS_MODULE;823	p->bus_desc.provider_name = NULL;824	p->bus_desc.attr_groups = ndtest_attribute_groups;825 826	p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc);827	if (!p->bus) {828		dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn);829		return -ENOMEM;830	}831 832	return 0;833}834 835static void ndtest_remove(struct platform_device *pdev)836{837	struct ndtest_priv *p = to_ndtest_priv(&pdev->dev);838 839	nvdimm_bus_unregister(p->bus);840}841 842static int ndtest_probe(struct platform_device *pdev)843{844	struct ndtest_priv *p;845	int rc;846 847	p = to_ndtest_priv(&pdev->dev);848	if (ndtest_bus_register(p))849		return -ENOMEM;850 851	p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,852				 sizeof(dma_addr_t), GFP_KERNEL);853	p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,854				   sizeof(dma_addr_t), GFP_KERNEL);855	p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR,856				  sizeof(dma_addr_t), GFP_KERNEL);857 858	rc = ndtest_nvdimm_init(p);859	if (rc)860		goto err;861 862	rc = ndtest_init_regions(p);863	if (rc)864		goto err;865 866	rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p);867	if (rc)868		goto err;869 870	platform_set_drvdata(pdev, p);871 872	return 0;873 874err:875	pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__);876	return rc;877}878 879static const struct platform_device_id ndtest_id[] = {880	{ KBUILD_MODNAME },881	{ },882};883 884static struct platform_driver ndtest_driver = {885	.probe = ndtest_probe,886	.remove_new = ndtest_remove,887	.driver = {888		.name = KBUILD_MODNAME,889	},890	.id_table = ndtest_id,891};892 893static void ndtest_release(struct device *dev)894{895	struct ndtest_priv *p = to_ndtest_priv(dev);896 897	kfree(p);898}899 900static void cleanup_devices(void)901{902	int i;903 904	for (i = 0; i < NUM_INSTANCES; i++)905		if (instances[i])906			platform_device_unregister(&instances[i]->pdev);907 908	nfit_test_teardown();909 910	if (ndtest_pool)911		gen_pool_destroy(ndtest_pool);912 913 914	class_unregister(&ndtest_dimm_class);915}916 917static __init int ndtest_init(void)918{919	int rc, i;920 921	pmem_test();922	libnvdimm_test();923	device_dax_test();924	dax_pmem_test();925 926	nfit_test_setup(ndtest_resource_lookup, NULL);927 928	rc = class_register(&ndtest_dimm_class);929	if (rc)930		goto err_register;931 932	ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE);933	if (!ndtest_pool) {934		rc = -ENOMEM;935		goto err_register;936	}937 938	if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) {939		rc = -ENOMEM;940		goto err_register;941	}942 943	/* Each instance can be taken as a bus, which can have multiple dimms */944	for (i = 0; i < NUM_INSTANCES; i++) {945		struct ndtest_priv *priv;946		struct platform_device *pdev;947 948		priv = kzalloc(sizeof(*priv), GFP_KERNEL);949		if (!priv) {950			rc = -ENOMEM;951			goto err_register;952		}953 954		INIT_LIST_HEAD(&priv->resources);955		pdev = &priv->pdev;956		pdev->name = KBUILD_MODNAME;957		pdev->id = i;958		pdev->dev.release = ndtest_release;959		rc = platform_device_register(pdev);960		if (rc) {961			put_device(&pdev->dev);962			goto err_register;963		}964		get_device(&pdev->dev);965 966		instances[i] = priv;967	}968 969	rc = platform_driver_register(&ndtest_driver);970	if (rc)971		goto err_register;972 973	return 0;974 975err_register:976	pr_err("Error registering platform device\n");977	cleanup_devices();978 979	return rc;980}981 982static __exit void ndtest_exit(void)983{984	cleanup_devices();985	platform_driver_unregister(&ndtest_driver);986}987 988module_init(ndtest_init);989module_exit(ndtest_exit);990MODULE_DESCRIPTION("Test non-NFIT devices");991MODULE_LICENSE("GPL");992MODULE_AUTHOR("IBM Corporation");993