libnvdimm, pmem: allow nfit_test to override pmem_direct_access()
[deliverable/linux.git] / tools / testing / nvdimm / test / iomap.c
CommitLineData
6bc75619
DW
1/*
2 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 */
13#include <linux/rculist.h>
14#include <linux/export.h>
15#include <linux/ioport.h>
16#include <linux/module.h>
17#include <linux/types.h>
18#include <linux/io.h>
9bfa8496 19#include <linux/mm.h>
6bc75619
DW
20#include "nfit_test.h"
21
22static LIST_HEAD(iomap_head);
23
24static struct iomap_ops {
25 nfit_test_lookup_fn nfit_test_lookup;
26 struct list_head list;
27} iomap_ops = {
28 .list = LIST_HEAD_INIT(iomap_ops.list),
29};
30
31void nfit_test_setup(nfit_test_lookup_fn lookup)
32{
33 iomap_ops.nfit_test_lookup = lookup;
34 list_add_rcu(&iomap_ops.list, &iomap_head);
35}
36EXPORT_SYMBOL(nfit_test_setup);
37
38void nfit_test_teardown(void)
39{
40 list_del_rcu(&iomap_ops.list);
41 synchronize_rcu();
42}
43EXPORT_SYMBOL(nfit_test_teardown);
44
9bfa8496 45static struct nfit_test_resource *__get_nfit_res(resource_size_t resource)
6bc75619
DW
46{
47 struct iomap_ops *ops;
48
49 ops = list_first_or_null_rcu(&iomap_head, typeof(*ops), list);
50 if (ops)
51 return ops->nfit_test_lookup(resource);
52 return NULL;
53}
54
f295e53b 55struct nfit_test_resource *get_nfit_res(resource_size_t resource)
6bc75619 56{
9bfa8496 57 struct nfit_test_resource *res;
6bc75619
DW
58
59 rcu_read_lock();
9bfa8496 60 res = __get_nfit_res(resource);
6bc75619 61 rcu_read_unlock();
9bfa8496
DW
62
63 return res;
64}
f295e53b 65EXPORT_SYMBOL(get_nfit_res);
9bfa8496
DW
66
67void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
68 void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
69{
70 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
71
6bc75619
DW
72 if (nfit_res)
73 return (void __iomem *) nfit_res->buf + offset
74 - nfit_res->res->start;
75 return fallback_fn(offset, size);
76}
77
9d27a87e
DW
78void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
79 resource_size_t offset, unsigned long size)
80{
9bfa8496 81 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
9d27a87e 82
9d27a87e
DW
83 if (nfit_res)
84 return (void __iomem *) nfit_res->buf + offset
85 - nfit_res->res->start;
86 return devm_ioremap_nocache(dev, offset, size);
87}
88EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
89
708ab62b
CH
90void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
91 size_t size, unsigned long flags)
6bc75619 92{
9bfa8496 93 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
e836a256 94
e836a256 95 if (nfit_res)
67a3e8fe 96 return nfit_res->buf + offset - nfit_res->res->start;
708ab62b 97 return devm_memremap(dev, offset, size, flags);
6bc75619 98}
708ab62b 99EXPORT_SYMBOL(__wrap_devm_memremap);
6bc75619 100
979fccfb
DW
101#ifdef __HAVE_ARCH_PTE_DEVMAP
102#include <linux/memremap.h>
103#include <linux/pfn_t.h>
104
105void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
106 struct percpu_ref *ref, struct vmem_altmap *altmap)
107{
108 resource_size_t offset = res->start;
9bfa8496 109 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
979fccfb 110
979fccfb
DW
111 if (nfit_res)
112 return nfit_res->buf + offset - nfit_res->res->start;
113 return devm_memremap_pages(dev, res, ref, altmap);
114}
115EXPORT_SYMBOL(__wrap_devm_memremap_pages);
116
76e9f0ee 117pfn_t __wrap_phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
979fccfb 118{
9bfa8496 119 struct nfit_test_resource *nfit_res = get_nfit_res(addr);
979fccfb 120
979fccfb
DW
121 if (nfit_res)
122 flags &= ~PFN_MAP;
123 return phys_to_pfn_t(addr, flags);
124}
125EXPORT_SYMBOL(__wrap_phys_to_pfn_t);
126#else
127/* to be removed post 4.5-rc1 */
128void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res)
129{
130 resource_size_t offset = res->start;
9bfa8496 131 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
979fccfb 132
979fccfb
DW
133 if (nfit_res)
134 return nfit_res->buf + offset - nfit_res->res->start;
135 return devm_memremap_pages(dev, res);
136}
137EXPORT_SYMBOL(__wrap_devm_memremap_pages);
138#endif
139
67a3e8fe
RZ
140void *__wrap_memremap(resource_size_t offset, size_t size,
141 unsigned long flags)
142{
9bfa8496 143 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
67a3e8fe 144
67a3e8fe
RZ
145 if (nfit_res)
146 return nfit_res->buf + offset - nfit_res->res->start;
147 return memremap(offset, size, flags);
148}
149EXPORT_SYMBOL(__wrap_memremap);
150
32ab0a3f
DW
151void __wrap_devm_memunmap(struct device *dev, void *addr)
152{
9bfa8496 153 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
32ab0a3f 154
32ab0a3f
DW
155 if (nfit_res)
156 return;
157 return devm_memunmap(dev, addr);
158}
159EXPORT_SYMBOL(__wrap_devm_memunmap);
160
6bc75619
DW
161void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size)
162{
163 return __nfit_test_ioremap(offset, size, ioremap_nocache);
164}
165EXPORT_SYMBOL(__wrap_ioremap_nocache);
166
9d27a87e
DW
167void __iomem *__wrap_ioremap_wc(resource_size_t offset, unsigned long size)
168{
169 return __nfit_test_ioremap(offset, size, ioremap_wc);
170}
171EXPORT_SYMBOL(__wrap_ioremap_wc);
172
6bc75619
DW
173void __wrap_iounmap(volatile void __iomem *addr)
174{
9bfa8496 175 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
6bc75619
DW
176 if (nfit_res)
177 return;
178 return iounmap(addr);
179}
180EXPORT_SYMBOL(__wrap_iounmap);
181
67a3e8fe
RZ
182void __wrap_memunmap(void *addr)
183{
9bfa8496 184 struct nfit_test_resource *nfit_res = get_nfit_res((long) addr);
67a3e8fe 185
67a3e8fe
RZ
186 if (nfit_res)
187 return;
188 return memunmap(addr);
189}
190EXPORT_SYMBOL(__wrap_memunmap);
191
708ab62b
CH
192static struct resource *nfit_test_request_region(struct device *dev,
193 struct resource *parent, resource_size_t start,
194 resource_size_t n, const char *name, int flags)
6bc75619
DW
195{
196 struct nfit_test_resource *nfit_res;
197
198 if (parent == &iomem_resource) {
6bc75619 199 nfit_res = get_nfit_res(start);
6bc75619
DW
200 if (nfit_res) {
201 struct resource *res = nfit_res->res + 1;
202
203 if (start + n > nfit_res->res->start
204 + resource_size(nfit_res->res)) {
205 pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
206 __func__, start, n,
207 nfit_res->res);
208 return NULL;
209 }
210
211 res->start = start;
212 res->end = start + n - 1;
213 res->name = name;
214 res->flags = resource_type(parent);
215 res->flags |= IORESOURCE_BUSY | flags;
216 pr_debug("%s: %pr\n", __func__, res);
217 return res;
218 }
219 }
708ab62b
CH
220 if (dev)
221 return __devm_request_region(dev, parent, start, n, name);
6bc75619
DW
222 return __request_region(parent, start, n, name, flags);
223}
708ab62b
CH
224
225struct resource *__wrap___request_region(struct resource *parent,
226 resource_size_t start, resource_size_t n, const char *name,
227 int flags)
228{
229 return nfit_test_request_region(NULL, parent, start, n, name, flags);
230}
6bc75619
DW
231EXPORT_SYMBOL(__wrap___request_region);
232
708ab62b
CH
233struct resource *__wrap___devm_request_region(struct device *dev,
234 struct resource *parent, resource_size_t start,
235 resource_size_t n, const char *name)
236{
237 if (!dev)
238 return NULL;
239 return nfit_test_request_region(dev, parent, start, n, name, 0);
240}
241EXPORT_SYMBOL(__wrap___devm_request_region);
242
200c79da
DW
243static bool nfit_test_release_region(struct resource *parent,
244 resource_size_t start, resource_size_t n)
6bc75619 245{
6bc75619 246 if (parent == &iomem_resource) {
200c79da 247 struct nfit_test_resource *nfit_res = get_nfit_res(start);
6bc75619
DW
248 if (nfit_res) {
249 struct resource *res = nfit_res->res + 1;
250
251 if (start != res->start || resource_size(res) != n)
252 pr_info("%s: start: %llx n: %llx mismatch: %pr\n",
253 __func__, start, n, res);
254 else
255 memset(res, 0, sizeof(*res));
200c79da 256 return true;
6bc75619
DW
257 }
258 }
200c79da
DW
259 return false;
260}
261
262void __wrap___release_region(struct resource *parent, resource_size_t start,
263 resource_size_t n)
264{
265 if (!nfit_test_release_region(parent, start, n))
266 __release_region(parent, start, n);
6bc75619
DW
267}
268EXPORT_SYMBOL(__wrap___release_region);
269
200c79da
DW
270void __wrap___devm_release_region(struct device *dev, struct resource *parent,
271 resource_size_t start, resource_size_t n)
272{
273 if (!nfit_test_release_region(parent, start, n))
274 __devm_release_region(dev, parent, start, n);
275}
276EXPORT_SYMBOL(__wrap___devm_release_region);
277
6bc75619 278MODULE_LICENSE("GPL v2");
This page took 0.065484 seconds and 5 git commands to generate.