Merge branch 'for-4.2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj...
[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{
570c9e69
AH
34 printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n",
35 (unsigned long long) pattern,
36 (unsigned long long) start_bad,
37 (unsigned long long) end_bad);
24aa0788 38 memblock_reserve(start_bad, end_bad - start_bad);
7dad169e
AH
39}
40
7f70baee 41static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size)
1f067167 42{
9866b7e8 43 u64 *p, *start, *end;
7f70baee
VM
44 phys_addr_t start_bad, last_bad;
45 phys_addr_t start_phys_aligned;
9866b7e8 46 const size_t incr = sizeof(pattern);
1f067167 47
1f067167 48 start_phys_aligned = ALIGN(start_phys, incr);
1f067167 49 start = __va(start_phys_aligned);
9866b7e8 50 end = start + (size - (start_phys_aligned - start_phys)) / incr;
1f067167
YL
51 start_bad = 0;
52 last_bad = 0;
53
c9690998
AH
54 for (p = start; p < end; p++)
55 *p = pattern;
9866b7e8 56
c9690998
AH
57 for (p = start; p < end; p++, start_phys_aligned += incr) {
58 if (*p == pattern)
7dad169e
AH
59 continue;
60 if (start_phys_aligned == last_bad + incr) {
61 last_bad += incr;
62 continue;
1f067167 63 }
7dad169e
AH
64 if (start_bad)
65 reserve_bad_mem(pattern, start_bad, last_bad + incr);
66 start_bad = last_bad = start_phys_aligned;
1f067167 67 }
7dad169e
AH
68 if (start_bad)
69 reserve_bad_mem(pattern, start_bad, last_bad + incr);
1f067167
YL
70}
71
7f70baee 72static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end)
bfb4dc0d 73{
8d89ac80
TH
74 u64 i;
75 phys_addr_t this_start, this_end;
76
fc6daaf9
TL
77 for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start,
78 &this_end, NULL) {
7f70baee
VM
79 this_start = clamp(this_start, start, end);
80 this_end = clamp(this_end, start, end);
8d89ac80
TH
81 if (this_start < this_end) {
82 printk(KERN_INFO " %010llx - %010llx pattern %016llx\n",
83 (unsigned long long)this_start,
84 (unsigned long long)this_end,
85 (unsigned long long)cpu_to_be64(pattern));
86 memtest(pattern, this_start, this_end - this_start);
87 }
bfb4dc0d
AH
88 }
89}
90
1f067167
YL
91/* default is disabled */
92static int memtest_pattern __initdata;
93
94static int __init parse_memtest(char *arg)
95{
96 if (arg)
97 memtest_pattern = simple_strtoul(arg, NULL, 0);
d1a8e779
YL
98 else
99 memtest_pattern = ARRAY_SIZE(patterns);
100
1f067167
YL
101 return 0;
102}
103
104early_param("memtest", parse_memtest);
105
7f70baee 106void __init early_memtest(phys_addr_t start, phys_addr_t end)
1f067167 107{
6d74171b 108 unsigned int i;
bfb4dc0d 109 unsigned int idx = 0;
1f067167
YL
110
111 if (!memtest_pattern)
112 return;
113
570c9e69 114 printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
20bf062c 115 for (i = memtest_pattern-1; i < UINT_MAX; --i) {
bfb4dc0d
AH
116 idx = i % ARRAY_SIZE(patterns);
117 do_one_pass(patterns[idx], start, end);
118 }
1f067167 119}