1*4a20799dSVladimir Murzin #include <linux/kernel.h> 2*4a20799dSVladimir Murzin #include <linux/errno.h> 3*4a20799dSVladimir Murzin #include <linux/string.h> 4*4a20799dSVladimir Murzin #include <linux/types.h> 5*4a20799dSVladimir Murzin #include <linux/mm.h> 6*4a20799dSVladimir Murzin #include <linux/smp.h> 7*4a20799dSVladimir Murzin #include <linux/init.h> 8*4a20799dSVladimir Murzin #include <linux/pfn.h> 9*4a20799dSVladimir Murzin #include <linux/memblock.h> 10*4a20799dSVladimir Murzin 11*4a20799dSVladimir Murzin static u64 patterns[] __initdata = { 12*4a20799dSVladimir Murzin /* The first entry has to be 0 to leave memtest with zeroed memory */ 13*4a20799dSVladimir Murzin 0, 14*4a20799dSVladimir Murzin 0xffffffffffffffffULL, 15*4a20799dSVladimir Murzin 0x5555555555555555ULL, 16*4a20799dSVladimir Murzin 0xaaaaaaaaaaaaaaaaULL, 17*4a20799dSVladimir Murzin 0x1111111111111111ULL, 18*4a20799dSVladimir Murzin 0x2222222222222222ULL, 19*4a20799dSVladimir Murzin 0x4444444444444444ULL, 20*4a20799dSVladimir Murzin 0x8888888888888888ULL, 21*4a20799dSVladimir Murzin 0x3333333333333333ULL, 22*4a20799dSVladimir Murzin 0x6666666666666666ULL, 23*4a20799dSVladimir Murzin 0x9999999999999999ULL, 24*4a20799dSVladimir Murzin 0xccccccccccccccccULL, 25*4a20799dSVladimir Murzin 0x7777777777777777ULL, 26*4a20799dSVladimir Murzin 0xbbbbbbbbbbbbbbbbULL, 27*4a20799dSVladimir Murzin 0xddddddddddddddddULL, 28*4a20799dSVladimir Murzin 0xeeeeeeeeeeeeeeeeULL, 29*4a20799dSVladimir Murzin 0x7a6c7258554e494cULL, /* yeah ;-) */ 30*4a20799dSVladimir Murzin }; 31*4a20799dSVladimir Murzin 32*4a20799dSVladimir Murzin static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad) 33*4a20799dSVladimir Murzin { 34*4a20799dSVladimir Murzin printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n", 35*4a20799dSVladimir Murzin (unsigned long long) pattern, 36*4a20799dSVladimir Murzin (unsigned long long) start_bad, 37*4a20799dSVladimir Murzin (unsigned long long) end_bad); 38*4a20799dSVladimir Murzin memblock_reserve(start_bad, end_bad - start_bad); 39*4a20799dSVladimir Murzin } 40*4a20799dSVladimir Murzin 41*4a20799dSVladimir Murzin static void __init memtest(u64 pattern, u64 start_phys, u64 size) 42*4a20799dSVladimir Murzin { 43*4a20799dSVladimir Murzin u64 *p, *start, *end; 44*4a20799dSVladimir Murzin u64 start_bad, last_bad; 45*4a20799dSVladimir Murzin u64 start_phys_aligned; 46*4a20799dSVladimir Murzin const size_t incr = sizeof(pattern); 47*4a20799dSVladimir Murzin 48*4a20799dSVladimir Murzin start_phys_aligned = ALIGN(start_phys, incr); 49*4a20799dSVladimir Murzin start = __va(start_phys_aligned); 50*4a20799dSVladimir Murzin end = start + (size - (start_phys_aligned - start_phys)) / incr; 51*4a20799dSVladimir Murzin start_bad = 0; 52*4a20799dSVladimir Murzin last_bad = 0; 53*4a20799dSVladimir Murzin 54*4a20799dSVladimir Murzin for (p = start; p < end; p++) 55*4a20799dSVladimir Murzin *p = pattern; 56*4a20799dSVladimir Murzin 57*4a20799dSVladimir Murzin for (p = start; p < end; p++, start_phys_aligned += incr) { 58*4a20799dSVladimir Murzin if (*p == pattern) 59*4a20799dSVladimir Murzin continue; 60*4a20799dSVladimir Murzin if (start_phys_aligned == last_bad + incr) { 61*4a20799dSVladimir Murzin last_bad += incr; 62*4a20799dSVladimir Murzin continue; 63*4a20799dSVladimir Murzin } 64*4a20799dSVladimir Murzin if (start_bad) 65*4a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 66*4a20799dSVladimir Murzin start_bad = last_bad = start_phys_aligned; 67*4a20799dSVladimir Murzin } 68*4a20799dSVladimir Murzin if (start_bad) 69*4a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 70*4a20799dSVladimir Murzin } 71*4a20799dSVladimir Murzin 72*4a20799dSVladimir Murzin static void __init do_one_pass(u64 pattern, u64 start, u64 end) 73*4a20799dSVladimir Murzin { 74*4a20799dSVladimir Murzin u64 i; 75*4a20799dSVladimir Murzin phys_addr_t this_start, this_end; 76*4a20799dSVladimir Murzin 77*4a20799dSVladimir Murzin for_each_free_mem_range(i, NUMA_NO_NODE, &this_start, &this_end, NULL) { 78*4a20799dSVladimir Murzin this_start = clamp_t(phys_addr_t, this_start, start, end); 79*4a20799dSVladimir Murzin this_end = clamp_t(phys_addr_t, this_end, start, end); 80*4a20799dSVladimir Murzin if (this_start < this_end) { 81*4a20799dSVladimir Murzin printk(KERN_INFO " %010llx - %010llx pattern %016llx\n", 82*4a20799dSVladimir Murzin (unsigned long long)this_start, 83*4a20799dSVladimir Murzin (unsigned long long)this_end, 84*4a20799dSVladimir Murzin (unsigned long long)cpu_to_be64(pattern)); 85*4a20799dSVladimir Murzin memtest(pattern, this_start, this_end - this_start); 86*4a20799dSVladimir Murzin } 87*4a20799dSVladimir Murzin } 88*4a20799dSVladimir Murzin } 89*4a20799dSVladimir Murzin 90*4a20799dSVladimir Murzin /* default is disabled */ 91*4a20799dSVladimir Murzin static int memtest_pattern __initdata; 92*4a20799dSVladimir Murzin 93*4a20799dSVladimir Murzin static int __init parse_memtest(char *arg) 94*4a20799dSVladimir Murzin { 95*4a20799dSVladimir Murzin if (arg) 96*4a20799dSVladimir Murzin memtest_pattern = simple_strtoul(arg, NULL, 0); 97*4a20799dSVladimir Murzin else 98*4a20799dSVladimir Murzin memtest_pattern = ARRAY_SIZE(patterns); 99*4a20799dSVladimir Murzin 100*4a20799dSVladimir Murzin return 0; 101*4a20799dSVladimir Murzin } 102*4a20799dSVladimir Murzin 103*4a20799dSVladimir Murzin early_param("memtest", parse_memtest); 104*4a20799dSVladimir Murzin 105*4a20799dSVladimir Murzin void __init early_memtest(unsigned long start, unsigned long end) 106*4a20799dSVladimir Murzin { 107*4a20799dSVladimir Murzin unsigned int i; 108*4a20799dSVladimir Murzin unsigned int idx = 0; 109*4a20799dSVladimir Murzin 110*4a20799dSVladimir Murzin if (!memtest_pattern) 111*4a20799dSVladimir Murzin return; 112*4a20799dSVladimir Murzin 113*4a20799dSVladimir Murzin printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); 114*4a20799dSVladimir Murzin for (i = memtest_pattern-1; i < UINT_MAX; --i) { 115*4a20799dSVladimir Murzin idx = i % ARRAY_SIZE(patterns); 116*4a20799dSVladimir Murzin do_one_pass(patterns[idx], start, end); 117*4a20799dSVladimir Murzin } 118*4a20799dSVladimir Murzin } 119