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, 269a27e109SSantosh Sivaraj }; 279a27e109SSantosh Sivaraj 289399ab61SSantosh Sivaraj #define NDTEST_SCM_DIMM_CMD_MASK \ 299399ab61SSantosh Sivaraj ((1ul << ND_CMD_GET_CONFIG_SIZE) | \ 309399ab61SSantosh Sivaraj (1ul << ND_CMD_GET_CONFIG_DATA) | \ 319399ab61SSantosh Sivaraj (1ul << ND_CMD_SET_CONFIG_DATA) | \ 329399ab61SSantosh Sivaraj (1ul << ND_CMD_CALL)) 339399ab61SSantosh Sivaraj 349399ab61SSantosh Sivaraj #define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm) \ 359399ab61SSantosh Sivaraj (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \ 369399ab61SSantosh Sivaraj | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf)) 379399ab61SSantosh Sivaraj 389399ab61SSantosh Sivaraj static DEFINE_SPINLOCK(ndtest_lock); 399a27e109SSantosh Sivaraj static struct ndtest_priv *instances[NUM_INSTANCES]; 409a27e109SSantosh Sivaraj static struct class *ndtest_dimm_class; 419399ab61SSantosh Sivaraj static struct gen_pool *ndtest_pool; 429399ab61SSantosh Sivaraj 439399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group1[] = { 449399ab61SSantosh Sivaraj { 459399ab61SSantosh Sivaraj .size = DIMM_SIZE, 469399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0), 479399ab61SSantosh Sivaraj .uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72", 489399ab61SSantosh Sivaraj .physical_id = 0, 499399ab61SSantosh Sivaraj .num_formats = 2, 509399ab61SSantosh Sivaraj }, 519399ab61SSantosh Sivaraj { 529399ab61SSantosh Sivaraj .size = DIMM_SIZE, 539399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), 549399ab61SSantosh Sivaraj .uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72", 559399ab61SSantosh Sivaraj .physical_id = 1, 569399ab61SSantosh Sivaraj .num_formats = 2, 579399ab61SSantosh Sivaraj }, 589399ab61SSantosh Sivaraj { 599399ab61SSantosh Sivaraj .size = DIMM_SIZE, 609399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), 619399ab61SSantosh Sivaraj .uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72", 629399ab61SSantosh Sivaraj .physical_id = 2, 639399ab61SSantosh Sivaraj .num_formats = 2, 649399ab61SSantosh Sivaraj }, 659399ab61SSantosh Sivaraj { 669399ab61SSantosh Sivaraj .size = DIMM_SIZE, 679399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), 689399ab61SSantosh Sivaraj .uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72", 699399ab61SSantosh Sivaraj .physical_id = 3, 709399ab61SSantosh Sivaraj .num_formats = 2, 719399ab61SSantosh Sivaraj }, 729399ab61SSantosh Sivaraj { 739399ab61SSantosh Sivaraj .size = DIMM_SIZE, 749399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), 759399ab61SSantosh Sivaraj .uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72", 769399ab61SSantosh Sivaraj .physical_id = 4, 779399ab61SSantosh Sivaraj .num_formats = 2, 789399ab61SSantosh Sivaraj }, 799399ab61SSantosh Sivaraj }; 809399ab61SSantosh Sivaraj 819399ab61SSantosh Sivaraj static struct ndtest_dimm dimm_group2[] = { 829399ab61SSantosh Sivaraj { 839399ab61SSantosh Sivaraj .size = DIMM_SIZE, 849399ab61SSantosh Sivaraj .handle = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0), 859399ab61SSantosh Sivaraj .uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72", 869399ab61SSantosh Sivaraj .physical_id = 0, 879399ab61SSantosh Sivaraj .num_formats = 1, 889399ab61SSantosh Sivaraj }, 899399ab61SSantosh Sivaraj }; 909399ab61SSantosh Sivaraj 919399ab61SSantosh Sivaraj static struct ndtest_config bus_configs[NUM_INSTANCES] = { 929399ab61SSantosh Sivaraj /* bus 1 */ 939399ab61SSantosh Sivaraj { 949399ab61SSantosh Sivaraj .dimm_start = 0, 959399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group1), 969399ab61SSantosh Sivaraj .dimms = dimm_group1, 979399ab61SSantosh Sivaraj }, 989399ab61SSantosh Sivaraj /* bus 2 */ 999399ab61SSantosh Sivaraj { 1009399ab61SSantosh Sivaraj .dimm_start = ARRAY_SIZE(dimm_group1), 1019399ab61SSantosh Sivaraj .dimm_count = ARRAY_SIZE(dimm_group2), 1029399ab61SSantosh Sivaraj .dimms = dimm_group2, 1039399ab61SSantosh Sivaraj }, 1049399ab61SSantosh Sivaraj }; 1059a27e109SSantosh Sivaraj 1069a27e109SSantosh Sivaraj static inline struct ndtest_priv *to_ndtest_priv(struct device *dev) 1079a27e109SSantosh Sivaraj { 1089a27e109SSantosh Sivaraj struct platform_device *pdev = to_platform_device(dev); 1099a27e109SSantosh Sivaraj 1109a27e109SSantosh Sivaraj return container_of(pdev, struct ndtest_priv, pdev); 1119a27e109SSantosh Sivaraj } 1129a27e109SSantosh Sivaraj 1139a27e109SSantosh Sivaraj static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 1149a27e109SSantosh Sivaraj struct nvdimm *nvdimm, unsigned int cmd, void *buf, 1159a27e109SSantosh Sivaraj unsigned int buf_len, int *cmd_rc) 1169a27e109SSantosh Sivaraj { 1179a27e109SSantosh Sivaraj struct ndtest_dimm *dimm; 1189a27e109SSantosh Sivaraj int _cmd_rc; 1199a27e109SSantosh Sivaraj 1209a27e109SSantosh Sivaraj if (!cmd_rc) 1219a27e109SSantosh Sivaraj cmd_rc = &_cmd_rc; 1229a27e109SSantosh Sivaraj 1239a27e109SSantosh Sivaraj *cmd_rc = 0; 1249a27e109SSantosh Sivaraj 1259a27e109SSantosh Sivaraj if (!nvdimm) 1269a27e109SSantosh Sivaraj return -EINVAL; 1279a27e109SSantosh Sivaraj 1289a27e109SSantosh Sivaraj dimm = nvdimm_provider_data(nvdimm); 1299a27e109SSantosh Sivaraj if (!dimm) 1309a27e109SSantosh Sivaraj return -EINVAL; 1319a27e109SSantosh Sivaraj 1329a27e109SSantosh Sivaraj switch (cmd) { 1339a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_SIZE: 1349a27e109SSantosh Sivaraj case ND_CMD_GET_CONFIG_DATA: 1359a27e109SSantosh Sivaraj case ND_CMD_SET_CONFIG_DATA: 1369a27e109SSantosh Sivaraj default: 1379a27e109SSantosh Sivaraj return -EINVAL; 1389a27e109SSantosh Sivaraj } 1399a27e109SSantosh Sivaraj 1409a27e109SSantosh Sivaraj return 0; 1419a27e109SSantosh Sivaraj } 1429a27e109SSantosh Sivaraj 1439399ab61SSantosh Sivaraj static void ndtest_release_resource(void *data) 1449399ab61SSantosh Sivaraj { 1459399ab61SSantosh Sivaraj struct nfit_test_resource *res = data; 1469399ab61SSantosh Sivaraj 1479399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 1489399ab61SSantosh Sivaraj list_del(&res->list); 1499399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 1509399ab61SSantosh Sivaraj 1519399ab61SSantosh Sivaraj if (resource_size(&res->res) >= DIMM_SIZE) 1529399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, res->res.start, 1539399ab61SSantosh Sivaraj resource_size(&res->res)); 1549399ab61SSantosh Sivaraj vfree(res->buf); 1559399ab61SSantosh Sivaraj kfree(res); 1569399ab61SSantosh Sivaraj } 1579399ab61SSantosh Sivaraj 1589399ab61SSantosh Sivaraj static void *ndtest_alloc_resource(struct ndtest_priv *p, size_t size, 1599399ab61SSantosh Sivaraj dma_addr_t *dma) 1609399ab61SSantosh Sivaraj { 1619399ab61SSantosh Sivaraj dma_addr_t __dma; 1629399ab61SSantosh Sivaraj void *buf; 1639399ab61SSantosh Sivaraj struct nfit_test_resource *res; 1649399ab61SSantosh Sivaraj struct genpool_data_align data = { 1659399ab61SSantosh Sivaraj .align = SZ_128M, 1669399ab61SSantosh Sivaraj }; 1679399ab61SSantosh Sivaraj 1689399ab61SSantosh Sivaraj res = kzalloc(sizeof(*res), GFP_KERNEL); 1699399ab61SSantosh Sivaraj if (!res) 1709399ab61SSantosh Sivaraj return NULL; 1719399ab61SSantosh Sivaraj 1729399ab61SSantosh Sivaraj buf = vmalloc(size); 1739399ab61SSantosh Sivaraj if (size >= DIMM_SIZE) 1749399ab61SSantosh Sivaraj __dma = gen_pool_alloc_algo(ndtest_pool, size, 1759399ab61SSantosh Sivaraj gen_pool_first_fit_align, &data); 1769399ab61SSantosh Sivaraj else 1779399ab61SSantosh Sivaraj __dma = (unsigned long) buf; 1789399ab61SSantosh Sivaraj 1799399ab61SSantosh Sivaraj if (!__dma) 1809399ab61SSantosh Sivaraj goto buf_err; 1819399ab61SSantosh Sivaraj 1829399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->list); 1839399ab61SSantosh Sivaraj res->dev = &p->pdev.dev; 1849399ab61SSantosh Sivaraj res->buf = buf; 1859399ab61SSantosh Sivaraj res->res.start = __dma; 1869399ab61SSantosh Sivaraj res->res.end = __dma + size - 1; 1879399ab61SSantosh Sivaraj res->res.name = "NFIT"; 1889399ab61SSantosh Sivaraj spin_lock_init(&res->lock); 1899399ab61SSantosh Sivaraj INIT_LIST_HEAD(&res->requests); 1909399ab61SSantosh Sivaraj spin_lock(&ndtest_lock); 1919399ab61SSantosh Sivaraj list_add(&res->list, &p->resources); 1929399ab61SSantosh Sivaraj spin_unlock(&ndtest_lock); 1939399ab61SSantosh Sivaraj 1949399ab61SSantosh Sivaraj if (dma) 1959399ab61SSantosh Sivaraj *dma = __dma; 1969399ab61SSantosh Sivaraj 1979399ab61SSantosh Sivaraj if (!devm_add_action(&p->pdev.dev, ndtest_release_resource, res)) 1989399ab61SSantosh Sivaraj return res->buf; 1999399ab61SSantosh Sivaraj 2009399ab61SSantosh Sivaraj buf_err: 2019399ab61SSantosh Sivaraj if (__dma && size >= DIMM_SIZE) 2029399ab61SSantosh Sivaraj gen_pool_free(ndtest_pool, __dma, size); 2039399ab61SSantosh Sivaraj if (buf) 2049399ab61SSantosh Sivaraj vfree(buf); 2059399ab61SSantosh Sivaraj kfree(res); 2069399ab61SSantosh Sivaraj 2079399ab61SSantosh Sivaraj return NULL; 2089399ab61SSantosh Sivaraj } 2099399ab61SSantosh Sivaraj 2109399ab61SSantosh Sivaraj static void put_dimms(void *data) 2119399ab61SSantosh Sivaraj { 2129399ab61SSantosh Sivaraj struct ndtest_priv *p = data; 2139399ab61SSantosh Sivaraj int i; 2149399ab61SSantosh Sivaraj 2159399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) 2169399ab61SSantosh Sivaraj if (p->config->dimms[i].dev) { 2179399ab61SSantosh Sivaraj device_unregister(p->config->dimms[i].dev); 2189399ab61SSantosh Sivaraj p->config->dimms[i].dev = NULL; 2199399ab61SSantosh Sivaraj } 2209399ab61SSantosh Sivaraj } 2219399ab61SSantosh Sivaraj 222*5e41396fSSantosh Sivaraj static ssize_t handle_show(struct device *dev, struct device_attribute *attr, 223*5e41396fSSantosh Sivaraj char *buf) 224*5e41396fSSantosh Sivaraj { 225*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 226*5e41396fSSantosh Sivaraj 227*5e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 228*5e41396fSSantosh Sivaraj } 229*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(handle); 230*5e41396fSSantosh Sivaraj 231*5e41396fSSantosh Sivaraj static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 232*5e41396fSSantosh Sivaraj char *buf) 233*5e41396fSSantosh Sivaraj { 234*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 235*5e41396fSSantosh Sivaraj 236*5e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->fail_cmd); 237*5e41396fSSantosh Sivaraj } 238*5e41396fSSantosh Sivaraj 239*5e41396fSSantosh Sivaraj static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 240*5e41396fSSantosh Sivaraj const char *buf, size_t size) 241*5e41396fSSantosh Sivaraj { 242*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 243*5e41396fSSantosh Sivaraj unsigned long val; 244*5e41396fSSantosh Sivaraj ssize_t rc; 245*5e41396fSSantosh Sivaraj 246*5e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 247*5e41396fSSantosh Sivaraj if (rc) 248*5e41396fSSantosh Sivaraj return rc; 249*5e41396fSSantosh Sivaraj 250*5e41396fSSantosh Sivaraj dimm->fail_cmd = val; 251*5e41396fSSantosh Sivaraj 252*5e41396fSSantosh Sivaraj return size; 253*5e41396fSSantosh Sivaraj } 254*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd); 255*5e41396fSSantosh Sivaraj 256*5e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 257*5e41396fSSantosh Sivaraj char *buf) 258*5e41396fSSantosh Sivaraj { 259*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 260*5e41396fSSantosh Sivaraj 261*5e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->fail_cmd_code); 262*5e41396fSSantosh Sivaraj } 263*5e41396fSSantosh Sivaraj 264*5e41396fSSantosh Sivaraj static ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 265*5e41396fSSantosh Sivaraj const char *buf, size_t size) 266*5e41396fSSantosh Sivaraj { 267*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = dev_get_drvdata(dev); 268*5e41396fSSantosh Sivaraj unsigned long val; 269*5e41396fSSantosh Sivaraj ssize_t rc; 270*5e41396fSSantosh Sivaraj 271*5e41396fSSantosh Sivaraj rc = kstrtol(buf, 0, &val); 272*5e41396fSSantosh Sivaraj if (rc) 273*5e41396fSSantosh Sivaraj return rc; 274*5e41396fSSantosh Sivaraj 275*5e41396fSSantosh Sivaraj dimm->fail_cmd_code = val; 276*5e41396fSSantosh Sivaraj return size; 277*5e41396fSSantosh Sivaraj } 278*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RW(fail_cmd_code); 279*5e41396fSSantosh Sivaraj 280*5e41396fSSantosh Sivaraj static struct attribute *dimm_attributes[] = { 281*5e41396fSSantosh Sivaraj &dev_attr_handle.attr, 282*5e41396fSSantosh Sivaraj &dev_attr_fail_cmd.attr, 283*5e41396fSSantosh Sivaraj &dev_attr_fail_cmd_code.attr, 284*5e41396fSSantosh Sivaraj NULL, 285*5e41396fSSantosh Sivaraj }; 286*5e41396fSSantosh Sivaraj 287*5e41396fSSantosh Sivaraj static struct attribute_group dimm_attribute_group = { 288*5e41396fSSantosh Sivaraj .attrs = dimm_attributes, 289*5e41396fSSantosh Sivaraj }; 290*5e41396fSSantosh Sivaraj 291*5e41396fSSantosh Sivaraj static const struct attribute_group *dimm_attribute_groups[] = { 292*5e41396fSSantosh Sivaraj &dimm_attribute_group, 293*5e41396fSSantosh Sivaraj NULL, 294*5e41396fSSantosh Sivaraj }; 295*5e41396fSSantosh Sivaraj 296*5e41396fSSantosh Sivaraj static ssize_t phys_id_show(struct device *dev, 297*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 298*5e41396fSSantosh Sivaraj { 299*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 300*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 301*5e41396fSSantosh Sivaraj 302*5e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->physical_id); 303*5e41396fSSantosh Sivaraj } 304*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(phys_id); 305*5e41396fSSantosh Sivaraj 306*5e41396fSSantosh Sivaraj static ssize_t vendor_show(struct device *dev, 307*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 308*5e41396fSSantosh Sivaraj { 309*5e41396fSSantosh Sivaraj return sprintf(buf, "0x1234567\n"); 310*5e41396fSSantosh Sivaraj } 311*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(vendor); 312*5e41396fSSantosh Sivaraj 313*5e41396fSSantosh Sivaraj static ssize_t id_show(struct device *dev, 314*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 315*5e41396fSSantosh Sivaraj { 316*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 317*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 318*5e41396fSSantosh Sivaraj 319*5e41396fSSantosh Sivaraj return sprintf(buf, "%04x-%02x-%04x-%08x", 0xabcd, 320*5e41396fSSantosh Sivaraj 0xa, 2016, ~(dimm->handle)); 321*5e41396fSSantosh Sivaraj } 322*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(id); 323*5e41396fSSantosh Sivaraj 324*5e41396fSSantosh Sivaraj static ssize_t nvdimm_handle_show(struct device *dev, 325*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 326*5e41396fSSantosh Sivaraj { 327*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 328*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 329*5e41396fSSantosh Sivaraj 330*5e41396fSSantosh Sivaraj return sprintf(buf, "%#x\n", dimm->handle); 331*5e41396fSSantosh Sivaraj } 332*5e41396fSSantosh Sivaraj 333*5e41396fSSantosh Sivaraj static struct device_attribute dev_attr_nvdimm_show_handle = { 334*5e41396fSSantosh Sivaraj .attr = { .name = "handle", .mode = 0444 }, 335*5e41396fSSantosh Sivaraj .show = nvdimm_handle_show, 336*5e41396fSSantosh Sivaraj }; 337*5e41396fSSantosh Sivaraj 338*5e41396fSSantosh Sivaraj static ssize_t subsystem_vendor_show(struct device *dev, 339*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 340*5e41396fSSantosh Sivaraj { 341*5e41396fSSantosh Sivaraj return sprintf(buf, "0x%04x\n", 0); 342*5e41396fSSantosh Sivaraj } 343*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(subsystem_vendor); 344*5e41396fSSantosh Sivaraj 345*5e41396fSSantosh Sivaraj static ssize_t dirty_shutdown_show(struct device *dev, 346*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 347*5e41396fSSantosh Sivaraj { 348*5e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", 42); 349*5e41396fSSantosh Sivaraj } 350*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(dirty_shutdown); 351*5e41396fSSantosh Sivaraj 352*5e41396fSSantosh Sivaraj static ssize_t formats_show(struct device *dev, 353*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 354*5e41396fSSantosh Sivaraj { 355*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 356*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 357*5e41396fSSantosh Sivaraj 358*5e41396fSSantosh Sivaraj return sprintf(buf, "%d\n", dimm->num_formats); 359*5e41396fSSantosh Sivaraj } 360*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(formats); 361*5e41396fSSantosh Sivaraj 362*5e41396fSSantosh Sivaraj static ssize_t format_show(struct device *dev, 363*5e41396fSSantosh Sivaraj struct device_attribute *attr, char *buf) 364*5e41396fSSantosh Sivaraj { 365*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 366*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 367*5e41396fSSantosh Sivaraj 368*5e41396fSSantosh Sivaraj if (dimm->num_formats > 1) 369*5e41396fSSantosh Sivaraj return sprintf(buf, "0x201\n"); 370*5e41396fSSantosh Sivaraj 371*5e41396fSSantosh Sivaraj return sprintf(buf, "0x101\n"); 372*5e41396fSSantosh Sivaraj } 373*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format); 374*5e41396fSSantosh Sivaraj 375*5e41396fSSantosh Sivaraj static ssize_t format1_show(struct device *dev, struct device_attribute *attr, 376*5e41396fSSantosh Sivaraj char *buf) 377*5e41396fSSantosh Sivaraj { 378*5e41396fSSantosh Sivaraj return sprintf(buf, "0x301\n"); 379*5e41396fSSantosh Sivaraj } 380*5e41396fSSantosh Sivaraj static DEVICE_ATTR_RO(format1); 381*5e41396fSSantosh Sivaraj 382*5e41396fSSantosh Sivaraj static umode_t ndtest_nvdimm_attr_visible(struct kobject *kobj, 383*5e41396fSSantosh Sivaraj struct attribute *a, int n) 384*5e41396fSSantosh Sivaraj { 385*5e41396fSSantosh Sivaraj struct device *dev = container_of(kobj, struct device, kobj); 386*5e41396fSSantosh Sivaraj struct nvdimm *nvdimm = to_nvdimm(dev); 387*5e41396fSSantosh Sivaraj struct ndtest_dimm *dimm = nvdimm_provider_data(nvdimm); 388*5e41396fSSantosh Sivaraj 389*5e41396fSSantosh Sivaraj if (a == &dev_attr_format1.attr && dimm->num_formats <= 1) 390*5e41396fSSantosh Sivaraj return 0; 391*5e41396fSSantosh Sivaraj 392*5e41396fSSantosh Sivaraj return a->mode; 393*5e41396fSSantosh Sivaraj } 394*5e41396fSSantosh Sivaraj 395*5e41396fSSantosh Sivaraj static struct attribute *ndtest_nvdimm_attributes[] = { 396*5e41396fSSantosh Sivaraj &dev_attr_nvdimm_show_handle.attr, 397*5e41396fSSantosh Sivaraj &dev_attr_vendor.attr, 398*5e41396fSSantosh Sivaraj &dev_attr_id.attr, 399*5e41396fSSantosh Sivaraj &dev_attr_phys_id.attr, 400*5e41396fSSantosh Sivaraj &dev_attr_subsystem_vendor.attr, 401*5e41396fSSantosh Sivaraj &dev_attr_dirty_shutdown.attr, 402*5e41396fSSantosh Sivaraj &dev_attr_formats.attr, 403*5e41396fSSantosh Sivaraj &dev_attr_format.attr, 404*5e41396fSSantosh Sivaraj &dev_attr_format1.attr, 405*5e41396fSSantosh Sivaraj NULL, 406*5e41396fSSantosh Sivaraj }; 407*5e41396fSSantosh Sivaraj 408*5e41396fSSantosh Sivaraj static const struct attribute_group ndtest_nvdimm_attribute_group = { 409*5e41396fSSantosh Sivaraj .name = "papr", 410*5e41396fSSantosh Sivaraj .attrs = ndtest_nvdimm_attributes, 411*5e41396fSSantosh Sivaraj .is_visible = ndtest_nvdimm_attr_visible, 412*5e41396fSSantosh Sivaraj }; 413*5e41396fSSantosh Sivaraj 414*5e41396fSSantosh Sivaraj static const struct attribute_group *ndtest_nvdimm_attribute_groups[] = { 415*5e41396fSSantosh Sivaraj &ndtest_nvdimm_attribute_group, 416*5e41396fSSantosh Sivaraj NULL, 417*5e41396fSSantosh Sivaraj }; 418*5e41396fSSantosh Sivaraj 4199399ab61SSantosh Sivaraj static int ndtest_dimm_register(struct ndtest_priv *priv, 4209399ab61SSantosh Sivaraj struct ndtest_dimm *dimm, int id) 4219399ab61SSantosh Sivaraj { 4229399ab61SSantosh Sivaraj struct device *dev = &priv->pdev.dev; 4239399ab61SSantosh Sivaraj unsigned long dimm_flags = dimm->flags; 4249399ab61SSantosh Sivaraj 4259399ab61SSantosh Sivaraj if (dimm->num_formats > 1) { 4269399ab61SSantosh Sivaraj set_bit(NDD_ALIASING, &dimm_flags); 4279399ab61SSantosh Sivaraj set_bit(NDD_LABELING, &dimm_flags); 4289399ab61SSantosh Sivaraj } 4299399ab61SSantosh Sivaraj 430*5e41396fSSantosh Sivaraj dimm->nvdimm = nvdimm_create(priv->bus, dimm, 431*5e41396fSSantosh Sivaraj ndtest_nvdimm_attribute_groups, dimm_flags, 4329399ab61SSantosh Sivaraj NDTEST_SCM_DIMM_CMD_MASK, 0, NULL); 4339399ab61SSantosh Sivaraj if (!dimm->nvdimm) { 4349399ab61SSantosh Sivaraj dev_err(dev, "Error creating DIMM object for %pOF\n", priv->dn); 4359399ab61SSantosh Sivaraj return -ENXIO; 4369399ab61SSantosh Sivaraj } 4379399ab61SSantosh Sivaraj 4389399ab61SSantosh Sivaraj dimm->dev = device_create_with_groups(ndtest_dimm_class, 4399399ab61SSantosh Sivaraj &priv->pdev.dev, 440*5e41396fSSantosh Sivaraj 0, dimm, dimm_attribute_groups, 4419399ab61SSantosh Sivaraj "test_dimm%d", id); 4429399ab61SSantosh Sivaraj if (!dimm->dev) { 4439399ab61SSantosh Sivaraj pr_err("Could not create dimm device attributes\n"); 4449399ab61SSantosh Sivaraj return -ENOMEM; 4459399ab61SSantosh Sivaraj } 4469399ab61SSantosh Sivaraj 4479399ab61SSantosh Sivaraj return 0; 4489399ab61SSantosh Sivaraj } 4499399ab61SSantosh Sivaraj 4509399ab61SSantosh Sivaraj static int ndtest_nvdimm_init(struct ndtest_priv *p) 4519399ab61SSantosh Sivaraj { 4529399ab61SSantosh Sivaraj struct ndtest_dimm *d; 4539399ab61SSantosh Sivaraj void *res; 4549399ab61SSantosh Sivaraj int i, id; 4559399ab61SSantosh Sivaraj 4569399ab61SSantosh Sivaraj for (i = 0; i < p->config->dimm_count; i++) { 4579399ab61SSantosh Sivaraj d = &p->config->dimms[i]; 4589399ab61SSantosh Sivaraj d->id = id = p->config->dimm_start + i; 4599399ab61SSantosh Sivaraj res = ndtest_alloc_resource(p, LABEL_SIZE, NULL); 4609399ab61SSantosh Sivaraj if (!res) 4619399ab61SSantosh Sivaraj return -ENOMEM; 4629399ab61SSantosh Sivaraj 4639399ab61SSantosh Sivaraj d->label_area = res; 4649399ab61SSantosh Sivaraj sprintf(d->label_area, "label%d", id); 4659399ab61SSantosh Sivaraj d->config_size = LABEL_SIZE; 4669399ab61SSantosh Sivaraj 4679399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, d->size, 4689399ab61SSantosh Sivaraj &p->dimm_dma[id])) 4699399ab61SSantosh Sivaraj return -ENOMEM; 4709399ab61SSantosh Sivaraj 4719399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 4729399ab61SSantosh Sivaraj &p->label_dma[id])) 4739399ab61SSantosh Sivaraj return -ENOMEM; 4749399ab61SSantosh Sivaraj 4759399ab61SSantosh Sivaraj if (!ndtest_alloc_resource(p, LABEL_SIZE, 4769399ab61SSantosh Sivaraj &p->dcr_dma[id])) 4779399ab61SSantosh Sivaraj return -ENOMEM; 4789399ab61SSantosh Sivaraj 4799399ab61SSantosh Sivaraj d->address = p->dimm_dma[id]; 4809399ab61SSantosh Sivaraj 4819399ab61SSantosh Sivaraj ndtest_dimm_register(p, d, id); 4829399ab61SSantosh Sivaraj } 4839399ab61SSantosh Sivaraj 4849399ab61SSantosh Sivaraj return 0; 4859399ab61SSantosh Sivaraj } 4869399ab61SSantosh Sivaraj 487107b04e9SSantosh Sivaraj static ssize_t compatible_show(struct device *dev, 488107b04e9SSantosh Sivaraj struct device_attribute *attr, char *buf) 489107b04e9SSantosh Sivaraj { 490107b04e9SSantosh Sivaraj return sprintf(buf, "nvdimm_test"); 491107b04e9SSantosh Sivaraj } 492107b04e9SSantosh Sivaraj static DEVICE_ATTR_RO(compatible); 493107b04e9SSantosh Sivaraj 494107b04e9SSantosh Sivaraj static struct attribute *of_node_attributes[] = { 495107b04e9SSantosh Sivaraj &dev_attr_compatible.attr, 496107b04e9SSantosh Sivaraj NULL 497107b04e9SSantosh Sivaraj }; 498107b04e9SSantosh Sivaraj 499107b04e9SSantosh Sivaraj static const struct attribute_group of_node_attribute_group = { 500107b04e9SSantosh Sivaraj .name = "of_node", 501107b04e9SSantosh Sivaraj .attrs = of_node_attributes, 502107b04e9SSantosh Sivaraj }; 503107b04e9SSantosh Sivaraj 504107b04e9SSantosh Sivaraj static const struct attribute_group *ndtest_attribute_groups[] = { 505107b04e9SSantosh Sivaraj &of_node_attribute_group, 506107b04e9SSantosh Sivaraj NULL, 507107b04e9SSantosh Sivaraj }; 508107b04e9SSantosh Sivaraj 5099a27e109SSantosh Sivaraj static int ndtest_bus_register(struct ndtest_priv *p) 5109a27e109SSantosh Sivaraj { 5119399ab61SSantosh Sivaraj p->config = &bus_configs[p->pdev.id]; 5129399ab61SSantosh Sivaraj 5139a27e109SSantosh Sivaraj p->bus_desc.ndctl = ndtest_ctl; 5149a27e109SSantosh Sivaraj p->bus_desc.module = THIS_MODULE; 5159a27e109SSantosh Sivaraj p->bus_desc.provider_name = NULL; 516107b04e9SSantosh Sivaraj p->bus_desc.attr_groups = ndtest_attribute_groups; 5179a27e109SSantosh Sivaraj 5189a27e109SSantosh Sivaraj p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 5199a27e109SSantosh Sivaraj if (!p->bus) { 5209a27e109SSantosh Sivaraj dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 5219a27e109SSantosh Sivaraj return -ENOMEM; 5229a27e109SSantosh Sivaraj } 5239a27e109SSantosh Sivaraj 5249a27e109SSantosh Sivaraj return 0; 5259a27e109SSantosh Sivaraj } 5269a27e109SSantosh Sivaraj 5279a27e109SSantosh Sivaraj static int ndtest_remove(struct platform_device *pdev) 5289a27e109SSantosh Sivaraj { 5299a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 5309a27e109SSantosh Sivaraj 5319a27e109SSantosh Sivaraj nvdimm_bus_unregister(p->bus); 5329a27e109SSantosh Sivaraj return 0; 5339a27e109SSantosh Sivaraj } 5349a27e109SSantosh Sivaraj 5359a27e109SSantosh Sivaraj static int ndtest_probe(struct platform_device *pdev) 5369a27e109SSantosh Sivaraj { 5379a27e109SSantosh Sivaraj struct ndtest_priv *p; 5389399ab61SSantosh Sivaraj int rc; 5399a27e109SSantosh Sivaraj 5409a27e109SSantosh Sivaraj p = to_ndtest_priv(&pdev->dev); 5419a27e109SSantosh Sivaraj if (ndtest_bus_register(p)) 5429a27e109SSantosh Sivaraj return -ENOMEM; 5439a27e109SSantosh Sivaraj 5449399ab61SSantosh Sivaraj p->dcr_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 5459399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 5469399ab61SSantosh Sivaraj p->label_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 5479399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 5489399ab61SSantosh Sivaraj p->dimm_dma = devm_kcalloc(&p->pdev.dev, NUM_DCR, 5499399ab61SSantosh Sivaraj sizeof(dma_addr_t), GFP_KERNEL); 5509399ab61SSantosh Sivaraj 5519399ab61SSantosh Sivaraj rc = ndtest_nvdimm_init(p); 5529399ab61SSantosh Sivaraj if (rc) 5539399ab61SSantosh Sivaraj goto err; 5549399ab61SSantosh Sivaraj 5559399ab61SSantosh Sivaraj rc = devm_add_action_or_reset(&pdev->dev, put_dimms, p); 5569399ab61SSantosh Sivaraj if (rc) 5579399ab61SSantosh Sivaraj goto err; 5589399ab61SSantosh Sivaraj 5599a27e109SSantosh Sivaraj platform_set_drvdata(pdev, p); 5609a27e109SSantosh Sivaraj 5619a27e109SSantosh Sivaraj return 0; 5629399ab61SSantosh Sivaraj 5639399ab61SSantosh Sivaraj err: 5649399ab61SSantosh Sivaraj pr_err("%s:%d Failed nvdimm init\n", __func__, __LINE__); 5659399ab61SSantosh Sivaraj return rc; 5669a27e109SSantosh Sivaraj } 5679a27e109SSantosh Sivaraj 5689a27e109SSantosh Sivaraj static const struct platform_device_id ndtest_id[] = { 5699a27e109SSantosh Sivaraj { KBUILD_MODNAME }, 5709a27e109SSantosh Sivaraj { }, 5719a27e109SSantosh Sivaraj }; 5729a27e109SSantosh Sivaraj 5739a27e109SSantosh Sivaraj static struct platform_driver ndtest_driver = { 5749a27e109SSantosh Sivaraj .probe = ndtest_probe, 5759a27e109SSantosh Sivaraj .remove = ndtest_remove, 5769a27e109SSantosh Sivaraj .driver = { 5779a27e109SSantosh Sivaraj .name = KBUILD_MODNAME, 5789a27e109SSantosh Sivaraj }, 5799a27e109SSantosh Sivaraj .id_table = ndtest_id, 5809a27e109SSantosh Sivaraj }; 5819a27e109SSantosh Sivaraj 5829a27e109SSantosh Sivaraj static void ndtest_release(struct device *dev) 5839a27e109SSantosh Sivaraj { 5849a27e109SSantosh Sivaraj struct ndtest_priv *p = to_ndtest_priv(dev); 5859a27e109SSantosh Sivaraj 5869a27e109SSantosh Sivaraj kfree(p); 5879a27e109SSantosh Sivaraj } 5889a27e109SSantosh Sivaraj 5899a27e109SSantosh Sivaraj static void cleanup_devices(void) 5909a27e109SSantosh Sivaraj { 5919a27e109SSantosh Sivaraj int i; 5929a27e109SSantosh Sivaraj 5939a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) 5949a27e109SSantosh Sivaraj if (instances[i]) 5959a27e109SSantosh Sivaraj platform_device_unregister(&instances[i]->pdev); 5969a27e109SSantosh Sivaraj 5979a27e109SSantosh Sivaraj nfit_test_teardown(); 5989a27e109SSantosh Sivaraj 5999399ab61SSantosh Sivaraj if (ndtest_pool) 6009399ab61SSantosh Sivaraj gen_pool_destroy(ndtest_pool); 6019399ab61SSantosh Sivaraj 6029399ab61SSantosh Sivaraj 6039a27e109SSantosh Sivaraj if (ndtest_dimm_class) 6049a27e109SSantosh Sivaraj class_destroy(ndtest_dimm_class); 6059a27e109SSantosh Sivaraj } 6069a27e109SSantosh Sivaraj 6079a27e109SSantosh Sivaraj static __init int ndtest_init(void) 6089a27e109SSantosh Sivaraj { 6099a27e109SSantosh Sivaraj int rc, i; 6109a27e109SSantosh Sivaraj 6119a27e109SSantosh Sivaraj pmem_test(); 6129a27e109SSantosh Sivaraj libnvdimm_test(); 6139a27e109SSantosh Sivaraj device_dax_test(); 6149a27e109SSantosh Sivaraj dax_pmem_test(); 6159a27e109SSantosh Sivaraj dax_pmem_core_test(); 6169a27e109SSantosh Sivaraj #ifdef CONFIG_DEV_DAX_PMEM_COMPAT 6179a27e109SSantosh Sivaraj dax_pmem_compat_test(); 6189a27e109SSantosh Sivaraj #endif 6199a27e109SSantosh Sivaraj 6209a27e109SSantosh Sivaraj ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm"); 6219a27e109SSantosh Sivaraj if (IS_ERR(ndtest_dimm_class)) { 6229a27e109SSantosh Sivaraj rc = PTR_ERR(ndtest_dimm_class); 6239a27e109SSantosh Sivaraj goto err_register; 6249a27e109SSantosh Sivaraj } 6259a27e109SSantosh Sivaraj 6269399ab61SSantosh Sivaraj ndtest_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 6279399ab61SSantosh Sivaraj if (!ndtest_pool) { 6289399ab61SSantosh Sivaraj rc = -ENOMEM; 6299399ab61SSantosh Sivaraj goto err_register; 6309399ab61SSantosh Sivaraj } 6319399ab61SSantosh Sivaraj 6329399ab61SSantosh Sivaraj if (gen_pool_add(ndtest_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 6339399ab61SSantosh Sivaraj rc = -ENOMEM; 6349399ab61SSantosh Sivaraj goto err_register; 6359399ab61SSantosh Sivaraj } 6369399ab61SSantosh Sivaraj 6379a27e109SSantosh Sivaraj /* Each instance can be taken as a bus, which can have multiple dimms */ 6389a27e109SSantosh Sivaraj for (i = 0; i < NUM_INSTANCES; i++) { 6399a27e109SSantosh Sivaraj struct ndtest_priv *priv; 6409a27e109SSantosh Sivaraj struct platform_device *pdev; 6419a27e109SSantosh Sivaraj 6429a27e109SSantosh Sivaraj priv = kzalloc(sizeof(*priv), GFP_KERNEL); 6439a27e109SSantosh Sivaraj if (!priv) { 6449a27e109SSantosh Sivaraj rc = -ENOMEM; 6459a27e109SSantosh Sivaraj goto err_register; 6469a27e109SSantosh Sivaraj } 6479a27e109SSantosh Sivaraj 6489a27e109SSantosh Sivaraj INIT_LIST_HEAD(&priv->resources); 6499a27e109SSantosh Sivaraj pdev = &priv->pdev; 6509a27e109SSantosh Sivaraj pdev->name = KBUILD_MODNAME; 6519a27e109SSantosh Sivaraj pdev->id = i; 6529a27e109SSantosh Sivaraj pdev->dev.release = ndtest_release; 6539a27e109SSantosh Sivaraj rc = platform_device_register(pdev); 6549a27e109SSantosh Sivaraj if (rc) { 6559a27e109SSantosh Sivaraj put_device(&pdev->dev); 6569a27e109SSantosh Sivaraj goto err_register; 6579a27e109SSantosh Sivaraj } 6589a27e109SSantosh Sivaraj get_device(&pdev->dev); 6599a27e109SSantosh Sivaraj 6609a27e109SSantosh Sivaraj instances[i] = priv; 6619a27e109SSantosh Sivaraj } 6629a27e109SSantosh Sivaraj 6639a27e109SSantosh Sivaraj rc = platform_driver_register(&ndtest_driver); 6649a27e109SSantosh Sivaraj if (rc) 6659a27e109SSantosh Sivaraj goto err_register; 6669a27e109SSantosh Sivaraj 6679a27e109SSantosh Sivaraj return 0; 6689a27e109SSantosh Sivaraj 6699a27e109SSantosh Sivaraj err_register: 6709a27e109SSantosh Sivaraj pr_err("Error registering platform device\n"); 6719a27e109SSantosh Sivaraj cleanup_devices(); 6729a27e109SSantosh Sivaraj 6739a27e109SSantosh Sivaraj return rc; 6749a27e109SSantosh Sivaraj } 6759a27e109SSantosh Sivaraj 6769a27e109SSantosh Sivaraj static __exit void ndtest_exit(void) 6779a27e109SSantosh Sivaraj { 6789a27e109SSantosh Sivaraj cleanup_devices(); 6799a27e109SSantosh Sivaraj platform_driver_unregister(&ndtest_driver); 6809a27e109SSantosh Sivaraj } 6819a27e109SSantosh Sivaraj 6829a27e109SSantosh Sivaraj module_init(ndtest_init); 6839a27e109SSantosh Sivaraj module_exit(ndtest_exit); 6849a27e109SSantosh Sivaraj MODULE_LICENSE("GPL"); 6859a27e109SSantosh Sivaraj MODULE_AUTHOR("IBM Corporation"); 686