2008-05-12 23:20:56 +04:00
/*
2009-03-01 17:09:14 +03:00
* Written by Pekka Paalanen , 2008 - 2009 < pq @ iki . fi >
2008-05-12 23:20:56 +04:00
*/
2009-10-05 04:53:40 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-05-12 23:20:56 +04:00
# include <linux/module.h>
2008-05-12 23:21:03 +04:00
# include <linux/io.h>
2008-09-16 23:00:34 +04:00
# include <linux/mmiotrace.h>
2008-05-12 23:20:56 +04:00
static unsigned long mmio_address ;
module_param ( mmio_address , ulong , 0 ) ;
2009-03-01 17:10:08 +03:00
MODULE_PARM_DESC ( mmio_address , " Start address of the mapping of 16 kB "
" (or 8 MB if read_far is non-zero). " ) ;
static unsigned long read_far = 0x400100 ;
module_param ( read_far , ulong , 0 ) ;
MODULE_PARM_DESC ( read_far , " Offset of a 32-bit read within 8 MB "
" (default: 0x400100). " ) ;
2008-05-12 23:20:56 +04:00
2009-03-01 17:09:14 +03:00
static unsigned v16 ( unsigned i )
{
return i * 12 + 7 ;
}
static unsigned v32 ( unsigned i )
{
return i * 212371 + 13 ;
}
2008-05-12 23:20:56 +04:00
static void do_write_test ( void __iomem * p )
{
unsigned int i ;
2009-10-05 04:53:40 +04:00
pr_info ( " write test. \n " ) ;
2008-09-16 23:00:34 +04:00
mmiotrace_printk ( " Write test. \n " ) ;
2009-03-01 17:09:14 +03:00
2008-05-12 23:20:56 +04:00
for ( i = 0 ; i < 256 ; i + + )
iowrite8 ( i , p + i ) ;
2009-03-01 17:09:14 +03:00
2008-05-12 23:20:56 +04:00
for ( i = 1024 ; i < ( 5 * 1024 ) ; i + = 2 )
2009-03-01 17:09:14 +03:00
iowrite16 ( v16 ( i ) , p + i ) ;
2008-05-12 23:20:56 +04:00
for ( i = ( 5 * 1024 ) ; i < ( 16 * 1024 ) ; i + = 4 )
2009-03-01 17:09:14 +03:00
iowrite32 ( v32 ( i ) , p + i ) ;
2008-05-12 23:20:56 +04:00
}
static void do_read_test ( void __iomem * p )
{
unsigned int i ;
2009-03-01 17:09:14 +03:00
unsigned errs [ 3 ] = { 0 } ;
2009-10-05 04:53:40 +04:00
pr_info ( " read test. \n " ) ;
2008-09-16 23:00:34 +04:00
mmiotrace_printk ( " Read test. \n " ) ;
2009-03-01 17:09:14 +03:00
2008-05-12 23:20:56 +04:00
for ( i = 0 ; i < 256 ; i + + )
2009-03-01 17:09:14 +03:00
if ( ioread8 ( p + i ) ! = i )
+ + errs [ 0 ] ;
2008-05-12 23:20:56 +04:00
for ( i = 1024 ; i < ( 5 * 1024 ) ; i + = 2 )
2009-03-01 17:09:14 +03:00
if ( ioread16 ( p + i ) ! = v16 ( i ) )
+ + errs [ 1 ] ;
2008-05-12 23:20:56 +04:00
for ( i = ( 5 * 1024 ) ; i < ( 16 * 1024 ) ; i + = 4 )
2009-03-01 17:09:14 +03:00
if ( ioread32 ( p + i ) ! = v32 ( i ) )
+ + errs [ 2 ] ;
mmiotrace_printk ( " Read errors: 8-bit %d, 16-bit %d, 32-bit %d. \n " ,
errs [ 0 ] , errs [ 1 ] , errs [ 2 ] ) ;
2008-05-12 23:20:56 +04:00
}
2009-03-01 17:10:08 +03:00
static void do_read_far_test ( void __iomem * p )
{
2009-10-05 04:53:40 +04:00
pr_info ( " read far test. \n " ) ;
2009-03-01 17:10:08 +03:00
mmiotrace_printk ( " Read far test. \n " ) ;
ioread32 ( p + read_far ) ;
}
static void do_test ( unsigned long size )
2008-05-12 23:20:56 +04:00
{
2009-03-01 17:10:08 +03:00
void __iomem * p = ioremap_nocache ( mmio_address , size ) ;
2008-05-12 23:20:56 +04:00
if ( ! p ) {
2009-10-05 04:53:40 +04:00
pr_err ( " could not ioremap, aborting. \n " ) ;
2008-05-12 23:20:56 +04:00
return ;
}
2008-09-16 23:00:34 +04:00
mmiotrace_printk ( " ioremap returned %p. \n " , p ) ;
2008-05-12 23:20:56 +04:00
do_write_test ( p ) ;
do_read_test ( p ) ;
2009-03-01 17:10:08 +03:00
if ( read_far & & read_far < size - 4 )
do_read_far_test ( p ) ;
2008-05-12 23:20:57 +04:00
iounmap ( p ) ;
2008-05-12 23:20:56 +04:00
}
2010-06-14 01:56:54 +04:00
/*
* Tests how mmiotrace behaves in face of multiple ioremap / iounmaps in
* a short time . We had a bug in deferred freeing procedure which tried
* to free this region multiple times ( ioremap can reuse the same address
* for many mappings ) .
*/
static void do_test_bulk_ioremapping ( void )
{
void __iomem * p ;
int i ;
for ( i = 0 ; i < 10 ; + + i ) {
p = ioremap_nocache ( mmio_address , PAGE_SIZE ) ;
if ( p )
iounmap ( p ) ;
}
/* Force freeing. If it will crash we will know why. */
synchronize_rcu ( ) ;
}
2008-05-12 23:20:56 +04:00
static int __init init ( void )
{
2009-03-01 17:10:08 +03:00
unsigned long size = ( read_far ) ? ( 8 < < 20 ) : ( 16 < < 10 ) ;
2008-05-12 23:20:56 +04:00
if ( mmio_address = = 0 ) {
2009-10-05 04:53:40 +04:00
pr_err ( " you have to use the module argument mmio_address. \n " ) ;
pr_err ( " DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! \n " ) ;
2008-05-12 23:20:56 +04:00
return - ENXIO ;
}
2009-10-05 04:53:40 +04:00
pr_warning ( " WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
" and writing 16 kB of rubbish in there. \n " ,
size > > 10 , mmio_address ) ;
2009-03-01 17:10:08 +03:00
do_test ( size ) ;
2010-06-14 01:56:54 +04:00
do_test_bulk_ioremapping ( ) ;
2009-10-05 04:53:40 +04:00
pr_info ( " All done. \n " ) ;
2008-05-12 23:20:56 +04:00
return 0 ;
}
static void __exit cleanup ( void )
{
2009-10-05 04:53:40 +04:00
pr_debug ( " unloaded. \n " ) ;
2008-05-12 23:20:56 +04:00
}
module_init ( init ) ;
module_exit ( cleanup ) ;
MODULE_LICENSE ( " GPL " ) ;