linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH 2/4] mtd: nand: implement two pairing scheme
@ 2016-06-11 22:30 George Spelvin
  2016-06-12  7:20 ` Boris Brezillon
  0 siblings, 1 reply; 14+ messages in thread
From: George Spelvin @ 2016-06-11 22:30 UTC (permalink / raw)
  To: boris.brezillon; +Cc: linux, linux-kernel, richard

I was just browsing LKML history and wanted to understand this
concept, but while reading I think I spotted an error.


+static void nand_pairing_dist3_get_info(struct mtd_info *mtd, int page,
+					struct mtd_pairing_info *info)
+{
+	int lastpage = (mtd->erasesize / mtd->writesize) - 1;
+	int dist = 3;
+
+	if (page == lastpage)
+		dist = 2;
+
+	if (!page || (page & 1)) {
+		info->group = 0;
+		info->pair = (page + 1) / 2;
+	} else {
+		info->group = 1;
+		info->pair = (page + 1 - dist) / 2;
+	}
+}

As I understand this, the general rule is that odd pages i are paired with
even pages i+3, and group = !(i & 1).

If there are N pages total (numbered 0..N-1), this leaves four exceptions
to deal with:

-3 would be apired with 0
-1 would be paired with 2
N-3 would be paired with N
N-1 would be paired with N+2

This is solved by pairing 0 with 2, and N-1 with N-3.

In terms of group addresses, there are only two exceptions:
* 0 is pair 0, group 0 (not pair -1, group 1)
* N-1 is pair N/2/-1, group 1 (not pair N/2, group 0)

You have the first exception correct, but not the second; the condition
detects it, but the change to "dist" doesn't matter since the first half
of the second if() will be taken.


I think the easiest way to get this right is the following:

	page = page + (page != 0) + (page == lastpage);

	info->group = page & 1;
	if (page & 1)
		page -= dist;
	info->pair = page >> 1;

Rather than make up too many rules, this just maps 0 -> -1 and N-1 -> N,
then applies the general rule.

It also applies an offset of +1, to avoid negative numbers and the
problems of signed divides.


Also, a very minor note: divides are expensive.
A cheaper way to evaluate the "page == lastpage" condition is

	if ((page + 1) * mtd->writesize == mtd->erasesize)

(or you could add an mtd->write_per_erase field).


Applying all of this, the corrected code looks like the following:

(Note the addition of "const" and "__pure" annotations, which should
get copied to the "struct mtd_pairing_scheme" declaration.)

Signed-off-by: George Spelvin <linux@sciencehorizons.net>

/*
 * In distance-3 pairing, odd pages i are group 0, and are paired
 * with even pages i+3.  The exceptions are the first page (page 0)
 * and last page (page N-1) in an erase group.  These pair as if
 * they were pages -1 and N, respectively.
 */
static void nand_pairing_dist3_get_info(const struct mtd_info *mtd, int page,
					struct mtd_pairing_info *info)
{
	page += (page != 0) + ((page + 1) * mtd->writesize == mtd->erasesize);

	info->group = page & 1;
	if (page & 1)
		page -= 3;
	info->pair = page >> 1;
}

static int __pure nand_pairing_dist3_get_wunit(const struct mtd_info *mtd,
					const struct mtd_pairing_info *info)
{
	int page = 2 * info->pair + 3 * info->group;

	page -= (page != 0) + (page * mtd->writesize > mtd->erasesize);
	return page;
}

const struct mtd_pairing_scheme dist3_pairing_scheme = {
	.ngroups = 2,
	.get_info = nand_pairing_dist3_get_info,
	.get_wunit = nand_pairing_dist3_get_wunit,
};
EXPORT_SYMBOL_GPL(dist3_pairing_scheme);

/*
 * Distance-6 pairing works like distance-3 pairing, except that pages
 * are taken two at a time.  The lsbit of the page number is chopped off
 * and later re-added as the lsbit of the pair number.
 */
static void nand_pairing_dist6_get_info(const struct mtd_info *mtd, int page,
					struct mtd_pairing_info *info)
{
	bool lsbit = page & 1;

	page >>= 1;
	page += (page != 0) + ((page+1) * 2*mtd->writesize == mtd->erasesize);

	info->group = page & 1;
	if (page & 1)
		page -= 3;
	info->pair = page | lsbit;
}

static int __pure nand_pairing_dist6_get_wunit(const struct mtd_info *mtd,
				       const struct mtd_pairing_info *info)
{
	int page = (info->pair & ~1) + 3 * info->group;

	page -= (page != 0) + (page * 2 * mtd->writesize > mtd->erasesize);
	return 2 * page + (info->pair & 1);
}

const struct mtd_pairing_scheme dist6_pairing_scheme = {
	.ngroups = 2,
	.get_info = nand_pairing_dist6_get_info,
	.get_wunit = nand_pairing_dist6_get_wunit,
};
EXPORT_SYMBOL_GPL(dist6_pairing_scheme);

^ permalink raw reply	[flat|nested] 14+ messages in thread
* [PATCH 0/4] mtd: add support for pairing scheme description
@ 2016-04-25 10:01 Boris Brezillon
  2016-04-25 10:01 ` [PATCH 2/4] mtd: nand: implement two pairing scheme Boris Brezillon
  0 siblings, 1 reply; 14+ messages in thread
