aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 15:19:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 15:19:31 -0400
commitd09ba13110e303d7baa29d170da94cd24f7662b2 (patch)
tree570b4d5e11889a6f951dee963c6549b2c8ca0293 /tools/testing
parentf29135b54bcbfe1fea97d94e2ae860bade1d5a31 (diff)
parente476f94482fc20a23b7b33b3d8e50f1953f71828 (diff)
Merge tag 'libnvdimm-for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams: "Aside from the recently added pmem sub-division support these have been in -next for several releases with no reported issues. The sub- division support was included in next-20161010 with no reported issues. It passes all unit tests including new tests for all the new functionality below. Summary: - PMEM sub-division support: Allow a single PMEM region to be divided into multiple namespaces. Originally, ~2 years ago, it was thought that partitions of a /dev/pmemX block device could handle sub-allocations of persistent memory for different use cases. With the decision to not support DAX mappings of raw block-devices, and the genesis of device-dax, the need for having multiple pmem-namespace per region has grown. - Device-DAX unified inode: In support of dynamic-resizing of a device-dax instance the kernel arranges for all mappings of a device-dax node to share the same inode. This allows unmap / truncate / invalidation events to affect all instances of the device similar to the behavior of mmap on block devices. - Hardware error scrubbing reworks: The original address-range-scrub and badblocks tracking solution allowed clearing entries at the individual namespace level, but it failed to clear the internal list of media errors maintained at the bus level. The result was that the next scrub or namespace disable/re-enable event would restore the cleared badblocks, but now that is fixed. The v4.8 kernel introduced an auto-scrub-on-machine-check behavior to repopulate the badblocks list. Now, in v4.9, the auto-scrub behavior can be disabled and simply arrange for the error reported in the machine-check to be added to the list. - DIMM health-event notification support: ACPI 6.1 defines a notification event code that can be send to ACPI NVDIMM devices. A poll(2) capable file descriptor for these events can be obtained from the nmemX/nfit/flags sysfs-attribute of a libnvdimm memory device. - Miscellaneous fixes: NVDIMM-N probe error, device-dax build error, and a change to dedup the flush hint list to not flush the memory controller more than necessary" * tag 'libnvdimm-for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (39 commits) /dev/dax: fix Kconfig dependency build breakage dax: use correct dev_t value dax: convert devm_create_dax_dev to PTR_ERR libnvdimm, namespace: allow creation of multiple pmem-namespaces per region libnvdimm, namespace: lift single pmem limit in scan_labels() libnvdimm, namespace: filter out of range labels in scan_labels() libnvdimm, namespace: enable allocation of multiple pmem namespaces libnvdimm, namespace: update label implementation for multi-pmem libnvdimm, namespace: expand pmem device naming scheme for multi-pmem libnvdimm, region: update nd_region_available_dpa() for multi-pmem support libnvdimm, namespace: sort namespaces by dpa at init libnvdimm, namespace: allow multiple pmem-namespaces per region at scan time tools/testing/nvdimm: support for sub-dividing a pmem region libnvdimm, namespace: unify blk and pmem label scanning libnvdimm, namespace: refactor uuid_show() into a namespace_to_uuid() helper libnvdimm, label: convert label tracking to a linked list libnvdimm, region: move region-mapping input-paramters to nd_mapping_desc nvdimm: reduce duplicated wpq flushes libnvdimm: clear the internal poison_list when clearing badblocks pmem: reduce kmap_atomic sections to the memcpys only ...
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/test/iomap.c151
-rw-r--r--tools/testing/nvdimm/test/nfit.c160
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h12
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
13ldflags-y += --wrap=devm_memremap_pages 13ldflags-y += --wrap=devm_memremap_pages
14ldflags-y += --wrap=insert_resource 14ldflags-y += --wrap=insert_resource
15ldflags-y += --wrap=remove_resource 15ldflags-y += --wrap=remove_resource
16ldflags-y += --wrap=acpi_evaluate_object
16 17
17DRIVERS := ../../../drivers 18DRIVERS := ../../../drivers
18NVDIMM_SRC := $(DRIVERS)/nvdimm 19NVDIMM_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}
90EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); 91EXPORT_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}
101EXPORT_SYMBOL(__wrap_devm_memremap); 102EXPORT_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}
113EXPORT_SYMBOL(__wrap_devm_memremap_pages); 114EXPORT_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}
134EXPORT_SYMBOL(__wrap_memremap); 135EXPORT_SYMBOL(__wrap_memremap);
@@ -174,6 +175,63 @@ void __wrap_memunmap(void *addr)
174} 175}
175EXPORT_SYMBOL(__wrap_memunmap); 176EXPORT_SYMBOL(__wrap_memunmap);
176 177
178static bool nfit_test_release_region(struct device *dev,
179 struct resource *parent, resource_size_t start,
180 resource_size_t n);
181
182static 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
190static 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
198static 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
177static struct resource *nfit_test_request_region(struct device *dev, 235static 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}
242EXPORT_SYMBOL(__wrap___devm_request_region); 336EXPORT_SYMBOL(__wrap___devm_request_region);
243 337
244static 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
263void __wrap___release_region(struct resource *parent, resource_size_t start, 338void __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}
269EXPORT_SYMBOL(__wrap___release_region); 344EXPORT_SYMBOL(__wrap___release_region);
@@ -271,9 +346,25 @@ EXPORT_SYMBOL(__wrap___release_region);
271void __wrap___devm_release_region(struct device *dev, struct resource *parent, 346void __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}
277EXPORT_SYMBOL(__wrap___devm_release_region); 352EXPORT_SYMBOL(__wrap___devm_release_region);
278 353
354acpi_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}
368EXPORT_SYMBOL(__wrap_acpi_evaluate_object);
369
279MODULE_LICENSE("GPL v2"); 370MODULE_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
135static unsigned long dimm_fail_cmd_flags[NUM_DCR];
136
135struct nfit_test { 137struct 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
164static struct nfit_test *to_nfit_test(struct device *dev) 169static 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];
467static void release_nfit_res(void *data) 478static 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
575static 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
585static struct class *nfit_test_dimm;
586
587static 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
598static 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}
608DEVICE_ATTR_RO(handle);
609
610static 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
621static 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}
638static DEVICE_ATTR_RW(fail_cmd);
639
640static struct attribute *nfit_test_dimm_attributes[] = {
641 &dev_attr_fail_cmd.attr,
642 &dev_attr_handle.attr,
643 NULL,
644};
645
646static struct attribute_group nfit_test_dimm_attribute_group = {
647 .attrs = nfit_test_dimm_attributes,
648};
649
650static const struct attribute_group *nfit_test_dimm_attribute_groups[] = {
651 &nfit_test_dimm_attribute_group,
652 NULL,
653};
654
567static int nfit_test0_alloc(struct nfit_test *t) 655static 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
1589module_init(nfit_test_init); 1715module_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
19struct nfit_test_request {
20 struct list_head list;
21 struct resource res;
22};
16 23
17struct nfit_test_resource { 24struct 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