testmmiotrace.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Written by Pekka Paalanen, 2008-2009 <[email protected]>
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/module.h>
  7. #include <linux/io.h>
  8. #include <linux/mmiotrace.h>
  9. #include <linux/security.h>
  10. static unsigned long mmio_address;
  11. module_param_hw(mmio_address, ulong, iomem, 0);
  12. MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
  13. "(or 8 MB if read_far is non-zero).");
  14. static unsigned long read_far = 0x400100;
  15. module_param(read_far, ulong, 0);
  16. MODULE_PARM_DESC(read_far, " Offset of a 32-bit read within 8 MB "
  17. "(default: 0x400100).");
  18. static unsigned v16(unsigned i)
  19. {
  20. return i * 12 + 7;
  21. }
  22. static unsigned v32(unsigned i)
  23. {
  24. return i * 212371 + 13;
  25. }
  26. static void do_write_test(void __iomem *p)
  27. {
  28. unsigned int i;
  29. pr_info("write test.\n");
  30. mmiotrace_printk("Write test.\n");
  31. for (i = 0; i < 256; i++)
  32. iowrite8(i, p + i);
  33. for (i = 1024; i < (5 * 1024); i += 2)
  34. iowrite16(v16(i), p + i);
  35. for (i = (5 * 1024); i < (16 * 1024); i += 4)
  36. iowrite32(v32(i), p + i);
  37. }
  38. static void do_read_test(void __iomem *p)
  39. {
  40. unsigned int i;
  41. unsigned errs[3] = { 0 };
  42. pr_info("read test.\n");
  43. mmiotrace_printk("Read test.\n");
  44. for (i = 0; i < 256; i++)
  45. if (ioread8(p + i) != i)
  46. ++errs[0];
  47. for (i = 1024; i < (5 * 1024); i += 2)
  48. if (ioread16(p + i) != v16(i))
  49. ++errs[1];
  50. for (i = (5 * 1024); i < (16 * 1024); i += 4)
  51. if (ioread32(p + i) != v32(i))
  52. ++errs[2];
  53. mmiotrace_printk("Read errors: 8-bit %d, 16-bit %d, 32-bit %d.\n",
  54. errs[0], errs[1], errs[2]);
  55. }
  56. static void do_read_far_test(void __iomem *p)
  57. {
  58. pr_info("read far test.\n");
  59. mmiotrace_printk("Read far test.\n");
  60. ioread32(p + read_far);
  61. }
  62. static void do_test(unsigned long size)
  63. {
  64. void __iomem *p = ioremap(mmio_address, size);
  65. if (!p) {
  66. pr_err("could not ioremap, aborting.\n");
  67. return;
  68. }
  69. mmiotrace_printk("ioremap returned %p.\n", p);
  70. do_write_test(p);
  71. do_read_test(p);
  72. if (read_far && read_far < size - 4)
  73. do_read_far_test(p);
  74. iounmap(p);
  75. }
  76. /*
  77. * Tests how mmiotrace behaves in face of multiple ioremap / iounmaps in
  78. * a short time. We had a bug in deferred freeing procedure which tried
  79. * to free this region multiple times (ioremap can reuse the same address
  80. * for many mappings).
  81. */
  82. static void do_test_bulk_ioremapping(void)
  83. {
  84. void __iomem *p;
  85. int i;
  86. for (i = 0; i < 10; ++i) {
  87. p = ioremap(mmio_address, PAGE_SIZE);
  88. if (p)
  89. iounmap(p);
  90. }
  91. /* Force freeing. If it will crash we will know why. */
  92. synchronize_rcu();
  93. }
  94. static int __init init(void)
  95. {
  96. unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
  97. int ret = security_locked_down(LOCKDOWN_MMIOTRACE);
  98. if (ret)
  99. return ret;
  100. if (mmio_address == 0) {
  101. pr_err("you have to use the module argument mmio_address.\n");
  102. pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
  103. return -ENXIO;
  104. }
  105. pr_warn("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
  106. "and writing 16 kB of rubbish in there.\n",
  107. size >> 10, mmio_address);
  108. do_test(size);
  109. do_test_bulk_ioremapping();
  110. pr_info("All done.\n");
  111. return 0;
  112. }
  113. static void __exit cleanup(void)
  114. {
  115. pr_debug("unloaded.\n");
  116. }
  117. module_init(init);
  118. module_exit(cleanup);
  119. MODULE_LICENSE("GPL");