All of lore.kernel.org
 help / color / mirror / Atom feed
From: holler@ahsoftware.de (Alexander Holler)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC] arm: memtest
Date: Thu, 08 Nov 2012 21:48:18 +0100	[thread overview]
Message-ID: <509C1A92.9080407@ahsoftware.de> (raw)

Hello,

I've recently discovered the lack of the command line parameter memtest 
for ARM. So I've made a patch.

But I have some questions:

1. arch/x86/mm/memtest.c looks platform independ.
The only thing why I don't use it for arm, is because it uses 64bit 
pointers. Maybe it could be moved to mm/memtest.c. If so, the 
memtest32.c I'm using (basically a copy of memtest.c) could be moved 
there too.

2. Because the below memtest32.c is basically a copy of 
arch/x86/mm/memtest.c, I'm not sure if the mapping from physical to 
virtual locations there does fit (always) for ARM too. I know almost as 
much about the in-kernel memory organization on x86 as on ARM, which is 
not really that much (some theory about TLBs, some source code 
explorations, ..., but I'm working on it). ;)

3. I've just implemented a test for all the memory which is marked as 
free, leaving all reserved memory untested. But even if a full memory 
test could only be done in the boot-loader, I think at least some of the 
memory the kernel reserves for itself (e.g. for modules) could be tested 
too. I just haven't searched how/where this could be done. Maybe someone 
else has a hint or even a patch for the below patch.

4. I don't have an ARM box with bad memory. So my tests are a bit 
limited. Maybe someone else could do a test with real bad memory.

Anyway, I would still prefer to have at least the possibility to test 
some of the memory using the kernel instead of none at all. So if nobody 
offers a better solution, I would be glad if the below patch would find 
some friends. ;)

Regards,

Alexander


Here is how dmesg does look like (memtest=4):

--------- no error ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000]   000054c000 - 0007ffb000 pattern ffffffff
[    0.000000]   000054c000 - 0007ffb000 pattern 55555555
[    0.000000]   000054c000 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 128MB = 128MB total
[    0.000000] Memory: 125648k/125648k available, 5424k reserved, 0K highmem
--------- no error ---------

--------- error inected (by sw) ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000]   00000000 bad mem addr 0000600000 - 0000600014 reserved
[    0.000000]   0000600014 - 0007ffb000 pattern 00000000
[    0.000000]   000054c000 - 0000600000 pattern ffffffff
[    0.000000]   0000600014 - 0007ffb000 pattern ffffffff
[    0.000000]   000054c000 - 0000600000 pattern 55555555
[    0.000000]   0000600014 - 0007ffb000 pattern 55555555
[    0.000000]   000054c000 - 0000600000 pattern aaaaaaaa
[    0.000000]   0000600014 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0000600000 pattern 00000000
[    0.000000]   0000600014 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 128MB = 128MB total
[    0.000000] Memory: 125648k/125648k available, 5424k reserved, 0K highmem
--------- error inected (by sw) ---------

--------- with hole (mem=99M at 0x0 mem=28M at 0x6400000) ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0006300000 pattern 00000000
[    0.000000]   000054c000 - 0006300000 pattern ffffffff
[    0.000000]   000054c000 - 0006300000 pattern 55555555
[    0.000000]   000054c000 - 0006300000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0006300000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0006400000 - 0007ffb000 pattern 00000000
[    0.000000]   0006400000 - 0007ffb000 pattern ffffffff
[    0.000000]   0006400000 - 0007ffb000 pattern 55555555
[    0.000000]   0006400000 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0006400000 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 99MB 28MB = 127MB total
[    0.000000] Memory: 124624k/124624k available, 5424k reserved, 0K highmem
--------- with hole (mem=99M at 0x0 mem=28M at 0x6400000) ---------


 From 3034a0d2fc71c8edef43d0d04b3be0ffad484fca Mon Sep 17 00:00:00 2001
From: Alexander Holler <holler@ahsoftware.de>
Date: Wed, 31 Oct 2012 22:24:04 +0100
Subject: [PATCH] arm: add memtest

Signed-off-by: Alexander Holler <holler@ahsoftware.de>
---
  arch/arm/mm/Kconfig     |   11 ++++
  arch/arm/mm/Makefile    |    2 +
  arch/arm/mm/init.c      |   36 +++++++++++++-
  arch/arm/mm/memtest32.c |  126 
+++++++++++++++++++++++++++++++++++++++++++++++
  4 files changed, 173 insertions(+), 2 deletions(-)
  create mode 100644 arch/arm/mm/memtest32.c

diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 101b968..b14941f 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -874,3 +874,14 @@ config ARCH_HAS_BARRIERS
  	help
  	  This option allows the use of custom mandatory barriers
  	  included via the mach/barriers.h file.
+
+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.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 8a9c4cb..8cbfda1 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -96,3 +96,5 @@ obj-$(CONFIG_CACHE_FEROCEON_L2)	+= cache-feroceon-l2.o
  obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
  obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
  obj-$(CONFIG_CACHE_TAUROS2)	+= cache-tauros2.o
+
+obj-$(CONFIG_MEMTEST)		+= memtest32.o
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 9aec41f..0941946 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -584,6 +584,10 @@ static void __init free_highpages(void)
  #endif
  }

+#ifdef CONFIG_MEMTEST
+extern void early_memtest32(unsigned long start, unsigned long end);
+#endif
+
  /*
   * mem_init() marks the free areas in the mem_map and tells us how much
   * memory is free.  This is done after various parts of the system have
@@ -618,6 +622,9 @@ void __init mem_init(void)
  	reserved_pages = free_pages = 0;

  	for_each_bank(i, &meminfo) {
+#ifdef CONFIG_MEMTEST
+		phys_addr_t memtest_start = 0xffffffff, memtest_end;
+#endif
  		struct membank *bank = &meminfo.bank[i];
  		unsigned int pfn1, pfn2;
  		struct page *page, *end;
@@ -629,12 +636,37 @@ void __init mem_init(void)
  		end  = pfn_to_page(pfn2 - 1) + 1;

  		do {
-			if (PageReserved(page))
+			if (PageReserved(page)) {
  				reserved_pages++;
-			else if (!page_count(page))
+#ifdef CONFIG_MEMTEST
+				/* something has cut a hole */
+				if (memtest_start != 0xffffffff) {
+					early_memtest32(memtest_start,  memtest_end);
+					memtest_start = 0xffffffff;
+				}
+#endif
+			} else if (!page_count(page)) {
  				free_pages++;
+#ifdef CONFIG_MEMTEST
+				if (memtest_start == 0xffffffff) {
+					/* start of a block for memtest */
+					memtest_start = page_to_phys(page);
+				} else if (memtest_end != page_to_phys(page)) {
+					/* hole detected, call memtest */
+					early_memtest32(memtest_start,  memtest_end);
+					/* and start with new values */
+					memtest_start = page_to_phys(page);
+				}
+				memtest_end = page_to_phys(page)+PAGE_SIZE;
+#endif
+			}
  			page++;
  		} while (page < end);
+#ifdef CONFIG_MEMTEST
+		if (memtest_start != 0xffffffff)
+			early_memtest32(memtest_start,  memtest_end);
+		/* if bad memory was found, reserved_pages is wrong (without bad mem) */
+#endif
  	}

  	/*
diff --git a/arch/arm/mm/memtest32.c b/arch/arm/mm/memtest32.c
new file mode 100644
index 0000000..1564b5b
--- /dev/null
+++ b/arch/arm/mm/memtest32.c
@@ -0,0 +1,126 @@
+/* This is just a checkpatch'ed copy of arch/x86/mm/memtest.c modified 
to use 32bit */
+#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 u32 patterns[] __initdata = {
+	0,
+	0xffffffffUL,
+	0x55555555UL,
+	0xaaaaaaaaUL,
+	0x11111111UL,
+	0x22222222UL,
+	0x44444444UL,
+	0x88888888UL,
+	0x33333333UL,
+	0x66666666UL,
+	0x99999999UL,
+	0xccccccccUL,
+	0x77777777UL,
+	0xbbbbbbbbUL,
+	0xddddddddUL,
+	0xeeeeeeeeUL,
+	0x7a6c7258UL, /* yeah ;-) */
+};
+
+static void __init reserve_bad_mem(u32 pattern, u32 start_bad, u32 end_bad)
+{
+	pr_info("  %08lx bad mem addr %010lx - %010lx reserved\n",
+	       (unsigned long) pattern,
+	       (unsigned long) start_bad,
+	       (unsigned long) end_bad);
+	memblock_reserve(start_bad, end_bad - start_bad);
+}
+
+static void __init memtest(u32 pattern, u32 start_phys, u32 size)
+{
+	u32 *p, *start, *end;
+	u32 start_bad, last_bad;
+	u32 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(u32 pattern, u32 start, u32 end)
+{
+	u64 i;
+	phys_addr_t this_start, this_end;
+
+	for_each_free_mem_range(i, MAX_NUMNODES, &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) {
+			pr_info("  %010lx - %010lx pattern %08lx\n",
+			       (unsigned long)this_start,
+			       (unsigned long)this_end,
+			       (unsigned long)cpu_to_be32(pattern));
+			memtest(pattern, this_start, this_end - this_start);
+		}
+	}
+}
+
+/* default is disabled */
+static int memtest_pattern __initdata;
+
+static int __init parse_memtest(char *arg)
+{
+	ssize_t ret __always_unused;
+
+	if (arg)
+		ret = kstrtoint(arg, 0, &memtest_pattern);
+	else
+		memtest_pattern = ARRAY_SIZE(patterns);
+
+	return 0;
+}
+
+early_param("memtest", parse_memtest);
+
+void __init early_memtest32(unsigned long start, unsigned long end)
+{
+	unsigned int i;
+	unsigned int idx = 0;
+
+	if (!memtest_pattern)
+		return;
+
+	pr_info("early_memtest: # of tests: %d\n", memtest_pattern);
+	for (i = 0; i < memtest_pattern; i++) {
+		idx = i % ARRAY_SIZE(patterns);
+		do_one_pass(patterns[idx], start, end);
+	}
+
+	if (idx > 0) {
+		pr_info("early_memtest: wipe out test pattern from memory\n");
+		/* additional test with pattern 0 will do this */
+		do_one_pass(0, start, end);
+	}
+}
-- 
1.7.8.6

