Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/kernel.h>
0003 #include <linux/types.h>
0004 #include <linux/init.h>
0005 #include <linux/memblock.h>
0006 
0007 static u64 patterns[] __initdata = {
0008     /* The first entry has to be 0 to leave memtest with zeroed memory */
0009     0,
0010     0xffffffffffffffffULL,
0011     0x5555555555555555ULL,
0012     0xaaaaaaaaaaaaaaaaULL,
0013     0x1111111111111111ULL,
0014     0x2222222222222222ULL,
0015     0x4444444444444444ULL,
0016     0x8888888888888888ULL,
0017     0x3333333333333333ULL,
0018     0x6666666666666666ULL,
0019     0x9999999999999999ULL,
0020     0xccccccccccccccccULL,
0021     0x7777777777777777ULL,
0022     0xbbbbbbbbbbbbbbbbULL,
0023     0xddddddddddddddddULL,
0024     0xeeeeeeeeeeeeeeeeULL,
0025     0x7a6c7258554e494cULL, /* yeah ;-) */
0026 };
0027 
0028 static void __init reserve_bad_mem(u64 pattern, phys_addr_t start_bad, phys_addr_t end_bad)
0029 {
0030     pr_info("  %016llx bad mem addr %pa - %pa reserved\n",
0031         cpu_to_be64(pattern), &start_bad, &end_bad);
0032     memblock_reserve(start_bad, end_bad - start_bad);
0033 }
0034 
0035 static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size)
0036 {
0037     u64 *p, *start, *end;
0038     phys_addr_t start_bad, last_bad;
0039     phys_addr_t start_phys_aligned;
0040     const size_t incr = sizeof(pattern);
0041 
0042     start_phys_aligned = ALIGN(start_phys, incr);
0043     start = __va(start_phys_aligned);
0044     end = start + (size - (start_phys_aligned - start_phys)) / incr;
0045     start_bad = 0;
0046     last_bad = 0;
0047 
0048     for (p = start; p < end; p++)
0049         *p = pattern;
0050 
0051     for (p = start; p < end; p++, start_phys_aligned += incr) {
0052         if (*p == pattern)
0053             continue;
0054         if (start_phys_aligned == last_bad + incr) {
0055             last_bad += incr;
0056             continue;
0057         }
0058         if (start_bad)
0059             reserve_bad_mem(pattern, start_bad, last_bad + incr);
0060         start_bad = last_bad = start_phys_aligned;
0061     }
0062     if (start_bad)
0063         reserve_bad_mem(pattern, start_bad, last_bad + incr);
0064 }
0065 
0066 static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end)
0067 {
0068     u64 i;
0069     phys_addr_t this_start, this_end;
0070 
0071     for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start,
0072                 &this_end, NULL) {
0073         this_start = clamp(this_start, start, end);
0074         this_end = clamp(this_end, start, end);
0075         if (this_start < this_end) {
0076             pr_info("  %pa - %pa pattern %016llx\n",
0077                 &this_start, &this_end, cpu_to_be64(pattern));
0078             memtest(pattern, this_start, this_end - this_start);
0079         }
0080     }
0081 }
0082 
0083 /* default is disabled */
0084 static unsigned int memtest_pattern __initdata;
0085 
0086 static int __init parse_memtest(char *arg)
0087 {
0088     int ret = 0;
0089 
0090     if (arg)
0091         ret = kstrtouint(arg, 0, &memtest_pattern);
0092     else
0093         memtest_pattern = ARRAY_SIZE(patterns);
0094 
0095     return ret;
0096 }
0097 
0098 early_param("memtest", parse_memtest);
0099 
0100 void __init early_memtest(phys_addr_t start, phys_addr_t end)
0101 {
0102     unsigned int i;
0103     unsigned int idx = 0;
0104 
0105     if (!memtest_pattern)
0106         return;
0107 
0108     pr_info("early_memtest: # of tests: %u\n", memtest_pattern);
0109     for (i = memtest_pattern-1; i < UINT_MAX; --i) {
0110         idx = i % ARRAY_SIZE(patterns);
0111         do_one_pass(patterns[idx], start, end);
0112     }
0113 }