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, 899399ab61SSantosh Sivaraj }, 909399ab61SSantosh Sivaraj }; 919399ab61SSantosh Sivaraj 926fde2d4cSSantosh Sivaraj static struct ndtest_mapping region0_mapping[] = { 936fde2d4cSSantosh Sivaraj { 946fde2d4cSSantosh Sivaraj .dimm = 0, 956fde2d4cSSantosh Sivaraj .position = 0, 966fde2d4cSSantosh Sivaraj .start = 0, 976fde2d4cSSantosh Sivaraj .size = SZ_16M, 986fde2d4cSSantosh Sivaraj }, 996fde2d4cSSantosh Sivaraj { 1006fde2d4cSSantosh Sivaraj .dimm = 1, 1016fde2d4cSSantosh Sivaraj .position = 1, 1026fde2d4cSSantosh Sivaraj .start = 0, 1036fde2d4cSSantosh Sivaraj .size = SZ_16M, 1046fde2d4cSSantosh Sivaraj } 1056fde2d4cSSantosh Sivaraj }; 1066fde2d4cSSantosh Sivaraj 1076fde2d4cSSantosh Sivaraj static struct ndtest_mapping region1_mapping[] = { 1086fde2d4cSSantosh Sivaraj { 1096fde2d4cSSantosh Sivaraj .dimm = 0, 1106fde2d4cSSantosh Sivaraj .position = 0, 1116fde2d4cSSantosh Sivaraj .start = SZ_16M, 1126fde2d4cSSantosh Sivaraj .size = SZ_16M, 1136fde2d4cSSantosh Sivaraj }, 1146fde2d4cSSantosh Sivaraj { 1156fde2d4cSSantosh Sivaraj .dimm = 1, 1166fde2d4cSSantosh Sivaraj .position = 1, 1176fde2d4cSSantosh Sivaraj .start = SZ_16M, 1186fde2d4cSSantosh Sivaraj .size = SZ_16M, 1196fde2d4cSSantosh Sivaraj }, 1206fde2d4cSSantosh Sivaraj { 1216fde2d4cSSantosh Sivaraj .dimm = 2, 1226fde2d4cSSantosh Sivaraj .position = 2, 1236fde2d4cSSantosh Sivaraj .start = SZ_16M, 1246fde2d4cSSantosh Sivaraj .size = SZ_16M, 1256fde2d4cSSantosh Sivaraj }, 1266fde2d4cSSantosh Sivaraj { 1276fde2d4cSSantosh Sivaraj .dimm = 3, 1286fde2d4cSSantosh Sivaraj .position = 3, 1296fde2d4cSSantosh Sivaraj .start = SZ_16M, 1306fde2d4cSSantosh Sivaraj .size = SZ_16M, 1316fde2d4cSSantosh Sivaraj }, 1326fde2d4cSSantosh Sivaraj }; 1336fde2d4cSSantosh Sivaraj 1346fde2d4cSSantosh Sivaraj static struct ndtest_mapping region2_mapping[] = { 1356fde2d4cSSantosh Sivaraj { 1366fde2d4cSSantosh Sivaraj .dimm = 0, 1376fde2d4cSSantosh Sivaraj .position = 0, 1386fde2d4cSSantosh Sivaraj .start = 0, 1396fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1406fde2d4cSSantosh Sivaraj }, 1416fde2d4cSSantosh Sivaraj }; 1426fde2d4cSSantosh Sivaraj 1436fde2d4cSSantosh Sivaraj static struct ndtest_mapping region3_mapping[] = { 1446fde2d4cSSantosh Sivaraj { 1456fde2d4cSSantosh Sivaraj .dimm = 1, 1466fde2d4cSSantosh Sivaraj .start = 0, 1476fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1486fde2d4cSSantosh Sivaraj } 1496fde2d4cSSantosh Sivaraj }; 1506fde2d4cSSantosh Sivaraj 1516fde2d4cSSantosh Sivaraj static struct ndtest_mapping region4_mapping[] = { 1526fde2d4cSSantosh Sivaraj { 1536fde2d4cSSantosh Sivaraj .dimm = 2, 1546fde2d4cSSantosh Sivaraj .start = 0, 1556fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1566fde2d4cSSantosh Sivaraj } 1576fde2d4cSSantosh Sivaraj }; 1586fde2d4cSSantosh Sivaraj 1596fde2d4cSSantosh Sivaraj static struct ndtest_mapping region5_mapping[] = { 1606fde2d4cSSantosh Sivaraj { 1616fde2d4cSSantosh Sivaraj .dimm = 3, 1626fde2d4cSSantosh Sivaraj .start = 0, 1636fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1646fde2d4cSSantosh Sivaraj } 1656fde2d4cSSantosh Sivaraj }; 1666fde2d4cSSantosh Sivaraj 1676fde2d4cSSantosh Sivaraj static struct ndtest_region bus0_regions[] = { 1686fde2d4cSSantosh Sivaraj { 1696fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1706fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region0_mapping), 1716fde2d4cSSantosh Sivaraj .mapping = region0_mapping, 1726fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1736fde2d4cSSantosh Sivaraj .range_index = 1, 1746fde2d4cSSantosh Sivaraj }, 1756fde2d4cSSantosh Sivaraj { 1766fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1776fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region1_mapping), 1786fde2d4cSSantosh Sivaraj .mapping = region1_mapping, 1796fde2d4cSSantosh Sivaraj .size = DIMM_SIZE * 2, 1806fde2d4cSSantosh Sivaraj .range_index = 2, 1816fde2d4cSSantosh Sivaraj }, 1826fde2d4cSSantosh Sivaraj { 1836fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 1846fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region2_mapping), 1856fde2d4cSSantosh Sivaraj .mapping = region2_mapping, 1866fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1876fde2d4cSSantosh Sivaraj .range_index = 3, 1886fde2d4cSSantosh Sivaraj }, 1896fde2d4cSSantosh Sivaraj { 1906fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 1916fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region3_mapping), 1926fde2d4cSSantosh Sivaraj .mapping = region3_mapping, 1936fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1946fde2d4cSSantosh Sivaraj .range_index = 4, 1956fde2d4cSSantosh Sivaraj }, 1966fde2d4cSSantosh Sivaraj { 1976fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 1986fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region4_mapping), 1996fde2d4cSSantosh Sivaraj .mapping = region4_mapping, 2006fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2016fde2d4cSSantosh Sivaraj .range_index = 5, 2026fde2d4cSSantosh Sivaraj }, 2036fde2d4cSSantosh Sivaraj { 2046fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 2056fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region5_mapping), 2066fde2d4cSSantosh Sivaraj .mapping = region5_mapping, 2076fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2086fde2d4cSSantosh Sivaraj .range_index = 6, 2096fde2d4cSSantosh Sivaraj }, 2106fde2d4cSSantosh Sivaraj }; 2116fde2d4cSSantosh Sivaraj 2126fde2d4cSSantosh Sivaraj static struct ndtest_mapping region6_mapping[] = { 2136fde2d4cSSantosh Sivaraj { 2146fde2d4cSSantosh Sivaraj .dimm = 0, 2156fde2d4cSSantosh Sivaraj .position = 0, 2166fde2d4cSSantosh Sivaraj .start = 0, 2176fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2186fde2d4cSSantosh Sivaraj }, 2196fde2d4cSSantosh Sivaraj }; 2206fde2d4cSSantosh Sivaraj 2216fde2d4cSSantosh Sivaraj static struct ndtest_region bus1_regions[] = { 2226fde2d4cSSantosh Sivaraj { 2236fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_IO, 2246fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region6_mapping), 2256fde2d4cSSantosh Sivaraj .mapping = region6_mapping, 2266fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 2276fde2d4cSSantosh Sivaraj .range_index = 1, 2286fde2d4cSSantosh Sivaraj }, 2296fde2d4cSSantosh Sivaraj }; 2306fde2d4cSSantosh Sivaraj 2319399ab61SSantosh Sivaraj static struct ndtest_config bus_configs[NUM_INSTANCES] = { 2329399ab61SSantosh Sivaraj /* bus 1 */ 2339399ab61SSantosh Sivaraj { 2349399ab61SSantosh Sivaraj .dimm_start = 0, 2359399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group1), 2369399ab61SSantosh Sivaraj .dimms = dimm_group1, 2376fde2d4cSSantosh Sivaraj .regions = bus0_regions, 2386fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus0_regions), 2399399ab61SSantosh Sivaraj }, 2409399ab61SSantosh Sivaraj /* bus 2 */ 2419399ab61SSantosh Sivaraj { 2429399ab61SSantosh Sivaraj .dimm_start = ARRAY_SIZE(dimm_group1), 2439399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group2), 2449399ab61SSantosh Sivaraj .dimms = dimm_group2, 2456fde2d4cSSantosh Sivaraj .regions = bus1_regions, 2466fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus1_regions), 2479399ab61SSantosh Sivaraj }, 2489399ab61SSantosh Sivaraj }; 2499a27e109SSantosh Sivaraj 2509a27e109SSantosh Sivaraj static inline struct ndtest_priv *to_ndtest_priv(struct device *dev) 2519a27e109SSantosh Sivaraj { 2529a27e109SSantosh Sivaraj struct platform_device *pdev = to_platform_device(dev); 2539a27e109SSantosh Sivaraj 2549a27e109SSantosh Sivaraj return container_of(pdev, struct ndtest_priv, pdev); 2559a27e109SSantosh Sivaraj } 2569a27e109SSantosh Sivaraj 257*14ccef10SSantosh Sivaraj static int ndtest_config_get(struct ndtest_dimm *p, unsigned int buf_len, 258*14ccef10SSantosh Sivaraj struct nd_cmd_get_config_data_hdr *hdr) 259*14ccef10SSantosh Sivaraj { 260*14ccef10SSantosh Sivaraj unsigned int len; 261*14ccef10SSantosh Sivaraj 262*14ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 263*14ccef10SSantosh Sivaraj return -EINVAL; 264*14ccef10SSantosh Sivaraj 265*14ccef10SSantosh Sivaraj hdr->status = 0; 266*14ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 267*14ccef10SSantosh Sivaraj memcpy(hdr->out_buf, p->label_area + hdr->in_offset, len); 268*14ccef10SSantosh Sivaraj 269*14ccef10SSantosh Sivaraj return buf_len - len; 270*14ccef10SSantosh Sivaraj } 271*14ccef10SSantosh Sivaraj 272*14ccef10SSantosh Sivaraj static int ndtest_config_set(struct ndtest_dimm *p, unsigned int buf_len, 273*14ccef10SSantosh Sivaraj struct nd_cmd_set_config_hdr *hdr) 274*14ccef10SSantosh Sivaraj { 275*14ccef10SSantosh Sivaraj unsigned int len; 276*14ccef10SSantosh Sivaraj 277*14ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 278*14ccef10SSantosh Sivaraj return -EINVAL; 279*14ccef10SSantosh Sivaraj 280*14ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 281*14ccef10SSantosh Sivaraj memcpy(p->label_area + hdr->in_offset, hdr->in_buf, len); 282*14ccef10SSantosh Sivaraj 283*14ccef10SSantosh Sivaraj return buf_len - len; 284*14ccef10SSantosh Sivaraj } 285*14ccef10SSantosh Sivaraj 286*14ccef10SSantosh Sivaraj static int ndtest_get_config_size(struct ndtest_dimm *dimm, unsigned int buf_len, 287*14ccef10SSantosh Sivaraj struct nd_cmd_get_config_size *size) 288*14ccef10SSantosh Sivaraj { 289*14ccef10SSantosh Sivaraj size->status = 0; 290*14ccef10SSantosh Sivaraj size->max_xfer = 8; 291*14ccef10SSantosh Sivaraj size->config_size = dimm->config_size; 292*14ccef10SSantosh Sivaraj 293*14ccef10SSantosh Sivaraj return 0; 294*14ccef10SSantosh Sivaraj } 295*14ccef10SSantosh Sivaraj 2969a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 2979a27e109SSantosh Sivaraj struct nvdimm *nvdimm, unsigned int cmd, void *buf, 2989a27e109SSantosh Sivaraj unsigned int buf_len, int *cmd_rc) 2999a27e109SSantosh Sivaraj { 3009a27e109SSantosh Sivaraj struct ndtest_dimm *dimm; 3019a27e109SSantosh Sivaraj int _cmd_rc; 3029a27e109SSantosh Sivaraj 3039a27e109SSantosh Sivaraj if (!cmd_rc) 3049a27e109SSantosh Sivaraj cmd_rc = &_cmd_rc; 3059a27e109SSantosh Sivaraj 3069a27e109SSantosh Sivaraj *cmd_rc = 0; 3079a27e109SSantosh Sivaraj 3089a27e109SSantosh Sivaraj if (!nvdimm) 3099a27e109SSantosh Sivaraj return -EINVAL; 3109a27e109SSantosh Sivaraj 3119a27e109SSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 3129a27e109SSantosh Sivaraj if (!dimm) 3139a27e109SSantosh Sivaraj return -EINVAL; 3149a27e109SSantosh Sivaraj 3159a27e109SSantosh Sivaraj switch (cmd) { 3169a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_SIZE: 317*14ccef10SSantosh Sivaraj *cmd_rc = ndtest_get_config_size(dimm, buf_len, buf); 318*14ccef10SSantosh Sivaraj break; 3199a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_DATA: 320*14ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_get(dimm, buf_len, buf); 321*14ccef10SSantosh Sivaraj break; 3229a27e109SSantosh Sivaraj case ND_CMD_SET_CONFIG_DATA: 323*14ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_set(dimm, buf_len, buf); 324*14ccef10SSantosh Sivaraj break; 3259a27e109SSantosh Sivaraj default: 3269a27e109SSantosh Sivaraj return -EINVAL; 3279a27e109SSantosh Sivaraj } 3289a27e109SSantosh Sivaraj 329*14ccef10SSantosh Sivaraj /* Failures for a DIMM can be injected using fail_cmd and 330*14ccef10SSantosh Sivaraj * fail_cmd_code, see the device attributes below 331*14ccef10SSantosh Sivaraj */ 332*14ccef10SSantosh Sivaraj if ((1 << cmd) & dimm->fail_cmd) 333*14ccef10SSantosh Sivaraj return dimm->fail_cmd_code ? dimm->fail_cmd_code : -EIO; 334*14ccef10SSantosh Sivaraj 3359a27e109SSantosh Sivaraj return 0; 3369a27e109SSantosh Sivaraj } 3379a27e109SSantosh Sivaraj 3386fde2d4cSSantosh Sivaraj static int ndtest_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, 3396fde2d4cSSantosh Sivaraj void *iobuf, u64 len, int rw) 3406fde2d4cSSantosh Sivaraj { 3416fde2d4cSSantosh Sivaraj struct ndtest_dimm *dimm = ndbr->blk_provider_data; 3426fde2d4cSSantosh Sivaraj struct ndtest_blk_mmio *mmio = dimm->mmio; 3436fde2d4cSSantosh Sivaraj struct nd_region *nd_region = &ndbr->nd_region; 3446fde2d4cSSantosh Sivaraj unsigned int lane; 3456fde2d4cSSantosh Sivaraj 3466fde2d4cSSantosh Sivaraj if (!mmio) 3476fde2d4cSSantosh Sivaraj return -ENOMEM; 3486fde2d4cSSantosh Sivaraj 3496fde2d4cSSantosh Sivaraj lane = nd_region_acquire_lane(nd_region); 3506fde2d4cSSantosh Sivaraj if (rw) 3516fde2d4cSSantosh Sivaraj memcpy(mmio->base + dpa, iobuf, len); 3526fde2d4cSSantosh Sivaraj else { 3536fde2d4cSSantosh Sivaraj memcpy(iobuf, mmio->base + dpa, len); 3546fde2d4cSSantosh Sivaraj arch_invalidate_pmem(mmio->base + dpa, len); 3556fde2d4cSSantosh Sivaraj } 3566fde2d4cSSantosh Sivaraj 3576fde2d4cSSantosh Sivaraj nd_region_release_lane(nd_region, lane); 3586fde2d4cSSantosh Sivaraj 3596fde2d4cSSantosh Sivaraj return 0; 3606fde2d4cSSantosh Sivaraj } 3616fde2d4cSSantosh Sivaraj 3626fde2d4cSSantosh Sivaraj static int ndtest_blk_region_enable(struct nvdimm_bus *nvdimm_bus, 3636fde2d4cSSantosh Sivaraj struct device *dev) 3646fde2d4cSSantosh Sivaraj { 3656fde2d4cSSantosh Sivaraj struct nd_blk_region *ndbr = to_nd_blk_region(dev); 3666fde2d4cSSantosh Sivaraj struct nvdimm *nvdimm; 3676fde2d4cSSantosh Sivaraj struct ndtest_dimm *dimm; 3686fde2d4cSSantosh Sivaraj struct ndtest_blk_mmio *mmio; 3696fde2d4cSSantosh Sivaraj 3706fde2d4cSSantosh Sivaraj nvdimm = nd_blk_region_to_dimm(ndbr); 3716fde2d4cSSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 3726fde2d4cSSantosh Sivaraj 3736fde2d4cSSantosh Sivaraj nd_blk_region_set_provider_data(ndbr, dimm); 3746fde2d4cSSantosh Sivaraj dimm->blk_region = to_nd_region(dev); 3756fde2d4cSSantosh Sivaraj 3766fde2d4cSSantosh Sivaraj mmio = devm_kzalloc(dev, sizeof(struct ndtest_blk_mmio), GFP_KERNEL); 3776fde2d4cSSantosh Sivaraj if (!mmio) 3786fde2d4cSSantosh Sivaraj return -ENOMEM; 3796fde2d4cSSantosh Sivaraj 3806fde2d4cSSantosh Sivaraj mmio->base = (void __iomem *) devm_nvdimm_memremap( 3816fde2d4cSSantosh Sivaraj dev, dimm->address, 12, nd_blk_memremap_flags(ndbr)); 3826fde2d4cSSantosh Sivaraj if (!mmio->base) { 3836fde2d4cSSantosh Sivaraj dev_err(dev, "%s failed to map blk dimm\n", nvdimm_name(nvdimm)); 3846fde2d4cSSantosh Sivaraj return -ENOMEM; 3856fde2d4cSSantosh Sivaraj } 3866fde2d4cSSantosh Sivaraj mmio->size = dimm->size; 3876fde2d4cSSantosh Sivaraj mmio->base_offset = 0; 3886fde2d4cSSantosh Sivaraj 3896fde2d4cSSantosh Sivaraj dimm->mmio = mmio; 3906fde2d4cSSantosh Sivaraj 3916fde2d4cSSantosh Sivaraj return 0; 3926fde2d4cSSantosh Sivaraj } 3936fde2d4cSSantosh Sivaraj 3946fde2d4cSSantosh Sivaraj static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr) 3956fde2d4cSSantosh Sivaraj { 3966fde2d4cSSantosh Sivaraj int i; 3976fde2d4cSSantosh Sivaraj 3986fde2d4cSSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 3996fde2d4cSSantosh Sivaraj struct nfit_test_resource *n, *nfit_res = NULL; 4006fde2d4cSSantosh Sivaraj struct ndtest_priv *t = instances[i]; 4016fde2d4cSSantosh Sivaraj 4026fde2d4cSSantosh Sivaraj if (!t) 4036fde2d4cSSantosh Sivaraj continue; 4046fde2d4cSSantosh Sivaraj spin_lock(&ndtest_lock); 4056fde2d4cSSantosh Sivaraj list_for_each_entry(n, &t->resources, list) { 4066fde2d4cSSantosh Sivaraj if (addr >= n->res.start && (addr < n->res.start 4076fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 4086fde2d4cSSantosh Sivaraj nfit_res = n; 4096fde2d4cSSantosh Sivaraj break; 4106fde2d4cSSantosh Sivaraj } else if (addr >= (unsigned long) n->buf 4116fde2d4cSSantosh Sivaraj && (addr < (unsigned long) n->buf 4126fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 4136fde2d4cSSantosh Sivaraj nfit_res = n; 4146fde2d4cSSantosh Sivaraj break; 4156fde2d4cSSantosh Sivaraj } 4166fde2d4cSSantosh Sivaraj } 4176fde2d4cSSantosh Sivaraj spin_unlock(&ndtest_lock); 4186fde2d4cSSantosh Sivaraj if (nfit_res) 4196fde2d4cSSantosh Sivaraj return nfit_res; 4206fde2d4cSSantosh Sivaraj } 4216fde2d4cSSantosh Sivaraj 4226fde2d4cSSantosh Sivaraj pr_warn("Failed to get resource\n"); 4236fde2d4cSSantosh Sivaraj 4246fde2d4cSSantosh Sivaraj return NULL; 4256fde2d4cSSantosh Sivaraj } 4266fde2d4cSSantosh Sivaraj 4279399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data) 4289399ab61SSantosh Sivaraj { 4299399ab61SSantosh Sivaraj struct nfit_test_resource *res = data; 4309399ab61SSantosh Sivaraj 4319399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 4329399ab61SSantosh Sivaraj list_del(&res->list); 4339399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 4349399ab61SSantosh Sivaraj 4359399ab61SSantosh Sivaraj if (resource_size(&res->res) >= DIMM_SIZE) 4369399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, res->res.start, 4379399ab61SSantosh Sivaraj resource_size(&res->res)); 4389399ab61SSantosh Sivaraj vfree(res->buf); 4399399ab61SSantosh Sivaraj kfree(res); 4409399ab61SSantosh Sivaraj } 4419399ab61SSantosh Sivaraj 4429399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size, 4439399ab61SSantosh Sivaraj dma_addr_t *dma) 4449399ab61SSantosh Sivaraj { 4459399ab61SSantosh Sivaraj dma_addr_t __dma; 4469399ab61SSantosh Sivaraj void *buf; 4479399ab61SSantosh Sivaraj struct nfit_test_resource *res; 4489399ab61SSantosh Sivaraj struct genpool_data_align data = { 4499399ab61SSantosh Sivaraj .align = SZ_128M, 4509399ab61SSantosh Sivaraj }; 4519399ab61SSantosh Sivaraj 4529399ab61SSantosh Sivaraj res = kzalloc(sizeof(*res), GFP_KERNEL); 4539399ab61SSantosh Sivaraj if (!res) 4549399ab61SSantosh Sivaraj return NULL; 4559399ab61SSantosh Sivaraj 4569399ab61SSantosh Sivaraj buf = vmalloc(size); 4579399ab61SSantosh Sivaraj if (size >= DIMM_SIZE) 4589399ab61SSantosh Sivaraj __dma = gen_pool_alloc_algo(ndtest_pool, size, 4599399ab61SSantosh Sivaraj gen_pool_first_fit_align, &data); 4609399ab61SSantosh Sivaraj else 4619399ab61SSantosh Sivaraj __dma = (unsigned long) buf; 4629399ab61SSantosh Sivaraj 4639399ab61SSantosh Sivaraj if (!__dma) 4649399ab61SSantosh Sivaraj goto buf_err; 4659399ab61SSantosh Sivaraj 4669399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->list); 4679399ab61SSantosh Sivaraj res->dev = &p->pdev.dev; 4689399ab61SSantosh Sivaraj res->buf = buf; 4699399ab61SSantosh Sivaraj res->res.start = __dma; 4709399ab61SSantosh Sivaraj res->res.end = __dma + size - 1; 4719399ab61SSantosh Sivaraj res->res.name = "NFIT"; 4729399ab61SSantosh Sivaraj spin_lock_init(&res->lock); 4739399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->requests); 4749399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 4759399ab61SSantosh Sivaraj list_add(&res->list, &p->resources); 4769399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 4779399ab61SSantosh Sivaraj 4789399ab61SSantosh Sivaraj if (dma) 4799399ab61SSantosh Sivaraj *dma = __dma; 4809399ab61SSantosh Sivaraj 4819399ab61SSantosh Sivaraj if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res)) 4829399ab61SSantosh Sivaraj return res->buf; 4839399ab61SSantosh Sivaraj 4849399ab61SSantosh Sivaraj buf_err: 4859399ab61SSantosh Sivaraj if (__dma && size >= DIMM_SIZE) 4869399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, __dma, size); 4879399ab61SSantosh Sivaraj if (buf) 4889399ab61SSantosh Sivaraj vfree(buf); 4899399ab61SSantosh Sivaraj kfree(res); 4909399ab61SSantosh Sivaraj 4919399ab61SSantosh Sivaraj return NULL; 4929399ab61SSantosh Sivaraj } 4939399ab61SSantosh Sivaraj 4946fde2d4cSSantosh Sivaraj static ssize_t range_index_show(struct device *dev, 4956fde2d4cSSantosh Sivaraj struct device_attribute *attr, char *buf) 4966fde2d4cSSantosh Sivaraj { 4976fde2d4cSSantosh Sivaraj struct nd_region *nd_region = to_nd_region(dev); 4986fde2d4cSSantosh Sivaraj struct ndtest_region *region = nd_region_provider_data(nd_region); 4996fde2d4cSSantosh Sivaraj 5006fde2d4cSSantosh Sivaraj return sprintf(buf, "%d\n", region->range_index); 5016fde2d4cSSantosh Sivaraj } 5026fde2d4cSSantosh Sivaraj static DEVICE_ATTR_RO(range_index); 5036fde2d4cSSantosh Sivaraj 5046fde2d4cSSantosh Sivaraj static struct attribute *ndtest_region_attributes[] = { 5056fde2d4cSSantosh Sivaraj &dev_attr_range_index.attr, 5066fde2d4cSSantosh Sivaraj NULL, 5076fde2d4cSSantosh Sivaraj }; 5086fde2d4cSSantosh Sivaraj 5096fde2d4cSSantosh Sivaraj static const struct attribute_group ndtest_region_attribute_group = { 5106fde2d4cSSantosh Sivaraj .name = "papr", 5116fde2d4cSSantosh Sivaraj .attrs = ndtest_region_attributes, 5126fde2d4cSSantosh Sivaraj }; 5136fde2d4cSSantosh Sivaraj 5146fde2d4cSSantosh Sivaraj static const struct attribute_group *ndtest_region_attribute_groups[] = { 5156fde2d4cSSantosh Sivaraj &ndtest_region_attribute_group, 5166fde2d4cSSantosh Sivaraj NULL, 5176fde2d4cSSantosh Sivaraj }; 5186fde2d4cSSantosh Sivaraj 5196fde2d4cSSantosh Sivaraj static int ndtest_create_region(struct ndtest_priv *p, 5206fde2d4cSSantosh Sivaraj struct ndtest_region *region) 5216fde2d4cSSantosh Sivaraj { 5226fde2d4cSSantosh Sivaraj struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING]; 5236fde2d4cSSantosh Sivaraj struct nd_blk_region_desc ndbr_desc; 5246fde2d4cSSantosh Sivaraj struct nd_interleave_set *nd_set; 5256fde2d4cSSantosh Sivaraj struct nd_region_desc *ndr_desc; 5266fde2d4cSSantosh Sivaraj struct resource res; 5276fde2d4cSSantosh Sivaraj int i, ndimm = region->mapping[0].dimm; 5286fde2d4cSSantosh Sivaraj u64 uuid[2]; 5296fde2d4cSSantosh Sivaraj 5306fde2d4cSSantosh Sivaraj memset(&res, 0, sizeof(res)); 5316fde2d4cSSantosh Sivaraj memset(&mappings, 0, sizeof(mappings)); 5326fde2d4cSSantosh Sivaraj memset(&ndbr_desc, 0, sizeof(ndbr_desc)); 5336fde2d4cSSantosh Sivaraj ndr_desc = &ndbr_desc.ndr_desc; 5346fde2d4cSSantosh Sivaraj 5356fde2d4cSSantosh Sivaraj if (!ndtest_alloc_resource(p, region->size, &res.start)) 5366fde2d4cSSantosh Sivaraj return -ENOMEM; 5376fde2d4cSSantosh Sivaraj 5386fde2d4cSSantosh Sivaraj res.end = res.start + region->size - 1; 5396fde2d4cSSantosh Sivaraj ndr_desc->mapping = mappings; 5406fde2d4cSSantosh Sivaraj ndr_desc->res = &res; 5416fde2d4cSSantosh Sivaraj ndr_desc->provider_data = region; 5426fde2d4cSSantosh Sivaraj ndr_desc->attr_groups = ndtest_region_attribute_groups; 5436fde2d4cSSantosh Sivaraj 5446fde2d4cSSantosh Sivaraj if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) { 5456fde2d4cSSantosh Sivaraj pr_err("failed to parse UUID\n"); 5466fde2d4cSSantosh Sivaraj return -ENXIO; 5476fde2d4cSSantosh Sivaraj } 5486fde2d4cSSantosh Sivaraj 5496fde2d4cSSantosh Sivaraj nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL); 5506fde2d4cSSantosh Sivaraj if (!nd_set) 5516fde2d4cSSantosh Sivaraj return -ENOMEM; 5526fde2d4cSSantosh Sivaraj 5536fde2d4cSSantosh Sivaraj nd_set->cookie1 = cpu_to_le64(uuid[0]); 5546fde2d4cSSantosh Sivaraj nd_set->cookie2 = cpu_to_le64(uuid[1]); 5556fde2d4cSSantosh Sivaraj nd_set->altcookie = nd_set->cookie1; 5566fde2d4cSSantosh Sivaraj ndr_desc->nd_set = nd_set; 5576fde2d4cSSantosh Sivaraj 5586fde2d4cSSantosh Sivaraj if (region->type == ND_DEVICE_NAMESPACE_BLK) { 5596fde2d4cSSantosh Sivaraj mappings[0].start = 0; 5606fde2d4cSSantosh Sivaraj mappings[0].size = DIMM_SIZE; 5616fde2d4cSSantosh Sivaraj mappings[0].nvdimm = p->config->dimms[ndimm].nvdimm; 5626fde2d4cSSantosh Sivaraj 5636fde2d4cSSantosh Sivaraj ndr_desc->mapping = &mappings[0]; 5646fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = 1; 5656fde2d4cSSantosh Sivaraj ndr_desc->num_lanes = 1; 5666fde2d4cSSantosh Sivaraj ndbr_desc.enable = ndtest_blk_region_enable; 5676fde2d4cSSantosh Sivaraj ndbr_desc.do_io = ndtest_blk_do_io; 5686fde2d4cSSantosh Sivaraj region->region = nvdimm_blk_region_create(p->bus, ndr_desc); 5696fde2d4cSSantosh Sivaraj 5706fde2d4cSSantosh Sivaraj goto done; 5716fde2d4cSSantosh Sivaraj } 5726fde2d4cSSantosh Sivaraj 5736fde2d4cSSantosh Sivaraj for (i = 0; i < region->num_mappings; i++) { 5746fde2d4cSSantosh Sivaraj ndimm = region->mapping[i].dimm; 5756fde2d4cSSantosh Sivaraj mappings[i].start = region->mapping[i].start; 5766fde2d4cSSantosh Sivaraj mappings[i].size = region->mapping[i].size; 5776fde2d4cSSantosh Sivaraj mappings[i].position = region->mapping[i].position; 5786fde2d4cSSantosh Sivaraj mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm; 5796fde2d4cSSantosh Sivaraj } 5806fde2d4cSSantosh Sivaraj 5816fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = region->num_mappings; 5826fde2d4cSSantosh Sivaraj region->region = nvdimm_pmem_region_create(p->bus, ndr_desc); 5836fde2d4cSSantosh Sivaraj 5846fde2d4cSSantosh Sivaraj done: 5856fde2d4cSSantosh Sivaraj if (!region->region) { 5866fde2d4cSSantosh Sivaraj dev_err(&p->pdev.dev, "Error registering region %pR\n", 5876fde2d4cSSantosh Sivaraj ndr_desc->res); 5886fde2d4cSSantosh Sivaraj return -ENXIO; 5896fde2d4cSSantosh Sivaraj } 5906fde2d4cSSantosh Sivaraj 5916fde2d4cSSantosh Sivaraj return 0; 5926fde2d4cSSantosh Sivaraj } 5936fde2d4cSSantosh Sivaraj 5946fde2d4cSSantosh Sivaraj static int ndtest_init_regions(struct ndtest_priv *p) 5956fde2d4cSSantosh Sivaraj { 5966fde2d4cSSantosh Sivaraj int i, ret = 0; 5976fde2d4cSSantosh Sivaraj 5986fde2d4cSSantosh Sivaraj for (i = 0; i < p->config->num_regions; i++) { 5996fde2d4cSSantosh Sivaraj ret = ndtest_create_region(p, &p->config->regions[i]); 6006fde2d4cSSantosh Sivaraj if (ret) 6016fde2d4cSSantosh Sivaraj return ret; 6026fde2d4cSSantosh Sivaraj } 6036fde2d4cSSantosh Sivaraj 6046fde2d4cSSantosh Sivaraj return 0; 6056fde2d4cSSantosh Sivaraj } 6066fde2d4cSSantosh Sivaraj 6079399ab61SSantosh Sivaraj static void put_dimms(void *data) 6089399ab61SSantosh Sivaraj { 6099399ab61SSantosh Sivaraj struct ndtest_priv *p = data; 6109399ab61SSantosh Sivaraj int i; 6119399ab61SSantosh Sivaraj 6129399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) 6139399ab61SSantosh Sivaraj if (p->config->dimms[i].dev) { 6149399ab61SSantosh Sivaraj device_unregister(p->config->dimms[i].dev); 6159399ab61SSantosh Sivaraj p->config->dimms[i].dev = NULL; 6169399ab61SSantosh Sivaraj } 6179399ab61SSantosh Sivaraj } 6189399ab61SSantosh Sivaraj 6195e41396fSSantosh Sivaraj static ssize_t handle_show(struct device *dev, struct device_attribute *attr, 6205e41396fSSantosh Sivaraj char *buf) 6215e41396fSSantosh Sivaraj { 6225e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6235e41396fSSantosh Sivaraj 6245e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 6255e41396fSSantosh Sivaraj } 6265e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(handle); 6275e41396fSSantosh Sivaraj 6285e41396fSSantosh Sivaraj static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 6295e41396fSSantosh Sivaraj char *buf) 6305e41396fSSantosh Sivaraj { 6315e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6325e41396fSSantosh Sivaraj 6335e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->fail_cmd); 6345e41396fSSantosh Sivaraj } 6355e41396fSSantosh Sivaraj 6365e41396fSSantosh Sivaraj static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 6375e41396fSSantosh Sivaraj const char *buf, size_t size) 6385e41396fSSantosh Sivaraj { 6395e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6405e41396fSSantosh Sivaraj unsigned long val; 6415e41396fSSantosh Sivaraj ssize_t rc; 6425e41396fSSantosh Sivaraj 6435e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 6445e41396fSSantosh Sivaraj if (rc) 6455e41396fSSantosh Sivaraj return rc; 6465e41396fSSantosh Sivaraj 6475e41396fSSantosh Sivaraj dimm->fail_cmd = val; 6485e41396fSSantosh Sivaraj 6495e41396fSSantosh Sivaraj return size; 6505e41396fSSantosh Sivaraj } 6515e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd); 6525e41396fSSantosh Sivaraj 6535e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 6545e41396fSSantosh Sivaraj char *buf) 6555e41396fSSantosh Sivaraj { 6565e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6575e41396fSSantosh Sivaraj 6585e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->fail_cmd_code); 6595e41396fSSantosh Sivaraj } 6605e41396fSSantosh Sivaraj 6615e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 6625e41396fSSantosh Sivaraj const char *buf, size_t size) 6635e41396fSSantosh Sivaraj { 6645e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6655e41396fSSantosh Sivaraj unsigned long val; 6665e41396fSSantosh Sivaraj ssize_t rc; 6675e41396fSSantosh Sivaraj 6685e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 6695e41396fSSantosh Sivaraj if (rc) 6705e41396fSSantosh Sivaraj return rc; 6715e41396fSSantosh Sivaraj 6725e41396fSSantosh Sivaraj dimm->fail_cmd_code = val; 6735e41396fSSantosh Sivaraj return size; 6745e41396fSSantosh Sivaraj } 6755e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd_code); 6765e41396fSSantosh Sivaraj 6775e41396fSSantosh Sivaraj static struct attribute *dimm_attributes[] = { 6785e41396fSSantosh Sivaraj &dev_attr_handle.attr, 6795e41396fSSantosh Sivaraj &dev_attr_fail_cmd.attr, 6805e41396fSSantosh Sivaraj &dev_attr_fail_cmd_code.attr, 6815e41396fSSantosh Sivaraj NULL, 6825e41396fSSantosh Sivaraj }; 6835e41396fSSantosh Sivaraj 6845e41396fSSantosh Sivaraj static struct attribute_group dimm_attribute_group = { 6855e41396fSSantosh Sivaraj .attrs = dimm_attributes, 6865e41396fSSantosh Sivaraj }; 6875e41396fSSantosh Sivaraj 6885e41396fSSantosh Sivaraj static const struct attribute_group *dimm_attribute_groups[] = { 6895e41396fSSantosh Sivaraj &dimm_attribute_group, 6905e41396fSSantosh Sivaraj NULL, 6915e41396fSSantosh Sivaraj }; 6925e41396fSSantosh Sivaraj 6935e41396fSSantosh Sivaraj static ssize_t phys_id_show(struct device *dev, 6945e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6955e41396fSSantosh Sivaraj { 6965e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6975e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6985e41396fSSantosh Sivaraj 6995e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->physical_id); 7005e41396fSSantosh Sivaraj } 7015e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(phys_id); 7025e41396fSSantosh Sivaraj 7035e41396fSSantosh Sivaraj static ssize_t vendor_show(struct device *dev, 7045e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7055e41396fSSantosh Sivaraj { 7065e41396fSSantosh Sivaraj return sprintf(buf, "0x1234567\n"); 7075e41396fSSantosh Sivaraj } 7085e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(vendor); 7095e41396fSSantosh Sivaraj 7105e41396fSSantosh Sivaraj static ssize_t id_show(struct device *dev, 7115e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7125e41396fSSantosh Sivaraj { 7135e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7145e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7155e41396fSSantosh Sivaraj 7165e41396fSSantosh Sivaraj return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd, 7175e41396fSSantosh Sivaraj 0xa, 2016, ~(dimm->handle)); 7185e41396fSSantosh Sivaraj } 7195e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(id); 7205e41396fSSantosh Sivaraj 7215e41396fSSantosh Sivaraj static ssize_t nvdimm_handle_show(struct device *dev, 7225e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7235e41396fSSantosh Sivaraj { 7245e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7255e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7265e41396fSSantosh Sivaraj 7275e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 7285e41396fSSantosh Sivaraj } 7295e41396fSSantosh Sivaraj 7305e41396fSSantosh Sivaraj static struct device_attribute dev_attr_nvdimm_show_handle = { 7315e41396fSSantosh Sivaraj .attr = { .name = "handle", .mode = 0444 }, 7325e41396fSSantosh Sivaraj .show = nvdimm_handle_show, 7335e41396fSSantosh Sivaraj }; 7345e41396fSSantosh Sivaraj 7355e41396fSSantosh Sivaraj static ssize_t subsystem_vendor_show(struct device *dev, 7365e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7375e41396fSSantosh Sivaraj { 7385e41396fSSantosh Sivaraj return sprintf(buf, "0x%04x\n", 0); 7395e41396fSSantosh Sivaraj } 7405e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(subsystem_vendor); 7415e41396fSSantosh Sivaraj 7425e41396fSSantosh Sivaraj static ssize_t dirty_shutdown_show(struct device *dev, 7435e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7445e41396fSSantosh Sivaraj { 7455e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", 42); 7465e41396fSSantosh Sivaraj } 7475e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(dirty_shutdown); 7485e41396fSSantosh Sivaraj 7495e41396fSSantosh Sivaraj static ssize_t formats_show(struct device *dev, 7505e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7515e41396fSSantosh Sivaraj { 7525e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7535e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7545e41396fSSantosh Sivaraj 7555e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->num_formats); 7565e41396fSSantosh Sivaraj } 7575e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(formats); 7585e41396fSSantosh Sivaraj 7595e41396fSSantosh Sivaraj static ssize_t format_show(struct device *dev, 7605e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7615e41396fSSantosh Sivaraj { 7625e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7635e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7645e41396fSSantosh Sivaraj 7655e41396fSSantosh Sivaraj if (dimm->num_formats > 1) 7665e41396fSSantosh Sivaraj return sprintf(buf, "0x201\n"); 7675e41396fSSantosh Sivaraj 7685e41396fSSantosh Sivaraj return sprintf(buf, "0x101\n"); 7695e41396fSSantosh Sivaraj } 7705e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format); 7715e41396fSSantosh Sivaraj 7725e41396fSSantosh Sivaraj static ssize_t format1_show(struct device *dev, struct device_attribute *attr, 7735e41396fSSantosh Sivaraj char *buf) 7745e41396fSSantosh Sivaraj { 7755e41396fSSantosh Sivaraj return sprintf(buf, "0x301\n"); 7765e41396fSSantosh Sivaraj } 7775e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format1); 7785e41396fSSantosh Sivaraj 7795e41396fSSantosh Sivaraj static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj, 7805e41396fSSantosh Sivaraj struct attribute *a, int n) 7815e41396fSSantosh Sivaraj { 7825e41396fSSantosh Sivaraj struct device *dev = container_of(kobj, struct device, kobj); 7835e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7845e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7855e41396fSSantosh Sivaraj 7865e41396fSSantosh Sivaraj if (a == &dev_attr_format1.attr && dimm->num_formats <= 1) 7875e41396fSSantosh Sivaraj return 0; 7885e41396fSSantosh Sivaraj 7895e41396fSSantosh Sivaraj return a->mode; 7905e41396fSSantosh Sivaraj } 7915e41396fSSantosh Sivaraj 7925e41396fSSantosh Sivaraj static struct attribute *ndtest_nvdimm_attributes[] = { 7935e41396fSSantosh Sivaraj &dev_attr_nvdimm_show_handle.attr, 7945e41396fSSantosh Sivaraj &dev_attr_vendor.attr, 7955e41396fSSantosh Sivaraj &dev_attr_id.attr, 7965e41396fSSantosh Sivaraj &dev_attr_phys_id.attr, 7975e41396fSSantosh Sivaraj &dev_attr_subsystem_vendor.attr, 7985e41396fSSantosh Sivaraj &dev_attr_dirty_shutdown.attr, 7995e41396fSSantosh Sivaraj &dev_attr_formats.attr, 8005e41396fSSantosh Sivaraj &dev_attr_format.attr, 8015e41396fSSantosh Sivaraj &dev_attr_format1.attr, 8025e41396fSSantosh Sivaraj NULL, 8035e41396fSSantosh Sivaraj }; 8045e41396fSSantosh Sivaraj 8055e41396fSSantosh Sivaraj static const struct attribute_group ndtest_nvdimm_attribute_group = { 8065e41396fSSantosh Sivaraj .name = "papr", 8075e41396fSSantosh Sivaraj .attrs = ndtest_nvdimm_attributes, 8085e41396fSSantosh Sivaraj .is_visible = ndtest_nvdimm_attr_visible, 8095e41396fSSantosh Sivaraj }; 8105e41396fSSantosh Sivaraj 8115e41396fSSantosh Sivaraj static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = { 8125e41396fSSantosh Sivaraj &ndtest_nvdimm_attribute_group, 8135e41396fSSantosh Sivaraj NULL, 8145e41396fSSantosh Sivaraj }; 8155e41396fSSantosh Sivaraj 8169399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv, 8179399ab61SSantosh Sivaraj struct ndtest_dimm *dimm, int id) 8189399ab61SSantosh Sivaraj { 8199399ab61SSantosh Sivaraj struct device *dev = &priv->pdev.dev; 8209399ab61SSantosh Sivaraj unsigned long dimm_flags = dimm->flags; 8219399ab61SSantosh Sivaraj 8229399ab61SSantosh Sivaraj if (dimm->num_formats > 1) { 8239399ab61SSantosh Sivaraj set_bit(NDD_ALIASING, &dimm_flags); 8249399ab61SSantosh Sivaraj set_bit(NDD_LABELING, &dimm_flags); 8259399ab61SSantosh Sivaraj } 8269399ab61SSantosh Sivaraj 8275e41396fSSantosh Sivaraj dimm->nvdimm = nvdimm_create(priv->bus, dimm, 8285e41396fSSantosh Sivaraj ndtest_nvdimm_attribute_groups, dimm_flags, 8299399ab61SSantosh Sivaraj NDTEST_SCM_DIMM_CMD_MASK, 0, NULL); 8309399ab61SSantosh Sivaraj if (!dimm->nvdimm) { 8319399ab61SSantosh Sivaraj dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn); 8329399ab61SSantosh Sivaraj return -ENXIO; 8339399ab61SSantosh Sivaraj } 8349399ab61SSantosh Sivaraj 8359399ab61SSantosh Sivaraj dimm->dev = device_create_with_groups(ndtest_dimm_class, 8369399ab61SSantosh Sivaraj &priv->pdev.dev, 8375e41396fSSantosh Sivaraj 0, dimm, dimm_attribute_groups, 8389399ab61SSantosh Sivaraj "test_dimm%d", id); 8399399ab61SSantosh Sivaraj if (!dimm->dev) { 8409399ab61SSantosh Sivaraj pr_err("Could not create dimm device attributes\n"); 8419399ab61SSantosh Sivaraj return -ENOMEM; 8429399ab61SSantosh Sivaraj } 8439399ab61SSantosh Sivaraj 8449399ab61SSantosh Sivaraj return 0; 8459399ab61SSantosh Sivaraj } 8469399ab61SSantosh Sivaraj 8479399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p) 8489399ab61SSantosh Sivaraj { 8499399ab61SSantosh Sivaraj struct ndtest_dimm *d; 8509399ab61SSantosh Sivaraj void *res; 8519399ab61SSantosh Sivaraj int i, id; 8529399ab61SSantosh Sivaraj 8539399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) { 8549399ab61SSantosh Sivaraj d = &p->config->dimms[i]; 8559399ab61SSantosh Sivaraj d->id = id = p->config->dimm_start + i; 8569399ab61SSantosh Sivaraj res = ndtest_alloc_resource(p, LABEL_SIZE, NULL); 8579399ab61SSantosh Sivaraj if (!res) 8589399ab61SSantosh Sivaraj return -ENOMEM; 8599399ab61SSantosh Sivaraj 8609399ab61SSantosh Sivaraj d->label_area = res; 8619399ab61SSantosh Sivaraj sprintf(d->label_area, "label%d", id); 8629399ab61SSantosh Sivaraj d->config_size = LABEL_SIZE; 8639399ab61SSantosh Sivaraj 8649399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, d->size, 8659399ab61SSantosh Sivaraj &p->dimm_dma[id])) 8669399ab61SSantosh Sivaraj return -ENOMEM; 8679399ab61SSantosh Sivaraj 8689399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8699399ab61SSantosh Sivaraj &p->label_dma[id])) 8709399ab61SSantosh Sivaraj return -ENOMEM; 8719399ab61SSantosh Sivaraj 8729399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8739399ab61SSantosh Sivaraj &p->dcr_dma[id])) 8749399ab61SSantosh Sivaraj return -ENOMEM; 8759399ab61SSantosh Sivaraj 8769399ab61SSantosh Sivaraj d->address = p->dimm_dma[id]; 8779399ab61SSantosh Sivaraj 8789399ab61SSantosh Sivaraj ndtest_dimm_register(p, d, id); 8799399ab61SSantosh Sivaraj } 8809399ab61SSantosh Sivaraj 8819399ab61SSantosh Sivaraj return 0; 8829399ab61SSantosh Sivaraj } 8839399ab61SSantosh Sivaraj 884107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev, 885107b04e9SSantosh Sivaraj struct device_attribute *attr, char *buf) 886107b04e9SSantosh Sivaraj { 887107b04e9SSantosh Sivaraj return sprintf(buf, "nvdimm_test"); 888107b04e9SSantosh Sivaraj } 889107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible); 890107b04e9SSantosh Sivaraj 891107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = { 892107b04e9SSantosh Sivaraj &dev_attr_compatible.attr, 893107b04e9SSantosh Sivaraj NULL 894107b04e9SSantosh Sivaraj }; 895107b04e9SSantosh Sivaraj 896107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = { 897107b04e9SSantosh Sivaraj .name = "of_node", 898107b04e9SSantosh Sivaraj .attrs = of_node_attributes, 899107b04e9SSantosh Sivaraj }; 900107b04e9SSantosh Sivaraj 901107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = { 902107b04e9SSantosh Sivaraj &of_node_attribute_group, 903107b04e9SSantosh Sivaraj NULL, 904107b04e9SSantosh Sivaraj }; 905107b04e9SSantosh Sivaraj 9069a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p) 9079a27e109SSantosh Sivaraj { 9089399ab61SSantosh Sivaraj p->config = &bus_configs[p->pdev.id]; 9099399ab61SSantosh Sivaraj 9109a27e109SSantosh Sivaraj p->bus_desc.ndctl = ndtest_ctl; 9119a27e109SSantosh Sivaraj p->bus_desc.module = THIS_MODULE; 9129a27e109SSantosh Sivaraj p->bus_desc.provider_name = NULL; 913107b04e9SSantosh Sivaraj p->bus_desc.attr_groups = ndtest_attribute_groups; 9149a27e109SSantosh Sivaraj 9159a27e109SSantosh Sivaraj p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 9169a27e109SSantosh Sivaraj if (!p->bus) { 9179a27e109SSantosh Sivaraj dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 9189a27e109SSantosh Sivaraj return -ENOMEM; 9199a27e109SSantosh Sivaraj } 9209a27e109SSantosh Sivaraj 9219a27e109SSantosh Sivaraj return 0; 9229a27e109SSantosh Sivaraj } 9239a27e109SSantosh Sivaraj 9249a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev) 9259a27e109SSantosh Sivaraj { 9269a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 9279a27e109SSantosh Sivaraj 9289a27e109SSantosh Sivaraj nvdimm_bus_unregister(p->bus); 9299a27e109SSantosh Sivaraj return 0; 9309a27e109SSantosh Sivaraj } 9319a27e109SSantosh Sivaraj 9329a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev) 9339a27e109SSantosh Sivaraj { 9349a27e109SSantosh Sivaraj struct ndtest_priv *p; 9359399ab61SSantosh Sivaraj int rc; 9369a27e109SSantosh Sivaraj 9379a27e109SSantosh Sivaraj p = to_ndtest_priv(&pdev->dev); 9389a27e109SSantosh Sivaraj if (ndtest_bus_register(p)) 9399a27e109SSantosh Sivaraj return -ENOMEM; 9409a27e109SSantosh Sivaraj 9419399ab61SSantosh Sivaraj p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9429399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9439399ab61SSantosh Sivaraj p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9449399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9459399ab61SSantosh Sivaraj p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 9469399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 9479399ab61SSantosh Sivaraj 9489399ab61SSantosh Sivaraj rc = ndtest_nvdimm_init(p); 9499399ab61SSantosh Sivaraj if (rc) 9509399ab61SSantosh Sivaraj goto err; 9519399ab61SSantosh Sivaraj 9526fde2d4cSSantosh Sivaraj rc = ndtest_init_regions(p); 9536fde2d4cSSantosh Sivaraj if (rc) 9546fde2d4cSSantosh Sivaraj goto err; 9556fde2d4cSSantosh Sivaraj 9569399ab61SSantosh Sivaraj rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p); 9579399ab61SSantosh Sivaraj if (rc) 9589399ab61SSantosh Sivaraj goto err; 9599399ab61SSantosh Sivaraj 9609a27e109SSantosh Sivaraj platform_set_drvdata(pdev, p); 9619a27e109SSantosh Sivaraj 9629a27e109SSantosh Sivaraj return 0; 9639399ab61SSantosh Sivaraj 9649399ab61SSantosh Sivaraj err: 9659399ab61SSantosh Sivaraj pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__); 9669399ab61SSantosh Sivaraj return rc; 9679a27e109SSantosh Sivaraj } 9689a27e109SSantosh Sivaraj 9699a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = { 9709a27e109SSantosh Sivaraj { KBUILD_MODNAME }, 9719a27e109SSantosh Sivaraj { }, 9729a27e109SSantosh Sivaraj }; 9739a27e109SSantosh Sivaraj 9749a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = { 9759a27e109SSantosh Sivaraj .probe = ndtest_probe, 9769a27e109SSantosh Sivaraj .remove = ndtest_remove, 9779a27e109SSantosh Sivaraj .driver = { 9789a27e109SSantosh Sivaraj .name = KBUILD_MODNAME, 9799a27e109SSantosh Sivaraj }, 9809a27e109SSantosh Sivaraj .id_table = ndtest_id, 9819a27e109SSantosh Sivaraj }; 9829a27e109SSantosh Sivaraj 9839a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev) 9849a27e109SSantosh Sivaraj { 9859a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(dev); 9869a27e109SSantosh Sivaraj 9879a27e109SSantosh Sivaraj kfree(p); 9889a27e109SSantosh Sivaraj } 9899a27e109SSantosh Sivaraj 9909a27e109SSantosh Sivaraj static void cleanup_devices(void) 9919a27e109SSantosh Sivaraj { 9929a27e109SSantosh Sivaraj int i; 9939a27e109SSantosh Sivaraj 9949a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) 9959a27e109SSantosh Sivaraj if (instances[i]) 9969a27e109SSantosh Sivaraj platform_device_unregister(&instances[i]->pdev); 9979a27e109SSantosh Sivaraj 9989a27e109SSantosh Sivaraj nfit_test_teardown(); 9999a27e109SSantosh Sivaraj 10009399ab61SSantosh Sivaraj if (ndtest_pool) 10019399ab61SSantosh Sivaraj gen_pool_destroy(ndtest_pool); 10029399ab61SSantosh Sivaraj 10039399ab61SSantosh Sivaraj 10049a27e109SSantosh Sivaraj if (ndtest_dimm_class) 10059a27e109SSantosh Sivaraj class_destroy(ndtest_dimm_class); 10069a27e109SSantosh Sivaraj } 10079a27e109SSantosh Sivaraj 10089a27e109SSantosh Sivaraj static __init int ndtest_init(void) 10099a27e109SSantosh Sivaraj { 10109a27e109SSantosh Sivaraj int rc, i; 10119a27e109SSantosh Sivaraj 10129a27e109SSantosh Sivaraj pmem_test(); 10139a27e109SSantosh Sivaraj libnvdimm_test(); 10149a27e109SSantosh Sivaraj device_dax_test(); 10159a27e109SSantosh Sivaraj dax_pmem_test(); 10169a27e109SSantosh Sivaraj dax_pmem_core_test(); 10179a27e109SSantosh Sivaraj #ifdef CONFIG_DEV_DAX_PMEM_COMPAT 10189a27e109SSantosh Sivaraj dax_pmem_compat_test(); 10199a27e109SSantosh Sivaraj #endif 10209a27e109SSantosh Sivaraj 10216fde2d4cSSantosh Sivaraj nfit_test_setup(ndtest_resource_lookup, NULL); 10226fde2d4cSSantosh Sivaraj 10239a27e109SSantosh Sivaraj ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm"); 10249a27e109SSantosh Sivaraj if (IS_ERR(ndtest_dimm_class)) { 10259a27e109SSantosh Sivaraj rc = PTR_ERR(ndtest_dimm_class); 10269a27e109SSantosh Sivaraj goto err_register; 10279a27e109SSantosh Sivaraj } 10289a27e109SSantosh Sivaraj 10299399ab61SSantosh Sivaraj ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 10309399ab61SSantosh Sivaraj if (!ndtest_pool) { 10319399ab61SSantosh Sivaraj rc = -ENOMEM; 10329399ab61SSantosh Sivaraj goto err_register; 10339399ab61SSantosh Sivaraj } 10349399ab61SSantosh Sivaraj 10359399ab61SSantosh Sivaraj if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 10369399ab61SSantosh Sivaraj rc = -ENOMEM; 10379399ab61SSantosh Sivaraj goto err_register; 10389399ab61SSantosh Sivaraj } 10399399ab61SSantosh Sivaraj 10409a27e109SSantosh Sivaraj /* Each instance can be taken as a bus, which can have multiple dimms */ 10419a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 10429a27e109SSantosh Sivaraj struct ndtest_priv *priv; 10439a27e109SSantosh Sivaraj struct platform_device *pdev; 10449a27e109SSantosh Sivaraj 10459a27e109SSantosh Sivaraj priv = kzalloc(sizeof(*priv), GFP_KERNEL); 10469a27e109SSantosh Sivaraj if (!priv) { 10479a27e109SSantosh Sivaraj rc = -ENOMEM; 10489a27e109SSantosh Sivaraj goto err_register; 10499a27e109SSantosh Sivaraj } 10509a27e109SSantosh Sivaraj 10519a27e109SSantosh Sivaraj INIT_LIST_HEAD(&priv->resources); 10529a27e109SSantosh Sivaraj pdev = &priv->pdev; 10539a27e109SSantosh Sivaraj pdev->name = KBUILD_MODNAME; 10549a27e109SSantosh Sivaraj pdev->id = i; 10559a27e109SSantosh Sivaraj pdev->dev.release = ndtest_release; 10569a27e109SSantosh Sivaraj rc = platform_device_register(pdev); 10579a27e109SSantosh Sivaraj if (rc) { 10589a27e109SSantosh Sivaraj put_device(&pdev->dev); 10599a27e109SSantosh Sivaraj goto err_register; 10609a27e109SSantosh Sivaraj } 10619a27e109SSantosh Sivaraj get_device(&pdev->dev); 10629a27e109SSantosh Sivaraj 10639a27e109SSantosh Sivaraj instances[i] = priv; 10649a27e109SSantosh Sivaraj } 10659a27e109SSantosh Sivaraj 10669a27e109SSantosh Sivaraj rc = platform_driver_register(&ndtest_driver); 10679a27e109SSantosh Sivaraj if (rc) 10689a27e109SSantosh Sivaraj goto err_register; 10699a27e109SSantosh Sivaraj 10709a27e109SSantosh Sivaraj return 0; 10719a27e109SSantosh Sivaraj 10729a27e109SSantosh Sivaraj err_register: 10739a27e109SSantosh Sivaraj pr_err("Error registering platform device\n"); 10749a27e109SSantosh Sivaraj cleanup_devices(); 10759a27e109SSantosh Sivaraj 10769a27e109SSantosh Sivaraj return rc; 10779a27e109SSantosh Sivaraj } 10789a27e109SSantosh Sivaraj 10799a27e109SSantosh Sivaraj static __exit void ndtest_exit(void) 10809a27e109SSantosh Sivaraj { 10819a27e109SSantosh Sivaraj cleanup_devices(); 10829a27e109SSantosh Sivaraj platform_driver_unregister(&ndtest_driver); 10839a27e109SSantosh Sivaraj } 10849a27e109SSantosh Sivaraj 10859a27e109SSantosh Sivaraj module_init(ndtest_init); 10869a27e109SSantosh Sivaraj module_exit(ndtest_exit); 10879a27e109SSantosh Sivaraj MODULE_LICENSE("GPL"); 10889a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation"); 1089