aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2016-10-06 14:22:37 -0400
committerDan Williams <dan.j.williams@intel.com>2016-10-07 12:20:53 -0400
commitbd4cd745b3b412ac93227640e3b337962f41d932 (patch)
treefc87b054e3d62373f8059e3d5e9bea285489c748
parent8a5f50d3b7f2f601c200f84827c2c9220cd69f71 (diff)
tools/testing/nvdimm: support for sub-dividing a pmem region
Update nfit_test to handle multiple sub-allocations within a given pmem region. The mock resource now tracks and un-tracks sub-ranges as they are requested and released (either explicitly or via devm callback). Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--tools/testing/nvdimm/test/iomap.c134
-rw-r--r--tools/testing/nvdimm/test/nfit.c21
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h12
3 files changed, 124 insertions, 43 deletions
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index dae5b9b6d186..3ccef732fce9 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -74,7 +74,7 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
74 74
75 if (nfit_res) 75 if (nfit_res)
76 return (void __iomem *) nfit_res->buf + offset 76 return (void __iomem *) nfit_res->buf + offset
77 - nfit_res->res->start; 77 - nfit_res->res.start;
78 return fallback_fn(offset, size); 78 return fallback_fn(offset, size);
79} 79}
80 80
@@ -85,7 +85,7 @@ void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
85 85
86 if (nfit_res) 86 if (nfit_res)
87 return (void __iomem *) nfit_res->buf + offset 87 return (void __iomem *) nfit_res->buf + offset
88 - nfit_res->res->start; 88 - nfit_res->res.start;
89 return devm_ioremap_nocache(dev, offset, size); 89 return devm_ioremap_nocache(dev, offset, size);
90} 90}
91EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); 91EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
@@ -96,7 +96,7 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
96 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 96 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
97 97
98 if (nfit_res) 98 if (nfit_res)
99 return nfit_res->buf + offset - nfit_res->res->start; 99 return nfit_res->buf + offset - nfit_res->res.start;
100 return devm_memremap(dev, offset, size, flags); 100 return devm_memremap(dev, offset, size, flags);
101} 101}
102EXPORT_SYMBOL(__wrap_devm_memremap); 102EXPORT_SYMBOL(__wrap_devm_memremap);
@@ -108,7 +108,7 @@ void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
108 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 108 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
109 109
110 if (nfit_res) 110 if (nfit_res)
111 return nfit_res->buf + offset - nfit_res->res->start; 111 return nfit_res->buf + offset - nfit_res->res.start;
112 return devm_memremap_pages(dev, res, ref, altmap); 112 return devm_memremap_pages(dev, res, ref, altmap);
113} 113}
114EXPORT_SYMBOL(__wrap_devm_memremap_pages); 114EXPORT_SYMBOL(__wrap_devm_memremap_pages);
@@ -129,7 +129,7 @@ void *__wrap_memremap(resource_size_t offset, size_t size,
129 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 129 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
130 130
131 if (nfit_res) 131 if (nfit_res)
132 return nfit_res->buf + offset - nfit_res->res->start; 132 return nfit_res->buf + offset - nfit_res->res.start;
133 return memremap(offset, size, flags); 133 return memremap(offset, size, flags);
134} 134}
135EXPORT_SYMBOL(__wrap_memremap); 135EXPORT_SYMBOL(__wrap_memremap);
@@ -175,6 +175,63 @@ void __wrap_memunmap(void *addr)
175} 175}
176EXPORT_SYMBOL(__wrap_memunmap); 176EXPORT_SYMBOL(__wrap_memunmap);
177 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
178static struct resource *nfit_test_request_region(struct device *dev, 235static struct resource *nfit_test_request_region(struct device *dev,
179 struct resource *parent, resource_size_t start, 236 struct resource *parent, resource_size_t start,
180 resource_size_t n, const char *name, int flags) 237 resource_size_t n, const char *name, int flags)
@@ -184,21 +241,57 @@ static struct resource *nfit_test_request_region(struct device *dev,
184 if (parent == &iomem_resource) { 241 if (parent == &iomem_resource) {
185 nfit_res = get_nfit_res(start); 242 nfit_res = get_nfit_res(start);
186 if (nfit_res) { 243 if (nfit_res) {
187 struct resource *res = nfit_res->res + 1; 244 struct nfit_test_request *req;
245 struct resource *res = NULL;
188 246
189 if (start + n > nfit_res->res->start 247 if (start + n > nfit_res->res.start
190 + resource_size(nfit_res->res)) { 248 + resource_size(&nfit_res->res)) {
191 pr_debug("%s: start: %llx n: %llx overflow: %pr\n", 249 pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
192 __func__, start, n, 250 __func__, start, n,
193 nfit_res->res); 251 &nfit_res->res);
252 return NULL;
253 }
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);
194 return NULL; 265 return NULL;
195 } 266 }
196 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
197 res->start = start; 274 res->start = start;
198 res->end = start + n - 1; 275 res->end = start + n - 1;
199 res->name = name; 276 res->name = name;
200 res->flags = resource_type(parent); 277 res->flags = resource_type(parent);
201 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
202 pr_debug("%s: %pr\n", __func__, res); 295 pr_debug("%s: %pr\n", __func__, res);
203 return res; 296 return res;
204 } 297 }
@@ -242,29 +335,10 @@ struct resource *__wrap___devm_request_region(struct device *dev,
242} 335}
243EXPORT_SYMBOL(__wrap___devm_request_region); 336EXPORT_SYMBOL(__wrap___devm_request_region);
244 337
245static bool nfit_test_release_region(struct resource *parent,
246 resource_size_t start, resource_size_t n)
247{
248 if (parent == &iomem_resource) {
249 struct nfit_test_resource *nfit_res = get_nfit_res(start);
250 if (nfit_res) {
251 struct resource *res = nfit_res->res + 1;
252
253 if (start != res->start || resource_size(res) != n)
254 pr_info("%s: start: %llx n: %llx mismatch: %pr\n",
255 __func__, start, n, res);
256 else
257 memset(res, 0, sizeof(*res));
258 return true;
259 }
260 }
261 return false;
262}
263
264void __wrap___release_region(struct resource *parent, resource_size_t start, 338void __wrap___release_region(struct resource *parent, resource_size_t start,
265 resource_size_t n) 339 resource_size_t n)
266{ 340{
267 if (!nfit_test_release_region(parent, start, n)) 341 if (!nfit_test_release_region(NULL, parent, start, n))
268 __release_region(parent, start, n); 342 __release_region(parent, start, n);
269} 343}
270EXPORT_SYMBOL(__wrap___release_region); 344EXPORT_SYMBOL(__wrap___release_region);
@@ -272,7 +346,7 @@ EXPORT_SYMBOL(__wrap___release_region);
272void __wrap___devm_release_region(struct device *dev, struct resource *parent, 346void __wrap___devm_release_region(struct device *dev, struct resource *parent,
273 resource_size_t start, resource_size_t n) 347 resource_size_t start, resource_size_t n)
274{ 348{
275 if (!nfit_test_release_region(parent, start, n)) 349 if (!nfit_test_release_region(dev, parent, start, n))
276 __devm_release_region(dev, parent, start, n); 350 __devm_release_region(dev, parent, start, n);
277} 351}
278EXPORT_SYMBOL(__wrap___devm_release_region); 352EXPORT_SYMBOL(__wrap___devm_release_region);
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 175fc24f8f3a..0e721c6fb1cf 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -478,14 +478,12 @@ static struct nfit_test *instances[NUM_NFITS];
478static void release_nfit_res(void *data) 478static void release_nfit_res(void *data)
479{ 479{
480 struct nfit_test_resource *nfit_res = data; 480 struct nfit_test_resource *nfit_res = data;
481 struct resource *res = nfit_res->res;
482 481
483 spin_lock(&nfit_test_lock); 482 spin_lock(&nfit_test_lock);
484 list_del(&nfit_res->list); 483 list_del(&nfit_res->list);
485 spin_unlock(&nfit_test_lock); 484 spin_unlock(&nfit_test_lock);
486 485
487 vfree(nfit_res->buf); 486 vfree(nfit_res->buf);
488 kfree(res);
489 kfree(nfit_res); 487 kfree(nfit_res);
490} 488}
491 489
@@ -493,12 +491,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
493 void *buf) 491 void *buf)
494{ 492{
495 struct device *dev = &t->pdev.dev; 493 struct device *dev = &t->pdev.dev;
496 struct resource *res = kzalloc(sizeof(*res) * 2, GFP_KERNEL);
497 struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res), 494 struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res),
498 GFP_KERNEL); 495 GFP_KERNEL);
499 int rc; 496 int rc;
500 497
501 if (!res || !buf || !nfit_res) 498 if (!buf || !nfit_res)
502 goto err; 499 goto err;
503 rc = devm_add_action(dev, release_nfit_res, nfit_res); 500 rc = devm_add_action(dev, release_nfit_res, nfit_res);
504 if (rc) 501 if (rc)
@@ -507,10 +504,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
507 memset(buf, 0, size); 504 memset(buf, 0, size);
508 nfit_res->dev = dev; 505 nfit_res->dev = dev;
509 nfit_res->buf = buf; 506 nfit_res->buf = buf;
510 nfit_res->res = res; 507 nfit_res->res.start = *dma;
511 res->start = *dma; 508 nfit_res->res.end = *dma + size - 1;
512 res->end = *dma + size - 1; 509 nfit_res->res.name = "NFIT";
513 res->name = "NFIT"; 510 spin_lock_init(&nfit_res->lock);
511 INIT_LIST_HEAD(&nfit_res->requests);
514 spin_lock(&nfit_test_lock); 512 spin_lock(&nfit_test_lock);
515 list_add(&nfit_res->list, &t->resources); 513 list_add(&nfit_res->list, &t->resources);
516 spin_unlock(&nfit_test_lock); 514 spin_unlock(&nfit_test_lock);
@@ -519,7 +517,6 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
519 err: 517 err:
520 if (buf) 518 if (buf)
521 vfree(buf); 519 vfree(buf);
522 kfree(res);
523 kfree(nfit_res); 520 kfree(nfit_res);
524 return NULL; 521 return NULL;
525} 522}
@@ -544,13 +541,13 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
544 continue; 541 continue;
545 spin_lock(&nfit_test_lock); 542 spin_lock(&nfit_test_lock);
546 list_for_each_entry(n, &t->resources, list) { 543 list_for_each_entry(n, &t->resources, list) {
547 if (addr >= n->res->start && (addr < n->res->start 544 if (addr >= n->res.start && (addr < n->res.start
548 + resource_size(n->res))) { 545 + resource_size(&n->res))) {
549 nfit_res = n; 546 nfit_res = n;
550 break; 547 break;
551 } else if (addr >= (unsigned long) n->buf 548 } else if (addr >= (unsigned long) n->buf
552 && (addr < (unsigned long) n->buf 549 && (addr < (unsigned long) n->buf
553 + resource_size(n->res))) { 550 + resource_size(&n->res))) {
554 nfit_res = n; 551 nfit_res = n;
555 break; 552 break;
556 } 553 }
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