Skip to content

Commit bd4cd74

Browse files
committed
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 <[email protected]>
1 parent 8a5f50d commit bd4cd74

File tree

3 files changed

+124
-43
lines changed

3 files changed

+124
-43
lines changed

tools/testing/nvdimm/test/iomap.c

Lines changed: 104 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
7474

7575
if (nfit_res)
7676
return (void __iomem *) nfit_res->buf + offset
77-
- nfit_res->res->start;
77+
- nfit_res->res.start;
7878
return fallback_fn(offset, size);
7979
}
8080

@@ -85,7 +85,7 @@ void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
8585

8686
if (nfit_res)
8787
return (void __iomem *) nfit_res->buf + offset
88-
- nfit_res->res->start;
88+
- nfit_res->res.start;
8989
return devm_ioremap_nocache(dev, offset, size);
9090
}
9191
EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
@@ -96,7 +96,7 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
9696
struct nfit_test_resource *nfit_res = get_nfit_res(offset);
9797

9898
if (nfit_res)
99-
return nfit_res->buf + offset - nfit_res->res->start;
99+
return nfit_res->buf + offset - nfit_res->res.start;
100100
return devm_memremap(dev, offset, size, flags);
101101
}
102102
EXPORT_SYMBOL(__wrap_devm_memremap);
@@ -108,7 +108,7 @@ void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
108108
struct nfit_test_resource *nfit_res = get_nfit_res(offset);
109109

110110
if (nfit_res)
111-
return nfit_res->buf + offset - nfit_res->res->start;
111+
return nfit_res->buf + offset - nfit_res->res.start;
112112
return devm_memremap_pages(dev, res, ref, altmap);
113113
}
114114
EXPORT_SYMBOL(__wrap_devm_memremap_pages);
@@ -129,7 +129,7 @@ void *__wrap_memremap(resource_size_t offset, size_t size,
129129
struct nfit_test_resource *nfit_res = get_nfit_res(offset);
130130

131131
if (nfit_res)
132-
return nfit_res->buf + offset - nfit_res->res->start;
132+
return nfit_res->buf + offset - nfit_res->res.start;
133133
return memremap(offset, size, flags);
134134
}
135135
EXPORT_SYMBOL(__wrap_memremap);
@@ -175,6 +175,63 @@ void __wrap_memunmap(void *addr)
175175
}
176176
EXPORT_SYMBOL(__wrap_memunmap);
177177

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+
178235
static struct resource *nfit_test_request_region(struct device *dev,
179236
struct resource *parent, resource_size_t start,
180237
resource_size_t n, const char *name, int flags)
@@ -184,21 +241,57 @@ static struct resource *nfit_test_request_region(struct device *dev,
184241
if (parent == &iomem_resource) {
185242
nfit_res = get_nfit_res(start);
186243
if (nfit_res) {
187-
struct resource *res = nfit_res->res + 1;
244+
struct nfit_test_request *req;
245+
struct resource *res = NULL;
188246

189-
if (start + n > nfit_res->res->start
190-
+ resource_size(nfit_res->res)) {
247+
if (start + n > nfit_res->res.start
248+
+ resource_size(&nfit_res->res)) {
191249
pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
192250
__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);
194265
return NULL;
195266
}
196267

268+
req = kzalloc(sizeof(*req), GFP_KERNEL);
269+
if (!req)
270+
return NULL;
271+
INIT_LIST_HEAD(&req->list);
272+
res = &req->res;
273+
197274
res->start = start;
198275
res->end = start + n - 1;
199276
res->name = name;
200277
res->flags = resource_type(parent);
201278
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+
202295
pr_debug("%s: %pr\n", __func__, res);
203296
return res;
204297
}
@@ -242,37 +335,18 @@ struct resource *__wrap___devm_request_region(struct device *dev,
242335
}
243336
EXPORT_SYMBOL(__wrap___devm_request_region);
244337

245-
static 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-
264338
void __wrap___release_region(struct resource *parent, resource_size_t start,
265339
resource_size_t n)
266340
{
267-
if (!nfit_test_release_region(parent, start, n))
341+
if (!nfit_test_release_region(NULL, parent, start, n))
268342
__release_region(parent, start, n);
269343
}
270344
EXPORT_SYMBOL(__wrap___release_region);
271345

272346
void __wrap___devm_release_region(struct device *dev, struct resource *parent,
273347
resource_size_t start, resource_size_t n)
274348
{
275-
if (!nfit_test_release_region(parent, start, n))
349+
if (!nfit_test_release_region(dev, parent, start, n))
276350
__devm_release_region(dev, parent, start, n);
277351
}
278352
EXPORT_SYMBOL(__wrap___devm_release_region);

tools/testing/nvdimm/test/nfit.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -478,27 +478,24 @@ static struct nfit_test *instances[NUM_NFITS];
478478
static void release_nfit_res(void *data)
479479
{
480480
struct nfit_test_resource *nfit_res = data;
481-
struct resource *res = nfit_res->res;
482481

483482
spin_lock(&nfit_test_lock);
484483
list_del(&nfit_res->list);
485484
spin_unlock(&nfit_test_lock);
486485

487486
vfree(nfit_res->buf);
488-
kfree(res);
489487
kfree(nfit_res);
490488
}
491489

492490
static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
493491
void *buf)
494492
{
495493
struct device *dev = &t->pdev.dev;
496-
struct resource *res = kzalloc(sizeof(*res) * 2, GFP_KERNEL);
497494
struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res),
498495
GFP_KERNEL);
499496
int rc;
500497

