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_region bus0_regions[] = { 1386fde2d4cSSantosh Sivaraj { 1396fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1406fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region0_mapping), 1416fde2d4cSSantosh Sivaraj .mapping = region0_mapping, 1426fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1436fde2d4cSSantosh Sivaraj .range_index = 1, 1446fde2d4cSSantosh Sivaraj }, 1456fde2d4cSSantosh Sivaraj { 1466fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 1476fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region1_mapping), 1486fde2d4cSSantosh Sivaraj .mapping = region1_mapping, 1496fde2d4cSSantosh Sivaraj .size = DIMM_SIZE * 2, 1506fde2d4cSSantosh Sivaraj .range_index = 2, 1516fde2d4cSSantosh Sivaraj }, 1526fde2d4cSSantosh Sivaraj }; 1536fde2d4cSSantosh Sivaraj 1546fde2d4cSSantosh Sivaraj static struct ndtest_mapping region6_mapping[] = { 1556fde2d4cSSantosh Sivaraj { 1566fde2d4cSSantosh Sivaraj .dimm = 0, 1576fde2d4cSSantosh Sivaraj .position = 0, 1586fde2d4cSSantosh Sivaraj .start = 0, 1596fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1606fde2d4cSSantosh Sivaraj }, 1616fde2d4cSSantosh Sivaraj }; 1626fde2d4cSSantosh Sivaraj 1636fde2d4cSSantosh Sivaraj static struct ndtest_region bus1_regions[] = { 1646fde2d4cSSantosh Sivaraj { 1656fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_IO, 1666fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region6_mapping), 1676fde2d4cSSantosh Sivaraj .mapping = region6_mapping, 1686fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 1696fde2d4cSSantosh Sivaraj .range_index = 1, 1706fde2d4cSSantosh Sivaraj }, 1716fde2d4cSSantosh Sivaraj }; 1726fde2d4cSSantosh Sivaraj 1739399ab61SSantosh Sivaraj static struct ndtest_config bus_configs[NUM_INSTANCES] = { 1749399ab61SSantosh Sivaraj /* bus 1 */ 1759399ab61SSantosh Sivaraj { 1769399ab61SSantosh Sivaraj .dimm_start = 0, 1779399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group1), 1789399ab61SSantosh Sivaraj .dimms = dimm_group1, 1796fde2d4cSSantosh Sivaraj .regions = bus0_regions, 1806fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus0_regions), 1819399ab61SSantosh Sivaraj }, 1829399ab61SSantosh Sivaraj /* bus 2 */ 1839399ab61SSantosh Sivaraj { 1849399ab61SSantosh Sivaraj .dimm_start = ARRAY_SIZE(dimm_group1), 1859399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group2), 1869399ab61SSantosh Sivaraj .dimms = dimm_group2, 1876fde2d4cSSantosh Sivaraj .regions = bus1_regions, 1886fde2d4cSSantosh Sivaraj .num_regions = ARRAY_SIZE(bus1_regions), 1899399ab61SSantosh Sivaraj }, 1909399ab61SSantosh Sivaraj }; 1919a27e109SSantosh Sivaraj 1929a27e109SSantosh Sivaraj static inline struct ndtest_priv *to_ndtest_priv(struct device *dev) 1939a27e109SSantosh Sivaraj { 1949a27e109SSantosh Sivaraj struct platform_device *pdev = to_platform_device(dev); 1959a27e109SSantosh Sivaraj 1969a27e109SSantosh Sivaraj return container_of(pdev, struct ndtest_priv, pdev); 1979a27e109SSantosh Sivaraj } 1989a27e109SSantosh Sivaraj 19914ccef10SSantosh Sivaraj static int ndtest_config_get(struct ndtest_dimm *p, unsigned int buf_len, 20014ccef10SSantosh Sivaraj struct nd_cmd_get_config_data_hdr *hdr) 20114ccef10SSantosh Sivaraj { 20214ccef10SSantosh Sivaraj unsigned int len; 20314ccef10SSantosh Sivaraj 20414ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 20514ccef10SSantosh Sivaraj return -EINVAL; 20614ccef10SSantosh Sivaraj 20714ccef10SSantosh Sivaraj hdr->status = 0; 20814ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 20914ccef10SSantosh Sivaraj memcpy(hdr->out_buf, p->label_area + hdr->in_offset, len); 21014ccef10SSantosh Sivaraj 21114ccef10SSantosh Sivaraj return buf_len - len; 21214ccef10SSantosh Sivaraj } 21314ccef10SSantosh Sivaraj 21414ccef10SSantosh Sivaraj static int ndtest_config_set(struct ndtest_dimm *p, unsigned int buf_len, 21514ccef10SSantosh Sivaraj struct nd_cmd_set_config_hdr *hdr) 21614ccef10SSantosh Sivaraj { 21714ccef10SSantosh Sivaraj unsigned int len; 21814ccef10SSantosh Sivaraj 21914ccef10SSantosh Sivaraj if ((hdr->in_offset + hdr->in_length) > LABEL_SIZE) 22014ccef10SSantosh Sivaraj return -EINVAL; 22114ccef10SSantosh Sivaraj 22214ccef10SSantosh Sivaraj len = min(hdr->in_length, LABEL_SIZE - hdr->in_offset); 22314ccef10SSantosh Sivaraj memcpy(p->label_area + hdr->in_offset, hdr->in_buf, len); 22414ccef10SSantosh Sivaraj 22514ccef10SSantosh Sivaraj return buf_len - len; 22614ccef10SSantosh Sivaraj } 22714ccef10SSantosh Sivaraj 22814ccef10SSantosh Sivaraj static int ndtest_get_config_size(struct ndtest_dimm *dimm, unsigned int buf_len, 22914ccef10SSantosh Sivaraj struct nd_cmd_get_config_size *size) 23014ccef10SSantosh Sivaraj { 23114ccef10SSantosh Sivaraj size->status = 0; 23214ccef10SSantosh Sivaraj size->max_xfer = 8; 23314ccef10SSantosh Sivaraj size->config_size = dimm->config_size; 23414ccef10SSantosh Sivaraj 23514ccef10SSantosh Sivaraj return 0; 23614ccef10SSantosh Sivaraj } 23714ccef10SSantosh Sivaraj 2389a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 2399a27e109SSantosh Sivaraj struct nvdimm *nvdimm, unsigned int cmd, void *buf, 2409a27e109SSantosh Sivaraj unsigned int buf_len, int *cmd_rc) 2419a27e109SSantosh Sivaraj { 2429a27e109SSantosh Sivaraj struct ndtest_dimm *dimm; 2439a27e109SSantosh Sivaraj int _cmd_rc; 2449a27e109SSantosh Sivaraj 2459a27e109SSantosh Sivaraj if (!cmd_rc) 2469a27e109SSantosh Sivaraj cmd_rc = &_cmd_rc; 2479a27e109SSantosh Sivaraj 2489a27e109SSantosh Sivaraj *cmd_rc = 0; 2499a27e109SSantosh Sivaraj 2509a27e109SSantosh Sivaraj if (!nvdimm) 2519a27e109SSantosh Sivaraj return -EINVAL; 2529a27e109SSantosh Sivaraj 2539a27e109SSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 2549a27e109SSantosh Sivaraj if (!dimm) 2559a27e109SSantosh Sivaraj return -EINVAL; 2569a27e109SSantosh Sivaraj 2579a27e109SSantosh Sivaraj switch (cmd) { 2589a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_SIZE: 25914ccef10SSantosh Sivaraj *cmd_rc = ndtest_get_config_size(dimm, buf_len, buf); 26014ccef10SSantosh Sivaraj break; 2619a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_DATA: 26214ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_get(dimm, buf_len, buf); 26314ccef10SSantosh Sivaraj break; 2649a27e109SSantosh Sivaraj case ND_CMD_SET_CONFIG_DATA: 26514ccef10SSantosh Sivaraj *cmd_rc = ndtest_config_set(dimm, buf_len, buf); 26614ccef10SSantosh Sivaraj break; 2679a27e109SSantosh Sivaraj default: 2689a27e109SSantosh Sivaraj return -EINVAL; 2699a27e109SSantosh Sivaraj } 2709a27e109SSantosh Sivaraj 27114ccef10SSantosh Sivaraj /* Failures for a DIMM can be injected using fail_cmd and 27214ccef10SSantosh Sivaraj * fail_cmd_code, see the device attributes below 27314ccef10SSantosh Sivaraj */ 27414ccef10SSantosh Sivaraj if ((1 << cmd) & dimm->fail_cmd) 27514ccef10SSantosh Sivaraj return dimm->fail_cmd_code ? dimm->fail_cmd_code : -EIO; 27614ccef10SSantosh Sivaraj 2779a27e109SSantosh Sivaraj return 0; 2789a27e109SSantosh Sivaraj } 2799a27e109SSantosh Sivaraj 2806fde2d4cSSantosh Sivaraj static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr) 2816fde2d4cSSantosh Sivaraj { 2826fde2d4cSSantosh Sivaraj int i; 2836fde2d4cSSantosh Sivaraj 2846fde2d4cSSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 2856fde2d4cSSantosh Sivaraj struct nfit_test_resource *n, *nfit_res = NULL; 2866fde2d4cSSantosh Sivaraj struct ndtest_priv *t = instances[i]; 2876fde2d4cSSantosh Sivaraj 2886fde2d4cSSantosh Sivaraj if (!t) 2896fde2d4cSSantosh Sivaraj continue; 2906fde2d4cSSantosh Sivaraj spin_lock(&ndtest_lock); 2916fde2d4cSSantosh Sivaraj list_for_each_entry(n, &t->resources, list) { 2926fde2d4cSSantosh Sivaraj if (addr >= n->res.start && (addr < n->res.start 2936fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 2946fde2d4cSSantosh Sivaraj nfit_res = n; 2956fde2d4cSSantosh Sivaraj break; 2966fde2d4cSSantosh Sivaraj } else if (addr >= (unsigned long) n->buf 2976fde2d4cSSantosh Sivaraj && (addr < (unsigned long) n->buf 2986fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 2996fde2d4cSSantosh Sivaraj nfit_res = n; 3006fde2d4cSSantosh Sivaraj break; 3016fde2d4cSSantosh Sivaraj } 3026fde2d4cSSantosh Sivaraj } 3036fde2d4cSSantosh Sivaraj spin_unlock(&ndtest_lock); 3046fde2d4cSSantosh Sivaraj if (nfit_res) 3056fde2d4cSSantosh Sivaraj return nfit_res; 3066fde2d4cSSantosh Sivaraj } 3076fde2d4cSSantosh Sivaraj 3086fde2d4cSSantosh Sivaraj pr_warn("Failed to get resource\n"); 3096fde2d4cSSantosh Sivaraj 3106fde2d4cSSantosh Sivaraj return NULL; 3116fde2d4cSSantosh Sivaraj } 3126fde2d4cSSantosh Sivaraj 3139399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data) 3149399ab61SSantosh Sivaraj { 3159399ab61SSantosh Sivaraj struct nfit_test_resource *res = data; 3169399ab61SSantosh Sivaraj 3179399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 3189399ab61SSantosh Sivaraj list_del(&res->list); 3199399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 3209399ab61SSantosh Sivaraj 3219399ab61SSantosh Sivaraj if (resource_size(&res->res) >= DIMM_SIZE) 3229399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, res->res.start, 3239399ab61SSantosh Sivaraj resource_size(&res->res)); 3249399ab61SSantosh Sivaraj vfree(res->buf); 3259399ab61SSantosh Sivaraj kfree(res); 3269399ab61SSantosh Sivaraj } 3279399ab61SSantosh Sivaraj 3289399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size, 3299399ab61SSantosh Sivaraj dma_addr_t *dma) 3309399ab61SSantosh Sivaraj { 3319399ab61SSantosh Sivaraj dma_addr_t __dma; 3329399ab61SSantosh Sivaraj void *buf; 3339399ab61SSantosh Sivaraj struct nfit_test_resource *res; 3349399ab61SSantosh Sivaraj struct genpool_data_align data = { 3359399ab61SSantosh Sivaraj .align = SZ_128M, 3369399ab61SSantosh Sivaraj }; 3379399ab61SSantosh Sivaraj 3389399ab61SSantosh Sivaraj res = kzalloc(sizeof(*res), GFP_KERNEL); 3399399ab61SSantosh Sivaraj if (!res) 3409399ab61SSantosh Sivaraj return NULL; 3419399ab61SSantosh Sivaraj 3429399ab61SSantosh Sivaraj buf = vmalloc(size); 3439399ab61SSantosh Sivaraj if (size >= DIMM_SIZE) 3449399ab61SSantosh Sivaraj __dma = gen_pool_alloc_algo(ndtest_pool, size, 3459399ab61SSantosh Sivaraj gen_pool_first_fit_align, &data); 3469399ab61SSantosh Sivaraj else 3479399ab61SSantosh Sivaraj __dma = (unsigned long) buf; 3489399ab61SSantosh Sivaraj 3499399ab61SSantosh Sivaraj if (!__dma) 3509399ab61SSantosh Sivaraj goto buf_err; 3519399ab61SSantosh Sivaraj 3529399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->list); 3539399ab61SSantosh Sivaraj res->dev = &p->pdev.dev; 3549399ab61SSantosh Sivaraj res->buf = buf; 3559399ab61SSantosh Sivaraj res->res.start = __dma; 3569399ab61SSantosh Sivaraj res->res.end = __dma + size - 1; 3579399ab61SSantosh Sivaraj res->res.name = "NFIT"; 3589399ab61SSantosh Sivaraj spin_lock_init(&res->lock); 3599399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->requests); 3609399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 3619399ab61SSantosh Sivaraj list_add(&res->list, &p->resources); 3629399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 3639399ab61SSantosh Sivaraj 3649399ab61SSantosh Sivaraj if (dma) 3659399ab61SSantosh Sivaraj *dma = __dma; 3669399ab61SSantosh Sivaraj 3679399ab61SSantosh Sivaraj if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res)) 3689399ab61SSantosh Sivaraj return res->buf; 3699399ab61SSantosh Sivaraj 3709399ab61SSantosh Sivaraj buf_err: 3719399ab61SSantosh Sivaraj if (__dma && size >= DIMM_SIZE) 3729399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, __dma, size); 3739399ab61SSantosh Sivaraj if (buf) 3749399ab61SSantosh Sivaraj vfree(buf); 3759399ab61SSantosh Sivaraj kfree(res); 3769399ab61SSantosh Sivaraj 3779399ab61SSantosh Sivaraj return NULL; 3789399ab61SSantosh Sivaraj } 3799399ab61SSantosh Sivaraj 3806fde2d4cSSantosh Sivaraj static ssize_t range_index_show(struct device *dev, 3816fde2d4cSSantosh Sivaraj struct device_attribute *attr, char *buf) 3826fde2d4cSSantosh Sivaraj { 3836fde2d4cSSantosh Sivaraj struct nd_region *nd_region = to_nd_region(dev); 3846fde2d4cSSantosh Sivaraj struct ndtest_region *region = nd_region_provider_data(nd_region); 3856fde2d4cSSantosh Sivaraj 3866fde2d4cSSantosh Sivaraj return sprintf(buf, "%d\n", region->range_index); 3876fde2d4cSSantosh Sivaraj } 3886fde2d4cSSantosh Sivaraj static DEVICE_ATTR_RO(range_index); 3896fde2d4cSSantosh Sivaraj 3906fde2d4cSSantosh Sivaraj static struct attribute *ndtest_region_attributes[] = { 3916fde2d4cSSantosh Sivaraj &dev_attr_range_index.attr, 3926fde2d4cSSantosh Sivaraj NULL, 3936fde2d4cSSantosh Sivaraj }; 3946fde2d4cSSantosh Sivaraj 3956fde2d4cSSantosh Sivaraj static const struct attribute_group ndtest_region_attribute_group = { 3966fde2d4cSSantosh Sivaraj .name = "papr", 3976fde2d4cSSantosh Sivaraj .attrs = ndtest_region_attributes, 3986fde2d4cSSantosh Sivaraj }; 3996fde2d4cSSantosh Sivaraj 4006fde2d4cSSantosh Sivaraj static const struct attribute_group *ndtest_region_attribute_groups[] = { 4016fde2d4cSSantosh Sivaraj &ndtest_region_attribute_group, 4026fde2d4cSSantosh Sivaraj NULL, 4036fde2d4cSSantosh Sivaraj }; 4046fde2d4cSSantosh Sivaraj 4056fde2d4cSSantosh Sivaraj static int ndtest_create_region(struct ndtest_priv *p, 4066fde2d4cSSantosh Sivaraj struct ndtest_region *region) 4076fde2d4cSSantosh Sivaraj { 4086fde2d4cSSantosh Sivaraj struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING]; 4093b6c6c03SDan Williams struct nd_region_desc *ndr_desc, _ndr_desc; 4106fde2d4cSSantosh Sivaraj struct nd_interleave_set *nd_set; 4116fde2d4cSSantosh Sivaraj struct resource res; 4126fde2d4cSSantosh Sivaraj int i, ndimm = region->mapping[0].dimm; 4136fde2d4cSSantosh Sivaraj u64 uuid[2]; 4146fde2d4cSSantosh Sivaraj 4156fde2d4cSSantosh Sivaraj memset(&res, 0, sizeof(res)); 4166fde2d4cSSantosh Sivaraj memset(&mappings, 0, sizeof(mappings)); 4173b6c6c03SDan Williams memset(&_ndr_desc, 0, sizeof(_ndr_desc)); 4183b6c6c03SDan Williams ndr_desc = &_ndr_desc; 4196fde2d4cSSantosh Sivaraj 4206fde2d4cSSantosh Sivaraj if (!ndtest_alloc_resource(p, region->size, &res.start)) 4216fde2d4cSSantosh Sivaraj return -ENOMEM; 4226fde2d4cSSantosh Sivaraj 4236fde2d4cSSantosh Sivaraj res.end = res.start + region->size - 1; 4246fde2d4cSSantosh Sivaraj ndr_desc->mapping = mappings; 4256fde2d4cSSantosh Sivaraj ndr_desc->res = &res; 4266fde2d4cSSantosh Sivaraj ndr_desc->provider_data = region; 4276fde2d4cSSantosh Sivaraj ndr_desc->attr_groups = ndtest_region_attribute_groups; 4286fde2d4cSSantosh Sivaraj 4296fde2d4cSSantosh Sivaraj if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) { 4306fde2d4cSSantosh Sivaraj pr_err("failed to parse UUID\n"); 4316fde2d4cSSantosh Sivaraj return -ENXIO; 4326fde2d4cSSantosh Sivaraj } 4336fde2d4cSSantosh Sivaraj 4346fde2d4cSSantosh Sivaraj nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL); 4356fde2d4cSSantosh Sivaraj if (!nd_set) 4366fde2d4cSSantosh Sivaraj return -ENOMEM; 4376fde2d4cSSantosh Sivaraj 4386fde2d4cSSantosh Sivaraj nd_set->cookie1 = cpu_to_le64(uuid[0]); 4396fde2d4cSSantosh Sivaraj nd_set->cookie2 = cpu_to_le64(uuid[1]); 4406fde2d4cSSantosh Sivaraj nd_set->altcookie = nd_set->cookie1; 4416fde2d4cSSantosh Sivaraj ndr_desc->nd_set = nd_set; 4426fde2d4cSSantosh Sivaraj 4436fde2d4cSSantosh Sivaraj for (i = 0; i < region->num_mappings; i++) { 4446fde2d4cSSantosh Sivaraj ndimm = region->mapping[i].dimm; 4456fde2d4cSSantosh Sivaraj mappings[i].start = region->mapping[i].start; 4466fde2d4cSSantosh Sivaraj mappings[i].size = region->mapping[i].size; 4476fde2d4cSSantosh Sivaraj mappings[i].position = region->mapping[i].position; 4486fde2d4cSSantosh Sivaraj mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm; 4496fde2d4cSSantosh Sivaraj } 4506fde2d4cSSantosh Sivaraj 4516fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = region->num_mappings; 4526fde2d4cSSantosh Sivaraj region->region = nvdimm_pmem_region_create(p->bus, ndr_desc); 4536fde2d4cSSantosh Sivaraj 4546fde2d4cSSantosh Sivaraj if (!region->region) { 4556fde2d4cSSantosh Sivaraj dev_err(&p->pdev.dev, "Error registering region %pR\n", 4566fde2d4cSSantosh Sivaraj ndr_desc->res); 4576fde2d4cSSantosh Sivaraj return -ENXIO; 4586fde2d4cSSantosh Sivaraj } 4596fde2d4cSSantosh Sivaraj 4606fde2d4cSSantosh Sivaraj return 0; 4616fde2d4cSSantosh Sivaraj } 4626fde2d4cSSantosh Sivaraj 4636fde2d4cSSantosh Sivaraj static int ndtest_init_regions(struct ndtest_priv *p) 4646fde2d4cSSantosh Sivaraj { 4656fde2d4cSSantosh Sivaraj int i, ret = 0; 4666fde2d4cSSantosh Sivaraj 4676fde2d4cSSantosh Sivaraj for (i = 0; i < p->config->num_regions; i++) { 4686fde2d4cSSantosh Sivaraj ret = ndtest_create_region(p, &p->config->regions[i]); 4696fde2d4cSSantosh Sivaraj if (ret) 4706fde2d4cSSantosh Sivaraj return ret; 4716fde2d4cSSantosh Sivaraj } 4726fde2d4cSSantosh Sivaraj 4736fde2d4cSSantosh Sivaraj return 0; 4746fde2d4cSSantosh Sivaraj } 4756fde2d4cSSantosh Sivaraj 4769399ab61SSantosh Sivaraj static void put_dimms(void *data) 4779399ab61SSantosh Sivaraj { 4789399ab61SSantosh Sivaraj struct ndtest_priv *p = data; 4799399ab61SSantosh Sivaraj int i; 4809399ab61SSantosh Sivaraj 4819399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) 4829399ab61SSantosh Sivaraj if (p->config->dimms[i].dev) { 4839399ab61SSantosh Sivaraj device_unregister(p->config->dimms[i].dev); 4849399ab61SSantosh Sivaraj p->config->dimms[i].dev = NULL; 4859399ab61SSantosh Sivaraj } 4869399ab61SSantosh Sivaraj } 4879399ab61SSantosh Sivaraj 4885e41396fSSantosh Sivaraj static ssize_t handle_show(struct device *dev, struct device_attribute *attr, 4895e41396fSSantosh Sivaraj char *buf) 4905e41396fSSantosh Sivaraj { 4915e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 4925e41396fSSantosh Sivaraj 4935e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 4945e41396fSSantosh Sivaraj } 4955e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(handle); 4965e41396fSSantosh Sivaraj 4975e41396fSSantosh Sivaraj static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 4985e41396fSSantosh Sivaraj char *buf) 4995e41396fSSantosh Sivaraj { 5005e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5015e41396fSSantosh Sivaraj 5025e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->fail_cmd); 5035e41396fSSantosh Sivaraj } 5045e41396fSSantosh Sivaraj 5055e41396fSSantosh Sivaraj static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 5065e41396fSSantosh Sivaraj const char *buf, size_t size) 5075e41396fSSantosh Sivaraj { 5085e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5095e41396fSSantosh Sivaraj unsigned long val; 5105e41396fSSantosh Sivaraj ssize_t rc; 5115e41396fSSantosh Sivaraj 5125e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 5135e41396fSSantosh Sivaraj if (rc) 5145e41396fSSantosh Sivaraj return rc; 5155e41396fSSantosh Sivaraj 5165e41396fSSantosh Sivaraj dimm->fail_cmd = val; 5175e41396fSSantosh Sivaraj 5185e41396fSSantosh Sivaraj return size; 5195e41396fSSantosh Sivaraj } 5205e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd); 5215e41396fSSantosh Sivaraj 5225e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 5235e41396fSSantosh Sivaraj char *buf) 5245e41396fSSantosh Sivaraj { 5255e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5265e41396fSSantosh Sivaraj 5275e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->fail_cmd_code); 5285e41396fSSantosh Sivaraj } 5295e41396fSSantosh Sivaraj 5305e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 5315e41396fSSantosh Sivaraj const char *buf, size_t size) 5325e41396fSSantosh Sivaraj { 5335e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5345e41396fSSantosh Sivaraj unsigned long val; 5355e41396fSSantosh Sivaraj ssize_t rc; 5365e41396fSSantosh Sivaraj 5375e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 5385e41396fSSantosh Sivaraj if (rc) 5395e41396fSSantosh Sivaraj return rc; 5405e41396fSSantosh Sivaraj 5415e41396fSSantosh Sivaraj dimm->fail_cmd_code = val; 5425e41396fSSantosh Sivaraj return size; 5435e41396fSSantosh Sivaraj } 5445e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd_code); 5455e41396fSSantosh Sivaraj 5465e41396fSSantosh Sivaraj static struct attribute *dimm_attributes[] = { 5475e41396fSSantosh Sivaraj &dev_attr_handle.attr, 5485e41396fSSantosh Sivaraj &dev_attr_fail_cmd.attr, 5495e41396fSSantosh Sivaraj &dev_attr_fail_cmd_code.attr, 5505e41396fSSantosh Sivaraj NULL, 5515e41396fSSantosh Sivaraj }; 5525e41396fSSantosh Sivaraj 5535e41396fSSantosh Sivaraj static struct attribute_group dimm_attribute_group = { 5545e41396fSSantosh Sivaraj .attrs = dimm_attributes, 5555e41396fSSantosh Sivaraj }; 5565e41396fSSantosh Sivaraj 5575e41396fSSantosh Sivaraj static const struct attribute_group *dimm_attribute_groups[] = { 5585e41396fSSantosh Sivaraj &dimm_attribute_group, 5595e41396fSSantosh Sivaraj NULL, 5605e41396fSSantosh Sivaraj }; 5615e41396fSSantosh Sivaraj 5625e41396fSSantosh Sivaraj static ssize_t phys_id_show(struct device *dev, 5635e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 5645e41396fSSantosh Sivaraj { 5655e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 5665e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 5675e41396fSSantosh Sivaraj 5685e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->physical_id); 5695e41396fSSantosh Sivaraj } 5705e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(phys_id); 5715e41396fSSantosh Sivaraj 5725e41396fSSantosh Sivaraj static ssize_t vendor_show(struct device *dev, 5735e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 5745e41396fSSantosh Sivaraj { 5755e41396fSSantosh Sivaraj return sprintf(buf, "0x1234567\n"); 5765e41396fSSantosh Sivaraj } 5775e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(vendor); 5785e41396fSSantosh Sivaraj 5795e41396fSSantosh Sivaraj static ssize_t id_show(struct device *dev, 5805e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 5815e41396fSSantosh Sivaraj { 5825e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 5835e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 5845e41396fSSantosh Sivaraj 5855e41396fSSantosh Sivaraj return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd, 5865e41396fSSantosh Sivaraj 0xa, 2016, ~(dimm->handle)); 5875e41396fSSantosh Sivaraj } 5885e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(id); 5895e41396fSSantosh Sivaraj 5905e41396fSSantosh Sivaraj static ssize_t nvdimm_handle_show(struct device *dev, 5915e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 5925e41396fSSantosh Sivaraj { 5935e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 5945e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 5955e41396fSSantosh Sivaraj 5965e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 5975e41396fSSantosh Sivaraj } 5985e41396fSSantosh Sivaraj 5995e41396fSSantosh Sivaraj static struct device_attribute dev_attr_nvdimm_show_handle = { 6005e41396fSSantosh Sivaraj .attr = { .name = "handle", .mode = 0444 }, 6015e41396fSSantosh Sivaraj .show = nvdimm_handle_show, 6025e41396fSSantosh Sivaraj }; 6035e41396fSSantosh Sivaraj 6045e41396fSSantosh Sivaraj static ssize_t subsystem_vendor_show(struct device *dev, 6055e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6065e41396fSSantosh Sivaraj { 6075e41396fSSantosh Sivaraj return sprintf(buf, "0x%04x\n", 0); 6085e41396fSSantosh Sivaraj } 6095e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(subsystem_vendor); 6105e41396fSSantosh Sivaraj 6115e41396fSSantosh Sivaraj static ssize_t dirty_shutdown_show(struct device *dev, 6125e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6135e41396fSSantosh Sivaraj { 6145e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", 42); 6155e41396fSSantosh Sivaraj } 6165e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(dirty_shutdown); 6175e41396fSSantosh Sivaraj 6185e41396fSSantosh Sivaraj static ssize_t formats_show(struct device *dev, 6195e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6205e41396fSSantosh Sivaraj { 6215e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6225e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6235e41396fSSantosh Sivaraj 6245e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->num_formats); 6255e41396fSSantosh Sivaraj } 6265e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(formats); 6275e41396fSSantosh Sivaraj 6285e41396fSSantosh Sivaraj static ssize_t format_show(struct device *dev, 6295e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6305e41396fSSantosh Sivaraj { 6315e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6325e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6335e41396fSSantosh Sivaraj 6345e41396fSSantosh Sivaraj if (dimm->num_formats > 1) 6355e41396fSSantosh Sivaraj return sprintf(buf, "0x201\n"); 6365e41396fSSantosh Sivaraj 6375e41396fSSantosh Sivaraj return sprintf(buf, "0x101\n"); 6385e41396fSSantosh Sivaraj } 6395e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format); 6405e41396fSSantosh Sivaraj 6415e41396fSSantosh Sivaraj static ssize_t format1_show(struct device *dev, struct device_attribute *attr, 6425e41396fSSantosh Sivaraj char *buf) 6435e41396fSSantosh Sivaraj { 6445e41396fSSantosh Sivaraj return sprintf(buf, "0x301\n"); 6455e41396fSSantosh Sivaraj } 6465e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format1); 6475e41396fSSantosh Sivaraj 6485e41396fSSantosh Sivaraj static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj, 6495e41396fSSantosh Sivaraj struct attribute *a, int n) 6505e41396fSSantosh Sivaraj { 6515e41396fSSantosh Sivaraj struct device *dev = container_of(kobj, struct device, kobj); 6525e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6535e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6545e41396fSSantosh Sivaraj 6555e41396fSSantosh Sivaraj if (a == &dev_attr_format1.attr && dimm->num_formats <= 1) 6565e41396fSSantosh Sivaraj return 0; 6575e41396fSSantosh Sivaraj 6585e41396fSSantosh Sivaraj return a->mode; 6595e41396fSSantosh Sivaraj } 6605e41396fSSantosh Sivaraj 66150f558a5SSantosh Sivaraj static ssize_t flags_show(struct device *dev, 66250f558a5SSantosh Sivaraj struct device_attribute *attr, char *buf) 66350f558a5SSantosh Sivaraj { 66450f558a5SSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 66550f558a5SSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 66650f558a5SSantosh Sivaraj struct seq_buf s; 66750f558a5SSantosh Sivaraj u64 flags; 66850f558a5SSantosh Sivaraj 66950f558a5SSantosh Sivaraj flags = dimm->flags; 67050f558a5SSantosh Sivaraj 67150f558a5SSantosh Sivaraj seq_buf_init(&s, buf, PAGE_SIZE); 67250f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_UNARMED_MASK) 67350f558a5SSantosh Sivaraj seq_buf_printf(&s, "not_armed "); 67450f558a5SSantosh Sivaraj 67550f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_BAD_SHUTDOWN_MASK) 67650f558a5SSantosh Sivaraj seq_buf_printf(&s, "flush_fail "); 67750f558a5SSantosh Sivaraj 67850f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_BAD_RESTORE_MASK) 67950f558a5SSantosh Sivaraj seq_buf_printf(&s, "restore_fail "); 68050f558a5SSantosh Sivaraj 68150f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_SAVE_MASK) 68250f558a5SSantosh Sivaraj seq_buf_printf(&s, "save_fail "); 68350f558a5SSantosh Sivaraj 68450f558a5SSantosh Sivaraj if (flags & PAPR_PMEM_SMART_EVENT_MASK) 68550f558a5SSantosh Sivaraj seq_buf_printf(&s, "smart_notify "); 68650f558a5SSantosh Sivaraj 68750f558a5SSantosh Sivaraj 68850f558a5SSantosh Sivaraj if (seq_buf_used(&s)) 68950f558a5SSantosh Sivaraj seq_buf_printf(&s, "\n"); 69050f558a5SSantosh Sivaraj 69150f558a5SSantosh Sivaraj return seq_buf_used(&s); 69250f558a5SSantosh Sivaraj } 69350f558a5SSantosh Sivaraj static DEVICE_ATTR_RO(flags); 69450f558a5SSantosh Sivaraj 6955e41396fSSantosh Sivaraj static struct attribute *ndtest_nvdimm_attributes[] = { 6965e41396fSSantosh Sivaraj &dev_attr_nvdimm_show_handle.attr, 6975e41396fSSantosh Sivaraj &dev_attr_vendor.attr, 6985e41396fSSantosh Sivaraj &dev_attr_id.attr, 6995e41396fSSantosh Sivaraj &dev_attr_phys_id.attr, 7005e41396fSSantosh Sivaraj &dev_attr_subsystem_vendor.attr, 7015e41396fSSantosh Sivaraj &dev_attr_dirty_shutdown.attr, 7025e41396fSSantosh Sivaraj &dev_attr_formats.attr, 7035e41396fSSantosh Sivaraj &dev_attr_format.attr, 7045e41396fSSantosh Sivaraj &dev_attr_format1.attr, 70550f558a5SSantosh Sivaraj &dev_attr_flags.attr, 7065e41396fSSantosh Sivaraj NULL, 7075e41396fSSantosh Sivaraj }; 7085e41396fSSantosh Sivaraj 7095e41396fSSantosh Sivaraj static const struct attribute_group ndtest_nvdimm_attribute_group = { 7105e41396fSSantosh Sivaraj .name = "papr", 7115e41396fSSantosh Sivaraj .attrs = ndtest_nvdimm_attributes, 7125e41396fSSantosh Sivaraj .is_visible = ndtest_nvdimm_attr_visible, 7135e41396fSSantosh Sivaraj }; 7145e41396fSSantosh Sivaraj 7155e41396fSSantosh Sivaraj static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = { 7165e41396fSSantosh Sivaraj &ndtest_nvdimm_attribute_group, 7175e41396fSSantosh Sivaraj NULL, 7185e41396fSSantosh Sivaraj }; 7195e41396fSSantosh Sivaraj 7209399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv, 7219399ab61SSantosh Sivaraj struct ndtest_dimm *dimm, int id) 7229399ab61SSantosh Sivaraj { 7239399ab61SSantosh Sivaraj struct device *dev = &priv->pdev.dev; 7249399ab61SSantosh Sivaraj unsigned long dimm_flags = dimm->flags; 7259399ab61SSantosh Sivaraj 7263b6c6c03SDan Williams if (dimm->num_formats > 1) 7279399ab61SSantosh Sivaraj set_bit(NDD_LABELING, &dimm_flags); 7289399ab61SSantosh Sivaraj 72950f558a5SSantosh Sivaraj if (dimm->flags & PAPR_PMEM_UNARMED_MASK) 73050f558a5SSantosh Sivaraj set_bit(NDD_UNARMED, &dimm_flags); 73150f558a5SSantosh Sivaraj 7325e41396fSSantosh Sivaraj dimm->nvdimm = nvdimm_create(priv->bus, dimm, 7335e41396fSSantosh Sivaraj ndtest_nvdimm_attribute_groups, dimm_flags, 7349399ab61SSantosh Sivaraj NDTEST_SCM_DIMM_CMD_MASK, 0, NULL); 7359399ab61SSantosh Sivaraj if (!dimm->nvdimm) { 7369399ab61SSantosh Sivaraj dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn); 7379399ab61SSantosh Sivaraj return -ENXIO; 7389399ab61SSantosh Sivaraj } 7399399ab61SSantosh Sivaraj 7409399ab61SSantosh Sivaraj dimm->dev = device_create_with_groups(ndtest_dimm_class, 7419399ab61SSantosh Sivaraj &priv->pdev.dev, 7425e41396fSSantosh Sivaraj 0, dimm, dimm_attribute_groups, 7439399ab61SSantosh Sivaraj "test_dimm%d", id); 7449399ab61SSantosh Sivaraj if (!dimm->dev) { 7459399ab61SSantosh Sivaraj pr_err("Could not create dimm device attributes\n"); 7469399ab61SSantosh Sivaraj return -ENOMEM; 7479399ab61SSantosh Sivaraj } 7489399ab61SSantosh Sivaraj 7499399ab61SSantosh Sivaraj return 0; 7509399ab61SSantosh Sivaraj } 7519399ab61SSantosh Sivaraj 7529399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p) 7539399ab61SSantosh Sivaraj { 7549399ab61SSantosh Sivaraj struct ndtest_dimm *d; 7559399ab61SSantosh Sivaraj void *res; 7569399ab61SSantosh Sivaraj int i, id; 7579399ab61SSantosh Sivaraj 7589399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) { 7599399ab61SSantosh Sivaraj d = &p->config->dimms[i]; 7609399ab61SSantosh Sivaraj d->id = id = p->config->dimm_start + i; 7619399ab61SSantosh Sivaraj res = ndtest_alloc_resource(p, LABEL_SIZE, NULL); 7629399ab61SSantosh Sivaraj if (!res) 7639399ab61SSantosh Sivaraj return -ENOMEM; 7649399ab61SSantosh Sivaraj 7659399ab61SSantosh Sivaraj d->label_area = res; 7669399ab61SSantosh Sivaraj sprintf(d->label_area, "label%d", id); 7679399ab61SSantosh Sivaraj d->config_size = LABEL_SIZE; 7689399ab61SSantosh Sivaraj 7699399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, d->size, 7709399ab61SSantosh Sivaraj &p->dimm_dma[id])) 7719399ab61SSantosh Sivaraj return -ENOMEM; 7729399ab61SSantosh Sivaraj 7739399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 7749399ab61SSantosh Sivaraj &p->label_dma[id])) 7759399ab61SSantosh Sivaraj return -ENOMEM; 7769399ab61SSantosh Sivaraj 7779399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 7789399ab61SSantosh Sivaraj &p->dcr_dma[id])) 7799399ab61SSantosh Sivaraj return -ENOMEM; 7809399ab61SSantosh Sivaraj 7819399ab61SSantosh Sivaraj d->address = p->dimm_dma[id]; 7829399ab61SSantosh Sivaraj 7839399ab61SSantosh Sivaraj ndtest_dimm_register(p, d, id); 7849399ab61SSantosh Sivaraj } 7859399ab61SSantosh Sivaraj 7869399ab61SSantosh Sivaraj return 0; 7879399ab61SSantosh Sivaraj } 7889399ab61SSantosh Sivaraj 789107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev, 790107b04e9SSantosh Sivaraj struct device_attribute *attr, char *buf) 791107b04e9SSantosh Sivaraj { 792107b04e9SSantosh Sivaraj return sprintf(buf, "nvdimm_test"); 793107b04e9SSantosh Sivaraj } 794107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible); 795107b04e9SSantosh Sivaraj 796107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = { 797107b04e9SSantosh Sivaraj &dev_attr_compatible.attr, 798107b04e9SSantosh Sivaraj NULL 799107b04e9SSantosh Sivaraj }; 800107b04e9SSantosh Sivaraj 801107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = { 802107b04e9SSantosh Sivaraj .name = "of_node", 803107b04e9SSantosh Sivaraj .attrs = of_node_attributes, 804107b04e9SSantosh Sivaraj }; 805107b04e9SSantosh Sivaraj 806107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = { 807107b04e9SSantosh Sivaraj &of_node_attribute_group, 808107b04e9SSantosh Sivaraj NULL, 809107b04e9SSantosh Sivaraj }; 810107b04e9SSantosh Sivaraj 8119a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p) 8129a27e109SSantosh Sivaraj { 8139399ab61SSantosh Sivaraj p->config = &bus_configs[p->pdev.id]; 8149399ab61SSantosh Sivaraj 8159a27e109SSantosh Sivaraj p->bus_desc.ndctl = ndtest_ctl; 8169a27e109SSantosh Sivaraj p->bus_desc.module = THIS_MODULE; 8179a27e109SSantosh Sivaraj p->bus_desc.provider_name = NULL; 818107b04e9SSantosh Sivaraj p->bus_desc.attr_groups = ndtest_attribute_groups; 8199a27e109SSantosh Sivaraj 8209a27e109SSantosh Sivaraj p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 8219a27e109SSantosh Sivaraj if (!p->bus) { 8229a27e109SSantosh Sivaraj dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 8239a27e109SSantosh Sivaraj return -ENOMEM; 8249a27e109SSantosh Sivaraj } 8259a27e109SSantosh Sivaraj 8269a27e109SSantosh Sivaraj return 0; 8279a27e109SSantosh Sivaraj } 8289a27e109SSantosh Sivaraj 8299a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev) 8309a27e109SSantosh Sivaraj { 8319a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 8329a27e109SSantosh Sivaraj 8339a27e109SSantosh Sivaraj nvdimm_bus_unregister(p->bus); 8349a27e109SSantosh Sivaraj return 0; 8359a27e109SSantosh Sivaraj } 8369a27e109SSantosh Sivaraj 8379a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev) 8389a27e109SSantosh Sivaraj { 8399a27e109SSantosh Sivaraj struct ndtest_priv *p; 8409399ab61SSantosh Sivaraj int rc; 8419a27e109SSantosh Sivaraj 8429a27e109SSantosh Sivaraj p = to_ndtest_priv(&pdev->dev); 8439a27e109SSantosh Sivaraj if (ndtest_bus_register(p)) 8449a27e109SSantosh Sivaraj return -ENOMEM; 8459a27e109SSantosh Sivaraj 8469399ab61SSantosh Sivaraj p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8479399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8489399ab61SSantosh Sivaraj p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8499399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8509399ab61SSantosh Sivaraj p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8519399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8529399ab61SSantosh Sivaraj 8539399ab61SSantosh Sivaraj rc = ndtest_nvdimm_init(p); 8549399ab61SSantosh Sivaraj if (rc) 8559399ab61SSantosh Sivaraj goto err; 8569399ab61SSantosh Sivaraj 8576fde2d4cSSantosh Sivaraj rc = ndtest_init_regions(p); 8586fde2d4cSSantosh Sivaraj if (rc) 8596fde2d4cSSantosh Sivaraj goto err; 8606fde2d4cSSantosh Sivaraj 8619399ab61SSantosh Sivaraj rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p); 8629399ab61SSantosh Sivaraj if (rc) 8639399ab61SSantosh Sivaraj goto err; 8649399ab61SSantosh Sivaraj 8659a27e109SSantosh Sivaraj platform_set_drvdata(pdev, p); 8669a27e109SSantosh Sivaraj 8679a27e109SSantosh Sivaraj return 0; 8689399ab61SSantosh Sivaraj 8699399ab61SSantosh Sivaraj err: 8709399ab61SSantosh Sivaraj pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__); 8719399ab61SSantosh Sivaraj return rc; 8729a27e109SSantosh Sivaraj } 8739a27e109SSantosh Sivaraj 8749a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = { 8759a27e109SSantosh Sivaraj { KBUILD_MODNAME }, 8769a27e109SSantosh Sivaraj { }, 8779a27e109SSantosh Sivaraj }; 8789a27e109SSantosh Sivaraj 8799a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = { 8809a27e109SSantosh Sivaraj .probe = ndtest_probe, 8819a27e109SSantosh Sivaraj .remove = ndtest_remove, 8829a27e109SSantosh Sivaraj .driver = { 8839a27e109SSantosh Sivaraj .name = KBUILD_MODNAME, 8849a27e109SSantosh Sivaraj }, 8859a27e109SSantosh Sivaraj .id_table = ndtest_id, 8869a27e109SSantosh Sivaraj }; 8879a27e109SSantosh Sivaraj 8889a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev) 8899a27e109SSantosh Sivaraj { 8909a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(dev); 8919a27e109SSantosh Sivaraj 8929a27e109SSantosh Sivaraj kfree(p); 8939a27e109SSantosh Sivaraj } 8949a27e109SSantosh Sivaraj 8959a27e109SSantosh Sivaraj static void cleanup_devices(void) 8969a27e109SSantosh Sivaraj { 8979a27e109SSantosh Sivaraj int i; 8989a27e109SSantosh Sivaraj 8999a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) 9009a27e109SSantosh Sivaraj if (instances[i]) 9019a27e109SSantosh Sivaraj platform_device_unregister(&instances[i]->pdev); 9029a27e109SSantosh Sivaraj 9039a27e109SSantosh Sivaraj nfit_test_teardown(); 9049a27e109SSantosh Sivaraj 9059399ab61SSantosh Sivaraj if (ndtest_pool) 9069399ab61SSantosh Sivaraj gen_pool_destroy(ndtest_pool); 9079399ab61SSantosh Sivaraj 9089399ab61SSantosh Sivaraj 9099a27e109SSantosh Sivaraj if (ndtest_dimm_class) 9109a27e109SSantosh Sivaraj class_destroy(ndtest_dimm_class); 9119a27e109SSantosh Sivaraj } 9129a27e109SSantosh Sivaraj 9139a27e109SSantosh Sivaraj static __init int ndtest_init(void) 9149a27e109SSantosh Sivaraj { 9159a27e109SSantosh Sivaraj int rc, i; 9169a27e109SSantosh Sivaraj 9179a27e109SSantosh Sivaraj pmem_test(); 9189a27e109SSantosh Sivaraj libnvdimm_test(); 9199a27e109SSantosh Sivaraj device_dax_test(); 9209a27e109SSantosh Sivaraj dax_pmem_test(); 9219a27e109SSantosh Sivaraj 9226fde2d4cSSantosh Sivaraj nfit_test_setup(ndtest_resource_lookup, NULL); 9236fde2d4cSSantosh Sivaraj 924*1aaba11dSGreg Kroah-Hartman ndtest_dimm_class = class_create("nfit_test_dimm"); 9259a27e109SSantosh Sivaraj if (IS_ERR(ndtest_dimm_class)) { 9269a27e109SSantosh Sivaraj rc = PTR_ERR(ndtest_dimm_class); 9279a27e109SSantosh Sivaraj goto err_register; 9289a27e109SSantosh Sivaraj } 9299a27e109SSantosh Sivaraj 9309399ab61SSantosh Sivaraj ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 9319399ab61SSantosh Sivaraj if (!ndtest_pool) { 9329399ab61SSantosh Sivaraj rc = -ENOMEM; 9339399ab61SSantosh Sivaraj goto err_register; 9349399ab61SSantosh Sivaraj } 9359399ab61SSantosh Sivaraj 9369399ab61SSantosh Sivaraj if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 9379399ab61SSantosh Sivaraj rc = -ENOMEM; 9389399ab61SSantosh Sivaraj goto err_register; 9399399ab61SSantosh Sivaraj } 9409399ab61SSantosh Sivaraj 9419a27e109SSantosh Sivaraj /* Each instance can be taken as a bus, which can have multiple dimms */ 9429a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 9439a27e109SSantosh Sivaraj struct ndtest_priv *priv; 9449a27e109SSantosh Sivaraj struct platform_device *pdev; 9459a27e109SSantosh Sivaraj 9469a27e109SSantosh Sivaraj priv = kzalloc(sizeof(*priv), GFP_KERNEL); 9479a27e109SSantosh Sivaraj if (!priv) { 9489a27e109SSantosh Sivaraj rc = -ENOMEM; 9499a27e109SSantosh Sivaraj goto err_register; 9509a27e109SSantosh Sivaraj } 9519a27e109SSantosh Sivaraj 9529a27e109SSantosh Sivaraj INIT_LIST_HEAD(&priv->resources); 9539a27e109SSantosh Sivaraj pdev = &priv->pdev; 9549a27e109SSantosh Sivaraj pdev->name = KBUILD_MODNAME; 9559a27e109SSantosh Sivaraj pdev->id = i; 9569a27e109SSantosh Sivaraj pdev->dev.release = ndtest_release; 9579a27e109SSantosh Sivaraj rc = platform_device_register(pdev); 9589a27e109SSantosh Sivaraj if (rc) { 9599a27e109SSantosh Sivaraj put_device(&pdev->dev); 9609a27e109SSantosh Sivaraj goto err_register; 9619a27e109SSantosh Sivaraj } 9629a27e109SSantosh Sivaraj get_device(&pdev->dev); 9639a27e109SSantosh Sivaraj 9649a27e109SSantosh Sivaraj instances[i] = priv; 9659a27e109SSantosh Sivaraj } 9669a27e109SSantosh Sivaraj 9679a27e109SSantosh Sivaraj rc = platform_driver_register(&ndtest_driver); 9689a27e109SSantosh Sivaraj if (rc) 9699a27e109SSantosh Sivaraj goto err_register; 9709a27e109SSantosh Sivaraj 9719a27e109SSantosh Sivaraj return 0; 9729a27e109SSantosh Sivaraj 9739a27e109SSantosh Sivaraj err_register: 9749a27e109SSantosh Sivaraj pr_err("Error registering platform device\n"); 9759a27e109SSantosh Sivaraj cleanup_devices(); 9769a27e109SSantosh Sivaraj 9779a27e109SSantosh Sivaraj return rc; 9789a27e109SSantosh Sivaraj } 9799a27e109SSantosh Sivaraj 9809a27e109SSantosh Sivaraj static __exit void ndtest_exit(void) 9819a27e109SSantosh Sivaraj { 9829a27e109SSantosh Sivaraj cleanup_devices(); 9839a27e109SSantosh Sivaraj platform_driver_unregister(&ndtest_driver); 9849a27e109SSantosh Sivaraj } 9859a27e109SSantosh Sivaraj 9869a27e109SSantosh Sivaraj module_init(ndtest_init); 9879a27e109SSantosh Sivaraj module_exit(ndtest_exit); 9889a27e109SSantosh Sivaraj MODULE_LICENSE("GPL"); 9899a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation"); 990