Commit 90f4ad03 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 9b458a26 b27d8946
......@@ -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;
/* 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;
/*
* 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;
/*
* 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;
/*
* 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;
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
......
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