mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
Raw NAND:
Rockchip NAND controller driver was not checking the timings properly and the introduction of NV-DDR support broke it. The core was also misbehaving in some very specific cases: in case of (unlikely) bitflips in the parameter page, the fallback might have failed as well but for software reasons. Finally, the chosen ECC configuration was no longer properly propagated to upper layers, mostly failing an info message at probe time. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmaCmhsACgkQJWrqGEe9 VoQsIQf+OBYRAEI5q31rPnGQUnt1NFIjbVKdcdTu6fSK3Xb+DcXsPEJrYdh3RFQz tbT+yZ0KzGHxo7e0e+K5SqtlpmBAyT6SZi00jfaag0qgvU8R+px7Okcywc6iIdCX 7lIDnyrMy8kurz6FsJ7I9CvwCUiWOCmJTJbVSfnHvCg8TdfH7Sk2i02aDYyvEbcC YKxGpZTLqwE7DFP0N9IdQ9j3Ke5gZu6+q3HdMpCZp/cDuLOsmStmomykPGDWjxDC K72GqDT/kXqm7T5jHKAlFqm5nirDfqscuwGbiGcgOoM0JKFYicLe/bC2JL2HJr5M ujGxeC379kjRcofm5hny8BWPxb9kuA== =kC92 -----END PGP SIGNATURE----- Merge tag 'mtd/fixes-for-6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux Pull mtd fixes from Miquel Raynal: - Rockchip NAND controller driver was not checking the timings properly and the introduction of NV-DDR support broke it. - The core was also misbehaving in some very specific cases: in case of (unlikely) bitflips in the parameter page, the fallback might have failed as well but for software reasons. - Finally, the chosen ECC configuration was no longer properly propagated to upper layers, mostly failing an info message at probe time. * tag 'mtd/fixes-for-6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: mtd: rawnand: rockchip: ensure NVDDR timings are rejected mtd: rawnand: Bypass a couple of sanity checks during NAND identification mtd: rawnand: Fix the nand_read_data_op() early check mtd: rawnand: Ensure ECC configuration is propagated to upper layers
This commit is contained in:
commit
90f4ad0343
|
|
@ -1093,28 +1093,32 @@ static int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs,
|
|||
unsigned int offset_in_page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
bool ident_stage = !mtd->writesize;
|
||||
|
||||
/* Make sure the offset is less than the actual page size. */
|
||||
if (offset_in_page > mtd->writesize + mtd->oobsize)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* On small page NANDs, there's a dedicated command to access the OOB
|
||||
* area, and the column address is relative to the start of the OOB
|
||||
* area, not the start of the page. Asjust the address accordingly.
|
||||
*/
|
||||
if (mtd->writesize <= 512 && offset_in_page >= mtd->writesize)
|
||||
offset_in_page -= mtd->writesize;
|
||||
|
||||
/*
|
||||
* The offset in page is expressed in bytes, if the NAND bus is 16-bit
|
||||
* wide, then it must be divided by 2.
|
||||
*/
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
if (WARN_ON(offset_in_page % 2))
|
||||
/* Bypass all checks during NAND identification */
|
||||
if (likely(!ident_stage)) {
|
||||
/* Make sure the offset is less than the actual page size. */
|
||||
if (offset_in_page > mtd->writesize + mtd->oobsize)
|
||||
return -EINVAL;
|
||||
|
||||
offset_in_page /= 2;
|
||||
/*
|
||||
* On small page NANDs, there's a dedicated command to access the OOB
|
||||
* area, and the column address is relative to the start of the OOB
|
||||
* area, not the start of the page. Asjust the address accordingly.
|
||||
*/
|
||||
if (mtd->writesize <= 512 && offset_in_page >= mtd->writesize)
|
||||
offset_in_page -= mtd->writesize;
|
||||
|
||||
/*
|
||||
* The offset in page is expressed in bytes, if the NAND bus is 16-bit
|
||||
* wide, then it must be divided by 2.
|
||||
*/
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
if (WARN_ON(offset_in_page % 2))
|
||||
return -EINVAL;
|
||||
|
||||
offset_in_page /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
addrs[0] = offset_in_page;
|
||||
|
|
@ -1123,7 +1127,7 @@ static int nand_fill_column_cycles(struct nand_chip *chip, u8 *addrs,
|
|||
* Small page NANDs use 1 cycle for the columns, while large page NANDs
|
||||
* need 2
|
||||
*/
|
||||
if (mtd->writesize <= 512)
|
||||
if (!ident_stage && mtd->writesize <= 512)
|
||||
return 1;
|
||||
|
||||
addrs[1] = offset_in_page >> 8;
|
||||
|
|
@ -1436,16 +1440,19 @@ int nand_change_read_column_op(struct nand_chip *chip,
|
|||
unsigned int len, bool force_8bit)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
bool ident_stage = !mtd->writesize;
|
||||
|
||||
if (len && !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
|
||||
return -EINVAL;
|
||||
if (!ident_stage) {
|
||||
if (offset_in_page + len > mtd->writesize + mtd->oobsize)
|
||||
return -EINVAL;
|
||||
|
||||
/* Small page NANDs do not support column change. */
|
||||
if (mtd->writesize <= 512)
|
||||
return -ENOTSUPP;
|
||||
/* Small page NANDs do not support column change. */
|
||||
if (mtd->writesize <= 512)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (nand_has_exec_op(chip)) {
|
||||
const struct nand_interface_config *conf =
|
||||
|
|
@ -2173,7 +2180,7 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
|
|||
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
|
||||
bool force_8bit, bool check_only)
|
||||
{
|
||||
if (!len || !buf)
|
||||
if (!len || (!check_only && !buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (nand_has_exec_op(chip)) {
|
||||
|
|
@ -6301,6 +6308,7 @@ static const struct nand_ops rawnand_ops = {
|
|||
static int nand_scan_tail(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_device *base = &chip->base;
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int ret, i;
|
||||
|
||||
|
|
@ -6445,9 +6453,13 @@ static int nand_scan_tail(struct nand_chip *chip)
|
|||
if (!ecc->write_oob_raw)
|
||||
ecc->write_oob_raw = ecc->write_oob;
|
||||
|
||||
/* propagate ecc info to mtd_info */
|
||||
/* Propagate ECC info to the generic NAND and MTD layers */
|
||||
mtd->ecc_strength = ecc->strength;
|
||||
if (!base->ecc.ctx.conf.strength)
|
||||
base->ecc.ctx.conf.strength = ecc->strength;
|
||||
mtd->ecc_step_size = ecc->size;
|
||||
if (!base->ecc.ctx.conf.step_size)
|
||||
base->ecc.ctx.conf.step_size = ecc->size;
|
||||
|
||||
/*
|
||||
* Set the number of read / write steps for one page depending on ECC
|
||||
|
|
@ -6455,6 +6467,8 @@ static int nand_scan_tail(struct nand_chip *chip)
|
|||
*/
|
||||
if (!ecc->steps)
|
||||
ecc->steps = mtd->writesize / ecc->size;
|
||||
if (!base->ecc.ctx.nsteps)
|
||||
base->ecc.ctx.nsteps = ecc->steps;
|
||||
if (ecc->steps * ecc->size != mtd->writesize) {
|
||||
WARN(1, "Invalid ECC parameters\n");
|
||||
ret = -EINVAL;
|
||||
|
|
|
|||
|
|
@ -420,13 +420,13 @@ static int rk_nfc_setup_interface(struct nand_chip *chip, int target,
|
|||
u32 rate, tc2rw, trwpw, trw2c;
|
||||
u32 temp;
|
||||
|
||||
if (target < 0)
|
||||
return 0;
|
||||
|
||||
timings = nand_get_sdr_timings(conf);
|
||||
if (IS_ERR(timings))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (target < 0)
|
||||
return 0;
|
||||
|
||||
if (IS_ERR(nfc->nfc_clk))
|
||||
rate = clk_get_rate(nfc->ahb_clk);
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user