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, 26*6fde2d4cSSantosh 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 92*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region0_mapping[] = { 93*6fde2d4cSSantosh Sivaraj { 94*6fde2d4cSSantosh Sivaraj .dimm = 0, 95*6fde2d4cSSantosh Sivaraj .position = 0, 96*6fde2d4cSSantosh Sivaraj .start = 0, 97*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 98*6fde2d4cSSantosh Sivaraj }, 99*6fde2d4cSSantosh Sivaraj { 100*6fde2d4cSSantosh Sivaraj .dimm = 1, 101*6fde2d4cSSantosh Sivaraj .position = 1, 102*6fde2d4cSSantosh Sivaraj .start = 0, 103*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 104*6fde2d4cSSantosh Sivaraj } 105*6fde2d4cSSantosh Sivaraj }; 106*6fde2d4cSSantosh Sivaraj 107*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region1_mapping[] = { 108*6fde2d4cSSantosh Sivaraj { 109*6fde2d4cSSantosh Sivaraj .dimm = 0, 110*6fde2d4cSSantosh Sivaraj .position = 0, 111*6fde2d4cSSantosh Sivaraj .start = SZ_16M, 112*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 113*6fde2d4cSSantosh Sivaraj }, 114*6fde2d4cSSantosh Sivaraj { 115*6fde2d4cSSantosh Sivaraj .dimm = 1, 116*6fde2d4cSSantosh Sivaraj .position = 1, 117*6fde2d4cSSantosh Sivaraj .start = SZ_16M, 118*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 119*6fde2d4cSSantosh Sivaraj }, 120*6fde2d4cSSantosh Sivaraj { 121*6fde2d4cSSantosh Sivaraj .dimm = 2, 122*6fde2d4cSSantosh Sivaraj .position = 2, 123*6fde2d4cSSantosh Sivaraj .start = SZ_16M, 124*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 125*6fde2d4cSSantosh Sivaraj }, 126*6fde2d4cSSantosh Sivaraj { 127*6fde2d4cSSantosh Sivaraj .dimm = 3, 128*6fde2d4cSSantosh Sivaraj .position = 3, 129*6fde2d4cSSantosh Sivaraj .start = SZ_16M, 130*6fde2d4cSSantosh Sivaraj .size = SZ_16M, 131*6fde2d4cSSantosh Sivaraj }, 132*6fde2d4cSSantosh Sivaraj }; 133*6fde2d4cSSantosh Sivaraj 134*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region2_mapping[] = { 135*6fde2d4cSSantosh Sivaraj { 136*6fde2d4cSSantosh Sivaraj .dimm = 0, 137*6fde2d4cSSantosh Sivaraj .position = 0, 138*6fde2d4cSSantosh Sivaraj .start = 0, 139*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 140*6fde2d4cSSantosh Sivaraj }, 141*6fde2d4cSSantosh Sivaraj }; 142*6fde2d4cSSantosh Sivaraj 143*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region3_mapping[] = { 144*6fde2d4cSSantosh Sivaraj { 145*6fde2d4cSSantosh Sivaraj .dimm = 1, 146*6fde2d4cSSantosh Sivaraj .start = 0, 147*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 148*6fde2d4cSSantosh Sivaraj } 149*6fde2d4cSSantosh Sivaraj }; 150*6fde2d4cSSantosh Sivaraj 151*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region4_mapping[] = { 152*6fde2d4cSSantosh Sivaraj { 153*6fde2d4cSSantosh Sivaraj .dimm = 2, 154*6fde2d4cSSantosh Sivaraj .start = 0, 155*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 156*6fde2d4cSSantosh Sivaraj } 157*6fde2d4cSSantosh Sivaraj }; 158*6fde2d4cSSantosh Sivaraj 159*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region5_mapping[] = { 160*6fde2d4cSSantosh Sivaraj { 161*6fde2d4cSSantosh Sivaraj .dimm = 3, 162*6fde2d4cSSantosh Sivaraj .start = 0, 163*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 164*6fde2d4cSSantosh Sivaraj } 165*6fde2d4cSSantosh Sivaraj }; 166*6fde2d4cSSantosh Sivaraj 167*6fde2d4cSSantosh Sivaraj static struct ndtest_region bus0_regions[] = { 168*6fde2d4cSSantosh Sivaraj { 169*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 170*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region0_mapping), 171*6fde2d4cSSantosh Sivaraj .mapping = region0_mapping, 172*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 173*6fde2d4cSSantosh Sivaraj .range_index = 1, 174*6fde2d4cSSantosh Sivaraj }, 175*6fde2d4cSSantosh Sivaraj { 176*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_PMEM, 177*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region1_mapping), 178*6fde2d4cSSantosh Sivaraj .mapping = region1_mapping, 179*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE * 2, 180*6fde2d4cSSantosh Sivaraj .range_index = 2, 181*6fde2d4cSSantosh Sivaraj }, 182*6fde2d4cSSantosh Sivaraj { 183*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 184*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region2_mapping), 185*6fde2d4cSSantosh Sivaraj .mapping = region2_mapping, 186*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 187*6fde2d4cSSantosh Sivaraj .range_index = 3, 188*6fde2d4cSSantosh Sivaraj }, 189*6fde2d4cSSantosh Sivaraj { 190*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 191*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region3_mapping), 192*6fde2d4cSSantosh Sivaraj .mapping = region3_mapping, 193*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 194*6fde2d4cSSantosh Sivaraj .range_index = 4, 195*6fde2d4cSSantosh Sivaraj }, 196*6fde2d4cSSantosh Sivaraj { 197*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 198*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region4_mapping), 199*6fde2d4cSSantosh Sivaraj .mapping = region4_mapping, 200*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 201*6fde2d4cSSantosh Sivaraj .range_index = 5, 202*6fde2d4cSSantosh Sivaraj }, 203*6fde2d4cSSantosh Sivaraj { 204*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_BLK, 205*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region5_mapping), 206*6fde2d4cSSantosh Sivaraj .mapping = region5_mapping, 207*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 208*6fde2d4cSSantosh Sivaraj .range_index = 6, 209*6fde2d4cSSantosh Sivaraj }, 210*6fde2d4cSSantosh Sivaraj }; 211*6fde2d4cSSantosh Sivaraj 212*6fde2d4cSSantosh Sivaraj static struct ndtest_mapping region6_mapping[] = { 213*6fde2d4cSSantosh Sivaraj { 214*6fde2d4cSSantosh Sivaraj .dimm = 0, 215*6fde2d4cSSantosh Sivaraj .position = 0, 216*6fde2d4cSSantosh Sivaraj .start = 0, 217*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 218*6fde2d4cSSantosh Sivaraj }, 219*6fde2d4cSSantosh Sivaraj }; 220*6fde2d4cSSantosh Sivaraj 221*6fde2d4cSSantosh Sivaraj static struct ndtest_region bus1_regions[] = { 222*6fde2d4cSSantosh Sivaraj { 223*6fde2d4cSSantosh Sivaraj .type = ND_DEVICE_NAMESPACE_IO, 224*6fde2d4cSSantosh Sivaraj .num_mappings = ARRAY_SIZE(region6_mapping), 225*6fde2d4cSSantosh Sivaraj .mapping = region6_mapping, 226*6fde2d4cSSantosh Sivaraj .size = DIMM_SIZE, 227*6fde2d4cSSantosh Sivaraj .range_index = 1, 228*6fde2d4cSSantosh Sivaraj }, 229*6fde2d4cSSantosh Sivaraj }; 230*6fde2d4cSSantosh 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, 237*6fde2d4cSSantosh Sivaraj .regions = bus0_regions, 238*6fde2d4cSSantosh 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, 245*6fde2d4cSSantosh Sivaraj .regions = bus1_regions, 246*6fde2d4cSSantosh 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 2579a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 2589a27e109SSantosh Sivaraj struct nvdimm *nvdimm, unsigned int cmd, void *buf, 2599a27e109SSantosh Sivaraj unsigned int buf_len, int *cmd_rc) 2609a27e109SSantosh Sivaraj { 2619a27e109SSantosh Sivaraj struct ndtest_dimm *dimm; 2629a27e109SSantosh Sivaraj int _cmd_rc; 2639a27e109SSantosh Sivaraj 2649a27e109SSantosh Sivaraj if (!cmd_rc) 2659a27e109SSantosh Sivaraj cmd_rc = &_cmd_rc; 2669a27e109SSantosh Sivaraj 2679a27e109SSantosh Sivaraj *cmd_rc = 0; 2689a27e109SSantosh Sivaraj 2699a27e109SSantosh Sivaraj if (!nvdimm) 2709a27e109SSantosh Sivaraj return -EINVAL; 2719a27e109SSantosh Sivaraj 2729a27e109SSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 2739a27e109SSantosh Sivaraj if (!dimm) 2749a27e109SSantosh Sivaraj return -EINVAL; 2759a27e109SSantosh Sivaraj 2769a27e109SSantosh Sivaraj switch (cmd) { 2779a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_SIZE: 2789a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_DATA: 2799a27e109SSantosh Sivaraj case ND_CMD_SET_CONFIG_DATA: 2809a27e109SSantosh Sivaraj default: 2819a27e109SSantosh Sivaraj return -EINVAL; 2829a27e109SSantosh Sivaraj } 2839a27e109SSantosh Sivaraj 2849a27e109SSantosh Sivaraj return 0; 2859a27e109SSantosh Sivaraj } 2869a27e109SSantosh Sivaraj 287*6fde2d4cSSantosh Sivaraj static int ndtest_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, 288*6fde2d4cSSantosh Sivaraj void *iobuf, u64 len, int rw) 289*6fde2d4cSSantosh Sivaraj { 290*6fde2d4cSSantosh Sivaraj struct ndtest_dimm *dimm = ndbr->blk_provider_data; 291*6fde2d4cSSantosh Sivaraj struct ndtest_blk_mmio *mmio = dimm->mmio; 292*6fde2d4cSSantosh Sivaraj struct nd_region *nd_region = &ndbr->nd_region; 293*6fde2d4cSSantosh Sivaraj unsigned int lane; 294*6fde2d4cSSantosh Sivaraj 295*6fde2d4cSSantosh Sivaraj if (!mmio) 296*6fde2d4cSSantosh Sivaraj return -ENOMEM; 297*6fde2d4cSSantosh Sivaraj 298*6fde2d4cSSantosh Sivaraj lane = nd_region_acquire_lane(nd_region); 299*6fde2d4cSSantosh Sivaraj if (rw) 300*6fde2d4cSSantosh Sivaraj memcpy(mmio->base + dpa, iobuf, len); 301*6fde2d4cSSantosh Sivaraj else { 302*6fde2d4cSSantosh Sivaraj memcpy(iobuf, mmio->base + dpa, len); 303*6fde2d4cSSantosh Sivaraj arch_invalidate_pmem(mmio->base + dpa, len); 304*6fde2d4cSSantosh Sivaraj } 305*6fde2d4cSSantosh Sivaraj 306*6fde2d4cSSantosh Sivaraj nd_region_release_lane(nd_region, lane); 307*6fde2d4cSSantosh Sivaraj 308*6fde2d4cSSantosh Sivaraj return 0; 309*6fde2d4cSSantosh Sivaraj } 310*6fde2d4cSSantosh Sivaraj 311*6fde2d4cSSantosh Sivaraj static int ndtest_blk_region_enable(struct nvdimm_bus *nvdimm_bus, 312*6fde2d4cSSantosh Sivaraj struct device *dev) 313*6fde2d4cSSantosh Sivaraj { 314*6fde2d4cSSantosh Sivaraj struct nd_blk_region *ndbr = to_nd_blk_region(dev); 315*6fde2d4cSSantosh Sivaraj struct nvdimm *nvdimm; 316*6fde2d4cSSantosh Sivaraj struct ndtest_dimm *dimm; 317*6fde2d4cSSantosh Sivaraj struct ndtest_blk_mmio *mmio; 318*6fde2d4cSSantosh Sivaraj 319*6fde2d4cSSantosh Sivaraj nvdimm = nd_blk_region_to_dimm(ndbr); 320*6fde2d4cSSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 321*6fde2d4cSSantosh Sivaraj 322*6fde2d4cSSantosh Sivaraj nd_blk_region_set_provider_data(ndbr, dimm); 323*6fde2d4cSSantosh Sivaraj dimm->blk_region = to_nd_region(dev); 324*6fde2d4cSSantosh Sivaraj 325*6fde2d4cSSantosh Sivaraj mmio = devm_kzalloc(dev, sizeof(struct ndtest_blk_mmio), GFP_KERNEL); 326*6fde2d4cSSantosh Sivaraj if (!mmio) 327*6fde2d4cSSantosh Sivaraj return -ENOMEM; 328*6fde2d4cSSantosh Sivaraj 329*6fde2d4cSSantosh Sivaraj mmio->base = (void __iomem *) devm_nvdimm_memremap( 330*6fde2d4cSSantosh Sivaraj dev, dimm->address, 12, nd_blk_memremap_flags(ndbr)); 331*6fde2d4cSSantosh Sivaraj if (!mmio->base) { 332*6fde2d4cSSantosh Sivaraj dev_err(dev, "%s failed to map blk dimm\n", nvdimm_name(nvdimm)); 333*6fde2d4cSSantosh Sivaraj return -ENOMEM; 334*6fde2d4cSSantosh Sivaraj } 335*6fde2d4cSSantosh Sivaraj mmio->size = dimm->size; 336*6fde2d4cSSantosh Sivaraj mmio->base_offset = 0; 337*6fde2d4cSSantosh Sivaraj 338*6fde2d4cSSantosh Sivaraj dimm->mmio = mmio; 339*6fde2d4cSSantosh Sivaraj 340*6fde2d4cSSantosh Sivaraj return 0; 341*6fde2d4cSSantosh Sivaraj } 342*6fde2d4cSSantosh Sivaraj 343*6fde2d4cSSantosh Sivaraj static struct nfit_test_resource *ndtest_resource_lookup(resource_size_t addr) 344*6fde2d4cSSantosh Sivaraj { 345*6fde2d4cSSantosh Sivaraj int i; 346*6fde2d4cSSantosh Sivaraj 347*6fde2d4cSSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 348*6fde2d4cSSantosh Sivaraj struct nfit_test_resource *n, *nfit_res = NULL; 349*6fde2d4cSSantosh Sivaraj struct ndtest_priv *t = instances[i]; 350*6fde2d4cSSantosh Sivaraj 351*6fde2d4cSSantosh Sivaraj if (!t) 352*6fde2d4cSSantosh Sivaraj continue; 353*6fde2d4cSSantosh Sivaraj spin_lock(&ndtest_lock); 354*6fde2d4cSSantosh Sivaraj list_for_each_entry(n, &t->resources, list) { 355*6fde2d4cSSantosh Sivaraj if (addr >= n->res.start && (addr < n->res.start 356*6fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 357*6fde2d4cSSantosh Sivaraj nfit_res = n; 358*6fde2d4cSSantosh Sivaraj break; 359*6fde2d4cSSantosh Sivaraj } else if (addr >= (unsigned long) n->buf 360*6fde2d4cSSantosh Sivaraj && (addr < (unsigned long) n->buf 361*6fde2d4cSSantosh Sivaraj + resource_size(&n->res))) { 362*6fde2d4cSSantosh Sivaraj nfit_res = n; 363*6fde2d4cSSantosh Sivaraj break; 364*6fde2d4cSSantosh Sivaraj } 365*6fde2d4cSSantosh Sivaraj } 366*6fde2d4cSSantosh Sivaraj spin_unlock(&ndtest_lock); 367*6fde2d4cSSantosh Sivaraj if (nfit_res) 368*6fde2d4cSSantosh Sivaraj return nfit_res; 369*6fde2d4cSSantosh Sivaraj } 370*6fde2d4cSSantosh Sivaraj 371*6fde2d4cSSantosh Sivaraj pr_warn("Failed to get resource\n"); 372*6fde2d4cSSantosh Sivaraj 373*6fde2d4cSSantosh Sivaraj return NULL; 374*6fde2d4cSSantosh Sivaraj } 375*6fde2d4cSSantosh Sivaraj 3769399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data) 3779399ab61SSantosh Sivaraj { 3789399ab61SSantosh Sivaraj struct nfit_test_resource *res = data; 3799399ab61SSantosh Sivaraj 3809399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 3819399ab61SSantosh Sivaraj list_del(&res->list); 3829399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 3839399ab61SSantosh Sivaraj 3849399ab61SSantosh Sivaraj if (resource_size(&res->res) >= DIMM_SIZE) 3859399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, res->res.start, 3869399ab61SSantosh Sivaraj resource_size(&res->res)); 3879399ab61SSantosh Sivaraj vfree(res->buf); 3889399ab61SSantosh Sivaraj kfree(res); 3899399ab61SSantosh Sivaraj } 3909399ab61SSantosh Sivaraj 3919399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size, 3929399ab61SSantosh Sivaraj dma_addr_t *dma) 3939399ab61SSantosh Sivaraj { 3949399ab61SSantosh Sivaraj dma_addr_t __dma; 3959399ab61SSantosh Sivaraj void *buf; 3969399ab61SSantosh Sivaraj struct nfit_test_resource *res; 3979399ab61SSantosh Sivaraj struct genpool_data_align data = { 3989399ab61SSantosh Sivaraj .align = SZ_128M, 3999399ab61SSantosh Sivaraj }; 4009399ab61SSantosh Sivaraj 4019399ab61SSantosh Sivaraj res = kzalloc(sizeof(*res), GFP_KERNEL); 4029399ab61SSantosh Sivaraj if (!res) 4039399ab61SSantosh Sivaraj return NULL; 4049399ab61SSantosh Sivaraj 4059399ab61SSantosh Sivaraj buf = vmalloc(size); 4069399ab61SSantosh Sivaraj if (size >= DIMM_SIZE) 4079399ab61SSantosh Sivaraj __dma = gen_pool_alloc_algo(ndtest_pool, size, 4089399ab61SSantosh Sivaraj gen_pool_first_fit_align, &data); 4099399ab61SSantosh Sivaraj else 4109399ab61SSantosh Sivaraj __dma = (unsigned long) buf; 4119399ab61SSantosh Sivaraj 4129399ab61SSantosh Sivaraj if (!__dma) 4139399ab61SSantosh Sivaraj goto buf_err; 4149399ab61SSantosh Sivaraj 4159399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->list); 4169399ab61SSantosh Sivaraj res->dev = &p->pdev.dev; 4179399ab61SSantosh Sivaraj res->buf = buf; 4189399ab61SSantosh Sivaraj res->res.start = __dma; 4199399ab61SSantosh Sivaraj res->res.end = __dma + size - 1; 4209399ab61SSantosh Sivaraj res->res.name = "NFIT"; 4219399ab61SSantosh Sivaraj spin_lock_init(&res->lock); 4229399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->requests); 4239399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 4249399ab61SSantosh Sivaraj list_add(&res->list, &p->resources); 4259399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 4269399ab61SSantosh Sivaraj 4279399ab61SSantosh Sivaraj if (dma) 4289399ab61SSantosh Sivaraj *dma = __dma; 4299399ab61SSantosh Sivaraj 4309399ab61SSantosh Sivaraj if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res)) 4319399ab61SSantosh Sivaraj return res->buf; 4329399ab61SSantosh Sivaraj 4339399ab61SSantosh Sivaraj buf_err: 4349399ab61SSantosh Sivaraj if (__dma && size >= DIMM_SIZE) 4359399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, __dma, size); 4369399ab61SSantosh Sivaraj if (buf) 4379399ab61SSantosh Sivaraj vfree(buf); 4389399ab61SSantosh Sivaraj kfree(res); 4399399ab61SSantosh Sivaraj 4409399ab61SSantosh Sivaraj return NULL; 4419399ab61SSantosh Sivaraj } 4429399ab61SSantosh Sivaraj 443*6fde2d4cSSantosh Sivaraj static ssize_t range_index_show(struct device *dev, 444*6fde2d4cSSantosh Sivaraj struct device_attribute *attr, char *buf) 445*6fde2d4cSSantosh Sivaraj { 446*6fde2d4cSSantosh Sivaraj struct nd_region *nd_region = to_nd_region(dev); 447*6fde2d4cSSantosh Sivaraj struct ndtest_region *region = nd_region_provider_data(nd_region); 448*6fde2d4cSSantosh Sivaraj 449*6fde2d4cSSantosh Sivaraj return sprintf(buf, "%d\n", region->range_index); 450*6fde2d4cSSantosh Sivaraj } 451*6fde2d4cSSantosh Sivaraj static DEVICE_ATTR_RO(range_index); 452*6fde2d4cSSantosh Sivaraj 453*6fde2d4cSSantosh Sivaraj static struct attribute *ndtest_region_attributes[] = { 454*6fde2d4cSSantosh Sivaraj &dev_attr_range_index.attr, 455*6fde2d4cSSantosh Sivaraj NULL, 456*6fde2d4cSSantosh Sivaraj }; 457*6fde2d4cSSantosh Sivaraj 458*6fde2d4cSSantosh Sivaraj static const struct attribute_group ndtest_region_attribute_group = { 459*6fde2d4cSSantosh Sivaraj .name = "papr", 460*6fde2d4cSSantosh Sivaraj .attrs = ndtest_region_attributes, 461*6fde2d4cSSantosh Sivaraj }; 462*6fde2d4cSSantosh Sivaraj 463*6fde2d4cSSantosh Sivaraj static const struct attribute_group *ndtest_region_attribute_groups[] = { 464*6fde2d4cSSantosh Sivaraj &ndtest_region_attribute_group, 465*6fde2d4cSSantosh Sivaraj NULL, 466*6fde2d4cSSantosh Sivaraj }; 467*6fde2d4cSSantosh Sivaraj 468*6fde2d4cSSantosh Sivaraj static int ndtest_create_region(struct ndtest_priv *p, 469*6fde2d4cSSantosh Sivaraj struct ndtest_region *region) 470*6fde2d4cSSantosh Sivaraj { 471*6fde2d4cSSantosh Sivaraj struct nd_mapping_desc mappings[NDTEST_MAX_MAPPING]; 472*6fde2d4cSSantosh Sivaraj struct nd_blk_region_desc ndbr_desc; 473*6fde2d4cSSantosh Sivaraj struct nd_interleave_set *nd_set; 474*6fde2d4cSSantosh Sivaraj struct nd_region_desc *ndr_desc; 475*6fde2d4cSSantosh Sivaraj struct resource res; 476*6fde2d4cSSantosh Sivaraj int i, ndimm = region->mapping[0].dimm; 477*6fde2d4cSSantosh Sivaraj u64 uuid[2]; 478*6fde2d4cSSantosh Sivaraj 479*6fde2d4cSSantosh Sivaraj memset(&res, 0, sizeof(res)); 480*6fde2d4cSSantosh Sivaraj memset(&mappings, 0, sizeof(mappings)); 481*6fde2d4cSSantosh Sivaraj memset(&ndbr_desc, 0, sizeof(ndbr_desc)); 482*6fde2d4cSSantosh Sivaraj ndr_desc = &ndbr_desc.ndr_desc; 483*6fde2d4cSSantosh Sivaraj 484*6fde2d4cSSantosh Sivaraj if (!ndtest_alloc_resource(p, region->size, &res.start)) 485*6fde2d4cSSantosh Sivaraj return -ENOMEM; 486*6fde2d4cSSantosh Sivaraj 487*6fde2d4cSSantosh Sivaraj res.end = res.start + region->size - 1; 488*6fde2d4cSSantosh Sivaraj ndr_desc->mapping = mappings; 489*6fde2d4cSSantosh Sivaraj ndr_desc->res = &res; 490*6fde2d4cSSantosh Sivaraj ndr_desc->provider_data = region; 491*6fde2d4cSSantosh Sivaraj ndr_desc->attr_groups = ndtest_region_attribute_groups; 492*6fde2d4cSSantosh Sivaraj 493*6fde2d4cSSantosh Sivaraj if (uuid_parse(p->config->dimms[ndimm].uuid_str, (uuid_t *)uuid)) { 494*6fde2d4cSSantosh Sivaraj pr_err("failed to parse UUID\n"); 495*6fde2d4cSSantosh Sivaraj return -ENXIO; 496*6fde2d4cSSantosh Sivaraj } 497*6fde2d4cSSantosh Sivaraj 498*6fde2d4cSSantosh Sivaraj nd_set = devm_kzalloc(&p->pdev.dev, sizeof(*nd_set), GFP_KERNEL); 499*6fde2d4cSSantosh Sivaraj if (!nd_set) 500*6fde2d4cSSantosh Sivaraj return -ENOMEM; 501*6fde2d4cSSantosh Sivaraj 502*6fde2d4cSSantosh Sivaraj nd_set->cookie1 = cpu_to_le64(uuid[0]); 503*6fde2d4cSSantosh Sivaraj nd_set->cookie2 = cpu_to_le64(uuid[1]); 504*6fde2d4cSSantosh Sivaraj nd_set->altcookie = nd_set->cookie1; 505*6fde2d4cSSantosh Sivaraj ndr_desc->nd_set = nd_set; 506*6fde2d4cSSantosh Sivaraj 507*6fde2d4cSSantosh Sivaraj if (region->type == ND_DEVICE_NAMESPACE_BLK) { 508*6fde2d4cSSantosh Sivaraj mappings[0].start = 0; 509*6fde2d4cSSantosh Sivaraj mappings[0].size = DIMM_SIZE; 510*6fde2d4cSSantosh Sivaraj mappings[0].nvdimm = p->config->dimms[ndimm].nvdimm; 511*6fde2d4cSSantosh Sivaraj 512*6fde2d4cSSantosh Sivaraj ndr_desc->mapping = &mappings[0]; 513*6fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = 1; 514*6fde2d4cSSantosh Sivaraj ndr_desc->num_lanes = 1; 515*6fde2d4cSSantosh Sivaraj ndbr_desc.enable = ndtest_blk_region_enable; 516*6fde2d4cSSantosh Sivaraj ndbr_desc.do_io = ndtest_blk_do_io; 517*6fde2d4cSSantosh Sivaraj region->region = nvdimm_blk_region_create(p->bus, ndr_desc); 518*6fde2d4cSSantosh Sivaraj 519*6fde2d4cSSantosh Sivaraj goto done; 520*6fde2d4cSSantosh Sivaraj } 521*6fde2d4cSSantosh Sivaraj 522*6fde2d4cSSantosh Sivaraj for (i = 0; i < region->num_mappings; i++) { 523*6fde2d4cSSantosh Sivaraj ndimm = region->mapping[i].dimm; 524*6fde2d4cSSantosh Sivaraj mappings[i].start = region->mapping[i].start; 525*6fde2d4cSSantosh Sivaraj mappings[i].size = region->mapping[i].size; 526*6fde2d4cSSantosh Sivaraj mappings[i].position = region->mapping[i].position; 527*6fde2d4cSSantosh Sivaraj mappings[i].nvdimm = p->config->dimms[ndimm].nvdimm; 528*6fde2d4cSSantosh Sivaraj } 529*6fde2d4cSSantosh Sivaraj 530*6fde2d4cSSantosh Sivaraj ndr_desc->num_mappings = region->num_mappings; 531*6fde2d4cSSantosh Sivaraj region->region = nvdimm_pmem_region_create(p->bus, ndr_desc); 532*6fde2d4cSSantosh Sivaraj 533*6fde2d4cSSantosh Sivaraj done: 534*6fde2d4cSSantosh Sivaraj if (!region->region) { 535*6fde2d4cSSantosh Sivaraj dev_err(&p->pdev.dev, "Error registering region %pR\n", 536*6fde2d4cSSantosh Sivaraj ndr_desc->res); 537*6fde2d4cSSantosh Sivaraj return -ENXIO; 538*6fde2d4cSSantosh Sivaraj } 539*6fde2d4cSSantosh Sivaraj 540*6fde2d4cSSantosh Sivaraj return 0; 541*6fde2d4cSSantosh Sivaraj } 542*6fde2d4cSSantosh Sivaraj 543*6fde2d4cSSantosh Sivaraj static int ndtest_init_regions(struct ndtest_priv *p) 544*6fde2d4cSSantosh Sivaraj { 545*6fde2d4cSSantosh Sivaraj int i, ret = 0; 546*6fde2d4cSSantosh Sivaraj 547*6fde2d4cSSantosh Sivaraj for (i = 0; i < p->config->num_regions; i++) { 548*6fde2d4cSSantosh Sivaraj ret = ndtest_create_region(p, &p->config->regions[i]); 549*6fde2d4cSSantosh Sivaraj if (ret) 550*6fde2d4cSSantosh Sivaraj return ret; 551*6fde2d4cSSantosh Sivaraj } 552*6fde2d4cSSantosh Sivaraj 553*6fde2d4cSSantosh Sivaraj return 0; 554*6fde2d4cSSantosh Sivaraj } 555*6fde2d4cSSantosh Sivaraj 5569399ab61SSantosh Sivaraj static void put_dimms(void *data) 5579399ab61SSantosh Sivaraj { 5589399ab61SSantosh Sivaraj struct ndtest_priv *p = data; 5599399ab61SSantosh Sivaraj int i; 5609399ab61SSantosh Sivaraj 5619399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) 5629399ab61SSantosh Sivaraj if (p->config->dimms[i].dev) { 5639399ab61SSantosh Sivaraj device_unregister(p->config->dimms[i].dev); 5649399ab61SSantosh Sivaraj p->config->dimms[i].dev = NULL; 5659399ab61SSantosh Sivaraj } 5669399ab61SSantosh Sivaraj } 5679399ab61SSantosh Sivaraj 5685e41396fSSantosh Sivaraj static ssize_t handle_show(struct device *dev, struct device_attribute *attr, 5695e41396fSSantosh Sivaraj char *buf) 5705e41396fSSantosh Sivaraj { 5715e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5725e41396fSSantosh Sivaraj 5735e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 5745e41396fSSantosh Sivaraj } 5755e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(handle); 5765e41396fSSantosh Sivaraj 5775e41396fSSantosh Sivaraj static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 5785e41396fSSantosh Sivaraj char *buf) 5795e41396fSSantosh Sivaraj { 5805e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5815e41396fSSantosh Sivaraj 5825e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->fail_cmd); 5835e41396fSSantosh Sivaraj } 5845e41396fSSantosh Sivaraj 5855e41396fSSantosh Sivaraj static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 5865e41396fSSantosh Sivaraj const char *buf, size_t size) 5875e41396fSSantosh Sivaraj { 5885e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 5895e41396fSSantosh Sivaraj unsigned long val; 5905e41396fSSantosh Sivaraj ssize_t rc; 5915e41396fSSantosh Sivaraj 5925e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 5935e41396fSSantosh Sivaraj if (rc) 5945e41396fSSantosh Sivaraj return rc; 5955e41396fSSantosh Sivaraj 5965e41396fSSantosh Sivaraj dimm->fail_cmd = val; 5975e41396fSSantosh Sivaraj 5985e41396fSSantosh Sivaraj return size; 5995e41396fSSantosh Sivaraj } 6005e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd); 6015e41396fSSantosh Sivaraj 6025e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 6035e41396fSSantosh Sivaraj char *buf) 6045e41396fSSantosh Sivaraj { 6055e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6065e41396fSSantosh Sivaraj 6075e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->fail_cmd_code); 6085e41396fSSantosh Sivaraj } 6095e41396fSSantosh Sivaraj 6105e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 6115e41396fSSantosh Sivaraj const char *buf, size_t size) 6125e41396fSSantosh Sivaraj { 6135e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 6145e41396fSSantosh Sivaraj unsigned long val; 6155e41396fSSantosh Sivaraj ssize_t rc; 6165e41396fSSantosh Sivaraj 6175e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 6185e41396fSSantosh Sivaraj if (rc) 6195e41396fSSantosh Sivaraj return rc; 6205e41396fSSantosh Sivaraj 6215e41396fSSantosh Sivaraj dimm->fail_cmd_code = val; 6225e41396fSSantosh Sivaraj return size; 6235e41396fSSantosh Sivaraj } 6245e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd_code); 6255e41396fSSantosh Sivaraj 6265e41396fSSantosh Sivaraj static struct attribute *dimm_attributes[] = { 6275e41396fSSantosh Sivaraj &dev_attr_handle.attr, 6285e41396fSSantosh Sivaraj &dev_attr_fail_cmd.attr, 6295e41396fSSantosh Sivaraj &dev_attr_fail_cmd_code.attr, 6305e41396fSSantosh Sivaraj NULL, 6315e41396fSSantosh Sivaraj }; 6325e41396fSSantosh Sivaraj 6335e41396fSSantosh Sivaraj static struct attribute_group dimm_attribute_group = { 6345e41396fSSantosh Sivaraj .attrs = dimm_attributes, 6355e41396fSSantosh Sivaraj }; 6365e41396fSSantosh Sivaraj 6375e41396fSSantosh Sivaraj static const struct attribute_group *dimm_attribute_groups[] = { 6385e41396fSSantosh Sivaraj &dimm_attribute_group, 6395e41396fSSantosh Sivaraj NULL, 6405e41396fSSantosh Sivaraj }; 6415e41396fSSantosh Sivaraj 6425e41396fSSantosh Sivaraj static ssize_t phys_id_show(struct device *dev, 6435e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6445e41396fSSantosh Sivaraj { 6455e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6465e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6475e41396fSSantosh Sivaraj 6485e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->physical_id); 6495e41396fSSantosh Sivaraj } 6505e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(phys_id); 6515e41396fSSantosh Sivaraj 6525e41396fSSantosh Sivaraj static ssize_t vendor_show(struct device *dev, 6535e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6545e41396fSSantosh Sivaraj { 6555e41396fSSantosh Sivaraj return sprintf(buf, "0x1234567\n"); 6565e41396fSSantosh Sivaraj } 6575e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(vendor); 6585e41396fSSantosh Sivaraj 6595e41396fSSantosh Sivaraj static ssize_t id_show(struct device *dev, 6605e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6615e41396fSSantosh Sivaraj { 6625e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6635e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6645e41396fSSantosh Sivaraj 6655e41396fSSantosh Sivaraj return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd, 6665e41396fSSantosh Sivaraj 0xa, 2016, ~(dimm->handle)); 6675e41396fSSantosh Sivaraj } 6685e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(id); 6695e41396fSSantosh Sivaraj 6705e41396fSSantosh Sivaraj static ssize_t nvdimm_handle_show(struct device *dev, 6715e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6725e41396fSSantosh Sivaraj { 6735e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 6745e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 6755e41396fSSantosh Sivaraj 6765e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 6775e41396fSSantosh Sivaraj } 6785e41396fSSantosh Sivaraj 6795e41396fSSantosh Sivaraj static struct device_attribute dev_attr_nvdimm_show_handle = { 6805e41396fSSantosh Sivaraj .attr = { .name = "handle", .mode = 0444 }, 6815e41396fSSantosh Sivaraj .show = nvdimm_handle_show, 6825e41396fSSantosh Sivaraj }; 6835e41396fSSantosh Sivaraj 6845e41396fSSantosh Sivaraj static ssize_t subsystem_vendor_show(struct device *dev, 6855e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6865e41396fSSantosh Sivaraj { 6875e41396fSSantosh Sivaraj return sprintf(buf, "0x%04x\n", 0); 6885e41396fSSantosh Sivaraj } 6895e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(subsystem_vendor); 6905e41396fSSantosh Sivaraj 6915e41396fSSantosh Sivaraj static ssize_t dirty_shutdown_show(struct device *dev, 6925e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 6935e41396fSSantosh Sivaraj { 6945e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", 42); 6955e41396fSSantosh Sivaraj } 6965e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(dirty_shutdown); 6975e41396fSSantosh Sivaraj 6985e41396fSSantosh Sivaraj static ssize_t formats_show(struct device *dev, 6995e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7005e41396fSSantosh Sivaraj { 7015e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7025e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7035e41396fSSantosh Sivaraj 7045e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->num_formats); 7055e41396fSSantosh Sivaraj } 7065e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(formats); 7075e41396fSSantosh Sivaraj 7085e41396fSSantosh Sivaraj static ssize_t format_show(struct device *dev, 7095e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 7105e41396fSSantosh Sivaraj { 7115e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7125e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7135e41396fSSantosh Sivaraj 7145e41396fSSantosh Sivaraj if (dimm->num_formats > 1) 7155e41396fSSantosh Sivaraj return sprintf(buf, "0x201\n"); 7165e41396fSSantosh Sivaraj 7175e41396fSSantosh Sivaraj return sprintf(buf, "0x101\n"); 7185e41396fSSantosh Sivaraj } 7195e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format); 7205e41396fSSantosh Sivaraj 7215e41396fSSantosh Sivaraj static ssize_t format1_show(struct device *dev, struct device_attribute *attr, 7225e41396fSSantosh Sivaraj char *buf) 7235e41396fSSantosh Sivaraj { 7245e41396fSSantosh Sivaraj return sprintf(buf, "0x301\n"); 7255e41396fSSantosh Sivaraj } 7265e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format1); 7275e41396fSSantosh Sivaraj 7285e41396fSSantosh Sivaraj static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj, 7295e41396fSSantosh Sivaraj struct attribute *a, int n) 7305e41396fSSantosh Sivaraj { 7315e41396fSSantosh Sivaraj struct device *dev = container_of(kobj, struct device, kobj); 7325e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 7335e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 7345e41396fSSantosh Sivaraj 7355e41396fSSantosh Sivaraj if (a == &dev_attr_format1.attr && dimm->num_formats <= 1) 7365e41396fSSantosh Sivaraj return 0; 7375e41396fSSantosh Sivaraj 7385e41396fSSantosh Sivaraj return a->mode; 7395e41396fSSantosh Sivaraj } 7405e41396fSSantosh Sivaraj 7415e41396fSSantosh Sivaraj static struct attribute *ndtest_nvdimm_attributes[] = { 7425e41396fSSantosh Sivaraj &dev_attr_nvdimm_show_handle.attr, 7435e41396fSSantosh Sivaraj &dev_attr_vendor.attr, 7445e41396fSSantosh Sivaraj &dev_attr_id.attr, 7455e41396fSSantosh Sivaraj &dev_attr_phys_id.attr, 7465e41396fSSantosh Sivaraj &dev_attr_subsystem_vendor.attr, 7475e41396fSSantosh Sivaraj &dev_attr_dirty_shutdown.attr, 7485e41396fSSantosh Sivaraj &dev_attr_formats.attr, 7495e41396fSSantosh Sivaraj &dev_attr_format.attr, 7505e41396fSSantosh Sivaraj &dev_attr_format1.attr, 7515e41396fSSantosh Sivaraj NULL, 7525e41396fSSantosh Sivaraj }; 7535e41396fSSantosh Sivaraj 7545e41396fSSantosh Sivaraj static const struct attribute_group ndtest_nvdimm_attribute_group = { 7555e41396fSSantosh Sivaraj .name = "papr", 7565e41396fSSantosh Sivaraj .attrs = ndtest_nvdimm_attributes, 7575e41396fSSantosh Sivaraj .is_visible = ndtest_nvdimm_attr_visible, 7585e41396fSSantosh Sivaraj }; 7595e41396fSSantosh Sivaraj 7605e41396fSSantosh Sivaraj static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = { 7615e41396fSSantosh Sivaraj &ndtest_nvdimm_attribute_group, 7625e41396fSSantosh Sivaraj NULL, 7635e41396fSSantosh Sivaraj }; 7645e41396fSSantosh Sivaraj 7659399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv, 7669399ab61SSantosh Sivaraj struct ndtest_dimm *dimm, int id) 7679399ab61SSantosh Sivaraj { 7689399ab61SSantosh Sivaraj struct device *dev = &priv->pdev.dev; 7699399ab61SSantosh Sivaraj unsigned long dimm_flags = dimm->flags; 7709399ab61SSantosh Sivaraj 7719399ab61SSantosh Sivaraj if (dimm->num_formats > 1) { 7729399ab61SSantosh Sivaraj set_bit(NDD_ALIASING, &dimm_flags); 7739399ab61SSantosh Sivaraj set_bit(NDD_LABELING, &dimm_flags); 7749399ab61SSantosh Sivaraj } 7759399ab61SSantosh Sivaraj 7765e41396fSSantosh Sivaraj dimm->nvdimm = nvdimm_create(priv->bus, dimm, 7775e41396fSSantosh Sivaraj ndtest_nvdimm_attribute_groups, dimm_flags, 7789399ab61SSantosh Sivaraj NDTEST_SCM_DIMM_CMD_MASK, 0, NULL); 7799399ab61SSantosh Sivaraj if (!dimm->nvdimm) { 7809399ab61SSantosh Sivaraj dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn); 7819399ab61SSantosh Sivaraj return -ENXIO; 7829399ab61SSantosh Sivaraj } 7839399ab61SSantosh Sivaraj 7849399ab61SSantosh Sivaraj dimm->dev = device_create_with_groups(ndtest_dimm_class, 7859399ab61SSantosh Sivaraj &priv->pdev.dev, 7865e41396fSSantosh Sivaraj 0, dimm, dimm_attribute_groups, 7879399ab61SSantosh Sivaraj "test_dimm%d", id); 7889399ab61SSantosh Sivaraj if (!dimm->dev) { 7899399ab61SSantosh Sivaraj pr_err("Could not create dimm device attributes\n"); 7909399ab61SSantosh Sivaraj return -ENOMEM; 7919399ab61SSantosh Sivaraj } 7929399ab61SSantosh Sivaraj 7939399ab61SSantosh Sivaraj return 0; 7949399ab61SSantosh Sivaraj } 7959399ab61SSantosh Sivaraj 7969399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p) 7979399ab61SSantosh Sivaraj { 7989399ab61SSantosh Sivaraj struct ndtest_dimm *d; 7999399ab61SSantosh Sivaraj void *res; 8009399ab61SSantosh Sivaraj int i, id; 8019399ab61SSantosh Sivaraj 8029399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) { 8039399ab61SSantosh Sivaraj d = &p->config->dimms[i]; 8049399ab61SSantosh Sivaraj d->id = id = p->config->dimm_start + i; 8059399ab61SSantosh Sivaraj res = ndtest_alloc_resource(p, LABEL_SIZE, NULL); 8069399ab61SSantosh Sivaraj if (!res) 8079399ab61SSantosh Sivaraj return -ENOMEM; 8089399ab61SSantosh Sivaraj 8099399ab61SSantosh Sivaraj d->label_area = res; 8109399ab61SSantosh Sivaraj sprintf(d->label_area, "label%d", id); 8119399ab61SSantosh Sivaraj d->config_size = LABEL_SIZE; 8129399ab61SSantosh Sivaraj 8139399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, d->size, 8149399ab61SSantosh Sivaraj &p->dimm_dma[id])) 8159399ab61SSantosh Sivaraj return -ENOMEM; 8169399ab61SSantosh Sivaraj 8179399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8189399ab61SSantosh Sivaraj &p->label_dma[id])) 8199399ab61SSantosh Sivaraj return -ENOMEM; 8209399ab61SSantosh Sivaraj 8219399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 8229399ab61SSantosh Sivaraj &p->dcr_dma[id])) 8239399ab61SSantosh Sivaraj return -ENOMEM; 8249399ab61SSantosh Sivaraj 8259399ab61SSantosh Sivaraj d->address = p->dimm_dma[id]; 8269399ab61SSantosh Sivaraj 8279399ab61SSantosh Sivaraj ndtest_dimm_register(p, d, id); 8289399ab61SSantosh Sivaraj } 8299399ab61SSantosh Sivaraj 8309399ab61SSantosh Sivaraj return 0; 8319399ab61SSantosh Sivaraj } 8329399ab61SSantosh Sivaraj 833107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev, 834107b04e9SSantosh Sivaraj struct device_attribute *attr, char *buf) 835107b04e9SSantosh Sivaraj { 836107b04e9SSantosh Sivaraj return sprintf(buf, "nvdimm_test"); 837107b04e9SSantosh Sivaraj } 838107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible); 839107b04e9SSantosh Sivaraj 840107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = { 841107b04e9SSantosh Sivaraj &dev_attr_compatible.attr, 842107b04e9SSantosh Sivaraj NULL 843107b04e9SSantosh Sivaraj }; 844107b04e9SSantosh Sivaraj 845107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = { 846107b04e9SSantosh Sivaraj .name = "of_node", 847107b04e9SSantosh Sivaraj .attrs = of_node_attributes, 848107b04e9SSantosh Sivaraj }; 849107b04e9SSantosh Sivaraj 850107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = { 851107b04e9SSantosh Sivaraj &of_node_attribute_group, 852107b04e9SSantosh Sivaraj NULL, 853107b04e9SSantosh Sivaraj }; 854107b04e9SSantosh Sivaraj 8559a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p) 8569a27e109SSantosh Sivaraj { 8579399ab61SSantosh Sivaraj p->config = &bus_configs[p->pdev.id]; 8589399ab61SSantosh Sivaraj 8599a27e109SSantosh Sivaraj p->bus_desc.ndctl = ndtest_ctl; 8609a27e109SSantosh Sivaraj p->bus_desc.module = THIS_MODULE; 8619a27e109SSantosh Sivaraj p->bus_desc.provider_name = NULL; 862107b04e9SSantosh Sivaraj p->bus_desc.attr_groups = ndtest_attribute_groups; 8639a27e109SSantosh Sivaraj 8649a27e109SSantosh Sivaraj p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 8659a27e109SSantosh Sivaraj if (!p->bus) { 8669a27e109SSantosh Sivaraj dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 8679a27e109SSantosh Sivaraj return -ENOMEM; 8689a27e109SSantosh Sivaraj } 8699a27e109SSantosh Sivaraj 8709a27e109SSantosh Sivaraj return 0; 8719a27e109SSantosh Sivaraj } 8729a27e109SSantosh Sivaraj 8739a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev) 8749a27e109SSantosh Sivaraj { 8759a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 8769a27e109SSantosh Sivaraj 8779a27e109SSantosh Sivaraj nvdimm_bus_unregister(p->bus); 8789a27e109SSantosh Sivaraj return 0; 8799a27e109SSantosh Sivaraj } 8809a27e109SSantosh Sivaraj 8819a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev) 8829a27e109SSantosh Sivaraj { 8839a27e109SSantosh Sivaraj struct ndtest_priv *p; 8849399ab61SSantosh Sivaraj int rc; 8859a27e109SSantosh Sivaraj 8869a27e109SSantosh Sivaraj p = to_ndtest_priv(&pdev->dev); 8879a27e109SSantosh Sivaraj if (ndtest_bus_register(p)) 8889a27e109SSantosh Sivaraj return -ENOMEM; 8899a27e109SSantosh Sivaraj 8909399ab61SSantosh Sivaraj p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8919399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8929399ab61SSantosh Sivaraj p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8939399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8949399ab61SSantosh Sivaraj p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 8959399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 8969399ab61SSantosh Sivaraj 8979399ab61SSantosh Sivaraj rc = ndtest_nvdimm_init(p); 8989399ab61SSantosh Sivaraj if (rc) 8999399ab61SSantosh Sivaraj goto err; 9009399ab61SSantosh Sivaraj 901*6fde2d4cSSantosh Sivaraj rc = ndtest_init_regions(p); 902*6fde2d4cSSantosh Sivaraj if (rc) 903*6fde2d4cSSantosh Sivaraj goto err; 904*6fde2d4cSSantosh Sivaraj 9059399ab61SSantosh Sivaraj rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p); 9069399ab61SSantosh Sivaraj if (rc) 9079399ab61SSantosh Sivaraj goto err; 9089399ab61SSantosh Sivaraj 9099a27e109SSantosh Sivaraj platform_set_drvdata(pdev, p); 9109a27e109SSantosh Sivaraj 9119a27e109SSantosh Sivaraj return 0; 9129399ab61SSantosh Sivaraj 9139399ab61SSantosh Sivaraj err: 9149399ab61SSantosh Sivaraj pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__); 9159399ab61SSantosh Sivaraj return rc; 9169a27e109SSantosh Sivaraj } 9179a27e109SSantosh Sivaraj 9189a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = { 9199a27e109SSantosh Sivaraj { KBUILD_MODNAME }, 9209a27e109SSantosh Sivaraj { }, 9219a27e109SSantosh Sivaraj }; 9229a27e109SSantosh Sivaraj 9239a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = { 9249a27e109SSantosh Sivaraj .probe = ndtest_probe, 9259a27e109SSantosh Sivaraj .remove = ndtest_remove, 9269a27e109SSantosh Sivaraj .driver = { 9279a27e109SSantosh Sivaraj .name = KBUILD_MODNAME, 9289a27e109SSantosh Sivaraj }, 9299a27e109SSantosh Sivaraj .id_table = ndtest_id, 9309a27e109SSantosh Sivaraj }; 9319a27e109SSantosh Sivaraj 9329a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev) 9339a27e109SSantosh Sivaraj { 9349a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(dev); 9359a27e109SSantosh Sivaraj 9369a27e109SSantosh Sivaraj kfree(p); 9379a27e109SSantosh Sivaraj } 9389a27e109SSantosh Sivaraj 9399a27e109SSantosh Sivaraj static void cleanup_devices(void) 9409a27e109SSantosh Sivaraj { 9419a27e109SSantosh Sivaraj int i; 9429a27e109SSantosh Sivaraj 9439a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) 9449a27e109SSantosh Sivaraj if (instances[i]) 9459a27e109SSantosh Sivaraj platform_device_unregister(&instances[i]->pdev); 9469a27e109SSantosh Sivaraj 9479a27e109SSantosh Sivaraj nfit_test_teardown(); 9489a27e109SSantosh Sivaraj 9499399ab61SSantosh Sivaraj if (ndtest_pool) 9509399ab61SSantosh Sivaraj gen_pool_destroy(ndtest_pool); 9519399ab61SSantosh Sivaraj 9529399ab61SSantosh Sivaraj 9539a27e109SSantosh Sivaraj if (ndtest_dimm_class) 9549a27e109SSantosh Sivaraj class_destroy(ndtest_dimm_class); 9559a27e109SSantosh Sivaraj } 9569a27e109SSantosh Sivaraj 9579a27e109SSantosh Sivaraj static __init int ndtest_init(void) 9589a27e109SSantosh Sivaraj { 9599a27e109SSantosh Sivaraj int rc, i; 9609a27e109SSantosh Sivaraj 9619a27e109SSantosh Sivaraj pmem_test(); 9629a27e109SSantosh Sivaraj libnvdimm_test(); 9639a27e109SSantosh Sivaraj device_dax_test(); 9649a27e109SSantosh Sivaraj dax_pmem_test(); 9659a27e109SSantosh Sivaraj dax_pmem_core_test(); 9669a27e109SSantosh Sivaraj #ifdef CONFIG_DEV_DAX_PMEM_COMPAT 9679a27e109SSantosh Sivaraj dax_pmem_compat_test(); 9689a27e109SSantosh Sivaraj #endif 9699a27e109SSantosh Sivaraj 970*6fde2d4cSSantosh Sivaraj nfit_test_setup(ndtest_resource_lookup, NULL); 971*6fde2d4cSSantosh Sivaraj 9729a27e109SSantosh Sivaraj ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm"); 9739a27e109SSantosh Sivaraj if (IS_ERR(ndtest_dimm_class)) { 9749a27e109SSantosh Sivaraj rc = PTR_ERR(ndtest_dimm_class); 9759a27e109SSantosh Sivaraj goto err_register; 9769a27e109SSantosh Sivaraj } 9779a27e109SSantosh Sivaraj 9789399ab61SSantosh Sivaraj ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 9799399ab61SSantosh Sivaraj if (!ndtest_pool) { 9809399ab61SSantosh Sivaraj rc = -ENOMEM; 9819399ab61SSantosh Sivaraj goto err_register; 9829399ab61SSantosh Sivaraj } 9839399ab61SSantosh Sivaraj 9849399ab61SSantosh Sivaraj if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 9859399ab61SSantosh Sivaraj rc = -ENOMEM; 9869399ab61SSantosh Sivaraj goto err_register; 9879399ab61SSantosh Sivaraj } 9889399ab61SSantosh Sivaraj 9899a27e109SSantosh Sivaraj /* Each instance can be taken as a bus, which can have multiple dimms */ 9909a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 9919a27e109SSantosh Sivaraj struct ndtest_priv *priv; 9929a27e109SSantosh Sivaraj struct platform_device *pdev; 9939a27e109SSantosh Sivaraj 9949a27e109SSantosh Sivaraj priv = kzalloc(sizeof(*priv), GFP_KERNEL); 9959a27e109SSantosh Sivaraj if (!priv) { 9969a27e109SSantosh Sivaraj rc = -ENOMEM; 9979a27e109SSantosh Sivaraj goto err_register; 9989a27e109SSantosh Sivaraj } 9999a27e109SSantosh Sivaraj 10009a27e109SSantosh Sivaraj INIT_LIST_HEAD(&priv->resources); 10019a27e109SSantosh Sivaraj pdev = &priv->pdev; 10029a27e109SSantosh Sivaraj pdev->name = KBUILD_MODNAME; 10039a27e109SSantosh Sivaraj pdev->id = i; 10049a27e109SSantosh Sivaraj pdev->dev.release = ndtest_release; 10059a27e109SSantosh Sivaraj rc = platform_device_register(pdev); 10069a27e109SSantosh Sivaraj if (rc) { 10079a27e109SSantosh Sivaraj put_device(&pdev->dev); 10089a27e109SSantosh Sivaraj goto err_register; 10099a27e109SSantosh Sivaraj } 10109a27e109SSantosh Sivaraj get_device(&pdev->dev); 10119a27e109SSantosh Sivaraj 10129a27e109SSantosh Sivaraj instances[i] = priv; 10139a27e109SSantosh Sivaraj } 10149a27e109SSantosh Sivaraj 10159a27e109SSantosh Sivaraj rc = platform_driver_register(&ndtest_driver); 10169a27e109SSantosh Sivaraj if (rc) 10179a27e109SSantosh Sivaraj goto err_register; 10189a27e109SSantosh Sivaraj 10199a27e109SSantosh Sivaraj return 0; 10209a27e109SSantosh Sivaraj 10219a27e109SSantosh Sivaraj err_register: 10229a27e109SSantosh Sivaraj pr_err("Error registering platform device\n"); 10239a27e109SSantosh Sivaraj cleanup_devices(); 10249a27e109SSantosh Sivaraj 10259a27e109SSantosh Sivaraj return rc; 10269a27e109SSantosh Sivaraj } 10279a27e109SSantosh Sivaraj 10289a27e109SSantosh Sivaraj static __exit void ndtest_exit(void) 10299a27e109SSantosh Sivaraj { 10309a27e109SSantosh Sivaraj cleanup_devices(); 10319a27e109SSantosh Sivaraj platform_driver_unregister(&ndtest_driver); 10329a27e109SSantosh Sivaraj } 10339a27e109SSantosh Sivaraj 10349a27e109SSantosh Sivaraj module_init(ndtest_init); 10359a27e109SSantosh Sivaraj module_exit(ndtest_exit); 10369a27e109SSantosh Sivaraj MODULE_LICENSE("GPL"); 10379a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation"); 1038