diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2016-10-07 19:46:24 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2016-10-07 19:46:24 -0400 |
| commit | 178d6f4be8bf42b298bedf8ea2a00754100e0c4e (patch) | |
| tree | a71865455adc31082a4ad21a942286520a7b5da1 /tools/testing | |
| parent | db58028ee4e360430de8e3b48f657dc798ee6591 (diff) | |
| parent | 98a29c39dc689298d2f834f40102cba752eb49c0 (diff) | |
Merge branch 'for-4.9/libnvdimm' into libnvdimm-for-next
Diffstat (limited to 'tools/testing')
| -rw-r--r-- | tools/testing/nvdimm/Kbuild | 1 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/iomap.c | 151 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 160 | ||||
| -rw-r--r-- | tools/testing/nvdimm/test/nfit_test.h | 12 |
4 files changed, 276 insertions, 48 deletions
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index ad6dd0543019..582db95127ed 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
| @@ -13,6 +13,7 @@ ldflags-y += --wrap=__release_region | |||
| 13 | ldflags-y += --wrap=devm_memremap_pages | 13 | ldflags-y += --wrap=devm_memremap_pages |
| 14 | ldflags-y += --wrap=insert_resource | 14 | ldflags-y += --wrap=insert_resource |
| 15 | ldflags-y += --wrap=remove_resource | 15 | ldflags-y += --wrap=remove_resource |
| 16 | ldflags-y += --wrap=acpi_evaluate_object | ||
| 16 | 17 | ||
| 17 | DRIVERS := ../../../drivers | 18 | DRIVERS := ../../../drivers |
| 18 | NVDIMM_SRC := $(DRIVERS)/nvdimm | 19 | NVDIMM_SRC := $(DRIVERS)/nvdimm |
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index c29f8dca9e67..3ccef732fce9 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 19 | #include <linux/pfn_t.h> | 19 | #include <linux/pfn_t.h> |
| 20 | #include <linux/acpi.h> | ||
| 20 | #include <linux/io.h> | 21 | #include <linux/io.h> |
| 21 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
| 22 | #include "nfit_test.h" | 23 | #include "nfit_test.h" |
| @@ -73,7 +74,7 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, | |||
| 73 | 74 | ||
| 74 | if (nfit_res) | 75 | if (nfit_res) |
| 75 | return (void __iomem *) nfit_res->buf + offset | 76 | return (void __iomem *) nfit_res->buf + offset |
| 76 | - nfit_res->res->start; | 77 | - nfit_res->res.start; |
| 77 | return fallback_fn(offset, size); | 78 | return fallback_fn(offset, size); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| @@ -84,7 +85,7 @@ void __iomem *__wrap_devm_ioremap_nocache(struct device *dev, | |||
| 84 | 85 | ||
| 85 | if (nfit_res) | 86 | if (nfit_res) |
| 86 | return (void __iomem *) nfit_res->buf + offset | 87 | return (void __iomem *) nfit_res->buf + offset |
| 87 | - nfit_res->res->start; | 88 | - nfit_res->res.start; |
| 88 | return devm_ioremap_nocache(dev, offset, size); | 89 | return devm_ioremap_nocache(dev, offset, size); |
| 89 | } | 90 | } |
| 90 | EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); | 91 | EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); |
| @@ -95,7 +96,7 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset, | |||
| 95 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | 96 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
| 96 | 97 | ||
| 97 | if (nfit_res) | 98 | if (nfit_res) |
| 98 | return nfit_res->buf + offset - nfit_res->res->start; | 99 | return nfit_res->buf + offset - nfit_res->res.start; |
| 99 | return devm_memremap(dev, offset, size, flags); | 100 | return devm_memremap(dev, offset, size, flags); |
| 100 | } | 101 | } |
| 101 | EXPORT_SYMBOL(__wrap_devm_memremap); | 102 | EXPORT_SYMBOL(__wrap_devm_memremap); |
| @@ -107,7 +108,7 @@ void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res, | |||
| 107 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | 108 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
| 108 | 109 | ||
| 109 | if (nfit_res) | 110 | if (nfit_res) |
| 110 | return nfit_res->buf + offset - nfit_res->res->start; | 111 | return nfit_res->buf + offset - nfit_res->res.start; |
| 111 | return devm_memremap_pages(dev, res, ref, altmap); | 112 | return devm_memremap_pages(dev, res, ref, altmap); |
| 112 | } | 113 | } |
| 113 | EXPORT_SYMBOL(__wrap_devm_memremap_pages); | 114 | EXPORT_SYMBOL(__wrap_devm_memremap_pages); |
| @@ -128,7 +129,7 @@ void *__wrap_memremap(resource_size_t offset, size_t size, | |||
| 128 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); | 129 | struct nfit_test_resource *nfit_res = get_nfit_res(offset); |
| 129 | 130 | ||
| 130 | if (nfit_res) | 131 | if (nfit_res) |
| 131 | return nfit_res->buf + offset - nfit_res->res->start; | 132 | return nfit_res->buf + offset - nfit_res->res.start; |
| 132 | return memremap(offset, size, flags); | 133 | return memremap(offset, size, flags); |
| 133 | } | 134 | } |
| 134 | EXPORT_SYMBOL(__wrap_memremap); | 135 | EXPORT_SYMBOL(__wrap_memremap); |
| @@ -174,6 +175,63 @@ void __wrap_memunmap(void *addr) | |||
| 174 | } | 175 | } |
| 175 | EXPORT_SYMBOL(__wrap_memunmap); | 176 | EXPORT_SYMBOL(__wrap_memunmap); |
| 176 | 177 | ||
| 178 | static bool nfit_test_release_region(struct device *dev, | ||
| 179 | struct resource *parent, resource_size_t start, | ||
| 180 | resource_size_t n); | ||
| 181 | |||
| 182 | static void nfit_devres_release(struct device *dev, void *data) | ||
| 183 | { | ||
| 184 | struct resource *res = *((struct resource **) data); | ||
| 185 | |||
| 186 | WARN_ON(!nfit_test_release_region(NULL, &iomem_resource, res->start, | ||
| 187 | resource_size(res))); | ||
| 188 | } | ||
| 189 | |||
| 190 | static int match(struct device *dev, void *__res, void *match_data) | ||
| 191 | { | ||
| 192 | struct resource *res = *((struct resource **) __res); | ||
| 193 | resource_size_t start = *((resource_size_t *) match_data); | ||
| 194 | |||
| 195 | return res->start == start; | ||
| 196 | } | ||
| 197 | |||
| 198 | static bool nfit_test_release_region(struct device *dev, | ||
| 199 | struct resource *parent, resource_size_t start, | ||
| 200 | resource_size_t n) | ||
| 201 | { | ||
| 202 | if (parent == &iomem_resource) { | ||
| 203 | struct nfit_test_resource *nfit_res = get_nfit_res(start); | ||
| 204 | |||
| 205 | if (nfit_res) { | ||
| 206 | struct nfit_test_request *req; | ||
| 207 | struct resource *res = NULL; | ||
| 208 | |||
| 209 | if (dev) { | ||
| 210 | devres_release(dev, nfit_devres_release, match, | ||
| 211 | &start); | ||
| 212 | return true; | ||
| 213 | } | ||
| 214 | |||
| 215 | spin_lock(&nfit_res->lock); | ||
| 216 | list_for_each_entry(req, &nfit_res->requests, list) | ||
| 217 | if (req->res.start == start) { | ||
| 218 | res = &req->res; | ||
| 219 | list_del(&req->list); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | spin_unlock(&nfit_res->lock); | ||
| 223 | |||
| 224 | WARN(!res || resource_size(res) != n, | ||
| 225 | "%s: start: %llx n: %llx mismatch: %pr\n", | ||
| 226 | __func__, start, n, res); | ||
| 227 | if (res) | ||
| 228 | kfree(req); | ||
| 229 | return true; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | return false; | ||
| 233 | } | ||
| 234 | |||
| 177 | static struct resource *nfit_test_request_region(struct device *dev, | 235 | static struct resource *nfit_test_request_region(struct device *dev, |
| 178 | struct resource *parent, resource_size_t start, | 236 | struct resource *parent, resource_size_t start, |
| 179 | resource_size_t n, const char *name, int flags) | 237 | resource_size_t n, const char *name, int flags) |
| @@ -183,21 +241,57 @@ static struct resource *nfit_test_request_region(struct device *dev, | |||
| 183 | if (parent == &iomem_resource) { | 241 | if (parent == &iomem_resource) { |
| 184 | nfit_res = get_nfit_res(start); | 242 | nfit_res = get_nfit_res(start); |
| 185 | if (nfit_res) { | 243 | if (nfit_res) { |
| 186 | struct resource *res = nfit_res->res + 1; | 244 | struct nfit_test_request *req; |
| 245 | struct resource *res = NULL; | ||
| 187 | 246 | ||
| 188 | if (start + n > nfit_res->res->start | 247 | if (start + n > nfit_res->res.start |
| 189 | + resource_size(nfit_res->res)) { | 248 | + resource_size(&nfit_res->res)) { |
| 190 | pr_debug("%s: start: %llx n: %llx overflow: %pr\n", | 249 | pr_debug("%s: start: %llx n: %llx overflow: %pr\n", |
| 191 | __func__, start, n, | 250 | __func__, start, n, |
| 192 | nfit_res->res); | 251 | &nfit_res->res); |
| 193 | return NULL; | 252 | return NULL; |
| 194 | } | 253 | } |
| 195 | 254 | ||
| 255 | spin_lock(&nfit_res->lock); | ||
| 256 | list_for_each_entry(req, &nfit_res->requests, list) | ||
| 257 | if (start == req->res.start) { | ||
| 258 | res = &req->res; | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | spin_unlock(&nfit_res->lock); | ||
| 262 | |||
| 263 | if (res) { | ||
| 264 | WARN(1, "%pr already busy\n", res); | ||
| 265 | return NULL; | ||
| 266 | } | ||
| 267 | |||
| 268 | req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
| 269 | if (!req) | ||
| 270 | return NULL; | ||
| 271 | INIT_LIST_HEAD(&req->list); | ||
| 272 | res = &req->res; | ||
| 273 | |||
| 196 | res->start = start; | 274 | res->start = start; |
| 197 | res->end = start + n - 1; | 275 | res->end = start + n - 1; |
| 198 | res->name = name; | 276 | res->name = name; |
| 199 | res->flags = resource_type(parent); | 277 | res->flags = resource_type(parent); |
| 200 | res->flags |= IORESOURCE_BUSY | flags; | 278 | res->flags |= IORESOURCE_BUSY | flags; |
| 279 | spin_lock(&nfit_res->lock); | ||
| 280 | list_add(&req->list, &nfit_res->requests); | ||
| 281 | spin_unlock(&nfit_res->lock); | ||
| 282 | |||
| 283 | if (dev) { | ||
| 284 | struct resource **d; | ||
| 285 | |||
| 286 | d = devres_alloc(nfit_devres_release, | ||
| 287 | sizeof(struct resource *), | ||
| 288 | GFP_KERNEL); | ||
| 289 | if (!d) | ||
| 290 | return NULL; | ||
| 291 | *d = res; | ||
| 292 | devres_add(dev, d); | ||
| 293 | } | ||
| 294 | |||
| 201 | pr_debug("%s: %pr\n", __func__, res); | 295 | pr_debug("%s: %pr\n", __func__, res); |
| 202 | return res; | 296 | return res; |
| 203 | } | 297 | } |
| @@ -241,29 +335,10 @@ struct resource *__wrap___devm_request_region(struct device *dev, | |||
| 241 | } | 335 | } |
| 242 | EXPORT_SYMBOL(__wrap___devm_request_region); | 336 | EXPORT_SYMBOL(__wrap___devm_request_region); |
| 243 | 337 | ||
| 244 | static bool nfit_test_release_region(struct resource *parent, | ||
| 245 | resource_size_t start, resource_size_t n) | ||
| 246 | { | ||
| 247 | if (parent == &iomem_resource) { | ||
| 248 | struct nfit_test_resource *nfit_res = get_nfit_res(start); | ||
| 249 | if (nfit_res) { | ||
| 250 | struct resource *res = nfit_res->res + 1; | ||
| 251 | |||
| 252 | if (start != res->start || resource_size(res) != n) | ||
| 253 | pr_info("%s: start: %llx n: %llx mismatch: %pr\n", | ||
| 254 | __func__, start, n, res); | ||
| 255 | else | ||
| 256 | memset(res, 0, sizeof(*res)); | ||
| 257 | return true; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | return false; | ||
| 261 | } | ||
| 262 | |||
| 263 | void __wrap___release_region(struct resource *parent, resource_size_t start, | 338 | void __wrap___release_region(struct resource *parent, resource_size_t start, |
| 264 | resource_size_t n) | 339 | resource_size_t n) |
| 265 | { | 340 | { |
| 266 | if (!nfit_test_release_region(parent, start, n)) | 341 | if (!nfit_test_release_region(NULL, parent, start, n)) |
| 267 | __release_region(parent, start, n); | 342 | __release_region(parent, start, n); |
| 268 | } | 343 | } |
| 269 | EXPORT_SYMBOL(__wrap___release_region); | 344 | EXPORT_SYMBOL(__wrap___release_region); |
| @@ -271,9 +346,25 @@ EXPORT_SYMBOL(__wrap___release_region); | |||
| 271 | void __wrap___devm_release_region(struct device *dev, struct resource *parent, | 346 | void __wrap___devm_release_region(struct device *dev, struct resource *parent, |
| 272 | resource_size_t start, resource_size_t n) | 347 | resource_size_t start, resource_size_t n) |
| 273 | { | 348 | { |
| 274 | if (!nfit_test_release_region(parent, start, n)) | 349 | if (!nfit_test_release_region(dev, parent, start, n)) |
| 275 | __devm_release_region(dev, parent, start, n); | 350 | __devm_release_region(dev, parent, start, n); |
| 276 | } | 351 | } |
| 277 | EXPORT_SYMBOL(__wrap___devm_release_region); | 352 | EXPORT_SYMBOL(__wrap___devm_release_region); |
| 278 | 353 | ||
| 354 | acpi_status __wrap_acpi_evaluate_object(acpi_handle handle, acpi_string path, | ||
| 355 | struct acpi_object_list *p, struct acpi_buffer *buf) | ||
| 356 | { | ||
| 357 | struct nfit_test_resource *nfit_res = get_nfit_res((long) handle); | ||
| 358 | union acpi_object **obj; | ||
| 359 | |||
| 360 | if (!nfit_res || strcmp(path, "_FIT") || !buf) | ||
| 361 | return acpi_evaluate_object(handle, path, p, buf); | ||
| 362 | |||
| 363 | obj = nfit_res->buf; | ||
| 364 | buf->length = sizeof(union acpi_object); | ||
| 365 | buf->pointer = *obj; | ||
| 366 | return AE_OK; | ||
| 367 | } | ||
| 368 | EXPORT_SYMBOL(__wrap_acpi_evaluate_object); | ||
| 369 | |||
| 279 | MODULE_LICENSE("GPL v2"); | 370 | MODULE_LICENSE("GPL v2"); |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index f64c57bf1d4b..c9a6458cb63e 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
| @@ -132,6 +132,8 @@ static u32 handle[NUM_DCR] = { | |||
| 132 | [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), | 132 | [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | static unsigned long dimm_fail_cmd_flags[NUM_DCR]; | ||
| 136 | |||
| 135 | struct nfit_test { | 137 | struct nfit_test { |
| 136 | struct acpi_nfit_desc acpi_desc; | 138 | struct acpi_nfit_desc acpi_desc; |
| 137 | struct platform_device pdev; | 139 | struct platform_device pdev; |
| @@ -154,11 +156,14 @@ struct nfit_test { | |||
| 154 | int (*alloc)(struct nfit_test *t); | 156 | int (*alloc)(struct nfit_test *t); |
| 155 | void (*setup)(struct nfit_test *t); | 157 | void (*setup)(struct nfit_test *t); |
| 156 | int setup_hotplug; | 158 | int setup_hotplug; |
| 159 | union acpi_object **_fit; | ||
| 160 | dma_addr_t _fit_dma; | ||
| 157 | struct ars_state { | 161 | struct ars_state { |
| 158 | struct nd_cmd_ars_status *ars_status; | 162 | struct nd_cmd_ars_status *ars_status; |
| 159 | unsigned long deadline; | 163 | unsigned long deadline; |
| 160 | spinlock_t lock; | 164 | spinlock_t lock; |
| 161 | } ars_state; | 165 | } ars_state; |
| 166 | struct device *dimm_dev[NUM_DCR]; | ||
| 162 | }; | 167 | }; |
| 163 | 168 | ||
| 164 | static struct nfit_test *to_nfit_test(struct device *dev) | 169 | static struct nfit_test *to_nfit_test(struct device *dev) |
| @@ -411,6 +416,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 411 | if (i >= ARRAY_SIZE(handle)) | 416 | if (i >= ARRAY_SIZE(handle)) |
| 412 | return -ENXIO; | 417 | return -ENXIO; |
| 413 | 418 | ||
| 419 | if ((1 << func) & dimm_fail_cmd_flags[i]) | ||
| 420 | return -EIO; | ||
| 421 | |||
| 414 | switch (func) { | 422 | switch (func) { |
| 415 | case ND_CMD_GET_CONFIG_SIZE: | 423 | case ND_CMD_GET_CONFIG_SIZE: |
| 416 | rc = nfit_test_cmd_get_config_size(buf, buf_len); | 424 | rc = nfit_test_cmd_get_config_size(buf, buf_len); |
| @@ -428,6 +436,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
| 428 | break; | 436 | break; |
| 429 | case ND_CMD_SMART_THRESHOLD: | 437 | case ND_CMD_SMART_THRESHOLD: |
| 430 | rc = nfit_test_cmd_smart_threshold(buf, buf_len); | 438 | rc = nfit_test_cmd_smart_threshold(buf, buf_len); |
| 439 | device_lock(&t->pdev.dev); | ||
| 440 | __acpi_nvdimm_notify(t->dimm_dev[i], 0x81); | ||
| 441 | device_unlock(&t->pdev.dev); | ||
| 431 | break; | 442 | break; |
| 432 | default: | 443 | default: |
| 433 | return -ENOTTY; | 444 | return -ENOTTY; |
| @@ -467,14 +478,12 @@ static struct nfit_test *instances[NUM_NFITS]; | |||
| 467 | static void release_nfit_res(void *data) | 478 | static void release_nfit_res(void *data) |
| 468 | { | 479 | { |
| 469 | struct nfit_test_resource *nfit_res = data; | 480 | struct nfit_test_resource *nfit_res = data; |
| 470 | struct resource *res = nfit_res->res; | ||
| 471 | 481 | ||
| 472 | spin_lock(&nfit_test_lock); | 482 | spin_lock(&nfit_test_lock); |
| 473 | list_del(&nfit_res->list); | 483 | list_del(&nfit_res->list); |
| 474 | spin_unlock(&nfit_test_lock); | 484 | spin_unlock(&nfit_test_lock); |
| 475 | 485 | ||
| 476 | vfree(nfit_res->buf); | 486 | vfree(nfit_res->buf); |
| 477 | kfree(res); | ||
| 478 | kfree(nfit_res); | 487 | kfree(nfit_res); |
| 479 | } | 488 | } |
| 480 | 489 | ||
| @@ -482,12 +491,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, | |||
| 482 | void *buf) | 491 | void *buf) |
| 483 | { | 492 | { |
| 484 | struct device *dev = &t->pdev.dev; | 493 | struct device *dev = &t->pdev.dev; |
| 485 | struct resource *res = kzalloc(sizeof(*res) * 2, GFP_KERNEL); | ||
| 486 | struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res), | 494 | struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res), |
| 487 | GFP_KERNEL); | 495 | GFP_KERNEL); |
| 488 | int rc; | 496 | int rc; |
| 489 | 497 | ||
| 490 | if (!res || !buf || !nfit_res) | 498 | if (!buf || !nfit_res) |
| 491 | goto err; | 499 | goto err; |
| 492 | rc = devm_add_action(dev, release_nfit_res, nfit_res); | 500 | rc = devm_add_action(dev, release_nfit_res, nfit_res); |
| 493 | if (rc) | 501 | if (rc) |
| @@ -496,10 +504,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, | |||
| 496 | memset(buf, 0, size); | 504 | memset(buf, 0, size); |
| 497 | nfit_res->dev = dev; | 505 | nfit_res->dev = dev; |
| 498 | nfit_res->buf = buf; | 506 | nfit_res->buf = buf; |
| 499 | nfit_res->res = res; | 507 | nfit_res->res.start = *dma; |
| 500 | res->start = *dma; | 508 | nfit_res->res.end = *dma + size - 1; |
| 501 | res->end = *dma + size - 1; | 509 | nfit_res->res.name = "NFIT"; |
| 502 | res->name = "NFIT"; | 510 | spin_lock_init(&nfit_res->lock); |
| 511 | INIT_LIST_HEAD(&nfit_res->requests); | ||
| 503 | spin_lock(&nfit_test_lock); | 512 | spin_lock(&nfit_test_lock); |
| 504 | list_add(&nfit_res->list, &t->resources); | 513 | list_add(&nfit_res->list, &t->resources); |
| 505 | spin_unlock(&nfit_test_lock); | 514 | spin_unlock(&nfit_test_lock); |
| @@ -508,7 +517,6 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, | |||
| 508 | err: | 517 | err: |
| 509 | if (buf) | 518 | if (buf) |
| 510 | vfree(buf); | 519 | vfree(buf); |
| 511 | kfree(res); | ||
| 512 | kfree(nfit_res); | 520 | kfree(nfit_res); |
| 513 | return NULL; | 521 | return NULL; |
| 514 | } | 522 | } |
| @@ -533,13 +541,13 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) | |||
| 533 | continue; | 541 | continue; |
| 534 | spin_lock(&nfit_test_lock); | 542 | spin_lock(&nfit_test_lock); |
| 535 | list_for_each_entry(n, &t->resources, list) { | 543 | list_for_each_entry(n, &t->resources, list) { |
| 536 | if (addr >= n->res->start && (addr < n->res->start | 544 | if (addr >= n->res.start && (addr < n->res.start |
| 537 | + resource_size(n->res))) { | 545 | + resource_size(&n->res))) { |
| 538 | nfit_res = n; | 546 | nfit_res = n; |
| 539 | break; | 547 | break; |
| 540 | } else if (addr >= (unsigned long) n->buf | 548 | } else if (addr >= (unsigned long) n->buf |
| 541 | && (addr < (unsigned long) n->buf | 549 | && (addr < (unsigned long) n->buf |
| 542 | + resource_size(n->res))) { | 550 | + resource_size(&n->res))) { |
| 543 | nfit_res = n; | 551 | nfit_res = n; |
| 544 | break; | 552 | break; |
| 545 | } | 553 | } |
| @@ -564,6 +572,86 @@ static int ars_state_init(struct device *dev, struct ars_state *ars_state) | |||
| 564 | return 0; | 572 | return 0; |
| 565 | } | 573 | } |
| 566 | 574 | ||
| 575 | static void put_dimms(void *data) | ||
| 576 | { | ||
| 577 | struct device **dimm_dev = data; | ||
| 578 | int i; | ||
| 579 | |||
| 580 | for (i = 0; i < NUM_DCR; i++) | ||
| 581 | if (dimm_dev[i]) | ||
| 582 | device_unregister(dimm_dev[i]); | ||
| 583 | } | ||
| 584 | |||
| 585 | static struct class *nfit_test_dimm; | ||
| 586 | |||
| 587 | static int dimm_name_to_id(struct device *dev) | ||
| 588 | { | ||
| 589 | int dimm; | ||
| 590 | |||
| 591 | if (sscanf(dev_name(dev), "test_dimm%d", &dimm) != 1 | ||
| 592 | || dimm >= NUM_DCR || dimm < 0) | ||
| 593 | return -ENXIO; | ||
| 594 | return dimm; | ||
| 595 | } | ||
| 596 | |||
| 597 | |||
| 598 | static ssize_t handle_show(struct device *dev, struct device_attribute *attr, | ||
| 599 | char *buf) | ||
| 600 | { | ||
| 601 | int dimm = dimm_name_to_id(dev); | ||
| 602 | |||
| 603 | if (dimm < 0) | ||
| 604 | return dimm; | ||
| 605 | |||
| 606 | return sprintf(buf, "%#x", handle[dimm]); | ||
| 607 | } | ||
| 608 | DEVICE_ATTR_RO(handle); | ||
| 609 | |||
| 610 | static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, | ||
| 611 | char *buf) | ||
| 612 | { | ||
| 613 | int dimm = dimm_name_to_id(dev); | ||
| 614 | |||
| 615 | if (dimm < 0) | ||
| 616 | return dimm; | ||
| 617 | |||
| 618 | return sprintf(buf, "%#lx\n", dimm_fail_cmd_flags[dimm]); | ||
| 619 | } | ||
| 620 | |||
| 621 | static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, | ||
| 622 | const char *buf, size_t size) | ||
| 623 | { | ||
| 624 | int dimm = dimm_name_to_id(dev); | ||
| 625 | unsigned long val; | ||
| 626 | ssize_t rc; | ||
| 627 | |||
| 628 | if (dimm < 0) | ||
| 629 | return dimm; | ||
| 630 | |||
| 631 | rc = kstrtol(buf, 0, &val); | ||
| 632 | if (rc) | ||
| 633 | return rc; | ||
| 634 | |||
| 635 | dimm_fail_cmd_flags[dimm] = val; | ||
| 636 | return size; | ||
| 637 | } | ||
| 638 | static DEVICE_ATTR_RW(fail_cmd); | ||
| 639 | |||
| 640 | static struct attribute *nfit_test_dimm_attributes[] = { | ||
| 641 | &dev_attr_fail_cmd.attr, | ||
| 642 | &dev_attr_handle.attr, | ||
| 643 | NULL, | ||
| 644 | }; | ||
| 645 | |||
| 646 | static struct attribute_group nfit_test_dimm_attribute_group = { | ||
| 647 | .attrs = nfit_test_dimm_attributes, | ||
| 648 | }; | ||
| 649 | |||
| 650 | static const struct attribute_group *nfit_test_dimm_attribute_groups[] = { | ||
| 651 | &nfit_test_dimm_attribute_group, | ||
| 652 | NULL, | ||
| 653 | }; | ||
| 654 | |||
| 567 | static int nfit_test0_alloc(struct nfit_test *t) | 655 | static int nfit_test0_alloc(struct nfit_test *t) |
| 568 | { | 656 | { |
| 569 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA | 657 | size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA |
| @@ -616,6 +704,21 @@ static int nfit_test0_alloc(struct nfit_test *t) | |||
| 616 | return -ENOMEM; | 704 | return -ENOMEM; |
| 617 | } | 705 | } |
| 618 | 706 | ||
| 707 | t->_fit = test_alloc(t, sizeof(union acpi_object **), &t->_fit_dma); | ||
| 708 | if (!t->_fit) | ||
| 709 | return -ENOMEM; | ||
| 710 | |||
| 711 | if (devm_add_action_or_reset(&t->pdev.dev, put_dimms, t->dimm_dev)) | ||
| 712 | return -ENOMEM; | ||
| 713 | for (i = 0; i < NUM_DCR; i++) { | ||
| 714 | t->dimm_dev[i] = device_create_with_groups(nfit_test_dimm, | ||
| 715 | &t->pdev.dev, 0, NULL, | ||
| 716 | nfit_test_dimm_attribute_groups, | ||
| 717 | "test_dimm%d", i); | ||
| 718 | if (!t->dimm_dev[i]) | ||
| 719 | return -ENOMEM; | ||
| 720 | } | ||
| 721 | |||
| 619 | return ars_state_init(&t->pdev.dev, &t->ars_state); | 722 | return ars_state_init(&t->pdev.dev, &t->ars_state); |
| 620 | } | 723 | } |
| 621 | 724 | ||
| @@ -1409,6 +1512,8 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
| 1409 | struct acpi_nfit_desc *acpi_desc; | 1512 | struct acpi_nfit_desc *acpi_desc; |
| 1410 | struct device *dev = &pdev->dev; | 1513 | struct device *dev = &pdev->dev; |
| 1411 | struct nfit_test *nfit_test; | 1514 | struct nfit_test *nfit_test; |
| 1515 | struct nfit_mem *nfit_mem; | ||
| 1516 | union acpi_object *obj; | ||
| 1412 | int rc; | 1517 | int rc; |
| 1413 | 1518 | ||
| 1414 | nfit_test = to_nfit_test(&pdev->dev); | 1519 | nfit_test = to_nfit_test(&pdev->dev); |
| @@ -1476,14 +1581,30 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
| 1476 | if (nfit_test->setup != nfit_test0_setup) | 1581 | if (nfit_test->setup != nfit_test0_setup) |
| 1477 | return 0; | 1582 | return 0; |
| 1478 | 1583 | ||
| 1479 | flush_work(&acpi_desc->work); | ||
| 1480 | nfit_test->setup_hotplug = 1; | 1584 | nfit_test->setup_hotplug = 1; |
| 1481 | nfit_test->setup(nfit_test); | 1585 | nfit_test->setup(nfit_test); |
| 1482 | 1586 | ||
| 1483 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, | 1587 | obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
| 1484 | nfit_test->nfit_size); | 1588 | if (!obj) |
| 1485 | if (rc) | 1589 | return -ENOMEM; |
| 1486 | return rc; | 1590 | obj->type = ACPI_TYPE_BUFFER; |
| 1591 | obj->buffer.length = nfit_test->nfit_size; | ||
| 1592 | obj->buffer.pointer = nfit_test->nfit_buf; | ||
| 1593 | *(nfit_test->_fit) = obj; | ||
| 1594 | __acpi_nfit_notify(&pdev->dev, nfit_test, 0x80); | ||
| 1595 | |||
| 1596 | /* associate dimm devices with nfit_mem data for notification testing */ | ||
| 1597 | mutex_lock(&acpi_desc->init_mutex); | ||
| 1598 | list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { | ||
| 1599 | u32 nfit_handle = __to_nfit_memdev(nfit_mem)->device_handle; | ||
| 1600 | int i; | ||
| 1601 | |||
| 1602 | for (i = 0; i < NUM_DCR; i++) | ||
| 1603 | if (nfit_handle == handle[i]) | ||
| 1604 | dev_set_drvdata(nfit_test->dimm_dev[i], | ||
| 1605 | nfit_mem); | ||
| 1606 | } | ||
| 1607 | mutex_unlock(&acpi_desc->init_mutex); | ||
| 1487 | 1608 | ||
| 1488 | return 0; | 1609 | return 0; |
| 1489 | } | 1610 | } |
| @@ -1518,6 +1639,10 @@ static __init int nfit_test_init(void) | |||
| 1518 | { | 1639 | { |
| 1519 | int rc, i; | 1640 | int rc, i; |
| 1520 | 1641 | ||
| 1642 | nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm"); | ||
| 1643 | if (IS_ERR(nfit_test_dimm)) | ||
| 1644 | return PTR_ERR(nfit_test_dimm); | ||
| 1645 | |||
| 1521 | nfit_test_setup(nfit_test_lookup); | 1646 | nfit_test_setup(nfit_test_lookup); |
| 1522 | 1647 | ||
| 1523 | for (i = 0; i < NUM_NFITS; i++) { | 1648 | for (i = 0; i < NUM_NFITS; i++) { |
| @@ -1584,6 +1709,7 @@ static __exit void nfit_test_exit(void) | |||
| 1584 | for (i = 0; i < NUM_NFITS; i++) | 1709 | for (i = 0; i < NUM_NFITS; i++) |
| 1585 | platform_device_unregister(&instances[i]->pdev); | 1710 | platform_device_unregister(&instances[i]->pdev); |
| 1586 | nfit_test_teardown(); | 1711 | nfit_test_teardown(); |
| 1712 | class_destroy(nfit_test_dimm); | ||
| 1587 | } | 1713 | } |
| 1588 | 1714 | ||
| 1589 | module_init(nfit_test_init); | 1715 | module_init(nfit_test_init); |
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 9f18e2a4a862..c281dd2e5e2d 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
| @@ -13,11 +13,21 @@ | |||
| 13 | #ifndef __NFIT_TEST_H__ | 13 | #ifndef __NFIT_TEST_H__ |
| 14 | #define __NFIT_TEST_H__ | 14 | #define __NFIT_TEST_H__ |
| 15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 16 | #include <linux/ioport.h> | ||
| 17 | #include <linux/spinlock_types.h> | ||
| 18 | |||
| 19 | struct nfit_test_request { | ||
| 20 | struct list_head list; | ||
| 21 | struct resource res; | ||
| 22 | }; | ||
| 16 | 23 | ||
| 17 | struct nfit_test_resource { | 24 | struct nfit_test_resource { |
| 25 | struct list_head requests; | ||
| 18 | struct list_head list; | 26 | struct list_head list; |
| 19 | struct resource *res; | 27 | struct resource res; |
| 20 | struct device *dev; | 28 | struct device *dev; |
| 29 | spinlock_t lock; | ||
| 30 | int req_count; | ||
| 21 | void *buf; | 31 | void *buf; |
| 22 | }; | 32 | }; |
| 23 | 33 | ||
