1 // SPDX-License-Identifier: GPL-2.0-only 2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3 4 #include <linux/platform_device.h> 5 #include <linux/device.h> 6 #include <linux/module.h> 7 #include <linux/genalloc.h> 8 #include <linux/vmalloc.h> 9 #include <linux/dma-mapping.h> 10 #include <linux/list_sort.h> 11 #include <linux/libnvdimm.h> 12 #include <linux/ndctl.h> 13 #include <nd-core.h> 14 #include <linux/printk.h> 15 #include <linux/seq_buf.h> 16 17 #include "../watermark.h" 18 #include "nfit_test.h" 19 #include "ndtest.h" 20 21 enum { 22 DIMM_SIZE = SZ_32M, 23 LABEL_SIZE = SZ_128K, 24 NUM_INSTANCES = 2, 25 NUM_DCR = 4, 26 }; 27 28 static struct ndtest_priv *instances[NUM_INSTANCES]; 29 static struct class *ndtest_dimm_class; 30 31 static inline struct ndtest_priv *to_ndtest_priv(struct device *dev) 32 { 33 struct platform_device *pdev = to_platform_device(dev); 34 35 return container_of(pdev, struct ndtest_priv, pdev); 36 } 37 38 static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc, 39 struct nvdimm *nvdimm, unsigned int cmd, void *buf, 40 unsigned int buf_len, int *cmd_rc) 41 { 42 struct ndtest_dimm *dimm; 43 int _cmd_rc; 44 45 if (!cmd_rc) 46 cmd_rc = &_cmd_rc; 47 48 *cmd_rc = 0; 49 50 if (!nvdimm) 51 return -EINVAL; 52 53 dimm = nvdimm_provider_data(nvdimm); 54 if (!dimm) 55 return -EINVAL; 56 57 switch (cmd) { 58 case ND_CMD_GET_CONFIG_SIZE: 59 case ND_CMD_GET_CONFIG_DATA: 60 case ND_CMD_SET_CONFIG_DATA: 61 default: 62 return -EINVAL; 63 } 64 65 return 0; 66 } 67 68 static ssize_t compatible_show(struct device *dev, 69 struct device_attribute *attr, char *buf) 70 { 71 return sprintf(buf, "nvdimm_test"); 72 } 73 static DEVICE_ATTR_RO(compatible); 74 75 static struct attribute *of_node_attributes[] = { 76 &dev_attr_compatible.attr, 77 NULL 78 }; 79 80 static const struct attribute_group of_node_attribute_group = { 81 .name = "of_node", 82 .attrs = of_node_attributes, 83 }; 84 85 static const struct attribute_group *ndtest_attribute_groups[] = { 86 &of_node_attribute_group, 87 NULL, 88 }; 89 90 static int ndtest_bus_register(struct ndtest_priv *p) 91 { 92 p->bus_desc.ndctl = ndtest_ctl; 93 p->bus_desc.module = THIS_MODULE; 94 p->bus_desc.provider_name = NULL; 95 p->bus_desc.attr_groups = ndtest_attribute_groups; 96 97 p->bus = nvdimm_bus_register(&p->pdev.dev, &p->bus_desc); 98 if (!p->bus) { 99 dev_err(&p->pdev.dev, "Error creating nvdimm bus %pOF\n", p->dn); 100 return -ENOMEM; 101 } 102 103 return 0; 104 } 105 106 static int ndtest_remove(struct platform_device *pdev) 107 { 108 struct ndtest_priv *p = to_ndtest_priv(&pdev->dev); 109 110 nvdimm_bus_unregister(p->bus); 111 return 0; 112 } 113 114 static int ndtest_probe(struct platform_device *pdev) 115 { 116 struct ndtest_priv *p; 117 118 p = to_ndtest_priv(&pdev->dev); 119 if (ndtest_bus_register(p)) 120 return -ENOMEM; 121 122 platform_set_drvdata(pdev, p); 123 124 return 0; 125 } 126 127 static const struct platform_device_id ndtest_id[] = { 128 { KBUILD_MODNAME }, 129 { }, 130 }; 131 132 static struct platform_driver ndtest_driver = { 133 .probe = ndtest_probe, 134 .remove = ndtest_remove, 135 .driver = { 136 .name = KBUILD_MODNAME, 137 }, 138 .id_table = ndtest_id, 139 }; 140 141 static void ndtest_release(struct device *dev) 142 { 143 struct ndtest_priv *p = to_ndtest_priv(dev); 144 145 kfree(p); 146 } 147 148 static void cleanup_devices(void) 149 { 150 int i; 151 152 for (i = 0; i < NUM_INSTANCES; i++) 153 if (instances[i]) 154 platform_device_unregister(&instances[i]->pdev); 155 156 nfit_test_teardown(); 157 158 if (ndtest_dimm_class) 159 class_destroy(ndtest_dimm_class); 160 } 161 162 static __init int ndtest_init(void) 163 { 164 int rc, i; 165 166 pmem_test(); 167 libnvdimm_test(); 168 device_dax_test(); 169 dax_pmem_test(); 170 dax_pmem_core_test(); 171 #ifdef CONFIG_DEV_DAX_PMEM_COMPAT 172 dax_pmem_compat_test(); 173 #endif 174 175 ndtest_dimm_class = class_create(THIS_MODULE, "nfit_test_dimm"); 176 if (IS_ERR(ndtest_dimm_class)) { 177 rc = PTR_ERR(ndtest_dimm_class); 178 goto err_register; 179 } 180 181 /* Each instance can be taken as a bus, which can have multiple dimms */ 182 for (i = 0; i < NUM_INSTANCES; i++) { 183 struct ndtest_priv *priv; 184 struct platform_device *pdev; 185 186 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 187 if (!priv) { 188 rc = -ENOMEM; 189 goto err_register; 190 } 191 192 INIT_LIST_HEAD(&priv->resources); 193 pdev = &priv->pdev; 194 pdev->name = KBUILD_MODNAME; 195 pdev->id = i; 196 pdev->dev.release = ndtest_release; 197 rc = platform_device_register(pdev); 198 if (rc) { 199 put_device(&pdev->dev); 200 goto err_register; 201 } 202 get_device(&pdev->dev); 203 204 instances[i] = priv; 205 } 206 207 rc = platform_driver_register(&ndtest_driver); 208 if (rc) 209 goto err_register; 210 211 return 0; 212 213 err_register: 214 pr_err("Error registering platform device\n"); 215 cleanup_devices(); 216 217 return rc; 218 } 219 220 static __exit void ndtest_exit(void) 221 { 222 cleanup_devices(); 223 platform_driver_unregister(&ndtest_driver); 224 } 225 226 module_init(ndtest_init); 227 module_exit(ndtest_exit); 228 MODULE_LICENSE("GPL"); 229 MODULE_AUTHOR("IBM Corporation"); 230