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 { 34*f373bafcSVladimir Murzin pr_info(" %016llx bad mem addr %pa - %pa reserved\n", 35*f373bafcSVladimir Murzin cpu_to_be64(pattern), &start_bad, &end_bad); 364a20799dSVladimir Murzin memblock_reserve(start_bad, end_bad - start_bad); 374a20799dSVladimir Murzin } 384a20799dSVladimir Murzin 397f70baeeSVladimir Murzin static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size) 404a20799dSVladimir Murzin { 414a20799dSVladimir Murzin u64 *p, *start, *end; 427f70baeeSVladimir Murzin phys_addr_t start_bad, last_bad; 437f70baeeSVladimir Murzin phys_addr_t start_phys_aligned; 444a20799dSVladimir Murzin const size_t incr = sizeof(pattern); 454a20799dSVladimir Murzin 464a20799dSVladimir Murzin start_phys_aligned = ALIGN(start_phys, incr); 474a20799dSVladimir Murzin start = __va(start_phys_aligned); 484a20799dSVladimir Murzin end = start + (size - (start_phys_aligned - start_phys)) / incr; 494a20799dSVladimir Murzin start_bad = 0; 504a20799dSVladimir Murzin last_bad = 0; 514a20799dSVladimir Murzin 524a20799dSVladimir Murzin for (p = start; p < end; p++) 534a20799dSVladimir Murzin *p = pattern; 544a20799dSVladimir Murzin 554a20799dSVladimir Murzin for (p = start; p < end; p++, start_phys_aligned += incr) { 564a20799dSVladimir Murzin if (*p == pattern) 574a20799dSVladimir Murzin continue; 584a20799dSVladimir Murzin if (start_phys_aligned == last_bad + incr) { 594a20799dSVladimir Murzin last_bad += incr; 604a20799dSVladimir Murzin continue; 614a20799dSVladimir Murzin } 624a20799dSVladimir Murzin if (start_bad) 634a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 644a20799dSVladimir Murzin start_bad = last_bad = start_phys_aligned; 654a20799dSVladimir Murzin } 664a20799dSVladimir Murzin if (start_bad) 674a20799dSVladimir Murzin reserve_bad_mem(pattern, start_bad, last_bad + incr); 684a20799dSVladimir Murzin } 694a20799dSVladimir Murzin 707f70baeeSVladimir Murzin static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end) 714a20799dSVladimir Murzin { 724a20799dSVladimir Murzin u64 i; 734a20799dSVladimir Murzin phys_addr_t this_start, this_end; 744a20799dSVladimir Murzin 75fc6daaf9STony Luck for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start, 76fc6daaf9STony Luck &this_end, NULL) { 777f70baeeSVladimir Murzin this_start = clamp(this_start, start, end); 787f70baeeSVladimir Murzin this_end = clamp(this_end, start, end); 794a20799dSVladimir Murzin if (this_start < this_end) { 80*f373bafcSVladimir Murzin pr_info(" %pa - %pa pattern %016llx\n", 81*f373bafcSVladimir Murzin &this_start, &this_end, cpu_to_be64(pattern)); 824a20799dSVladimir Murzin memtest(pattern, this_start, this_end - this_start); 834a20799dSVladimir Murzin } 844a20799dSVladimir Murzin } 854a20799dSVladimir Murzin } 864a20799dSVladimir Murzin 874a20799dSVladimir Murzin /* default is disabled */ 8806f80596SVladimir Murzin static unsigned int memtest_pattern __initdata; 894a20799dSVladimir Murzin 904a20799dSVladimir Murzin static int __init parse_memtest(char *arg) 914a20799dSVladimir Murzin { 9206f80596SVladimir Murzin int ret = 0; 9306f80596SVladimir Murzin 944a20799dSVladimir Murzin if (arg) 9506f80596SVladimir Murzin ret = kstrtouint(arg, 0, &memtest_pattern); 964a20799dSVladimir Murzin else 974a20799dSVladimir Murzin memtest_pattern = ARRAY_SIZE(patterns); 984a20799dSVladimir Murzin 9906f80596SVladimir Murzin return ret; 1004a20799dSVladimir Murzin } 1014a20799dSVladimir Murzin 1024a20799dSVladimir Murzin early_param("memtest", parse_memtest); 1034a20799dSVladimir Murzin 1047f70baeeSVladimir Murzin void __init early_memtest(phys_addr_t start, phys_addr_t end) 1054a20799dSVladimir Murzin { 1064a20799dSVladimir Murzin unsigned int i; 1074a20799dSVladimir Murzin unsigned int idx = 0; 1084a20799dSVladimir Murzin 1094a20799dSVladimir Murzin if (!memtest_pattern) 1104a20799dSVladimir Murzin return; 1114a20799dSVladimir Murzin 112*f373bafcSVladimir Murzin pr_info("early_memtest: # of tests: %u\n", memtest_pattern); 1134a20799dSVladimir Murzin for (i = memtest_pattern-1; i < UINT_MAX; --i) { 1144a20799dSVladimir Murzin idx = i % ARRAY_SIZE(patterns); 1154a20799dSVladimir Murzin do_one_pass(patterns[idx], start, end); 1164a20799dSVladimir Murzin } 1174a20799dSVladimir Murzin } 118