Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[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
9a28f9dc 77 for_each_free_mem_range(i, NUMA_NO_NODE, &this_start, &this_end, NULL) {
7f70baee
VM
78 this_start = clamp(this_start, start, end);
79 this_end = clamp(this_end, start, end);
8d89ac80
TH
80 if (this_start < this_end) {
81 printk(KERN_INFO " %010llx - %010llx pattern %016llx\n",
82 (unsigned long long)this_start,
83 (unsigned long long)this_end,
84 (unsigned long long)cpu_to_be64(pattern));
85 memtest(pattern, this_start, this_end - this_start);
86 }
bfb4dc0d
AH
87 }
88}
89
1f067167
YL
90/* default is disabled */
91static int memtest_pattern __initdata;
92
93static int __init parse_memtest(char *arg)
94{
95 if (arg)
96 memtest_pattern = simple_strtoul(arg, NULL, 0);
d1a8e779
YL
97 else
98 memtest_pattern = ARRAY_SIZE(patterns);
99
1f067167
YL
100 return 0;
101}
102
103early_param("memtest", parse_memtest);
104
7f70baee 105void __init early_memtest(phys_addr_t start, phys_addr_t end)
1f067167 106{
6d74171b 107 unsigned int i;
bfb4dc0d 108 unsigned int idx = 0;
1f067167
YL
109
110 if (!memtest_pattern)
111 return;
112
570c9e69 113 printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
20bf062c 114 for (i = memtest_pattern-1; i < UINT_MAX; --i) {
bfb4dc0d
AH
115 idx = i % ARRAY_SIZE(patterns);
116 do_one_pass(patterns[idx], start, end);
117 }
1f067167 118}