aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nandsim.c
diff options
context:
space:
mode:
authorAdrian Hunter <ext-adrian.hunter@nokia.com>2008-11-12 09:06:07 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-12-10 08:35:21 -0500
commita9fc8991883cdf029bd373a82cbc2d12a10799dd (patch)
treec695dd7928354028733f9621ba67a592d2b1c5ed /drivers/mtd/nand/nandsim.c
parent9359ea461b382de3249469d2165da45f4762b910 (diff)
MTD: nandsim: add option to use a file to cache pages
Add a new module parameter 'cache_file' which causes nandsim to use that file instead of memory to cache nand data. Using a file allows the simulation of NAND that is bigger than the available memory. Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/nandsim.c')
-rw-r--r--drivers/mtd/nand/nandsim.c285
1 files changed, 261 insertions, 24 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index fdf82cf24449..baa6f95e9621 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -38,6 +38,8 @@
38#include <linux/delay.h> 38#include <linux/delay.h>
39#include <linux/list.h> 39#include <linux/list.h>
40#include <linux/random.h> 40#include <linux/random.h>
41#include <linux/fs.h>
42#include <linux/pagemap.h>
41 43
42/* Default simulator parameters values */ 44/* Default simulator parameters values */
43#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ 45#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@@ -100,6 +102,7 @@ static unsigned int bitflips = 0;
100static char *gravepages = NULL; 102static char *gravepages = NULL;
101static unsigned int rptwear = 0; 103static unsigned int rptwear = 0;
102static unsigned int overridesize = 0; 104static unsigned int overridesize = 0;
105static char *cache_file = NULL;
103 106
104module_param(first_id_byte, uint, 0400); 107module_param(first_id_byte, uint, 0400);
105module_param(second_id_byte, uint, 0400); 108module_param(second_id_byte, uint, 0400);
@@ -122,12 +125,13 @@ module_param(bitflips, uint, 0400);
122module_param(gravepages, charp, 0400); 125module_param(gravepages, charp, 0400);
123module_param(rptwear, uint, 0400); 126module_param(rptwear, uint, 0400);
124module_param(overridesize, uint, 0400); 127module_param(overridesize, uint, 0400);
128module_param(cache_file, charp, 0400);
125 129
126MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); 130MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
127MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); 131MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
128MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); 132MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
129MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); 133MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
130MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); 134MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)");
131MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); 135MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
132MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); 136MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
133MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); 137MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)");
@@ -153,6 +157,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if
153MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " 157MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
154 "The size is specified in erase blocks and as the exponent of a power of two" 158 "The size is specified in erase blocks and as the exponent of a power of two"
155 " e.g. 5 means a size of 32 erase blocks"); 159 " e.g. 5 means a size of 32 erase blocks");
160MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
156 161
157/* The largest possible page size */ 162/* The largest possible page size */
158#define NS_LARGEST_PAGE_SIZE 2048 163#define NS_LARGEST_PAGE_SIZE 2048
@@ -266,6 +271,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
266 */ 271 */
267#define NS_MAX_PREVSTATES 1 272#define NS_MAX_PREVSTATES 1
268 273
274/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
275#define NS_MAX_HELD_PAGES 16
276
269/* 277/*
270 * A union to represent flash memory contents and flash buffer. 278 * A union to represent flash memory contents and flash buffer.
271 */ 279 */
@@ -335,6 +343,13 @@ struct nandsim {
335 int ale; /* address Latch Enable */ 343 int ale; /* address Latch Enable */
336 int wp; /* write Protect */ 344 int wp; /* write Protect */
337 } lines; 345 } lines;
346
347 /* Fields needed when using a cache file */
348 struct file *cfile; /* Open file */
349 unsigned char *pages_written; /* Which pages have been written */
350 void *file_buf;
351 struct page *held_pages[NS_MAX_HELD_PAGES];
352 int held_cnt;
338}; 353};
339 354
340/* 355/*
@@ -427,11 +442,43 @@ static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
427 */ 442 */
428static int alloc_device(struct nandsim *ns) 443static int alloc_device(struct nandsim *ns)
429{ 444{
430 int i; 445 struct file *cfile;
446 int i, err;
447
448 if (cache_file) {
449 cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
450 if (IS_ERR(cfile))
451 return PTR_ERR(cfile);
452 if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) {
453 NS_ERR("alloc_device: cache file not readable\n");
454 err = -EINVAL;
455 goto err_close;
456 }
457 if (!cfile->f_op->write && !cfile->f_op->aio_write) {
458 NS_ERR("alloc_device: cache file not writeable\n");
459 err = -EINVAL;
460 goto err_close;
461 }
462 ns->pages_written = vmalloc(ns->geom.pgnum);
463 if (!ns->pages_written) {
464 NS_ERR("alloc_device: unable to allocate pages written array\n");
465 err = -ENOMEM;
466 goto err_close;
467 }
468 ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
469 if (!ns->file_buf) {
470 NS_ERR("alloc_device: unable to allocate file buf\n");
471 err = -ENOMEM;
472 goto err_free;
473 }
474 ns->cfile = cfile;
475 memset(ns->pages_written, 0, ns->geom.pgnum);
476 return 0;
477 }
431 478
432 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); 479 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
433 if (!ns->pages) { 480 if (!ns->pages) {
434 NS_ERR("alloc_map: unable to allocate page array\n"); 481 NS_ERR("alloc_device: unable to allocate page array\n");
435 return -ENOMEM; 482 return -ENOMEM;
436 } 483 }
437 for (i = 0; i < ns->geom.pgnum; i++) { 484 for (i = 0; i < ns->geom.pgnum; i++) {
@@ -439,6 +486,12 @@ static int alloc_device(struct nandsim *ns)
439 } 486 }
440 487
441 return 0; 488 return 0;
489
490err_free:
491 vfree(ns->pages_written);
492err_close:
493 filp_close(cfile, NULL);
494 return err;
442} 495}
443 496
444/* 497/*
@@ -448,6 +501,13 @@ static void free_device(struct nandsim *ns)
448{ 501{
449 int i; 502 int i;
450 503
504 if (ns->cfile) {
505 kfree(ns->file_buf);
506 vfree(ns->pages_written);
507 filp_close(ns->cfile, NULL);
508 return;
509 }
510
451 if (ns->pages) { 511 if (ns->pages) {
452 for (i = 0; i < ns->geom.pgnum; i++) { 512 for (i = 0; i < ns->geom.pgnum; i++) {
453 if (ns->pages[i].byte) 513 if (ns->pages[i].byte)
@@ -1211,6 +1271,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
1211 return -1; 1271 return -1;
1212} 1272}
1213 1273
1274static void put_pages(struct nandsim *ns)
1275{
1276 int i;
1277
1278 for (i = 0; i < ns->held_cnt; i++)
1279 page_cache_release(ns->held_pages[i]);
1280}
1281
1282/* Get page cache pages in advance to provide NOFS memory allocation */
1283static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
1284{
1285 pgoff_t index, start_index, end_index;
1286 struct page *page;
1287 struct address_space *mapping = file->f_mapping;
1288
1289 start_index = pos >> PAGE_CACHE_SHIFT;
1290 end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT;
1291 if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
1292 return -EINVAL;
1293 ns->held_cnt = 0;
1294 for (index = start_index; index <= end_index; index++) {
1295 page = find_get_page(mapping, index);
1296 if (page == NULL) {
1297 page = find_or_create_page(mapping, index, GFP_NOFS);
1298 if (page == NULL) {
1299 write_inode_now(mapping->host, 1);
1300 page = find_or_create_page(mapping, index, GFP_NOFS);
1301 }
1302 if (page == NULL) {
1303 put_pages(ns);
1304 return -ENOMEM;
1305 }
1306 unlock_page(page);
1307 }
1308 ns->held_pages[ns->held_cnt++] = page;
1309 }
1310 return 0;
1311}
1312
1313static int set_memalloc(void)
1314{
1315 if (current->flags & PF_MEMALLOC)
1316 return 0;
1317 current->flags |= PF_MEMALLOC;
1318 return 1;
1319}
1320
1321static void clear_memalloc(int memalloc)
1322{
1323 if (memalloc)
1324 current->flags &= ~PF_MEMALLOC;
1325}
1326
1327static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
1328{
1329 mm_segment_t old_fs;
1330 ssize_t tx;
1331 int err, memalloc;
1332
1333 err = get_pages(ns, file, count, *pos);
1334 if (err)
1335 return err;
1336 old_fs = get_fs();
1337 set_fs(get_ds());
1338 memalloc = set_memalloc();
1339 tx = vfs_read(file, (char __user *)buf, count, pos);
1340 clear_memalloc(memalloc);
1341 set_fs(old_fs);
1342 put_pages(ns);
1343 return tx;
1344}
1345
1346static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
1347{
1348 mm_segment_t old_fs;
1349 ssize_t tx;
1350 int err, memalloc;
1351
1352 err = get_pages(ns, file, count, *pos);
1353 if (err)
1354 return err;
1355 old_fs = get_fs();
1356 set_fs(get_ds());
1357 memalloc = set_memalloc();
1358 tx = vfs_write(file, (char __user *)buf, count, pos);
1359 clear_memalloc(memalloc);
1360 set_fs(old_fs);
1361 put_pages(ns);
1362 return tx;
1363}
1364
1214/* 1365/*
1215 * Returns a pointer to the current page. 1366 * Returns a pointer to the current page.
1216 */ 1367 */
@@ -1227,6 +1378,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
1227 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; 1378 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
1228} 1379}
1229 1380
1381int do_read_error(struct nandsim *ns, int num)
1382{
1383 unsigned int page_no = ns->regs.row;
1384
1385 if (read_error(page_no)) {
1386 int i;
1387 memset(ns->buf.byte, 0xFF, num);
1388 for (i = 0; i < num; ++i)
1389 ns->buf.byte[i] = random32();
1390 NS_WARN("simulating read error in page %u\n", page_no);
1391 return 1;
1392 }
1393 return 0;
1394}
1395
1396void do_bit_flips(struct nandsim *ns, int num)
1397{
1398 if (bitflips && random32() < (1 << 22)) {
1399 int flips = 1;
1400 if (bitflips > 1)
1401 flips = (random32() % (int) bitflips) + 1;
1402 while (flips--) {
1403 int pos = random32() % (num * 8);
1404 ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
1405 NS_WARN("read_page: flipping bit %d in page %d "
1406 "reading from %d ecc: corrected=%u failed=%u\n",
1407 pos, ns->regs.row, ns->regs.column + ns->regs.off,
1408 nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
1409 }
1410 }
1411}
1412
1230/* 1413/*
1231 * Fill the NAND buffer with data read from the specified page. 1414 * Fill the NAND buffer with data read from the specified page.
1232 */ 1415 */
@@ -1234,36 +1417,40 @@ static void read_page(struct nandsim *ns, int num)
1234{ 1417{
1235 union ns_mem *mypage; 1418 union ns_mem *mypage;
1236 1419
1420 if (ns->cfile) {
1421 if (!ns->pages_written[ns->regs.row]) {
1422 NS_DBG("read_page: page %d not written\n", ns->regs.row);
1423 memset(ns->buf.byte, 0xFF, num);
1424 } else {
1425 loff_t pos;
1426 ssize_t tx;
1427
1428 NS_DBG("read_page: page %d written, reading from %d\n",
1429 ns->regs.row, ns->regs.column + ns->regs.off);
1430 if (do_read_error(ns, num))
1431 return;
1432 pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
1433 tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos);
1434 if (tx != num) {
1435 NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
1436 return;
1437 }
1438 do_bit_flips(ns, num);
1439 }
1440 return;
1441 }
1442
1237 mypage = NS_GET_PAGE(ns); 1443 mypage = NS_GET_PAGE(ns);
1238 if (mypage->byte == NULL) { 1444 if (mypage->byte == NULL) {
1239 NS_DBG("read_page: page %d not allocated\n", ns->regs.row); 1445 NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
1240 memset(ns->buf.byte, 0xFF, num); 1446 memset(ns->buf.byte, 0xFF, num);
1241 } else { 1447 } else {
1242 unsigned int page_no = ns->regs.row;
1243 NS_DBG("read_page: page %d allocated, reading from %d\n", 1448 NS_DBG("read_page: page %d allocated, reading from %d\n",
1244 ns->regs.row, ns->regs.column + ns->regs.off); 1449 ns->regs.row, ns->regs.column + ns->regs.off);
1245 if (read_error(page_no)) { 1450 if (do_read_error(ns, num))
1246 int i;
1247 memset(ns->buf.byte, 0xFF, num);
1248 for (i = 0; i < num; ++i)
1249 ns->buf.byte[i] = random32();
1250 NS_WARN("simulating read error in page %u\n", page_no);
1251 return; 1451 return;
1252 }
1253 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); 1452 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
1254 if (bitflips && random32() < (1 << 22)) { 1453 do_bit_flips(ns, num);
1255 int flips = 1;
1256 if (bitflips > 1)
1257 flips = (random32() % (int) bitflips) + 1;
1258 while (flips--) {
1259 int pos = random32() % (num * 8);
1260 ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
1261 NS_WARN("read_page: flipping bit %d in page %d "
1262 "reading from %d ecc: corrected=%u failed=%u\n",
1263 pos, ns->regs.row, ns->regs.column + ns->regs.off,
1264 nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
1265 }
1266 }
1267 } 1454 }
1268} 1455}
1269 1456
@@ -1275,6 +1462,15 @@ static void erase_sector(struct nandsim *ns)
1275 union ns_mem *mypage; 1462 union ns_mem *mypage;
1276 int i; 1463 int i;
1277 1464
1465 if (ns->cfile) {
1466 for (i = 0; i < ns->geom.pgsec; i++)
1467 if (ns->pages_written[ns->regs.row + i]) {
1468 NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
1469 ns->pages_written[ns->regs.row + i] = 0;
1470 }
1471 return;
1472 }
1473
1278 mypage = NS_GET_PAGE(ns); 1474 mypage = NS_GET_PAGE(ns);
1279 for (i = 0; i < ns->geom.pgsec; i++) { 1475 for (i = 0; i < ns->geom.pgsec; i++) {
1280 if (mypage->byte != NULL) { 1476 if (mypage->byte != NULL) {
@@ -1295,6 +1491,47 @@ static int prog_page(struct nandsim *ns, int num)
1295 union ns_mem *mypage; 1491 union ns_mem *mypage;
1296 u_char *pg_off; 1492 u_char *pg_off;
1297 1493
1494 if (ns->cfile) {
1495 loff_t off, pos;
1496 ssize_t tx;
1497 int all;
1498
1499 NS_DBG("prog_page: writing page %d\n", ns->regs.row);
1500 pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
1501 off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
1502 if (!ns->pages_written[ns->regs.row]) {
1503 all = 1;
1504 memset(ns->file_buf, 0xff, ns->geom.pgszoob);
1505 } else {
1506 all = 0;
1507 pos = off;
1508 tx = read_file(ns, ns->cfile, pg_off, num, &pos);
1509 if (tx != num) {
1510 NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
1511 return -1;
1512 }
1513 }
1514 for (i = 0; i < num; i++)
1515 pg_off[i] &= ns->buf.byte[i];
1516 if (all) {
1517 pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
1518 tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos);
1519 if (tx != ns->geom.pgszoob) {
1520 NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
1521 return -1;
1522 }
1523 ns->pages_written[ns->regs.row] = 1;
1524 } else {
1525 pos = off;
1526 tx = write_file(ns, ns->cfile, pg_off, num, &pos);
1527 if (tx != num) {
1528 NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
1529 return -1;
1530 }
1531 }
1532 return 0;
1533 }
1534
1298 mypage = NS_GET_PAGE(ns); 1535 mypage = NS_GET_PAGE(ns);
1299 if (mypage->byte == NULL) { 1536 if (mypage->byte == NULL) {
1300 NS_DBG("prog_page: allocating page %d\n", ns->regs.row); 1537 NS_DBG("prog_page: allocating page %d\n", ns->regs.row);