WARNING: multiple messages have this Message-ID (diff)
From: Alexander Holler <holler@ahsoftware.de>
To: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Subject: [RFC] arm: memtest
Date: Thu, 08 Nov 2012 21:48:18 +0100	[thread overview]
Message-ID: <509C1A92.9080407@ahsoftware.de> (raw)

Hello,

I've recently discovered the lack of the command line parameter memtest 
for ARM. So I've made a patch.

But I have some questions:

1. arch/x86/mm/memtest.c looks platform independ.
The only thing why I don't use it for arm, is because it uses 64bit 
pointers. Maybe it could be moved to mm/memtest.c. If so, the 
memtest32.c I'm using (basically a copy of memtest.c) could be moved 
there too.

2. Because the below memtest32.c is basically a copy of 
arch/x86/mm/memtest.c, I'm not sure if the mapping from physical to 
virtual locations there does fit (always) for ARM too. I know almost as 
much about the in-kernel memory organization on x86 as on ARM, which is 
not really that much (some theory about TLBs, some source code 
explorations, ..., but I'm working on it). ;)

3. I've just implemented a test for all the memory which is marked as 
free, leaving all reserved memory untested. But even if a full memory 
test could only be done in the boot-loader, I think at least some of the 
memory the kernel reserves for itself (e.g. for modules) could be tested 
too. I just haven't searched how/where this could be done. Maybe someone 
else has a hint or even a patch for the below patch.

4. I don't have an ARM box with bad memory. So my tests are a bit 
limited. Maybe someone else could do a test with real bad memory.

Anyway, I would still prefer to have at least the possibility to test 
some of the memory using the kernel instead of none at all. So if nobody 
offers a better solution, I would be glad if the below patch would find 
some friends. ;)

Regards,

Alexander


Here is how dmesg does look like (memtest=4):

--------- no error ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000]   000054c000 - 0007ffb000 pattern ffffffff
[    0.000000]   000054c000 - 0007ffb000 pattern 55555555
[    0.000000]   000054c000 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 128MB = 128MB total
[    0.000000] Memory: 125648k/125648k available, 5424k reserved, 0K highmem
--------- no error ---------

--------- error inected (by sw) ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0007ffb000 pattern 00000000
[    0.000000]   00000000 bad mem addr 0000600000 - 0000600014 reserved
[    0.000000]   0000600014 - 0007ffb000 pattern 00000000
[    0.000000]   000054c000 - 0000600000 pattern ffffffff
[    0.000000]   0000600014 - 0007ffb000 pattern ffffffff
[    0.000000]   000054c000 - 0000600000 pattern 55555555
[    0.000000]   0000600014 - 0007ffb000 pattern 55555555
[    0.000000]   000054c000 - 0000600000 pattern aaaaaaaa
[    0.000000]   0000600014 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0000600000 pattern 00000000
[    0.000000]   0000600014 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 128MB = 128MB total
[    0.000000] Memory: 125648k/125648k available, 5424k reserved, 0K highmem
--------- error inected (by sw) ---------

--------- with hole (mem=99M@0x0 mem=28M@0x6400000) ---------
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000]   0000000000 - 0000004000 pattern ffffffff
[    0.000000]   0000000000 - 0000004000 pattern 55555555
[    0.000000]   0000000000 - 0000004000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0000000000 - 0000004000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   000054c000 - 0006300000 pattern 00000000
[    0.000000]   000054c000 - 0006300000 pattern ffffffff
[    0.000000]   000054c000 - 0006300000 pattern 55555555
[    0.000000]   000054c000 - 0006300000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   000054c000 - 0006300000 pattern 00000000
[    0.000000] early_memtest: # of tests: 4
[    0.000000]   0006400000 - 0007ffb000 pattern 00000000
[    0.000000]   0006400000 - 0007ffb000 pattern ffffffff
[    0.000000]   0006400000 - 0007ffb000 pattern 55555555
[    0.000000]   0006400000 - 0007ffb000 pattern aaaaaaaa
[    0.000000] early_memtest: wipe out test pattern from memory
[    0.000000]   0006400000 - 0007ffb000 pattern 00000000
[    0.000000] Memory: 99MB 28MB = 127MB total
[    0.000000] Memory: 124624k/124624k available, 5424k reserved, 0K highmem
--------- with hole (mem=99M@0x0 mem=28M@0x6400000) ---------


 From 3034a0d2fc71c8edef43d0d04b3be0ffad484fca Mon Sep 17 00:00:00 2001
From: Alexander Holler <holler@ahsoftware.de>
Date: Wed, 31 Oct 2012 22:24:04 +0100
Subject: [PATCH] arm: add memtest

Signed-off-by: Alexander Holler <holler@ahsoftware.de>
---
  arch/arm/mm/Kconfig     |   11 ++++
  arch/arm/mm/Makefile    |    2 +
  arch/arm/mm/init.c      |   36 +++++++++++++-
  arch/arm/mm/memtest32.c |  126 
+++++++++++++++++++++++++++++++++++++++++++++++
  4 files changed, 173 insertions(+), 2 deletions(-)
  create mode 100644 arch/arm/mm/memtest32.c

diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 101b968..b14941f 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -874,3 +874,14 @@ config ARCH_HAS_BARRIERS
  	help
  	  This option allows the use of custom mandatory barriers
  	  included via the mach/barriers.h file.
+
+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.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 8a9c4cb..8cbfda1 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -96,3 +96,5 @@ obj-$(CONFIG_CACHE_FEROCEON_L2)	+= cache-feroceon-l2.o
  obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
  obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
  obj-$(CONFIG_CACHE_TAUROS2)	+= cache-tauros2.o
+
+obj-$(CONFIG_MEMTEST)		+= memtest32.o
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 9aec41f..0941946 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -584,6 +584,10 @@ static void __init free_highpages(void)
  #endif
  }

+#ifdef CONFIG_MEMTEST
+extern void early_memtest32(unsigned long start, unsigned long end);
+#endif
+
  /*
   * mem_init() marks the free areas in the mem_map and tells us how much
   * memory is free.  This is done after various parts of the system have
@@ -618,6 +622,9 @@ void __init mem_init(void)
  	reserved_pages = free_pages = 0;

  	for_each_bank(i, &meminfo) {
+#ifdef CONFIG_MEMTEST
+		phys_addr_t memtest_start = 0xffffffff, memtest_end;
+#endif
  		struct membank *bank = &meminfo.bank[i];
  		unsigned int pfn1, pfn2;
  		struct page *page, *end;
@@ -629,12 +636,37 @@ void __init mem_init(void)
  		end  = pfn_to_page(pfn2 - 1) + 1;

  		do {
-			if (PageReserved(page))
+			if (PageReserved(page)) {
  				reserved_pages++;
-			else if (!page_count(page))
+#ifdef CONFIG_MEMTEST
+				/* something has cut a hole */
+				if (memtest_start != 0xffffffff) {
+					early_memtest32(memtest_start,  memtest_end);
+					memtest_start = 0xffffffff;
+				}
+#endif
+			} else if (!page_count(page)) {
  				free_pages++;
+#ifdef CONFIG_MEMTEST
+				if (memtest_start == 0xffffffff) {
+					/* start of a block for memtest */
+					memtest_start = page_to_phys(page);
+				} else if (memtest_end != page_to_phys(page)) {
+					/* hole detected, call memtest */
+					early_memtest32(memtest_start,  memtest_end);
+					/* and start with new values */
+					memtest_start = page_to_phys(page);
+				}
+				memtest_end = page_to_phys(page)+PAGE_SIZE;
+#endif
+			}
  			page++;
  		} while (page < end);
