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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user