2008-07-15 11:02:28 +04:00
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/init.h>
2010-08-26 00:39:17 +04:00
# include <linux/memblock.h>
2008-07-15 11:02:28 +04:00
2009-02-25 13:27:27 +03:00
static u64 patterns [ ] __initdata = {
2013-02-16 19:38:17 +04:00
/* The first entry has to be 0 to leave memtest with zeroed memory */
2009-02-25 13:27:27 +03:00
0 ,
0xffffffffffffffffULL ,
0x5555555555555555ULL ,
0xaaaaaaaaaaaaaaaaULL ,
2009-02-25 13:31:49 +03:00
0x1111111111111111ULL ,
0x2222222222222222ULL ,
0x4444444444444444ULL ,
0x8888888888888888ULL ,
0x3333333333333333ULL ,
0x6666666666666666ULL ,
0x9999999999999999ULL ,
0xccccccccccccccccULL ,
0x7777777777777777ULL ,
0xbbbbbbbbbbbbbbbbULL ,
0xddddddddddddddddULL ,
0xeeeeeeeeeeeeeeeeULL ,
0x7a6c7258554e494cULL , /* yeah ;-) */
2009-02-25 13:27:27 +03:00
} ;
2009-02-25 13:26:18 +03:00
2015-04-15 01:48:30 +03:00
static void __init reserve_bad_mem ( u64 pattern , phys_addr_t start_bad , phys_addr_t end_bad )
2009-02-25 13:28:07 +03:00
{
2015-09-09 01:00:19 +03:00
pr_info ( " %016llx bad mem addr %pa - %pa reserved \n " ,
cpu_to_be64 ( pattern ) , & start_bad , & end_bad ) ;
2011-07-12 13:16:06 +04:00
memblock_reserve ( start_bad , end_bad - start_bad ) ;
2009-02-25 13:28:07 +03:00
}
2015-04-15 01:48:30 +03:00
static void __init memtest ( u64 pattern , phys_addr_t start_phys , phys_addr_t size )
2008-07-15 11:02:28 +04:00
{
2009-06-11 18:25:01 +04:00
u64 * p , * start , * end ;
2015-04-15 01:48:30 +03:00
phys_addr_t start_bad , last_bad ;
phys_addr_t start_phys_aligned ;
2009-06-11 18:25:01 +04:00
const size_t incr = sizeof ( pattern ) ;
2008-07-15 11:02:28 +04:00
start_phys_aligned = ALIGN ( start_phys , incr ) ;
start = __va ( start_phys_aligned ) ;
2009-06-11 18:25:01 +04:00
end = start + ( size - ( start_phys_aligned - start_phys ) ) / incr ;
2008-07-15 11:02:28 +04:00
start_bad = 0 ;
last_bad = 0 ;
2009-06-08 21:09:39 +04:00
for ( p = start ; p < end ; p + + )
* p = pattern ;
2009-06-11 18:25:01 +04:00
2009-06-08 21:09:39 +04:00
for ( p = start ; p < end ; p + + , start_phys_aligned + = incr ) {
if ( * p = = pattern )
2009-02-25 13:28:07 +03:00
continue ;
if ( start_phys_aligned = = last_bad + incr ) {
last_bad + = incr ;
continue ;
2008-07-15 11:02:28 +04:00
}
2009-02-25 13:28:07 +03:00
if ( start_bad )
reserve_bad_mem ( pattern , start_bad , last_bad + incr ) ;
start_bad = last_bad = start_phys_aligned ;
2008-07-15 11:02:28 +04:00
}
2009-02-25 13:28:07 +03:00
if ( start_bad )
reserve_bad_mem ( pattern , start_bad , last_bad + incr ) ;
2008-07-15 11:02:28 +04:00
}
2015-04-15 01:48:30 +03:00
static void __init do_one_pass ( u64 pattern , phys_addr_t start , phys_addr_t end )
2009-02-25 13:30:04 +03:00
{
2011-07-12 13:16:00 +04:00
u64 i ;
phys_addr_t this_start , this_end ;
2015-06-25 02:58:09 +03:00
for_each_free_mem_range ( i , NUMA_NO_NODE , MEMBLOCK_NONE , & this_start ,
& this_end , NULL ) {
2015-04-15 01:48:30 +03:00
this_start = clamp ( this_start , start , end ) ;
this_end = clamp ( this_end , start , end ) ;
2011-07-12 13:16:00 +04:00
if ( this_start < this_end ) {
2015-09-09 01:00:19 +03:00
pr_info ( " %pa - %pa pattern %016llx \n " ,
& this_start , & this_end , cpu_to_be64 ( pattern ) ) ;
2011-07-12 13:16:00 +04:00
memtest ( pattern , this_start , this_end - this_start ) ;
}
2009-02-25 13:30:04 +03:00
}
}
2008-07-15 11:02:28 +04:00
/* default is disabled */
2015-09-09 01:00:16 +03:00
static unsigned int memtest_pattern __initdata ;
2008-07-15 11:02:28 +04:00
static int __init parse_memtest ( char * arg )
{
2015-09-09 01:00:16 +03:00
int ret = 0 ;
2008-07-15 11:02:28 +04:00
if ( arg )
2015-09-09 01:00:16 +03:00
ret = kstrtouint ( arg , 0 , & memtest_pattern ) ;
2009-03-06 14:12:50 +03:00
else
memtest_pattern = ARRAY_SIZE ( patterns ) ;
2015-09-09 01:00:16 +03:00
return ret ;
2008-07-15 11:02:28 +04:00
}
early_param ( " memtest " , parse_memtest ) ;
2015-04-15 01:48:30 +03:00
void __init early_memtest ( phys_addr_t start , phys_addr_t end )
2008-07-15 11:02:28 +04:00
{
2009-02-25 13:27:27 +03:00
unsigned int i ;
2009-02-25 13:30:04 +03:00
unsigned int idx = 0 ;
2008-07-15 11:02:28 +04:00
if ( ! memtest_pattern )
return ;
2015-09-09 01:00:19 +03:00
pr_info ( " early_memtest: # of tests: %u \n " , memtest_pattern ) ;
2013-02-16 19:38:17 +04:00
for ( i = memtest_pattern - 1 ; i < UINT_MAX ; - - i ) {
2009-02-25 13:30:04 +03:00
idx = i % ARRAY_SIZE ( patterns ) ;
do_one_pass ( patterns [ idx ] , start , end ) ;
}
2008-07-15 11:02:28 +04:00
}