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