Commit 8adf1ac2 authored by Miquel Raynal's avatar Miquel Raynal

mtd: nand: Introduce a block iterator

In order to be able to iterate easily across eraseblocks rather than
pages, let's introduce a block iterator inspired from the page iterator.

The main usage of this iterator will be for continuous/sequential reads,
where it is interesting to use a single request rather than split the
requests in smaller chunks (ie. pages) that can be hardly optimized.

So a "continuous" boolean get's added for this purpose.
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20240826101412.20644-3-miquel.raynal@bootlin.com
parent 3f4c0ad4
...@@ -103,6 +103,8 @@ enum nand_page_io_req_type { ...@@ -103,6 +103,8 @@ enum nand_page_io_req_type {
* @ooblen: the number of OOB bytes to read from/write to this page * @ooblen: the number of OOB bytes to read from/write to this page
* @oobbuf: buffer to store OOB data in or get OOB data from * @oobbuf: buffer to store OOB data in or get OOB data from
* @mode: one of the %MTD_OPS_XXX mode * @mode: one of the %MTD_OPS_XXX mode
* @continuous: no need to start over the operation at the end of each page, the
* NAND device will automatically prepare the next one
* *
* This object is used to pass per-page I/O requests to NAND sub-layers. This * This object is used to pass per-page I/O requests to NAND sub-layers. This
* way all useful information are already formatted in a useful way and * way all useful information are already formatted in a useful way and
...@@ -125,6 +127,7 @@ struct nand_page_io_req { ...@@ -125,6 +127,7 @@ struct nand_page_io_req {
void *in; void *in;
} oobbuf; } oobbuf;
int mode; int mode;
bool continuous;
}; };
const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void); const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void);
...@@ -937,6 +940,43 @@ static inline void nanddev_io_page_iter_init(struct nand_device *nand, ...@@ -937,6 +940,43 @@ static inline void nanddev_io_page_iter_init(struct nand_device *nand,
iter->req.ooblen = min_t(unsigned int, iter->req.ooblen = min_t(unsigned int,
iter->oobbytes_per_page - iter->req.ooboffs, iter->oobbytes_per_page - iter->req.ooboffs,
iter->oobleft); iter->oobleft);
iter->req.continuous = false;
}
/**
* nand_io_block_iter_init - Initialize a NAND I/O iterator
* @nand: NAND device
* @offs: absolute offset
* @req: MTD request
* @iter: NAND I/O iterator
*
* Initializes a NAND iterator based on the information passed by the MTD
* layer for block jumps (no OOB)
*
* In practice only reads may leverage this iterator.
*/
static inline void nanddev_io_block_iter_init(struct nand_device *nand,
enum nand_page_io_req_type reqtype,
loff_t offs, struct mtd_oob_ops *req,
struct nand_io_iter *iter)
{
unsigned int offs_in_eb;
iter->req.type = reqtype;
iter->req.mode = req->mode;
iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
iter->req.ooboffs = 0;
iter->oobbytes_per_page = 0;
iter->dataleft = req->len;
iter->oobleft = 0;
iter->req.databuf.in = req->datbuf;
offs_in_eb = (nand->memorg.pagesize * iter->req.pos.page) + iter->req.dataoffs;
iter->req.datalen = min_t(unsigned int,
nanddev_eraseblock_size(nand) - offs_in_eb,
iter->dataleft);
iter->req.oobbuf.in = NULL;
iter->req.ooblen = 0;
iter->req.continuous = true;
} }
/** /**
...@@ -962,6 +1002,25 @@ static inline void nanddev_io_iter_next_page(struct nand_device *nand, ...@@ -962,6 +1002,25 @@ static inline void nanddev_io_iter_next_page(struct nand_device *nand,
iter->oobleft); iter->oobleft);
} }
/**
* nand_io_iter_next_block - Move to the next block
* @nand: NAND device
* @iter: NAND I/O iterator
*
* Updates the @iter to point to the next block.
* No OOB handling available.
*/
static inline void nanddev_io_iter_next_block(struct nand_device *nand,
struct nand_io_iter *iter)
{
nanddev_pos_next_eraseblock(nand, &iter->req.pos);
iter->dataleft -= iter->req.datalen;
iter->req.databuf.in += iter->req.datalen;
iter->req.dataoffs = 0;
iter->req.datalen = min_t(unsigned int, nanddev_eraseblock_size(nand),
iter->dataleft);
}
/** /**
* nand_io_iter_end - Should end iteration or not * nand_io_iter_end - Should end iteration or not
* @nand: NAND device * @nand: NAND device
...@@ -997,6 +1056,21 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand, ...@@ -997,6 +1056,21 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
!nanddev_io_iter_end(nand, iter); \ !nanddev_io_iter_end(nand, iter); \
nanddev_io_iter_next_page(nand, iter)) nanddev_io_iter_next_page(nand, iter))
/**
* nand_io_for_each_block - Iterate over all NAND pages contained in an MTD I/O
* request, one block at a time
* @nand: NAND device
* @start: start address to read/write from
* @req: MTD I/O request
* @iter: NAND I/O iterator
*
* Should be used for iterating over blocks that are contained in an MTD request.
*/
#define nanddev_io_for_each_block(nand, type, start, req, iter) \
for (nanddev_io_block_iter_init(nand, type, start, req, iter); \
!nanddev_io_iter_end(nand, iter); \
nanddev_io_iter_next_block(nand, iter))
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment