iomap.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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>
  19. #include "nfit_test.h"
  20. static LIST_HEAD(iomap_head);
  21. static struct iomap_ops {
  22. nfit_test_lookup_fn nfit_test_lookup;
  23. struct list_head list;
  24. } iomap_ops = {
  25. .list = LIST_HEAD_INIT(iomap_ops.list),
  26. };
  27. void nfit_test_setup(nfit_test_lookup_fn lookup)
  28. {
  29. iomap_ops.nfit_test_lookup = lookup;
  30. list_add_rcu(&iomap_ops.list, &iomap_head);
  31. }
  32. EXPORT_SYMBOL(nfit_test_setup);
  33. void nfit_test_teardown(void)
  34. {
  35. list_del_rcu(&iomap_ops.list);
  36. synchronize_rcu();
  37. }
  38. EXPORT_SYMBOL(nfit_test_teardown);
  39. static struct nfit_test_resource *get_nfit_res(resource_size_t resource)
  40. {
  41. struct iomap_ops *ops;
  42. ops = list_first_or_null_rcu(&iomap_head, typeof(*ops), list);
  43. if (ops)
  44. return ops->nfit_test_lookup(resource);
  45. return NULL;
  46. }
  47. void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
  48. void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
  49. {
  50. struct nfit_test_resource *nfit_res;
  51. rcu_read_lock();
  52. nfit_res = get_nfit_res(offset);
  53. rcu_read_unlock();
  54. if (nfit_res)
  55. return (void __iomem *) nfit_res->buf + offset
  56. - nfit_res->res->start;
  57. return fallback_fn(offset, size);
  58. }
  59. void __iomem *__wrap_ioremap_cache(resource_size_t offset, unsigned long size)
  60. {
  61. return __nfit_test_ioremap(offset, size, ioremap_cache);
  62. }
  63. EXPORT_SYMBOL(__wrap_ioremap_cache);
  64. void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size)
  65. {
  66. return __nfit_test_ioremap(offset, size, ioremap_nocache);
  67. }
  68. EXPORT_SYMBOL(__wrap_ioremap_nocache);
  69. void __wrap_iounmap(volatile void __iomem *addr)
  70. {
  71. struct nfit_test_resource *nfit_res;
  72. rcu_read_lock();
  73. nfit_res = get_nfit_res((unsigned long) addr);
  74. rcu_read_unlock();
  75. if (nfit_res)
  76. return;
  77. return iounmap(addr);
  78. }
  79. EXPORT_SYMBOL(__wrap_iounmap);
  80. struct resource *__wrap___request_region(struct resource *parent,
  81. resource_size_t start, resource_size_t n, const char *name,
  82. int flags)
  83. {
  84. struct nfit_test_resource *nfit_res;
  85. if (parent == &iomem_resource) {
  86. rcu_read_lock();
  87. nfit_res = get_nfit_res(start);
  88. rcu_read_unlock();
  89. if (nfit_res) {
  90. struct resource *res = nfit_res->res + 1;
  91. if (start + n > nfit_res->res->start
  92. + resource_size(nfit_res->res)) {
  93. pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
  94. __func__, start, n,
  95. nfit_res->res);
  96. return NULL;
  97. }
  98. res->start = start;
  99. res->end = start + n - 1;
  100. res->name = name;
  101. res->flags = resource_type(parent);
  102. res->flags |= IORESOURCE_BUSY | flags;
  103. pr_debug("%s: %pr\n", __func__, res);
  104. return res;
  105. }
  106. }
  107. return __request_region(parent, start, n, name, flags);
  108. }
  109. EXPORT_SYMBOL(__wrap___request_region);
  110. void __wrap___release_region(struct resource *parent, resource_size_t start,
  111. resource_size_t n)
  112. {
  113. struct nfit_test_resource *nfit_res;
  114. if (parent == &iomem_resource) {
  115. rcu_read_lock();
  116. nfit_res = get_nfit_res(start);
  117. rcu_read_unlock();
  118. if (nfit_res) {
  119. struct resource *res = nfit_res->res + 1;
  120. if (start != res->start || resource_size(res) != n)
  121. pr_info("%s: start: %llx n: %llx mismatch: %pr\n",
  122. __func__, start, n, res);
  123. else
  124. memset(res, 0, sizeof(*res));
  125. return;
  126. }
  127. }
  128. __release_region(parent, start, n);
  129. }
  130. EXPORT_SYMBOL(__wrap___release_region);
  131. MODULE_LICENSE("GPL v2");