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 | |
parent | db58028ee4e360430de8e3b48f657dc798ee6591 (diff) | |
parent | 98a29c39dc689298d2f834f40102cba752eb49c0 (diff) |
Merge branch 'for-4.9/libnvdimm' into libnvdimm-for-next
Diffstat (limited to 'tools')
-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 | ||