From: Erik M. <er...@us...> - 2001-10-24 12:28:28
|
Update of /cvsroot/blob/blob/src/blob In directory usw-pr-cvs1:/tmp/cvs-serv13224/src/blob Modified Files: flash.c main.c Log Message: More flash cleanup. This includes the new flash write algorithm. Next is static flash partition support. Index: flash.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/flash.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- flash.c 2001/10/21 21:36:15 1.5 +++ flash.c 2001/10/24 12:28:25 1.6 @@ -11,6 +11,7 @@ /* * flash.c: Flash I/O functions for blob * + * Copyright (C) 2001 Erik Mouw (J.A...@it...) * Copyright (C) 1999 Jan-Derk Bakker (J.D...@it...) * * This program is free software; you can redistribute it and/or modify @@ -48,7 +49,7 @@ /* this is enough for a 16MB flash with 128kB blocks */ -#define NEW_NUM_FLASH_BLOCKS (128) +#define NUM_FLASH_BLOCKS (128) typedef struct { @@ -58,7 +59,7 @@ } flash_block_t; -static flash_block_t flash_blocks[NEW_NUM_FLASH_BLOCKS]; +static flash_block_t flash_blocks[NUM_FLASH_BLOCKS]; static int num_flash_blocks; flash_descriptor_t *flash_descriptors; @@ -113,7 +114,7 @@ num_flash_blocks++; - if(num_flash_blocks >= NEW_NUM_FLASH_BLOCKS) { + if(num_flash_blocks >= NUM_FLASH_BLOCKS) { printerrprefix(); SerialOutputString("not enough flash_blocks\n"); break; @@ -155,14 +156,21 @@ cur = start; end = start + nwords; +#if BLOB_DEBUG + SerialOutputString(__FUNCTION__ "(): erasing 0x"); + SerialOutputHex(nwords); + SerialOutputString(" ("); + SerialOutputDec(nwords); + SerialOutputString(") words at 0x"); + SerialOutputHex((u32)start); + SerialOutputByte('\n'); +#endif while(cur < end) { if(*cur != 0xffffffff) { - -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ "(): erasing dirty block at 0x"); + SerialOutputString("erasing dirty block at 0x"); SerialOutputHex((u32)cur); SerialOutputByte('\n'); -#endif + /* dirty block */ rv = flash_driver->flash_erase(cur); @@ -184,189 +192,107 @@ + +/* Write a flash region with a minimum number of erase operations. + * + * Flash chips wear from erase operations (that's why flash lifetime + * is specified in erase cycles), so we try to limit the number of + * erase operations in this function. Luckily the flash helps us a + * little bit with this, because it only allows you to change a '1' + * bit into a '0' during a write operation. This means that 0xffff can + * be changed into 0x1010, and 0x1010 into 0x0000, but 0x0000 can't be + * changed into anything else anymore because there are no '1' bits + * left. + */ int flash_write_region(u32 *dst, const u32 *src, u32 nwords) { - u32 *cur; - u32 *end; int rv; + u32 nerrors = 0; + u32 i = 0; - cur = dst; - end = dst + nwords; + u32 nerase = 0; + u32 nwrite = 0; + u32 nscandown = 0; + u32 nskip = 0; -#ifdef BLOB_DEBUG +#if BLOB_DEBUG SerialOutputString(__FUNCTION__ "(): flashing 0x"); SerialOutputHex(nwords); - SerialOutputString(" words from 0x"); + SerialOutputString(" ("); + SerialOutputDec(nwords); + SerialOutputString(") words from 0x"); SerialOutputHex((u32)src); SerialOutputString(" to 0x"); SerialOutputHex((u32)dst); SerialOutputByte('\n'); #endif - - while(cur < end) { - if((u32)cur % (16 * 1024) == 0) { - SerialOutputByte('.'); - led_toggle(); - } - - rv = flash_driver->flash_write(cur, src); - if(rv < 0) { - printerrprefix(); - SerialOutputString("flash write error at 0x"); - SerialOutputHex((u32)cur); - SerialOutputByte('\n'); - return rv; + while(i < nwords) { + /* nothing to write */ + if(dst[i] == src[i]) { + i++; + nskip++; + continue; } - - cur ++; - src ++; - } - - return 0; -} - - - - -/* -------- OLD ---------------------------------------------------- */ - - - - -/* Static function defs */ -static u32 EraseOne(const char *whichOne); - - + /* different, so write to this location */ + rv = flash_driver->flash_write(&dst[i], &src[i]); + nwrite++; + + if(rv == 0) { + i++; + } else { + nerrors++; + + SerialOutputString("erasing at 0x"); + SerialOutputHex((u32)&dst[i]); + SerialOutputString("..."); -void EraseBlocks(tBlockType which) -{ - char *thisBlock; - int numBlocks, i; + /* erase block at current location */ + rv = flash_driver->flash_erase(&dst[i]); + nerase++; + if(rv < 0) { + /* something is obviously wrong */ + return rv; + } + + SerialOutputString(" scanning down..."); - switch(which) { - case blBlob: - thisBlock = (char *)BLOB_START; - numBlocks = NUM_BLOB_BLOCKS; - break; + /* scan down until we find the first + non-erased location and restart writing + again from that location */ + while((i > 0) && + ((dst[i] != src[i]) || (dst[i] == 0xffffffff))) { + i--; + nscandown++; + } -#ifdef PARAM_START - case blParam: - thisBlock = (char *)PARAM_START; - numBlocks = NUM_PARAM_BLOCKS; - break; -#endif + SerialOutputString(" resume writing at 0x"); + SerialOutputHex((u32)&dst[i]); + SerialOutputByte('\n'); + } - case blKernel: - thisBlock = (char *)KERNEL_START; - numBlocks = NUM_KERNEL_BLOCKS; - break; - - case blRamdisk: - thisBlock = (char *)INITRD_START; - numBlocks = NUM_INITRD_BLOCKS; - break; - - default: - /* this should not happen */ - return; - } - - for(i = 0; i < numBlocks; i++, thisBlock += MAIN_BLOCK_SIZE) { - SerialOutputByte('.'); - led_toggle(); - if(EraseOne(thisBlock) != 0) { + /* there is something seriously wrong if this is true */ + if(nerrors > 2 * nwords) { printerrprefix(); - SerialOutputString("erase error at address 0x"); - SerialOutputHex((u32)thisBlock); - SerialOutputByte('\n'); - return; + SerialOutputString("too many flash errors, probably hardware error\n"); + return -EFLASHPGM; } } -} /* EraseBlocks */ - - - -void WriteBlocksFromMem(tBlockType type, const u32 *source, int length) -{ - u32 *flashBase; - int maxLength; - - if((u32)source & 0x03) { - printerror(EALIGN, NULL); #ifdef BLOB_DEBUG - printerrprefix(); - SerialOutputString("Address = 0x"); - SerialOutputHex((u32)source); - SerialOutputByte('\n'); -#endif - return; - } - - if(length & 0x03) - length += 0x04; - length &= ~((u32) 0x03); - - switch(type) { - case blBlob: - flashBase = (u32 *)BLOB_START; - maxLength = BLOB_LEN; - break; - -#ifdef PARAM_START - case blParam: - flashBase = (u32 *)PARAM_START; - maxLength = PARAM_LEN; - break; -#endif - - case blKernel: - flashBase = (u32 *)KERNEL_START; - maxLength = KERNEL_LEN; - break; - - case blRamdisk: - flashBase = (u32 *)INITRD_START; - maxLength = INITRD_LEN; - break; - - default: - /* this should not happen */ - return; - } - - length = (length + 3) / 4; - maxLength /= 4; - - if(length > maxLength) - length = maxLength; - -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ "(): Flashing 0x"); - SerialOutputHex((u32)length); - SerialOutputString(" words from 0x"); - SerialOutputHex((u32)source); - SerialOutputString(" to 0x"); - SerialOutputHex((u32)flashBase); + SerialOutputDec(nwords); + SerialOutputString(" words source image\n"); + SerialOutputDec(nwrite); + SerialOutputString(" words written to flash\n"); + SerialOutputDec(nskip); + SerialOutputString(" words skipped\n"); + SerialOutputDec(nerase); + SerialOutputString(" erase operations\n"); + SerialOutputDec(nscandown); + SerialOutputString(" words scanned down\n"); SerialOutputByte('\n'); #endif - - flash_write_region(flashBase, source, length); -} /* WriteBlocksFromMem */ - - - -static u32 EraseOne(const char *whichOne) -{ - int rv; - - rv = flash_erase_region((u32 *)whichOne, MAIN_BLOCK_SIZE / 4); - - if(rv < 0) - return 1; - else - return 0; -} /* EraseOne */ + return 0; +} Index: main.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/main.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- main.c 2001/10/14 20:24:32 1.3 +++ main.c 2001/10/24 12:28:25 1.4 @@ -131,13 +131,7 @@ #ifdef BLOB_DEBUG /* print some information */ - SerialOutputString("Running from "); - if(RunningFromInternal()) - SerialOutputString("internal"); - else - SerialOutputString("external"); - - SerialOutputString(" flash, blockSize = 0x"); + SerialOutputString("Flash blockSize = 0x"); SerialOutputHex(blockSize); SerialOutputByte('\n'); #endif @@ -271,38 +265,40 @@ static int Flash(int argc, char *argv[]) { - u32 startAddress = 0; - tBlockType block; - int numBytes = 0; - int maxSize = 0; + u32 *src; + u32 *dst; + u32 numBytes = 0; + u32 maxSize = 0; + u32 nwords; block_source_t type = fromFlash; + if(argc < 2) return -ENOPARAMS; if(strncmp(argv[1], "blob", 4) == 0) { - startAddress = BLOB_RAM_BASE; - block = blBlob; - numBytes = blob_status.blobSize; + src = (u32 *)BLOB_RAM_BASE; + dst = (u32 *)BLOB_START; maxSize = BLOB_LEN; + numBytes = blob_status.blobSize; type = blob_status.blobType; #ifdef PARAM_START } else if(strncmp(argv[1], "param", 5) == 0) { - startAddress = PARAM_RAM_BASE; - block = blParam; - numBytes = blob_status.paramSize; + src = (u32 *)PARAM_RAM_BASE; + dst = (u32 *)PARAM_START; maxSize = PARAM_LEN; + numBytes = blob_status.paramSize; type = blob_status.paramType; #endif } else if(strncmp(argv[1], "kernel", 6) == 0) { - startAddress = KERNEL_RAM_BASE; - block = blKernel; + src = (u32 *)KERNEL_RAM_BASE; + dst = (u32 *)KERNEL_START; numBytes = blob_status.kernelSize; maxSize = KERNEL_LEN; type = blob_status.kernelType; } else if(strncmp(argv[1], "ramdisk", 7) == 0) { - startAddress = RAMDISK_RAM_BASE; - block = blRamdisk; + src = (u32 *)RAMDISK_RAM_BASE; + dst = (u32 *)INITRD_START; numBytes = blob_status.ramdiskSize; maxSize = INITRD_LEN; type = blob_status.ramdiskType; @@ -312,7 +308,6 @@ } if(type == fromFlash) { - /* error */ printerrprefix(); SerialOutputString(argv[1]); SerialOutputString(" not downloaded\n"); @@ -330,13 +325,14 @@ return -ETOOLONG; } + nwords = (numBytes + sizeof(u32) - 1) / sizeof(u32); + SerialOutputString("Saving "); SerialOutputString(argv[1]); - SerialOutputString(" to flash "); - EraseBlocks(block); - SerialOutputByte(' '); - WriteBlocksFromMem(block, (u32 *)startAddress, numBytes); - SerialOutputString(" done\n"); + SerialOutputString(" to flash\n"); + + + flash_write_region(dst, src, nwords); return 0; } @@ -407,12 +403,6 @@ { SerialOutputString("Bootloader : " PACKAGE "\n"); SerialOutputString("Version : " VERSION "\n"); - - SerialOutputString("Running from : "); - if(RunningFromInternal()) - SerialOutputString("internal"); - else - SerialOutputString("external"); SerialOutputString(" flash\nBlocksize : 0x"); SerialOutputHex(blob_status.blockSize); |