blob: 8161789280184a882b2ef2cb2a09fe3dd5be350d [file] [log] [blame]
William Juulc051bbe2007-11-15 11:13:05 +01001/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/*
15 * yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2)
16 */
17
William Juule24ebad2007-11-15 12:23:57 +010018/* XXX U-BOOT XXX */
19#include <common.h>
William Juulc051bbe2007-11-15 11:13:05 +010020
21const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
22
23#ifndef __KERNEL__
24#define CONFIG_YAFFS_RAM_ENABLED
25#else
26#include <linux/config.h>
27#endif
28
29#ifdef CONFIG_YAFFS_RAM_ENABLED
30
31#include "yportenv.h"
32
33#include "yaffs_nandemul2k.h"
34#include "yaffs_guts.h"
35#include "yaffsinterface.h"
36#include "devextras.h"
37#include "yaffs_packedtags2.h"
38
39
40
41#define EM_SIZE_IN_MEG (32)
42#define PAGE_DATA_SIZE (2048)
43#define PAGE_SPARE_SIZE (64)
44#define PAGES_PER_BLOCK (64)
45
46
47
48#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
49
50#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
51
52#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
53
54#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
55
56
57typedef struct
58{
59 __u8 data[PAGE_TOTAL_SIZE]; // Data + spare
60 int empty; // is this empty?
61} nandemul_Page;
62
63
64typedef struct
65{
66 nandemul_Page *page[PAGES_PER_BLOCK];
67 int damaged;
68} nandemul_Block;
69
70
71
72typedef struct
73{
74 nandemul_Block**block;
75 int nBlocks;
76} nandemul_Device;
77
78static nandemul_Device ned;
79
80static int sizeInMB = EM_SIZE_IN_MEG;
81
82
83static void nandemul_yield(int n)
84{
85#ifdef __KERNEL__
86 if(n > 0) schedule_timeout(n);
87#endif
88
89}
90
91
92static void nandemul_ReallyEraseBlock(int blockNumber)
93{
94 int i;
95
96 nandemul_Block *blk;
97
98 if(blockNumber < 0 || blockNumber >= ned.nBlocks)
99 {
100 return;
101 }
102
103 blk = ned.block[blockNumber];
104
105 for(i = 0; i < PAGES_PER_BLOCK; i++)
106 {
107 memset(blk->page[i],0xff,sizeof(nandemul_Page));
108 blk->page[i]->empty = 1;
109 }
110 nandemul_yield(2);
111}
112
113
114static int nandemul2k_CalcNBlocks(void)
115{
116 return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
117}
118
119
120
121static int CheckInit(void)
122{
123 static int initialised = 0;
124
125 int i,j;
126
127 int fail = 0;
128 int nBlocks;
129
130 int nAllocated = 0;
131
132 if(initialised)
133 {
134 return YAFFS_OK;
135 }
136
137
138 ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
139
140
141 ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks );
142
143 if(!ned.block) return YAFFS_FAIL;
144
145
146
147
148
149 for(i=fail=0; i <nBlocks; i++)
150 {
151
152 nandemul_Block *blk;
153
154 if(!(blk = ned.block[i] = YMALLOC(sizeof(nandemul_Block))))
155 {
156 fail = 1;
157 }
158 else
159 {
160 for(j = 0; j < PAGES_PER_BLOCK; j++)
161 {
162 if((blk->page[j] = YMALLOC(sizeof(nandemul_Page))) == 0)
163 {
164 fail = 1;
165 }
166 }
167 nandemul_ReallyEraseBlock(i);
168 ned.block[i]->damaged = 0;
169 nAllocated++;
170 }
171 }
172
173 if(fail)
174 {
175 //Todo thump pages
176
177 for(i = 0; i < nAllocated; i++)
178 {
179 YFREE(ned.block[i]);
180 }
181 YFREE(ned.block);
182
183 T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
184 nAllocated/64,sizeInMB));
185 return 0;
186 }
187
188 ned.nBlocks = nBlocks;
189
190 initialised = 1;
191
192 return 1;
193}
194
195int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
196{
197 int blk;
198 int pg;
199 int i;
200
201 __u8 *x;
202
203
204 blk = chunkInNAND/PAGES_PER_BLOCK;
205 pg = chunkInNAND%PAGES_PER_BLOCK;
206
207
208 if(data)
209 {
210 x = ned.block[blk]->page[pg]->data;
211
212 for(i = 0; i < PAGE_DATA_SIZE; i++)
213 {
214 x[i] &=data[i];
215 }
216
217 ned.block[blk]->page[pg]->empty = 0;
218 }
219
220
221 if(tags)
222 {
223 x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
224
225 yaffs_PackTags2((yaffs_PackedTags2 *)x,tags);
226
227 }
228
229 if(tags || data)
230 {
231 nandemul_yield(1);
232 }
233
234 return YAFFS_OK;
235}
236
237
238int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
239{
240 int blk;
241 int pg;
242
243 __u8 *x;
244
245
246
247 blk = chunkInNAND/PAGES_PER_BLOCK;
248 pg = chunkInNAND%PAGES_PER_BLOCK;
249
250
251 if(data)
252 {
253 memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE);
254 }
255
256
257 if(tags)
258 {
259 x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
260
261 yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x);
262 }
263
264 return YAFFS_OK;
265}
266
267
268static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
269{
270 int blk;
271 int pg;
272 int i;
273
274
275
276 blk = chunkInNAND/PAGES_PER_BLOCK;
277 pg = chunkInNAND%PAGES_PER_BLOCK;
278
279
280 for(i = 0; i < PAGE_TOTAL_SIZE; i++)
281 {
282 if(ned.block[blk]->page[pg]->data[i] != 0xFF)
283 {
284 return YAFFS_FAIL;
285 }
286 }
287
288 return YAFFS_OK;
289
290}
291
292int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
293{
294
295
296 if(blockNumber < 0 || blockNumber >= ned.nBlocks)
297 {
298 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
299 }
300 else if(ned.block[blockNumber]->damaged)
301 {
302 T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber));
303 }
304 else
305 {
306 nandemul_ReallyEraseBlock(blockNumber);
307 }
308
309 return YAFFS_OK;
310}
311
312int nandemul2k_InitialiseNAND(yaffs_Device *dev)
313{
314 CheckInit();
315 return YAFFS_OK;
316}
317
318int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
319{
320
321 __u8 *x;
322
323 x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE];
324
325 memset(x,0,sizeof(yaffs_PackedTags2));
326
327
328 return YAFFS_OK;
329
330}
331
332int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
333{
334 yaffs_ExtendedTags tags;
335 int chunkNo;
336
337 *sequenceNumber = 0;
338
339 chunkNo = blockNo * dev->nChunksPerBlock;
340
341 nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
342 if(tags.blockBad)
343 {
344 *state = YAFFS_BLOCK_STATE_DEAD;
345 }
346 else if(!tags.chunkUsed)
347 {
348 *state = YAFFS_BLOCK_STATE_EMPTY;
349 }
350 else if(tags.chunkUsed)
351 {
352 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
353 *sequenceNumber = tags.sequenceNumber;
354 }
355 return YAFFS_OK;
356}
357
358int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
359
360int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
361int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
362
363
364#endif //YAFFS_RAM_ENABLED