]> git.ipfire.org Git - thirdparty/linux.git/blame - mm/memtest.c
dt-bindings: arm: tegra: pmc: Remove useless boilerplate descriptions
[thirdparty/linux.git] / mm / memtest.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1f067167 2#include <linux/kernel.h>
1f067167 3#include <linux/types.h>
1f067167 4#include <linux/init.h>
a9ce6bc1 5#include <linux/memblock.h>
3f32c49e 6#include <linux/seq_file.h>
1f067167 7
3f32c49e
KW
8static bool early_memtest_done;
9static phys_addr_t early_memtest_bad_size;
bd23024b 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);
bd23024b 37 early_memtest_bad_size += (end_bad - start_bad);
7dad169e
AH
38}
39
7f70baee 40static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size)
1f067167 41{
9866b7e8 42 u64 *p, *start, *end;
7f70baee
VM
43 phys_addr_t start_bad, last_bad;
44 phys_addr_t start_phys_aligned;
9866b7e8 45 const size_t incr = sizeof(pattern);
1f067167 46
1f067167 47 start_phys_aligned = ALIGN(start_phys, incr);
1f067167 48 start = __va(start_phys_aligned);
9866b7e8 49 end = start + (size - (start_phys_aligned - start_phys)) / incr;
1f067167
YL
50 start_bad = 0;
51 last_bad = 0;
52
c9690998
AH
53 for (p = start; p < end; p++)
54 *p = pattern;
9866b7e8 55
c9690998
AH
56 for (p = start; p < end; p++, start_phys_aligned += incr) {
57 if (*p == pattern)
7dad169e
AH
58 continue;
59 if (start_phys_aligned == last_bad + incr) {
60 last_bad += incr;
61 continue;
1f067167 62 }
7dad169e
AH
63 if (start_bad)
64 reserve_bad_mem(pattern, start_bad, last_bad + incr);
65 start_bad = last_bad = start_phys_aligned;
1f067167 66 }
7dad169e
AH
67 if (start_bad)
68 reserve_bad_mem(pattern, start_bad, last_bad + incr);
bd23024b
TM
69
70 early_memtest_done = true;
1f067167
YL
71}
72
7f70baee 73static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end)
bfb4dc0d 74{
8d89ac80
TH
75 u64 i;
76 phys_addr_t this_start, this_end;
77
fc6daaf9
TL
78 for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start,
79 &this_end, NULL) {
7f70baee
VM
80 this_start = clamp(this_start, start, end);
81 this_end = clamp(this_end, start, end);
8d89ac80 82 if (this_start < this_end) {
f373bafc
VM
83 pr_info(" %pa - %pa pattern %016llx\n",
84 &this_start, &this_end, cpu_to_be64(pattern));
8d89ac80
TH
85 memtest(pattern, this_start, this_end - this_start);
86 }
bfb4dc0d
AH
87 }
88}
89
1f067167 90/* default is disabled */
06f80596 91static unsigned int memtest_pattern __initdata;
1f067167
YL
92
93static int __init parse_memtest(char *arg)
94{
06f80596
VM
95 int ret = 0;
96
1f067167 97 if (arg)
06f80596 98 ret = kstrtouint(arg, 0, &memtest_pattern);
d1a8e779
YL
99 else
100 memtest_pattern = ARRAY_SIZE(patterns);
101
06f80596 102 return ret;
1f067167
YL
103}
104
105early_param("memtest", parse_memtest);
106
7f70baee 107void __init early_memtest(phys_addr_t start, phys_addr_t end)
1f067167 108{
6d74171b 109 unsigned int i;
bfb4dc0d 110 unsigned int idx = 0;
1f067167
YL
111
112 if (!memtest_pattern)
113 return;
114
f373bafc 115 pr_info("early_memtest: # of tests: %u\n", memtest_pattern);
20bf062c 116 for (i = memtest_pattern-1; i < UINT_MAX; --i) {
bfb4dc0d
AH
117 idx = i % ARRAY_SIZE(patterns);
118 do_one_pass(patterns[idx], start, end);
119 }
1f067167 120}
3f32c49e
KW
121
122void memtest_report_meminfo(struct seq_file *m)
123{
124 unsigned long early_memtest_bad_size_kb;
125
126 if (!IS_ENABLED(CONFIG_PROC_FS))
127 return;
128
129 if (!early_memtest_done)
130 return;
131
132 early_memtest_bad_size_kb = early_memtest_bad_size >> 10;
133 if (early_memtest_bad_size && !early_memtest_bad_size_kb)
134 early_memtest_bad_size_kb = 1;
135 /* When 0 is reported, it means there actually was a successful test */
136 seq_printf(m, "EarlyMemtestBad: %5lu kB\n", early_memtest_bad_size_kb);
137}