xref: /openbmc/linux/mm/memtest.c (revision f373bafcad68834761b40da9cecda842f43d4797)
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