Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
0004  */
0005 
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007 
0008 #include <linux/module.h>
0009 #include <linux/io.h>
0010 #include <linux/mmiotrace.h>
0011 #include <linux/security.h>
0012 
0013 static unsigned long mmio_address;
0014 module_param_hw(mmio_address, ulong, iomem, 0);
0015 MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
0016                 "(or 8 MB if read_far is non-zero).");
0017 
0018 static unsigned long read_far = 0x400100;
0019 module_param(read_far, ulong, 0);
0020 MODULE_PARM_DESC(read_far, " Offset of a 32-bit read within 8 MB "
0021                 "(default: 0x400100).");
0022 
0023 static unsigned v16(unsigned i)
0024 {
0025     return i * 12 + 7;
0026 }
0027 
0028 static unsigned v32(unsigned i)
0029 {
0030     return i * 212371 + 13;
0031 }
0032 
0033 static void do_write_test(void __iomem *p)
0034 {
0035     unsigned int i;
0036     pr_info("write test.\n");
0037     mmiotrace_printk("Write test.\n");
0038 
0039     for (i = 0; i < 256; i++)
0040         iowrite8(i, p + i);
0041 
0042     for (i = 1024; i < (5 * 1024); i += 2)
0043         iowrite16(v16(i), p + i);
0044 
0045     for (i = (5 * 1024); i < (16 * 1024); i += 4)
0046         iowrite32(v32(i), p + i);
0047 }
0048 
0049 static void do_read_test(void __iomem *p)
0050 {
0051     unsigned int i;
0052     unsigned errs[3] = { 0 };
0053     pr_info("read test.\n");
0054     mmiotrace_printk("Read test.\n");
0055 
0056     for (i = 0; i < 256; i++)
0057         if (ioread8(p + i) != i)
0058             ++errs[0];
0059 
0060     for (i = 1024; i < (5 * 1024); i += 2)
0061         if (ioread16(p + i) != v16(i))
0062             ++errs[1];
0063 
0064     for (i = (5 * 1024); i < (16 * 1024); i += 4)
0065         if (ioread32(p + i) != v32(i))
0066             ++errs[2];
0067 
0068     mmiotrace_printk("Read errors: 8-bit %d, 16-bit %d, 32-bit %d.\n",
0069                         errs[0], errs[1], errs[2]);
0070 }
0071 
0072 static void do_read_far_test(void __iomem *p)
0073 {
0074     pr_info("read far test.\n");
0075     mmiotrace_printk("Read far test.\n");
0076 
0077     ioread32(p + read_far);
0078 }
0079 
0080 static void do_test(unsigned long size)
0081 {
0082     void __iomem *p = ioremap(mmio_address, size);
0083     if (!p) {
0084         pr_err("could not ioremap, aborting.\n");
0085         return;
0086     }
0087     mmiotrace_printk("ioremap returned %p.\n", p);
0088     do_write_test(p);
0089     do_read_test(p);
0090     if (read_far && read_far < size - 4)
0091         do_read_far_test(p);
0092     iounmap(p);
0093 }
0094 
0095 /*
0096  * Tests how mmiotrace behaves in face of multiple ioremap / iounmaps in
0097  * a short time. We had a bug in deferred freeing procedure which tried
0098  * to free this region multiple times (ioremap can reuse the same address
0099  * for many mappings).
0100  */
0101 static void do_test_bulk_ioremapping(void)
0102 {
0103     void __iomem *p;
0104     int i;
0105 
0106     for (i = 0; i < 10; ++i) {
0107         p = ioremap(mmio_address, PAGE_SIZE);
0108         if (p)
0109             iounmap(p);
0110     }
0111 
0112     /* Force freeing. If it will crash we will know why. */
0113     synchronize_rcu();
0114 }
0115 
0116 static int __init init(void)
0117 {
0118     unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
0119     int ret = security_locked_down(LOCKDOWN_MMIOTRACE);
0120 
0121     if (ret)
0122         return ret;
0123 
0124     if (mmio_address == 0) {
0125         pr_err("you have to use the module argument mmio_address.\n");
0126         pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
0127         return -ENXIO;
0128     }
0129 
0130     pr_warn("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
0131         "and writing 16 kB of rubbish in there.\n",
0132         size >> 10, mmio_address);
0133     do_test(size);
0134     do_test_bulk_ioremapping();
0135     pr_info("All done.\n");
0136     return 0;
0137 }
0138 
0139 static void __exit cleanup(void)
0140 {
0141     pr_debug("unloaded.\n");
0142 }
0143 
0144 module_init(init);
0145 module_exit(cleanup);
0146 MODULE_LICENSE("GPL");