mm: move memtest under mm
authorVladimir Murzin <vladimir.murzin@arm.com>
Tue, 14 Apr 2015 22:48:27 +0000 (15:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Apr 2015 23:49:06 +0000 (16:49 -0700)
Memtest is a simple feature which fills the memory with a given set of
patterns and validates memory contents, if bad memory regions is detected
it reserves them via memblock API.  Since memblock API is widely used by
other architectures this feature can be enabled outside of x86 world.

This patch set promotes memtest to live under generic mm umbrella and
enables memtest feature for arm/arm64.

It was reported that this patch set was useful for tracking down an issue
with some errant DMA on an arm64 platform.

This patch (of 6):

There is nothing platform dependent in the core memtest code, so other
platforms might benefit from this feature too.

[linux@roeck-us.net: MEMTEST depends on MEMBLOCK]
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Paul Bolle <pebolle@tiscali.nl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/Kconfig
arch/x86/include/asm/e820.h
arch/x86/mm/Makefile
arch/x86/mm/memtest.c [deleted file]
include/linux/memblock.h
lib/Kconfig.debug
mm/Makefile
mm/memtest.c [new file with mode: 0644]

index 1f7f185934a5ce0a60a6f07c610a56a2adea7d09..d43e7e1c784b308ee168a988536aa00e514e949c 100644 (file)
@@ -721,17 +721,6 @@ endif #HYPERVISOR_GUEST
 config NO_BOOTMEM
        def_bool y
 
-config MEMTEST
-       bool "Memtest"
-       ---help---
-         This option adds a kernel parameter 'memtest', which allows memtest
-         to be set.
-               memtest=0, mean disabled; -- default
-               memtest=1, mean do 1 test pattern;
-               ...
-               memtest=4, mean do 4 test patterns.
-         If you are unsure how to answer this question, answer N.
-
 source "arch/x86/Kconfig.cpu"
 
 config HPET_TIMER
index 779c2efe2e97cf3ceabe2d421f3f1772514a9120..3ab0537872fb790e6864674efcf3130324687723 100644 (file)
@@ -40,14 +40,6 @@ static inline void e820_mark_nosave_regions(unsigned long limit_pfn)
 }
 #endif
 
-#ifdef CONFIG_MEMTEST
-extern void early_memtest(unsigned long start, unsigned long end);
-#else
-static inline void early_memtest(unsigned long start, unsigned long end)
-{
-}
-#endif
-
 extern unsigned long e820_end_of_ram_pfn(void);
 extern unsigned long e820_end_of_low_ram_pfn(void);
 extern u64 early_reserve_e820(u64 sizet, u64 align);
index c4cc74006c61965b95e8d6035891eb5ef3a7cdff..a482d105172b68766b8cdfc89717a1623bc24a23 100644 (file)
@@ -32,6 +32,4 @@ obj-$(CONFIG_AMD_NUMA)                += amdtopology.o
 obj-$(CONFIG_ACPI_NUMA)                += srat.o
 obj-$(CONFIG_NUMA_EMU)         += numa_emulation.o
 
-obj-$(CONFIG_MEMTEST)          += memtest.o
-
 obj-$(CONFIG_X86_INTEL_MPX)    += mpx.o
diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
deleted file mode 100644 (file)
index 1e9da79..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/pfn.h>
-#include <linux/memblock.h>
-
-static u64 patterns[] __initdata = {
-       /* The first entry has to be 0 to leave memtest with zeroed memory */
-       0,
-       0xffffffffffffffffULL,
-       0x5555555555555555ULL,
-       0xaaaaaaaaaaaaaaaaULL,
-       0x1111111111111111ULL,
-       0x2222222222222222ULL,
-       0x4444444444444444ULL,
-       0x8888888888888888ULL,
-       0x3333333333333333ULL,
-       0x6666666666666666ULL,
-       0x9999999999999999ULL,
-       0xccccccccccccccccULL,
-       0x7777777777777777ULL,
-       0xbbbbbbbbbbbbbbbbULL,
-       0xddddddddddddddddULL,
-       0xeeeeeeeeeeeeeeeeULL,
-       0x7a6c7258554e494cULL, /* yeah ;-) */
-};
-
-static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
-{
-       printk(KERN_INFO "  %016llx bad mem addr %010llx - %010llx reserved\n",
-              (unsigned long long) pattern,
-              (unsigned long long) start_bad,
-              (unsigned long long) end_bad);
-       memblock_reserve(start_bad, end_bad - start_bad);
-}
-
-static void __init memtest(u64 pattern, u64 start_phys, u64 size)
-{
-       u64 *p, *start, *end;
-       u64 start_bad, last_bad;
-       u64 start_phys_aligned;
-       const size_t incr = sizeof(pattern);
-
-       start_phys_aligned = ALIGN(start_phys, incr);
-       start = __va(start_phys_aligned);
-       end = start + (size - (start_phys_aligned - start_phys)) / incr;
-       start_bad = 0;
-       last_bad = 0;
-
-       for (p = start; p < end; p++)
-               *p = pattern;
-
-       for (p = start; p < end; p++, start_phys_aligned += incr) {
-               if (*p == pattern)
-                       continue;
-               if (start_phys_aligned == last_bad + incr) {
-                       last_bad += incr;
-                       continue;
-               }
-               if (start_bad)
-                       reserve_bad_mem(pattern, start_bad, last_bad + incr);
-               start_bad = last_bad = start_phys_aligned;
-       }
-       if (start_bad)
-               reserve_bad_mem(pattern, start_bad, last_bad + incr);
-}
-
-static void __init do_one_pass(u64 pattern, u64 start, u64 end)
-{
-       u64 i;
-       phys_addr_t this_start, this_end;
-
-       for_each_free_mem_range(i, NUMA_NO_NODE, &this_start, &this_end, NULL) {
-               this_start = clamp_t(phys_addr_t, this_start, start, end);
-               this_end = clamp_t(phys_addr_t, this_end, start, end);
-               if (this_start < this_end) {
-                       printk(KERN_INFO "  %010llx - %010llx pattern %016llx\n",
-                              (unsigned long long)this_start,
-                              (unsigned long long)this_end,
-                              (unsigned long long)cpu_to_be64(pattern));
-                       memtest(pattern, this_start, this_end - this_start);
-               }
-       }
-}
-
-/* default is disabled */
-static int memtest_pattern __initdata;
-
-static int __init parse_memtest(char *arg)
-{
-       if (arg)
-               memtest_pattern = simple_strtoul(arg, NULL, 0);
-       else
-               memtest_pattern = ARRAY_SIZE(patterns);
-
-       return 0;
-}
-
-early_param("memtest", parse_memtest);
-
-void __init early_memtest(unsigned long start, unsigned long end)
-{
-       unsigned int i;
-       unsigned int idx = 0;
-
-       if (!memtest_pattern)
-               return;
-
-       printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
-       for (i = memtest_pattern-1; i < UINT_MAX; --i) {
-               idx = i % ARRAY_SIZE(patterns);
-               do_one_pass(patterns[idx], start, end);
-       }
-}
index e8cc45307f8f0d0f9897f0eb36d96b3c9fa7655c..6724cb020f5ece7e636e304d0506970177ef68d3 100644 (file)
@@ -365,6 +365,14 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
 #define __initdata_memblock
 #endif
 
