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

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
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ enum nand_page_io_req_type {
 * @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
 * @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
 * way all useful information are already formatted in a useful way and
@@ -125,6 +127,7 @@ struct nand_page_io_req {
		void *in;
	} oobbuf;
	int mode;
	bool continuous;
};

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,
	iter->req.ooblen = min_t(unsigned int,
				 iter->oobbytes_per_page - iter->req.ooboffs,
				 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,
				 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: NAND device
@@ -997,6 +1056,21 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
	     !nanddev_io_iter_end(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_isreserved(struct nand_device *nand, const struct nand_pos *pos);
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);