summaryrefslogtreecommitdiffstats
path: root/commands/memtest.c
diff options
context:
space:
mode:
Diffstat (limited to 'commands/memtest.c')
-rw-r--r--commands/memtest.c204
1 files changed, 76 insertions, 128 deletions
diff --git a/commands/memtest.c b/commands/memtest.c
index b88290c227..d784a5c0e2 100644
--- a/commands/memtest.c
+++ b/commands/memtest.c
@@ -21,137 +21,78 @@
#include <command.h>
#include <getopt.h>
-#include <asm/mmu.h>
#include <memory.h>
#include <malloc.h>
#include <common.h>
#include <errno.h>
-
#include <memtest.h>
+#include <mmu.h>
-static int alloc_memtest_region(struct list_head *list,
- resource_size_t start, resource_size_t size)
-{
- struct resource *r_new;
- struct mem_test_resource *r;
-
- r = xzalloc(sizeof(struct mem_test_resource));
- r_new = request_sdram_region("memtest", start, size);
- if (!r_new)
- return -EINVAL;
-
- r->r = r_new;
- list_add_tail(&r->list, list);
-
- return 0;
-}
-
-static int request_memtest_regions(struct list_head *list)
+static int do_test_one_area(struct mem_test_resource *r, int bus_only,
+ unsigned cache_flag)
{
int ret;
- struct memory_bank *bank;
- struct resource *r, *r_prev = NULL;
- resource_size_t start, end, size;
- for_each_memory_bank(bank) {
- /*
- * If we don't have any allocated region on bank,
- * we use the whole bank boundary
- */
- if (list_empty(&bank->res->children)) {
- start = PAGE_ALIGN(bank->res->start);
- size = PAGE_ALIGN_DOWN(bank->res->end - start + 1);
+ printf("Testing memory space: "
+ "0x%08x -> 0x%08x:\n",
+ r->r->start, r->r->end);
- if (size) {
- ret = alloc_memtest_region(list, start, size);
- if (ret < 0)
- return ret;
- }
+ remap_range((void *)r->r->start, r->r->end -
+ r->r->start + 1, cache_flag);
- continue;
- }
+ ret = mem_test_bus_integrity(r->r->start, r->r->end);
+ if (ret < 0)
+ return ret;
- r = list_first_entry(&bank->res->children,
- struct resource, sibling);
- start = PAGE_ALIGN(bank->res->start);
- end = PAGE_ALIGN_DOWN(r->start);
- r_prev = r;
- if (start != end) {
- size = end - start;
- ret = alloc_memtest_region(list, start, size);
- if (ret < 0)
- return ret;
- }
- /*
- * We assume that the regions are sorted in this list
- * So the first element has start boundary on bank->res->start
- * and the last element hast end boundary on bank->res->end.
- *
- * Between used regions. Start from second entry.
- */
- list_for_each_entry_from(r, &bank->res->children, sibling) {
- start = PAGE_ALIGN(r_prev->end + 1);
- end = r->start - 1;
- r_prev = r;
- if (start >= end)
- continue;
-
- size = PAGE_ALIGN_DOWN(end - start + 1);
- if (size == 0)
- continue;
- ret = alloc_memtest_region(list, start, size);
- if (ret < 0)
- return ret;
- }
+ if (bus_only)
+ return 0;
- /*
- * Do on head element for bank boundary.
- */
- r = list_last_entry(&bank->res->children,
- struct resource, sibling);
- start = PAGE_ALIGN(r->end);
- end = bank->res->end;
- size = PAGE_ALIGN_DOWN(end - start + 1);
- if (size && start < end && start > r->end) {
- ret = alloc_memtest_region(list, start, size);
- if (ret < 0)
- return ret;
- }
- }
+ ret = mem_test_moving_inversions(r->r->start, r->r->end);
+ if (ret < 0)
+ return ret;
+ printf("done.\n\n");
return 0;
}
-static int __do_memtest(struct list_head *memtest_regions,
- int bus_only, uint32_t cache_flag)
+static int do_memtest_thorough(struct list_head *memtest_regions,
+ int bus_only, unsigned cache_flag)
{
struct mem_test_resource *r;
int ret;
list_for_each_entry(r, memtest_regions, list) {
- printf("Testing memory space: "
- "0x%08x -> 0x%08x:\n",
- r->r->start, r->r->end);
- remap_range((void *)r->r->start, r->r->end -
- r->r->start + 1, cache_flag);
-
- ret = mem_test(r->r->start, r->r->end, bus_only);
- if (ret < 0)
+ ret = do_test_one_area(r, bus_only, cache_flag);
+ if (ret)
return ret;
- printf("done.\n\n");
}
return 0;
}
+static int do_memtest_biggest(struct list_head *memtest_regions,
+ int bus_only, unsigned cache_flag)
+{
+ struct mem_test_resource *r;
+
+ r = mem_test_biggest_region(memtest_regions);
+ if (!r)
+ return -EINVAL;
+
+ return do_test_one_area(r, bus_only, cache_flag);
+}
+
static int do_memtest(int argc, char *argv[])
{
int bus_only = 0, ret, opt;
- uint32_t i, max_i = 1, pte_flags_cached, pte_flags_uncached;
- struct mem_test_resource *r, *r_tmp;
+ uint32_t i, max_i = 1;
struct list_head memtest_used_regions;
+ int (*memtest)(struct list_head *, int, unsigned);
+ int cached = 0, uncached = 0;
+
+ memtest = do_memtest_biggest;
- while ((opt = getopt(argc, argv, "i:b")) > 0) {
+ while ((opt = getopt(argc, argv, "i:btcu")) > 0) {
switch (opt) {
case 'i':
max_i = simple_strtoul(optarg, NULL, 0);
@@ -159,23 +100,31 @@ static int do_memtest(int argc, char *argv[])
case 'b':
bus_only = 1;
break;
+ case 't':
+ memtest = do_memtest_thorough;
+ break;
+ case 'c':
+ cached = 1;
+ break;
+ case 'u':
+ uncached = 1;
+ break;
default:
return COMMAND_ERROR_USAGE;
}
}
+ if (!arch_can_remap() && (cached || uncached)) {
+ printf("Cannot map cached or uncached\n");
+ return -EINVAL;
+ }
+
if (optind > argc)
return COMMAND_ERROR_USAGE;
- /*
- * Get pte flags for enable and disable cache support on page.
- */
- pte_flags_cached = mmu_get_pte_cached_flags();
- pte_flags_uncached = mmu_get_pte_uncached_flags();
-
INIT_LIST_HEAD(&memtest_used_regions);
- ret = request_memtest_regions(&memtest_used_regions);
+ ret = mem_test_request_regions(&memtest_used_regions);
if (ret < 0)
goto out;
@@ -186,36 +135,32 @@ static int do_memtest(int argc, char *argv[])
else
putchar('\n');
- /*
- * First try a memtest with caching enabled.
- */
- if (IS_ENABLED(CONFIG_MMU)) {
+ if (cached) {
printf("Do memtest with caching enabled.\n");
- ret = __do_memtest(&memtest_used_regions,
- bus_only, pte_flags_cached);
+ ret = memtest(&memtest_used_regions,
+ bus_only, MAP_CACHED);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (uncached) {
+ printf("Do memtest with caching disabled.\n");
+ ret = memtest(&memtest_used_regions,
+ bus_only, MAP_UNCACHED);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (!cached && !uncached) {
+ ret = memtest(&memtest_used_regions,
+ bus_only, MAP_DEFAULT);
if (ret < 0)
goto out;
}
- /*
- * Second try a memtest with caching disabled.
- */
- printf("Do memtest with caching disabled.\n");
- ret = __do_memtest(&memtest_used_regions,
- bus_only, pte_flags_uncached);
- if (ret < 0)
- goto out;
}
out:
- list_for_each_entry_safe(r, r_tmp, &memtest_used_regions, list) {
- /*
- * Ensure to leave with a cached on non used sdram regions.
- */
- remap_range((void *)r->r->start, r->r->end -
- r->r->start + 1, pte_flags_cached);
- release_sdram_region(r->r);
- free(r);
- }
+ mem_test_release_regions(&memtest_used_regions);
if (ret < 0) {
/*
@@ -238,6 +183,9 @@ BAREBOX_CMD_HELP_START(memtest)
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT("-i ITERATIONS", "perform number of iterations (default 1, 0 is endless)")
BAREBOX_CMD_HELP_OPT("-b", "perform only a test on bus lines")
+BAREBOX_CMD_HELP_OPT("-c", "cached. Test using cached memory")
+BAREBOX_CMD_HELP_OPT("-u", "uncached. Test using uncached memory")
+BAREBOX_CMD_HELP_OPT("-t", "thorough. test all free areas. If unset, only test biggest free area")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(memtest)