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