0001
0002 #include <linux/kernel.h>
0003 #include <linux/types.h>
0004 #include <linux/init.h>
0005 #include <linux/memblock.h>
0006
0007 static u64 patterns[] __initdata = {
0008
0009 0,
0010 0xffffffffffffffffULL,
0011 0x5555555555555555ULL,
0012 0xaaaaaaaaaaaaaaaaULL,
0013 0x1111111111111111ULL,
0014 0x2222222222222222ULL,
0015 0x4444444444444444ULL,
0016 0x8888888888888888ULL,
0017 0x3333333333333333ULL,
0018 0x6666666666666666ULL,
0019 0x9999999999999999ULL,
0020 0xccccccccccccccccULL,
0021 0x7777777777777777ULL,
0022 0xbbbbbbbbbbbbbbbbULL,
0023 0xddddddddddddddddULL,
0024 0xeeeeeeeeeeeeeeeeULL,
0025 0x7a6c7258554e494cULL,
0026 };
0027
0028 static void __init reserve_bad_mem(u64 pattern, phys_addr_t start_bad, phys_addr_t end_bad)
0029 {
0030 pr_info(" %016llx bad mem addr %pa - %pa reserved\n",
0031 cpu_to_be64(pattern), &start_bad, &end_bad);
0032 memblock_reserve(start_bad, end_bad - start_bad);
0033 }
0034
0035 static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size)
0036 {
0037 u64 *p, *start, *end;
0038 phys_addr_t start_bad, last_bad;
0039 phys_addr_t start_phys_aligned;
0040 const size_t incr = sizeof(pattern);
0041
0042 start_phys_aligned = ALIGN(start_phys, incr);
0043 start = __va(start_phys_aligned);
0044 end = start + (size - (start_phys_aligned - start_phys)) / incr;
0045 start_bad = 0;
0046 last_bad = 0;
0047
0048 for (p = start; p < end; p++)
0049 *p = pattern;
0050
0051 for (p = start; p < end; p++, start_phys_aligned += incr) {
0052 if (*p == pattern)
0053 continue;
0054 if (start_phys_aligned == last_bad + incr) {
0055 last_bad += incr;
0056 continue;
0057 }
0058 if (start_bad)
0059 reserve_bad_mem(pattern, start_bad, last_bad + incr);
0060 start_bad = last_bad = start_phys_aligned;
0061 }
0062 if (start_bad)
0063 reserve_bad_mem(pattern, start_bad, last_bad + incr);
0064 }
0065
0066 static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end)
0067 {
0068 u64 i;
0069 phys_addr_t this_start, this_end;
0070
0071 for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start,
0072 &this_end, NULL) {
0073 this_start = clamp(this_start, start, end);
0074 this_end = clamp(this_end, start, end);
0075 if (this_start < this_end) {
0076 pr_info(" %pa - %pa pattern %016llx\n",
0077 &this_start, &this_end, cpu_to_be64(pattern));
0078 memtest(pattern, this_start, this_end - this_start);
0079 }
0080 }
0081 }
0082
0083
0084 static unsigned int memtest_pattern __initdata;
0085
0086 static int __init parse_memtest(char *arg)
0087 {
0088 int ret = 0;
0089
0090 if (arg)
0091 ret = kstrtouint(arg, 0, &memtest_pattern);
0092 else
0093 memtest_pattern = ARRAY_SIZE(patterns);
0094
0095 return ret;
0096 }
0097
0098 early_param("memtest", parse_memtest);
0099
0100 void __init early_memtest(phys_addr_t start, phys_addr_t end)
0101 {
0102 unsigned int i;
0103 unsigned int idx = 0;
0104
0105 if (!memtest_pattern)
0106 return;
0107
0108 pr_info("early_memtest: # of tests: %u\n", memtest_pattern);
0109 for (i = memtest_pattern-1; i < UINT_MAX; --i) {
0110 idx = i % ARRAY_SIZE(patterns);
0111 do_one_pass(patterns[idx], start, end);
0112 }
0113 }