diff options
Diffstat (limited to 'drivers/mtd/nand/nandsim.c')
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 339 |
1 files changed, 296 insertions, 43 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index ae7c57781a68..cd0711b83ac4 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -38,6 +38,9 @@ | |||
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/sched.h> | ||
42 | #include <linux/fs.h> | ||
43 | #include <linux/pagemap.h> | ||
41 | 44 | ||
42 | /* Default simulator parameters values */ | 45 | /* Default simulator parameters values */ |
43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 46 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -100,6 +103,7 @@ static unsigned int bitflips = 0; | |||
100 | static char *gravepages = NULL; | 103 | static char *gravepages = NULL; |
101 | static unsigned int rptwear = 0; | 104 | static unsigned int rptwear = 0; |
102 | static unsigned int overridesize = 0; | 105 | static unsigned int overridesize = 0; |
106 | static char *cache_file = NULL; | ||
103 | 107 | ||
104 | module_param(first_id_byte, uint, 0400); | 108 | module_param(first_id_byte, uint, 0400); |
105 | module_param(second_id_byte, uint, 0400); | 109 | module_param(second_id_byte, uint, 0400); |
@@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400); | |||
122 | module_param(gravepages, charp, 0400); | 126 | module_param(gravepages, charp, 0400); |
123 | module_param(rptwear, uint, 0400); | 127 | module_param(rptwear, uint, 0400); |
124 | module_param(overridesize, uint, 0400); | 128 | module_param(overridesize, uint, 0400); |
129 | module_param(cache_file, charp, 0400); | ||
125 | 130 | ||
126 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | 131 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); |
127 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 132 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
128 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); | 133 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); |
129 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); | 134 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); |
130 | MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); | 135 | MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); |
131 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); | 136 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); |
132 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); | 137 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); |
133 | MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); | 138 | MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); |
@@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if | |||
153 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | 158 | MODULE_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" | 159 | "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"); | 160 | " e.g. 5 means a size of 32 erase blocks"); |
161 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); | ||
156 | 162 | ||
157 | /* The largest possible page size */ | 163 | /* The largest possible page size */ |
158 | #define NS_LARGEST_PAGE_SIZE 2048 | 164 | #define NS_LARGEST_PAGE_SIZE 2048 |
@@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I | |||
266 | */ | 272 | */ |
267 | #define NS_MAX_PREVSTATES 1 | 273 | #define NS_MAX_PREVSTATES 1 |
268 | 274 | ||
275 | /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ | ||
276 | #define NS_MAX_HELD_PAGES 16 | ||
277 | |||
269 | /* | 278 | /* |
270 | * A union to represent flash memory contents and flash buffer. | 279 | * A union to represent flash memory contents and flash buffer. |
271 | */ | 280 | */ |
@@ -295,6 +304,9 @@ struct nandsim { | |||
295 | /* The simulated NAND flash pages array */ | 304 | /* The simulated NAND flash pages array */ |
296 | union ns_mem *pages; | 305 | union ns_mem *pages; |
297 | 306 | ||
307 | /* Slab allocator for nand pages */ | ||
308 | struct kmem_cache *nand_pages_slab; | ||
309 | |||
298 | /* Internal buffer of page + OOB size bytes */ | 310 | /* Internal buffer of page + OOB size bytes */ |
299 | union ns_mem buf; | 311 | union ns_mem buf; |
300 | 312 | ||
@@ -335,6 +347,13 @@ struct nandsim { | |||
335 | int ale; /* address Latch Enable */ | 347 | int ale; /* address Latch Enable */ |
336 | int wp; /* write Protect */ | 348 | int wp; /* write Protect */ |
337 | } lines; | 349 | } lines; |
350 | |||
351 | /* Fields needed when using a cache file */ | ||
352 | struct file *cfile; /* Open file */ | ||
353 | unsigned char *pages_written; /* Which pages have been written */ | ||
354 | void *file_buf; | ||
355 | struct page *held_pages[NS_MAX_HELD_PAGES]; | ||
356 | int held_cnt; | ||
338 | }; | 357 | }; |
339 | 358 | ||
340 | /* | 359 | /* |
@@ -420,25 +439,69 @@ static struct mtd_info *nsmtd; | |||
420 | static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; | 439 | static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; |
421 | 440 | ||
422 | /* | 441 | /* |
423 | * Allocate array of page pointers and initialize the array to NULL | 442 | * Allocate array of page pointers, create slab allocation for an array |
424 | * pointers. | 443 | * and initialize the array by NULL pointers. |
425 | * | 444 | * |
426 | * RETURNS: 0 if success, -ENOMEM if memory alloc fails. | 445 | * RETURNS: 0 if success, -ENOMEM if memory alloc fails. |
427 | */ | 446 | */ |
428 | static int alloc_device(struct nandsim *ns) | 447 | static int alloc_device(struct nandsim *ns) |
429 | { | 448 | { |
430 | int i; | 449 | struct file *cfile; |
450 | int i, err; | ||
451 | |||
452 | if (cache_file) { | ||
453 | cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); | ||
454 | if (IS_ERR(cfile)) | ||
455 | return PTR_ERR(cfile); | ||
456 | if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { | ||
457 | NS_ERR("alloc_device: cache file not readable\n"); | ||
458 | err = -EINVAL; | ||
459 | goto err_close; | ||
460 | } | ||
461 | if (!cfile->f_op->write && !cfile->f_op->aio_write) { | ||
462 | NS_ERR("alloc_device: cache file not writeable\n"); | ||
463 | err = -EINVAL; | ||
464 | goto err_close; | ||
465 | } | ||
466 | ns->pages_written = vmalloc(ns->geom.pgnum); | ||
467 | if (!ns->pages_written) { | ||
468 | NS_ERR("alloc_device: unable to allocate pages written array\n"); | ||
469 | err = -ENOMEM; | ||
470 | goto err_close; | ||
471 | } | ||
472 | ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); | ||
473 | if (!ns->file_buf) { | ||
474 | NS_ERR("alloc_device: unable to allocate file buf\n"); | ||
475 | err = -ENOMEM; | ||
476 | goto err_free; | ||
477 | } | ||
478 | ns->cfile = cfile; | ||
479 | memset(ns->pages_written, 0, ns->geom.pgnum); | ||
480 | return 0; | ||
481 | } | ||
431 | 482 | ||
432 | ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); | 483 | ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); |
433 | if (!ns->pages) { | 484 | if (!ns->pages) { |
434 | NS_ERR("alloc_map: unable to allocate page array\n"); | 485 | NS_ERR("alloc_device: unable to allocate page array\n"); |
435 | return -ENOMEM; | 486 | return -ENOMEM; |
436 | } | 487 | } |
437 | for (i = 0; i < ns->geom.pgnum; i++) { | 488 | for (i = 0; i < ns->geom.pgnum; i++) { |
438 | ns->pages[i].byte = NULL; | 489 | ns->pages[i].byte = NULL; |
439 | } | 490 | } |
491 | ns->nand_pages_slab = kmem_cache_create("nandsim", | ||
492 | ns->geom.pgszoob, 0, 0, NULL); | ||
493 | if (!ns->nand_pages_slab) { | ||
494 | NS_ERR("cache_create: unable to create kmem_cache\n"); | ||
495 | return -ENOMEM; | ||
496 | } | ||
440 | 497 | ||
441 | return 0; | 498 | return 0; |
499 | |||
500 | err_free: | ||
501 | vfree(ns->pages_written); | ||
502 | err_close: | ||
503 | filp_close(cfile, NULL); | ||
504 | return err; | ||
442 | } | 505 | } |
443 | 506 | ||
444 | /* | 507 | /* |
@@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns) | |||
448 | { | 511 | { |
449 | int i; | 512 | int i; |
450 | 513 | ||
514 | if (ns->cfile) { | ||
515 | kfree(ns->file_buf); | ||
516 | vfree(ns->pages_written); | ||
517 | filp_close(ns->cfile, NULL); | ||
518 | return; | ||
519 | } | ||
520 | |||
451 | if (ns->pages) { | 521 | if (ns->pages) { |
452 | for (i = 0; i < ns->geom.pgnum; i++) { | 522 | for (i = 0; i < ns->geom.pgnum; i++) { |
453 | if (ns->pages[i].byte) | 523 | if (ns->pages[i].byte) |
454 | kfree(ns->pages[i].byte); | 524 | kmem_cache_free(ns->nand_pages_slab, |
525 | ns->pages[i].byte); | ||
455 | } | 526 | } |
527 | kmem_cache_destroy(ns->nand_pages_slab); | ||
456 | vfree(ns->pages); | 528 | vfree(ns->pages); |
457 | } | 529 | } |
458 | } | 530 | } |
@@ -464,7 +536,7 @@ static char *get_partition_name(int i) | |||
464 | return kstrdup(buf, GFP_KERNEL); | 536 | return kstrdup(buf, GFP_KERNEL); |
465 | } | 537 | } |
466 | 538 | ||
467 | static u_int64_t divide(u_int64_t n, u_int32_t d) | 539 | static uint64_t divide(uint64_t n, uint32_t d) |
468 | { | 540 | { |
469 | do_div(n, d); | 541 | do_div(n, d); |
470 | return n; | 542 | return n; |
@@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
480 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 552 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
481 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 553 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
482 | int i, ret = 0; | 554 | int i, ret = 0; |
483 | u_int64_t remains; | 555 | uint64_t remains; |
484 | u_int64_t next_offset; | 556 | uint64_t next_offset; |
485 | 557 | ||
486 | if (NS_IS_INITIALIZED(ns)) { | 558 | if (NS_IS_INITIALIZED(ns)) { |
487 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 559 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
548 | remains = ns->geom.totsz; | 620 | remains = ns->geom.totsz; |
549 | next_offset = 0; | 621 | next_offset = 0; |
550 | for (i = 0; i < parts_num; ++i) { | 622 | for (i = 0; i < parts_num; ++i) { |
551 | u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; | 623 | uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz; |
552 | 624 | ||
553 | if (!part_sz || part_sz > remains) { | 625 | if (!part_sz || part_sz > remains) { |
554 | NS_ERR("bad partition size.\n"); | 626 | NS_ERR("bad partition size.\n"); |
@@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag) | |||
1211 | return -1; | 1283 | return -1; |
1212 | } | 1284 | } |
1213 | 1285 | ||
1286 | static void put_pages(struct nandsim *ns) | ||
1287 | { | ||
1288 | int i; | ||
1289 | |||
1290 | for (i = 0; i < ns->held_cnt; i++) | ||
1291 | page_cache_release(ns->held_pages[i]); | ||
1292 | } | ||
1293 | |||
1294 | /* Get page cache pages in advance to provide NOFS memory allocation */ | ||
1295 | static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) | ||
1296 | { | ||
1297 | pgoff_t index, start_index, end_index; | ||
1298 | struct page *page; | ||
1299 | struct address_space *mapping = file->f_mapping; | ||
1300 | |||
1301 | start_index = pos >> PAGE_CACHE_SHIFT; | ||
1302 | end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT; | ||
1303 | if (end_index - start_index + 1 > NS_MAX_HELD_PAGES) | ||
1304 | return -EINVAL; | ||
1305 | ns->held_cnt = 0; | ||
1306 | for (index = start_index; index <= end_index; index++) { | ||
1307 | page = find_get_page(mapping, index); | ||
1308 | if (page == NULL) { | ||
1309 | page = find_or_create_page(mapping, index, GFP_NOFS); | ||
1310 | if (page == NULL) { | ||
1311 | write_inode_now(mapping->host, 1); | ||
1312 | page = find_or_create_page(mapping, index, GFP_NOFS); | ||
1313 | } | ||
1314 | if (page == NULL) { | ||
1315 | put_pages(ns); | ||
1316 | return -ENOMEM; | ||
1317 | } | ||
1318 | unlock_page(page); | ||
1319 | } | ||
1320 | ns->held_pages[ns->held_cnt++] = page; | ||
1321 | } | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | static int set_memalloc(void) | ||
1326 | { | ||
1327 | if (current->flags & PF_MEMALLOC) | ||
1328 | return 0; | ||
1329 | current->flags |= PF_MEMALLOC; | ||
1330 | return 1; | ||
1331 | } | ||
1332 | |||
1333 | static void clear_memalloc(int memalloc) | ||
1334 | { | ||
1335 | if (memalloc) | ||
1336 | current->flags &= ~PF_MEMALLOC; | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) | ||
1340 | { | ||
1341 | mm_segment_t old_fs; | ||
1342 | ssize_t tx; | ||
1343 | int err, memalloc; | ||
1344 | |||
1345 | err = get_pages(ns, file, count, *pos); | ||
1346 | if (err) | ||
1347 | return err; | ||
1348 | old_fs = get_fs(); | ||
1349 | set_fs(get_ds()); | ||
1350 | memalloc = set_memalloc(); | ||
1351 | tx = vfs_read(file, (char __user *)buf, count, pos); | ||
1352 | clear_memalloc(memalloc); | ||
1353 | set_fs(old_fs); | ||
1354 | put_pages(ns); | ||
1355 | return tx; | ||
1356 | } | ||
1357 | |||
1358 | static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) | ||
1359 | { | ||
1360 | mm_segment_t old_fs; | ||
1361 | ssize_t tx; | ||
1362 | int err, memalloc; | ||
1363 | |||
1364 | err = get_pages(ns, file, count, *pos); | ||
1365 | if (err) | ||
1366 | return err; | ||
1367 | old_fs = get_fs(); | ||
1368 | set_fs(get_ds()); | ||
1369 | memalloc = set_memalloc(); | ||
1370 | tx = vfs_write(file, (char __user *)buf, count, pos); | ||
1371 | clear_memalloc(memalloc); | ||
1372 | set_fs(old_fs); | ||
1373 | put_pages(ns); | ||
1374 | return tx; | ||
1375 | } | ||
1376 | |||
1214 | /* | 1377 | /* |
1215 | * Returns a pointer to the current page. | 1378 | * Returns a pointer to the current page. |
1216 | */ | 1379 | */ |
@@ -1227,6 +1390,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; | 1390 | return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; |
1228 | } | 1391 | } |
1229 | 1392 | ||
1393 | int do_read_error(struct nandsim *ns, int num) | ||
1394 | { | ||
1395 | unsigned int page_no = ns->regs.row; | ||
1396 | |||
1397 | if (read_error(page_no)) { | ||
1398 | int i; | ||
1399 | memset(ns->buf.byte, 0xFF, num); | ||
1400 | for (i = 0; i < num; ++i) | ||
1401 | ns->buf.byte[i] = random32(); | ||
1402 | NS_WARN("simulating read error in page %u\n", page_no); | ||
1403 | return 1; | ||
1404 | } | ||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | void do_bit_flips(struct nandsim *ns, int num) | ||
1409 | { | ||
1410 | if (bitflips && random32() < (1 << 22)) { | ||
1411 | int flips = 1; | ||
1412 | if (bitflips > 1) | ||
1413 | flips = (random32() % (int) bitflips) + 1; | ||
1414 | while (flips--) { | ||
1415 | int pos = random32() % (num * 8); | ||
1416 | ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); | ||
1417 | NS_WARN("read_page: flipping bit %d in page %d " | ||
1418 | "reading from %d ecc: corrected=%u failed=%u\n", | ||
1419 | pos, ns->regs.row, ns->regs.column + ns->regs.off, | ||
1420 | nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); | ||
1421 | } | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1230 | /* | 1425 | /* |
1231 | * Fill the NAND buffer with data read from the specified page. | 1426 | * Fill the NAND buffer with data read from the specified page. |
1232 | */ | 1427 | */ |
@@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num) | |||
1234 | { | 1429 | { |
1235 | union ns_mem *mypage; | 1430 | union ns_mem *mypage; |
1236 | 1431 | ||
1432 | if (ns->cfile) { | ||
1433 | if (!ns->pages_written[ns->regs.row]) { | ||
1434 | NS_DBG("read_page: page %d not written\n", ns->regs.row); | ||
1435 | memset(ns->buf.byte, 0xFF, num); | ||
1436 | } else { | ||
1437 | loff_t pos; | ||
1438 | ssize_t tx; | ||
1439 | |||
1440 | NS_DBG("read_page: page %d written, reading from %d\n", | ||
1441 | ns->regs.row, ns->regs.column + ns->regs.off); | ||
1442 | if (do_read_error(ns, num)) | ||
1443 | return; | ||
1444 | pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; | ||
1445 | tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos); | ||
1446 | if (tx != num) { | ||
1447 | NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1448 | return; | ||
1449 | } | ||
1450 | do_bit_flips(ns, num); | ||
1451 | } | ||
1452 | return; | ||
1453 | } | ||
1454 | |||
1237 | mypage = NS_GET_PAGE(ns); | 1455 | mypage = NS_GET_PAGE(ns); |
1238 | if (mypage->byte == NULL) { | 1456 | if (mypage->byte == NULL) { |
1239 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); | 1457 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); |
1240 | memset(ns->buf.byte, 0xFF, num); | 1458 | memset(ns->buf.byte, 0xFF, num); |
1241 | } else { | 1459 | } else { |
1242 | unsigned int page_no = ns->regs.row; | ||
1243 | NS_DBG("read_page: page %d allocated, reading from %d\n", | 1460 | NS_DBG("read_page: page %d allocated, reading from %d\n", |
1244 | ns->regs.row, ns->regs.column + ns->regs.off); | 1461 | ns->regs.row, ns->regs.column + ns->regs.off); |
1245 | if (read_error(page_no)) { | 1462 | 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; | 1463 | return; |
1252 | } | ||
1253 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); | 1464 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); |
1254 | if (bitflips && random32() < (1 << 22)) { | 1465 | 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 | } | 1466 | } |
1268 | } | 1467 | } |
1269 | 1468 | ||
@@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns) | |||
1275 | union ns_mem *mypage; | 1474 | union ns_mem *mypage; |
1276 | int i; | 1475 | int i; |
1277 | 1476 | ||
1477 | if (ns->cfile) { | ||
1478 | for (i = 0; i < ns->geom.pgsec; i++) | ||
1479 | if (ns->pages_written[ns->regs.row + i]) { | ||
1480 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); | ||
1481 | ns->pages_written[ns->regs.row + i] = 0; | ||
1482 | } | ||
1483 | return; | ||
1484 | } | ||
1485 | |||
1278 | mypage = NS_GET_PAGE(ns); | 1486 | mypage = NS_GET_PAGE(ns); |
1279 | for (i = 0; i < ns->geom.pgsec; i++) { | 1487 | for (i = 0; i < ns->geom.pgsec; i++) { |
1280 | if (mypage->byte != NULL) { | 1488 | if (mypage->byte != NULL) { |
1281 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); | 1489 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); |
1282 | kfree(mypage->byte); | 1490 | kmem_cache_free(ns->nand_pages_slab, mypage->byte); |
1283 | mypage->byte = NULL; | 1491 | mypage->byte = NULL; |
1284 | } | 1492 | } |
1285 | mypage++; | 1493 | mypage++; |
@@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num) | |||
1295 | union ns_mem *mypage; | 1503 | union ns_mem *mypage; |
1296 | u_char *pg_off; | 1504 | u_char *pg_off; |
1297 | 1505 | ||
1506 | if (ns->cfile) { | ||
1507 | loff_t off, pos; | ||
1508 | ssize_t tx; | ||
1509 | int all; | ||
1510 | |||
1511 | NS_DBG("prog_page: writing page %d\n", ns->regs.row); | ||
1512 | pg_off = ns->file_buf + ns->regs.column + ns->regs.off; | ||
1513 | off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; | ||
1514 | if (!ns->pages_written[ns->regs.row]) { | ||
1515 | all = 1; | ||
1516 | memset(ns->file_buf, 0xff, ns->geom.pgszoob); | ||
1517 | } else { | ||
1518 | all = 0; | ||
1519 | pos = off; | ||
1520 | tx = read_file(ns, ns->cfile, pg_off, num, &pos); | ||
1521 | if (tx != num) { | ||
1522 | NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1523 | return -1; | ||
1524 | } | ||
1525 | } | ||
1526 | for (i = 0; i < num; i++) | ||
1527 | pg_off[i] &= ns->buf.byte[i]; | ||
1528 | if (all) { | ||
1529 | pos = (loff_t)ns->regs.row * ns->geom.pgszoob; | ||
1530 | tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); | ||
1531 | if (tx != ns->geom.pgszoob) { | ||
1532 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1533 | return -1; | ||
1534 | } | ||
1535 | ns->pages_written[ns->regs.row] = 1; | ||
1536 | } else { | ||
1537 | pos = off; | ||
1538 | tx = write_file(ns, ns->cfile, pg_off, num, &pos); | ||
1539 | if (tx != num) { | ||
1540 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1541 | return -1; | ||
1542 | } | ||
1543 | } | ||
1544 | return 0; | ||
1545 | } | ||
1546 | |||
1298 | mypage = NS_GET_PAGE(ns); | 1547 | mypage = NS_GET_PAGE(ns); |
1299 | if (mypage->byte == NULL) { | 1548 | if (mypage->byte == NULL) { |
1300 | NS_DBG("prog_page: allocating page %d\n", ns->regs.row); | 1549 | NS_DBG("prog_page: allocating page %d\n", ns->regs.row); |
1301 | /* | 1550 | /* |
1302 | * We allocate memory with GFP_NOFS because a flash FS may | 1551 | * We allocate memory with GFP_NOFS because a flash FS may |
1303 | * utilize this. If it is holding an FS lock, then gets here, | 1552 | * utilize this. If it is holding an FS lock, then gets here, |
1304 | * then kmalloc runs writeback which goes to the FS again | 1553 | * then kernel memory alloc runs writeback which goes to the FS |
1305 | * and deadlocks. This was seen in practice. | 1554 | * again and deadlocks. This was seen in practice. |
1306 | */ | 1555 | */ |
1307 | mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); | 1556 | mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS); |
1308 | if (mypage->byte == NULL) { | 1557 | if (mypage->byte == NULL) { |
1309 | NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); | 1558 | NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); |
1310 | return -1; | 1559 | return -1; |
@@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1736 | 1985 | ||
1737 | /* Check if chip is expecting command */ | 1986 | /* Check if chip is expecting command */ |
1738 | if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { | 1987 | if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { |
1739 | /* | 1988 | /* Do not warn if only 2 id bytes are read */ |
1740 | * We are in situation when something else (not command) | 1989 | if (!(ns->regs.command == NAND_CMD_READID && |
1741 | * was expected but command was input. In this case ignore | 1990 | NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) { |
1742 | * previous command(s)/state(s) and accept the last one. | 1991 | /* |
1743 | */ | 1992 | * We are in situation when something else (not command) |
1744 | NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " | 1993 | * was expected but command was input. In this case ignore |
1745 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | 1994 | * previous command(s)/state(s) and accept the last one. |
1995 | */ | ||
1996 | NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " | ||
1997 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | ||
1998 | } | ||
1746 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1999 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1747 | } | 2000 | } |
1748 | 2001 | ||
@@ -2044,7 +2297,7 @@ static int __init ns_init_module(void) | |||
2044 | } | 2297 | } |
2045 | 2298 | ||
2046 | if (overridesize) { | 2299 | if (overridesize) { |
2047 | u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; | 2300 | uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; |
2048 | if (new_size >> overridesize != nsmtd->erasesize) { | 2301 | if (new_size >> overridesize != nsmtd->erasesize) { |
2049 | NS_ERR("overridesize is too big\n"); | 2302 | NS_ERR("overridesize is too big\n"); |
2050 | goto err_exit; | 2303 | goto err_exit; |