diff --git a/commands/Kconfig b/commands/Kconfig index 384643b..7cc7129 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -562,14 +562,15 @@ select PARTITION_NEED_MTD prompt "nandtest" -config CMD_MTEST - tristate - prompt "mtest" - -config CMD_MTEST_ALTERNATIVE - bool - depends on CMD_MTEST - prompt "alternative mtest implementation" +config CMD_MEMTEST + tristate + prompt "memtest" + help + The memtest command can test the registered barebox memory. + During this test barebox memory regions like heap, stack, ... + will be skipped. If the tested architecture has MMU with PTE + flags support, the memtest is running twice with cache enabled + and with cache disabled endmenu diff --git a/commands/Makefile b/commands/Makefile index 419d93b..6acffc8 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_CMD_MEMCMP) += memcmp.o obj-$(CONFIG_CMD_MEMCPY) += memcpy.o obj-$(CONFIG_CMD_MEMSET) += memset.o -obj-$(CONFIG_CMD_MTEST) += memtest.o obj-$(CONFIG_CMD_EDIT) += edit.o obj-$(CONFIG_CMD_EXEC) += exec.o obj-$(CONFIG_CMD_SLEEP) += sleep.o @@ -49,6 +48,7 @@ obj-$(CONFIG_CMD_LOADENV) += loadenv.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NANDTEST) += nandtest.o +obj-$(CONFIG_CMD_MEMTEST) += memtest.o obj-$(CONFIG_CMD_TRUE) += true.o obj-$(CONFIG_CMD_FALSE) += false.o obj-$(CONFIG_CMD_VERSION) += version.o diff --git a/commands/memtest.c b/commands/memtest.c index 2d64d00..d2a1487 100644 --- a/commands/memtest.c +++ b/commands/memtest.c @@ -1,8 +1,8 @@ /* - * mtest - Perform a memory test + * memtest - Perform a memory test * - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * (C) Copyright 2013 + * Alexander Aring , Pengutronix * * See file CREDITS for list of people who contributed to this * project. @@ -17,335 +17,237 @@ * 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 #include -#include +#include +#include +#include +#include +#include +#include -/* - * Perform a memory test. A more complete alternative test can be - * configured using CONFIG_CMD_MTEST_ALTERNATIVE. The complete test - * loops until interrupted by ctrl-c or by a failure of one of the - * sub-tests. - */ -#ifdef CONFIG_CMD_MTEST_ALTERNATIVE -static int mem_test(ulong _start, ulong _end, ulong pattern_unused) +#include + +static int alloc_memtest_region(struct list_head *list, + resource_size_t start, resource_size_t size) { - vu_long *start = (vu_long *)_start; - vu_long *end = (vu_long *)_end; - vu_long *addr; - ulong val; - ulong readback; - vu_long addr_mask; - vu_long offset; - vu_long test_offset; - vu_long pattern; - vu_long temp; - vu_long anti_pattern; - vu_long num_words; -#ifdef CFG_MEMTEST_SCRATCH - vu_long *dummy = (vu_long*)CFG_MEMTEST_SCRATCH; -#else - vu_long *dummy = start; -#endif - int j; - int iterations = 1; + struct resource *r_new; + struct mem_test_resource *r; - static const ulong bitpattern[] = { - 0x00000001, /* single bit */ - 0x00000003, /* two adjacent bits */ - 0x00000007, /* three adjacent bits */ - 0x0000000F, /* four adjacent bits */ - 0x00000005, /* two non-adjacent bits */ - 0x00000015, /* three non-adjacent bits */ - 0x00000055, /* four non-adjacent bits */ - 0xaaaaaaaa, /* alternating 1/0 */ - }; + r = xzalloc(sizeof(struct mem_test_resource)); + r_new = request_sdram_region("memtest", start, size); + if (!r_new) + return -EINVAL; - /* XXX: enforce alignment of start and end? */ - for (;;) { - if (ctrlc()) { - putchar ('\n'); - return 1; + r->r = r_new; + list_add_tail(&r->list, list); + + return 0; +} + +static int request_memtest_regions(struct list_head *list) +{ + 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); + end = PAGE_ALIGN_DOWN(bank->res->end) - 1; + size = end - start + 1; + + ret = alloc_memtest_region(list, start, size); + if (ret < 0) + return ret; + + continue; } - printf("Iteration: %6d\r", iterations); - iterations++; - /* - * Data line test: write a pattern to the first - * location, write the 1's complement to a 'parking' - * address (changes the state of the data bus so a - * floating bus doen't give a false OK), and then - * read the value back. Note that we read it back - * into a variable because the next time we read it, - * it might be right (been there, tough to explain to - * the quality guys why it prints a failure when the - * "is" and "should be" are obviously the same in the - * error message). - * - * Rather than exhaustively testing, we test some - * patterns by shifting '1' bits through a field of - * '0's and '0' bits through a field of '1's (i.e. - * pattern and ~pattern). + * 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 */ - addr = start; - /* XXX */ - if (addr == dummy) ++addr; - for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) { - val = bitpattern[j]; - for(; val != 0; val <<= 1) { - *addr = val; - *dummy = ~val; /* clear the test data off of the bus */ - readback = *addr; - if(readback != val) { - printf ("FAILURE (data line): " - "expected 0x%08lx, actual 0x%08lx at address 0x%p\n", - val, readback, addr); + 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 + */ + start = PAGE_ALIGN(bank->res->start); + end = PAGE_ALIGN_DOWN(r->start) - 1; + size = end - start + 1; + r_prev = r; + if (start >= end) + continue; + + ret = alloc_memtest_region(list, start, size); + if (ret < 0) + return ret; + continue; } - *addr = ~val; - *dummy = val; - readback = *addr; - if(readback != ~val) { - printf ("FAILURE (data line): " - "Is 0x%08lx, should be 0x%08lx at address 0x%p\n", - readback, ~val, addr); + /* + * Between used regions + */ + start = PAGE_ALIGN(r_prev->end); + end = PAGE_ALIGN_DOWN(r->start) - 1; + size = end - start + 1; + r_prev = r; + if (start >= end) + continue; + + ret = alloc_memtest_region(list, start, size); + if (ret < 0) + return ret; + + if (list_is_last(&r->sibling, &bank->res->children)) { + /* + * Do on head element for bank boundary + */ + start = PAGE_ALIGN(r->end); + end = PAGE_ALIGN_DOWN(bank->res->end) - 1; + size = end - start + 1; + if (start >= end) + continue; + + ret = alloc_memtest_region(list, start, size); + if (ret < 0) + return ret; } - } - } - - /* - * Based on code whose Original Author and Copyright - * information follows: Copyright (c) 1998 by Michael - * Barr. This software is placed into the public - * domain and may be used for any purpose. However, - * this notice must not be changed or removed and no - * warranty is either expressed or implied by its - * publication or distribution. - */ - - /* - * Address line test - * - * Description: Test the address bus wiring in a - * memory region by performing a walking - * 1's test on the relevant bits of the - * address and checking for aliasing. - * This test will find single-bit - * address failures such as stuck -high, - * stuck-low, and shorted pins. The base - * address and size of the region are - * selected by the caller. - * - * Notes: For best results, the selected base - * address should have enough LSB 0's to - * guarantee single address bit changes. - * For example, to test a 64-Kbyte - * region, select a base address on a - * 64-Kbyte boundary. Also, select the - * region size as a power-of-two if at - * all possible. - * - * Returns: 0 if the test succeeds, 1 if the test fails. - * - * ## NOTE ## Be sure to specify start and end - * addresses such that addr_mask has - * lots of bits set. For example an - * address range of 01000000 02000000 is - * bad while a range of 01000000 - * 01ffffff is perfect. - */ - addr_mask = ((ulong)end - (ulong)start)/sizeof(vu_long); - pattern = (vu_long) 0xaaaaaaaa; - anti_pattern = (vu_long) 0x55555555; - - debug("%s:%d: addr mask = 0x%.8lx\n", - __FUNCTION__, __LINE__, - addr_mask); - /* - * Write the default pattern at each of the - * power-of-two offsets. - */ - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) - start[offset] = pattern; - - /* - * Check for address bits stuck high. - */ - test_offset = 0; - start[test_offset] = anti_pattern; - - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { - temp = start[offset]; - if (temp != pattern) { - printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx\n", - (ulong)&start[offset], pattern, temp); - return 1; - } - } - start[test_offset] = pattern; - - /* - * Check for addr bits stuck low or shorted. - */ - for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) { - start[test_offset] = anti_pattern; - - for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { - temp = start[offset]; - if ((temp != pattern) && (offset != test_offset)) { - printf ("\nFAILURE: Address bit stuck low or shorted @" - " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n", - (ulong)&start[offset], pattern, temp); - return 1; - } - } - start[test_offset] = pattern; - } - - /* - * Description: Test the integrity of a physical - * memory device by performing an - * increment/decrement test over the - * entire region. In the process every - * storage bit in the device is tested - * as a zero and a one. The base address - * and the size of the region are - * selected by the caller. - * - * Returns: 0 if the test succeeds, 1 if the test fails. - */ - num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1; - - /* - * Fill memory with a known pattern. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - start[offset] = pattern; - } - - /* - * Check each location and invert it for the second pass. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - temp = start[offset]; - if (temp != pattern) { - printf ("\nFAILURE (read/write) @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx)\n", - (ulong)&start[offset], pattern, temp); - return 1; - } - - anti_pattern = ~pattern; - start[offset] = anti_pattern; - } - - /* - * Check each location for the inverted pattern and zero it. - */ - for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { - anti_pattern = ~pattern; - temp = start[offset]; - if (temp != anti_pattern) { - printf ("\nFAILURE (read/write): @ 0x%.8lx:" - " expected 0x%.8lx, actual 0x%.8lx)\n", - (ulong)&start[offset], anti_pattern, temp); - return 1; - } - start[offset] = 0; } } + return 0; } -#else -static int mem_test(ulong _start, ulong _end, ulong pattern) + +static int __do_memtest(struct list_head *memtest_regions, + int bus_only, uint32_t cache_flag) { - vu_long *addr; - vu_long *start = (vu_long *)_start; - vu_long *end = (vu_long *)_end; - ulong val; - ulong readback; - ulong incr; - int rcode; + struct mem_test_resource *r; + int ret; - incr = 1; - for (;;) { - if (ctrlc()) { - putchar('\n'); - return 1; - } + 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); - printf ("\rPattern 0x%08lX Writing..." - "%12s" - "\b\b\b\b\b\b\b\b\b\b", - pattern, ""); - - for (addr=start,val=pattern; addrr->start, r->r->end, bus_only); + if (ret < 0) + return ret; + printf("done.\n\n"); } - return rcode; + + return 0; } -#endif -static int do_mem_mtest(int argc, char *argv[]) +static int do_memtest(int argc, char *argv[]) { - ulong start, end, pattern = 0; + 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; + struct list_head memtest_used_regions; - if (argc < 3) + while ((opt = getopt(argc, argv, "i:b")) > 0) { + switch (opt) { + case 'i': + max_i = simple_strtoul(optarg, NULL, 0); + break; + case 'b': + bus_only = 1; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind > argc) return COMMAND_ERROR_USAGE; - start = simple_strtoul(argv[1], NULL, 0); - end = simple_strtoul(argv[2], NULL, 0); + /* + * 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(); - if (argc > 3) - pattern = simple_strtoul(argv[3], NULL, 0); + INIT_LIST_HEAD(&memtest_used_regions); - printf ("Testing 0x%08x ... 0x%08x:\n", (uint)start, (uint)end); - - return mem_test(start, end, pattern); + ret = request_memtest_regions(&memtest_used_regions); + if (ret < 0) + goto out; + + for (i = 1; (i <= max_i) || !max_i; i++) { + if (max_i) + printf("Start iteration %u of %u.\n", i, max_i); + /* + * First try a memtest with caching enabled. + */ + if (IS_ENABLED(CONFIG_MMU)) { + printf("Do memtest with caching enabled.\n"); + ret = __do_memtest(&memtest_used_regions, + bus_only, pte_flags_cached); + 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); + } + + if (ret < 0) { + /* + * Set cursor to newline, because mem_test failed at + * drawing of progressbar. + */ + if (ret == -EINTR) + printf("\n"); + + printf("Memtest failed.\n"); + return 1; + } else { + printf("Memtest successful.\n"); + return 1; + } } -static const __maybe_unused char cmd_mtest_help[] = -"Usage: " -#ifdef CONFIG_CMD_MTEST_ALTERNATIVE -"[pattern]" -#endif -"\nsimple RAM read/write test\n"; +static const __maybe_unused char cmd_memtest_help[] = +"Usage: memtest [OPTION]...\n" +"memtest related commands\n" +" -i iterations [default=1, endless=0].\n" +" -b perform only a test on buslines."; -BAREBOX_CMD_START(mtest) - .cmd = do_mem_mtest, - .usage = "simple RAM test", - BAREBOX_CMD_HELP(cmd_mtest_help) +BAREBOX_CMD_START(memtest) + .cmd = do_memtest, + .usage = "Memory Test", + BAREBOX_CMD_HELP(cmd_memtest_help) BAREBOX_CMD_END - diff --git a/common/Makefile b/common/Makefile index 34eb7e4..4f430b6 100644 --- a/common/Makefile +++ b/common/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o obj-$(CONFIG_MALLOC_TLSF) += tlsf.o obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o +obj-$(CONFIG_CMD_MEMTEST) += memtest.o obj-y += clock.o obj-$(CONFIG_BANNER) += version.o obj-$(CONFIG_MEMINFO) += meminfo.o diff --git a/common/memtest.c b/common/memtest.c new file mode 100644 index 0000000..22178cf --- /dev/null +++ b/common/memtest.c @@ -0,0 +1,313 @@ +/* + * memory_test.c + * + * Copyright (c) 2013 Alexander Aring , 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 version 2 + * as published by the Free Software Foundation. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +static const resource_size_t bitpattern[] = { + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xAAAAAAAA, /* alternating 1/0 */ +}; + +/* + * Perform a memory test. The complete test + * loops until interrupted by ctrl-c. + * + * Prameters: + * start: start address for memory test. + * end: end address of memory test. + * bus_only: skip integrity check and do only a address/data bus + * testing. + * + * Return value can be -EINVAL for invalid parameter or -EINTR + * if memory test was interrupted. + */ +int mem_test(resource_size_t _start, + resource_size_t _end, int bus_only) +{ + volatile resource_size_t *start, *dummy, val, readback, offset, + offset2, pattern, temp, anti_pattern, num_words; + int i; + + _start = ALIGN(_start, sizeof(resource_size_t)); + _end = ALIGN_DOWN(_end, sizeof(resource_size_t)) - 1; + + if (_end <= _start) + return -EINVAL; + + start = (resource_size_t *)_start; + /* + * Point the dummy to start[1] + */ + dummy = start + 1; + num_words = (_end - _start + 1)/sizeof(resource_size_t); + + printf("Starting data line test.\n"); + + /* + * Data line test: write a pattern to the first + * location, write the 1's complement to a 'parking' + * address (changes the state of the data bus so a + * floating bus doen't give a false OK), and then + * read the value back. Note that we read it back + * into a variable because the next time we read it, + * it might be right (been there, tough to explain to + * the quality guys why it prints a failure when the + * "is" and "should be" are obviously the same in the + * error message). + * + * Rather than exhaustively testing, we test some + * patterns by shifting '1' bits through a field of + * '0's and '0' bits through a field of '1's (i.e. + * pattern and ~pattern). + */ + for (i = 0; i < ARRAY_SIZE(bitpattern)/ + sizeof(resource_size_t); i++) { + val = bitpattern[i]; + + for (; val != 0; val <<= 1) { + *start = val; + /* clear the test data off of the bus */ + *dummy = ~val; + readback = *start; + if (readback != val) { + printf("FAILURE (data line): " + "expected 0x%08x, actual 0x%08x at address 0x%08x.\n", + val, readback, (resource_size_t)start); + return -EIO; + } + + *start = ~val; + *dummy = val; + readback = *start; + if (readback != ~val) { + printf("FAILURE (data line): " + "Is 0x%08x, should be 0x%08x at address 0x%08x.\n", + readback, + ~val, (resource_size_t)start); + return -EIO; + } + } + } + + + /* + * Based on code whose Original Author and Copyright + * information follows: Copyright (c) 1998 by Michael + * Barr. This software is placed into the public + * domain and may be used for any purpose. However, + * this notice must not be changed or removed and no + * warranty is either expressed or implied by its + * publication or distribution. + */ + + /* + * Address line test + * + * Description: Test the address bus wiring in a + * memory region by performing a walking + * 1's test on the relevant bits of the + * address and checking for aliasing. + * This test will find single-bit + * address failures such as stuck -high, + * stuck-low, and shorted pins. The base + * address and size of the region are + * selected by the caller. + * + * Notes: For best results, the selected base + * address should have enough LSB 0's to + * guarantee single address bit changes. + * For example, to test a 64-Kbyte + * region, select a base address on a + * 64-Kbyte boundary. Also, select the + * region size as a power-of-two if at + * all possible. + * + * ## NOTE ## Be sure to specify start and end + * addresses such that num_words has + * lots of bits set. For example an + * address range of 01000000 02000000 is + * bad while a range of 01000000 + * 01ffffff is perfect. + */ + + pattern = 0xAAAAAAAA; + anti_pattern = 0x55555555; + + /* + * Write the default pattern at each of the + * power-of-two offsets. + */ + for (offset = 1; offset <= num_words; offset <<= 1) + start[offset] = pattern; + + printf("Check for address bits stuck high.\n"); + + /* + * Check for address bits stuck high. + */ + for (offset = 1; offset <= num_words; offset <<= 1) { + temp = start[offset]; + if (temp != pattern) { + printf("FAILURE: Address bit " + "stuck high @ 0x%08x:" + " expected 0x%08x, actual 0x%08x.\n", + (resource_size_t)&start[offset], + pattern, temp); + return -EIO; + } + } + + printf("Check for address bits stuck " + "low or shorted.\n"); + + /* + * Check for address bits stuck low or shorted. + */ + for (offset2 = 1; offset2 <= num_words; offset2 <<= 1) { + start[offset2] = anti_pattern; + + for (offset = 1; offset <= num_words; offset <<= 1) { + temp = start[offset]; + + if ((temp != pattern) && + (offset != offset2)) { + printf("FAILURE: Address bit stuck" + " low or shorted @" + " 0x%08x: expected 0x%08x, actual 0x%08x.\n", + (resource_size_t)&start[offset], + pattern, temp); + return -EIO; + } + } + start[offset2] = pattern; + } + + /* + * We tested only the bus if != 0 + * leaving here + */ + if (bus_only) + return 0; + + printf("Starting integrity check of physicaly ram.\n" + "Filling ram with patterns...\n"); + + /* + * Description: Test the integrity of a physical + * memory device by performing an + * increment/decrement test over the + * entire region. In the process every + * storage bit in the device is tested + * as a zero and a one. The base address + * and the size of the region are + * selected by the caller. + */ + + /* + * Fill memory with a known pattern. + */ + init_progression_bar(num_words); + for (offset = 0; offset < num_words; offset++) { + /* + * Every 4K we update the progressbar. + */ + if (!(offset & (SZ_4K - 1))) { + if (ctrlc()) + return -EINTR; + show_progress(offset); + } + + start[offset] = offset + 1; + } + show_progress(offset); + + printf("\nCompare written patterns...\n"); + /* + * Check each location and invert it for the second pass. + */ + init_progression_bar(num_words - 1); + for (offset = 0; offset < num_words; offset++) { + if (!(offset & (SZ_4K - 1))) { + if (ctrlc()) + return -EINTR; + show_progress(offset); + } + + temp = start[offset]; + if (temp != (offset + 1)) { + printf("\nFAILURE (read/write) @ 0x%08x:" + " expected 0x%08x, actual 0x%08x.\n", + (resource_size_t)&start[offset], + (offset + 1), temp); + return -EIO; + } + + anti_pattern = ~(offset + 1); + start[offset] = anti_pattern; + } + show_progress(offset); + + printf("\nFilling ram with inverted pattern and compare it...\n"); + /* + * Check each location for the inverted pattern and zero it. + */ + init_progression_bar(num_words - 1); + for (offset = 0; offset < num_words; offset++) { + if (!(offset & (SZ_4K - 1))) { + if (ctrlc()) + return -EINTR; + show_progress(offset); + } + + anti_pattern = ~(offset + 1); + temp = start[offset]; + + if (temp != anti_pattern) { + printf("\nFAILURE (read/write): @ 0x%08x:" + " expected 0x%08x, actual 0x%08x.\n", + (resource_size_t)&start[offset], + anti_pattern, temp); + return -EIO; + } + + start[offset] = 0; + } + show_progress(offset); + + /* + * end of progressbar + */ + printf("\n"); + + return 0; +} diff --git a/include/common.h b/include/common.h index 59fcd35..fc2c8ca 100644 --- a/include/common.h +++ b/include/common.h @@ -182,8 +182,9 @@ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) -#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) -#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN_DOWN(x, a) ((x) & ~((typeof(x))(a) - 1)) #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) diff --git a/include/memtest.h b/include/memtest.h new file mode 100644 index 0000000..a337be8 --- /dev/null +++ b/include/memtest.h @@ -0,0 +1,14 @@ +#ifndef __MEMTEST_H +#define __MEMTEST_H + +#include + +struct mem_test_resource { + struct resource *r; + struct list_head list; +}; + +int mem_test(resource_size_t _start, + resource_size_t _end, int bus_only); + +#endif /* __MEMTEST_H */