changeset 2950:cde493f78168

NAND: add sweccwalk test
author Ross Younger <wry@ecoscentric.com>
date Wed, 28 Oct 2009 15:11:33 +0000
parents b72667909323
children 0eb1d8b14623
files packages/io/nand/current/ChangeLog packages/io/nand/current/cdl/nand.cdl packages/io/nand/current/tests/sweccwalk.c
diffstat 3 files changed, 179 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/nand/current/ChangeLog
+++ b/packages/io/nand/current/ChangeLog
@@ -4,6 +4,8 @@ 2009-10-27  Ross Younger  <wry@eCosCentr
 	implemented (default on).  Updated tests and utils to suit.
 	* nand.cdl: Add convenience options to build the utils as well
 	as the tests.
+	* tests/sweccwalk.c: Created (software ECC bit-walker and repair
+	consistency checks)
 
 2009-10-08  Ross Younger  <wry@eCosCentric.com>
 
--- a/packages/io/nand/current/cdl/nand.cdl
+++ b/packages/io/nand/current/cdl/nand.cdl
@@ -249,7 +249,7 @@ cdl_package CYGPKG_IO_NAND {
 		flavor data
 		no_define
 		calculated { "tests/nandunit tests/readlimits tests/readwrite"
-                     . " tests/rwbenchmark"
+                     . " tests/rwbenchmark tests/sweccwalk"
                      . (CYGBLD_IO_NAND_BUILD_UTILS ? CYGBLD_IO_NAND_UTILS : "")
         }
 		description "This special option specifies the set of NAND
new file mode 100644
--- /dev/null
+++ b/packages/io/nand/current/tests/sweccwalk.c
@@ -0,0 +1,176 @@
+//=============================================================================
+//
+//      sweccwalk.c
+//
+//      Walks some sample data through the software ECC algorithm to
+//      check that computation and repair operate correctly.
+//
+//=============================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2009 eCosCentric Limited.
+//
+// eCos 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 or (at your option) any later      
+// version.                                                                 
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   wry
+// Date:        2009-10-27
+//
+//####DESCRIPTIONEND####
+//=============================================================================
+
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/testcase.h>
+#include <cyg/nand/nand.h>
+#include <cyg/nand/nand_devtab.h>
+#include <cyg/nand/util.h>
+#include <cyg/infra/diag.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0)
+
+static CYG_NAND_DEVICE(fakenand, 0, 0, 0, &linux_mtd_ecc, 0);
+
+void init_fakenand(void)
+{
+    if (fakenand.is_inited)
+        return;
+
+    fakenand.is_inited = 1;
+    fakenand.pf = diag_printf;
+    fakenand.page_bits = 11; // 2048 byte test pattern.
+    fakenand.oob = &nand_mtd_oob_64;
+}
+
+
+void ecc(cyg_nand_device *dev, const CYG_BYTE *data, const char *msg, CYG_BYTE *out)
+{
+    if (dev->ecc->init)
+        dev->ecc->init(dev);
+    dev->ecc->calc(dev, data, dev->ecc->data_size, out);
+    diag_printf("%s: ecc=%02x%02x%02x\n", msg, out[0], out[1], out[2]);
+    // TODO adapt this display for ECCs longer than 3 bytes
+}
+
+const char msg[]="software ECC walker";
+
+#define ECC_BUFFER_SIZE 10
+CYG_BYTE buf[CYGNUM_NAND_PAGEBUFFER];
+CYG_BYTE ecc1[ECC_BUFFER_SIZE], ecc2[ECC_BUFFER_SIZE];
+
+int cyg_user_start(void)
+{
+    cyg_nand_device *dev = &fakenand;
+    int i;
+
+    CYG_TEST_INIT();
+    CYG_TEST_INFO(msg);
+
+#if 0
+    // This code can be adapted to test a hardware ECC algorithm but
+    // this usually requires some cunning in ecc() to cause the test
+    // data to pass through the hardware.
+    if (cyg_nanddevtab == &cyg_nanddevtab_end)
+        CYG_TEST_NA("No NAND devices found");
+
+    CYG_TEST_CHECK(0==cyg_nand_lookup("onboard", &dev),"lookup failed");
+#endif
+
+#define datasize (fakenand.ecc->data_size)
+#define eccsize  (fakenand.ecc->ecc_size)
+
+    CYG_ASSERTC(datasize <= CYGNUM_NAND_PAGEBUFFER);
+    CYG_ASSERTC(eccsize <= ECC_BUFFER_SIZE);
+
+    diag_printf("ECC sizes: data %d, ecc %d\n", datasize, eccsize);
+
+    // Plan: Start with a buffer full of 0xFF; then, changing one bit 
+    // at a time, compute a fresh ECC and check that the repair code
+    // does the right thing. This code can also be used to help work
+    // out what's going on with an unclearly-documented ECC algorithm.
+
+    memset(buf, 255, sizeof(buf));
+    ecc(dev, buf, "all-ff", ecc1);
+
+    for (i=0; i<8; i++) {
+        int st;
+        char msg[] = "bit X";
+        buf[0] ^= 1<<i;
+        msg[4] = '0' + i;
+        ecc(dev, buf, msg, ecc2);
+
+        st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2);
+        CYG_ASSERTC(st==1);
+        CYG_ASSERTC(buf[0] == 0xff);
+
+        ecc(dev, buf, msg, ecc2);
+        st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2);
+        CYG_ASSERTC(st==0);
+    }
+    int max;
+    switch(datasize) {
+        case 256: max = 8; break;
+        case 512: max = 9; break;
+        // Add further cases here for different ECC data sizes.
+        default:
+                  diag_printf("Unhandled case datasize=%d\n",datasize);
+                  CYG_TEST_FAIL_EXIT("Unhandled case!");
+    }
+    for (i=0; i<max; i++) {
+        char msg[256];
+        int st;
+        diag_snprintf(msg, sizeof msg, "bytelog %d", i);
+
+        buf[1<<i] ^= 1;
+        ecc(dev, buf, msg, ecc2);
+        st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2);
+        CYG_ASSERTC(st==1);
+        CYG_ASSERTC(buf[1<<i] == 0xff);
+
+        ecc(dev, buf, msg, ecc2);
+        st = dev->ecc->repair(dev, buf, sizeof buf, ecc1, ecc2);
+        CYG_ASSERTC(st==0);
+    }
+
+    int fail=0;
+    for (i=0; i<datasize; i++) {
+        if (buf[i] != 0xff) {
+            ++fail;
+            diag_printf("buf[%d] == %02x != 0xff\n", i, buf[i]);
+        }
+    }
+
+    if (fail)
+        CYG_TEST_FAIL_FINISH(msg);
+    else
+        CYG_TEST_PASS_FINISH(msg);
+}
+