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, 266fde2d4cSSantosh Sivaraj NDTEST_MAX_MAPPING = 6, 279a27e109SSantosh Sivaraj }; 289a27e109SSantosh Sivaraj 299399ab61SSantosh Sivaraj #define NDTEST_SCM_DIMM_CMD_MASK \ 309399ab61SSantosh Sivaraj ((1ul << ND_CMD_GET_CONFIG_SIZE) | \ 319399ab61SSantosh Sivaraj (1ul << ND_CMD_GET_CONFIG_DATA) | \ 329399ab61SSantosh Sivaraj (1ul << ND_CMD_SET_CONFIG_DATA) | \ 339399ab61SSantosh Sivaraj (1ul << ND_CMD_CALL)) 349399ab61SSantosh Sivaraj 359399ab61SSantosh Sivaraj #define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm) \ 369399ab61SSantosh Sivaraj (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \ 379399ab61SSantosh Sivaraj | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf)) 389399ab61SSantosh Sivaraj 399399ab61SSantosh Sivaraj static DEFINE_SPINLOCK(ndtest_lock); 409a27e109SSantosh Sivaraj static struct ndtest_priv *instances[NUM_INSTANCES]; 419a27e109SSantosh Sivaraj static struct class *ndtest_dimm_class; 429399ab61SSantosh Sivaraj static struct gen_pool *ndtest_pool; 439399ab61SSantosh Sivaraj 449399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group1[] = { 459399ab61SSantosh Sivaraj { 469399ab61SSantosh Sivaraj .size = DIMM_SIZE, 479399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0), 489399ab61SSantosh Sivaraj .uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72", 499399ab61SSantosh Sivaraj .physical_id = 0, 509399ab61SSantosh Sivaraj .num_formats = 2, 519399ab61SSantosh Sivaraj }, 529399ab61SSantosh Sivaraj { 539399ab61SSantosh Sivaraj .size = DIMM_SIZE, 549399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), 559399ab61SSantosh Sivaraj .uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72", 569399ab61SSantosh Sivaraj .physical_id = 1, 579399ab61SSantosh Sivaraj .num_formats = 2, 589399ab61SSantosh Sivaraj }, 599399ab61SSantosh Sivaraj { 609399ab61SSantosh Sivaraj .size = DIMM_SIZE, 619399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), 629399ab61SSantosh Sivaraj .uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72", 639399ab61SSantosh Sivaraj .physical_id = 2, 649399ab61SSantosh Sivaraj .num_formats = 2, 659399ab61SSantosh Sivaraj }, 669399ab61SSantosh Sivaraj { 679399ab61SSantosh Sivaraj .size = DIMM_SIZE, 689399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), 699399ab61SSantosh Sivaraj .uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72", 709399ab61SSantosh Sivaraj .physical_id = 3, 719399ab61SSantosh Sivaraj .num_formats = 2, 729399ab61SSantosh Sivaraj }, 739399ab61SSantosh Sivaraj { 749399ab61SSantosh Sivaraj .size = DIMM_SIZE, 759399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), 769399ab61SSantosh Sivaraj .uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72", 779399ab61SSantosh Sivaraj .physical_id = 4, 789399ab61SSantosh Sivaraj .num_formats = 2, 799399ab61SSantosh Sivaraj }, 809399ab61SSantosh Sivaraj }; 819399ab61SSantosh Sivaraj 829399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group2[] = { 839399ab61SSantosh Sivaraj { 849399ab61SSantosh Sivaraj .size = DIMM_SIZE, 859399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0), 869399ab61SSantosh Sivaraj .uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72", 879399ab61SSantosh Sivaraj .physical_id = 0, 889399ab61SSantosh Sivaraj .num_formats = 1, 8950f558a5SSantosh Sivaraj .flags = PAPR_PMEM_UNARMED | PAPR_PMEM_EMPTY | 9050f558a5SSantosh Sivaraj PAPR_PMEM_SAVE_FAILED | PAPR_PMEM_SHUTDOWN_DIRTY | 9150f558a5SSantosh Sivaraj PAPR_PMEM_HEALTH_FATAL, 929399ab61SSantosh Sivaraj }, 939399ab61SSantosh Sivaraj }; 949399ab61SSantosh Sivaraj 956fde2d4cSSantosh Sivaraj static struct ndtest_mapping region0_mapping[] = { 966fde2d4cSSantosh Sivaraj { 976fde2d4cSSantosh Sivaraj .dimm = 0, 986fde2d4cSSantosh Sivaraj .position = 0, 996fde2d4cSSantosh Sivaraj .start = 0, 1006fde2d4cSSantosh Sivaraj .size = SZ_16M, 1016fde2d4cSSantosh Sivaraj }, 1026fde2d4cSSantosh Sivaraj { 1036fde2d4cSSantosh Sivaraj .dimm = 1, 1046fde2d4cSSantosh Sivaraj .position = 1, 1056fde2d4cSSantosh Sivaraj .start = 0, 1066fde2d4cSSantosh Sivaraj .size = SZ_16M, 1076fde2d4cSSantosh Sivaraj } 1086fde2d4cSSantosh Sivaraj }; 1096fde2d4cSSantosh Sivaraj 1106fde2d4cSSantosh Sivaraj static struct ndtest_mapping region1_mapping[] = { 1116fde2d4cSSantosh Sivaraj { 1126fde2d4cSSantosh Sivaraj .dimm = 0, 1136fde2d4cSSantosh Sivaraj .position = 0, 1146fde2d4cSSantosh Sivaraj .start = SZ_16M, 1156fde2d4cSSantosh Sivaraj .size = SZ_16M, 1166fde2d4cSSantosh Sivaraj }, 1176fde2d4cSSantosh Sivaraj { 1186fde2d4cSSantosh Sivaraj .dimm = 1, 1196fde2d4cSSantosh Sivaraj .position = 1, 1206fde2d4cSSantosh Sivaraj .start = SZ_16M, 1216fde2d4cSSantosh Sivaraj .size = SZ_16M, 1226fde2d4cSSantosh Sivaraj }, 1236fde2d4cSSantosh Sivaraj { 1246fde2d4cSSantosh Sivaraj .dimm = 2, 1256fde2d4cSSantosh Sivaraj .position = 2, 1266fde2d4cSSantosh Sivaraj .start = SZ_16M, 1276fde2d4cSSantosh Sivaraj .size = SZ_16M, 1286fde2d4cSSantosh Sivaraj }, 1296fde2d4cSSantosh Sivaraj { 1306fde2d4cSSantosh Sivaraj .dimm = 3, 1316fde2d4cSSantosh Sivaraj .position = 3, 1326fde2d4cSSantosh Sivaraj .start = SZ_16M, 1336fde2d4cSSantosh Sivaraj .size = SZ_16M, 1346fde2d4cSSantosh Sivaraj }, 1356fde2d4cSSantosh Sivaraj }; 1366fde2d4cSSantosh Sivaraj 1376fde2d4cSSantosh Sivaraj static struct ndtest_mapping region2_mapping[] = { 1386fde2d4cSSantosh Sivaraj { 1396fde2d4cSSantosh Sivaraj .dimm = 0, 1406fde2d4cSSantosh Sivaraj .position = 0, 1416fde2d4cSSantosh Sivaraj .start = 0, 1426fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1436fde2d4cSSantosh Sivaraj }, 1446fde2d4cSSantosh Sivaraj }; 1456fde2d4cSSantosh Sivaraj 1466fde2d4cSSantosh Sivaraj static struct ndtest_mapping region3_mapping[] = { 1476fde2d4cSSantosh Sivaraj { 1486fde2d4cSSantosh Sivaraj .dimm = 1, 1496fde2d4cSSantosh Sivaraj .start = 0, 1506fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1516fde2d4cSSantosh Sivaraj } 1526fde2d4cSSantosh Sivaraj }; 1536fde2d4cSSantosh Sivaraj 1546fde2d4cSSantosh Sivaraj static struct ndtest_mapping region4_mapping[] = { 1556fde2d4cSSantosh Sivaraj { 1566fde2d4cSSantosh Sivaraj .dimm = 2, 1576fde2d4cSSantosh Sivaraj .start = 0, 1586fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1596fde2d4cSSantosh Sivaraj } 1606fde2d4cSSantosh Sivaraj }; 1616fde2d4cSSantosh Sivaraj 1626fde2d4cSSantosh Sivaraj static struct ndtest_mapping region5_mapping[] = { 1636fde2d4cSSantosh Sivaraj { 1646fde2d4cSSantosh Sivaraj .dimm = 3, 1656fde2d4cSSantosh Sivaraj .start = 0, 1666fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1676fde2d4cSSantosh Sivaraj } 1686fde2d4cSSantosh Sivaraj }; 1696fde2d4cSSantosh Sivaraj 1706fde2d4cSSantosh Sivaraj static struct ndtest_region bus0_regions[] = { 1716fde2d4cSSantosh Sivaraj { 1726fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1736fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region0_mapping), 1746fde2d4cSSantosh Sivaraj .mapping = region0_mapping, 1756fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1766fde2d4cSSantosh Sivaraj .range_index = 1, 1776fde2d4cSSantosh Sivaraj }, 1786fde2d4cSSantosh Sivaraj { 1796fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1806fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region1_mapping), 1816fde2d4cSSantosh Sivaraj .mapping = region1_mapping, 1826fde2d4cSSantosh Sivaraj .size = DIMM_SIZE * 2, 1836fde2d4cSSantosh Sivaraj .range_index = 2, 1846fde2d4cSSantosh Sivaraj }, 1856fde2d4cSSantosh Sivaraj { 1866fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 1876fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region2_mapping), 1886fde2d4cSSantosh Sivaraj .mapping = region2_mapping, 1896fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1906fde2d4cSSantosh Sivaraj .range_index = 3, 1916fde2d4cSSantosh Sivaraj }, 1926fde2d4cSSantosh Sivaraj { 1936fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 1946fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region3_mapping), 1956fde2d4cSSantosh Sivaraj .mapping = region3_mapping, 1966fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1976fde2d4cSSantosh Sivaraj .range_index = 4, 1986fde2d4cSSantosh Sivaraj }, 1996fde2d4cSSantosh Sivaraj { 2006fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 2016fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region4_mapping), 2026fde2d4cSSantosh Sivaraj .mapping = region4_mapping, 2036fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2046fde2d4cSSantosh Sivaraj .range_index = 5, 2056fde2d4cSSantosh Sivaraj }, 2066fde2d4cSSantosh Sivaraj { 2076fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 2086fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region5_mapping), 2096fde2d4cSSantosh Sivaraj .mapping = region5_mapping, 2106fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2116fde2d4cSSantosh Sivaraj .range_index = 6, 2126fde2d4cSSantosh Sivaraj }, 2136fde2d4cSSantosh Sivaraj }; 2146fde2d4cSSantosh Sivaraj 2156fde2d4cSSantosh Sivaraj static struct ndtest_mapping region6_mapping[] = { 2166fde2d4cSSantosh Sivaraj { 2176fde2d4cSSantosh Sivaraj .dimm = 0, 2186fde2d4cSSantosh Sivaraj .position = 0, 2196fde2d4cSSantosh Sivaraj .start = 0, 2206fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2216fde2d4cSSantosh Sivaraj }, 2226fde2d4cSSantosh Sivaraj }; 2236fde2d4cSSantosh Sivaraj 2246fde2d4cSSantosh Sivaraj static struct ndtest_region bus1_regions[] = { 2256fde2d4cSSantosh Sivaraj { 2266fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_IO, 2276fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region6_mapping), 2286fde2d4cSSantosh Sivaraj .mapping = region6_mapping, 2296fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2306fde2d4cSSantosh Sivaraj .range_index = 1, 2316fde2d4cSSantosh Sivaraj }, 2326fde2d4cSSantosh Sivaraj }; 2336fde2d4cSSantosh Sivaraj 2349399ab61SSantosh Sivaraj static struct ndtest_config bus_configs[NUM_INSTANCES] = { 2359399ab61SSantosh Sivaraj /* bus 1 */ 2369399ab61SSantosh Sivaraj { 2379399ab61SSantosh Sivaraj .dimm_start = 0, 2389399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group1), 2399399ab61SSantosh Sivaraj .dimms = dimm_group1, 2406fde2d4cSSantosh Sivaraj .regions = bus0_regions, 2416fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus0_regions), 2429399ab61SSantosh Sivaraj }, 2439399ab61SSantosh Sivaraj /* bus 2 */ 2449399ab61SSantosh Sivaraj { 2459399ab61SSantosh Sivaraj .dimm_start = ARRAY_SIZE(dimm_group1), 2469399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group2), 2479399ab61SSantosh Sivaraj .dimms = dimm_group2, 2486fde2d4cSSantosh Sivaraj .regions = bus1_regions, 2496fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus1_regions), 2509399ab61SSantosh Sivaraj }, 2519399ab61SSantosh Sivaraj }; 2529a27e109SSantosh Sivaraj 2539a27e109SSantosh Sivaraj static inline struct ndtest_priv *to_ndtest_priv(struct device *dev) 2549a27e109SSantosh Sivaraj { 2559a27e109SSantosh Sivaraj struct platform_device *pdev = to_platform_device(dev); 2569a27e109SSantosh Sivaraj 2579a27e109SSantosh Sivaraj return container_of(pdev, struct ndtest_priv, pdev); 2589a27e109SSantosh Sivaraj } 2599a27e109SSantosh Sivaraj 26014ccef10SSantosh Sivaraj static int ndtest_config_get(struct ndtest_dimm *p, unsigned int buf_len, 26114ccef10SSantosh Sivaraj struct nd_cmd_get_config_data_hdr *hdr) 26214ccef10SSantosh Sivaraj { 26314ccef10SSantosh Sivaraj unsigned int len; 26414ccef10SSantosh Sivaraj 26514ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 26614ccef10SSantosh Sivaraj return -EINVAL; 26714ccef10SSantosh Sivaraj 26814ccef10SSantosh Sivaraj hdr->status = 0; 26914ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 27014ccef10SSantosh Sivaraj memcpy(hdr->out_buf, p->label_area + hdr->in_offset, len); 27114ccef10SSantosh Sivaraj 27214ccef10SSantosh Sivaraj return buf_len - len; 27314ccef10SSantosh Sivaraj } 27414ccef10SSantosh Sivaraj 27514ccef10SSantosh Sivaraj static int ndtest_config_set(struct ndtest_dimm *p, unsigned int buf_len, 27614ccef10SSantosh Sivaraj struct nd_cmd_set_config_hdr *hdr) 27714ccef10SSantosh Sivaraj { 27814ccef10SSantosh Sivaraj unsigned int len; 27914ccef10SSantosh Sivaraj 28014ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 28114ccef10SSantosh Sivaraj return -EINVAL; 28214ccef10SSantosh Sivaraj 28314ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 28414ccef10SSantosh Sivaraj memcpy(p->label_area + hdr->in_offset, hdr->in_buf, len); 28514ccef10SSantosh Sivaraj 28614ccef10SSantosh Sivaraj return buf_len - len; 28714ccef10SSantosh Sivaraj } 28814ccef10SSantosh Sivaraj 28914ccef10SSantosh Sivaraj static int ndtest_get_config_size(struct ndtest_dimm *dimm, unsigned int buf_len, 29014ccef10SSantosh Sivaraj struct nd_cmd_get_config_size *size) 29114ccef10SSantosh Sivaraj { 29214ccef10SSantosh Sivaraj size->status = 0; 29314ccef10SSantosh Sivaraj size->max_xfer = 8; 29414ccef10SSantosh Sivaraj size->config_size = dimm->config_size; 29514ccef10SSantosh Sivaraj 29614ccef10SSantosh Sivaraj return 0; 29714ccef10SSantosh Sivaraj } 29814ccef10SSantosh Sivaraj 2999a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 3009a27e109SSantosh Sivaraj struct nvdimm *nvdimm, unsigned int cmd, void *buf, 3019a27e109SSantosh Sivaraj unsigned int buf_len, int *cmd_rc) 3029a27e109SSantosh Sivaraj { 3039a27e109SSantosh Sivaraj struct ndtest_dimm *dimm; 3049a27e109SSantosh Sivaraj int _cmd_rc; 3059a27e109SSantosh Sivaraj 3069a27e109SSantosh Sivaraj if (!cmd_rc) 3079a27e109SSantosh Sivaraj cmd_rc = &_cmd_rc; 3089a27e109SSantosh Sivaraj 3099a27e109SSantosh Sivaraj *cmd_rc = 0; 3109a27e109SSantosh Sivaraj 3119a27e109SSantosh Sivaraj if (!nvdimm) 3129a27e109SSantosh Sivaraj return -EINVAL; 3139a27e109SSantosh Sivaraj 3149a27e109SSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 3159a27e109SSantosh Sivaraj if (!dimm) 3169a27e109SSantosh Sivaraj return -EINVAL; 3179a27e109SSantosh Sivaraj 3189a27e109SSantosh Sivaraj switch (cmd) { 3199a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_SIZE: 32014ccef10SSantosh Sivaraj *cmd_rc = ndtest_get_config_size(dimm, buf_len, buf); 32114ccef10SSantosh Sivaraj break; 3229a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_DATA: 32314ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_get(dimm, buf_len, buf); 32414ccef10SSantosh Sivaraj break; 3259a27e109SSantosh Sivaraj case ND_CMD_SET_CONFIG_DATA: 32614ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_set(dimm, buf_len, buf); 32714ccef10SSantosh Sivaraj break; 3289a27e109SSantosh Sivaraj default: 3299a27e109SSantosh Sivaraj return -EINVAL; 3309a27e109SSantosh Sivaraj } 3319a27e109SSantosh Sivaraj 33214ccef10SSantosh Sivaraj /* Failures for a DIMM can be injected using fail_cmd and 33314ccef10SSantosh Sivaraj * fail_cmd_code, see the device attributes below 33414ccef10SSantosh Sivaraj */ 33514ccef10SSantosh Sivaraj if ((1 << cmd) & dimm->fail_cmd) 33614ccef10SSantosh Sivaraj return dimm->fail_cmd_code ? dimm->fail_cmd_code : -EIO; 33714ccef10SSantosh Sivaraj 3389a27e109SSantosh Sivaraj return 0; 3399a27e109SSantosh Sivaraj } 3409a27e109SSantosh Sivaraj 3416fde2d4cSSantosh Sivaraj static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr) 3426fde2d4cSSantosh Sivaraj { 3436fde2d4cSSantosh Sivaraj int i; 3446fde2d4cSSantosh Sivaraj 3456fde2d4cSSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 3466fde2d4cSSantosh Sivaraj struct nfit_test_resource *n, *nfit_res = NULL; 3476fde2d4cSSantosh Sivaraj struct ndtest_priv *t = instances[i]; 3486fde2d4cSSantosh Sivaraj 3496fde2d4cSSantosh Sivaraj if (!t) 3506fde2d4cSSantosh Sivaraj continue; 3516fde2d4cSSantosh Sivaraj spin_lock(&ndtest_lock); 3526fde2d4cSSantosh Sivaraj list_for_each_entry(n, &t->resources, list) { 3536fde2d4cSSantosh Sivaraj if (addr >= n->res.start && (addr < n->res.start 3546fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 3556fde2d4cSSantosh Sivaraj nfit_res = n; 3566fde2d4cSSantosh Sivaraj break; 3576fde2d4cSSantosh Sivaraj } else if (addr >= (unsigned long) n->buf 3586fde2d4cSSantosh Sivaraj && (addr < (unsigned long) n->buf 3596fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 3606fde2d4cSSantosh Sivaraj nfit_res = n; 3616fde2d4cSSantosh Sivaraj break; 3626fde2d4cSSantosh Sivaraj } 3636fde2d4cSSantosh Sivaraj } 3646fde2d4cSSantosh Sivaraj spin_unlock(&ndtest_lock); 3656fde2d4cSSantosh Sivaraj if (nfit_res) 3666fde2d4cSSantosh Sivaraj return nfit_res; 3676fde2d4cSSantosh Sivaraj } 3686fde2d4cSSantosh Sivaraj 3696fde2d4cSSantosh Sivaraj pr_warn("Failed to get resource\n"); 3706fde2d4cSSantosh Sivaraj 3716fde2d4cSSantosh Sivaraj return NULL; 3726fde2d4cSSantosh Sivaraj } 3736fde2d4cSSantosh Sivaraj 3749399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data) 3759399ab61SSantosh Sivaraj { 3769399ab61SSantosh Sivaraj struct nfit_test_resource *res = data; 3779399ab61SSantosh Sivaraj 3789399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 3799399ab61SSantosh Sivaraj list_del(&res->list); 3809399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 3819399ab61SSantosh Sivaraj 3829399ab61SSantosh Sivaraj if (resource_size(&res->res) >= DIMM_SIZE) 3839399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, res->res.start, 3849399ab61SSantosh Sivaraj resource_size(&res->res)); 3859399ab61SSantosh Sivaraj vfree(res->buf); 3869399ab61SSantosh Sivaraj kfree(res); 3879399ab61SSantosh Sivaraj } 3889399ab61SSantosh Sivaraj 3899399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size, 3909399ab61SSantosh Sivaraj dma_addr_t *dma) 3919399ab61SSantosh Sivaraj { 3929399ab61SSantosh Sivaraj dma_addr_t __dma; 3939399ab61SSantosh Sivaraj void *buf; 3949399ab61SSantosh Sivaraj struct nfit_test_resource *res; 3959399ab61SSantosh Sivaraj struct genpool_data_align data = { 3969399ab61SSantosh Sivaraj .align = SZ_128M, 3979399ab61SSantosh Sivaraj }; 3989399ab61SSantosh Sivaraj 3999399ab61SSantosh Sivaraj res = kzalloc(sizeof(*res), GFP_KERNEL); 4009399ab61SSantosh Sivaraj if (!res) 4019399ab61SSantosh Sivaraj return NULL; 4029399ab61SSantosh Sivaraj 4039399ab61SSantosh Sivaraj buf = vmalloc(size); 4049399ab61SSantosh Sivaraj if (size >= DIMM_SIZE) 4059399ab61SSantosh Sivaraj __dma = gen_pool_alloc_algo(ndtest_pool, size, 4069399ab61SSantosh Sivaraj gen_pool_first_fit_align, &data); 4079399ab61SSantosh Sivaraj else 4089399ab61SSantosh Sivaraj __dma = (unsigned long) buf; 4099399ab61SSantosh Sivaraj 4109399ab61SSantosh Sivaraj if (!__dma) 4119399ab61SSantosh Sivaraj goto buf_err; 4129399ab61SSantosh Sivaraj 4139399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->list); 4149399ab61SSantosh Sivaraj res->dev = &p->pdev.dev; 4159399ab61SSantosh Sivaraj res->buf = buf; 4169399ab61SSantosh Sivaraj res->res.start = __dma; 4179399ab61SSantosh Sivaraj res->res.end = __dma + size - 1; 4189399ab61SSantosh Sivaraj res->res.name = "NFIT"; 4199399ab61SSantosh Sivaraj spin_lock_init(&res->lock); 4209399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->requests); 4219399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 4229399ab61SSantosh Sivaraj list_add(&res->list, &p->resources); 4239399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 4249399ab61SSantosh Sivaraj 4259399ab61SSantosh Sivaraj if (dma) 4269399ab61SSantosh Sivaraj *dma = __dma; 4279399ab61SSantosh Sivaraj 4289399ab61SSantosh Sivaraj if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res)) 4299399ab61SSantosh Sivaraj return res->buf; 4309399ab61SSantosh Sivaraj 4319399ab61SSantosh Sivaraj buf_err: 4329399ab61SSantosh Sivaraj if (__dma && size >= DIMM_SIZE) 4339399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, __dma, size); 4349399ab61SSantosh Sivaraj if (buf) 4359399ab61SSantosh Sivaraj vfree(buf); 4369399ab61SSantosh Sivaraj kfree(res); 4379399ab61SSantosh Sivaraj 4389399ab61SSantosh Sivaraj return NULL; 4399399ab61SSantosh Sivaraj } 4409399ab61SSantosh Sivaraj 4416fde2d4cSSantosh Sivaraj static ssize_t range_index_show(struct device *dev, 4426fde2d4cSSantosh Sivaraj struct device_attribute *attr, char *buf) 4436fde2d4cSSantosh Sivaraj { 4446fde2d4cSSantosh Sivaraj struct nd_region *nd_region = to_nd_region(dev); 4456fde2d4cSSantosh Sivaraj struct ndtest_region *region = nd_region_provider_data(nd_region); 4466fde2d4cSSantosh Sivaraj 4476fde2d4cSSantosh Sivaraj return sprintf(buf, "%d\n", region->range_index); 4486fde2d4cSSantosh Sivaraj } 4496fde2d4cSSantosh Sivaraj static DEVICE_ATTR_RO(range_index); 4506fde2d4cSSantosh Sivaraj 4516fde2d4cSSantosh Sivaraj static struct attribute *ndtest_region_attributes[] = { 4526fde2d4cSSantosh Sivaraj &dev_attr_range_index.attr, 4536fde2d4cSSantosh Sivaraj NULL, 4546fde2d4cSSantosh Sivaraj }; 4556fde2d4cSSantosh Sivaraj 4566fde2d4cSSantosh Sivaraj static const struct attribute_group ndtest_region_attribute_group = { 4576fde2d4cSSantosh Sivaraj .name = "papr", 4586fde2d4cSSantosh Sivaraj .attrs = ndtest_region_attributes, 4596fde2d4cSSantosh Sivaraj }; 4606fde2d4cSSantosh Sivaraj 4616fde2d4cSSantosh Sivaraj static const struct attribute_group *ndtest_region_attribute_groups[] = { 4626fde2d4cSSantosh Sivaraj &ndtest_region_attribute_group, 4636fde2d4cSSantosh Sivaraj NULL, 4646fde2d4cSSantosh Sivaraj }; 4656fde2d4cSSantosh Sivaraj 4666fde2d4cSSantosh Sivaraj static int ndtest_create_region(struct ndtest_priv *p, 4676fde2d4cSSantosh Sivaraj struct ndtest_region *region) 4686fde2d4cSSantosh Sivaraj { 4696fde2d4cSSantosh Sivaraj struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING]; 470*3b6c6c03SDan Williams struct nd_region_desc *ndr_desc, _ndr_desc; 4716fde2d4cSSantosh Sivaraj struct nd_interleave_set *nd_set; 4726fde2d4cSSantosh Sivaraj struct resource res; 4736fde2d4cSSantosh Sivaraj int i, ndimm = region->mapping[0].dimm; 4746fde2d4cSSantosh Sivaraj u64 uuid[2]; 4756fde2d4cSSantosh Sivaraj 4766fde2d4cSSantosh Sivaraj memset(&res, 0, sizeof(res)); 4776fde2d4cSSantosh Sivaraj memset(&mappings, 0, sizeof(mappings)); 478*3b6c6c03SDan Williams memset(&_ndr_desc, 0, sizeof(_ndr_desc)); 479*3b6c6c03SDan Williams ndr_desc = &_ndr_desc; 4806fde2d4cSSantosh Sivaraj 4816fde2d4cSSantosh Sivaraj if (!ndtest_alloc_resource(p, region->size, &res.start)) 4826fde2d4cSSantosh Sivaraj return -ENOMEM; 4836fde2d4cSSantosh Sivaraj 4846fde2d4cSSantosh Sivaraj res.end = res.start + region->size - 1; 4856fde2d4cSSantosh Sivaraj ndr_desc->mapping = mappings; 4866fde2d4cSSantosh Sivaraj ndr_desc->res = &res; 4876fde2d4cSSantosh Sivaraj ndr_desc->provider_data = region; 4886fde2d4cSSantosh Sivaraj ndr_desc->attr_groups = ndtest_region_attribute_groups; 4896fde2d4cSSantosh Sivaraj 4906fde2d4cSSantosh Sivaraj if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) { 4916fde2d4cSSantosh Sivaraj pr_err("failed to parse UUID\n"); 4926fde2d4cSSantosh Sivaraj return -ENXIO; 4936fde2d4cSSantosh Sivaraj } 4946fde2d4cSSantosh Sivaraj 4956fde2d4cSSantosh Sivaraj nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL); 4966fde2d4cSSantosh Sivaraj if (!nd_set) 4976fde2d4cSSantosh Sivaraj return -ENOMEM; 4986fde2d4cSSantosh Sivaraj 4996fde2d4cSSantosh Sivaraj nd_set->cookie1 = cpu_to_le64(uuid[0]); 5006fde2d4cSSantosh Sivaraj nd_set->cookie2 = cpu_to_le64(uuid[1]); 5016fde2d4cSSantosh Sivaraj nd_set->altcookie = nd_set->cookie1; 5026fde2d4cSSantosh Sivaraj ndr_desc->nd_set = nd_set; 5036fde2d4cSSantosh Sivaraj 5046fde2d4cSSantosh Sivaraj if (region->type == ND_DEVICE_NAMESPACE_BLK) { 5056fde2d4cSSantosh Sivaraj mappings[0].start = 0; 5066fde2d4cSSantosh Sivaraj mappings[0].size = DIMM_SIZE; 5076fde2d4cSSantosh Sivaraj mappings[0].nvdimm = p->config->dimms[ndimm].nvdimm; 5086fde2d4cSSantosh Sivaraj 5096fde2d4cSSantosh Sivaraj ndr_desc->mapping = &mappings[0]; 5106fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = 1; 5116fde2d4cSSantosh Sivaraj ndr_desc->num_lanes = 1; 5126fde2d4cSSantosh Sivaraj ndbr_desc.enable = ndtest_blk_region_enable; 5136fde2d4cSSantosh Sivaraj ndbr_desc.do_io = ndtest_blk_do_io; 5146fde2d4cSSantosh Sivaraj region->region = nvdimm_blk_region_create(p->bus, ndr_desc); 5156fde2d4cSSantosh Sivaraj 5166fde2d4cSSantosh Sivaraj goto done; 5176fde2d4cSSantosh Sivaraj } 5186fde2d4cSSantosh Sivaraj 5196fde2d4cSSantosh Sivaraj for (i = 0; i < region->num_mappings; i++) { 5206fde2d4cSSantosh Sivaraj ndimm = region->mapping[i].dimm; 5216fde2d4cSSantosh Sivaraj mappings[i].start = region->mapping[i].start; 5226fde2d4cSSantosh Sivaraj mappings[i].size = region->mapping[i].size; 5236fde2d4cSSantosh Sivaraj mappings[i].position = region->mapping[i].position; 5246fde2d4cSSantosh Sivaraj mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm; 5256fde2d4cSSantosh Sivaraj } 5266fde2d4cSSantosh Sivaraj 5276fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = region->num_mappings; 5286fde2d4cSSantosh Sivaraj region->region = nvdimm_pmem_region_create(p->bus, ndr_desc); 5296fde2d4cSSantosh Sivaraj 5306fde2d4cSSantosh Sivaraj done: 5316fde2d4cSSantosh Sivaraj if (!region->region) { 5326fde2d4cSSantosh Sivaraj dev_err(&p->pdev.dev, "Error registering region %pR\n", 5336fde2d4cSSantosh Sivaraj ndr_desc->res); 5346fde2d4cSSantosh Sivaraj return -ENXIO; 5356fde2d4cSSantosh Sivaraj } 5366fde2d4cSSantosh Sivaraj 5376fde2d4cSSantosh Sivaraj return 0; 5386fde2d4cSSantosh Sivaraj } 5396fde2d4cSSantosh Sivaraj 5406fde2d4cSSantosh Sivaraj static int ndtest_init_regions(struct ndtest_priv *p) 5416fde2d4cSSantosh Sivaraj { 5426fde2d4cSSantosh Sivaraj int i, ret = 0; 5436fde2d4cSSantosh Sivaraj 5446fde2d4cSSantosh Sivaraj for (i = 0; i < p->config->num_regions; i++) { 5456fde2d4cSSantosh Sivaraj ret = ndtest_create_region(p, &p->config->regions[i]); 5466fde2d4cSSantosh Sivaraj if (ret) 5476fde2d4cSSantosh Sivaraj return ret; 5486fde2d4cSSantosh Sivaraj } 5496fde2d4cSSantosh Sivaraj 5506fde2d4cSSantosh Sivaraj return 0; 5516fde2d4cSSantosh Sivaraj } 5526fde2d4cSSantosh Sivaraj 5539399ab61SSantosh Sivaraj static void put_dimms(void *data) 5549399ab61SSantosh Sivaraj { 5559399ab61SSantosh Sivaraj struct ndtest_priv *p = data; 5569399ab61SSantosh Sivaraj int i; 5579399ab61SSantosh Sivaraj 5589399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) 5599399ab61SSantosh Sivaraj if (p->config->dimms[i].dev) { 5609399ab61SSantosh Sivaraj device_unregister(p->config->dimms[i].dev); 5619399ab61SSantosh Sivaraj p->config->dimms[i].dev = NULL; 5629399ab61SSantosh Sivaraj } 5639399ab61SSantosh Sivaraj } 5649399ab61SSantosh Sivaraj 5655e41396fSSantosh Sivaraj static ssize_t handle_show(struct device *dev, struct device_attribute *attr, 5665e41396fSSantosh Sivaraj char *buf) 5675e41396fSSantosh Sivaraj { 5685e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5695e41396fSSantosh Sivaraj 5705e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 5715e41396fSSantosh Sivaraj } 5725e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(handle); 5735e41396fSSantosh Sivaraj 5745e41396fSSantosh Sivaraj static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 5755e41396fSSantosh Sivaraj char *buf) 5765e41396fSSantosh Sivaraj { 5775e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5785e41396fSSantosh Sivaraj 5795e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->fail_cmd); 5805e41396fSSantosh Sivaraj } 5815e41396fSSantosh Sivaraj 5825e41396fSSantosh Sivaraj static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 5835e41396fSSantosh Sivaraj const char *buf, size_t size) 5845e41396fSSantosh Sivaraj { 5855e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5865e41396fSSantosh Sivaraj unsigned long val; 5875e41396fSSantosh Sivaraj ssize_t rc; 5885e41396fSSantosh Sivaraj 5895e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 5905e41396fSSantosh Sivaraj if (rc) 5915e41396fSSantosh Sivaraj return rc; 5925e41396fSSantosh Sivaraj 5935e41396fSSantosh Sivaraj dimm->fail_cmd = val; 5945e41396fSSantosh Sivaraj 5955e41396fSSantosh Sivaraj return size; 5965e41396fSSantosh Sivaraj } 5975e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd); 5985e41396fSSantosh Sivaraj 5995e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 6005e41396fSSantosh Sivaraj char *buf) 6015e41396fSSantosh Sivaraj { 6025e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6035e41396fSSantosh Sivaraj 6045e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->fail_cmd_code); 6055e41396fSSantosh Sivaraj } 6065e41396fSSantosh Sivaraj 6075e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 6085e41396fSSantosh Sivaraj const char *buf, size_t size) 6095e41396fSSantosh Sivaraj { 6105e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6115e41396fSSantosh Sivaraj unsigned long val; 6125e41396fSSantosh Sivaraj ssize_t rc; 6135e41396fSSantosh Sivaraj 6145e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 6155e41396fSSantosh Sivaraj if (rc) 6165e41396fSSantosh Sivaraj return rc; 6175e41396fSSantosh Sivaraj 6185e41396fSSantosh Sivaraj dimm->fail_cmd_code = val; 6195e41396fSSantosh Sivaraj return size; 6205e41396fSSantosh Sivaraj } 6215e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd_code); 6225e41396fSSantosh Sivaraj 6235e41396fSSantosh Sivaraj static struct attribute *dimm_attributes[] = { 6245e41396fSSantosh Sivaraj &dev_attr_handle.attr, 6255e41396fSSantosh Sivaraj &dev_attr_fail_cmd.attr, 6265e41396fSSantosh Sivaraj &dev_attr_fail_cmd_code.attr, 6275e41396fSSantosh Sivaraj NULL, 6285e41396fSSantosh Sivaraj }; 6295e41396fSSantosh Sivaraj 6305e41396fSSantosh Sivaraj static struct attribute_group dimm_attribute_group = { 6315e41396fSSantosh Sivaraj .attrs = dimm_attributes, 6325e41396fSSantosh Sivaraj }; 6335e41396fSSantosh Sivaraj 6345e41396fSSantosh Sivaraj static const struct attribute_group *dimm_attribute_groups[] = { 6355e41396fSSantosh Sivaraj &dimm_attribute_group, 6365e41396fSSantosh Sivaraj NULL, 6375e41396fSSantosh Sivaraj }; 6385e41396fSSantosh Sivaraj 6395e41396fSSantosh Sivaraj static ssize_t phys_id_show(struct device *dev, 6405e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6415e41396fSSantosh Sivaraj { 6425e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6435e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6445e41396fSSantosh Sivaraj 6455e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->physical_id); 6465e41396fSSantosh Sivaraj } 6475e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(phys_id); 6485e41396fSSantosh Sivaraj 6495e41396fSSantosh Sivaraj static ssize_t vendor_show(struct device *dev, 6505e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6515e41396fSSantosh Sivaraj { 6525e41396fSSantosh Sivaraj return sprintf(buf, "0x1234567\n"); 6535e41396fSSantosh Sivaraj } 6545e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(vendor); 6555e41396fSSantosh Sivaraj 6565e41396fSSantosh Sivaraj static ssize_t id_show(struct device *dev, 6575e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6585e41396fSSantosh Sivaraj { 6595e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6605e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6615e41396fSSantosh Sivaraj 6625e41396fSSantosh Sivaraj return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd, 6635e41396fSSantosh Sivaraj 0xa, 2016, ~(dimm->handle)); 6645e41396fSSantosh Sivaraj } 6655e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(id); 6665e41396fSSantosh Sivaraj 6675e41396fSSantosh Sivaraj static ssize_t nvdimm_handle_show(struct device *dev, 6685e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6695e41396fSSantosh Sivaraj { 6705e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6715e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6725e41396fSSantosh Sivaraj 6735e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 6745e41396fSSantosh Sivaraj } 6755e41396fSSantosh Sivaraj 6765e41396fSSantosh Sivaraj static struct device_attribute dev_attr_nvdimm_show_handle = { 6775e41396fSSantosh Sivaraj .attr = { .name = "handle", .mode = 0444 }, 6785e41396fSSantosh Sivaraj .show = nvdimm_handle_show, 6795e41396fSSantosh Sivaraj }; 6805e41396fSSantosh Sivaraj 6815e41396fSSantosh Sivaraj static ssize_t subsystem_vendor_show(struct device *dev, 6825e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6835e41396fSSantosh Sivaraj { 6845e41396fSSantosh Sivaraj return sprintf(buf, "0x%04x\n", 0); 6855e41396fSSantosh Sivaraj } 6865e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(subsystem_vendor); 6875e41396fSSantosh Sivaraj 6885e41396fSSantosh Sivaraj static ssize_t dirty_shutdown_show(struct device *dev, 6895e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6905e41396fSSantosh Sivaraj { 6915e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", 42); 6925e41396fSSantosh Sivaraj } 6935e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(dirty_shutdown); 6945e41396fSSantosh Sivaraj 6955e41396fSSantosh Sivaraj static ssize_t formats_show(struct device *dev, 6965e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6975e41396fSSantosh Sivaraj { 6985e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6995e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7005e41396fSSantosh Sivaraj 7015e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->num_formats); 7025e41396fSSantosh Sivaraj } 7035e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(formats); 7045e41396fSSantosh Sivaraj 7055e41396fSSantosh Sivaraj static ssize_t format_show(struct device *dev, 7065e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7075e41396fSSantosh Sivaraj { 7085e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7095e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7105e41396fSSantosh Sivaraj 7115e41396fSSantosh Sivaraj if (dimm->num_formats > 1) 7125e41396fSSantosh Sivaraj return sprintf(buf, "0x201\n"); 7135e41396fSSantosh Sivaraj 7145e41396fSSantosh Sivaraj return sprintf(buf, "0x101\n"); 7155e41396fSSantosh Sivaraj } 7165e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format); 7175e41396fSSantosh Sivaraj 7185e41396fSSantosh Sivaraj static ssize_t format1_show(struct device *dev, struct device_attribute *attr, 7195e41396fSSantosh Sivaraj char *buf) 7205e41396fSSantosh Sivaraj { 7215e41396fSSantosh Sivaraj return sprintf(buf, "0x301\n"); 7225e41396fSSantosh Sivaraj } 7235e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format1); 7245e41396fSSantosh Sivaraj 7255e41396fSSantosh Sivaraj static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj, 7265e41396fSSantosh Sivaraj struct attribute *a, int n) 7275e41396fSSantosh Sivaraj { 7285e41396fSSantosh Sivaraj struct device *dev = container_of(kobj, struct device, kobj); 7295e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7305e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7315e41396fSSantosh Sivaraj 7325e41396fSSantosh Sivaraj if (a == &dev_attr_format1.attr && dimm->num_formats <= 1) 7335e41396fSSantosh Sivaraj return 0; 7345e41396fSSantosh Sivaraj 7355e41396fSSantosh Sivaraj return a->mode; 7365e41396fSSantosh Sivaraj } 7375e41396fSSantosh Sivaraj 73850f558a5SSantosh Sivaraj static ssize_t flags_show(struct device *dev, 73950f558a5SSantosh Sivaraj struct device_attribute *attr, char *buf) 74050f558a5SSantosh Sivaraj { 74150f558a5SSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 74250f558a5SSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 74350f558a5SSantosh Sivaraj struct seq_buf s; 74450f558a5SSantosh Sivaraj u64 flags; 74550f558a5SSantosh Sivaraj 74650f558a5SSantosh Sivaraj flags = dimm->flags; 74750f558a5SSantosh Sivaraj 74850f558a5SSantosh Sivaraj seq_buf_init(&s, buf, PAGE_SIZE); 74950f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_UNARMED_MASK) 75050f558a5SSantosh Sivaraj seq_buf_printf(&s, "not_armed "); 75150f558a5SSantosh Sivaraj 75250f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_BAD_SHUTDOWN_MASK) 75350f558a5SSantosh Sivaraj seq_buf_printf(&s, "flush_fail "); 75450f558a5SSantosh Sivaraj 75550f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_BAD_RESTORE_MASK) 75650f558a5SSantosh Sivaraj seq_buf_printf(&s, "restore_fail "); 75750f558a5SSantosh Sivaraj 75850f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_SAVE_MASK) 75950f558a5SSantosh Sivaraj seq_buf_printf(&s, "save_fail "); 76050f558a5SSantosh Sivaraj 76150f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_SMART_EVENT_MASK) 76250f558a5SSantosh Sivaraj seq_buf_printf(&s, "smart_notify "); 76350f558a5SSantosh Sivaraj 76450f558a5SSantosh Sivaraj 76550f558a5SSantosh Sivaraj if (seq_buf_used(&s)) 76650f558a5SSantosh Sivaraj seq_buf_printf(&s, "\n"); 76750f558a5SSantosh Sivaraj 76850f558a5SSantosh Sivaraj return seq_buf_used(&s); 76950f558a5SSantosh Sivaraj } 77050f558a5SSantosh Sivaraj static DEVICE_ATTR_RO(flags); 77150f558a5SSantosh Sivaraj 7725e41396fSSantosh Sivaraj static struct attribute *ndtest_nvdimm_attributes[] = { 7735e41396fSSantosh Sivaraj &dev_attr_nvdimm_show_handle.attr, 7745e41396fSSantosh Sivaraj &dev_attr_vendor.attr, 7755e41396fSSantosh Sivaraj &dev_attr_id.attr, 7765e41396fSSantosh Sivaraj &dev_attr_phys_id.attr, 7775e41396fSSantosh Sivaraj &dev_attr_subsystem_vendor.attr, 7785e41396fSSantosh Sivaraj &dev_attr_dirty_shutdown.attr, 7795e41396fSSantosh Sivaraj &dev_attr_formats.attr, 7805e41396fSSantosh Sivaraj &dev_attr_format.attr, 7815e41396fSSantosh Sivaraj &dev_attr_format1.attr, 78250f558a5SSantosh Sivaraj &dev_attr_flags.attr, 7835e41396fSSantosh Sivaraj NULL, 7845e41396fSSantosh Sivaraj }; 7855e41396fSSantosh Sivaraj 7865e41396fSSantosh Sivaraj static const struct attribute_group ndtest_nvdimm_attribute_group = { 7875e41396fSSantosh Sivaraj .name = "papr", 7885e41396fSSantosh Sivaraj .attrs = ndtest_nvdimm_attributes, 7895e41396fSSantosh Sivaraj .is_visible = ndtest_nvdimm_attr_visible, 7905e41396fSSantosh Sivaraj }; 7915e41396fSSantosh Sivaraj 7925e41396fSSantosh Sivaraj static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = { 7935e41396fSSantosh Sivaraj &ndtest_nvdimm_attribute_group, 7945e41396fSSantosh Sivaraj NULL, 7955e41396fSSantosh Sivaraj }; 7965e41396fSSantosh Sivaraj 7979399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv, 7989399ab61SSantosh Sivaraj struct ndtest_dimm *dimm, int id) 7999399ab61SSantosh Sivaraj { 8009399ab61SSantosh Sivaraj struct device *dev = &priv->pdev.dev; 8019399ab61SSantosh Sivaraj unsigned long dimm_flags = dimm->flags; 8029399ab61SSantosh Sivaraj 803*3b6c6c03SDan Williams if (dimm->num_formats > 1) 8049399ab61SSantosh Sivaraj set_bit(NDD_LABELING, &dimm_flags); 8059399ab61SSantosh Sivaraj 80650f558a5SSantosh Sivaraj if (dimm->flags & PAPR_PMEM_UNARMED_MASK) 80750f558a5SSantosh Sivaraj set_bit(NDD_UNARMED, &dimm_flags); 80850f558a5SSantosh Sivaraj 8095e41396fSSantosh Sivaraj dimm->nvdimm = nvdimm_create(priv->bus, dimm, 8105e41396fSSantosh Sivaraj ndtest_nvdimm_attribute_groups, dimm_flags, 8119399ab61SSantosh Sivaraj NDTEST_SCM_DIMM_CMD_MASK, 0, NULL); 8129399ab61SSantosh Sivaraj if (!dimm->nvdimm) { 8139399ab61SSantosh Sivaraj dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn); 8149399ab61SSantosh Sivaraj return -ENXIO; 8159399ab61SSantosh Sivaraj } 8169399ab61SSantosh Sivaraj 8179399ab61SSantosh Sivaraj dimm->dev = device_create_with_groups(ndtest_dimm_class, 8189399ab61SSantosh Sivaraj &priv->pdev.dev, 8195e41396fSSantosh Sivaraj 0, dimm, dimm_attribute_groups, 8209399ab61SSantosh Sivaraj "test_dimm%d", id); 8219399ab61SSantosh Sivaraj if (!dimm->dev) { 8229399ab61SSantosh Sivaraj pr_err("Could not create dimm device attributes\n"); 8239399ab61SSantosh Sivaraj return -ENOMEM; 8249399ab61SSantosh Sivaraj } 8259399ab61SSantosh Sivaraj 8269399ab61SSantosh Sivaraj return 0; 8279399ab61SSantosh Sivaraj } 8289399ab61SSantosh Sivaraj 8299399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p) 8309399ab61SSantosh Sivaraj { 8319399ab61SSantosh Sivaraj struct ndtest_dimm *d; 8329399ab61SSantosh Sivaraj void *res; 8339399ab61SSantosh Sivaraj int i, id; 8349399ab61SSantosh Sivaraj 8359399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) { 8369399ab61SSantosh Sivaraj d = &p->config->dimms[i]; 8379399ab61SSantosh Sivaraj d->id = id = p->config->dimm_start + i; 8389399ab61SSantosh Sivaraj res = ndtest_alloc_resource(p, LABEL_SIZE, NULL); 8399399ab61SSantosh Sivaraj if (!res) 8409399ab61SSantosh Sivaraj return -ENOMEM; 8419399ab61SSantosh Sivaraj 8429399ab61SSantosh Sivaraj d->label_area = res; 8439399ab61SSantosh Sivaraj sprintf(d->label_area, "label%d", id); 8449399ab61SSantosh Sivaraj d->config_size = LABEL_SIZE; 8459399ab61SSantosh Sivaraj 8469399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, d->size, 8479399ab61SSantosh Sivaraj &p->dimm_dma[id])) 8489399ab61SSantosh Sivaraj return -ENOMEM; 8499399ab61SSantosh Sivaraj 8509399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8519399ab61SSantosh Sivaraj &p->label_dma[id])) 8529399ab61SSantosh Sivaraj return -ENOMEM; 8539399ab61SSantosh Sivaraj 8549399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8559399ab61SSantosh Sivaraj &p->dcr_dma[id])) 8569399ab61SSantosh Sivaraj return -ENOMEM; 8579399ab61SSantosh Sivaraj 8589399ab61SSantosh Sivaraj d->address = p->dimm_dma[id]; 8599399ab61SSantosh Sivaraj 8609399ab61SSantosh Sivaraj ndtest_dimm_register(p, d, id); 8619399ab61SSantosh Sivaraj } 8629399ab61SSantosh Sivaraj 8639399ab61SSantosh Sivaraj return 0; 8649399ab61SSantosh Sivaraj } 8659399ab61SSantosh Sivaraj 866107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev, 867107b04e9SSantosh Sivaraj struct device_attribute *attr, char *buf) 868107b04e9SSantosh Sivaraj { 869107b04e9SSantosh Sivaraj return sprintf(buf, "nvdimm_test"); 870107b04e9SSantosh Sivaraj } 871107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible); 872107b04e9SSantosh Sivaraj 873107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = { 874107b04e9SSantosh Sivaraj &dev_attr_compatible.attr, 875107b04e9SSantosh Sivaraj NULL 876107b04e9SSantosh Sivaraj }; 877107b04e9SSantosh Sivaraj 878107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = { 879107b04e9SSantosh Sivaraj .name = "of_node", 880107b04e9SSantosh Sivaraj .attrs = of_node_attributes, 881107b04e9SSantosh Sivaraj }; 882107b04e9SSantosh Sivaraj 883107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = { 884107b04e9SSantosh Sivaraj &of_node_attribute_group, 885107b04e9SSantosh Sivaraj NULL, 886107b04e9SSantosh Sivaraj }; 887107b04e9SSantosh Sivaraj 8889a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p) 8899a27e109SSantosh Sivaraj { 8909399ab61SSantosh Sivaraj p->config = &bus_configs[p->pdev.id]; 8919399ab61SSantosh Sivaraj 8929a27e109SSantosh Sivaraj p->bus_desc.ndctl = ndtest_ctl; 8939a27e109SSantosh Sivaraj p->bus_desc.module = THIS_MODULE; 8949a27e109SSantosh Sivaraj p->bus_desc.provider_name = NULL; 895107b04e9SSantosh Sivaraj p->bus_desc.attr_groups = ndtest_attribute_groups; 8969a27e109SSantosh Sivaraj 8979a27e109SSantosh Sivaraj p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 8989a27e109SSantosh Sivaraj if (!p->bus) { 8999a27e109SSantosh Sivaraj dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 9009a27e109SSantosh Sivaraj return -ENOMEM; 9019a27e109SSantosh Sivaraj } 9029a27e109SSantosh Sivaraj 9039a27e109SSantosh Sivaraj return 0; 9049a27e109SSantosh Sivaraj } 9059a27e109SSantosh Sivaraj 9069a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev) 9079a27e109SSantosh Sivaraj { 9089a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 9099a27e109SSantosh Sivaraj 9109a27e109SSantosh Sivaraj nvdimm_bus_unregister(p->bus); 9119a27e109SSantosh Sivaraj return 0; 9129a27e109SSantosh Sivaraj } 9139a27e109SSantosh Sivaraj 9149a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev) 9159a27e109SSantosh Sivaraj { 9169a27e109SSantosh Sivaraj struct ndtest_priv *p; 9179399ab61SSantosh Sivaraj int rc; 9189a27e109SSantosh Sivaraj 9199a27e109SSantosh Sivaraj p = to_ndtest_priv(&pdev->dev); 9209a27e109SSantosh Sivaraj if (ndtest_bus_register(p)) 9219a27e109SSantosh Sivaraj return -ENOMEM; 9229a27e109SSantosh Sivaraj 9239399ab61SSantosh Sivaraj p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9249399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9259399ab61SSantosh Sivaraj p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9269399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9279399ab61SSantosh Sivaraj p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9289399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9299399ab61SSantosh Sivaraj 9309399ab61SSantosh Sivaraj rc = ndtest_nvdimm_init(p); 9319399ab61SSantosh Sivaraj if (rc) 9329399ab61SSantosh Sivaraj goto err; 9339399ab61SSantosh Sivaraj 9346fde2d4cSSantosh Sivaraj rc = ndtest_init_regions(p); 9356fde2d4cSSantosh Sivaraj if (rc) 9366fde2d4cSSantosh Sivaraj goto err; 9376fde2d4cSSantosh Sivaraj 9389399ab61SSantosh Sivaraj rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p); 9399399ab61SSantosh Sivaraj if (rc) 9409399ab61SSantosh Sivaraj goto err; 9419399ab61SSantosh Sivaraj 9429a27e109SSantosh Sivaraj platform_set_drvdata(pdev, p); 9439a27e109SSantosh Sivaraj 9449a27e109SSantosh Sivaraj return 0; 9459399ab61SSantosh Sivaraj 9469399ab61SSantosh Sivaraj err: 9479399ab61SSantosh Sivaraj pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__); 9489399ab61SSantosh Sivaraj return rc; 9499a27e109SSantosh Sivaraj } 9509a27e109SSantosh Sivaraj 9519a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = { 9529a27e109SSantosh Sivaraj { KBUILD_MODNAME }, 9539a27e109SSantosh Sivaraj { }, 9549a27e109SSantosh Sivaraj }; 9559a27e109SSantosh Sivaraj 9569a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = { 9579a27e109SSantosh Sivaraj .probe = ndtest_probe, 9589a27e109SSantosh Sivaraj .remove = ndtest_remove, 9599a27e109SSantosh Sivaraj .driver = { 9609a27e109SSantosh Sivaraj .name = KBUILD_MODNAME, 9619a27e109SSantosh Sivaraj }, 9629a27e109SSantosh Sivaraj .id_table = ndtest_id, 9639a27e109SSantosh Sivaraj }; 9649a27e109SSantosh Sivaraj 9659a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev) 9669a27e109SSantosh Sivaraj { 9679a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(dev); 9689a27e109SSantosh Sivaraj 9699a27e109SSantosh Sivaraj kfree(p); 9709a27e109SSantosh Sivaraj } 9719a27e109SSantosh Sivaraj 9729a27e109SSantosh Sivaraj static void cleanup_devices(void) 9739a27e109SSantosh Sivaraj { 9749a27e109SSantosh Sivaraj int i; 9759a27e109SSantosh Sivaraj 9769a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) 9779a27e109SSantosh Sivaraj if (instances[i]) 9789a27e109SSantosh Sivaraj platform_device_unregister(&instances[i]->pdev); 9799a27e109SSantosh Sivaraj 9809a27e109SSantosh Sivaraj nfit_test_teardown(); 9819a27e109SSantosh Sivaraj 9829399ab61SSantosh Sivaraj if (ndtest_pool) 9839399ab61SSantosh Sivaraj gen_pool_destroy(ndtest_pool); 9849399ab61SSantosh Sivaraj 9859399ab61SSantosh Sivaraj 9869a27e109SSantosh Sivaraj if (ndtest_dimm_class) 9879a27e109SSantosh Sivaraj class_destroy(ndtest_dimm_class); 9889a27e109SSantosh Sivaraj } 9899a27e109SSantosh Sivaraj 9909a27e109SSantosh Sivaraj static __init int ndtest_init(void) 9919a27e109SSantosh Sivaraj { 9929a27e109SSantosh Sivaraj int rc, i; 9939a27e109SSantosh Sivaraj 9949a27e109SSantosh Sivaraj pmem_test(); 9959a27e109SSantosh Sivaraj libnvdimm_test(); 9969a27e109SSantosh Sivaraj device_dax_test(); 9979a27e109SSantosh Sivaraj dax_pmem_test(); 9989a27e109SSantosh Sivaraj 9996fde2d4cSSantosh Sivaraj nfit_test_setup(ndtest_resource_lookup, NULL); 10006fde2d4cSSantosh Sivaraj 10019a27e109SSantosh Sivaraj ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm"); 10029a27e109SSantosh Sivaraj if (IS_ERR(ndtest_dimm_class)) { 10039a27e109SSantosh Sivaraj rc = PTR_ERR(ndtest_dimm_class); 10049a27e109SSantosh Sivaraj goto err_register; 10059a27e109SSantosh Sivaraj } 10069a27e109SSantosh Sivaraj 10079399ab61SSantosh Sivaraj ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 10089399ab61SSantosh Sivaraj if (!ndtest_pool) { 10099399ab61SSantosh Sivaraj rc = -ENOMEM; 10109399ab61SSantosh Sivaraj goto err_register; 10119399ab61SSantosh Sivaraj } 10129399ab61SSantosh Sivaraj 10139399ab61SSantosh Sivaraj if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 10149399ab61SSantosh Sivaraj rc = -ENOMEM; 10159399ab61SSantosh Sivaraj goto err_register; 10169399ab61SSantosh Sivaraj } 10179399ab61SSantosh Sivaraj 10189a27e109SSantosh Sivaraj /* Each instance can be taken as a bus, which can have multiple dimms */ 10199a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 10209a27e109SSantosh Sivaraj struct ndtest_priv *priv; 10219a27e109SSantosh Sivaraj struct platform_device *pdev; 10229a27e109SSantosh Sivaraj 10239a27e109SSantosh Sivaraj priv = kzalloc(sizeof(*priv), GFP_KERNEL); 10249a27e109SSantosh Sivaraj if (!priv) { 10259a27e109SSantosh Sivaraj rc = -ENOMEM; 10269a27e109SSantosh Sivaraj goto err_register; 10279a27e109SSantosh Sivaraj } 10289a27e109SSantosh Sivaraj 10299a27e109SSantosh Sivaraj INIT_LIST_HEAD(&priv->resources); 10309a27e109SSantosh Sivaraj pdev = &priv->pdev; 10319a27e109SSantosh Sivaraj pdev->name = KBUILD_MODNAME; 10329a27e109SSantosh Sivaraj pdev->id = i; 10339a27e109SSantosh Sivaraj pdev->dev.release = ndtest_release; 10349a27e109SSantosh Sivaraj rc = platform_device_register(pdev); 10359a27e109SSantosh Sivaraj if (rc) { 10369a27e109SSantosh Sivaraj put_device(&pdev->dev); 10379a27e109SSantosh Sivaraj goto err_register; 10389a27e109SSantosh Sivaraj } 10399a27e109SSantosh Sivaraj get_device(&pdev->dev); 10409a27e109SSantosh Sivaraj 10419a27e109SSantosh Sivaraj instances[i] = priv; 10429a27e109SSantosh Sivaraj } 10439a27e109SSantosh Sivaraj 10449a27e109SSantosh Sivaraj rc = platform_driver_register(&ndtest_driver); 10459a27e109SSantosh Sivaraj if (rc) 10469a27e109SSantosh Sivaraj goto err_register; 10479a27e109SSantosh Sivaraj 10489a27e109SSantosh Sivaraj return 0; 10499a27e109SSantosh Sivaraj 10509a27e109SSantosh Sivaraj err_register: 10519a27e109SSantosh Sivaraj pr_err("Error registering platform device\n"); 10529a27e109SSantosh Sivaraj cleanup_devices(); 10539a27e109SSantosh Sivaraj 10549a27e109SSantosh Sivaraj return rc; 10559a27e109SSantosh Sivaraj } 10569a27e109SSantosh Sivaraj 10579a27e109SSantosh Sivaraj static __exit void ndtest_exit(void) 10589a27e109SSantosh Sivaraj { 10599a27e109SSantosh Sivaraj cleanup_devices(); 10609a27e109SSantosh Sivaraj platform_driver_unregister(&ndtest_driver); 10619a27e109SSantosh Sivaraj } 10629a27e109SSantosh Sivaraj 10639a27e109SSantosh Sivaraj module_init(ndtest_init); 10649a27e109SSantosh Sivaraj module_exit(ndtest_exit); 10659a27e109SSantosh Sivaraj MODULE_LICENSE("GPL"); 10669a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation"); 1067