/* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * 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. */ /* * yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2) */ /* XXX U-BOOT XXX */ #include const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.3 2007/02/14 01:09:06 wookey Exp $"; #ifndef __KERNEL__ #define CONFIG_YAFFS_RAM_ENABLED #else #include #endif #ifdef CONFIG_YAFFS_RAM_ENABLED #include "yportenv.h" #include "yaffs_nandemul2k.h" #include "yaffs_guts.h" #include "yaffsinterface.h" #include "devextras.h" #include "yaffs_packedtags2.h" #define EM_SIZE_IN_MEG (32) #define PAGE_DATA_SIZE (2048) #define PAGE_SPARE_SIZE (64) #define PAGES_PER_BLOCK (64) #define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20)) #define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE) #define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE) #define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE)) typedef struct { __u8 data[PAGE_TOTAL_SIZE]; // Data + spare int empty; // is this empty? } nandemul_Page; typedef struct { nandemul_Page *page[PAGES_PER_BLOCK]; int damaged; } nandemul_Block; typedef struct { nandemul_Block**block; int nBlocks; } nandemul_Device; static nandemul_Device ned; static int sizeInMB = EM_SIZE_IN_MEG; static void nandemul_yield(int n) { #ifdef __KERNEL__ if(n > 0) schedule_timeout(n); #endif } static void nandemul_ReallyEraseBlock(int blockNumber) { int i; nandemul_Block *blk; if(blockNumber < 0 || blockNumber >= ned.nBlocks) { return; } blk = ned.block[blockNumber]; for(i = 0; i < PAGES_PER_BLOCK; i++) { memset(blk->page[i],0xff,sizeof(nandemul_Page)); blk->page[i]->empty = 1; } nandemul_yield(2); } static int nandemul2k_CalcNBlocks(void) { return EM_SIZE_IN_MEG * BLOCKS_PER_MEG; } static int CheckInit(void) { static int initialised = 0; int i,j; int fail = 0; int nBlocks; int nAllocated = 0; if(initialised) { return YAFFS_OK; } ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks ); if(!ned.block) return YAFFS_FAIL; for(i=fail=0; i page[j] = YMALLOC(sizeof(nandemul_Page))) == 0) { fail = 1; } } nandemul_ReallyEraseBlock(i); ned.block[i]->damaged = 0; nAllocated++; } } if(fail) { //Todo thump pages for(i = 0; i < nAllocated; i++) { YFREE(ned.block[i]); } YFREE(ned.block); T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n", nAllocated/64,sizeInMB)); return 0; } ned.nBlocks = nBlocks; initialised = 1; return 1; } int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags) { int blk; int pg; int i; __u8 *x; blk = chunkInNAND/PAGES_PER_BLOCK; pg = chunkInNAND%PAGES_PER_BLOCK; if(data) { x = ned.block[blk]->page[pg]->data; for(i = 0; i < PAGE_DATA_SIZE; i++) { x[i] &=data[i]; } ned.block[blk]->page[pg]->empty = 0; } if(tags) { x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; yaffs_PackTags2((yaffs_PackedTags2 *)x,tags); } if(tags || data) { nandemul_yield(1); } return YAFFS_OK; } int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags) { int blk; int pg; __u8 *x; blk = chunkInNAND/PAGES_PER_BLOCK; pg = chunkInNAND%PAGES_PER_BLOCK; if(data) { memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE); } if(tags) { x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x); } return YAFFS_OK; } static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND) { int blk; int pg; int i; blk = chunkInNAND/PAGES_PER_BLOCK; pg = chunkInNAND%PAGES_PER_BLOCK; for(i = 0; i < PAGE_TOTAL_SIZE; i++) { if(ned.block[blk]->page[pg]->data[i] != 0xFF) { return YAFFS_FAIL; } } return YAFFS_OK; } int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) { if(blockNumber < 0 || blockNumber >= ned.nBlocks) { T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber)); } else if(ned.block[blockNumber]->damaged) { T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber)); } else { nandemul_ReallyEraseBlock(blockNumber); } return YAFFS_OK; } int nandemul2k_InitialiseNAND(yaffs_Device *dev) { CheckInit(); return YAFFS_OK; } int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) { __u8 *x; x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE]; memset(x,0,sizeof(yaffs_PackedTags2)); return YAFFS_OK; } int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) { yaffs_ExtendedTags tags; int chunkNo; *sequenceNumber = 0; chunkNo = blockNo * dev->nChunksPerBlock; nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); if(tags.blockBad) { *state = YAFFS_BLOCK_STATE_DEAD; } else if(!tags.chunkUsed) { *state = YAFFS_BLOCK_STATE_EMPTY; } else if(tags.chunkUsed) { *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; *sequenceNumber = tags.sequenceNumber; } return YAFFS_OK; } int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;} int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; } int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();} #endif //YAFFS_RAM_ENABLED