Mercurial > nand-ecoscentric
changeset 2952:56aff9481398
NAND: make rwbenchmark check its work
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Wed, 28 Oct 2009 16:28:12 +0000 |
| parents | 0eb1d8b14623 |
| children | b8b477f45f0c |
| files | packages/io/nand/current/ChangeLog packages/io/nand/current/tests/rwbenchmark.c |
| diffstat | 2 files changed, 95 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/nand/current/ChangeLog +++ b/packages/io/nand/current/ChangeLog @@ -8,6 +8,8 @@ 2009-10-28 Ross Younger <wry@eCosCentr consistency checks) * nand.sgml: Updated for the above. Documented ECC algorithm interface. + * tests/rwbenchmark.c: Have rwbenchmark use randomised test data + and check its work for better validity. 2009-10-08 Ross Younger <wry@eCosCentric.com>
--- a/packages/io/nand/current/tests/rwbenchmark.c +++ b/packages/io/nand/current/tests/rwbenchmark.c @@ -80,6 +80,13 @@ void cyg_user_start(void) #include <cyg/kernel/kapi.h> +#include "ar4prng.inl" +ar4ctx rnd; +/* we'll use our text segment as seed to the prng; not crypto-secure but + * pretty good for running tests */ +extern unsigned char _stext[], _etext[]; + + #ifdef CYGPKG_DEVS_NAND_SYNTH #define DEVICE "synth" #else @@ -327,41 +334,60 @@ next: CYG_TEST_FAIL_EXIT("can't find an untagged block"); } -unsigned char pagebuffer[CYGNUM_NAND_PAGEBUFFER]; +CYG_BYTE databuf[CYGNUM_NAND_PAGEBUFFER], testbuf[CYGNUM_NAND_PAGEBUFFER]; timing ft_read[NREADS]; timing ft_write[NWRITES]; timing ft_erase[NERASES]; -static void check_ff(const CYG_BYTE * buf, size_t size) -{ - while (size--) { - if (*buf != 0xFF) { - CYG_TEST_FAIL("readback check failed"); - } - } -} +int fails = 0; void test_reads(cyg_nand_partition *part, cyg_nand_block_addr b) { cyg_nand_page_addr pgstart = CYG_NAND_BLOCK2PAGEADDR(part->dev, b), pgend = CYG_NAND_BLOCK2PAGEADDR(part->dev, b+1)-1, pg = pgstart; - int i; + int i, rv; const int oobz = NAND_APPSPARE_PER_PAGE(part->dev); unsigned char oob[oobz]; #define ft ft_read - // TODO: Rather than reading 0xff, read back a test pattern that we've just put in there. -#define CLEARDATA() memset(pagebuffer, 0, sizeof pagebuffer) -#define CHECKDATA() check_ff(pagebuffer, sizeof pagebuffer) + /* First, set up the block the way we want it ... */ + cyg_nand_erase_block(part, b); + memcpy(oob, databuf, oobz); + for (i=pgstart; i <= pgend; i++) { + rv = cyg_nand_write_page(part, i, databuf, sizeof databuf, oob, oobz); + switch (rv) { + case 0: break; + case -EIO: + cyg_nand_bbt_markbad(part, b); + CYG_TEST_FAIL_FINISH("Write failed; block now marked as bad. This run can't continue but should be OK to repeat."); + + default: + diag_printf("Unexpected write failure: %d\n", rv); + CYG_TEST_FAIL_FINISH("Pre-write failed"); + } + } + +#define CLEARDATA() memset(testbuf, 0, sizeof testbuf) +#define CHECKDATA() do { if (0 != memcmp(testbuf, databuf, sizeof testbuf)) { \ + CYG_TEST_FAIL("readback check failed"); \ + ++fails; \ + break; \ +} } while(0) + #define CLEAROOB() memset(oob, 0, oobz) -#define CHECKOOB() check_ff(oob, oobz) +#define CHECKOOB() do { if (0 != memcmp(oob, databuf, oobz)) { \ + CYG_TEST_FAIL("readback OOB check failed"); \ + ++fails; \ + break; \ +} } while(0) + for (i=0; i < NREADS; i++) { CLEARDATA(); wait_for_tick(); get_timestamp(&ft[i].start); - cyg_nand_read_page(part, pg, pagebuffer, sizeof pagebuffer, 0, 0); + cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, 0, 0); get_timestamp(&ft[i].end); CHECKDATA(); ++pg; @@ -386,13 +412,14 @@ void test_reads(cyg_nand_partition *part CLEAROOB(); wait_for_tick(); get_timestamp(&ft[i].start); - cyg_nand_read_page(part, pg, pagebuffer, sizeof pagebuffer, oob, oobz); + cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz); get_timestamp(&ft[i].end); CHECKDATA(); CHECKOOB(); ++pg; if (pg > pgend) pg = pgstart; } + cyg_nand_erase_block(part, b); show_times(ft, NREADS, "NAND page reads (page + OOB)"); #undef ft } @@ -408,14 +435,20 @@ void test_writes(cyg_nand_partition *par unsigned char oob[oobz]; #define ft ft_write - memset(pagebuffer, 0xFF, sizeof pagebuffer); - memset(oob, 0xFF, oobz); - + cyg_nand_erase_block(part, b); for (i=0; i < NWRITES; i++) { wait_for_tick(); get_timestamp(&ft[i].start); - cyg_nand_write_page(part, pg, pagebuffer, sizeof pagebuffer, oob, oobz); + cyg_nand_write_page(part, pg, databuf, sizeof databuf, databuf, oobz); get_timestamp(&ft[i].end); + + // Read it back to confirm + CLEARDATA(); + CLEAROOB(); + cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz); + CHECKDATA(); + CHECKOOB(); + ++pg; if (pg > pgend) { cyg_nand_erase_block(part, b); @@ -438,6 +471,32 @@ void test_erases(cyg_nand_partition *par get_timestamp(&ft[i].start); cyg_nand_erase_block(part, b); get_timestamp(&ft[i].end); + + if (i==0) { + cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b); + const int oobz = NAND_APPSPARE_PER_PAGE(part->dev); + unsigned char oob[oobz]; + int j; + // TODO: It only makes sense to check the one, unless we want + // to try writing out more dummy data each time. + CLEARDATA(); + CLEAROOB(); + cyg_nand_read_page(part, pg, testbuf, sizeof testbuf, oob, oobz); + for (j=0; j < sizeof testbuf; j++) { + if (testbuf[j] != 0xff) { + CYG_TEST_FAIL("readback check failed"); + ++fails; + break; + } + } + for (j=0; j < oobz; j++) { + if (oob[j] != 0xff) { + CYG_TEST_FAIL("readback OOB check failed"); + ++fails; + break; + } + } + } } show_times(ft, NERASES, "NAND block erases"); #undef ft @@ -464,9 +523,13 @@ void rwbenchmark_main(void) show_test_parameters(); show_times_hdr(); - cyg_nand_erase_block(part, block); + // TODO: For speed, refactor test_reads and test_writes into each other. test_reads(part, block); + + // Freshen our test data for the second phase + ar4prng_many(&rnd, databuf, sizeof databuf); test_writes(part,block); + test_erases(part,block); } @@ -475,12 +538,21 @@ int main(void) { CYG_TEST_INIT(); init_timing(); + + ar4prng_init(&rnd,_stext, _etext-_stext); + ar4prng_many(&rnd, databuf, sizeof databuf); + + #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) || defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) CYG_TEST_INFO("WARNING: Clock or DSR latency instrumentation can mess with the results, recommend you turn it off."); #endif rwbenchmark_main(); + + if (fails) + CYG_TEST_FAIL_FINISH("something went wrong, THESE RESULTS ARE INVALID"); + CYG_TEST_EXIT("Run complete"); }
