Merge commit 'origin/master'
[linux-2.6] / arch / x86 / mm / memtest.c
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>
9
10 #include <asm/e820.h>
11
12 static void __init memtest(unsigned long start_phys, unsigned long size,
13                                  unsigned pattern)
14 {
15         unsigned long i;
16         unsigned long *start;
17         unsigned long start_bad;
18         unsigned long last_bad;
19         unsigned long val;
20         unsigned long start_phys_aligned;
21         unsigned long count;
22         unsigned long incr;
23
24         switch (pattern) {
25         case 0:
26                 val = 0UL;
27                 break;
28         case 1:
29                 val = -1UL;
30                 break;
31         case 2:
32 #ifdef CONFIG_X86_64
33                 val = 0x5555555555555555UL;
34 #else
35                 val = 0x55555555UL;
36 #endif
37                 break;
38         case 3:
39 #ifdef CONFIG_X86_64
40                 val = 0xaaaaaaaaaaaaaaaaUL;
41 #else
42                 val = 0xaaaaaaaaUL;
43 #endif
44                 break;
45         default:
46                 return;
47         }
48
49         incr = sizeof(unsigned long);
50         start_phys_aligned = ALIGN(start_phys, incr);
51         count = (size - (start_phys_aligned - start_phys))/incr;
52         start = __va(start_phys_aligned);
53         start_bad = 0;
54         last_bad = 0;
55
56         for (i = 0; i < count; i++)
57                 start[i] = val;
58         for (i = 0; i < count; i++, start++, start_phys_aligned += incr) {
59                 if (*start != val) {
60                         if (start_phys_aligned == last_bad + incr) {
61                                 last_bad += incr;
62                         } else {
63                                 if (start_bad) {
64                                         printk(KERN_CONT "\n  %010lx bad mem addr %010lx - %010lx reserved",
65                                                 val, start_bad, last_bad + incr);
66                                         reserve_early(start_bad, last_bad - start_bad, "BAD RAM");
67                                 }
68                                 start_bad = last_bad = start_phys_aligned;
69                         }
70                 }
71         }
72         if (start_bad) {
73                 printk(KERN_CONT "\n  %016lx bad mem addr %010lx - %010lx reserved",
74                         val, start_bad, last_bad + incr);
75                 reserve_early(start_bad, last_bad - start_bad, "BAD RAM");
76         }
77
78 }
79
80 /* default is disabled */
81 static int memtest_pattern __initdata;
82
83 static int __init parse_memtest(char *arg)
84 {
85         if (arg)
86                 memtest_pattern = simple_strtoul(arg, NULL, 0);
87         return 0;
88 }
89
90 early_param("memtest", parse_memtest);
91
92 void __init early_memtest(unsigned long start, unsigned long end)
93 {
94         u64 t_start, t_size;
95         unsigned pattern;
96
97         if (!memtest_pattern)
98                 return;
99
100         printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern);
101         for (pattern = 0; pattern < memtest_pattern; pattern++) {
102                 t_start = start;
103                 t_size = 0;
104                 while (t_start < end) {
105                         t_start = find_e820_area_size(t_start, &t_size, 1);
106
107                         /* done ? */
108                         if (t_start >= end)
109                                 break;
110                         if (t_start + t_size > end)
111                                 t_size = end - t_start;
112
113                         printk(KERN_CONT "\n  %010llx - %010llx pattern %d",
114                                 (unsigned long long)t_start,
115                                 (unsigned long long)t_start + t_size, pattern);
116
117                         memtest(t_start, t_size, pattern);
118
119                         t_start += t_size;
120                 }
121         }
122         printk(KERN_CONT "\n");
123 }