diff options
author | Adrian Hunter <ext-adrian.hunter@nokia.com> | 2008-11-12 09:06:07 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-12-10 08:35:21 -0500 |
commit | a9fc8991883cdf029bd373a82cbc2d12a10799dd (patch) | |
tree | c695dd7928354028733f9621ba67a592d2b1c5ed /drivers/mtd/nand/nandsim.c | |
parent | 9359ea461b382de3249469d2165da45f4762b910 (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.c | 285 |
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; | |||
100 | static char *gravepages = NULL; | 102 | static char *gravepages = NULL; |
101 | static unsigned int rptwear = 0; | 103 | static unsigned int rptwear = 0; |
102 | static unsigned int overridesize = 0; | 104 | static unsigned int overridesize = 0; |
105 | static char *cache_file = NULL; | ||
103 | 106 | ||
104 | module_param(first_id_byte, uint, 0400); | 107 | module_param(first_id_byte, uint, 0400); |
105 | module_param(second_id_byte, uint, 0400); | 108 | module_param(second_id_byte, uint, 0400); |
@@ -122,12 +125,13 @@ module_param(bitflips, uint, 0400); | |||
122 | module_param(gravepages, charp, 0400); | 125 | module_param(gravepages, charp, 0400); |
123 | module_param(rptwear, uint, 0400); | 126 | module_param(rptwear, uint, 0400); |
124 | module_param(overridesize, uint, 0400); | 127 | module_param(overridesize, uint, 0400); |
128 | module_param(cache_file, charp, 0400); | ||
125 | 129 | ||
126 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | 130 | 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)"); | 131 | 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"); | 132 | 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"); | 133 | 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)"); | 134 | MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); |
131 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); | 135 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); |
132 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); | 136 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); |
133 | MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); | 137 | MODULE_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 | |||
153 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | 157 | 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" | 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"); |
160 | MODULE_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 | */ |
428 | static int alloc_device(struct nandsim *ns) | 443 | static 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 | |||
490 | err_free: | ||
491 | vfree(ns->pages_written); | ||
492 | err_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 | ||
1274 | static 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 */ | ||
1283 | static 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 | |||
1313 | static int set_memalloc(void) | ||
1314 | { | ||
1315 | if (current->flags & PF_MEMALLOC) | ||
1316 | return 0; | ||
1317 | current->flags |= PF_MEMALLOC; | ||
1318 | return 1; | ||
1319 | } | ||
1320 | |||
1321 | static void clear_memalloc(int memalloc) | ||
1322 | { | ||
1323 | if (memalloc) | ||
1324 | current->flags &= ~PF_MEMALLOC; | ||
1325 | } | ||
1326 | |||
1327 | static 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 | |||
1346 | static 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 | ||
1381 | int 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 | |||
1396 | void 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); |