+#ifdef CONFIG_MEMTEST
+		if (memtest_start != 0xffffffff)
+			early_memtest32(memtest_start,  memtest_end);
+		/* if bad memory was found, reserved_pages is wrong (without bad mem) */
+#endif
  	}

  	/*
diff --git a/arch/arm/mm/memtest32.c b/arch/arm/mm/memtest32.c
new file mode 100644
index 0000000..1564b5b
--- /dev/null
+++ b/arch/arm/mm/memtest32.c
@@ -0,0 +1,126 @@
+/* This is just a checkpatch'ed copy of arch/x86/mm/memtest.c modified 
to use 32bit */
+#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 u32 patterns[] __initdata = {
+	0,
+	0xffffffffUL,
+	0x55555555UL,
+	0xaaaaaaaaUL,
+	0x11111111UL,
+	0x22222222UL,
+	0x44444444UL,
+	0x88888888UL,
+	0x33333333UL,
+	0x66666666UL,
+	0x99999999UL,
+	0xccccccccUL,
+	0x77777777UL,
+	0xbbbbbbbbUL,
+	0xddddddddUL,
+	0xeeeeeeeeUL,
+	0x7a6c7258UL, /* yeah ;-) */
+};
+
+static void __init reserve_bad_mem(u32 pattern, u32 start_bad, u32 end_bad)
+{
+	pr_info("  %08lx bad mem addr %010lx - %010lx reserved\n",
+	       (unsigned long) pattern,
+	       (unsigned long) start_bad,
+	       (unsigned long) end_bad);
+	memblock_reserve(start_bad, end_bad - start_bad);
+}
+
+static void __init memtest(u32 pattern, u32 start_phys, u32 size)
+{
+	u32 *p, *start, *end;
+	u32 start_bad, last_bad;
+	u32 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(u32 pattern, u32 start, u32 end)
+{
+	u64 i;
+	phys_addr_t this_start, this_end;
+
+	for_each_free_mem_range(i, MAX_NUMNODES, &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) {
+			pr_info("  %010lx - %010lx pattern %08lx\n",
+			       (unsigned long)this_start,
+			       (unsigned long)this_end,
+			       (unsigned long)cpu_to_be32(pattern));
+			memtest(pattern, this_start, this_end - this_start);
+		}
+	}
+}
+
+/* default is disabled */
+static int memtest_pattern __initdata;
+
+static int __init parse_memtest(char *arg)
+{
+	ssize_t ret __always_unused;
+
+	if (arg)
+		ret = kstrtoint(arg, 0, &memtest_pattern);
+	else
+		memtest_pattern = ARRAY_SIZE(patterns);
+
+	return 0;
+}
+
+early_param("memtest", parse_memtest);
+
+void __init early_memtest32(unsigned long start, unsigned long end)
+{
+	unsigned int i;
+	unsigned int idx = 0;
+
+	if (!memtest_pattern)
+		return;
+
+	pr_info("early_memtest: # of tests: %d\n", memtest_pattern);
+	for (i = 0; i < memtest_pattern; i++) {
+		idx = i % ARRAY_SIZE(patterns);
+		do_one_pass(patterns[idx], start, end);
+	}
+
+	if (idx > 0) {
+		pr_info("early_memtest: wipe out test pattern from memory\n");
+		/* additional test with pattern 0 will do this */
+		do_one_pass(0, start, end);
+	}
+}
-- 
1.7.8.6



             reply	other threads:[~2012-11-08 20:48 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-08 20:48 Alexander Holler [this message]
2012-11-08 20:48 ` [RFC] arm: memtest Alexander Holler
2012-11-08 22:18 ` Matthieu Castet
2012-11-08 22:18   ` RE : " Matthieu Castet
2012-11-08 22:39 ` Yinghai Lu
2012-11-08 22:39   ` Yinghai Lu
2012-11-09  5:00   ` Alexander Holler
2012-11-09  5:00     ` Alexander Holler
2012-11-09 12:10 ` Alexander Holler
2012-11-09 12:10   ` Alexander Holler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=509C1A92.9080407@ahsoftware.de \
    --to=holler@ahsoftware.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.