501-
if (!res || !buf || !nfit_res)
498+
if (!buf || !nfit_res)
502499
goto err;
503500
rc = devm_add_action(dev, release_nfit_res, nfit_res);
504501
if (rc)
@@ -507,10 +504,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
507504
memset(buf, 0, size);
508505
nfit_res->dev = dev;
509506
nfit_res->buf = buf;
510-
nfit_res->res = res;
511-
res->start = *dma;
512-
res->end = *dma + size - 1;
513-
res->name = "NFIT";
507+
nfit_res->res.start = *dma;
508+
nfit_res->res.end = *dma + size - 1;
509+
nfit_res->res.name = "NFIT";
510+
spin_lock_init(&nfit_res->lock);
511+
INIT_LIST_HEAD(&nfit_res->requests);
514512
spin_lock(&nfit_test_lock);
515513
list_add(&nfit_res->list, &t->resources);
516514
spin_unlock(&nfit_test_lock);
@@ -519,7 +517,6 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
519517
err:
520518
if (buf)
521519
vfree(buf);
522-
kfree(res);
523520
kfree(nfit_res);
524521
return NULL;
525522
}
@@ -544,13 +541,13 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
544541
continue;
545542
spin_lock(&nfit_test_lock);
546543
list_for_each_entry(n, &t->resources, list) {
547-
if (addr >= n->res->start && (addr < n->res->start
548-
+ resource_size(n->res))) {
544+
if (addr >= n->res.start && (addr < n->res.start
545+
+ resource_size(&n->res))) {
549546
nfit_res = n;
550547
break;
551548
} else if (addr >= (unsigned long) n->buf
552549
&& (addr < (unsigned long) n->buf
553-
+ resource_size(n->res))) {
550+
+ resource_size(&n->res))) {
554551
nfit_res = n;
555552
break;
556553
}

tools/testing/nvdimm/test/nfit_test.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,21 @@
1313
#ifndef __NFIT_TEST_H__
1414
#define __NFIT_TEST_H__
1515
#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+
};
1623

1724
struct nfit_test_resource {
25+
struct list_head requests;
1826
struct list_head list;
19-
struct resource *res;
27+
struct resource res;
2028
struct device *dev;
29+
spinlock_t lock;
30+
int req_count;
2131
void *buf;
2232
};
2333

0 commit comments

Comments
 (0)