+#ifdef CONFIG_MEMTEST
+extern void early_memtest(unsigned long start, unsigned long end);
+#else
+static inline void early_memtest(unsigned long start, unsigned long end)
+{
+}
+#endif
+
 #else
 static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align)
 {
index 36b6fa88ce5b412f92b15da530772c5a058e5d12..5c7a3183423b0d49b86424cd5218f6cf4009257e 100644 (file)
@@ -1745,6 +1745,18 @@ config TEST_UDELAY
 
          If unsure, say N.
 
+config MEMTEST
+       bool "Memtest"
+       depends on HAVE_MEMBLOCK
+       ---help---
+         This option adds a kernel parameter 'memtest', which allows memtest
+         to be set.
+               memtest=0, mean disabled; -- default
+               memtest=1, mean do 1 test pattern;
+               ...
+               memtest=4, mean do 4 test patterns.
+         If you are unsure how to answer this question, answer N.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
index 668a9bb82be4de01f13dd41f4e7b3cbb665d2e74..98c4eaeabdcb4592d0b15fd71f3f520aa1bd3d35 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
 obj-$(CONFIG_KASAN)    += kasan/
 obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+obj-$(CONFIG_MEMTEST)          += memtest.o
 obj-$(CONFIG_MIGRATION) += migrate.o
 obj-$(CONFIG_QUICKLIST) += quicklist.o
 obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o
diff --git a/mm/memtest.c b/mm/memtest.c
new file mode 100644 (file)
index 0000000..1e9da79
--- /dev/null
@@ -0,0 +1,118 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/pfn.h>
+#include <linux/memblock.h>
+
+static u64 patterns[] __initdata = {
+       /* The first entry has to be 0 to leave memtest with zeroed memory */
+       0,
+       0xffffffffffffffffULL,
+       0x5555555555555555ULL,
+       0xaaaaaaaaaaaaaaaaULL,
+       0x1111111111111111ULL,
+       0x2222222222222222ULL,
+       0x4444444444444444ULL,
+       0x8888888888888888ULL,
+       0x3333333333333333ULL,
+       0x6666666666666666ULL,
+       0x9999999999999999ULL,
+       0xccccccccccccccccULL,
+       0x7777777777777777ULL,
+       0xbbbbbbbbbbbbbbbbULL,
+       0xddddddddddddddddULL,
+       0xeeeeeeeeeeeeeeeeULL,
+       0x7a6c7258554e494cULL, /* yeah ;-) */
+};
+
+static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
+{
+       printk(KERN_INFO "  %016llx bad mem addr %010llx - %010llx reserved\n",
+              (unsigned long long) pattern,
+              (unsigned long long) start_bad,
+              (unsigned long long) end_bad);
+       memblock_reserve(start_bad, end_bad - start_bad);
+}
+
+static void __init memtest(u64 pattern, u64 start_phys, u64 size)
+{
+       u64 *p, *start, *end;
+       u64 start_bad, last_bad;
+       u64 start_phys_aligned;
+       const size_t incr = sizeof(pattern);
+
+       start_phys_aligned = ALIGN(start_phys, incr);
+       start = __va(start_phys_aligned);
+       end = start + (size - (start_phys_aligned - start_phys)) / incr;
+       start_bad = 0;
+       last_bad = 0;
+
+       for (p = start; p < end; p++)
+               *p = pattern;
+
+       for (p = start; p < end; p++, start_phys_aligned += incr) {
+               if (*p == pattern)
+                       continue;
+               if (start_phys_aligned == last_bad + incr) {
+                       last_bad += incr;
+                       continue;
+               }
+               if (start_bad)
+                       reserve_bad_mem(pattern, start_bad, last_bad + incr);
+               start_bad = last_bad = start_phys_aligned;
+       }
+       if (start_bad)
+               reserve_bad_mem(pattern, start_bad, last_bad + incr);
+}
+
+static void __init do_one_pass(u64 pattern, u64 start, u64 end)
+{
+       u64 i;
+       phys_addr_t this_start, this_end;
+
+       for_each_free_mem_range(i, NUMA_NO_NODE, &this_start, &this_end, NULL) {
+               this_start = clamp_t(phys_addr_t, this_start, start, end);
+               this_end = clamp_t(phys_addr_t, this_end, start, end);
+               if (this_start < this_end) {
+                       printk(KERN_INFO "  %010llx - %010llx pattern %016llx\n",
+                              (unsigned long long)this_start,
+                              (unsigned long long)this_end,
+                              (unsigned long long)cpu_to_be64(pattern));
+                       memtest(pattern, this_start, this_end - this_start);
+               }
+       }
+}
+
+/* default is disabled */
+static int memtest_pattern __initdata;
+
+static int __init parse_memtest(char *arg)
+{
+       if (arg)
+               memtest_pattern = simple_strtoul(arg, NULL, 0);
+       else
+               memtest_pattern = ARRAY_SIZE(patterns);
+
+       return 0;
+}
+
+early_param("memtest", parse_memtest);
+
+void __init early_memtest(unsigned long start, unsigned long end)
+{
+       unsigned int i;
+       unsigned int idx = 0;
+
+       if (!memtest_pattern)
+               return;
+
+       printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
+       for (i = memtest_pattern-1; i < UINT_MAX; --i) {
+               idx = i % ARRAY_SIZE(patterns);
+               do_one_pass(patterns[idx], start, end);
+       }
+}