Commit d7904619 authored by Miquel Raynal's avatar Miquel Raynal
Browse files

mtd: rawnand: Add nand_extract_bits()



There are cases where ECC bytes are not byte-aligned. Indeed, BCH
implies using a number of ECC bits, which are not always a multiple of
8. We then need a helper like nand_extract_bits() to extract these
syndromes from a buffer.

Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/linux-mtd/20200519074549.23673-5-miquel.raynal@bootlin.com
parent 0651ed50
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -274,6 +274,50 @@ static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len)
	return ret;
}

/**
 * nand_extract_bits - Copy unaligned bits from one buffer to another one
 * @dst: destination buffer
 * @dst_off: bit offset at which the writing starts
 * @src: source buffer
 * @src_off: bit offset at which the reading starts
 * @nbits: number of bits to copy from @src to @dst
 *
 * Copy bits from one memory region to another (overlap authorized).
 */
void nand_extract_bits(u8 *dst, unsigned int dst_off, const u8 *src,
		       unsigned int src_off, unsigned int nbits)
{
	unsigned int tmp, n;

	dst += dst_off / 8;
	dst_off %= 8;
	src += src_off / 8;
	src_off %= 8;

	while (nbits) {
		n = min3(8 - dst_off, 8 - src_off, nbits);

		tmp = (*src >> src_off) & GENMASK(n - 1, 0);
		*dst &= ~GENMASK(n - 1 + dst_off, dst_off);
		*dst |= tmp << dst_off;

		dst_off += n;
		if (dst_off >= 8) {
			dst++;
			dst_off -= 8;
		}

		src_off += n;
		if (src_off >= 8) {
			src++;
			src_off -= 8;
		}

		nbits -= n;
	}
}
EXPORT_SYMBOL_GPL(nand_extract_bits);

/**
 * nand_select_target() - Select a NAND target (A.K.A. die)
 * @chip: NAND chip object
+4 −0
Original line number Diff line number Diff line
@@ -1414,6 +1414,10 @@ int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
void nand_select_target(struct nand_chip *chip, unsigned int cs);
void nand_deselect_target(struct nand_chip *chip);

/* Bitops */
void nand_extract_bits(u8 *dst, unsigned int dst_off, const u8 *src,
		       unsigned int src_off, unsigned int nbits);

/**
 * nand_get_data_buf() - Get the internal page buffer
 * @chip: NAND chip object