Skip to content

Commit bbcd80f

Browse files
committed
mtd: rawnand: Prevent crossing LUN boundaries during sequential reads
The ONFI specification states that devices do not need to support sequential reads across LUN boundaries. In order to prevent such event from happening and possibly failing, let's introduce the concept of "pause" in the sequential read to handle these cases. The first/last pages remain the same but any time we cross a LUN boundary we will end and restart (if relevant) the sequential read operation. Cc: stable@vger.kernel.org Fixes: 003fe4b ("mtd: rawnand: Support for sequential cache reads") Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Tested-by: Martin Hundebøll <martin@geanix.com> Link: https://lore.kernel.org/linux-mtd/20231215123208.516590-2-miquel.raynal@bootlin.com
1 parent a43bdc3 commit bbcd80f

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

drivers/mtd/nand/raw/nand_base.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,23 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
12071207
return nand_exec_op(chip, &op);
12081208
}
12091209

1210+
static void rawnand_cap_cont_reads(struct nand_chip *chip)
1211+
{
1212+
struct nand_memory_organization *memorg;
1213+
unsigned int pages_per_lun, first_lun, last_lun;
1214+
1215+
memorg = nanddev_get_memorg(&chip->base);
1216+
pages_per_lun = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
1217+
first_lun = chip->cont_read.first_page / pages_per_lun;
1218+
last_lun = chip->cont_read.last_page / pages_per_lun;
1219+
1220+
/* Prevent sequential cache reads across LUN boundaries */
1221+
if (first_lun != last_lun)
1222+
chip->cont_read.pause_page = first_lun * pages_per_lun + pages_per_lun - 1;
1223+
else
1224+
chip->cont_read.pause_page = chip->cont_read.last_page;
1225+
}
1226+
12101227
static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
12111228
unsigned int offset_in_page, void *buf,
12121229
unsigned int len, bool check_only)
@@ -1225,7 +1242,7 @@ static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int p
12251242
NAND_OP_DATA_IN(len, buf, 0),
12261243
};
12271244
struct nand_op_instr cont_instrs[] = {
1228-
NAND_OP_CMD(page == chip->cont_read.last_page ?
1245+
NAND_OP_CMD(page == chip->cont_read.pause_page ?
12291246
NAND_CMD_READCACHEEND : NAND_CMD_READCACHESEQ,
12301247
NAND_COMMON_TIMING_NS(conf, tWB_max)),
12311248
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
@@ -1262,16 +1279,29 @@ static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int p
12621279
}
12631280

12641281
if (page == chip->cont_read.first_page)
1265-
return nand_exec_op(chip, &start_op);
1282+
ret = nand_exec_op(chip, &start_op);
12661283
else
1267-
return nand_exec_op(chip, &cont_op);
1284+
ret = nand_exec_op(chip, &cont_op);
1285+
if (ret)
1286+
return ret;
1287+
1288+
if (!chip->cont_read.ongoing)
1289+
return 0;
1290+
1291+
if (page == chip->cont_read.pause_page &&
1292+
page != chip->cont_read.last_page) {
1293+
chip->cont_read.first_page = chip->cont_read.pause_page + 1;
1294+
rawnand_cap_cont_reads(chip);
1295+
} else if (page == chip->cont_read.last_page) {
1296+
chip->cont_read.ongoing = false;
1297+
}
1298+
1299+
return 0;
12681300
}
12691301

12701302
static bool rawnand_cont_read_ongoing(struct nand_chip *chip, unsigned int page)
12711303
{
1272-
return chip->cont_read.ongoing &&
1273-
page >= chip->cont_read.first_page &&
1274-
page <= chip->cont_read.last_page;
1304+
return chip->cont_read.ongoing && page >= chip->cont_read.first_page;
12751305
}
12761306

12771307
/**
@@ -3445,6 +3475,7 @@ static void rawnand_enable_cont_reads(struct nand_chip *chip, unsigned int page,
34453475
if (col)
34463476
chip->cont_read.first_page++;
34473477
chip->cont_read.last_page = page + ((readlen >> chip->page_shift) & chip->pagemask);
3478+
rawnand_cap_cont_reads(chip);
34483479
}
34493480

34503481
/**

include/linux/mtd/rawnand.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,7 @@ struct nand_secure_region {
12651265
* @cont_read: Sequential page read internals
12661266
* @cont_read.ongoing: Whether a continuous read is ongoing or not
12671267
* @cont_read.first_page: Start of the continuous read operation
1268+
* @cont_read.pause_page: End of the current sequential cache read operation
12681269
* @cont_read.last_page: End of the continuous read operation
12691270
* @controller: The hardware controller structure which is shared among multiple
12701271
* independent devices
@@ -1321,6 +1322,7 @@ struct nand_chip {
13211322
struct {
13221323
bool ongoing;
13231324
unsigned int first_page;
1325+
unsigned int pause_page;
13241326
unsigned int last_page;
13251327
} cont_read;
13261328

0 commit comments

Comments
 (0)