1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
5 #include <linux/memremap.h>
6 #include <linux/rculist.h>
7 #include <linux/export.h>
8 #include <linux/ioport.h>
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/pfn_t.h>
12 #include <linux/acpi.h>
15 #include "nfit_test.h"
17 static LIST_HEAD(iomap_head
);
19 static struct iomap_ops
{
20 nfit_test_lookup_fn nfit_test_lookup
;
21 nfit_test_evaluate_dsm_fn evaluate_dsm
;
22 struct list_head list
;
24 .list
= LIST_HEAD_INIT(iomap_ops
.list
),
27 void nfit_test_setup(nfit_test_lookup_fn lookup
,
28 nfit_test_evaluate_dsm_fn evaluate
)
30 iomap_ops
.nfit_test_lookup
= lookup
;
31 iomap_ops
.evaluate_dsm
= evaluate
;
32 list_add_rcu(&iomap_ops
.list
, &iomap_head
);
34 EXPORT_SYMBOL(nfit_test_setup
);
36 void nfit_test_teardown(void)
38 list_del_rcu(&iomap_ops
.list
);
41 EXPORT_SYMBOL(nfit_test_teardown
);
43 static struct nfit_test_resource
*__get_nfit_res(resource_size_t resource
)
45 struct iomap_ops
*ops
;
47 ops
= list_first_or_null_rcu(&iomap_head
, typeof(*ops
), list
);
49 return ops
->nfit_test_lookup(resource
);
53 struct nfit_test_resource
*get_nfit_res(resource_size_t resource
)
55 struct nfit_test_resource
*res
;
58 res
= __get_nfit_res(resource
);
63 EXPORT_SYMBOL(get_nfit_res
);
65 void __iomem
*__nfit_test_ioremap(resource_size_t offset
, unsigned long size
,
66 void __iomem
*(*fallback_fn
)(resource_size_t
, unsigned long))
68 struct nfit_test_resource
*nfit_res
= get_nfit_res(offset
);
71 return (void __iomem
*) nfit_res
->buf
+ offset
72 - nfit_res
->res
.start
;
73 return fallback_fn(offset
, size
);
76 void __iomem
*__wrap_devm_ioremap_nocache(struct device
*dev
,
77 resource_size_t offset
, unsigned long size
)
79 struct nfit_test_resource
*nfit_res
= get_nfit_res(offset
);
82 return (void __iomem
*) nfit_res
->buf
+ offset
83 - nfit_res
->res
.start
;
84 return devm_ioremap_nocache(dev
, offset
, size
);
86 EXPORT_SYMBOL(__wrap_devm_ioremap_nocache
);
88 void *__wrap_devm_memremap(struct device
*dev
, resource_size_t offset
,
89 size_t size
, unsigned long flags
)
91 struct nfit_test_resource
*nfit_res
= get_nfit_res(offset
);
94 return nfit_res
->buf
+ offset
- nfit_res
->res
.start
;
95 return devm_memremap(dev
, offset
, size
, flags
);
97 EXPORT_SYMBOL(__wrap_devm_memremap
);
99 static void nfit_test_kill(void *_pgmap
)
101 struct dev_pagemap
*pgmap
= _pgmap
;
103 WARN_ON(!pgmap
|| !pgmap
->ref
|| !pgmap
->kill
|| !pgmap
->cleanup
);
104 pgmap
->kill(pgmap
->ref
);
105 pgmap
->cleanup(pgmap
->ref
);
108 void *__wrap_devm_memremap_pages(struct device
*dev
, struct dev_pagemap
*pgmap
)
110 resource_size_t offset
= pgmap
->res
.start
;
111 struct nfit_test_resource
*nfit_res
= get_nfit_res(offset
);
116 rc
= devm_add_action_or_reset(dev
, nfit_test_kill
, pgmap
);
119 return nfit_res
->buf
+ offset
- nfit_res
->res
.start
;
121 return devm_memremap_pages(dev
, pgmap
);
123 EXPORT_SYMBOL_GPL(__wrap_devm_memremap_pages
);
125 pfn_t
__wrap_phys_to_pfn_t(phys_addr_t addr
, unsigned long flags
)
127 struct nfit_test_resource
*nfit_res
= get_nfit_res(addr
);
131 return phys_to_pfn_t(addr
, flags
);
133 EXPORT_SYMBOL(__wrap_phys_to_pfn_t
);
135 void *__wrap_memremap(resource_size_t offset
, size_t size
,
138 struct nfit_test_resource
*nfit_res
= get_nfit_res(offset
);
141 return nfit_res
->buf
+ offset
- nfit_res
->res
.start
;
142 return memremap(offset
, size
, flags
);
144 EXPORT_SYMBOL(__wrap_memremap
);
146 void __wrap_devm_memunmap(struct device
*dev
, void *addr
)
148 struct nfit_test_resource
*nfit_res
= get_nfit_res((long) addr
);
152 return devm_memunmap(dev
, addr
);
154 EXPORT_SYMBOL(__wrap_devm_memunmap
);
156 void __iomem
*__wrap_ioremap_nocache(resource_size_t offset
, unsigned long size
)
158 return __nfit_test_ioremap(offset
, size
, ioremap_nocache
);
160 EXPORT_SYMBOL(__wrap_ioremap_nocache
);
162 void __iomem
*__wrap_ioremap_wc(resource_size_t offset
, unsigned long size
)
164 return __nfit_test_ioremap(offset
, size
, ioremap_wc
);
166 EXPORT_SYMBOL(__wrap_ioremap_wc
);
168 void __wrap_iounmap(volatile void __iomem
*addr
)
170 struct nfit_test_resource
*nfit_res
= get_nfit_res((long) addr
);
173 return iounmap(addr
);
175 EXPORT_SYMBOL(__wrap_iounmap
);
177 void __wrap_memunmap(void *addr
)
179 struct nfit_test_resource
*nfit_res
= get_nfit_res((long) addr
);
183 return memunmap(addr
);
185 EXPORT_SYMBOL(__wrap_memunmap
);
187 static bool nfit_test_release_region(struct device
*dev
,
188 struct resource
*parent
, resource_size_t start
,
191 static void nfit_devres_release(struct device
*dev
, void *data
)
193 struct resource
*res
= *((struct resource
**) data
);
195 WARN_ON(!nfit_test_release_region(NULL
, &iomem_resource
, res
->start
,
196 resource_size(res
)));
199 static int match(struct device
*dev
, void *__res
, void *match_data
)
201 struct resource
*res
= *((struct resource
**) __res
);
202 resource_size_t start
= *((resource_size_t
*) match_data
);
204 return res
->start
== start
;
207 static bool nfit_test_release_region(struct device
*dev
,
208 struct resource
*parent
, resource_size_t start
,
211 if (parent
== &iomem_resource
) {
212 struct nfit_test_resource
*nfit_res
= get_nfit_res(start
);
215 struct nfit_test_request
*req
;
216 struct resource
*res
= NULL
;
219 devres_release(dev
, nfit_devres_release
, match
,
224 spin_lock(&nfit_res
->lock
);
225 list_for_each_entry(req
, &nfit_res
->requests
, list
)
226 if (req
->res
.start
== start
) {
228 list_del(&req
->list
);
231 spin_unlock(&nfit_res
->lock
);
233 WARN(!res
|| resource_size(res
) != n
,
234 "%s: start: %llx n: %llx mismatch: %pr\n",
235 __func__
, start
, n
, res
);
244 static struct resource
*nfit_test_request_region(struct device
*dev
,
245 struct resource
*parent
, resource_size_t start
,
246 resource_size_t n
, const char *name
, int flags
)
248 struct nfit_test_resource
*nfit_res
;
250 if (parent
== &iomem_resource
) {
251 nfit_res
= get_nfit_res(start
);
253 struct nfit_test_request
*req
;
254 struct resource
*res
= NULL
;
256 if (start
+ n
> nfit_res
->res
.start
257 + resource_size(&nfit_res
->res
)) {
258 pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
264 spin_lock(&nfit_res
->lock
);
265 list_for_each_entry(req
, &nfit_res
->requests
, list
)
266 if (start
== req
->res
.start
) {
270 spin_unlock(&nfit_res
->lock
);
273 WARN(1, "%pr already busy\n", res
);
277 req
= kzalloc(sizeof(*req
), GFP_KERNEL
);
280 INIT_LIST_HEAD(&req
->list
);
284 res
->end
= start
+ n
- 1;
286 res
->flags
= resource_type(parent
);
287 res
->flags
|= IORESOURCE_BUSY
| flags
;
288 spin_lock(&nfit_res
->lock
);
289 list_add(&req
->list
, &nfit_res
->requests
);
290 spin_unlock(&nfit_res
->lock
);
295 d
= devres_alloc(nfit_devres_release
,
296 sizeof(struct resource
*),
304 pr_debug("%s: %pr\n", __func__
, res
);
309 return __devm_request_region(dev
, parent
, start
, n
, name
);
310 return __request_region(parent
, start
, n
, name
, flags
);
313 struct resource
*__wrap___request_region(struct resource
*parent
,
314 resource_size_t start
, resource_size_t n
, const char *name
,
317 return nfit_test_request_region(NULL
, parent
, start
, n
, name
, flags
);
319 EXPORT_SYMBOL(__wrap___request_region
);
321 int __wrap_insert_resource(struct resource
*parent
, struct resource
*res
)
323 if (get_nfit_res(res
->start
))
325 return insert_resource(parent
, res
);
327 EXPORT_SYMBOL(__wrap_insert_resource
);
329 int __wrap_remove_resource(struct resource
*res
)
331 if (get_nfit_res(res
->start
))
333 return remove_resource(res
);
335 EXPORT_SYMBOL(__wrap_remove_resource
);
337 struct resource
*__wrap___devm_request_region(struct device
*dev
,
338 struct resource
*parent
, resource_size_t start
,
339 resource_size_t n
, const char *name
)
343 return nfit_test_request_region(dev
, parent
, start
, n
, name
, 0);
345 EXPORT_SYMBOL(__wrap___devm_request_region
);
347 void __wrap___release_region(struct resource
*parent
, resource_size_t start
,
350 if (!nfit_test_release_region(NULL
, parent
, start
, n
))
351 __release_region(parent
, start
, n
);
353 EXPORT_SYMBOL(__wrap___release_region
);
355 void __wrap___devm_release_region(struct device
*dev
, struct resource
*parent
,
356 resource_size_t start
, resource_size_t n
)
358 if (!nfit_test_release_region(dev
, parent
, start
, n
))
359 __devm_release_region(dev
, parent
, start
, n
);
361 EXPORT_SYMBOL(__wrap___devm_release_region
);
363 acpi_status
__wrap_acpi_evaluate_object(acpi_handle handle
, acpi_string path
,
364 struct acpi_object_list
*p
, struct acpi_buffer
*buf
)
366 struct nfit_test_resource
*nfit_res
= get_nfit_res((long) handle
);
367 union acpi_object
**obj
;
369 if (!nfit_res
|| strcmp(path
, "_FIT") || !buf
)
370 return acpi_evaluate_object(handle
, path
, p
, buf
);
373 buf
->length
= sizeof(union acpi_object
);
377 EXPORT_SYMBOL(__wrap_acpi_evaluate_object
);
379 union acpi_object
* __wrap_acpi_evaluate_dsm(acpi_handle handle
, const guid_t
*guid
,
380 u64 rev
, u64 func
, union acpi_object
*argv4
)
382 union acpi_object
*obj
= ERR_PTR(-ENXIO
);
383 struct iomap_ops
*ops
;
386 ops
= list_first_or_null_rcu(&iomap_head
, typeof(*ops
), list
);
388 obj
= ops
->evaluate_dsm(handle
, guid
, rev
, func
, argv4
);
392 return acpi_evaluate_dsm(handle
, guid
, rev
, func
, argv4
);
395 EXPORT_SYMBOL(__wrap_acpi_evaluate_dsm
);
397 MODULE_LICENSE("GPL v2");