From: Boris Brezillon @ 2016-04-25 10:01 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, linux-mtd, David Woodhouse,
	Brian Norris
  Cc: linux-kernel

Hi,

This series is the first step towards reliable MLC/TLC NAND support.
Those patches allows the NAND layer to expose page pairing information
to MTD users.
The plan is to teach UBI about those constraints and let UBI code take
the appropriate precautions when dealing with those multi-level cells
NANDs. The way we'll handle this "paired pages" constraint will be
described soon in a series adapting the UBI layer, so stay tune ;).

Note that this implementation only allows page pairing scheme description
when the NAND has a full-id entry in the nand_ids table.
This should be addressed in some way for ONFI and JEDEC NANDs, though
I'm not sure how to handle this yet.

Best Regards,

Boris

Boris Brezillon (4):
  mtd: introduce the mtd_pairing_scheme concept
  mtd: nand: implement two pairing scheme
  mtd: nand: add a pairing field to nand_flash_dev
  mtd: nand: H27UCG8T2ATR: point to the correct pairing scheme
    implementation

 drivers/mtd/mtdcore.c        | 62 ++++++++++++++++++++++++++++
 drivers/mtd/mtdpart.c        |  1 +
 drivers/mtd/nand/nand_base.c | 97 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/nand_ids.c  |  2 +-
 include/linux/mtd/mtd.h      | 64 +++++++++++++++++++++++++++++
 include/linux/mtd/nand.h     |  5 +++
 6 files changed, 230 insertions(+), 1 deletion(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2016-06-14 20:29 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-11 22:30 [PATCH 2/4] mtd: nand: implement two pairing scheme George Spelvin
2016-06-12  7:20 ` Boris Brezillon
2016-06-12  9:23   ` George Spelvin
2016-06-12 11:11     ` Boris Brezillon
2016-06-12 12:25       ` George Spelvin
2016-06-12 12:42         ` Boris Brezillon
2016-06-12 15:10           ` Boris Brezillon
2016-06-12 20:24           ` George Spelvin
2016-06-12 21:13             ` Boris Brezillon
2016-06-12 21:37               ` Boris Brezillon
2016-06-14  9:07               ` George Spelvin
2016-06-14  9:34                 ` Boris Brezillon
2016-06-14 20:29                 ` Boris Brezillon
  -- strict thread matches above, loose matches on Subject: below --
2016-04-25 10:01 [PATCH 0/4] mtd: add support for pairing scheme description Boris Brezillon
2016-04-25 10:01 ` [PATCH 2/4] mtd: nand: implement two pairing scheme Boris Brezillon

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).