From: Alexander Aring <alex.aring@gmail.com>
To: barebox@lists.infradead.org
Subject: [PATCH 6/6] commands: add new memtest command
Date: Thu, 7 Feb 2013 11:45:00 +0100 [thread overview]
Message-ID: <1360233900-26486-7-git-send-email-alex.aring@gmail.com> (raw)
In-Reply-To: <1360233900-26486-1-git-send-email-alex.aring@gmail.com>
Add new memtest command which can enable or disable caching
on non allocted barebox regions(test area).
This command simply parse and check parameters then call
the mem_test routine.
If no address parameters are given then mem_test will call
for each memory bank.
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
---
commands/Kconfig | 10 ++
commands/Makefile | 1 +
commands/memtest.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 373 insertions(+)
create mode 100644 commands/memtest.c
diff --git a/commands/Kconfig b/commands/Kconfig
index 7cc759c..d158c3f 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -516,6 +516,16 @@ config CMD_NANDTEST
select PARTITION_NEED_MTD
prompt "nandtest"
+config CMD_MEMTEST
+ tristate
+ select MEMTEST
+ prompt "memtest"
+ help
+ This command enables a memtest to test installed memory.
+ During this test allocated iomem regions will be skipped.
+ If tested architecture has MMU with PTE flags support,
+ caching can be set enabled or disabled.
+
endmenu
menu "video command"
diff --git a/commands/Makefile b/commands/Makefile
index 393ba51..b39b489 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_CMD_LOADY) += loadxy.o
obj-$(CONFIG_CMD_LOADS) += loads.o
obj-$(CONFIG_CMD_ECHO) += echo.o
obj-$(CONFIG_CMD_MEMORY) += mem.o
+obj-$(CONFIG_CMD_MEMTEST) += memtest.o
obj-$(CONFIG_CMD_EDIT) += edit.o
obj-$(CONFIG_CMD_EXEC) += exec.o
obj-$(CONFIG_CMD_SLEEP) += sleep.o
diff --git a/commands/memtest.c b/commands/memtest.c
new file mode 100644
index 0000000..22e8006
--- /dev/null
+++ b/commands/memtest.c
@@ -0,0 +1,362 @@
+/*
+ * memtest - Perform a memory test
+ *
+ * (C) Copyright 2013
+ * Alexander Aring <aar@pengutronix.de>, Pengutronix
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <command.h>
+#include <getopt.h>
+#include <asm/mmu.h>
+
+#include <memory_test.h>
+
+/*
+ * In CONFIG_MMU we have a special c flag.
+ */
+#ifdef CONFIG_MMU
+static char optstr[] = "s:e:i:cb";
+
+/*
+ * PTE flags variables to set cached and
+ * uncached regions.
+ */
+static uint32_t pte_flags_cached;
+static uint32_t pte_flags_uncached;
+#else
+static char optstr[] = "s:e:i:b";
+#endif
+
+#ifdef CONFIG_MMU
+static void print_region(vu_long start, vu_long size, uint32_t flags)
+{
+ if (!size)
+ return;
+
+ printf("\t0x%08lx - "
+ "0x%08lx (size 0x%08lx)\n",
+ start, start + size - 1, size);
+}
+
+static void do_remap_range(struct memory_bank *bank, uint32_t flags)
+{
+ struct resource *r = NULL;
+ struct resource *r_prev = NULL;
+
+ vu_long size;
+ vu_long start;
+ vu_long end;
+
+ if (flags == pte_flags_uncached)
+ printf("Set non caching regions:\n");
+ else if (flags == pte_flags_cached)
+ printf("Set caching regions:\n");
+ else
+ BUG();
+
+ /*
+ * We assume that the regions are sorted in this list
+ */
+ list_for_each_entry(r, &bank->res->children, sibling) {
+ /*
+ * Do on head element for bank boundary
+ */
+ if (r->sibling.prev == &bank->res->children) {
+ /*
+ * remember last used element
+ */
+ r_prev = r;
+
+ start = PAGE_ALIGN(bank->start);
+ end = PAGE_ALIGN_DOWN(r->start) - 1;
+ if (start >= end)
+ continue;
+ size = end - start + 1;
+
+ print_region(start, size, flags);
+ remap_range((void *)start, size, flags);
+
+ continue;
+ }
+ /*
+ * Between used regions
+ */
+ start = PAGE_ALIGN(r_prev->end);
+ end = PAGE_ALIGN_DOWN(r->start) - 1;
+ if (start < end) {
+ size = end - start + 1;
+ print_region(start, size, flags);
+ remap_range((void *)start, size, flags);
+ }
+
+ r_prev = r;
+ /*
+ * Do on head element for bank boundary
+ */
+ if (list_is_last(&r->sibling, &bank->res->children)) {
+ start = PAGE_ALIGN(r->end);
+ end = PAGE_ALIGN_DOWN(bank->start + bank->size) - 1;
+ if (start >= end)
+ continue;
+ size = end - start + 1;
+
+ print_region(start, size, flags);
+ remap_range((void *)start, size, flags);
+ }
+ }
+}
+#endif
+
+static int do_mem_memtest(int argc, char *argv[])
+{
+ /*
+ * Set start address to 0xffffffff which
+ * can't be.
+ */
+ vu_long start = 0xffffffff;
+ vu_long end = 0;
+
+ uint i;
+ uint max_i = 1;
+
+#ifdef CONFIG_MMU
+ int cache = 0;
+#endif
+ int bus_only = 0;
+ int err = 0;
+ int cnt = 0;
+ int opt;
+
+ struct memory_bank *bank = NULL;
+ struct resource *r = NULL;
+
+ while ((opt = getopt(argc, argv, optstr)) > 0) {
+ switch (opt) {
+ case 's':
+ start = simple_strtoul(optarg, NULL, 0);
+ break;
+ case 'e':
+ end = simple_strtoul(optarg, NULL, 0);
+ break;
+ case 'i':
+ max_i = simple_strtoul(optarg, NULL, 0);
+ break;
+#ifdef CONFIG_MMU
+ case 'c':
+ cache = 1;
+ break;
+#endif
+ case 'b':
+ bus_only = 1;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (optind > argc)
+ return COMMAND_ERROR_USAGE;
+
+ /*
+ * Error if no end address
+ */
+ if (start != 0xffffffff && !end) {
+ printf("Please add an end address.\n");
+ return 1;
+ }
+
+ /*
+ * Error if no start address
+ */
+ if (end && start == 0xffffffff) {
+ printf("Please add a start address.\n");
+ return 1;
+ }
+
+ /*
+ * Check parameters
+ */
+ if (start != 0xffffffff && end) {
+ if (end <= start) {
+ printf("End address less than or"
+ " equal start address.\n");
+ return 1;
+ }
+
+ /*
+ * Check if given start and end address are in any banks
+ */
+ for_each_memory_bank(bank) {
+ if (ADDRESS_IN_REGIONS(start, bank->start,
+ bank->start + bank->size))
+ cnt++;
+
+ if (ADDRESS_IN_REGIONS(end, bank->start,
+ bank->start + bank->size))
+ cnt++;
+ }
+
+ if (cnt != 2) {
+ printf("Start or end addresses are"
+ " not in any ram bank.\n");
+ return 1;
+ }
+ }
+
+#ifdef CONFIG_MMU
+ /*
+ * Get pte flags. Which are configured at
+ * runtime at booting.
+ */
+ pte_flags_cached = mmu_get_pte_cached_flags();
+ pte_flags_uncached = mmu_get_pte_uncached_flags();
+#endif
+
+ printf("Skipping regions:\n");
+ for_each_memory_bank(bank) {
+ list_for_each_entry(r, &bank->res->children, sibling)
+ printf("\t0x%08x - "
+ "0x%08x (size 0x%08x) %s\n",
+ r->start, r->end,
+ r->end - r->start + 1, r->name);
+#ifdef CONFIG_MMU
+ /*
+ * Disable or enable caching
+ */
+ if (cache)
+ do_remap_range(bank, pte_flags_cached);
+ else
+ do_remap_range(bank, pte_flags_uncached);
+#endif
+ }
+
+ /*
+ * Do test if we set a start or end address
+ */
+ if (start != 0xffffffff && end) {
+ printf("Testing address range:\n\t0x%08lx - 0x%08lx"
+ " (size 0x%08lx)\n",
+ start, end, end - start + 1);
+
+ for (i = 1; (i <= max_i) || !max_i; i++) {
+ printf("Iteration: %u\n", i);
+
+ /*
+ * Do the Memtest
+ */
+ err = mem_test(start, end, bus_only);
+ if (err == -EINTR) {
+ printf("Test interrupted.\n");
+ goto err;
+ }
+
+ if (err < 0) {
+ printf("Test failed.\n");
+ goto err;
+ }
+ printf("Tested %u iteration(s) without errors.\n", i);
+ }
+#ifdef CONFIG_MMU
+ /*
+ * Renable caching
+ */
+ if (!cache)
+ for_each_memory_bank(bank)
+ do_remap_range(bank, pte_flags_cached);
+#endif
+ printf("Memtest done.\n");
+
+ return 0;
+ }
+
+ /*
+ * If we set no start or end address
+ * we do the test on all ram banks
+ */
+ for (i = 1; (i <= max_i) || !max_i; i++) {
+ for_each_memory_bank(bank) {
+ start = bank->start;
+ end = bank->start + bank->size - 1;
+
+ printf("Iteration: %u\n", i);
+
+ printf("Testing address range:\n\t0x%08lx - "
+ "0x%08lx (size 0x%08lx) on bank /dev/%s\n",
+ start, end, bank->size,
+ bank->res->name);
+
+ err = mem_test(start, end, bus_only);
+ if (err == -EINTR) {
+ printf("Test interrupted.\n");
+ goto err;
+ }
+
+ if (err < 0) {
+ printf("Test on bank /dev/%s failed.\n",
+ bank->res->name);
+ goto err;
+ }
+ printf("Tested %u iteration(s) without errors.\n", i);
+ }
+ }
+#ifdef CONFIG_MMU
+ /*
+ * Renable caching
+ */
+ if (!cache)
+ for_each_memory_bank(bank)
+ do_remap_range(bank, pte_flags_cached);
+#endif
+ printf("Memtest done.\n");
+
+ return 0;
+
+err:
+#ifdef CONFIG_MMU
+ /*
+ * Enable caching
+ */
+ for_each_memory_bank(bank)
+ do_remap_range(bank, pte_flags_cached);
+#endif
+
+ return 1;
+}
+
+static const __maybe_unused char cmd_memtest_help[] =
+"Usage: memtest [OPTION]...\n"
+"memtest related commands\n"
+" -s <start> start address to begin memtest.\n"
+" -e <end> end address to stop memtest.\n"
+" -i <iterations> iterations [default=1, endless=0].\n"
+#ifdef CONFIG_MMU
+" -c run test with enable cache.\n"
+#endif
+" -b only test bus datalines.";
+
+BAREBOX_CMD_START(memtest)
+ .cmd = do_mem_memtest,
+ .usage = "Memory Test",
+ BAREBOX_CMD_HELP(cmd_memtest_help)
+BAREBOX_CMD_END
--
1.8.1.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2013-02-07 10:44 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-07 10:44 [PATCH v3 0/6] " Alexander Aring
2013-02-07 10:44 ` [PATCH 1/6] common: fix codestyle in ALIGN macros Alexander Aring
2013-02-07 10:44 ` [PATCH 2/6] common: add ALIGN_DOWN macro Alexander Aring
2013-02-07 10:44 ` [PATCH 3/6] memory: add function address_in_sdram_regions Alexander Aring
2013-02-07 10:44 ` [PATCH 4/6] memtest: remove memtest command Alexander Aring
2013-02-07 10:44 ` [PATCH 5/6] common: add mem_test routine Alexander Aring
2013-02-07 10:52 ` Marc Kleine-Budde
2013-02-07 11:16 ` Alexander Aring
2013-02-07 11:00 ` Sascha Hauer
2013-02-07 11:40 ` Alexander Aring
2013-02-07 11:54 ` Sascha Hauer
2013-02-07 15:41 ` Alexander Aring
2013-02-07 10:45 ` Alexander Aring [this message]
2013-02-07 10:56 ` [PATCH 6/6] commands: add new memtest command Marc Kleine-Budde
2013-02-07 11:20 ` Alexander Aring
2013-02-07 12:01 ` Sascha Hauer
2013-02-07 15:42 ` Alexander Aring
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=1360233900-26486-7-git-send-email-alex.aring@gmail.com \
--to=alex.aring@gmail.com \
--cc=barebox@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox