14a20799dSVladimir Murzin #include <linux/kernel.h> 24a20799dSVladimir Murzin #include <linux/errno.h> 34a20799dSVladimir Murzin #include <linux/string.h> 44a20799dSVladimir Murzin #include <linux/types.h> 54a20799dSVladimir Murzin #include <linux/mm.h> 64a20799dSVladimir Murzin #include <linux/smp.h> 74a20799dSVladimir Murzin #include <linux/init.h> 84a20799dSVladimir Murzin #include <linux/pfn.h> 94a20799dSVladimir Murzin #include <linux/memblock.h> 104a20799dSVladimir Murzin 114a20799dSVladimir Murzin static u64 patterns[] __initdata = { 124a20799dSVladimir Murzin /* The first entry has to be 0 to leave memtest with zeroed memory */ 134a20799dSVladimir Murzin 0, 144a20799dSVladimir Murzin 0xffffffffffffffffULL, 154a20799dSVladimir Murzin 0x5555555555555555ULL, 164a20799dSVladimir Murzin 0xaaaaaaaaaaaaaaaaULL, 174a20799dSVladimir Murzin 0x1111111111111111ULL, 184a20799dSVladimir Murzin 0x2222222222222222ULL, 194a20799dSVladimir Murzin 0x4444444444444444ULL, 204a20799dSVladimir Murzin 0x8888888888888888ULL, 214a20799dSVladimir Murzin 0x3333333333333333ULL, 224a20799dSVladimir Murzin 0x6666666666666666ULL, 234a20799dSVladimir Murzin 0x9999999999999999ULL, 244a20799dSVladimir Murzin 0xccccccccccccccccULL, 254a20799dSVladimir Murzin 0x7777777777777777ULL, 264a20799dSVladimir Murzin 0xbbbbbbbbbbbbbbbbULL, 274a20799dSVladimir Murzin 0xddddddddddddddddULL, 284a20799dSVladimir Murzin 0xeeeeeeeeeeeeeeeeULL, 294a20799dSVladimir Murzin 0x7a6c7258554e494cULL, /* yeah ;-) */ 304a20799dSVladimir Murzin }; 314a20799dSVladimir Murzin 327f70baeeSVladimir Murzin static void __init reserve_bad_mem(u64 pattern, phys_addr_t start_bad, phys_addr_t end_bad) 334a20799dSVladimir Murzin { 344a20799dSVladimir Murzin printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n", 354a20799dSVladimir Murzin (unsigned long long) pattern, 364a20799dSVladimir Murzin (unsigned long long) start_bad, 374a20799dSVladimir Murzin (unsigned long long) end_bad); 384a20799dSVladimir Murzin memblock_reserve(start_bad, end_bad - start_bad); 394a20799dSVladimir Murzin } 404a20799dSVladimir Murzin 417f70baeeSVladimir Murzin static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size) 424a20799dSVladimir Murzin { 434a20799dSVladimir Murzin u64 *p, *start, *end; 447f70baeeSVladimir Murzin phys_addr_t start_bad, last_bad; 457f70baeeSVladimir Murzin phys_addr_t start_phys_aligned; 464a20799dSVladimir Murzin const size_t incr = sizeof(pattern); 474a20799dSVladimir Murzin 484a20799dSVladimir Murzin start_phys_aligned = ALIGN(start_phys, incr); 494a20799dSVladimir Murzin start = __va(start_phys_aligned); 504a20799dSVladimir Murzin end = start + (size - (start_phys_aligned - start_phys)) / incr; 514a20799dSVladimir Murzin start_bad = 0; 524a20799dSVladimir Murzin last_bad = 0; 534a20799dSVladimir Murzin 544a20799dSVladimir Murzin for (p = start; p < end; p++) 554a20799dSVladimir Murzin *p = pattern; 564a20799dSVladimir Murzin 574a20799dSVladimir Murzin for (p = start; p < end; p++, start_phys_aligned += incr) { 584a20799dSVladimir Murzin if (*p == pattern) 594a20799dSVladimir Murzin continue; 604a20799dSVladimir Murzin if (start_phys_aligned == last_bad + incr) { 614a20799dSVladimir Murzin last_bad += incr; 624a20799dSVladimir Murzin continue; 634a20799dSVladimir Murzin } 644a20799dSVladimir Murzin if (start_bad) 654a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 664a20799dSVladimir Murzin start_bad = last_bad = start_phys_aligned; 674a20799dSVladimir Murzin } 684a20799dSVladimir Murzin if (start_bad) 694a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 704a20799dSVladimir Murzin } 714a20799dSVladimir Murzin 727f70baeeSVladimir Murzin static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end) 734a20799dSVladimir Murzin { 744a20799dSVladimir Murzin u64 i; 754a20799dSVladimir Murzin phys_addr_t this_start, this_end; 764a20799dSVladimir Murzin 77fc6daaf9STony Luck for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start, 78fc6daaf9STony Luck &this_end, NULL) { 797f70baeeSVladimir Murzin this_start = clamp(this_start, start, end); 807f70baeeSVladimir Murzin this_end = clamp(this_end, start, end); 814a20799dSVladimir Murzin if (this_start < this_end) { 824a20799dSVladimir Murzin printk(KERN_INFO " %010llx - %010llx pattern %016llx\n", 834a20799dSVladimir Murzin (unsigned long long)this_start, 844a20799dSVladimir Murzin (unsigned long long)this_end, 854a20799dSVladimir Murzin (unsigned long long)cpu_to_be64(pattern)); 864a20799dSVladimir Murzin memtest(pattern, this_start, this_end - this_start); 874a20799dSVladimir Murzin } 884a20799dSVladimir Murzin } 894a20799dSVladimir Murzin } 904a20799dSVladimir Murzin 914a20799dSVladimir Murzin /* default is disabled */ 92*06f80596SVladimir Murzin static unsigned int memtest_pattern __initdata; 934a20799dSVladimir Murzin 944a20799dSVladimir Murzin static int __init parse_memtest(char *arg) 954a20799dSVladimir Murzin { 96*06f80596SVladimir Murzin int ret = 0; 97*06f80596SVladimir Murzin 984a20799dSVladimir Murzin if (arg) 99*06f80596SVladimir Murzin ret = kstrtouint(arg, 0, &memtest_pattern); 1004a20799dSVladimir Murzin else 1014a20799dSVladimir Murzin memtest_pattern = ARRAY_SIZE(patterns); 1024a20799dSVladimir Murzin 103*06f80596SVladimir Murzin return ret; 1044a20799dSVladimir Murzin } 1054a20799dSVladimir Murzin 1064a20799dSVladimir Murzin early_param("memtest", parse_memtest); 1074a20799dSVladimir Murzin 1087f70baeeSVladimir Murzin void __init early_memtest(phys_addr_t start, phys_addr_t end) 1094a20799dSVladimir Murzin { 1104a20799dSVladimir Murzin unsigned int i; 1114a20799dSVladimir Murzin unsigned int idx = 0; 1124a20799dSVladimir Murzin 1134a20799dSVladimir Murzin if (!memtest_pattern) 1144a20799dSVladimir Murzin return; 1154a20799dSVladimir Murzin 1164a20799dSVladimir Murzin printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); 1174a20799dSVladimir Murzin for (i = memtest_pattern-1; i < UINT_MAX; --i) { 1184a20799dSVladimir Murzin idx = i % ARRAY_SIZE(patterns); 1194a20799dSVladimir Murzin do_one_pass(patterns[idx], start, end); 1204a20799dSVladimir Murzin } 1214a20799dSVladimir Murzin } 122