11f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/kernel.h> 21f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/errno.h> 31f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/string.h> 41f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/types.h> 51f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/mm.h> 61f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/smp.h> 71f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/init.h> 81f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu#include <linux/pfn.h> 9a9ce6bc15100023b411f8117e53a016d61889800Yinghai Lu#include <linux/memblock.h> 101f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 116d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmannstatic u64 patterns[] __initdata = { 126d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann 0, 136d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann 0xffffffffffffffffULL, 146d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann 0x5555555555555555ULL, 156d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann 0xaaaaaaaaaaaaaaaaULL, 1663823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x1111111111111111ULL, 1763823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x2222222222222222ULL, 1863823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x4444444444444444ULL, 1963823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x8888888888888888ULL, 2063823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x3333333333333333ULL, 2163823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x6666666666666666ULL, 2263823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x9999999999999999ULL, 2363823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0xccccccccccccccccULL, 2463823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x7777777777777777ULL, 2563823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0xbbbbbbbbbbbbbbbbULL, 2663823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0xddddddddddddddddULL, 2763823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0xeeeeeeeeeeeeeeeeULL, 2863823126c221dd721ce7351b596b3b73aa943613Andreas Herrmann 0x7a6c7258554e494cULL, /* yeah ;-) */ 296d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann}; 3040823f737e5bd186a1156fb1c28f360260e1e084Andreas Herrmann 31570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmannstatic void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad) 327dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann{ 33570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n", 34570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann (unsigned long long) pattern, 35570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann (unsigned long long) start_bad, 36570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann (unsigned long long) end_bad); 3724aa07882b672fff2da2f5c955759f0bd13d32d5Tejun Heo memblock_reserve(start_bad, end_bad - start_bad); 387dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann} 397dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann 40570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmannstatic void __init memtest(u64 pattern, u64 start_phys, u64 size) 411f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu{ 429866b7e86a2ce4daa677be750e3ccbfc65d187f5Thomas Gleixner u64 *p, *start, *end; 43570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann u64 start_bad, last_bad; 44570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann u64 start_phys_aligned; 459866b7e86a2ce4daa677be750e3ccbfc65d187f5Thomas Gleixner const size_t incr = sizeof(pattern); 461f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 471f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu start_phys_aligned = ALIGN(start_phys, incr); 481f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu start = __va(start_phys_aligned); 499866b7e86a2ce4daa677be750e3ccbfc65d187f5Thomas Gleixner end = start + (size - (start_phys_aligned - start_phys)) / incr; 501f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu start_bad = 0; 511f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu last_bad = 0; 521f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 53c9690998ef48ffefeccb91c70a7739eebdea57f9Andreas Herrmann for (p = start; p < end; p++) 54c9690998ef48ffefeccb91c70a7739eebdea57f9Andreas Herrmann *p = pattern; 559866b7e86a2ce4daa677be750e3ccbfc65d187f5Thomas Gleixner 56c9690998ef48ffefeccb91c70a7739eebdea57f9Andreas Herrmann for (p = start; p < end; p++, start_phys_aligned += incr) { 57c9690998ef48ffefeccb91c70a7739eebdea57f9Andreas Herrmann if (*p == pattern) 587dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann continue; 597dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann if (start_phys_aligned == last_bad + incr) { 607dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann last_bad += incr; 617dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann continue; 621f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu } 637dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann if (start_bad) 647dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann reserve_bad_mem(pattern, start_bad, last_bad + incr); 657dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann start_bad = last_bad = start_phys_aligned; 661f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu } 677dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann if (start_bad) 687dad169e57eda1f0aa6dc5ac43a898b4b0ced2c7Andreas Herrmann reserve_bad_mem(pattern, start_bad, last_bad + incr); 691f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu} 701f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 71bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmannstatic void __init do_one_pass(u64 pattern, u64 start, u64 end) 72bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann{ 738d89ac808417e92a33fb5fa3c86352016643775aTejun Heo u64 i; 748d89ac808417e92a33fb5fa3c86352016643775aTejun Heo phys_addr_t this_start, this_end; 758d89ac808417e92a33fb5fa3c86352016643775aTejun Heo 768d89ac808417e92a33fb5fa3c86352016643775aTejun Heo for_each_free_mem_range(i, MAX_NUMNODES, &this_start, &this_end, NULL) { 778d89ac808417e92a33fb5fa3c86352016643775aTejun Heo this_start = clamp_t(phys_addr_t, this_start, start, end); 788d89ac808417e92a33fb5fa3c86352016643775aTejun Heo this_end = clamp_t(phys_addr_t, this_end, start, end); 798d89ac808417e92a33fb5fa3c86352016643775aTejun Heo if (this_start < this_end) { 808d89ac808417e92a33fb5fa3c86352016643775aTejun Heo printk(KERN_INFO " %010llx - %010llx pattern %016llx\n", 818d89ac808417e92a33fb5fa3c86352016643775aTejun Heo (unsigned long long)this_start, 828d89ac808417e92a33fb5fa3c86352016643775aTejun Heo (unsigned long long)this_end, 838d89ac808417e92a33fb5fa3c86352016643775aTejun Heo (unsigned long long)cpu_to_be64(pattern)); 848d89ac808417e92a33fb5fa3c86352016643775aTejun Heo memtest(pattern, this_start, this_end - this_start); 858d89ac808417e92a33fb5fa3c86352016643775aTejun Heo } 86bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann } 87bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann} 88bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann 891f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu/* default is disabled */ 901f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lustatic int memtest_pattern __initdata; 911f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 921f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lustatic int __init parse_memtest(char *arg) 931f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu{ 941f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu if (arg) 951f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu memtest_pattern = simple_strtoul(arg, NULL, 0); 96d1a8e7792047f7dca7eb5759250e2c12800bf262Yinghai Lu else 97d1a8e7792047f7dca7eb5759250e2c12800bf262Yinghai Lu memtest_pattern = ARRAY_SIZE(patterns); 98d1a8e7792047f7dca7eb5759250e2c12800bf262Yinghai Lu 991f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu return 0; 1001f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu} 1011f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 1021f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Luearly_param("memtest", parse_memtest); 1031f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 1041f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Luvoid __init early_memtest(unsigned long start, unsigned long end) 1051f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu{ 1066d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann unsigned int i; 107bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann unsigned int idx = 0; 1081f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 1091f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu if (!memtest_pattern) 1101f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu return; 1111f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu 112570c9e69aaa84689fb8ed2a3a4af39ca54ba7a47Andreas Herrmann printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); 1136d74171bf7315257d276aa35400c5a8d6a993f19Andreas Herrmann for (i = 0; i < memtest_pattern; i++) { 114bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann idx = i % ARRAY_SIZE(patterns); 115bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann do_one_pass(patterns[idx], start, end); 116bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann } 117bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann 118bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann if (idx > 0) { 119bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann printk(KERN_INFO "early_memtest: wipe out " 120bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann "test pattern from memory\n"); 121bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann /* additional test with pattern 0 will do this */ 122bfb4dc0da45f8fddc76eba7e62919420c7d6dae2Andreas Herrmann do_one_pass(0, start, end); 1231f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu } 1241f067167a83d1c7f80437fd1d32b55508aaca009Yinghai Lu} 125