[RFC PATCH 4/5] MTD: nandsim: add ADJUST_ROW() to find the real page number
Sheng Yong
shengyong1 at huawei.com
Wed Aug 5 01:55:53 PDT 2015
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 at 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
More information about the linux-mtd
mailing list