* [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips
@ 2015-08-05 8:55 Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 1/5] MTD: nandsim: add numchips module parameter Sheng Yong
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
Hi, folks,
These patchset add a new module parameter, numchips, to supports to
simulate NAND flash with multiple chips.
This simulation helps to test and improve generic NAND driver on
multiple chips NAND flash.
MTD test (except for mtd_nandbiterr) are passed.
Thanks,
Sheng
Sheng Yong (5):
MTD: nandsim: add numchips module parameter
MTD: nandsim: fix column address size of large page
MTD: nandsim: fix page address size
MTD: nandsim: add ADJUST_ROW() to find the real page number
MTD: nandsim: extent outprint messages
drivers/mtd/nand/nandsim.c | 632 +++++++++++++++++++++++++++------------------
1 file changed, 377 insertions(+), 255 deletions(-)
--
1.8.3.4
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 1/5] MTD: nandsim: add numchips module parameter
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
@ 2015-08-05 8:55 ` Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 2/5] MTD: nandsim: fix column address size of large page Sheng Yong
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
Some NAND flash consists of multiple chips. numchips supports to simulate
linear chip array.
numchips indicates how many chips are concatenated in the NAND flash. For
now, it supports to simulate up to 16 chips, and 1 chip by default.
In order to simulate multi-chips, we:
* separate the definition of regs and lines from struct nandsim, so that
each chip could have its own virtual regsiters and pins.
* add a select_chip function to (de)select the request chip.
* change the maxchip parameter of nand_scan_ident() to scan all chips.
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
---
drivers/mtd/nand/nandsim.c | 409 +++++++++++++++++++++++++++------------------
1 file changed, 242 insertions(+), 167 deletions(-)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 95d0cc4..24a50e5 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -107,6 +107,7 @@ static unsigned int overridesize = 0;
static char *cache_file = NULL;
static unsigned int bbt;
static unsigned int bch;
+static unsigned int numchips = 1;
static u_char id_bytes[8] = {
[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
@@ -139,6 +140,7 @@ module_param(overridesize, uint, 0400);
module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400);
module_param(bch, uint, 0400);
+module_param(numchips, uint, 0400);
MODULE_PARM_DESC(id_bytes, "The ID bytes returned by NAND Flash 'read ID' command");
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
@@ -174,6 +176,7 @@ MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of mem
MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
"be correctable in 512-byte blocks");
+MODULE_PARM_DESC(numchips, "Number of chips of the NAND flash (1 by default)");
/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE 4096
@@ -203,14 +206,14 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
/* Good operation completion status */
-#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
+#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines->wp == 0)))
/* Operation failed completion status */
#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
/* Calculate the page offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET(ns) \
- (((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
+ (((ns)->regs->row * (ns)->geom.pgszoob) + (ns)->regs->column)
/* Calculate the OOB offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
@@ -273,6 +276,8 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE512) /* 512-byte page chips */
+#define NS_MAX_NUM_CHIP 16
+
/* Remove action bits from state */
#define NS_STATE(x) ((x) & ~ACTION_MASK)
@@ -299,6 +304,27 @@ union ns_mem {
uint16_t *word; /* for 16-bit word access */
};
+/* NAND flash internal registers */
+struct ns_regs {
+ unsigned command; /* the command register */
+ u_char status; /* the status register */
+ uint row; /* the page number */
+ uint column; /* the offset within page */
+ uint count; /* internal counter */
+ uint num; /* number of bytes which must be processed */
+ uint off; /* fixed page offset */
+};
+struct ns_regs *ns_regs;
+
+/* NAND flash lines state */
+struct ns_lines {
+ int ce; /* chip Enable */
+ int cle; /* command Latch Enable */
+ int ale; /* address Latch Enable */
+ int wp; /* write Protect */
+};
+struct ns_lines *ns_lines;
+
/*
* The structure which describes all the internal simulator data.
*/
@@ -326,6 +352,10 @@ struct nandsim {
/* Internal buffer of page + OOB size bytes */
union ns_mem buf;
+ /* Which chip is selected, protected by sel_lock */
+ spinlock_t sel_lock;
+ int chipselect;
+
/* NAND flash "geometry" */
struct {
uint64_t totsz; /* total flash size, bytes */
@@ -342,26 +372,12 @@ struct nandsim {
uint pgaddrbytes; /* bytes per page address */
uint secaddrbytes; /* bytes per sector address */
uint idbytes; /* the number ID bytes that this chip outputs */
+ uint numchips; /* the number of avaliable chips */
} geom;
- /* NAND flash internal registers */
- struct {
- unsigned command; /* the command register */
- u_char status; /* the status register */
- uint row; /* the page number */
- uint column; /* the offset within page */
- uint count; /* internal counter */
- uint num; /* number of bytes which must be processed */
- uint off; /* fixed page offset */
- } regs;
-
- /* NAND flash lines state */
- struct {
- int ce; /* chip Enable */
- int cle; /* command Latch Enable */
- int ale; /* address Latch Enable */
- int wp; /* write Protect */
- } lines;
+ /* regs and lines selected */
+ struct ns_regs *regs;
+ struct ns_lines *lines;
/* Fields needed when using a cache file */
struct file *cfile; /* Open file */
@@ -694,6 +710,7 @@ static int init_nandsim(struct mtd_info *mtd)
ns->geom.pgshift = chip->page_shift;
ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz;
ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
+ ns->geom.numchips = chip->numchips;
ns->options = 0;
if (ns->geom.pgsz == 512) {
@@ -772,6 +789,7 @@ static int init_nandsim(struct mtd_info *mtd)
printk("flash size: %llu MiB\n",
(unsigned long long)ns->geom.totsz >> 20);
+ printk("chip number: %d\n", ns->geom.numchips);
printk("page size: %u bytes\n", ns->geom.pgsz);
printk("OOB area size: %u bytes\n", ns->geom.oobsz);
printk("sector size: %u KiB\n", ns->geom.secsz >> 10);
@@ -1178,10 +1196,10 @@ static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
{
uint byte = (uint)bt;
- if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
- ns->regs.column |= (byte << 8 * ns->regs.count);
+ if (ns->regs->count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
+ ns->regs->column |= (byte << 8 * ns->regs->count);
else {
- ns->regs.row |= (byte << 8 * (ns->regs.count -
+ ns->regs->row |= (byte << 8 * (ns->regs->count -
ns->geom.pgaddrbytes +
ns->geom.secaddrbytes));
}
@@ -1196,17 +1214,17 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
{
NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
- ns->state = STATE_READY;
- ns->nxstate = STATE_UNKNOWN;
- ns->op = NULL;
- ns->npstates = 0;
- ns->stateidx = 0;
- ns->regs.num = 0;
- ns->regs.count = 0;
- ns->regs.off = 0;
- ns->regs.row = 0;
- ns->regs.column = 0;
- ns->regs.status = status;
+ ns->state = STATE_READY;
+ ns->nxstate = STATE_UNKNOWN;
+ ns->op = NULL;
+ ns->npstates = 0;
+ ns->stateidx = 0;
+ ns->regs->num = 0;
+ ns->regs->count = 0;
+ ns->regs->off = 0;
+ ns->regs->row = 0;
+ ns->regs->column = 0;
+ ns->regs->status = status;
}
/*
@@ -1423,7 +1441,7 @@ static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size
*/
static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
{
- return &(ns->pages[ns->regs.row]);
+ return &(ns->pages[ns->regs->row]);
}
/*
@@ -1431,12 +1449,12 @@ static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
*/
static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
{
- return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
+ return NS_GET_PAGE(ns)->byte + ns->regs->column + ns->regs->off;
}
static int do_read_error(struct nandsim *ns, int num)
{
- unsigned int page_no = ns->regs.row;
+ unsigned int page_no = ns->regs->row;
if (read_error(page_no)) {
prandom_bytes(ns->buf.byte, num);
@@ -1457,7 +1475,7 @@ static void do_bit_flips(struct nandsim *ns, int num)
ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
NS_WARN("read_page: flipping bit %d in page %d "
"reading from %d ecc: corrected=%u failed=%u\n",
- pos, ns->regs.row, ns->regs.column + ns->regs.off,
+ pos, ns->regs->row, ns->regs->column + ns->regs->off,
nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
}
}
@@ -1471,21 +1489,21 @@ static void read_page(struct nandsim *ns, int num)
union ns_mem *mypage;
if (ns->cfile) {
- if (!test_bit(ns->regs.row, ns->pages_written)) {
- NS_DBG("read_page: page %d not written\n", ns->regs.row);
+ if (!test_bit(ns->regs->row, ns->pages_written)) {
+ NS_DBG("read_page: page %d not written\n", ns->regs->row);
memset(ns->buf.byte, 0xFF, num);
} else {
loff_t pos;
ssize_t tx;
NS_DBG("read_page: page %d written, reading from %d\n",
- ns->regs.row, ns->regs.column + ns->regs.off);
+ ns->regs->row, ns->regs->column + ns->regs->off);
if (do_read_error(ns, num))
return;
- pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+ pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs->off;
tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
if (tx != num) {
- NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs->row, (long)tx);
return;
}
do_bit_flips(ns, num);
@@ -1495,11 +1513,11 @@ static void read_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
- NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+ NS_DBG("read_page: page %d not allocated\n", ns->regs->row);
memset(ns->buf.byte, 0xFF, num);
} else {
NS_DBG("read_page: page %d allocated, reading from %d\n",
- ns->regs.row, ns->regs.column + ns->regs.off);
+ ns->regs->row, ns->regs->column + ns->regs->off);
if (do_read_error(ns, num))
return;
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
@@ -1517,9 +1535,9 @@ static void erase_sector(struct nandsim *ns)
if (ns->cfile) {
for (i = 0; i < ns->geom.pgsec; i++)
- if (__test_and_clear_bit(ns->regs.row + i,
+ if (__test_and_clear_bit(ns->regs->row + i,
ns->pages_written)) {
- NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
+ NS_DBG("erase_sector: freeing page %d\n", ns->regs->row + i);
}
return;
}
@@ -1527,7 +1545,7 @@ static void erase_sector(struct nandsim *ns)
mypage = NS_GET_PAGE(ns);
for (i = 0; i < ns->geom.pgsec; i++) {
if (mypage->byte != NULL) {
- NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
+ NS_DBG("erase_sector: freeing page %d\n", ns->regs->row+i);
kmem_cache_free(ns->nand_pages_slab, mypage->byte);
mypage->byte = NULL;
}
@@ -1549,34 +1567,34 @@ static int prog_page(struct nandsim *ns, int num)
ssize_t tx;
int all;
- NS_DBG("prog_page: writing page %d\n", ns->regs.row);
- pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
- off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
- if (!test_bit(ns->regs.row, ns->pages_written)) {
+ NS_DBG("prog_page: writing page %d\n", ns->regs->row);
+ pg_off = ns->file_buf + ns->regs->column + ns->regs->off;
+ off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs->off;
+ if (!test_bit(ns->regs->row, ns->pages_written)) {
all = 1;
memset(ns->file_buf, 0xff, ns->geom.pgszoob);
} else {
all = 0;
tx = read_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) {
- NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
}
for (i = 0; i < num; i++)
pg_off[i] &= ns->buf.byte[i];
if (all) {
- loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
+ loff_t pos = (loff_t)ns->regs->row * ns->geom.pgszoob;
tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
if (tx != ns->geom.pgszoob) {
- NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
- __set_bit(ns->regs.row, ns->pages_written);
+ __set_bit(ns->regs->row, ns->pages_written);
} else {
tx = write_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) {
- NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
}
@@ -1585,7 +1603,7 @@ static int prog_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
- NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+ NS_DBG("prog_page: allocating page %d\n", ns->regs->row);
/*
* We allocate memory with GFP_NOFS because a flash FS may
* utilize this. If it is holding an FS lock, then gets here,
@@ -1594,7 +1612,7 @@ static int prog_page(struct nandsim *ns, int num)
*/
mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
if (mypage->byte == NULL) {
- NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
+ NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs->row);
return -1;
}
memset(mypage->byte, 0xFF, ns->geom.pgszoob);
@@ -1621,8 +1639,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
action &= ACTION_MASK;
/* Check that page address input is correct */
- if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
- NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
+ if (action != ACTION_SECERASE && ns->regs->row >= ns->geom.pgnum) {
+ NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs->row);
return -1;
}
@@ -1634,22 +1652,22 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
*/
/* Column shouldn't be very large */
- if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
+ if (ns->regs->column >= (ns->geom.pgszoob - ns->regs->off)) {
NS_ERR("do_state_action: column number is too large\n");
break;
}
- num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+ num = ns->geom.pgszoob - ns->regs->off - ns->regs->column;
read_page(ns, num);
NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
- num, NS_RAW_OFFSET(ns) + ns->regs.off);
+ num, NS_RAW_OFFSET(ns) + ns->regs->off);
- if (ns->regs.off == 0)
- NS_LOG("read page %d\n", ns->regs.row);
- else if (ns->regs.off < ns->geom.pgsz)
- NS_LOG("read page %d (second half)\n", ns->regs.row);
+ if (ns->regs->off == 0)
+ NS_LOG("read page %d\n", ns->regs->row);
+ else if (ns->regs->off < ns->geom.pgsz)
+ NS_LOG("read page %d (second half)\n", ns->regs->row);
else
- NS_LOG("read OOB of page %d\n", ns->regs.row);
+ NS_LOG("read OOB of page %d\n", ns->regs->row);
NS_UDELAY(access_delay);
NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
@@ -1661,25 +1679,25 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
* Erase sector.
*/
- if (ns->lines.wp) {
+ if (ns->lines->wp) {
NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
return -1;
}
- if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
- || (ns->regs.row & ~(ns->geom.secsz - 1))) {
- NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
+ if (ns->regs->row >= ns->geom.pgnum - ns->geom.pgsec
+ || (ns->regs->row & ~(ns->geom.secsz - 1))) {
+ NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs->row);
return -1;
}
- ns->regs.row = (ns->regs.row <<
- 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
- ns->regs.column = 0;
+ ns->regs->row = (ns->regs->row <<
+ 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs->column;
+ ns->regs->column = 0;
- erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
+ erase_block_no = ns->regs->row >> (ns->geom.secshift - ns->geom.pgshift);
NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
- ns->regs.row, NS_RAW_OFFSET(ns));
+ ns->regs->row, NS_RAW_OFFSET(ns));
NS_LOG("erase sector %u\n", erase_block_no);
erase_sector(ns);
@@ -1701,26 +1719,26 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
* Program page - move internal buffer data to the page.
*/
- if (ns->lines.wp) {
+ if (ns->lines->wp) {
NS_WARN("do_state_action: device is write-protected, programm\n");
return -1;
}
- num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
- if (num != ns->regs.count) {
+ num = ns->geom.pgszoob - ns->regs->off - ns->regs->column;
+ if (num != ns->regs->count) {
NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
- ns->regs.count, num);
+ ns->regs->count, num);
return -1;
}
if (prog_page(ns, num) == -1)
return -1;
- page_no = ns->regs.row;
+ page_no = ns->regs->row;
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
- num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
- NS_LOG("programm page %d\n", ns->regs.row);
+ num, ns->regs->row, ns->regs->column, NS_RAW_OFFSET(ns) + ns->regs->off);
+ NS_LOG("programm page %d\n", ns->regs->row);
NS_UDELAY(programm_delay);
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
@@ -1734,7 +1752,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
case ACTION_ZEROOFF:
NS_DBG("do_state_action: set internal offset to 0\n");
- ns->regs.off = 0;
+ ns->regs->off = 0;
break;
case ACTION_HALFOFF:
@@ -1744,12 +1762,12 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
return -1;
}
NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
- ns->regs.off = ns->geom.pgsz/2;
+ ns->regs->off = ns->geom.pgsz/2;
break;
case ACTION_OOBOFF:
NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
- ns->regs.off = ns->geom.pgsz;
+ ns->regs->off = ns->geom.pgsz;
break;
default:
@@ -1794,7 +1812,7 @@ static void switch_state(struct nandsim *ns)
* The only event causing the switch_state function to
* be called with yet unknown operation is new command.
*/
- ns->state = get_state_by_command(ns->regs.command);
+ ns->state = get_state_by_command(ns->regs->command);
NS_DBG("switch_state: operation is unknown, try to find it\n");
@@ -1810,7 +1828,7 @@ static void switch_state(struct nandsim *ns)
/* For 16x devices column means the page offset in words */
if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
NS_DBG("switch_state: double the column number for 16x device\n");
- ns->regs.column <<= 1;
+ ns->regs->column <<= 1;
}
if (NS_STATE(ns->nxstate) == STATE_READY) {
@@ -1822,9 +1840,9 @@ static void switch_state(struct nandsim *ns)
/* In case of data states, see if all bytes were input/output */
if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
- && ns->regs.count != ns->regs.num) {
+ && ns->regs->count != ns->regs->num) {
NS_WARN("switch_state: not all bytes were processed, %d left\n",
- ns->regs.num - ns->regs.count);
+ ns->regs->num - ns->regs->count);
status = NS_STATUS_FAILED(ns);
}
@@ -1840,7 +1858,7 @@ static void switch_state(struct nandsim *ns)
ns->state = ns->nxstate;
ns->nxstate = ns->op[++ns->stateidx + 1];
- ns->regs.num = ns->regs.count = 0;
+ ns->regs->num = ns->regs->count = 0;
NS_DBG("switch_state: the next state is data I/O, switch, "
"state: %s, nxstate: %s\n",
@@ -1853,15 +1871,15 @@ static void switch_state(struct nandsim *ns)
switch (NS_STATE(ns->state)) {
case STATE_DATAIN:
case STATE_DATAOUT:
- ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+ ns->regs->num = ns->geom.pgszoob - ns->regs->off - ns->regs->column;
break;
case STATE_DATAOUT_ID:
- ns->regs.num = ns->geom.idbytes;
+ ns->regs->num = ns->geom.idbytes;
break;
case STATE_DATAOUT_STATUS:
- ns->regs.count = ns->regs.num = 0;
+ ns->regs->count = ns->regs->num = 0;
break;
default:
@@ -1874,24 +1892,24 @@ static void switch_state(struct nandsim *ns)
* register to the number of expected address bytes
*/
- ns->regs.count = 0;
+ ns->regs->count = 0;
switch (NS_STATE(ns->nxstate)) {
case STATE_ADDR_PAGE:
- ns->regs.num = ns->geom.pgaddrbytes;
+ ns->regs->num = ns->geom.pgaddrbytes;
break;
case STATE_ADDR_SEC:
- ns->regs.num = ns->geom.secaddrbytes;
+ ns->regs->num = ns->geom.secaddrbytes;
break;
case STATE_ADDR_ZERO:
- ns->regs.num = 1;
+ ns->regs->num = 1;
break;
case STATE_ADDR_COLUMN:
/* Column address is always 2 bytes */
- ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
+ ns->regs->num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes;
break;
default:
@@ -1902,8 +1920,8 @@ static void switch_state(struct nandsim *ns)
* Just reset internal counters.
*/
- ns->regs.num = 0;
- ns->regs.count = 0;
+ ns->regs->num = 0;
+ ns->regs->count = 0;
}
}
@@ -1913,11 +1931,11 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
u_char outb = 0x00;
/* Sanity and correctness checks */
- if (!ns->lines.ce) {
+ if (!ns->lines->ce) {
NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
return outb;
}
- if (ns->lines.ale || ns->lines.cle) {
+ if (ns->lines->ale || ns->lines->cle) {
NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
return outb;
}
@@ -1929,12 +1947,12 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
/* Status register may be read as many times as it is wanted */
if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
- NS_DBG("read_byte: return %#x status\n", ns->regs.status);
- return ns->regs.status;
+ NS_DBG("read_byte: return %#x status\n", ns->regs->status);
+ return ns->regs->status;
}
/* Check if there is any data in the internal buffer which may be read */
- if (ns->regs.count == ns->regs.num) {
+ if (ns->regs->count == ns->regs->num) {
NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
return outb;
}
@@ -1942,23 +1960,23 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
switch (NS_STATE(ns->state)) {
case STATE_DATAOUT:
if (ns->busw == 8) {
- outb = ns->buf.byte[ns->regs.count];
- ns->regs.count += 1;
+ outb = ns->buf.byte[ns->regs->count];
+ ns->regs->count += 1;
} else {
- outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
- ns->regs.count += 2;
+ outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs->count >> 1]);
+ ns->regs->count += 2;
}
break;
case STATE_DATAOUT_ID:
- NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
- outb = ns->ids[ns->regs.count];
- ns->regs.count += 1;
+ NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs->count, ns->regs->num);
+ outb = ns->ids[ns->regs->count];
+ ns->regs->count += 1;
break;
default:
BUG();
}
- if (ns->regs.count == ns->regs.num) {
+ if (ns->regs->count == ns->regs->num) {
NS_DBG("read_byte: all bytes were read\n");
if (NS_STATE(ns->nxstate) == STATE_READY)
@@ -1973,16 +1991,16 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
/* Sanity and correctness checks */
- if (!ns->lines.ce) {
+ if (!ns->lines->ce) {
NS_ERR("write_byte: chip is disabled, ignore write\n");
return;
}
- if (ns->lines.ale && ns->lines.cle) {
+ if (ns->lines->ale && ns->lines->cle) {
NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
return;
}
- if (ns->lines.cle == 1) {
+ if (ns->lines->cle == 1) {
/*
* The byte written is a command.
*/
@@ -2001,18 +2019,18 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
|| NS_STATE(ns->state) == STATE_DATAOUT) {
- int row = ns->regs.row;
+ int row = ns->regs->row;
switch_state(ns);
if (byte == NAND_CMD_RNDOUT)
- ns->regs.row = row;
+ ns->regs->row = row;
}
/* Check if chip is expecting command */
if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
/* Do not warn if only 2 id bytes are read */
- if (!(ns->regs.command == NAND_CMD_READID &&
- NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
+ if (!(ns->regs->command == NAND_CMD_READID &&
+ NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs->count == 2)) {
/*
* We are in situation when something else (not command)
* was expected but command was input. In this case ignore
@@ -2026,10 +2044,10 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
NS_DBG("command byte corresponding to %s state accepted\n",
get_state_name(get_state_by_command(byte)));
- ns->regs.command = byte;
+ ns->regs->command = byte;
switch_state(ns);
- } else if (ns->lines.ale == 1) {
+ } else if (ns->lines->ale == 1) {
/*
* The byte written is an address.
*/
@@ -2046,16 +2064,16 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
return;
}
- ns->regs.count = 0;
+ ns->regs->count = 0;
switch (NS_STATE(ns->nxstate)) {
case STATE_ADDR_PAGE:
- ns->regs.num = ns->geom.pgaddrbytes;
+ ns->regs->num = ns->geom.pgaddrbytes;
break;
case STATE_ADDR_SEC:
- ns->regs.num = ns->geom.secaddrbytes;
+ ns->regs->num = ns->geom.secaddrbytes;
break;
case STATE_ADDR_ZERO:
- ns->regs.num = 1;
+ ns->regs->num = 1;
break;
default:
BUG();
@@ -2071,7 +2089,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
}
/* Check if this is expected byte */
- if (ns->regs.count == ns->regs.num) {
+ if (ns->regs->count == ns->regs->num) {
NS_ERR("write_byte: no more address bytes expected\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
@@ -2079,13 +2097,13 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
accept_addr_byte(ns, byte);
- ns->regs.count += 1;
+ ns->regs->count += 1;
NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
- (uint)byte, ns->regs.count, ns->regs.num);
+ (uint)byte, ns->regs->count, ns->regs->num);
- if (ns->regs.count == ns->regs.num) {
- NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
+ if (ns->regs->count == ns->regs->num) {
+ NS_DBG("address (%#x, %#x) is accepted\n", ns->regs->row, ns->regs->column);
switch_state(ns);
}
@@ -2104,18 +2122,18 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
}
/* Check if this is expected byte */
- if (ns->regs.count == ns->regs.num) {
+ if (ns->regs->count == ns->regs->num) {
NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
- ns->regs.num);
+ ns->regs->num);
return;
}
if (ns->busw == 8) {
- ns->buf.byte[ns->regs.count] = byte;
- ns->regs.count += 1;
+ ns->buf.byte[ns->regs->count] = byte;
+ ns->regs->count += 1;
} else {
- ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
- ns->regs.count += 2;
+ ns->buf.word[ns->regs->count >> 1] = cpu_to_le16((uint16_t)byte);
+ ns->regs->count += 2;
}
}
@@ -2126,9 +2144,9 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
{
struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
- ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
- ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
- ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
+ ns->lines->cle = bitmask & NAND_CLE ? 1 : 0;
+ ns->lines->ale = bitmask & NAND_ALE ? 1 : 0;
+ ns->lines->ce = bitmask & NAND_NCE ? 1 : 0;
if (cmd != NAND_CMD_NONE)
ns_nand_write_byte(mtd, cmd);
@@ -2162,17 +2180,17 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
/* Check if these are expected bytes */
- if (ns->regs.count + len > ns->regs.num) {
+ if (ns->regs->count + len > ns->regs->num) {
NS_ERR("write_buf: too many input bytes\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
- memcpy(ns->buf.byte + ns->regs.count, buf, len);
- ns->regs.count += len;
+ memcpy(ns->buf.byte + ns->regs->count, buf, len);
+ ns->regs->count += len;
- if (ns->regs.count == ns->regs.num) {
- NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
+ if (ns->regs->count == ns->regs->num) {
+ NS_DBG("write_buf: %d bytes were written\n", ns->regs->count);
}
}
@@ -2181,11 +2199,11 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
/* Sanity and correctness checks */
- if (!ns->lines.ce) {
+ if (!ns->lines->ce) {
NS_ERR("read_buf: chip is disabled\n");
return;
}
- if (ns->lines.ale || ns->lines.cle) {
+ if (ns->lines->ale || ns->lines->cle) {
NS_ERR("read_buf: ALE or CLE pin is high\n");
return;
}
@@ -2205,16 +2223,16 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
/* Check if these are expected bytes */
- if (ns->regs.count + len > ns->regs.num) {
+ if (ns->regs->count + len > ns->regs->num) {
NS_ERR("read_buf: too many bytes to read\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
- memcpy(buf, ns->buf.byte + ns->regs.count, len);
- ns->regs.count += len;
+ memcpy(buf, ns->buf.byte + ns->regs->count, len);
+ ns->regs->count += len;
- if (ns->regs.count == ns->regs.num) {
+ if (ns->regs->count == ns->regs->num) {
if (NS_STATE(ns->nxstate) == STATE_READY)
switch_state(ns);
}
@@ -2222,6 +2240,38 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
+static void ns_select_chip(struct mtd_info *mtd, int chipselect)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nandsim *ns = chip->priv;
+ int i;
+
+ if (chipselect == -1) {
+ /* disable all chips */
+ for (i = 0; i < numchips; i++) {
+ ns_lines[i].ce = 0;
+ ns_lines[i].ale = 0;
+ ns_lines[i].cle = 0;
+ ns_regs[i].row = 0;
+ ns_regs[i].column = 0;
+ ns_regs[i].count = 0;
+ ns_regs[i].num = 0;
+ ns_regs[i].off = 0;
+ }
+ if (spin_is_locked(&ns->sel_lock))
+ spin_unlock(&ns->sel_lock);
+ } else if (chipselect >= 0 && chipselect < chip->numchips) {
+ spin_lock(&ns->sel_lock);
+ ns->chipselect = chipselect;
+ ns->regs = &ns_regs[ns->chipselect];
+ ns->lines = &ns_lines[ns->chipselect];
+ } else {
+ ns->chipselect = -1;
+ NS_ERR("chip %d not exist, max numchips is %d, avaliable numchips is %d\n",
+ chipselect, numchips, chip->numchips);
+ }
+}
+
/*
* Module initialization function
*/
@@ -2229,6 +2279,7 @@ static int __init ns_init_module(void)
{
struct nand_chip *chip;
struct nandsim *nand;
+ size_t size;
int retval = -ENOMEM, i;
if (bus_width != 8 && bus_width != 16) {
@@ -2236,9 +2287,17 @@ static int __init ns_init_module(void)
return -EINVAL;
}
+ if (numchips > NS_MAX_NUM_CHIP) {
+ NS_ERR("numchips %d is too large, the max value is %d\n",
+ numchips, NS_MAX_NUM_CHIP);
+ return -EINVAL;
+ }
+
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
- nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
- + sizeof(struct nandsim), GFP_KERNEL);
+ size = sizeof(struct mtd_info) + sizeof(struct nand_chip) +
+ sizeof(struct nandsim) + sizeof(struct ns_regs) * numchips +
+ sizeof(struct ns_lines) * numchips;
+ nsmtd = kzalloc(size, GFP_KERNEL);
if (!nsmtd) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
@@ -2247,20 +2306,25 @@ static int __init ns_init_module(void)
nsmtd->priv = (void *)chip;
nand = (struct nandsim *)(chip + 1);
chip->priv = (void *)nand;
+ ns_regs = (struct ns_regs *)(nand + 1);
+ ns_lines = (struct ns_lines *)(ns_regs + numchips);
+
+ spin_lock_init(&nand->sel_lock);
/*
* Register simulator's callbacks.
*/
- chip->cmd_ctrl = ns_hwcontrol;
- chip->read_byte = ns_nand_read_byte;
- chip->dev_ready = ns_device_ready;
- chip->write_buf = ns_nand_write_buf;
- chip->read_buf = ns_nand_read_buf;
- chip->read_word = ns_nand_read_word;
- chip->ecc.mode = NAND_ECC_SOFT;
+ chip->select_chip = ns_select_chip;
+ chip->cmd_ctrl = ns_hwcontrol;
+ chip->read_byte = ns_nand_read_byte;
+ chip->dev_ready = ns_device_ready;
+ chip->write_buf = ns_nand_write_buf;
+ chip->read_buf = ns_nand_read_buf;
+ chip->read_word = ns_nand_read_word;
+ chip->ecc.mode = NAND_ECC_SOFT;
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
/* and 'badblocks' parameters to work */
- chip->options |= NAND_SKIP_BBTSCAN;
+ chip->options |= NAND_SKIP_BBTSCAN;
switch (bbt) {
case 2:
@@ -2286,7 +2350,18 @@ static int __init ns_init_module(void)
nand->geom.idbytes = 4;
else
nand->geom.idbytes = 2;
- nand->regs.status = NS_STATUS_OK(nand);
+
+ /* init chip status */
+ /* XXX: chip->numchips will be init and overwrite when
+ * scan_nand_ident(). Here we init it temporarily, so that
+ * we can select the correct chip the first time select_chip
+ * is called.
+ */
+ chip->numchips = numchips;
+ nand->chipselect = 0;
+ for (i = 0; i < numchips; i++)
+ ns_regs[i].status = NAND_STATUS_READY;
+
nand->nxstate = STATE_UNKNOWN;
nand->options |= OPT_PAGE512; /* temporary value */
memcpy(nand->ids, id_bytes, sizeof(nand->ids));
@@ -2306,7 +2381,7 @@ static int __init ns_init_module(void)
if ((retval = parse_gravepages()) != 0)
goto error;
- retval = nand_scan_ident(nsmtd, 1, NULL);
+ retval = nand_scan_ident(nsmtd, numchips, NULL);
if (retval) {
NS_ERR("cannot scan NAND Simulator device\n");
if (retval > 0)
@@ -2358,7 +2433,7 @@ static int __init ns_init_module(void)
goto err_exit;
}
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
- nsmtd->size = new_size;
+ nsmtd->size = new_size * chip->numchips;
chip->chipsize = new_size;
chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
--
1.8.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 2/5] MTD: nandsim: fix column address size of large page
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 1/5] MTD: nandsim: add numchips module parameter Sheng Yong
@ 2015-08-05 8:55 ` Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 3/5] MTD: nandsim: fix page address size Sheng Yong
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
If NAND flash has large page, its default cmdfunc is changed to
nand_command_lp() during scanning. When READID command is send, nand
tries to write 2 bytes as column address, so we have to tell nandsim
to read one more byte.
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
---
drivers/mtd/nand/nandsim.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 24a50e5..5938be4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -238,7 +238,7 @@ MODULE_PARM_DESC(numchips, "Number of chips of the NAND flash (1 by default)");
#define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */
#define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */
#define STATE_ADDR_COLUMN 0x00000030 /* column address was accepted */
-#define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */
+#define STATE_ADDR_ZERO 0x00000040 /* zero address was accepted */
#define STATE_ADDR_MASK 0x00000070 /* address states mask */
/* During data input/output the simulator is in these states */
@@ -1904,7 +1904,14 @@ static void switch_state(struct nandsim *ns)
break;
case STATE_ADDR_ZERO:
- ns->regs->num = 1;
+ /* For flash which has large page,
+ * its column consists of 2 bytes,
+ * so 2 bytes are written to flash
+ */
+ if (nsmtd->writesize > 512)
+ ns->regs->num = 2;
+ else
+ ns->regs->num = 1;
break;
case STATE_ADDR_COLUMN:
@@ -2073,7 +2080,14 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
ns->regs->num = ns->geom.secaddrbytes;
break;
case STATE_ADDR_ZERO:
- ns->regs->num = 1;
+ /* For flash which has large page,
+ * its column consists of 2 bytes,
+ * so 2 bytes are written to flash
+ */
+ if (mtd->writesize > 512)
+ ns->regs->num = 2;
+ else
+ ns->regs->num = 1;
break;
default:
BUG();
--
1.8.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 3/5] MTD: nandsim: fix page address size
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 1/5] MTD: nandsim: add numchips module parameter Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 2/5] MTD: nandsim: fix column address size of large page Sheng Yong
@ 2015-08-05 8:55 ` Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 4/5] MTD: nandsim: add ADJUST_ROW() to find the real page number Sheng Yong
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
The page address size should be calculated according to chip size, but not
total size of NAND flash. So we add a new chipsz in nandsim geometry to
save the chip size, and use it to get page address size.
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
---
drivers/mtd/nand/nandsim.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 5938be4..45100b37 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -359,6 +359,7 @@ struct nandsim {
/* NAND flash "geometry" */
struct {
uint64_t totsz; /* total flash size, bytes */
+ uint32_t chipsz; /* each chip size, bytes */
uint32_t secsz; /* flash sector (erase block) size, bytes */
uint pgsz; /* NAND flash page size, bytes */
uint oobsz; /* page OOB area size, bytes */
@@ -700,6 +701,7 @@ static int init_nandsim(struct mtd_info *mtd)
/* Initialize the NAND flash parameters */
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
ns->geom.totsz = mtd->size;
+ ns->geom.chipsz = chip->chipsize;
ns->geom.pgsz = mtd->writesize;
ns->geom.oobsz = mtd->oobsize;
ns->geom.secsz = mtd->erasesize;
@@ -727,7 +729,7 @@ static int init_nandsim(struct mtd_info *mtd)
}
if (ns->options & OPT_SMALLPAGE) {
- if (ns->geom.totsz <= (32 << 20)) {
+ if (ns->geom.chipsz <= (32 << 20)) {
ns->geom.pgaddrbytes = 3;
ns->geom.secaddrbytes = 2;
} else {
@@ -735,7 +737,7 @@ static int init_nandsim(struct mtd_info *mtd)
ns->geom.secaddrbytes = 3;
}
} else {
- if (ns->geom.totsz <= (128 << 20)) {
+ if (ns->geom.chipsz <= (128 << 20)) {
ns->geom.pgaddrbytes = 4;
ns->geom.secaddrbytes = 2;
} else {
--
1.8.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 4/5] MTD: nandsim: add ADJUST_ROW() to find the real page number
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
` (2 preceding siblings ...)
2015-08-05 8:55 ` [RFC PATCH 3/5] MTD: nandsim: fix page address size Sheng Yong
@ 2015-08-05 8:55 ` Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 5/5] MTD: nandsim: extent outprint messages Sheng Yong
2015-11-20 19:06 ` [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Brian Norris
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
regs->row only points to the relative page number in the selected
chip. In multiple chips case, we cannot get the correct page number
from regs->row directly. So we add a new cpgnum in nandsim geometry
to save the number of pages of one chip, and add an offset of
(cpgnum * chipselect) to get the real page number.
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
---
drivers/mtd/nand/nandsim.c | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 45100b37..5406ea7 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -211,9 +211,17 @@ MODULE_PARM_DESC(numchips, "Number of chips of the NAND flash (1 by default)");
/* Operation failed completion status */
#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
+/* Adjust row to suit for multichips, chipselect should be considered.
+ * Page number should be adjusted, if we want to read/prog/erase/etc. a
+ * "physic" page or get the raw offset. NOTE that the value in the row
+ * register should not be changed.
+ */
+#define ADJUST_ROW(ns) \
+ ((ns)->chipselect * (ns)->geom.cpgnum + (ns)->regs->row)
+
/* Calculate the page offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET(ns) \
- (((ns)->regs->row * (ns)->geom.pgszoob) + (ns)->regs->column)
+ ((ADJUST_ROW(ns) * (ns)->geom.pgszoob) + (ns)->regs->column)
/* Calculate the OOB offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
@@ -366,6 +374,7 @@ struct nandsim {
uint64_t totszoob; /* total flash size including OOB, bytes */
uint pgszoob; /* page size including OOB , bytes*/
uint secszoob; /* sector size including OOB, bytes */
+ uint cpgnum; /* number of pages per chip */
uint pgnum; /* total number of pages */
uint pgsec; /* number of pages per sector */
uint secshift; /* bits number in sector size */
@@ -707,6 +716,7 @@ static int init_nandsim(struct mtd_info *mtd)
ns->geom.secsz = mtd->erasesize;
ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz;
ns->geom.pgnum = div_u64(ns->geom.totsz, ns->geom.pgsz);
+ ns->geom.cpgnum = div_u64(ns->geom.chipsz, ns->geom.pgsz);
ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
ns->geom.secshift = ffs(ns->geom.secsz) - 1;
ns->geom.pgshift = chip->page_shift;
@@ -1198,9 +1208,9 @@ static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
{
uint byte = (uint)bt;
- if (ns->regs->count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
+ if (ns->regs->count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) {
ns->regs->column |= (byte << 8 * ns->regs->count);
- else {
+ } else {
ns->regs->row |= (byte << 8 * (ns->regs->count -
ns->geom.pgaddrbytes +
ns->geom.secaddrbytes));
@@ -1443,7 +1453,8 @@ static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size
*/
static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
{
- return &(ns->pages[ns->regs->row]);
+ uint pgnum = ADJUST_ROW(ns);
+ return &(ns->pages[pgnum]);
}
/*
@@ -1456,11 +1467,11 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
static int do_read_error(struct nandsim *ns, int num)
{
- unsigned int page_no = ns->regs->row;
+ unsigned int page_no = ADJUST_ROW(ns);
if (read_error(page_no)) {
prandom_bytes(ns->buf.byte, num);
- NS_WARN("simulating read error in page %u\n", page_no);
+ NS_WARN("simulating read error in page %u\n", ns->regs->row);
return 1;
}
return 0;
@@ -1491,7 +1502,7 @@ static void read_page(struct nandsim *ns, int num)
union ns_mem *mypage;
if (ns->cfile) {
- if (!test_bit(ns->regs->row, ns->pages_written)) {
+ if (!test_bit(ADJUST_ROW(ns), ns->pages_written)) {
NS_DBG("read_page: page %d not written\n", ns->regs->row);
memset(ns->buf.byte, 0xFF, num);
} else {
@@ -1537,7 +1548,7 @@ static void erase_sector(struct nandsim *ns)
if (ns->cfile) {
for (i = 0; i < ns->geom.pgsec; i++)
- if (__test_and_clear_bit(ns->regs->row + i,
+ if (__test_and_clear_bit(ADJUST_ROW(ns) + i,
ns->pages_written)) {
NS_DBG("erase_sector: freeing page %d\n", ns->regs->row + i);
}
@@ -1572,7 +1583,7 @@ static int prog_page(struct nandsim *ns, int num)
NS_DBG("prog_page: writing page %d\n", ns->regs->row);
pg_off = ns->file_buf + ns->regs->column + ns->regs->off;
off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs->off;
- if (!test_bit(ns->regs->row, ns->pages_written)) {
+ if (!test_bit(ADJUST_ROW(ns), ns->pages_written)) {
all = 1;
memset(ns->file_buf, 0xff, ns->geom.pgszoob);
} else {
@@ -1586,13 +1597,13 @@ static int prog_page(struct nandsim *ns, int num)
for (i = 0; i < num; i++)
pg_off[i] &= ns->buf.byte[i];
if (all) {
- loff_t pos = (loff_t)ns->regs->row * ns->geom.pgszoob;
+ loff_t pos = (loff_t)ADJUST_ROW(ns) * ns->geom.pgszoob;
tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
if (tx != ns->geom.pgszoob) {
NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
- __set_bit(ns->regs->row, ns->pages_written);
+ __set_bit(ADJUST_ROW(ns), ns->pages_written);
} else {
tx = write_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) {
@@ -1641,7 +1652,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
action &= ACTION_MASK;
/* Check that page address input is correct */
- if (action != ACTION_SECERASE && ns->regs->row >= ns->geom.pgnum) {
+ if (action != ACTION_SECERASE && ns->regs->row >= ns->geom.cpgnum) {
NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs->row);
return -1;
}
@@ -1686,8 +1697,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
return -1;
}
- if (ns->regs->row >= ns->geom.pgnum - ns->geom.pgsec
- || (ns->regs->row & ~(ns->geom.secsz - 1))) {
+ if (ns->regs->row >= ns->geom.cpgnum - ns->geom.pgsec ||
+ ns->regs->row & ~(ns->geom.secsz - 1)) {
NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs->row);
return -1;
}
@@ -1696,7 +1707,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs->column;
ns->regs->column = 0;
- erase_block_no = ns->regs->row >> (ns->geom.secshift - ns->geom.pgshift);
+ erase_block_no = ADJUST_ROW(ns) >> (ns->geom.secshift - ns->geom.pgshift);
NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
ns->regs->row, NS_RAW_OFFSET(ns));
@@ -1736,7 +1747,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
if (prog_page(ns, num) == -1)
return -1;
- page_no = ns->regs->row;
+ page_no = ADJUST_ROW(ns);
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
num, ns->regs->row, ns->regs->column, NS_RAW_OFFSET(ns) + ns->regs->off);
@@ -1746,7 +1757,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
if (write_error(page_no)) {
- NS_WARN("simulating write failure in page %u\n", page_no);
+ NS_WARN("simulating write failure in page %u\n", ns->regs->row);
return -1;
}
--
1.8.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [RFC PATCH 5/5] MTD: nandsim: extent outprint messages
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
` (3 preceding siblings ...)
2015-08-05 8:55 ` [RFC PATCH 4/5] MTD: nandsim: add ADJUST_ROW() to find the real page number Sheng Yong
@ 2015-08-05 8:55 ` Sheng Yong
2015-11-20 19:06 ` [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Brian Norris
5 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-08-05 8:55 UTC (permalink / raw)
To: computersforpeace; +Cc: dwmw2, richard, linux-mtd
* Replace printk with pr_{devel|info|warn|err}.
* Add NS_{DBG|INFO|WARN|ERR}_CHIP to print chip number, e.g.
[nandsim] chip0: error: do_state_action: too few bytes were input (512 instead of 528)
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
---
drivers/mtd/nand/nandsim.c | 244 ++++++++++++++++++++++++---------------------
1 file changed, 132 insertions(+), 112 deletions(-)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 5406ea7..b1cbc7e 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -182,19 +182,37 @@ MODULE_PARM_DESC(numchips, "Number of chips of the NAND flash (1 by default)");
#define NS_LARGEST_PAGE_SIZE 4096
/* The prefix for simulator output */
-#define NS_OUTPUT_PREFIX "[nandsim]"
+#define NS_PREFIX "[nandsim]"
+
+/* Get selected chip */
+#define CHIP_SEL_PREFIX "chip%d:"
+#define CHIP_SEL (((struct nandsim *) ((struct nand_chip *) nsmtd->priv)->priv)->chipselect)
/* Simulator's output macros (logging, debugging, warning, error) */
#define NS_LOG(args...) \
- do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
+ do { if (log) pr_devel(NS_PREFIX " log: " args); } while(0)
#define NS_DBG(args...) \
- do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
-#define NS_WARN(args...) \
- do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
-#define NS_ERR(args...) \
- do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
-#define NS_INFO(args...) \
- do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
+ do { if (dbg) pr_devel(NS_PREFIX " debug: " args); } while(0)
+#define NS_WARN(args...) pr_warn(NS_PREFIX " warning: " args)
+#define NS_ERR(args...) pr_err(NS_PREFIX " error: " args)
+#define NS_INFO(args...) pr_info(NS_PREFIX " " args)
+
+#define NS_LOG_CHIP(fmt, ...) do { \
+ if (log) \
+ pr_devel(NS_PREFIX " " CHIP_SEL_PREFIX " log: " fmt, \
+ CHIP_SEL, ##__VA_ARGS__); \
+} while(0)
+#define NS_DBG_CHIP(fmt, ...) do { \
+ if (dbg) \
+ pr_devel(NS_PREFIX " " CHIP_SEL_PREFIX " debug: " fmt, \
+ CHIP_SEL, ##__VA_ARGS__); \
+} while(0)
+#define NS_WARN_CHIP(fmt, ...) pr_warn(NS_PREFIX " " CHIP_SEL_PREFIX " warning: " fmt, \
+ CHIP_SEL, ##__VA_ARGS__)
+#define NS_ERR_CHIP(fmt, ...) pr_err(NS_PREFIX " " CHIP_SEL_PREFIX " error: " fmt, \
+ CHIP_SEL, ##__VA_ARGS__)
+#define NS_INFO_CHIP(fmt, ...) pr_info(NS_PREFIX " " CHIP_SEL_PREFIX " " fmt, \
+ CHIP_SEL, ##__VA_ARGS__)
/* Busy-wait delay macros (microseconds, milliseconds) */
#define NS_UDELAY(us) \
@@ -1070,10 +1088,10 @@ static void update_wear(unsigned int erase_block_no)
* instead of showing an error message.
*/
if (total_wear == 0)
- NS_ERR("Erase counter total overflow\n");
+ NS_ERR_CHIP("Erase counter total overflow\n");
erase_block_wear[erase_block_no] += 1;
if (erase_block_wear[erase_block_no] == 0)
- NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
+ NS_ERR_CHIP("Erase counter overflow for erase block %u\n", erase_block_no);
}
/*
@@ -1130,7 +1148,7 @@ static char *get_state_name(uint32_t state)
return "STATE_UNKNOWN";
}
- NS_ERR("get_state_name: unknown state, BUG\n");
+ NS_ERR_CHIP("get_state_name: unknown state, BUG\n");
return NULL;
}
@@ -1197,7 +1215,7 @@ static uint32_t get_state_by_command(unsigned command)
return STATE_CMD_RNDOUTSTART;
}
- NS_ERR("get_state_by_command: unknown command, BUG\n");
+ NS_ERR_CHIP("get_state_by_command: unknown command, BUG\n");
return 0;
}
@@ -1224,7 +1242,7 @@ static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
*/
static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
{
- NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
+ NS_DBG_CHIP("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
ns->state = STATE_READY;
ns->nxstate = STATE_UNKNOWN;
@@ -1333,7 +1351,7 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
ns->npstates = 0;
ns->state = ns->op[ns->stateidx];
ns->nxstate = ns->op[ns->stateidx + 1];
- NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
+ NS_DBG_CHIP("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
idx, get_state_name(ns->state), get_state_name(ns->nxstate));
return 0;
}
@@ -1341,24 +1359,24 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
if (opsfound == 0) {
/* Nothing was found. Try to ignore previous commands (if any) and search again */
if (ns->npstates != 0) {
- NS_DBG("find_operation: no operation found, try again with state %s\n",
+ NS_DBG_CHIP("find_operation: no operation found, try again with state %s\n",
get_state_name(ns->state));
ns->npstates = 0;
return find_operation(ns, 0);
}
- NS_DBG("find_operation: no operations found\n");
+ NS_DBG_CHIP("find_operation: no operations found\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return -2;
}
if (flag) {
/* This shouldn't happen */
- NS_DBG("find_operation: BUG, operation must be known if address is input\n");
+ NS_DBG_CHIP("find_operation: BUG, operation must be known if address is input\n");
return -2;
}
- NS_DBG("find_operation: there is still ambiguity\n");
+ NS_DBG_CHIP("find_operation: there is still ambiguity\n");
ns->pstates[ns->npstates++] = ns->state;
@@ -1471,7 +1489,7 @@ static int do_read_error(struct nandsim *ns, int num)
if (read_error(page_no)) {
prandom_bytes(ns->buf.byte, num);
- NS_WARN("simulating read error in page %u\n", ns->regs->row);
+ NS_WARN_CHIP("simulating read error in page %u\n", ns->regs->row);
return 1;
}
return 0;
@@ -1486,10 +1504,10 @@ static void do_bit_flips(struct nandsim *ns, int num)
while (flips--) {
int pos = prandom_u32() % (num * 8);
ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
- NS_WARN("read_page: flipping bit %d in page %d "
- "reading from %d ecc: corrected=%u failed=%u\n",
- pos, ns->regs->row, ns->regs->column + ns->regs->off,
- nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+ NS_WARN_CHIP("read_page: flipping bit %d in page %d "
+ "reading from %d ecc: corrected=%u failed=%u\n",
+ pos, ns->regs->row, ns->regs->column + ns->regs->off,
+ nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
}
}
}
@@ -1503,20 +1521,21 @@ static void read_page(struct nandsim *ns, int num)
if (ns->cfile) {
if (!test_bit(ADJUST_ROW(ns), ns->pages_written)) {
- NS_DBG("read_page: page %d not written\n", ns->regs->row);
+ NS_DBG_CHIP("read_page: page %d not written\n", ns->regs->row);
memset(ns->buf.byte, 0xFF, num);
} else {
loff_t pos;
ssize_t tx;
- NS_DBG("read_page: page %d written, reading from %d\n",
- ns->regs->row, ns->regs->column + ns->regs->off);
+ NS_DBG_CHIP("read_page: page %d written, reading from %d\n",
+ ns->regs->row, ns->regs->column + ns->regs->off);
if (do_read_error(ns, num))
return;
pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs->off;
tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
if (tx != num) {
- NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs->row, (long)tx);
+ NS_ERR_CHIP("read_page: read error for page %d ret %ld\n",
+ ns->regs->row, (long)tx);
return;
}
do_bit_flips(ns, num);
@@ -1526,11 +1545,11 @@ static void read_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
- NS_DBG("read_page: page %d not allocated\n", ns->regs->row);
+ NS_DBG_CHIP("read_page: page %d not allocated\n", ns->regs->row);
memset(ns->buf.byte, 0xFF, num);
} else {
- NS_DBG("read_page: page %d allocated, reading from %d\n",
- ns->regs->row, ns->regs->column + ns->regs->off);
+ NS_DBG_CHIP("read_page: page %d allocated, reading from %d\n",
+ ns->regs->row, ns->regs->column + ns->regs->off);
if (do_read_error(ns, num))
return;
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
@@ -1550,7 +1569,7 @@ static void erase_sector(struct nandsim *ns)
for (i = 0; i < ns->geom.pgsec; i++)
if (__test_and_clear_bit(ADJUST_ROW(ns) + i,
ns->pages_written)) {
- NS_DBG("erase_sector: freeing page %d\n", ns->regs->row + i);
+ NS_DBG_CHIP("erase_sector: freeing page %d\n", ns->regs->row + i);
}
return;
}
@@ -1558,7 +1577,7 @@ static void erase_sector(struct nandsim *ns)
mypage = NS_GET_PAGE(ns);
for (i = 0; i < ns->geom.pgsec; i++) {
if (mypage->byte != NULL) {
- NS_DBG("erase_sector: freeing page %d\n", ns->regs->row+i);
+ NS_DBG_CHIP("erase_sector: freeing page %d\n", ns->regs->row+i);
kmem_cache_free(ns->nand_pages_slab, mypage->byte);
mypage->byte = NULL;
}
@@ -1580,7 +1599,7 @@ static int prog_page(struct nandsim *ns, int num)
ssize_t tx;
int all;
- NS_DBG("prog_page: writing page %d\n", ns->regs->row);
+ NS_DBG_CHIP("prog_page: writing page %d\n", ns->regs->row);
pg_off = ns->file_buf + ns->regs->column + ns->regs->off;
off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs->off;
if (!test_bit(ADJUST_ROW(ns), ns->pages_written)) {
@@ -1590,7 +1609,8 @@ static int prog_page(struct nandsim *ns, int num)
all = 0;
tx = read_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) {
- NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs->row, (long)tx);
+ NS_ERR_CHIP("prog_page: read error for page %d ret %ld\n",
+ ns->regs->row, (long)tx);
return -1;
}
}
@@ -1600,14 +1620,14 @@ static int prog_page(struct nandsim *ns, int num)
loff_t pos = (loff_t)ADJUST_ROW(ns) * ns->geom.pgszoob;
tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
if (tx != ns->geom.pgszoob) {
- NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
+ NS_ERR_CHIP("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
__set_bit(ADJUST_ROW(ns), ns->pages_written);
} else {
tx = write_file(ns, ns->cfile, pg_off, num, off);
if (tx != num) {
- NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
+ NS_ERR_CHIP("prog_page: write error for page %d ret %ld\n", ns->regs->row, (long)tx);
return -1;
}
}
@@ -1616,7 +1636,7 @@ static int prog_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
- NS_DBG("prog_page: allocating page %d\n", ns->regs->row);
+ NS_DBG_CHIP("prog_page: allocating page %d\n", ns->regs->row);
/*
* We allocate memory with GFP_NOFS because a flash FS may
* utilize this. If it is holding an FS lock, then gets here,
@@ -1625,7 +1645,7 @@ static int prog_page(struct nandsim *ns, int num)
*/
mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
if (mypage->byte == NULL) {
- NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs->row);
+ NS_ERR_CHIP("prog_page: error allocating memory for page %d\n", ns->regs->row);
return -1;
}
memset(mypage->byte, 0xFF, ns->geom.pgszoob);
@@ -1653,7 +1673,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
/* Check that page address input is correct */
if (action != ACTION_SECERASE && ns->regs->row >= ns->geom.cpgnum) {
- NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs->row);
+ NS_WARN_CHIP("do_state_action: wrong page number (%#x)\n", ns->regs->row);
return -1;
}
@@ -1666,21 +1686,21 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
/* Column shouldn't be very large */
if (ns->regs->column >= (ns->geom.pgszoob - ns->regs->off)) {
- NS_ERR("do_state_action: column number is too large\n");
+ NS_ERR_CHIP("do_state_action: column number is too large\n");
break;
}
num = ns->geom.pgszoob - ns->regs->off - ns->regs->column;
read_page(ns, num);
- NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
+ NS_DBG_CHIP("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
num, NS_RAW_OFFSET(ns) + ns->regs->off);
if (ns->regs->off == 0)
- NS_LOG("read page %d\n", ns->regs->row);
+ NS_LOG_CHIP("read page %d\n", ns->regs->row);
else if (ns->regs->off < ns->geom.pgsz)
- NS_LOG("read page %d (second half)\n", ns->regs->row);
+ NS_LOG_CHIP("read page %d (second half)\n", ns->regs->row);
else
- NS_LOG("read OOB of page %d\n", ns->regs->row);
+ NS_LOG_CHIP("read OOB of page %d\n", ns->regs->row);
NS_UDELAY(access_delay);
NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
@@ -1693,13 +1713,13 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
*/
if (ns->lines->wp) {
- NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
+ NS_ERR_CHIP("do_state_action: device is write-protected, ignore sector erase\n");
return -1;
}
if (ns->regs->row >= ns->geom.cpgnum - ns->geom.pgsec ||
ns->regs->row & ~(ns->geom.secsz - 1)) {
- NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs->row);
+ NS_ERR_CHIP("do_state_action: wrong sector address (%#x)\n", ns->regs->row);
return -1;
}
@@ -1709,9 +1729,9 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
erase_block_no = ADJUST_ROW(ns) >> (ns->geom.secshift - ns->geom.pgshift);
- NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
+ NS_DBG_CHIP("do_state_action: erase sector at address %#x, off = %d\n",
ns->regs->row, NS_RAW_OFFSET(ns));
- NS_LOG("erase sector %u\n", erase_block_no);
+ NS_LOG_CHIP("erase sector %u\n", erase_block_no);
erase_sector(ns);
@@ -1721,7 +1741,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
update_wear(erase_block_no);
if (erase_error(erase_block_no)) {
- NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+ NS_WARN_CHIP("simulating erase failure in erase block %u\n", erase_block_no);
return -1;
}
@@ -1733,13 +1753,13 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
*/
if (ns->lines->wp) {
- NS_WARN("do_state_action: device is write-protected, programm\n");
+ NS_WARN_CHIP("do_state_action: device is write-protected, programm\n");
return -1;
}
num = ns->geom.pgszoob - ns->regs->off - ns->regs->column;
if (num != ns->regs->count) {
- NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
+ NS_ERR_CHIP("do_state_action: too few bytes were input (%d instead of %d)\n",
ns->regs->count, num);
return -1;
}
@@ -1749,42 +1769,42 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
page_no = ADJUST_ROW(ns);
- NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
+ NS_DBG_CHIP("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
num, ns->regs->row, ns->regs->column, NS_RAW_OFFSET(ns) + ns->regs->off);
- NS_LOG("programm page %d\n", ns->regs->row);
+ NS_LOG_CHIP("programm page %d\n", ns->regs->row);
NS_UDELAY(programm_delay);
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
if (write_error(page_no)) {
- NS_WARN("simulating write failure in page %u\n", ns->regs->row);
+ NS_WARN_CHIP("simulating write failure in page %u\n", ns->regs->row);
return -1;
}
break;
case ACTION_ZEROOFF:
- NS_DBG("do_state_action: set internal offset to 0\n");
+ NS_DBG_CHIP("do_state_action: set internal offset to 0\n");
ns->regs->off = 0;
break;
case ACTION_HALFOFF:
if (!(ns->options & OPT_PAGE512_8BIT)) {
- NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
+ NS_ERR_CHIP("do_state_action: BUG! can't skip half of page for non-512"
"byte page size 8x chips\n");
return -1;
}
- NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
+ NS_DBG_CHIP("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
ns->regs->off = ns->geom.pgsz/2;
break;
case ACTION_OOBOFF:
- NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
+ NS_DBG_CHIP("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
ns->regs->off = ns->geom.pgsz;
break;
default:
- NS_DBG("do_state_action: BUG! unknown action\n");
+ NS_DBG_CHIP("do_state_action: BUG! unknown action\n");
}
return 0;
@@ -1805,7 +1825,7 @@ static void switch_state(struct nandsim *ns)
ns->state = ns->nxstate;
ns->nxstate = ns->op[ns->stateidx + 1];
- NS_DBG("switch_state: operation is known, switch to the next state, "
+ NS_DBG_CHIP("switch_state: operation is known, switch to the next state, "
"state: %s, nxstate: %s\n",
get_state_name(ns->state), get_state_name(ns->nxstate));
@@ -1827,7 +1847,7 @@ static void switch_state(struct nandsim *ns)
*/
ns->state = get_state_by_command(ns->regs->command);
- NS_DBG("switch_state: operation is unknown, try to find it\n");
+ NS_DBG_CHIP("switch_state: operation is unknown, try to find it\n");
if (find_operation(ns, 0) != 0)
return;
@@ -1840,7 +1860,7 @@ static void switch_state(struct nandsim *ns)
/* For 16x devices column means the page offset in words */
if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
- NS_DBG("switch_state: double the column number for 16x device\n");
+ NS_DBG_CHIP("switch_state: double the column number for 16x device\n");
ns->regs->column <<= 1;
}
@@ -1854,12 +1874,12 @@ static void switch_state(struct nandsim *ns)
/* In case of data states, see if all bytes were input/output */
if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
&& ns->regs->count != ns->regs->num) {
- NS_WARN("switch_state: not all bytes were processed, %d left\n",
- ns->regs->num - ns->regs->count);
+ NS_WARN_CHIP("switch_state: not all bytes were processed, %d left\n",
+ ns->regs->num - ns->regs->count);
status = NS_STATUS_FAILED(ns);
}
- NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
+ NS_DBG_CHIP("switch_state: operation complete, switch to STATE_READY state\n");
switch_to_ready_state(ns, status);
@@ -1873,9 +1893,9 @@ static void switch_state(struct nandsim *ns)
ns->nxstate = ns->op[++ns->stateidx + 1];
ns->regs->num = ns->regs->count = 0;
- NS_DBG("switch_state: the next state is data I/O, switch, "
- "state: %s, nxstate: %s\n",
- get_state_name(ns->state), get_state_name(ns->nxstate));
+ NS_DBG_CHIP("switch_state: the next state is data I/O, switch, "
+ "state: %s, nxstate: %s\n",
+ get_state_name(ns->state), get_state_name(ns->nxstate));
/*
* Set the internal register to the count of bytes which
@@ -1896,7 +1916,7 @@ static void switch_state(struct nandsim *ns)
break;
default:
- NS_ERR("switch_state: BUG! unknown data state\n");
+ NS_ERR_CHIP("switch_state: BUG! unknown data state\n");
}
} else if (ns->nxstate & STATE_ADDR_MASK) {
@@ -1933,7 +1953,7 @@ static void switch_state(struct nandsim *ns)
break;
default:
- NS_ERR("switch_state: BUG! unknown address state\n");
+ NS_ERR_CHIP("switch_state: BUG! unknown address state\n");
}
} else {
/*
@@ -1952,28 +1972,28 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
/* Sanity and correctness checks */
if (!ns->lines->ce) {
- NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
+ NS_ERR_CHIP("read_byte: chip is disabled, return %#x\n", (uint)outb);
return outb;
}
if (ns->lines->ale || ns->lines->cle) {
- NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
+ NS_ERR_CHIP("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
return outb;
}
if (!(ns->state & STATE_DATAOUT_MASK)) {
- NS_WARN("read_byte: unexpected data output cycle, state is %s "
- "return %#x\n", get_state_name(ns->state), (uint)outb);
+ NS_WARN_CHIP("read_byte: unexpected data output cycle, state is %s "
+ "return %#x\n", get_state_name(ns->state), (uint)outb);
return outb;
}
/* Status register may be read as many times as it is wanted */
if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
- NS_DBG("read_byte: return %#x status\n", ns->regs->status);
+ NS_DBG_CHIP("read_byte: return %#x status\n", ns->regs->status);
return ns->regs->status;
}
/* Check if there is any data in the internal buffer which may be read */
if (ns->regs->count == ns->regs->num) {
- NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
+ NS_WARN_CHIP("read_byte: no more data to output, return %#x\n", (uint)outb);
return outb;
}
@@ -1988,7 +2008,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
}
break;
case STATE_DATAOUT_ID:
- NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs->count, ns->regs->num);
+ NS_DBG_CHIP("read_byte: read ID byte %d, total = %d\n", ns->regs->count, ns->regs->num);
outb = ns->ids[ns->regs->count];
ns->regs->count += 1;
break;
@@ -1997,7 +2017,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
}
if (ns->regs->count == ns->regs->num) {
- NS_DBG("read_byte: all bytes were read\n");
+ NS_DBG_CHIP("read_byte: all bytes were read\n");
if (NS_STATE(ns->nxstate) == STATE_READY)
switch_state(ns);
@@ -2012,11 +2032,11 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
/* Sanity and correctness checks */
if (!ns->lines->ce) {
- NS_ERR("write_byte: chip is disabled, ignore write\n");
+ NS_ERR_CHIP("write_byte: chip is disabled, ignore write\n");
return;
}
if (ns->lines->ale && ns->lines->cle) {
- NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
+ NS_ERR_CHIP("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
return;
}
@@ -2026,14 +2046,14 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
*/
if (byte == NAND_CMD_RESET) {
- NS_LOG("reset chip\n");
+ NS_LOG_CHIP("reset chip\n");
switch_to_ready_state(ns, NS_STATUS_OK(ns));
return;
}
/* Check that the command byte is correct */
if (check_command(byte)) {
- NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
+ NS_ERR_CHIP("write_byte: unknown command %#x\n", (uint)byte);
return;
}
@@ -2056,14 +2076,14 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
* was expected but command was input. In this case ignore
* previous command(s)/state(s) and accept the last one.
*/
- NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
- "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+ NS_WARN_CHIP("write_byte: command (%#x) wasn't expected, expected state is %s, "
+ "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
}
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
}
- NS_DBG("command byte corresponding to %s state accepted\n",
- get_state_name(get_state_by_command(byte)));
+ NS_DBG_CHIP("command byte corresponding to %s state accepted\n",
+ get_state_name(get_state_by_command(byte)));
ns->regs->command = byte;
switch_state(ns);
@@ -2074,7 +2094,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
- NS_DBG("write_byte: operation isn't known yet, identify it\n");
+ NS_DBG_CHIP("write_byte: operation isn't known yet, identify it\n");
if (find_operation(ns, 1) < 0)
return;
@@ -2109,15 +2129,15 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
/* Check that chip is expecting address */
if (!(ns->nxstate & STATE_ADDR_MASK)) {
- NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
- "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
+ NS_ERR_CHIP("write_byte: address (%#x) isn't expected, expected state is %s, "
+ "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
/* Check if this is expected byte */
if (ns->regs->count == ns->regs->num) {
- NS_ERR("write_byte: no more address bytes expected\n");
+ NS_ERR_CHIP("write_byte: no more address bytes expected\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2126,11 +2146,11 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
ns->regs->count += 1;
- NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
- (uint)byte, ns->regs->count, ns->regs->num);
+ NS_DBG_CHIP("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
+ (uint)byte, ns->regs->count, ns->regs->num);
if (ns->regs->count == ns->regs->num) {
- NS_DBG("address (%#x, %#x) is accepted\n", ns->regs->row, ns->regs->column);
+ NS_DBG_CHIP("address (%#x, %#x) is accepted\n", ns->regs->row, ns->regs->column);
switch_state(ns);
}
@@ -2141,17 +2161,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
/* Check that chip is expecting data input */
if (!(ns->state & STATE_DATAIN_MASK)) {
- NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
- "switch to %s\n", (uint)byte,
- get_state_name(ns->state), get_state_name(STATE_READY));
+ NS_ERR_CHIP("write_byte: data input (%#x) isn't expected, state is %s, "
+ "switch to %s\n", (uint)byte,
+ get_state_name(ns->state), get_state_name(STATE_READY));
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
/* Check if this is expected byte */
if (ns->regs->count == ns->regs->num) {
- NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
- ns->regs->num);
+ NS_WARN_CHIP("write_byte: %u input bytes has already been accepted, ignore write\n",
+ ns->regs->num);
return;
}
@@ -2181,7 +2201,7 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
static int ns_device_ready(struct mtd_info *mtd)
{
- NS_DBG("device_ready\n");
+ NS_DBG_CHIP("device_ready\n");
return 1;
}
@@ -2189,7 +2209,7 @@ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
- NS_DBG("read_word\n");
+ NS_DBG_CHIP("read_word\n");
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
}
@@ -2200,15 +2220,15 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
/* Check that chip is expecting data input */
if (!(ns->state & STATE_DATAIN_MASK)) {
- NS_ERR("write_buf: data input isn't expected, state is %s, "
- "switch to STATE_READY\n", get_state_name(ns->state));
+ NS_ERR_CHIP("write_buf: data input isn't expected, state is %s, "
+ "switch to STATE_READY\n", get_state_name(ns->state));
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
/* Check if these are expected bytes */
if (ns->regs->count + len > ns->regs->num) {
- NS_ERR("write_buf: too many input bytes\n");
+ NS_ERR_CHIP("write_buf: too many input bytes\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2217,7 +2237,7 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
ns->regs->count += len;
if (ns->regs->count == ns->regs->num) {
- NS_DBG("write_buf: %d bytes were written\n", ns->regs->count);
+ NS_DBG_CHIP("write_buf: %d bytes were written\n", ns->regs->count);
}
}
@@ -2227,16 +2247,16 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/* Sanity and correctness checks */
if (!ns->lines->ce) {
- NS_ERR("read_buf: chip is disabled\n");
+ NS_ERR_CHIP("read_buf: chip is disabled\n");
return;
}
if (ns->lines->ale || ns->lines->cle) {
- NS_ERR("read_buf: ALE or CLE pin is high\n");
+ NS_ERR_CHIP("read_buf: ALE or CLE pin is high\n");
return;
}
if (!(ns->state & STATE_DATAOUT_MASK)) {
- NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
- get_state_name(ns->state));
+ NS_WARN_CHIP("read_buf: unexpected data output cycle, current state is %s\n",
+ get_state_name(ns->state));
return;
}
@@ -2251,7 +2271,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/* Check if these are expected bytes */
if (ns->regs->count + len > ns->regs->num) {
- NS_ERR("read_buf: too many bytes to read\n");
+ NS_ERR_CHIP("read_buf: too many bytes to read\n");
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2294,8 +2314,8 @@ static void ns_select_chip(struct mtd_info *mtd, int chipselect)
ns->lines = &ns_lines[ns->chipselect];
} else {
ns->chipselect = -1;
- NS_ERR("chip %d not exist, max numchips is %d, avaliable numchips is %d\n",
- chipselect, numchips, chip->numchips);
+ NS_ERR_CHIP("chip not exist, max numchips is %d, avaliable numchips is %d\n",
+ numchips, chip->numchips);
}
}
--
1.8.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
` (4 preceding siblings ...)
2015-08-05 8:55 ` [RFC PATCH 5/5] MTD: nandsim: extent outprint messages Sheng Yong
@ 2015-11-20 19:06 ` Brian Norris
2015-11-23 1:53 ` Sheng Yong
5 siblings, 1 reply; 8+ messages in thread
From: Brian Norris @ 2015-11-20 19:06 UTC (permalink / raw)
To: Sheng Yong; +Cc: dwmw2, richard, linux-mtd, Boris Brezillon
On Wed, Aug 05, 2015 at 08:55:49AM +0000, Sheng Yong wrote:
> Hi, folks,
>
> These patchset add a new module parameter, numchips, to supports to
> simulate NAND flash with multiple chips.
>
> This simulation helps to test and improve generic NAND driver on
> multiple chips NAND flash.
I'm not quite sure I understand the real purpose of this feature. Seems
like you're just testing different corners of the internals of the NAND
framework, but not actually exposing anything new that an MTD user would
care about. Care to clarify?
Brian
> MTD test (except for mtd_nandbiterr) are passed.
>
> Thanks,
> Sheng
>
> Sheng Yong (5):
> MTD: nandsim: add numchips module parameter
> MTD: nandsim: fix column address size of large page
> MTD: nandsim: fix page address size
> MTD: nandsim: add ADJUST_ROW() to find the real page number
> MTD: nandsim: extent outprint messages
>
> drivers/mtd/nand/nandsim.c | 632 +++++++++++++++++++++++++++------------------
> 1 file changed, 377 insertions(+), 255 deletions(-)
>
> --
> 1.8.3.4
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips
2015-11-20 19:06 ` [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Brian Norris
@ 2015-11-23 1:53 ` Sheng Yong
0 siblings, 0 replies; 8+ messages in thread
From: Sheng Yong @ 2015-11-23 1:53 UTC (permalink / raw)
To: Brian Norris; +Cc: dwmw2, richard, linux-mtd, Boris Brezillon
On 11/21/2015 3:06 AM, Brian Norris wrote:
> On Wed, Aug 05, 2015 at 08:55:49AM +0000, Sheng Yong wrote:
>> Hi, folks,
>>
>> These patchset add a new module parameter, numchips, to supports to
>> simulate NAND flash with multiple chips.
>>
>> This simulation helps to test and improve generic NAND driver on
>> multiple chips NAND flash.
>
Hi, Brian
Thanks for your reply.
> I'm not quite sure I understand the real purpose of this feature. Seems
> like you're just testing different corners of the internals of the NAND
> framework, but not actually exposing anything new that an MTD user would
> care about. Care to clarify?
>
Sorry for I didn't put much explaination in the last mail. Test for multi-
chips NAND flash detection is not the main purpose. The main purpose of doing
this is that if nand_scan_ident() fails to read the first chip, it will not
continue to try to setup the other chips, while if we make an appropriate
partition strategy, the other chips may contains data we expect.
So we think it may worth trying to skip the faulty chips and continue scanning
the other chips and setup the partitions that are not on the faulty chips. We
are not quiet sure if it's correct to do so, but we think simulating a multi-
chip NAND is the first step.
thanks,
Sheng
> Brian
>
>> MTD test (except for mtd_nandbiterr) are passed.
>>
>> Thanks,
>> Sheng
>>
>> Sheng Yong (5):
>> MTD: nandsim: add numchips module parameter
>> MTD: nandsim: fix column address size of large page
>> MTD: nandsim: fix page address size
>> MTD: nandsim: add ADJUST_ROW() to find the real page number
>> MTD: nandsim: extent outprint messages
>>
>> drivers/mtd/nand/nandsim.c | 632 +++++++++++++++++++++++++++------------------
>> 1 file changed, 377 insertions(+), 255 deletions(-)
>>
>> --
>> 1.8.3.4
>>
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-11-23 1:55 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-05 8:55 [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 1/5] MTD: nandsim: add numchips module parameter Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 2/5] MTD: nandsim: fix column address size of large page Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 3/5] MTD: nandsim: fix page address size Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 4/5] MTD: nandsim: add ADJUST_ROW() to find the real page number Sheng Yong
2015-08-05 8:55 ` [RFC PATCH 5/5] MTD: nandsim: extent outprint messages Sheng Yong
2015-11-20 19:06 ` [RFC PATCH 0/5] MTD: nandsim: simulate multiple chips Brian Norris
2015-11-23 1:53 ` Sheng Yong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).