2018-07-20 15:20:20

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 00/35] Allow dynamic allocations during NAND chip identification phase

Hello,

This series make a quite deep change in the NAND framework. Until now,
the NAND chip identification phase could be done in two manners from the
controller driver perspective:

1/ Call nand_scan()

or

1/ Call nand_scan_ident()
2/ Do some controller-dependent configuration
3/ Call nand_scan_tail().

The fact that the identifaction could be split in two operations
involved that in the NAND framework, it was not possible to do any
dynamic allocation without risking a memory leak. What if the core
allocates a structure, then the driver between nand_scan_ident() and
nand_scan_tail() decides it cannot handle the chip and errors out?
The structure allocated by the core is lost: it is a memory leak. One
solution could have been to add a nand_scan_ident_cleanup() function,
but that would mean patching all the drivers anyway to make them call
this function when something fails between nand_scan_ident() and
nand_scan_tail().

To avoid this situation, we migrate all drivers to use nand_scan() in
conjuction with the recently added hooks ->attach_chip() and
->detach_chip() that are part of the nand_controller structure
operations. Drivers that need to tweak their configuration after
nand_scan_ident() should implement it. Any dynamically allocated space
in ->attach_chip() must be freed in the second hook: ->detach_chip().

The ->detach_chip() does not have to be called upon error in the
controller driver probe function. The nand_cleanup() helper already
exists for that and will do the call if needed. Of course, this helper
must be called on error after a successful nand_scan(), just like
before.

Once all drivers not using nand_scan() are migrated, nand_scan_ident()
and nand_scan_tail() are unexported and only available internally.

A previous work [1] removed the ONFI/JEDEC parameter pages and instead
allocated a nand_parameters structure in nand_chip, embedding both
generic entries and ONFI-related ones. The deal was, once dynamic
allocation possible, allocate in nand_scan_ident() the ONFI strcuture
only if actually needed. This is done in the last patches.

This series applies on top of nand/next.

Thank you,
Miquèl

[1] http://lists.infradead.org/pipermail/linux-mtd/2018-March/079456.html

Changes since v3:
=================
* Constified all the nand_controller_ops structure definitions.
* Fixed a build issue in fsl_elbc.
* Added a patch in the core to prevent executing nand_scan_ident if
maxchips is NULL.
* Fixed the regression around the model name.
* Used kstrdup to allocate the model.
* The migration from char model[] to const char *model is done in a
separate patch.

Changes since v2:
=================
* Rebased on top of nand/next.
* Adapted all drivers to declare statically a nand_controller_ops
structure and assign it in the probe().
* Added the migration of the tegra_nand.c driver.
* Moved brcmnand controller ops affectation in the probe().

Changes since v1:
=================
* Rebased on top of nand/next.
* Light rewording of the cover letter about the possibility to have a
nand_scan_ident_cleanup() function (just as example of how this series
could have been done differently).
* Changed the hooks to reside in the nand_hw_ctrl structure instead of
being part of nand_ecc_ctrl as these hooks are more
controller-related.


Miquel Raynal (35):
mtd: rawnand: brcmnand: convert driver to nand_scan()
mtd: rawnand: cafe: convert driver to nand_scan()
mtd: rawnand: davinci: convert driver to nand_scan()
mtd: rawnand: denali: convert to nand_scan()
mtd: rawnand: fsl_elbc: convert driver to nand_scan()
mtd: rawnand: fsl_ifc: convert driver to nand_scan()
mtd: rawnand: fsmc: convert driver to nand_scan()
mtd: rawnand: gpmi: convert driver to nand_scan()
mtd: rawnand: hisi504: convert driver to nand_scan()
mtd: rawnand: jz4780: convert driver to nand_scan()
mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()
mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()
mtd: rawnand: marvell: convert driver to nand_scan()
mtd: rawnand: mtk: convert driver to nand_scan()
mtd: rawnand: mxc: convert driver to nand_scan()
mtd: rawnand: nandsim: convert driver to nand_scan()
mtd: rawnand: omap2: convert driver to nand_scan()
mtd: rawnand: s3c2410: convert driver to nand_scan()
mtd: rawnand: sh_flctl: move all NAND chip related setup in one
function
mtd: rawnand: sh_flctl: convert driver to nand_scan()
mtd: rawnand: sunxi: convert driver to nand_scan()
mtd: rawnand: tango: convert driver to nand_scan()
mtd: rawnand: txx9ndfmc: rename nand controller internal structure
mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
mtd: rawnand: vf610: convert driver to nand_scan()
mtd: rawnand: atmel: convert driver to nand_scan()
mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()
mtd: rawnand: allow exiting immediately nand_scan_ident()
mtd: rawnand: docg4: convert driver to nand_scan()
mtd: rawnand: qcom: convert driver to nand_scan()
mtd: rawnand: jz4740: convert driver to nand_scan()
mtd: rawnand: tegra: convert driver to nand_scan()
mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
mtd: rawnand: allocate model parameter dynamically
mtd: rawnand: allocate dynamically ONFI parameters during detection

drivers/mtd/nand/raw/atmel/nand-controller.c | 83 ++---
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 47 ++-
drivers/mtd/nand/raw/cafe_nand.c | 130 ++++---
drivers/mtd/nand/raw/davinci_nand.c | 195 +++++-----
drivers/mtd/nand/raw/denali.c | 138 +++----
drivers/mtd/nand/raw/docg4.c | 55 +--
drivers/mtd/nand/raw/fsl_elbc_nand.c | 19 +-
drivers/mtd/nand/raw/fsl_ifc_nand.c | 19 +-
drivers/mtd/nand/raw/fsmc_nand.c | 148 ++++----
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 56 +--
drivers/mtd/nand/raw/hisi504_nand.c | 78 ++--
drivers/mtd/nand/raw/jz4740_nand.c | 46 ++-
drivers/mtd/nand/raw/jz4780_nand.c | 34 +-
drivers/mtd/nand/raw/lpc32xx_mlc.c | 109 +++---
drivers/mtd/nand/raw/lpc32xx_slc.c | 77 ++--
drivers/mtd/nand/raw/marvell_nand.c | 205 ++++++-----
drivers/mtd/nand/raw/mtk_nand.c | 75 ++--
drivers/mtd/nand/raw/mxc_nand.c | 136 +++----
drivers/mtd/nand/raw/nand_base.c | 132 +++++--
drivers/mtd/nand/raw/nand_micron.c | 6 +-
drivers/mtd/nand/raw/nand_timings.c | 12 +-
drivers/mtd/nand/raw/nandsim.c | 82 +++--
drivers/mtd/nand/raw/omap2.c | 521 +++++++++++++--------------
drivers/mtd/nand/raw/qcom_nandc.c | 71 ++--
drivers/mtd/nand/raw/s3c2410.c | 30 +-
drivers/mtd/nand/raw/sh_flctl.c | 57 ++-
drivers/mtd/nand/raw/sm_common.c | 39 +-
drivers/mtd/nand/raw/sunxi_nand.c | 43 +--
drivers/mtd/nand/raw/tango_nand.c | 40 +-
drivers/mtd/nand/raw/tegra_nand.c | 162 +++++----
drivers/mtd/nand/raw/txx9ndfmc.c | 35 +-
drivers/mtd/nand/raw/vf610_nfc.c | 127 +++----
include/linux/mtd/rawnand.h | 17 +-
include/linux/mtd/sh_flctl.h | 1 +
34 files changed, 1612 insertions(+), 1413 deletions(-)

--
2.14.1



2018-07-20 15:16:55

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 03/35] mtd: rawnand: davinci: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Also change the unused "struct device *dev" parameter of the driver
structure into a platform device to reuse it in the ->attach_chip()
hook.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/davinci_nand.c | 195 +++++++++++++++++++-----------------
1 file changed, 102 insertions(+), 93 deletions(-)

diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 626c9363e460..40145e206a6b 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -53,7 +53,7 @@
struct davinci_nand_info {
struct nand_chip chip;

- struct device *dev;
+ struct platform_device *pdev;

bool is_readmode;

@@ -605,6 +605,104 @@ static struct davinci_nand_pdata
}
#endif

+static int davinci_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
+ int ret = 0;
+
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ switch (info->chip.ecc.mode) {
+ case NAND_ECC_NONE:
+ pdata->ecc_bits = 0;
+ break;
+ case NAND_ECC_SOFT:
+ pdata->ecc_bits = 0;
+ /*
+ * This driver expects Hamming based ECC when ecc_mode is set
+ * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+ * avoid adding an extra ->ecc_algo field to
+ * davinci_nand_pdata.
+ */
+ info->chip.ecc.algo = NAND_ECC_HAMMING;
+ break;
+ case NAND_ECC_HW:
+ if (pdata->ecc_bits == 4) {
+ /*
+ * No sanity checks: CPUs must support this,
+ * and the chips may not use NAND_BUSWIDTH_16.
+ */
+
+ /* No sharing 4-bit hardware between chipselects yet */
+ spin_lock_irq(&davinci_nand_lock);
+ if (ecc4_busy)
+ ret = -EBUSY;
+ else
+ ecc4_busy = true;
+ spin_unlock_irq(&davinci_nand_lock);
+
+ if (ret == -EBUSY)
+ return ret;
+
+ info->chip.ecc.calculate = nand_davinci_calculate_4bit;
+ info->chip.ecc.correct = nand_davinci_correct_4bit;
+ info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
+ info->chip.ecc.bytes = 10;
+ info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+ info->chip.ecc.algo = NAND_ECC_BCH;
+ } else {
+ /* 1bit ecc hamming */
+ info->chip.ecc.calculate = nand_davinci_calculate_1bit;
+ info->chip.ecc.correct = nand_davinci_correct_1bit;
+ info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
+ info->chip.ecc.bytes = 3;
+ info->chip.ecc.algo = NAND_ECC_HAMMING;
+ }
+ info->chip.ecc.size = 512;
+ info->chip.ecc.strength = pdata->ecc_bits;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Update ECC layout if needed ... for 1-bit HW ECC, the default
+ * is OK, but it allocates 6 bytes when only 3 are needed (for
+ * each 512 bytes). For the 4-bit HW ECC, that default is not
+ * usable: 10 bytes are needed, not 6.
+ */
+ if (pdata->ecc_bits == 4) {
+ int chunks = mtd->writesize / 512;
+
+ if (!chunks || mtd->oobsize < 16) {
+ dev_dbg(&info->pdev->dev, "too small\n");
+ return -EINVAL;
+ }
+
+ /* For small page chips, preserve the manufacturer's
+ * badblock marking data ... and make sure a flash BBT
+ * table marker fits in the free bytes.
+ */
+ if (chunks == 1) {
+ mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
+ } else if (chunks == 4 || chunks == 8) {
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
+ } else {
+ return -EIO;
+ }
+ }
+
+ return ret;
+}
+
+static const struct nand_controller_ops davinci_nand_controller_ops = {
+ .attach_chip = davinci_nand_attach_chip,
+};
+
static int nand_davinci_probe(struct platform_device *pdev)
{
struct davinci_nand_pdata *pdata;
@@ -658,7 +756,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}

- info->dev = &pdev->dev;
+ info->pdev = pdev;
info->base = base;
info->vaddr = vaddr;

@@ -708,97 +806,13 @@ static int nand_davinci_probe(struct platform_device *pdev)
spin_unlock_irq(&davinci_nand_lock);

/* Scan to find existence of the device(s) */
- ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+ info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
+ ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
return ret;
}

- switch (info->chip.ecc.mode) {
- case NAND_ECC_NONE:
- pdata->ecc_bits = 0;
- break;
- case NAND_ECC_SOFT:
- pdata->ecc_bits = 0;
- /*
- * This driver expects Hamming based ECC when ecc_mode is set
- * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
- * avoid adding an extra ->ecc_algo field to
- * davinci_nand_pdata.
- */
- info->chip.ecc.algo = NAND_ECC_HAMMING;
- break;
- case NAND_ECC_HW:
- if (pdata->ecc_bits == 4) {
- /* No sanity checks: CPUs must support this,
- * and the chips may not use NAND_BUSWIDTH_16.
- */
-
- /* No sharing 4-bit hardware between chipselects yet */
- spin_lock_irq(&davinci_nand_lock);
- if (ecc4_busy)
- ret = -EBUSY;
- else
- ecc4_busy = true;
- spin_unlock_irq(&davinci_nand_lock);
-
- if (ret == -EBUSY)
- return ret;
-
- info->chip.ecc.calculate = nand_davinci_calculate_4bit;
- info->chip.ecc.correct = nand_davinci_correct_4bit;
- info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
- info->chip.ecc.bytes = 10;
- info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
- info->chip.ecc.algo = NAND_ECC_BCH;
- } else {
- /* 1bit ecc hamming */
- info->chip.ecc.calculate = nand_davinci_calculate_1bit;
- info->chip.ecc.correct = nand_davinci_correct_1bit;
- info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
- info->chip.ecc.bytes = 3;
- info->chip.ecc.algo = NAND_ECC_HAMMING;
- }
- info->chip.ecc.size = 512;
- info->chip.ecc.strength = pdata->ecc_bits;
- break;
- default:
- return -EINVAL;
- }
-
- /* Update ECC layout if needed ... for 1-bit HW ECC, the default
- * is OK, but it allocates 6 bytes when only 3 are needed (for
- * each 512 bytes). For the 4-bit HW ECC, that default is not
- * usable: 10 bytes are needed, not 6.
- */
- if (pdata->ecc_bits == 4) {
- int chunks = mtd->writesize / 512;
-
- if (!chunks || mtd->oobsize < 16) {
- dev_dbg(&pdev->dev, "too small\n");
- ret = -EINVAL;
- goto err;
- }
-
- /* For small page chips, preserve the manufacturer's
- * badblock marking data ... and make sure a flash BBT
- * table marker fits in the free bytes.
- */
- if (chunks == 1) {
- mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
- } else if (chunks == 4 || chunks == 8) {
- mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
- info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
- } else {
- ret = -EIO;
- goto err;
- }
- }
-
- ret = nand_scan_tail(mtd);
- if (ret < 0)
- goto err;
-
if (pdata->parts)
ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
else
@@ -815,11 +829,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
err_cleanup_nand:
nand_cleanup(&info->chip);

-err:
- spin_lock_irq(&davinci_nand_lock);
- if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
- ecc4_busy = false;
- spin_unlock_irq(&davinci_nand_lock);
return ret;
}

--
2.14.1


2018-07-20 15:17:02

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/denali.c | 138 +++++++++++++++++++++++-------------------
1 file changed, 77 insertions(+), 61 deletions(-)

diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index 4d53f41ada08..2fa92c297a66 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1205,62 +1205,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
return 0;
}

-int denali_init(struct denali_nand_info *denali)
+static int denali_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
- u32 features = ioread32(denali->reg + FEATURES);
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
int ret;

- mtd->dev.parent = denali->dev;
- denali_hw_init(denali);
-
- init_completion(&denali->complete);
- spin_lock_init(&denali->irq_lock);
-
- denali_clear_irq_all(denali);
-
- ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
- IRQF_SHARED, DENALI_NAND_NAME, denali);
- if (ret) {
- dev_err(denali->dev, "Unable to request IRQ\n");
- return ret;
- }
-
- denali_enable_irq(denali);
- denali_reset_banks(denali);
-
- denali->active_bank = DENALI_INVALID_BANK;
-
- nand_set_flash_node(chip, denali->dev->of_node);
- /* Fallback to the default name if DT did not give "label" property */
- if (!mtd->name)
- mtd->name = "denali-nand";
-
- chip->select_chip = denali_select_chip;
- chip->read_byte = denali_read_byte;
- chip->write_byte = denali_write_byte;
- chip->read_word = denali_read_word;
- chip->cmd_ctrl = denali_cmd_ctrl;
- chip->dev_ready = denali_dev_ready;
- chip->waitfunc = denali_waitfunc;
-
- if (features & FEATURES__INDEX_ADDR) {
- denali->host_read = denali_indexed_read;
- denali->host_write = denali_indexed_write;
- } else {
- denali->host_read = denali_direct_read;
- denali->host_write = denali_direct_write;
- }
-
- /* clk rate info is needed for setup_data_interface */
- if (denali->clk_rate && denali->clk_x_rate)
- chip->setup_data_interface = denali_setup_data_interface;
-
- ret = nand_scan_ident(mtd, denali->max_banks, NULL);
- if (ret)
- goto disable_irq;
-
if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
denali->dma_avail = 1;

@@ -1293,7 +1243,7 @@ int denali_init(struct denali_nand_info *denali)
mtd->oobsize - denali->oob_skip_bytes);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
- goto disable_irq;
+ return ret;
}

dev_dbg(denali->dev,
@@ -1337,7 +1287,7 @@ int denali_init(struct denali_nand_info *denali)

ret = denali_multidev_fixup(denali);
if (ret)
- goto disable_irq;
+ return ret;

/*
* This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
@@ -1345,26 +1295,92 @@ int denali_init(struct denali_nand_info *denali)
* guarantee DMA-safe alignment.
*/
denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- if (!denali->buf) {
- ret = -ENOMEM;
- goto disable_irq;
+ if (!denali->buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void denali_detach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+ kfree(denali->buf);
+}
+
+static const struct nand_controller_ops denali_controller_ops = {
+ .attach_chip = denali_attach_chip,
+ .detach_chip = denali_detach_chip,
+};
+
+int denali_init(struct denali_nand_info *denali)
+{
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ u32 features = ioread32(denali->reg + FEATURES);
+ int ret;
+
+ mtd->dev.parent = denali->dev;
+ denali_hw_init(denali);
+
+ init_completion(&denali->complete);
+ spin_lock_init(&denali->irq_lock);
+
+ denali_clear_irq_all(denali);
+
+ ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+ IRQF_SHARED, DENALI_NAND_NAME, denali);
+ if (ret) {
+ dev_err(denali->dev, "Unable to request IRQ\n");
+ return ret;
+ }
+
+ denali_enable_irq(denali);
+ denali_reset_banks(denali);
+
+ denali->active_bank = DENALI_INVALID_BANK;
+
+ nand_set_flash_node(chip, denali->dev->of_node);
+ /* Fallback to the default name if DT did not give "label" property */
+ if (!mtd->name)
+ mtd->name = "denali-nand";
+
+ chip->select_chip = denali_select_chip;
+ chip->read_byte = denali_read_byte;
+ chip->write_byte = denali_write_byte;
+ chip->read_word = denali_read_word;
+ chip->cmd_ctrl = denali_cmd_ctrl;
+ chip->dev_ready = denali_dev_ready;
+ chip->waitfunc = denali_waitfunc;
+
+ if (features & FEATURES__INDEX_ADDR) {
+ denali->host_read = denali_indexed_read;
+ denali->host_write = denali_indexed_write;
+ } else {
+ denali->host_read = denali_direct_read;
+ denali->host_write = denali_direct_write;
}

- ret = nand_scan_tail(mtd);
+ /* clk rate info is needed for setup_data_interface */
+ if (denali->clk_rate && denali->clk_x_rate)
+ chip->setup_data_interface = denali_setup_data_interface;
+
+ chip->dummy_controller.ops = &denali_controller_ops;
+ ret = nand_scan(mtd, denali->max_banks);
if (ret)
- goto free_buf;
+ goto disable_irq;

ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto cleanup_nand;
}
+
return 0;

cleanup_nand:
nand_cleanup(chip);
-free_buf:
- kfree(denali->buf);
disable_irq:
denali_disable_irq(denali);

--
2.14.1


2018-07-20 15:17:06

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 12/35] mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/lpc32xx_slc.c | 77 +++++++++++++++++++++-----------------
1 file changed, 42 insertions(+), 35 deletions(-)

diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index 42820aa1abab..a4e8b7e75135 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -779,6 +779,46 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}

+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+ /* OOB and ECC CPU and DMA work areas */
+ host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+ /*
+ * Small page FLASH has a unique OOB layout, but large and huge
+ * page FLASH use the standard layout. Small page FLASH uses a
+ * custom BBT marker layout.
+ */
+ if (mtd->writesize <= 512)
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+
+ /* These sizes remain the same regardless of page size */
+ chip->ecc.size = 256;
+ chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+ chip->ecc.prepad = 0;
+ chip->ecc.postpad = 0;
+
+ /*
+ * Use a custom BBT marker setup for small page FLASH that
+ * won't interfere with the ECC layout. Large and huge page
+ * FLASH use the standard layout.
+ */
+ if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+ mtd->writesize <= 512) {
+ chip->bbt_td = &bbt_smallpage_main_descr;
+ chip->bbt_md = &bbt_smallpage_mirror_descr;
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
+ .attach_chip = lpc32xx_nand_attach_chip,
+};
+
/*
* Probe for NAND controller
*/
@@ -884,41 +924,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}

/* Find NAND device */
- res = nand_scan_ident(mtd, 1, NULL);
- if (res)
- goto release_dma;
-
- /* OOB and ECC CPU and DMA work areas */
- host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
-
- /*
- * Small page FLASH has a unique OOB layout, but large and huge
- * page FLASH use the standard layout. Small page FLASH uses a
- * custom BBT marker layout.
- */
- if (mtd->writesize <= 512)
- mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-
- /* These sizes remain the same regardless of page size */
- chip->ecc.size = 256;
- chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
- chip->ecc.prepad = chip->ecc.postpad = 0;
-
- /*
- * Use a custom BBT marker setup for small page FLASH that
- * won't interfere with the ECC layout. Large and huge page
- * FLASH use the standard layout.
- */
- if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
- mtd->writesize <= 512) {
- chip->bbt_td = &bbt_smallpage_main_descr;
- chip->bbt_md = &bbt_smallpage_mirror_descr;
- }
-
- /*
- * Fills out all the uninitialized function pointers with the defaults
- */
- res = nand_scan_tail(mtd);
+ chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+ res = nand_scan(mtd, 1);
if (res)
goto release_dma;

--
2.14.1


2018-07-20 15:17:28

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 35/35] mtd: rawnand: allocate dynamically ONFI parameters during detection

Now that it is possible to do dynamic allocations during the
identification phase, convert the onfi_params structure (which is only
needed with ONFI compliant chips) into a pointer that will be allocated
only if needed.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/nand_base.c | 54 +++++++++++++++++++++++--------------
drivers/mtd/nand/raw/nand_micron.c | 6 ++---
drivers/mtd/nand/raw/nand_timings.c | 12 ++++-----
include/linux/mtd/rawnand.h | 6 ++---
4 files changed, 46 insertions(+), 32 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 8645f655e5b0..ed9e2f1578e6 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5151,6 +5151,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p;
+ struct onfi_params *onfi;
+ int onfi_version = 0;
char id[4];
int i, ret, val;

@@ -5206,21 +5208,19 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
/* Check version */
val = le16_to_cpu(p->revision);
if (val & ONFI_VERSION_2_3)
- chip->parameters.onfi.version = 23;
+ onfi_version = 23;
else if (val & ONFI_VERSION_2_2)
- chip->parameters.onfi.version = 22;
+ onfi_version = 22;
else if (val & ONFI_VERSION_2_1)
- chip->parameters.onfi.version = 21;
+ onfi_version = 21;
else if (val & ONFI_VERSION_2_0)
- chip->parameters.onfi.version = 20;
+ onfi_version = 20;
else if (val & ONFI_VERSION_1_0)
- chip->parameters.onfi.version = 10;
+ onfi_version = 10;

- if (!chip->parameters.onfi.version) {
+ if (!onfi_version) {
pr_info("unsupported ONFI version: %d\n", val);
goto free_onfi_param_page;
- } else {
- ret = 1;
}

sanitize_string(p->manufacturer, sizeof(p->manufacturer));
@@ -5257,7 +5257,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
chip->ecc_step_ds = 512;
- } else if (chip->parameters.onfi.version >= 21 &&
+ } else if (onfi_version >= 21 &&
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {

/*
@@ -5284,19 +5284,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
}
- chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
- chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
- chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
- chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
- chip->parameters.onfi.async_timing_mode =
- le16_to_cpu(p->async_timing_mode);
- chip->parameters.onfi.vendor_revision =
- le16_to_cpu(p->vendor_revision);
- memcpy(chip->parameters.onfi.vendor, p->vendor,
- sizeof(p->vendor));

+ onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+ if (!onfi) {
+ ret = -ENOMEM;
+ goto free_model;
+ }
+
+ onfi->version = onfi_version;
+ onfi->tPROG = le16_to_cpu(p->t_prog);
+ onfi->tBERS = le16_to_cpu(p->t_bers);
+ onfi->tR = le16_to_cpu(p->t_r);
+ onfi->tCCS = le16_to_cpu(p->t_ccs);
+ onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+ onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
+ memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+ chip->parameters.onfi = onfi;
+
+ /* Identification done, free the full ONFI parameter page and exit */
+ kfree(p);
+
+ return 1;
+
+free_model:
+ kfree(chip->parameters.model);
free_onfi_param_page:
kfree(p);
+
return ret;
}

@@ -5693,7 +5707,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
}
}

- chip->parameters.onfi.version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
ret = nand_flash_detect_onfi(chip);
@@ -6039,6 +6052,7 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
static void nand_scan_ident_cleanup(struct nand_chip *chip)
{
kfree(chip->parameters.model);
+ kfree(chip->parameters.onfi);
}

static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index 656947d91841..8466a1740b3b 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -88,9 +88,9 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
static int micron_nand_onfi_init(struct nand_chip *chip)
{
struct nand_parameters *p = &chip->parameters;
- struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
+ struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;

- if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
+ if (p->onfi && p->onfi->vendor_revision) {
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry;
}
@@ -382,7 +382,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
u8 id[5];
int ret;

- if (!chip->parameters.onfi.version)
+ if (!chip->parameters.onfi)
return MICRON_ON_DIE_UNSUPPORTED;

if (chip->bits_per_cell != 1)
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index 9bb599106a31..ebc7b5f76f77 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -294,6 +294,7 @@ int onfi_fill_data_interface(struct nand_chip *chip,
int timing_mode)
{
struct nand_data_interface *iface = &chip->data_interface;
+ struct onfi_params *onfi = chip->parameters.onfi;

if (type != NAND_SDR_IFACE)
return -EINVAL;
@@ -308,17 +309,16 @@ int onfi_fill_data_interface(struct nand_chip *chip,
* tPROG, tBERS, tR and tCCS.
* These information are part of the ONFI parameter page.
*/
- if (chip->parameters.onfi.version) {
- struct nand_parameters *params = &chip->parameters;
+ if (onfi) {
struct nand_sdr_timings *timings = &iface->timings.sdr;

/* microseconds -> picoseconds */
- timings->tPROG_max = 1000000ULL * params->onfi.tPROG;
- timings->tBERS_max = 1000000ULL * params->onfi.tBERS;
- timings->tR_max = 1000000ULL * params->onfi.tR;
+ timings->tPROG_max = 1000000ULL * onfi->tPROG;
+ timings->tBERS_max = 1000000ULL * onfi->tBERS;
+ timings->tR_max = 1000000ULL * onfi->tR;

/* nanoseconds -> picoseconds */
- timings->tCCS_min = 1000UL * params->onfi.tCCS;
+ timings->tCCS_min = 1000UL * onfi->tCCS;
} else {
struct nand_sdr_timings *timings = &iface->timings.sdr;
/*
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 5723d940a47d..8074cbd4e3fe 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -488,7 +488,7 @@ struct nand_parameters {
DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);

/* ONFI parameters */
- struct onfi_params onfi;
+ struct onfi_params *onfi;
};

/* The maximum expected count of bytes in the NAND ID sequence */
@@ -1618,10 +1618,10 @@ struct platform_nand_data {
/* return the supported asynchronous timing mode. */
static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
{
- if (!chip->parameters.onfi.version)
+ if (!chip->parameters.onfi)
return ONFI_TIMING_MODE_UNKNOWN;

- return chip->parameters.onfi.async_timing_mode;
+ return chip->parameters.onfi->async_timing_mode;
}

int onfi_fill_data_interface(struct nand_chip *chip,
--
2.14.1


2018-07-20 15:17:33

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 33/35] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore

Both nand_scan_ident() and nand_scan_tail() helpers used to be called
directly from controller drivers that needed to tweak some ECC-related
parameters before nand_scan_tail(). This separation prevented dynamic
allocations during the phase of NAND identification, which was
inconvenient.

All controller drivers have been moved to use nand_scan(), in
conjunction with the chip->ecc.[attach|detach]_chip() hooks that
actually do the required tweaking sequence between both ident/tail
calls, allowing programmers to use dynamic allocation as they need all
across the scanning sequence.

Declare nand_scan_[ident|tail]() statically now.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/nand_base.c | 16 +++++++++-------
include/linux/mtd/rawnand.h | 9 ++-------
2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index e7f135c100c2..da99232702a4 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5924,7 +5924,7 @@ static int nand_dt_init(struct nand_chip *chip)
}

/**
- * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * nand_scan_ident - Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for, returns immediately if 0
* @table: alternative NAND ID table
@@ -5932,9 +5932,13 @@ static int nand_dt_init(struct nand_chip *chip)
* This is the first phase of the normal nand_scan() function. It reads the
* flash ID and sets up MTD fields accordingly.
*
+ * This helper used to be called directly from controller drivers that needed
+ * to tweak some ECC-related parameters before nand_scan_tail(). This separation
+ * prevented dynamic allocations during this phase which was unconvenient and
+ * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
*/
-int nand_scan_ident(struct mtd_info *mtd, int maxchips,
- struct nand_flash_dev *table)
+static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+ struct nand_flash_dev *table)
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
@@ -6016,7 +6020,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,

return 0;
}
-EXPORT_SYMBOL(nand_scan_ident);

static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
{
@@ -6393,14 +6396,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
}

/**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * nand_scan_tail - Scan for the NAND device
* @mtd: MTD device structure
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
-int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -6724,7 +6727,6 @@ int nand_scan_tail(struct mtd_info *mtd)

return ret;
}
-EXPORT_SYMBOL(nand_scan_tail);

static int nand_attach(struct nand_chip *chip)
{
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index a20c78e25878..a928771a7ae4 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -36,14 +36,9 @@ static inline int nand_scan(struct mtd_info *mtd, int max_chips)
}

/*
- * Separate phases of nand_scan(), allowing board driver to intervene
- * and override command or ECC setup according to flash type.
+ * Unregister the MTD device and free resources held by the NAND device, must be
+ * called on error after a successful nand_scan().
*/
-int nand_scan_ident(struct mtd_info *mtd, int max_chips,
- struct nand_flash_dev *table);
-int nand_scan_tail(struct mtd_info *mtd);
-
-/* Unregister the MTD device and free resources held by the NAND device */
void nand_release(struct mtd_info *mtd);

/* Internal helper for board drivers which need to override command function */
--
2.14.1


2018-07-20 15:17:41

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 10/35] mtd: rawnand: jz4780: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
Acked-by: Harvey Hunt <[email protected]>
---
drivers/mtd/nand/raw/jz4780_nand.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
index 49841dad347c..db4fa60bd52a 100644
--- a/drivers/mtd/nand/raw/jz4780_nand.c
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -158,9 +158,8 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
}

-static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
+static int jz4780_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
int eccbytes;
@@ -171,7 +170,8 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
switch (chip->ecc.mode) {
case NAND_ECC_HW:
if (!nfc->bch) {
- dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+ dev_err(nfc->dev,
+ "HW BCH selected, but BCH controller not found\n");
return -ENODEV;
}

@@ -180,15 +180,16 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
chip->ecc.correct = jz4780_nand_ecc_correct;
/* fall through */
case NAND_ECC_SOFT:
- dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
- (nfc->bch) ? "hardware BCH" : "software ECC",
- chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+ dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
+ (nfc->bch) ? "hardware BCH" : "software ECC",
+ chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
break;
case NAND_ECC_NONE:
- dev_info(dev, "not using ECC\n");
+ dev_info(nfc->dev, "not using ECC\n");
break;
default:
- dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+ dev_err(nfc->dev, "ECC mode %d not supported\n",
+ chip->ecc.mode);
return -EINVAL;
}

@@ -200,7 +201,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;

if (eccbytes > mtd->oobsize - 2) {
- dev_err(dev,
+ dev_err(nfc->dev,
"invalid ECC config: required %d ECC bytes, but only %d are available",
eccbytes, mtd->oobsize - 2);
return -EINVAL;
@@ -211,6 +212,10 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
return 0;
}

+static const struct nand_controller_ops jz4780_nand_controller_ops = {
+ .attach_chip = jz4780_nand_attach_chip,
+};
+
static int jz4780_nand_init_chip(struct platform_device *pdev,
struct jz4780_nand_controller *nfc,
struct device_node *np,
@@ -280,15 +285,8 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
chip->controller = &nfc->controller;
nand_set_flash_node(chip, np);

- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
- ret = jz4780_nand_init_ecc(nand, dev);
- if (ret)
- return ret;
-
- ret = nand_scan_tail(mtd);
+ chip->controller->ops = &jz4780_nand_controller_ops;
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;

--
2.14.1


2018-07-20 15:17:49

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 27/35] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan_with_ids()
(alternative to nand_scan() for passing a flash IDs table) instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/sm_common.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index 7f5044a79f01..d05e3f976a5e 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
{NULL}
};

-int sm_register_device(struct mtd_info *mtd, int smartmedia)
+static int sm_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
-
- chip->options |= NAND_SKIP_BBTSCAN;
-
- /* Scan for card properties */
- ret = nand_scan_ident(mtd, 1, smartmedia ?
- nand_smartmedia_flash_ids : nand_xd_flash_ids);
-
- if (ret)
- return ret;
+ struct mtd_info *mtd = nand_to_mtd(chip);

/* Bad block marker position */
chip->badblockpos = 0x05;
@@ -187,12 +177,33 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
else
return -ENODEV;

- ret = nand_scan_tail(mtd);
+ return 0;
+}

+static const struct nand_controller_ops sm_controller_ops = {
+ .attach_chip = sm_attach_chip,
+};
+
+int sm_register_device(struct mtd_info *mtd, int smartmedia)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_flash_dev *flash_ids;
+ int ret;
+
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ /* Scan for card properties */
+ chip->dummy_controller.ops = &sm_controller_ops;
+ flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
+ ret = nand_scan_with_ids(mtd, 1, flash_ids);
if (ret)
return ret;

- return mtd_device_register(mtd, NULL, 0);
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret)
+ nand_release(mtd);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(sm_register_device);

--
2.14.1


2018-07-20 15:17:54

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 21/35] mtd: rawnand: sunxi: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/sunxi_nand.c | 43 +++++++++++++++++----------------------
1 file changed, 19 insertions(+), 24 deletions(-)

diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 07f3ff9a28f2..a4d23381003d 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1816,12 +1816,21 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
}
}

-static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
- struct device_node *np)
+static int sunxi_nand_attach_chip(struct nand_chip *nand)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
+ struct nand_ecc_ctrl *ecc = &nand->ecc;
+ struct device_node *np = nand_get_flash_node(nand);
int ret;

+ if (nand->bbt_options & NAND_BBT_USE_FLASH)
+ nand->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (nand->options & NAND_NEED_SCRAMBLING)
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+ nand->options |= NAND_SUBPAGE_READ;
+
if (!ecc->size) {
ecc->size = nand->ecc_step_ds;
ecc->strength = nand->ecc_strength_ds;
@@ -1846,6 +1855,10 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
return 0;
}

+static const struct nand_controller_ops sunxi_nand_controller_ops = {
+ .attach_chip = sunxi_nand_attach_chip,
+};
+
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
@@ -1911,6 +1924,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
nand->chip_delay = 200;
nand->controller = &nfc->controller;
+ nand->controller->ops = &sunxi_nand_controller_ops;
+
/*
* Set the ECC mode to the default value in case nothing is specified
* in the DT.
@@ -1927,30 +1942,10 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;

- ret = nand_scan_ident(mtd, nsels, NULL);
+ ret = nand_scan(mtd, nsels);
if (ret)
return ret;

- if (nand->bbt_options & NAND_BBT_USE_FLASH)
- nand->bbt_options |= NAND_BBT_NO_OOB;
-
- if (nand->options & NAND_NEED_SCRAMBLING)
- nand->options |= NAND_NO_SUBPAGE_WRITE;
-
- nand->options |= NAND_SUBPAGE_READ;
-
- ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
- if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
- return ret;
- }
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
- return ret;
- }
-
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
--
2.14.1


2018-07-20 15:17:56

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 24/35] mtd: rawnand: txx9ndfmc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/txx9ndfmc.c | 29 +++++++++++++++--------------
1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 9019022774f7..0134beb1136d 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -254,23 +254,23 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)

-static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
+static int txx9ndfmc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
+ struct mtd_info *mtd = nand_to_mtd(chip);

- ret = nand_scan_ident(mtd, 1, NULL);
- if (!ret) {
- if (mtd->writesize >= 512) {
- /* Hardware ECC 6 byte ECC per 512 Byte data */
- chip->ecc.size = 512;
- chip->ecc.bytes = 6;
- }
- ret = nand_scan_tail(mtd);
+ if (mtd->writesize >= 512) {
+ /* Hardware ECC 6 byte ECC per 512 Byte data */
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 6;
}
- return ret;
+
+ return 0;
}

+static const struct nand_controller_ops txx9ndfmc_controller_ops = {
+ .attach_chip = txx9ndfmc_attach_chip,
+};
+
static int __init txx9ndfmc_probe(struct platform_device *dev)
{
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -304,6 +304,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
(gbusclk + 500000) / 1000000, hold, spw);

nand_controller_init(&drvdata->controller);
+ drvdata->controller.ops = &txx9ndfmc_controller_ops;

platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
@@ -332,7 +333,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->ecc.correct = txx9ndfmc_correct_data;
chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
chip->ecc.mode = NAND_ECC_HW;
- /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
+ /* nand_scan() will overwrite ecc.size and ecc.bytes */
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
@@ -359,7 +360,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (plat->wide_mask & (1 << i))
chip->options |= NAND_BUSWIDTH_16;

- if (txx9ndfmc_nand_scan(mtd)) {
+ if (nand_scan(mtd, 1)) {
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
continue;
--
2.14.1


2018-07-20 15:17:58

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 25/35] mtd: rawnand: vf610: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/vf610_nfc.c | 127 ++++++++++++++++++++-------------------
1 file changed, 66 insertions(+), 61 deletions(-)

diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index d5a22fc96878..6f6dcbf9095b 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -747,6 +747,69 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
}
}

+static int vf610_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+ vf610_nfc_init_controller(nfc);
+
+ /* Bad block options. */
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ /* Single buffer only, max 256 OOB minus ECC status */
+ if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+ dev_err(nfc->dev, "Unsupported flash page size\n");
+ return -ENXIO;
+ }
+
+ if (chip->ecc.mode != NAND_ECC_HW)
+ return 0;
+
+ if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+ dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+ return -ENXIO;
+ }
+
+ if (chip->ecc.size != mtd->writesize) {
+ dev_err(nfc->dev, "Step size needs to be page size\n");
+ return -ENXIO;
+ }
+
+ /* Only 64 byte ECC layouts known */
+ if (mtd->oobsize > 64)
+ mtd->oobsize = 64;
+
+ /* Use default large page ECC layout defined in NAND core */
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ if (chip->ecc.strength == 32) {
+ nfc->ecc_mode = ECC_60_BYTE;
+ chip->ecc.bytes = 60;
+ } else if (chip->ecc.strength == 24) {
+ nfc->ecc_mode = ECC_45_BYTE;
+ chip->ecc.bytes = 45;
+ } else {
+ dev_err(nfc->dev, "Unsupported ECC strength\n");
+ return -ENXIO;
+ }
+
+ chip->ecc.read_page = vf610_nfc_read_page;
+ chip->ecc.write_page = vf610_nfc_write_page;
+ chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
+ chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
+ chip->ecc.read_oob = vf610_nfc_read_oob;
+ chip->ecc.write_oob = vf610_nfc_write_oob;
+
+ chip->ecc.size = PAGE_2K;
+
+ return 0;
+}
+
+static const struct nand_controller_ops vf610_nfc_controller_ops = {
+ .attach_chip = vf610_nfc_attach_chip,
+};
+
static int vf610_nfc_probe(struct platform_device *pdev)
{
struct vf610_nfc *nfc;
@@ -827,67 +890,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)

vf610_nfc_preinit_controller(nfc);

- /* first scan to find the device and get the page size */
- err = nand_scan_ident(mtd, 1, NULL);
- if (err)
- goto err_disable_clk;
-
- vf610_nfc_init_controller(nfc);
-
- /* Bad block options. */
- if (chip->bbt_options & NAND_BBT_USE_FLASH)
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- /* Single buffer only, max 256 OOB minus ECC status */
- if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
- dev_err(nfc->dev, "Unsupported flash page size\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- if (chip->ecc.mode == NAND_ECC_HW) {
- if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
- dev_err(nfc->dev, "Unsupported flash with hwecc\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- if (chip->ecc.size != mtd->writesize) {
- dev_err(nfc->dev, "Step size needs to be page size\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- /* Only 64 byte ECC layouts known */
- if (mtd->oobsize > 64)
- mtd->oobsize = 64;
-
- /* Use default large page ECC layout defined in NAND core */
- mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
- if (chip->ecc.strength == 32) {
- nfc->ecc_mode = ECC_60_BYTE;
- chip->ecc.bytes = 60;
- } else if (chip->ecc.strength == 24) {
- nfc->ecc_mode = ECC_45_BYTE;
- chip->ecc.bytes = 45;
- } else {
- dev_err(nfc->dev, "Unsupported ECC strength\n");
- err = -ENXIO;
- goto err_disable_clk;
- }
-
- chip->ecc.read_page = vf610_nfc_read_page;
- chip->ecc.write_page = vf610_nfc_write_page;
- chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
- chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
- chip->ecc.read_oob = vf610_nfc_read_oob;
- chip->ecc.write_oob = vf610_nfc_write_oob;
-
- chip->ecc.size = PAGE_2K;
- }
-
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ /* Scan the NAND chip */
+ chip->dummy_controller.ops = &vf610_nfc_controller_ops;
+ err = nand_scan(mtd, 1);
if (err)
goto err_disable_clk;

--
2.14.1


2018-07-20 15:17:59

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 26/35] mtd: rawnand: atmel: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/atmel/nand-controller.c | 83 ++++++++++++++--------------
1 file changed, 40 insertions(+), 43 deletions(-)

diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 855cc7729c43..0bc7e2abc885 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -202,7 +202,7 @@ struct atmel_nand_controller_ops {
int (*remove)(struct atmel_nand_controller *nc);
void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand);
- int (*ecc_init)(struct atmel_nand *nand);
+ int (*ecc_init)(struct nand_chip *chip);
int (*setup_data_interface)(struct atmel_nand *nand, int csline,
const struct nand_data_interface *conf);
};
@@ -1133,9 +1133,8 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
return 0;
}

-static int atmel_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_nand_ecc_init(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->base;
struct atmel_nand_controller *nc;
int ret;

@@ -1170,12 +1169,11 @@ static int atmel_nand_ecc_init(struct atmel_nand *nand)
return 0;
}

-static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
{
- struct nand_chip *chip = &nand->base;
int ret;

- ret = atmel_nand_ecc_init(nand);
+ ret = atmel_nand_ecc_init(chip);
if (ret)
return ret;

@@ -1558,22 +1556,6 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
chip->select_chip = atmel_hsmc_nand_select_chip;
}

-static int atmel_nand_detect(struct atmel_nand *nand)
-{
- struct nand_chip *chip = &nand->base;
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct atmel_nand_controller *nc;
- int ret;
-
- nc = to_nand_controller(chip->controller);
-
- ret = nand_scan_ident(mtd, nand->numcs, NULL);
- if (ret)
- dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
-
- return ret;
-}
-
static int atmel_nand_unregister(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
@@ -1595,7 +1577,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
- int ret;

nc = to_nand_controller(chip->controller);

@@ -1626,21 +1607,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
}
}

- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
- return ret;
- }
-
- ret = mtd_device_register(mtd, NULL, 0);
- if (ret) {
- dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
- nand_cleanup(chip);
- return ret;
- }
-
- list_add_tail(&nand->node, &nc->chips);
-
return 0;
}

@@ -1755,6 +1721,8 @@ static int
atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
+ struct nand_chip *chip = &nand->base;
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;

/* No card inserted, skip this NAND. */
@@ -1765,15 +1733,30 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,

nc->caps->ops->nand_init(nc, nand);

- ret = atmel_nand_detect(nand);
- if (ret)
+ ret = nand_scan(mtd, nand->numcs);
+ if (ret) {
+ dev_err(nc->dev, "NAND scan failed: %d\n", ret);
return ret;
+ }

- ret = nc->caps->ops->ecc_init(nand);
+ ret = atmel_nand_register(nand);
if (ret)
- return ret;
+ goto cleanup_nand;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
+ goto cleanup_nand;
+ }
+
+ list_add_tail(&nand->node, &nc->chips);
+
+ return 0;
+
+cleanup_nand:
+ nand_cleanup(chip);

- return atmel_nand_register(nand);
+ return ret;
}

static int
@@ -1958,6 +1941,19 @@ static const struct of_device_id atmel_matrix_of_ids[] = {
{ /* sentinel */ },
};

+static int atmel_nand_attach_chip(struct nand_chip *chip)
+{
+ struct atmel_nand_controller *nc;
+
+ nc = to_nand_controller(chip->controller);
+
+ return nc->caps->ops->ecc_init(chip);
+}
+
+static const struct nand_controller_ops atmel_nand_controller_ops = {
+ .attach_chip = atmel_nand_attach_chip,
+};
+
static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps)
@@ -1967,6 +1963,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
int ret;

nand_controller_init(&nc->base);
+ nc->base.ops = &atmel_nand_controller_ops;
INIT_LIST_HEAD(&nc->chips);
nc->dev = dev;
nc->caps = caps;
--
2.14.1


2018-07-20 15:18:20

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 34/35] mtd: rawnand: allocate model parameter dynamically

Thanks to the migration of all drivers to use nand_scan() and the
related nand_controller_ops, we can now allocate data during the
detection phase. Let's do it first for the NAND model parameter which
is allocated in nand_detect().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/nand_base.c | 52 +++++++++++++++++++++++++++++++---------
include/linux/mtd/rawnand.h | 2 +-
2 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index da99232702a4..8645f655e5b0 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5225,8 +5225,11 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)

sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
- strncpy(chip->parameters.model, p->model,
- sizeof(chip->parameters.model) - 1);
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_onfi_param_page;
+ }

mtd->writesize = le32_to_cpu(p->byte_per_page);

@@ -5356,8 +5359,11 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)

sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
- strncpy(chip->parameters.model, p->model,
- sizeof(chip->parameters.model) - 1);
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_jedec_param_page;
+ }

mtd->writesize = le32_to_cpu(p->byte_per_page);

@@ -5546,8 +5552,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;

- strncpy(chip->parameters.model, type->name,
- sizeof(chip->parameters.model) - 1);
+ chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
+ if (!chip->parameters.model)
+ return false;

return true;
}
@@ -5706,8 +5713,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
if (!type->name)
return -ENODEV;

- strncpy(chip->parameters.model, type->name,
- sizeof(chip->parameters.model) - 1);
+ chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
+ if (!chip->parameters.model)
+ return -ENOMEM;

chip->chipsize = (uint64_t)type->chipsize << 20;

@@ -5737,7 +5745,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
- return -EINVAL;
+ ret = -EINVAL;
+
+ goto free_detect_allocation;
}

nand_decode_bbm_options(chip);
@@ -5774,6 +5784,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
return 0;
+
+free_detect_allocation:
+ kfree(chip->parameters.model);
+
+ return ret;
}

static const char * const nand_ecc_modes[] = {
@@ -6021,6 +6036,11 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return 0;
}

+static void nand_scan_ident_cleanup(struct nand_chip *chip)
+{
+ kfree(chip->parameters.model);
+}
+
static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
@@ -6764,11 +6784,18 @@ int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,

ret = nand_attach(chip);
if (ret)
- return ret;
+ goto cleanup_ident;

ret = nand_scan_tail(mtd);
if (ret)
- nand_detach(chip);
+ goto detach_chip;
+
+ return 0;
+
+detach_chip:
+ nand_detach(chip);
+cleanup_ident:
+ nand_scan_ident_cleanup(chip);

return ret;
}
@@ -6800,6 +6827,9 @@ void nand_cleanup(struct nand_chip *chip)

/* Free controller specific allocations after chip identification */
nand_detach(chip);
+
+ /* Free identification phase allocations */
+ nand_scan_ident_cleanup(chip);
}

EXPORT_SYMBOL_GPL(nand_cleanup);
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index a928771a7ae4..5723d940a47d 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -482,7 +482,7 @@ struct onfi_params {
*/
struct nand_parameters {
/* Generic parameters */
- char model[100];
+ const char *model;
bool supports_set_get_features;
DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER);
DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
--
2.14.1


2018-07-20 15:18:28

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 28/35] mtd: rawnand: allow exiting immediately nand_scan_ident()

Some driver (eg. docg4) will need to handle themselves the
identification phase. As part of the migration to use nand_scan()
everywhere (which will unconditionnaly call nand_scan_ident()), we add
a condition at the start of nand_scan_ident() to just "do nothing" if
the maxchips parameters is zero, meaning that the driver does not want
the core to handle this phase.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/nand_base.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index dea41fa25be1..e7f135c100c2 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5926,7 +5926,7 @@ static int nand_dt_init(struct nand_chip *chip)
/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
- * @maxchips: number of chips to scan for
+ * @maxchips: number of chips to scan for, returns immediately if 0
* @table: alternative NAND ID table
*
* This is the first phase of the normal nand_scan() function. It reads the
@@ -5940,6 +5940,14 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
struct nand_chip *chip = mtd_to_nand(mtd);
int ret;

+ /*
+ * If the number of chips to scan for is null, just return silently.
+ * This is for specific drivers that must handle this part of the
+ * probe process themselves (e.g docg4).
+ */
+ if (!maxchips)
+ return 0;
+
/* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);

--
2.14.1


2018-07-20 15:18:36

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 15/35] mtd: rawnand: mxc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/mxc_nand.c | 136 +++++++++++++++++++++-------------------
1 file changed, 71 insertions(+), 65 deletions(-)

diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index c6eff61e909d..4c9214dea424 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -1691,6 +1691,74 @@ static int mxcnd_probe_dt(struct mxc_nand_host *host)
}
#endif

+static int mxcnd_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
+ struct device *dev = mtd->dev.parent;
+
+ switch (chip->ecc.mode) {
+ case NAND_ECC_HW:
+ chip->ecc.read_page = mxc_nand_read_page;
+ chip->ecc.read_page_raw = mxc_nand_read_page_raw;
+ chip->ecc.read_oob = mxc_nand_read_oob;
+ chip->ecc.write_page = mxc_nand_write_page_ecc;
+ chip->ecc.write_page_raw = mxc_nand_write_page_raw;
+ chip->ecc.write_oob = mxc_nand_write_oob;
+ break;
+
+ case NAND_ECC_SOFT:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+ }
+
+ /* Allocate the right size buffer now */
+ devm_kfree(dev, (void *)host->data_buf);
+ host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
+ GFP_KERNEL);
+ if (!host->data_buf)
+ return -ENOMEM;
+
+ /* Call preset again, with correct writesize chip time */
+ host->devtype_data->preset(mtd);
+
+ if (!chip->ecc.bytes) {
+ if (host->eccsize == 8)
+ chip->ecc.bytes = 18;
+ else if (host->eccsize == 4)
+ chip->ecc.bytes = 9;
+ }
+
+ /*
+ * Experimentation shows that i.MX NFC can only handle up to 218 oob
+ * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
+ * into copying invalid data to/from the spare IO buffer, as this
+ * might cause ECC data corruption when doing sub-page write to a
+ * partially written page.
+ */
+ host->used_oobsize = min(mtd->oobsize, 218U);
+
+ if (chip->ecc.mode == NAND_ECC_HW) {
+ if (is_imx21_nfc(host) || is_imx27_nfc(host))
+ chip->ecc.strength = 1;
+ else
+ chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops mxcnd_controller_ops = {
+ .attach_chip = mxcnd_attach_chip,
+};
+
static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
@@ -1830,71 +1898,9 @@ static int mxcnd_probe(struct platform_device *pdev)
host->devtype_data->irq_control(host, 1);
}

- /* first scan to find the device and get the page size */
- err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
- if (err)
- goto escan;
-
- switch (this->ecc.mode) {
- case NAND_ECC_HW:
- this->ecc.read_page = mxc_nand_read_page;
- this->ecc.read_page_raw = mxc_nand_read_page_raw;
- this->ecc.read_oob = mxc_nand_read_oob;
- this->ecc.write_page = mxc_nand_write_page_ecc;
- this->ecc.write_page_raw = mxc_nand_write_page_raw;
- this->ecc.write_oob = mxc_nand_write_oob;
- break;
-
- case NAND_ECC_SOFT:
- break;
-
- default:
- err = -EINVAL;
- goto escan;
- }
-
- if (this->bbt_options & NAND_BBT_USE_FLASH) {
- this->bbt_td = &bbt_main_descr;
- this->bbt_md = &bbt_mirror_descr;
- }
-
- /* allocate the right size buffer now */
- devm_kfree(&pdev->dev, (void *)host->data_buf);
- host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
- GFP_KERNEL);
- if (!host->data_buf) {
- err = -ENOMEM;
- goto escan;
- }
-
- /* Call preset again, with correct writesize this time */
- host->devtype_data->preset(mtd);
-
- if (!this->ecc.bytes) {
- if (host->eccsize == 8)
- this->ecc.bytes = 18;
- else if (host->eccsize == 4)
- this->ecc.bytes = 9;
- }
-
- /*
- * Experimentation shows that i.MX NFC can only handle up to 218 oob
- * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
- * into copying invalid data to/from the spare IO buffer, as this
- * might cause ECC data corruption when doing sub-page write to a
- * partially written page.
- */
- host->used_oobsize = min(mtd->oobsize, 218U);
-
- if (this->ecc.mode == NAND_ECC_HW) {
- if (is_imx21_nfc(host) || is_imx27_nfc(host))
- this->ecc.strength = 1;
- else
- this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
- }
-
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ /* Scan the NAND device */
+ this->dummy_controller.ops = &mxcnd_controller_ops;
+ err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
if (err)
goto escan;

--
2.14.1


2018-07-20 15:18:37

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 29/35] mtd: rawnand: docg4: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/docg4.c | 55 ++++++++++++++++++++++++++------------------
1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
index 4dccdfba6140..fec4353ff4ef 100644
--- a/drivers/mtd/nand/raw/docg4.c
+++ b/drivers/mtd/nand/raw/docg4.c
@@ -1227,10 +1227,9 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
* required within a nand driver because they are performed by the nand
* infrastructure code as part of nand_scan(). In this case they need
* to be initialized here because we skip call to nand_scan_ident() (the
- * first half of nand_scan()). The call to nand_scan_ident() is skipped
- * because for this device the chip id is not read in the manner of a
- * standard nand device. Unfortunately, nand_scan_ident() does other
- * things as well, such as call nand_set_defaults().
+ * first half of nand_scan()). The call to nand_scan_ident() could be
+ * skipped because for this device the chip id is not read in the manner
+ * of a standard nand device.
*/

struct nand_chip *nand = mtd_to_nand(mtd);
@@ -1315,6 +1314,27 @@ static int __init read_id_reg(struct mtd_info *mtd)

static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };

+static int docg4_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
+
+ init_mtd_structs(mtd);
+
+ /* Initialize kernel BCH algorithm */
+ doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+ if (!doc->bch)
+ return -EINVAL;
+
+ reset(mtd);
+
+ return read_id_reg(mtd);
+}
+
+static const struct nand_controller_ops docg4_controller_ops = {
+ .attach_chip = docg4_attach_chip,
+};
+
static int __init probe_docg4(struct platform_device *pdev)
{
struct mtd_info *mtd;
@@ -1350,26 +1370,16 @@ static int __init probe_docg4(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
doc->virtadr = virtadr;
doc->dev = dev;
-
- init_mtd_structs(mtd);
-
- /* initialize kernel bch algorithm */
- doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
- if (doc->bch == NULL) {
- retval = -EINVAL;
- goto free_nand;
- }
-
platform_set_drvdata(pdev, doc);

- reset(mtd);
- retval = read_id_reg(mtd);
- if (retval == -ENODEV) {
- dev_warn(dev, "No diskonchip G4 device found.\n");
- goto free_bch;
- }
-
- retval = nand_scan_tail(mtd);
+ /*
+ * Asking for 0 chips is useless here but it warns the user that the use
+ * of the nand_scan() function is a bit abused here because the
+ * initialization is actually a bit specific and re-handled again in the
+ * ->attach_chip() hook. It will probably leak some memory though.
+ */
+ nand->dummy_controller.ops = &docg4_controller_ops;
+ retval = nand_scan(mtd, 0);
if (retval)
goto free_bch;

@@ -1389,7 +1399,6 @@ static int __init probe_docg4(struct platform_device *pdev)
nand_cleanup(nand);
free_bch:
free_bch(doc->bch);
-free_nand:
kfree(nand);
unmap:
iounmap(virtadr);
--
2.14.1


2018-07-20 15:18:46

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 31/35] mtd: rawnand: jz4740: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/jz4740_nand.c | 46 ++++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
index 9bb8a89e09f9..8f821fdf8a1c 100644
--- a/drivers/mtd/nand/raw/jz4740_nand.c
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -59,6 +59,7 @@

struct jz_nand {
struct nand_chip chip;
+ struct platform_device *pdev;
void __iomem *base;
struct resource *mem;

@@ -329,8 +330,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
writel(ctrl, nand->base + JZ_REG_NAND_CTRL);

if (chipnr == 0) {
- /* Detect first chip. */
- ret = nand_scan_ident(mtd, 1, NULL);
+ /* Detect the first chip and register it */
+ ret = nand_scan(mtd, 1);
if (ret)
goto notfound_id;

@@ -367,6 +368,25 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
return ret;
}

+static int jz_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct device *dev = mtd->dev.parent;
+ struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
+
+ if (pdata && pdata->ident_callback) {
+ pdata->ident_callback(nand->pdev, mtd, &pdata->partitions,
+ &pdata->num_partitions);
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops jz_nand_controller_ops = {
+ .attach_chip = jz_nand_attach_chip,
+};
+
static int jz_nand_probe(struct platform_device *pdev)
{
int ret;
@@ -397,6 +417,7 @@ static int jz_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->name = "jz4740-nand";
+ nand->pdev = pdev;

chip->ecc.hwctl = jz_nand_hwctl;
chip->ecc.calculate = jz_nand_calculate_ecc_rs;
@@ -410,6 +431,7 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->chip_delay = 50;
chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
+ chip->dummy_controller.ops = &jz_nand_controller_ops;

if (nand->busy_gpio)
chip->dev_ready = jz_nand_dev_ready;
@@ -450,20 +472,10 @@ static int jz_nand_probe(struct platform_device *pdev)
else
nand->banks[chipnr] = 0;
}
+
if (chipnr == 0) {
dev_err(&pdev->dev, "No NAND chips found\n");
- goto err_iounmap_mmio;
- }
-
- if (pdata && pdata->ident_callback) {
- pdata->ident_callback(pdev, mtd, &pdata->partitions,
- &pdata->num_partitions);
- }
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(&pdev->dev, "Failed to scan NAND\n");
- goto err_unclaim_banks;
+ goto err_nand_release;
}

ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
@@ -471,15 +483,13 @@ static int jz_nand_probe(struct platform_device *pdev)

if (ret) {
dev_err(&pdev->dev, "Failed to add mtd device\n");
- goto err_nand_release;
+ goto err_unclaim_banks;
}

dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");

return 0;

-err_nand_release:
- nand_release(mtd);
err_unclaim_banks:
while (chipnr--) {
unsigned char bank = nand->banks[chipnr];
@@ -487,6 +497,8 @@ static int jz_nand_probe(struct platform_device *pdev)
nand->bank_base[bank - 1]);
}
writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_nand_release:
+ nand_release(mtd);
err_iounmap_mmio:
jz_nand_iounmap_resource(nand->mem, nand->base);
err_free:
--
2.14.1


2018-07-20 15:18:53

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 30/35] mtd: rawnand: qcom: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/qcom_nandc.c | 71 +++++++++++++--------------------------
1 file changed, 24 insertions(+), 47 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index aa6c3e026ef1..dc895b846b84 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -2475,10 +2475,10 @@ qcom_nandc_calc_ecc_bytes(int step_size, int strength)
NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
NANDC_STEP_SIZE, 4, 8);

-static int qcom_nand_host_setup(struct qcom_nand_host *host)
+static int qcom_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int cwperpage, bad_block_byte, ret;
@@ -2640,6 +2640,10 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
return 0;
}

+static const struct nand_controller_ops qcom_nandc_ops = {
+ .attach_chip = qcom_nand_attach_chip,
+};
+
static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
{
int ret;
@@ -2781,9 +2785,9 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
return 0;
}

-static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
- struct qcom_nand_host *host,
- struct device_node *dn)
+static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
+ struct qcom_nand_host *host,
+ struct device_node *dn)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
@@ -2824,36 +2828,20 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
chip->block_markbad = qcom_nandc_block_markbad;

chip->controller = &nandc->controller;
+ chip->controller->ops = &qcom_nandc_ops;
chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
NAND_SKIP_BBTSCAN;

/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;

- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
- ret = qcom_nand_host_setup(host);
-
- return ret;
-}
-
-static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
- struct qcom_nand_host *host,
- struct device_node *dn)
-{
- struct nand_chip *chip = &host->chip;
- struct mtd_info *mtd = nand_to_mtd(chip);
- int ret;
-
- ret = nand_scan_tail(mtd);
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;

ret = mtd_device_register(mtd, NULL, 0);
if (ret)
- nand_cleanup(mtd_to_nand(mtd));
+ nand_cleanup(chip);

return ret;
}
@@ -2862,9 +2850,19 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
{
struct device *dev = nandc->dev;
struct device_node *dn = dev->of_node, *child;
- struct qcom_nand_host *host, *tmp;
+ struct qcom_nand_host *host;
int ret;

+ if (nandc->props->is_bam) {
+ free_bam_transaction(nandc);
+ nandc->bam_txn = alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
+ return -ENOMEM;
+ }
+ }
+
for_each_available_child_of_node(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
@@ -2872,7 +2870,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
return -ENOMEM;
}

- ret = qcom_nand_host_init(nandc, host, child);
+ ret = qcom_nand_host_init_and_register(nandc, host, child);
if (ret) {
devm_kfree(dev, host);
continue;
@@ -2881,27 +2879,6 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
list_add_tail(&host->node, &nandc->host_list);
}

- if (list_empty(&nandc->host_list))
- return -ENODEV;
-
- if (nandc->props->is_bam) {
- free_bam_transaction(nandc);
- nandc->bam_txn = alloc_bam_transaction(nandc);
- if (!nandc->bam_txn) {
- dev_err(nandc->dev,
- "failed to allocate bam transaction\n");
- return -ENOMEM;
- }
- }
-
- list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
- ret = qcom_nand_mtd_register(nandc, host, child);
- if (ret) {
- list_del(&host->node);
- devm_kfree(dev, host);
- }
- }
-
if (list_empty(&nandc->host_list))
return -ENODEV;

--
2.14.1


2018-07-20 15:19:04

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 16/35] mtd: rawnand: nandsim: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/nandsim.c | 82 +++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 8a3b36cfe5ea..71ac034aee9c 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -2192,6 +2192,48 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}

+static int ns_attach_chip(struct nand_chip *chip)
+{
+ unsigned int eccsteps, eccbytes;
+
+ if (!bch)
+ return 0;
+
+ if (!mtd_nand_has_bch()) {
+ NS_ERR("BCH ECC support is disabled\n");
+ return -EINVAL;
+ }
+
+ /* Use 512-byte ecc blocks */
+ eccsteps = nsmtd->writesize / 512;
+ eccbytes = ((bch * 13) + 7) / 8;
+
+ /* Do not bother supporting small page devices */
+ if (nsmtd->oobsize < 64 || !eccsteps) {
+ NS_ERR("BCH not available on small page devices\n");
+ return -EINVAL;
+ }
+
+ if (((eccbytes * eccsteps) + 2) > nsmtd->oobsize) {
+ NS_ERR("Invalid BCH value %u\n", bch);
+ return -EINVAL;
+ }
+
+ chip->ecc.mode = NAND_ECC_SOFT;
+ chip->ecc.algo = NAND_ECC_BCH;
+ chip->ecc.size = 512;
+ chip->ecc.strength = bch;
+ chip->ecc.bytes = eccbytes;
+
+ NS_INFO("Using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
+
+ return 0;
+}
+
+static const struct nand_controller_ops ns_controller_ops = {
+ .attach_chip = ns_attach_chip,
+};
+
/*
* Module initialization function
*/
@@ -2276,44 +2318,10 @@ static int __init ns_init_module(void)
if ((retval = parse_gravepages()) != 0)
goto error;

- retval = nand_scan_ident(nsmtd, 1, NULL);
+ chip->dummy_controller.ops = &ns_controller_ops;
+ retval = nand_scan(nsmtd, 1);
if (retval) {
- NS_ERR("cannot scan NAND Simulator device\n");
- goto error;
- }
-
- if (bch) {
- unsigned int eccsteps, eccbytes;
- if (!mtd_nand_has_bch()) {
- NS_ERR("BCH ECC support is disabled\n");
- retval = -EINVAL;
- goto error;
- }
- /* use 512-byte ecc blocks */
- eccsteps = nsmtd->writesize/512;
- eccbytes = (bch*13+7)/8;
- /* do not bother supporting small page devices */
- if ((nsmtd->oobsize < 64) || !eccsteps) {
- NS_ERR("bch not available on small page devices\n");
- retval = -EINVAL;
- goto error;
- }
- if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
- NS_ERR("invalid bch value %u\n", bch);
- retval = -EINVAL;
- goto error;
- }
- chip->ecc.mode = NAND_ECC_SOFT;
- chip->ecc.algo = NAND_ECC_BCH;
- chip->ecc.size = 512;
- chip->ecc.strength = bch;
- chip->ecc.bytes = eccbytes;
- NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
- }
-
- retval = nand_scan_tail(nsmtd);
- if (retval) {
- NS_ERR("can't register NAND Simulator\n");
+ NS_ERR("Could not scan NAND Simulator device\n");
goto error;
}

--
2.14.1


2018-07-20 15:19:09

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 32/35] mtd: rawnand: tegra: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/tegra_nand.c | 162 +++++++++++++++++++++-----------------
1 file changed, 88 insertions(+), 74 deletions(-)

diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 31c0d9ca9d23..c40a53066cee 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -906,74 +906,13 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
bits_per_step, oobsize);
}

-static int tegra_nand_chips_init(struct device *dev,
- struct tegra_nand_controller *ctrl)
+static int tegra_nand_attach_chip(struct nand_chip *chip)
{
- struct device_node *np = dev->of_node;
- struct device_node *np_nand;
- int nsels, nchips = of_get_child_count(np);
- struct tegra_nand_chip *nand;
- struct mtd_info *mtd;
- struct nand_chip *chip;
+ struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
+ struct tegra_nand_chip *nand = to_tegra_chip(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
int bits_per_step;
int ret;
- u32 cs;
-
- if (nchips != 1) {
- dev_err(dev, "Currently only one NAND chip supported\n");
- return -EINVAL;
- }
-
- np_nand = of_get_next_child(np, NULL);
-
- nsels = of_property_count_elems_of_size(np_nand, "reg", sizeof(u32));
- if (nsels != 1) {
- dev_err(dev, "Missing/invalid reg property\n");
- return -EINVAL;
- }
-
- /* Retrieve CS id, currently only single die NAND supported */
- ret = of_property_read_u32(np_nand, "reg", &cs);
- if (ret) {
- dev_err(dev, "could not retrieve reg property: %d\n", ret);
- return ret;
- }
-
- nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
- if (!nand)
- return -ENOMEM;
-
- nand->cs[0] = cs;
-
- nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
-
- if (IS_ERR(nand->wp_gpio)) {
- ret = PTR_ERR(nand->wp_gpio);
- dev_err(dev, "Failed to request WP GPIO: %d\n", ret);
- return ret;
- }
-
- chip = &nand->chip;
- chip->controller = &ctrl->controller;
-
- mtd = nand_to_mtd(chip);
-
- mtd->dev.parent = dev;
- mtd->owner = THIS_MODULE;
-
- nand_set_flash_node(chip, np_nand);
-
- if (!mtd->name)
- mtd->name = "tegra_nand";
-
- chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
- chip->exec_op = tegra_nand_exec_op;
- chip->select_chip = tegra_nand_select_chip;
- chip->setup_data_interface = tegra_nand_setup_data_interface;
-
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;

if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
@@ -982,7 +921,8 @@ static int tegra_nand_chips_init(struct device *dev,
chip->ecc.size = 512;
chip->ecc.steps = mtd->writesize / chip->ecc.size;
if (chip->ecc_step_ds != 512) {
- dev_err(dev, "Unsupported step size %d\n", chip->ecc_step_ds);
+ dev_err(ctrl->dev, "Unsupported step size %d\n",
+ chip->ecc_step_ds);
return -EINVAL;
}

@@ -1004,14 +944,15 @@ static int tegra_nand_chips_init(struct device *dev,
}

if (chip->ecc.algo == NAND_ECC_BCH && mtd->writesize < 2048) {
- dev_err(dev, "BCH supports 2K or 4K page size only\n");
+ dev_err(ctrl->dev, "BCH supports 2K or 4K page size only\n");
return -EINVAL;
}

if (!chip->ecc.strength) {
ret = tegra_nand_select_strength(chip, mtd->oobsize);
if (ret < 0) {
- dev_err(dev, "No valid strength found, minimum %d\n",
+ dev_err(ctrl->dev,
+ "No valid strength found, minimum %d\n",
chip->ecc_strength_ds);
return ret;
}
@@ -1039,7 +980,7 @@ static int tegra_nand_chips_init(struct device *dev,
nand->config_ecc |= CONFIG_TVAL_8;
break;
default:
- dev_err(dev, "ECC strength %d not supported\n",
+ dev_err(ctrl->dev, "ECC strength %d not supported\n",
chip->ecc.strength);
return -EINVAL;
}
@@ -1062,17 +1003,17 @@ static int tegra_nand_chips_init(struct device *dev,
nand->bch_config |= BCH_TVAL_16;
break;
default:
- dev_err(dev, "ECC strength %d not supported\n",
+ dev_err(ctrl->dev, "ECC strength %d not supported\n",
chip->ecc.strength);
return -EINVAL;
}
break;
default:
- dev_err(dev, "ECC algorithm not supported\n");
+ dev_err(ctrl->dev, "ECC algorithm not supported\n");
return -EINVAL;
}

- dev_info(dev, "Using %s with strength %d per 512 byte step\n",
+ dev_info(ctrl->dev, "Using %s with strength %d per 512 byte step\n",
chip->ecc.algo == NAND_ECC_BCH ? "BCH" : "RS",
chip->ecc.strength);

@@ -1095,7 +1036,8 @@ static int tegra_nand_chips_init(struct device *dev,
nand->config |= CONFIG_PS_4096;
break;
default:
- dev_err(dev, "Unsupported writesize %d\n", mtd->writesize);
+ dev_err(ctrl->dev, "Unsupported writesize %d\n",
+ mtd->writesize);
return -ENODEV;
}

@@ -1106,7 +1048,79 @@ static int tegra_nand_chips_init(struct device *dev,
nand->config |= CONFIG_TAG_BYTE_SIZE(mtd->oobsize - 1);
writel_relaxed(nand->config, ctrl->regs + CONFIG);

- ret = nand_scan_tail(mtd);
+ return 0;
+}
+
+static const struct nand_controller_ops tegra_nand_controller_ops = {
+ .attach_chip = &tegra_nand_attach_chip,
+};
+
+static int tegra_nand_chips_init(struct device *dev,
+ struct tegra_nand_controller *ctrl)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *np_nand;
+ int nsels, nchips = of_get_child_count(np);
+ struct tegra_nand_chip *nand;
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+ int ret;
+ u32 cs;
+
+ if (nchips != 1) {
+ dev_err(dev, "Currently only one NAND chip supported\n");
+ return -EINVAL;
+ }
+
+ np_nand = of_get_next_child(np, NULL);
+
+ nsels = of_property_count_elems_of_size(np_nand, "reg", sizeof(u32));
+ if (nsels != 1) {
+ dev_err(dev, "Missing/invalid reg property\n");
+ return -EINVAL;
+ }
+
+ /* Retrieve CS id, currently only single die NAND supported */
+ ret = of_property_read_u32(np_nand, "reg", &cs);
+ if (ret) {
+ dev_err(dev, "could not retrieve reg property: %d\n", ret);
+ return ret;
+ }
+
+ nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL);
+ if (!nand)
+ return -ENOMEM;
+
+ nand->cs[0] = cs;
+
+ nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
+
+ if (IS_ERR(nand->wp_gpio)) {
+ ret = PTR_ERR(nand->wp_gpio);
+ dev_err(dev, "Failed to request WP GPIO: %d\n", ret);
+ return ret;
+ }
+
+ chip = &nand->chip;
+ chip->controller = &ctrl->controller;
+ chip->controller->ops = &tegra_nand_controller_ops;
+
+ mtd = nand_to_mtd(chip);
+
+ mtd->dev.parent = dev;
+ mtd->owner = THIS_MODULE;
+
+ nand_set_flash_node(chip, np_nand);
+
+ if (!mtd->name)
+ mtd->name = "tegra_nand";
+
+ chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
+ chip->exec_op = tegra_nand_exec_op;
+ chip->select_chip = tegra_nand_select_chip;
+ chip->setup_data_interface = tegra_nand_setup_data_interface;
+
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;

--
2.14.1


2018-07-20 15:19:10

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 22/35] mtd: rawnand: tango: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/tango_nand.c | 40 +++++++++++++++++++++++----------------
1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index dd7a26efdf4f..a448d0797cd5 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -517,6 +517,28 @@ static int tango_set_timings(struct mtd_info *mtd, int csline,
return 0;
}

+static int tango_attach_chip(struct nand_chip *chip)
+{
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+ ecc->mode = NAND_ECC_HW;
+ ecc->algo = NAND_ECC_BCH;
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+ ecc->read_page_raw = tango_read_page_raw;
+ ecc->write_page_raw = tango_write_page_raw;
+ ecc->read_page = tango_read_page;
+ ecc->write_page = tango_write_page;
+ ecc->read_oob = tango_read_oob;
+ ecc->write_oob = tango_write_oob;
+
+ return 0;
+}
+
+static const struct nand_controller_ops tango_controller_ops = {
+ .attach_chip = tango_attach_chip,
+};
+
static int chip_init(struct device *dev, struct device_node *np)
{
u32 cs;
@@ -560,28 +582,14 @@ static int chip_init(struct device *dev, struct device_node *np)
NAND_NO_SUBPAGE_WRITE |
NAND_WAIT_TCCS;
chip->controller = &nfc->hw;
+ chip->controller->ops = &tango_controller_ops;
tchip->base = nfc->pbus_base + (cs * 256);

nand_set_flash_node(chip, np);
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;

- err = nand_scan_ident(mtd, 1, NULL);
- if (err)
- return err;
-
- ecc->mode = NAND_ECC_HW;
- ecc->algo = NAND_ECC_BCH;
- ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
-
- ecc->read_page_raw = tango_read_page_raw;
- ecc->write_page_raw = tango_write_page_raw;
- ecc->read_page = tango_read_page;
- ecc->write_page = tango_write_page;
- ecc->read_oob = tango_read_oob;
- ecc->write_oob = tango_write_oob;
-
- err = nand_scan_tail(mtd);
+ err = nand_scan(mtd, 1);
if (err)
return err;

--
2.14.1


2018-07-20 15:19:15

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 18/35] mtd: rawnand: s3c2410: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/s3c2410.c | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index e8bf64832213..c21e8892394a 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -915,20 +915,19 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
}

/**
- * s3c2410_nand_update_chip - post probe update
- * @info: The controller instance.
- * @nmtd: The driver version of the MTD instance.
+ * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
+ * @chip: The NAND chip
*
- * This routine is called after the chip probe has successfully completed
- * and the relevant per-chip information updated. This call ensure that
+ * This hook is called by the core after the identification of the NAND chip,
+ * once the relevant per-chip information is up to date.. This call ensure that
* we update the internal state accordingly.
*
* The internal state is currently limited to the ECC state information.
*/
-static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
- struct s3c2410_nand_mtd *nmtd)
+static int s3c2410_nand_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = &nmtd->chip;
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);

switch (chip->ecc.mode) {

@@ -998,6 +997,10 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
return 0;
}

+static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
+ .attach_chip = s3c2410_nand_attach_chip,
+};
+
static const struct of_device_id s3c24xx_nand_dt_ids[] = {
{
.compatible = "samsung,s3c2410-nand",
@@ -1095,6 +1098,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);

nand_controller_init(&info->controller);
+ info->controller.ops = &s3c24xx_nand_controller_ops;

/* get the clock source and enable it */

@@ -1166,15 +1170,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);

- err = nand_scan_ident(mtd, (sets) ? sets->nr_chips : 1, NULL);
- if (err)
- goto exit_error;
-
- err = s3c2410_nand_update_chip(info, nmtd);
- if (err < 0)
- goto exit_error;
-
- err = nand_scan_tail(mtd);
+ err = nand_scan(mtd, sets ? sets->nr_chips : 1);
if (err)
goto exit_error;

--
2.14.1


2018-07-20 15:19:21

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 17/35] mtd: rawnand: omap2: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/omap2.c | 521 +++++++++++++++++++++----------------------
1 file changed, 259 insertions(+), 262 deletions(-)

diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index e943b2e5a5e2..73ffb1a9b99f 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -1915,17 +1915,271 @@ static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
.free = omap_sw_ooblayout_free,
};

+static int omap_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct device *dev = &info->pdev->dev;
+ int min_oobbytes = BADBLOCK_MARKER_LENGTH;
+ int oobbytes_per_step;
+ dma_cap_mask_t mask;
+ int err;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+ else
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ /* Re-populate low-level callbacks based on xfer modes */
+ switch (info->xfer_type) {
+ case NAND_OMAP_PREFETCH_POLLED:
+ chip->read_buf = omap_read_buf_pref;
+ chip->write_buf = omap_write_buf_pref;
+ break;
+
+ case NAND_OMAP_POLLED:
+ /* Use nand_base defaults for {read,write}_buf */
+ break;
+
+ case NAND_OMAP_PREFETCH_DMA:
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ info->dma = dma_request_chan(dev, "rxtx");
+
+ if (IS_ERR(info->dma)) {
+ dev_err(dev, "DMA engine request failed\n");
+ return PTR_ERR(info->dma);
+ } else {
+ struct dma_slave_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.src_addr = info->phys_base;
+ cfg.dst_addr = info->phys_base;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = 16;
+ cfg.dst_maxburst = 16;
+ err = dmaengine_slave_config(info->dma, &cfg);
+ if (err) {
+ dev_err(dev,
+ "DMA engine slave config failed: %d\n",
+ err);
+ return err;
+ }
+ chip->read_buf = omap_read_buf_dma_pref;
+ chip->write_buf = omap_write_buf_dma_pref;
+ }
+ break;
+
+ case NAND_OMAP_PREFETCH_IRQ:
+ info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
+ if (info->gpmc_irq_fifo <= 0) {
+ dev_err(dev, "Error getting fifo IRQ\n");
+ return -ENODEV;
+ }
+ err = devm_request_irq(dev, info->gpmc_irq_fifo,
+ omap_nand_irq, IRQF_SHARED,
+ "gpmc-nand-fifo", info);
+ if (err) {
+ dev_err(dev, "Requesting IRQ %d, error %d\n",
+ info->gpmc_irq_fifo, err);
+ info->gpmc_irq_fifo = 0;
+ return err;
+ }
+
+ info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
+ if (info->gpmc_irq_count <= 0) {
+ dev_err(dev, "Error getting IRQ count\n");
+ return -ENODEV;
+ }
+ err = devm_request_irq(dev, info->gpmc_irq_count,
+ omap_nand_irq, IRQF_SHARED,
+ "gpmc-nand-count", info);
+ if (err) {
+ dev_err(dev, "Requesting IRQ %d, error %d\n",
+ info->gpmc_irq_count, err);
+ info->gpmc_irq_count = 0;
+ return err;
+ }
+
+ chip->read_buf = omap_read_buf_irq_pref;
+ chip->write_buf = omap_write_buf_irq_pref;
+
+ break;
+
+ default:
+ dev_err(dev, "xfer_type %d not supported!\n", info->xfer_type);
+ return -EINVAL;
+ }
+
+ if (!omap2_nand_ecc_check(info))
+ return -EINVAL;
+
+ /*
+ * Bail out earlier to let NAND_ECC_SOFT code create its own
+ * ooblayout instead of using ours.
+ */
+ if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ chip->ecc.algo = NAND_ECC_HAMMING;
+ return 0;
+ }
+
+ /* Populate MTD interface based on ECC scheme */
+ switch (info->ecc_opt) {
+ case OMAP_ECC_HAM1_CODE_HW:
+ dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.bytes = 3;
+ chip->ecc.size = 512;
+ chip->ecc.strength = 1;
+ chip->ecc.calculate = omap_calculate_ecc;
+ chip->ecc.hwctl = omap_enable_hwecc;
+ chip->ecc.correct = omap_correct_data;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ if (!(chip->options & NAND_BUSWIDTH_16))
+ min_oobbytes = 1;
+
+ break;
+
+ case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+ pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 7;
+ chip->ecc.strength = 4;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = nand_bch_correct_data;
+ chip->ecc.calculate = omap_calculate_ecc_bch_sw;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = chip->ecc.bytes + 1;
+ /* Software BCH library is used for locating errors */
+ chip->ecc.priv = nand_bch_init(mtd);
+ if (!chip->ecc.priv) {
+ dev_err(dev, "Unable to use BCH library\n");
+ return -EINVAL;
+ }
+ break;
+
+ case OMAP_ECC_BCH4_CODE_HW:
+ pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ /* 14th bit is kept reserved for ROM-code compatibility */
+ chip->ecc.bytes = 7 + 1;
+ chip->ecc.strength = 4;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH4_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+ break;
+
+ case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+ pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 13;
+ chip->ecc.strength = 8;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = nand_bch_correct_data;
+ chip->ecc.calculate = omap_calculate_ecc_bch_sw;
+ mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+ /* Reserve one byte for the OMAP marker */
+ oobbytes_per_step = chip->ecc.bytes + 1;
+ /* Software BCH library is used for locating errors */
+ chip->ecc.priv = nand_bch_init(mtd);
+ if (!chip->ecc.priv) {
+ dev_err(dev, "unable to use BCH library\n");
+ return -EINVAL;
+ }
+ break;
+
+ case OMAP_ECC_BCH8_CODE_HW:
+ pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ /* 14th bit is kept reserved for ROM-code compatibility */
+ chip->ecc.bytes = 13 + 1;
+ chip->ecc.strength = 8;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH8_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+
+ break;
+
+ case OMAP_ECC_BCH16_CODE_HW:
+ pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 26;
+ chip->ecc.strength = 16;
+ chip->ecc.hwctl = omap_enable_hwecc_bch;
+ chip->ecc.correct = omap_elm_correct_data;
+ chip->ecc.read_page = omap_read_page_bch;
+ chip->ecc.write_page = omap_write_page_bch;
+ chip->ecc.write_subpage = omap_write_subpage_bch;
+ mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+ oobbytes_per_step = chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, BCH16_ECC,
+ mtd->writesize / chip->ecc.size,
+ chip->ecc.size, chip->ecc.bytes);
+ if (err < 0)
+ return err;
+
+ break;
+ default:
+ dev_err(dev, "Invalid or unsupported ECC scheme\n");
+ return -EINVAL;
+ }
+
+ /* Check if NAND device's OOB is enough to store ECC signatures */
+ min_oobbytes += (oobbytes_per_step *
+ (mtd->writesize / chip->ecc.size));
+ if (mtd->oobsize < min_oobbytes) {
+ dev_err(dev,
+ "Not enough OOB bytes: required = %d, available=%d\n",
+ min_oobbytes, mtd->oobsize);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops omap_nand_controller_ops = {
+ .attach_chip = omap_nand_attach_chip,
+};
+
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
int err;
- dma_cap_mask_t mask;
struct resource *res;
struct device *dev = &pdev->dev;
- int min_oobbytes = BADBLOCK_MARKER_LENGTH;
- int oobbytes_per_step;

info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
GFP_KERNEL);
@@ -1967,6 +2221,7 @@ static int omap_nand_probe(struct platform_device *pdev)
info->phys_base = res->start;

nand_chip->controller = &omap_gpmc_controller;
+ nand_chip->controller->ops = &omap_nand_controller_ops;

nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
nand_chip->cmd_ctrl = omap_hwcontrol;
@@ -1998,266 +2253,8 @@ static int omap_nand_probe(struct platform_device *pdev)

/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
- err = nand_scan_ident(mtd, 1, NULL);
- if (err) {
- dev_err(&info->pdev->dev,
- "scan failed, may be bus-width mismatch\n");
- goto return_error;
- }

- if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
- nand_chip->bbt_options |= NAND_BBT_NO_OOB;
- else
- nand_chip->options |= NAND_SKIP_BBTSCAN;
-
- /* re-populate low-level callbacks based on xfer modes */
- switch (info->xfer_type) {
- case NAND_OMAP_PREFETCH_POLLED:
- nand_chip->read_buf = omap_read_buf_pref;
- nand_chip->write_buf = omap_write_buf_pref;
- break;
-
- case NAND_OMAP_POLLED:
- /* Use nand_base defaults for {read,write}_buf */
- break;
-
- case NAND_OMAP_PREFETCH_DMA:
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
-
- if (IS_ERR(info->dma)) {
- dev_err(&pdev->dev, "DMA engine request failed\n");
- err = PTR_ERR(info->dma);
- goto return_error;
- } else {
- struct dma_slave_config cfg;
-
- memset(&cfg, 0, sizeof(cfg));
- cfg.src_addr = info->phys_base;
- cfg.dst_addr = info->phys_base;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cfg.src_maxburst = 16;
- cfg.dst_maxburst = 16;
- err = dmaengine_slave_config(info->dma, &cfg);
- if (err) {
- dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
- err);
- goto return_error;
- }
- nand_chip->read_buf = omap_read_buf_dma_pref;
- nand_chip->write_buf = omap_write_buf_dma_pref;
- }
- break;
-
- case NAND_OMAP_PREFETCH_IRQ:
- info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
- if (info->gpmc_irq_fifo <= 0) {
- dev_err(&pdev->dev, "error getting fifo irq\n");
- err = -ENODEV;
- goto return_error;
- }
- err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
- omap_nand_irq, IRQF_SHARED,
- "gpmc-nand-fifo", info);
- if (err) {
- dev_err(&pdev->dev, "requesting irq(%d) error:%d",
- info->gpmc_irq_fifo, err);
- info->gpmc_irq_fifo = 0;
- goto return_error;
- }
-
- info->gpmc_irq_count = platform_get_irq(pdev, 1);
- if (info->gpmc_irq_count <= 0) {
- dev_err(&pdev->dev, "error getting count irq\n");
- err = -ENODEV;
- goto return_error;
- }
- err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
- omap_nand_irq, IRQF_SHARED,
- "gpmc-nand-count", info);
- if (err) {
- dev_err(&pdev->dev, "requesting irq(%d) error:%d",
- info->gpmc_irq_count, err);
- info->gpmc_irq_count = 0;
- goto return_error;
- }
-
- nand_chip->read_buf = omap_read_buf_irq_pref;
- nand_chip->write_buf = omap_write_buf_irq_pref;
-
- break;
-
- default:
- dev_err(&pdev->dev,
- "xfer_type(%d) not supported!\n", info->xfer_type);
- err = -EINVAL;
- goto return_error;
- }
-
- if (!omap2_nand_ecc_check(info)) {
- err = -EINVAL;
- goto return_error;
- }
-
- /*
- * Bail out earlier to let NAND_ECC_SOFT code create its own
- * ooblayout instead of using ours.
- */
- if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
- nand_chip->ecc.mode = NAND_ECC_SOFT;
- nand_chip->ecc.algo = NAND_ECC_HAMMING;
- goto scan_tail;
- }
-
- /* populate MTD interface based on ECC scheme */
- switch (info->ecc_opt) {
- case OMAP_ECC_HAM1_CODE_HW:
- pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.bytes = 3;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.strength = 1;
- nand_chip->ecc.calculate = omap_calculate_ecc;
- nand_chip->ecc.hwctl = omap_enable_hwecc;
- nand_chip->ecc.correct = omap_correct_data;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- if (!(nand_chip->options & NAND_BUSWIDTH_16))
- min_oobbytes = 1;
-
- break;
-
- case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
- pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 7;
- nand_chip->ecc.strength = 4;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = nand_bch_correct_data;
- nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
- mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
- /* Reserve one byte for the OMAP marker */
- oobbytes_per_step = nand_chip->ecc.bytes + 1;
- /* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd);
- if (!nand_chip->ecc.priv) {
- dev_err(&info->pdev->dev, "unable to use BCH library\n");
- err = -EINVAL;
- goto return_error;
- }
- break;
-
- case OMAP_ECC_BCH4_CODE_HW:
- pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- /* 14th bit is kept reserved for ROM-code compatibility */
- nand_chip->ecc.bytes = 7 + 1;
- nand_chip->ecc.strength = 4;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH4_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
- break;
-
- case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
- pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 13;
- nand_chip->ecc.strength = 8;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = nand_bch_correct_data;
- nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
- mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
- /* Reserve one byte for the OMAP marker */
- oobbytes_per_step = nand_chip->ecc.bytes + 1;
- /* software bch library is used for locating errors */
- nand_chip->ecc.priv = nand_bch_init(mtd);
- if (!nand_chip->ecc.priv) {
- dev_err(&info->pdev->dev, "unable to use BCH library\n");
- err = -EINVAL;
- goto return_error;
- }
- break;
-
- case OMAP_ECC_BCH8_CODE_HW:
- pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- /* 14th bit is kept reserved for ROM-code compatibility */
- nand_chip->ecc.bytes = 13 + 1;
- nand_chip->ecc.strength = 8;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH8_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
-
- break;
-
- case OMAP_ECC_BCH16_CODE_HW:
- pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- nand_chip->ecc.bytes = 26;
- nand_chip->ecc.strength = 16;
- nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
- nand_chip->ecc.correct = omap_elm_correct_data;
- nand_chip->ecc.read_page = omap_read_page_bch;
- nand_chip->ecc.write_page = omap_write_page_bch;
- nand_chip->ecc.write_subpage = omap_write_subpage_bch;
- mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
- oobbytes_per_step = nand_chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH16_ECC,
- mtd->writesize / nand_chip->ecc.size,
- nand_chip->ecc.size, nand_chip->ecc.bytes);
- if (err < 0)
- goto return_error;
-
- break;
- default:
- dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
- err = -EINVAL;
- goto return_error;
- }
-
- /* check if NAND device's OOB is enough to store ECC signatures */
- min_oobbytes += (oobbytes_per_step *
- (mtd->writesize / nand_chip->ecc.size));
- if (mtd->oobsize < min_oobbytes) {
- dev_err(&info->pdev->dev,
- "not enough OOB bytes required = %d, available=%d\n",
- min_oobbytes, mtd->oobsize);
- err = -EINVAL;
- goto return_error;
- }
-
-scan_tail:
- /* second phase scan */
- err = nand_scan_tail(mtd);
+ err = nand_scan(mtd, 1);
if (err)
goto return_error;

--
2.14.1


2018-07-20 15:19:25

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 20/35] mtd: rawnand: sh_flctl: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/sh_flctl.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index d37d1d3ccbf9..663c75005ac9 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -1002,10 +1002,10 @@ static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
flctl->index += len;
}

-static int flctl_chip_init_tail(struct mtd_info *mtd)
+static int flctl_chip_attach_chip(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct sh_flctl *flctl = mtd_to_flctl(mtd);
- struct nand_chip *chip = &flctl->chip;

if (chip->options & NAND_BUSWIDTH_16) {
/*
@@ -1073,6 +1073,10 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
return 0;
}

+static const struct nand_controller_ops flctl_nand_controller_ops = {
+ .attach_chip = flctl_chip_attach_chip,
+};
+
static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
{
struct sh_flctl *flctl = dev_id;
@@ -1200,15 +1204,8 @@ static int flctl_probe(struct platform_device *pdev)

flctl_setup_dma(flctl);

- ret = nand_scan_ident(flctl_mtd, 1, NULL);
- if (ret)
- goto err_chip;
-
- ret = flctl_chip_init_tail(flctl_mtd);
- if (ret)
- goto err_chip;
-
- ret = nand_scan_tail(flctl_mtd);
+ nand->dummy_controller.ops = &flctl_nand_controller_ops;
+ ret = nand_scan(flctl_mtd, 1);
if (ret)
goto err_chip;

--
2.14.1


2018-07-20 15:19:32

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 23/35] mtd: rawnand: txx9ndfmc: rename nand controller internal structure

As already done in the core, calling a struct nand_controller
'hw_control' is misleading. Use the same name as in nand_base.c:
'controller'.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/txx9ndfmc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 8f5bbbac4612..9019022774f7 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -73,7 +73,7 @@ struct txx9ndfmc_drvdata {
void __iomem *base;
unsigned char hold; /* in gbusclock */
unsigned char spw; /* in gbusclock */
- struct nand_controller hw_control;
+ struct nand_controller controller;
};

static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
@@ -303,7 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw);

- nand_controller_init(&drvdata->hw_control);
+ nand_controller_init(&drvdata->controller);

platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
@@ -337,7 +337,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
chip->chip_delay = 100;
- chip->controller = &drvdata->hw_control;
+ chip->controller = &drvdata->controller;

nand_set_controller_data(chip, txx9_priv);
txx9_priv->dev = dev;
--
2.14.1


2018-07-20 15:19:38

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
1 file changed, 44 insertions(+), 31 deletions(-)

diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 7bc6be3f6ec0..967418f945ea 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
return 0;
}

+static int mtk_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct device *dev = mtd->dev.parent;
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
+ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+ int len;
+ int ret;
+
+ if (chip->options & NAND_BUSWIDTH_16) {
+ dev_err(dev, "16bits buswidth not supported");
+ return -EINVAL;
+ }
+
+ /* store bbt magic in page, cause OOB is not protected */
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ ret = mtk_nfc_ecc_init(dev, mtd);
+ if (ret)
+ return ret;
+
+ ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
+ if (ret)
+ return ret;
+
+ mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
+ mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
+
+ len = mtd->writesize + mtd->oobsize;
+ nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!nfc->buffer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct nand_controller_ops mtk_nfc_controller_ops = {
+ .attach_chip = mtk_nfc_attach_chip,
+};
+
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
struct device_node *np)
{
struct mtk_nfc_nand_chip *chip;
struct nand_chip *nand;
struct mtd_info *mtd;
- int nsels, len;
+ int nsels;
u32 tmp;
int ret;
int i;
@@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,

nand = &chip->nand;
nand->controller = &nfc->controller;
+ nand->controller->ops = &mtk_nfc_controller_ops;

nand_set_flash_node(nand, np);
nand_set_controller_data(nand, nfc);
@@ -1324,36 +1366,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,

mtk_nfc_hw_init(nfc);

- ret = nand_scan_ident(mtd, nsels, NULL);
- if (ret)
- return ret;
-
- /* store bbt magic in page, cause OOB is not protected */
- if (nand->bbt_options & NAND_BBT_USE_FLASH)
- nand->bbt_options |= NAND_BBT_NO_OOB;
-
- ret = mtk_nfc_ecc_init(dev, mtd);
- if (ret)
- return -EINVAL;
-
- if (nand->options & NAND_BUSWIDTH_16) {
- dev_err(dev, "16bits buswidth not supported");
- return -EINVAL;
- }
-
- ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
- if (ret)
- return ret;
-
- mtk_nfc_set_fdm(&chip->fdm, mtd);
- mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
-
- len = mtd->writesize + mtd->oobsize;
- nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
- if (!nfc->buffer)
- return -ENOMEM;
-
- ret = nand_scan_tail(mtd);
+ ret = nand_scan(mtd, nsels);
if (ret)
return ret;

--
2.14.1


2018-07-20 15:19:40

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 13/35] mtd: rawnand: marvell: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/marvell_nand.c | 205 +++++++++++++++++++-----------------
1 file changed, 108 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index bd5f9a4b7b16..7e5ffef0da76 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -2290,6 +2290,111 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
return 0;
}

+static int marvell_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+ struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+ struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(nfc->dev);
+ int ret;
+
+ if (pdata && pdata->flash_bbt)
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ /*
+ * We'll use a bad block table stored in-flash and don't
+ * allow writing the bad block marker to the flash.
+ */
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+ }
+
+ /* Save the chip-specific fields of NDCR */
+ marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
+ if (chip->options & NAND_BUSWIDTH_16)
+ marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+ /*
+ * On small page NANDs, only one cycle is needed to pass the
+ * column address.
+ */
+ if (mtd->writesize <= 512) {
+ marvell_nand->addr_cyc = 1;
+ } else {
+ marvell_nand->addr_cyc = 2;
+ marvell_nand->ndcr |= NDCR_RA_START;
+ }
+
+ /*
+ * Now add the number of cycles needed to pass the row
+ * address.
+ *
+ * Addressing a chip using CS 2 or 3 should also need the third row
+ * cycle but due to inconsistance in the documentation and lack of
+ * hardware to test this situation, this case is not supported.
+ */
+ if (chip->options & NAND_ROW_ADDR_3)
+ marvell_nand->addr_cyc += 3;
+ else
+ marvell_nand->addr_cyc += 2;
+
+ if (pdata) {
+ chip->ecc.size = pdata->ecc_step_size;
+ chip->ecc.strength = pdata->ecc_strength;
+ }
+
+ ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+ if (ret) {
+ dev_err(nfc->dev, "ECC init failed: %d\n", ret);
+ return ret;
+ }
+
+ if (chip->ecc.mode == NAND_ECC_HW) {
+ /*
+ * Subpage write not available with hardware ECC, prohibit also
+ * subpage read as in userspace subpage access would still be
+ * allowed and subpage write, if used, would lead to numerous
+ * uncorrectable ECC errors.
+ */
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
+ }
+
+ if (pdata || nfc->caps->legacy_of_bindings) {
+ /*
+ * We keep the MTD name unchanged to avoid breaking platforms
+ * where the MTD cmdline parser is used and the bootloader
+ * has not been updated to use the new naming scheme.
+ */
+ mtd->name = "pxa3xx_nand-0";
+ } else if (!mtd->name) {
+ /*
+ * If the new bindings are used and the bootloader has not been
+ * updated to pass a new mtdparts parameter on the cmdline, you
+ * should define the following property in your NAND node, ie:
+ *
+ * label = "main-storage";
+ *
+ * This way, mtd->name will be set by the core when
+ * nand_set_flash_node() is called.
+ */
+ mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+ "%s:nand.%d", dev_name(nfc->dev),
+ marvell_nand->sels[0].cs);
+ if (!mtd->name) {
+ dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops marvell_nand_controller_ops = {
+ .attach_chip = marvell_nand_attach_chip,
+};
+
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
struct device_node *np)
{
@@ -2432,105 +2537,11 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);

chip->options |= NAND_BUSWIDTH_AUTO;
- ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
- if (ret) {
- dev_err(dev, "could not identify the nand chip\n");
- return ret;
- }
-
- if (pdata && pdata->flash_bbt)
- chip->bbt_options |= NAND_BBT_USE_FLASH;
-
- if (chip->bbt_options & NAND_BBT_USE_FLASH) {
- /*
- * We'll use a bad block table stored in-flash and don't
- * allow writing the bad block marker to the flash.
- */
- chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
- chip->bbt_td = &bbt_main_descr;
- chip->bbt_md = &bbt_mirror_descr;
- }
-
- /* Save the chip-specific fields of NDCR */
- marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
- if (chip->options & NAND_BUSWIDTH_16)
- marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
-
- /*
- * On small page NANDs, only one cycle is needed to pass the
- * column address.
- */
- if (mtd->writesize <= 512) {
- marvell_nand->addr_cyc = 1;
- } else {
- marvell_nand->addr_cyc = 2;
- marvell_nand->ndcr |= NDCR_RA_START;
- }
-
- /*
- * Now add the number of cycles needed to pass the row
- * address.
- *
- * Addressing a chip using CS 2 or 3 should also need the third row
- * cycle but due to inconsistance in the documentation and lack of
- * hardware to test this situation, this case is not supported.
- */
- if (chip->options & NAND_ROW_ADDR_3)
- marvell_nand->addr_cyc += 3;
- else
- marvell_nand->addr_cyc += 2;
-
- if (pdata) {
- chip->ecc.size = pdata->ecc_step_size;
- chip->ecc.strength = pdata->ecc_strength;
- }
-
- ret = marvell_nand_ecc_init(mtd, &chip->ecc);
- if (ret) {
- dev_err(dev, "ECC init failed: %d\n", ret);
- return ret;
- }
-
- if (chip->ecc.mode == NAND_ECC_HW) {
- /*
- * Subpage write not available with hardware ECC, prohibit also
- * subpage read as in userspace subpage access would still be
- * allowed and subpage write, if used, would lead to numerous
- * uncorrectable ECC errors.
- */
- chip->options |= NAND_NO_SUBPAGE_WRITE;
- }
-
- if (pdata || nfc->caps->legacy_of_bindings) {
- /*
- * We keep the MTD name unchanged to avoid breaking platforms
- * where the MTD cmdline parser is used and the bootloader
- * has not been updated to use the new naming scheme.
- */
- mtd->name = "pxa3xx_nand-0";
- } else if (!mtd->name) {
- /*
- * If the new bindings are used and the bootloader has not been
- * updated to pass a new mtdparts parameter on the cmdline, you
- * should define the following property in your NAND node, ie:
- *
- * label = "main-storage";
- *
- * This way, mtd->name will be set by the core when
- * nand_set_flash_node() is called.
- */
- mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
- "%s:nand.%d", dev_name(nfc->dev),
- marvell_nand->sels[0].cs);
- if (!mtd->name) {
- dev_err(nfc->dev, "Failed to allocate mtd->name\n");
- return -ENOMEM;
- }
- }

- ret = nand_scan_tail(mtd);
+ chip->controller->ops = &marvell_nand_controller_ops;
+ ret = nand_scan(mtd, marvell_nand->nsels);
if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ dev_err(dev, "could not scan the nand chip\n");
return ret;
}

--
2.14.1


2018-07-20 15:19:47

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 11/35] mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/lpc32xx_mlc.c | 109 ++++++++++++++++++++-----------------
1 file changed, 59 insertions(+), 50 deletions(-)

diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index 052d123a8304..6f73136fa863 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -184,6 +184,7 @@ static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
};

struct lpc32xx_nand_host {
+ struct platform_device *pdev;
struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk;
@@ -653,6 +654,58 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}

+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+ struct device *dev = &host->pdev->dev;
+
+ host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dma_buf)
+ return -ENOMEM;
+
+ host->dummy_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+ if (!host->dummy_buf)
+ return -ENOMEM;
+
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.size = 512;
+ mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+ host->mlcsubpages = mtd->writesize / 512;
+
+ /* initially clear interrupt status */
+ readb(MLC_IRQ_SR(host->io_base));
+
+ init_completion(&host->comp_nand);
+ init_completion(&host->comp_controller);
+
+ host->irq = platform_get_irq(host->pdev, 0);
+ if (host->irq < 0) {
+ dev_err(dev, "failed to get platform irq\n");
+ return -EINVAL;
+ }
+
+ if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+ IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+ dev_err(dev, "Error requesting NAND IRQ\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void lpc32xx_nand_detach_chip(struct nand_chip *chip)
+{
+ struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+ free_irq(host->irq, host);
+}
+
+static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
+ .attach_chip = lpc32xx_nand_attach_chip,
+ .detach_chip = lpc32xx_nand_detach_chip,
+};
+
/*
* Probe for NAND controller
*/
@@ -669,6 +722,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (!host)
return -ENOMEM;

+ host->pdev = pdev;
+
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
if (IS_ERR(host->io_base))
@@ -749,58 +804,14 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}

/*
- * Scan to find existance of the device and
- * Get the type of NAND device SMALL block or LARGE block
+ * Scan to find existence of the device and get the type of NAND device:
+ * SMALL block or LARGE block.
*/
- res = nand_scan_ident(mtd, 1, NULL);
+ nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+ res = nand_scan(mtd, 1);
if (res)
goto release_dma_chan;

- host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
- if (!host->dma_buf) {
- res = -ENOMEM;
- goto release_dma_chan;
- }
-
- host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
- if (!host->dummy_buf) {
- res = -ENOMEM;
- goto release_dma_chan;
- }
-
- nand_chip->ecc.mode = NAND_ECC_HW;
- nand_chip->ecc.size = 512;
- mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
- host->mlcsubpages = mtd->writesize / 512;
-
- /* initially clear interrupt status */
- readb(MLC_IRQ_SR(host->io_base));
-
- init_completion(&host->comp_nand);
- init_completion(&host->comp_controller);
-
- host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- dev_err(&pdev->dev, "failed to get platform irq\n");
- res = -EINVAL;
- goto release_dma_chan;
- }
-
- if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
- IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
- dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
- res = -ENXIO;
- goto release_dma_chan;
- }
-
- /*
- * Fills out all the uninitialized function pointers with the defaults
- * And scans for a bad block table if appropriate.
- */
- res = nand_scan_tail(mtd);
- if (res)
- goto free_irq;
-
mtd->name = DRV_NAME;

res = mtd_device_register(mtd, host->ncfg->parts,
@@ -812,8 +823,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)

cleanup_nand:
nand_cleanup(nand_chip);
-free_irq:
- free_irq(host->irq, host);
release_dma_chan:
if (use_dma)
dma_release_channel(host->dma_chan);
--
2.14.1


2018-07-20 15:19:54

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 07/35] mtd: rawnand: fsmc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/fsmc_nand.c | 148 +++++++++++++++++++++------------------
1 file changed, 78 insertions(+), 70 deletions(-)

diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 59524d181bfe..f418236fa020 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -919,6 +919,82 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return 0;
}

+static int fsmc_nand_attach_chip(struct nand_chip *nand)
+{
+ struct mtd_info *mtd = nand_to_mtd(nand);
+ struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+
+ if (AMBA_REV_BITS(host->pid) >= 8) {
+ switch (mtd->oobsize) {
+ case 16:
+ case 64:
+ case 128:
+ case 224:
+ case 256:
+ break;
+ default:
+ dev_warn(host->dev,
+ "No oob scheme defined for oobsize %d\n",
+ mtd->oobsize);
+ return -EINVAL;
+ }
+
+ mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
+
+ return 0;
+ }
+
+ switch (nand->ecc.mode) {
+ case NAND_ECC_HW:
+ dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
+ nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+ nand->ecc.correct = nand_correct_data;
+ nand->ecc.bytes = 3;
+ nand->ecc.strength = 1;
+ break;
+
+ case NAND_ECC_SOFT:
+ if (nand->ecc.algo == NAND_ECC_BCH) {
+ dev_info(host->dev,
+ "Using 4-bit SW BCH ECC scheme\n");
+ break;
+ }
+
+ case NAND_ECC_ON_DIE:
+ break;
+
+ default:
+ dev_err(host->dev, "Unsupported ECC mode!\n");
+ return -ENOTSUPP;
+ }
+
+ /*
+ * Don't set layout for BCH4 SW ECC. This will be
+ * generated later in nand_bch_init() later.
+ */
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ switch (mtd->oobsize) {
+ case 16:
+ case 64:
+ case 128:
+ mtd_set_ooblayout(mtd,
+ &fsmc_ecc1_ooblayout_ops);
+ break;
+ default:
+ dev_warn(host->dev,
+ "No oob scheme defined for oobsize %d\n",
+ mtd->oobsize);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops fsmc_nand_controller_ops = {
+ .attach_chip = fsmc_nand_attach_chip,
+};
+
/*
* fsmc_nand_probe - Probe function
* @pdev: platform device structure
@@ -1048,76 +1124,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret) {
- dev_err(&pdev->dev, "No NAND Device found!\n");
- goto release_dma_write_chan;
- }
-
- if (AMBA_REV_BITS(host->pid) >= 8) {
- switch (mtd->oobsize) {
- case 16:
- case 64:
- case 128:
- case 224:
- case 256:
- break;
- default:
- dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
- ret = -EINVAL;
- goto release_dma_write_chan;
- }
-
- mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
- } else {
- switch (nand->ecc.mode) {
- case NAND_ECC_HW:
- dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
- nand->ecc.calculate = fsmc_read_hwecc_ecc1;
- nand->ecc.correct = nand_correct_data;
- nand->ecc.bytes = 3;
- nand->ecc.strength = 1;
- break;
-
- case NAND_ECC_SOFT:
- if (nand->ecc.algo == NAND_ECC_BCH) {
- dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
- break;
- }
-
- case NAND_ECC_ON_DIE:
- break;
-
- default:
- dev_err(&pdev->dev, "Unsupported ECC mode!\n");
- goto release_dma_write_chan;
- }
-
- /*
- * Don't set layout for BCH4 SW ECC. This will be
- * generated later in nand_bch_init() later.
- */
- if (nand->ecc.mode == NAND_ECC_HW) {
- switch (mtd->oobsize) {
- case 16:
- case 64:
- case 128:
- mtd_set_ooblayout(mtd,
- &fsmc_ecc1_ooblayout_ops);
- break;
- default:
- dev_warn(&pdev->dev,
- "No oob scheme defined for oobsize %d\n",
- mtd->oobsize);
- ret = -EINVAL;
- goto release_dma_write_chan;
- }
- }
- }
-
- /* Second stage of scan to fill MTD data-structures */
- ret = nand_scan_tail(mtd);
+ nand->dummy_controller.ops = &fsmc_nand_controller_ops;
+ ret = nand_scan(mtd, 1);
if (ret)
goto release_dma_write_chan;

--
2.14.1


2018-07-20 15:20:09

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 19/35] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function

Prepare the conversion of the sh_flctl driver to nand_scan() by moving
all the configuration that must be made after nand_scan_ident() in one
single function. Create a pdata entry in the controller structure for
that.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/sh_flctl.c | 38 +++++++++++++++++++-------------------
include/linux/mtd/sh_flctl.h | 1 +
2 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index c7abceffcc40..d37d1d3ccbf9 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -1007,6 +1007,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
struct sh_flctl *flctl = mtd_to_flctl(mtd);
struct nand_chip *chip = &flctl->chip;

+ if (chip->options & NAND_BUSWIDTH_16) {
+ /*
+ * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
+ * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
+ * flctl->flcmncr_base to pdata->flcmncr_val.
+ */
+ flctl->pdata->flcmncr_val |= SEL_16BIT;
+ flctl->flcmncr_base = flctl->pdata->flcmncr_val;
+ }
+
if (mtd->writesize == 512) {
flctl->page_size = 0;
if (chip->chipsize > (32 << 20)) {
@@ -1122,7 +1132,6 @@ static int flctl_probe(struct platform_device *pdev)
struct sh_flctl *flctl;
struct mtd_info *flctl_mtd;
struct nand_chip *nand;
- struct sh_flctl_platform_data *pdata;
int ret;
int irq;

@@ -1150,11 +1159,11 @@ static int flctl_probe(struct platform_device *pdev)
}

if (pdev->dev.of_node)
- pdata = flctl_parse_dt(&pdev->dev);
+ flctl->pdata = flctl_parse_dt(&pdev->dev);
else
- pdata = dev_get_platdata(&pdev->dev);
+ flctl->pdata = dev_get_platdata(&pdev->dev);

- if (!pdata) {
+ if (!flctl->pdata) {
dev_err(&pdev->dev, "no setup data defined\n");
return -EINVAL;
}
@@ -1165,9 +1174,9 @@ static int flctl_probe(struct platform_device *pdev)
nand_set_flash_node(nand, pdev->dev.of_node);
flctl_mtd->dev.parent = &pdev->dev;
flctl->pdev = pdev;
- flctl->hwecc = pdata->has_hwecc;
- flctl->holden = pdata->use_holden;
- flctl->flcmncr_base = pdata->flcmncr_val;
+ flctl->hwecc = flctl->pdata->has_hwecc;
+ flctl->holden = flctl->pdata->use_holden;
+ flctl->flcmncr_base = flctl->pdata->flcmncr_val;
flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;

/* Set address of hardware control function */
@@ -1183,7 +1192,7 @@ static int flctl_probe(struct platform_device *pdev)
nand->set_features = nand_get_set_features_notsupp;
nand->get_features = nand_get_set_features_notsupp;

- if (pdata->flcmncr_val & SEL_16BIT)
+ if (flctl->pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16;

pm_runtime_enable(&pdev->dev);
@@ -1195,16 +1204,6 @@ static int flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;

- if (nand->options & NAND_BUSWIDTH_16) {
- /*
- * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
- * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
- * flctl->flcmncr_base to pdata->flcmncr_val.
- */
- pdata->flcmncr_val |= SEL_16BIT;
- flctl->flcmncr_base = pdata->flcmncr_val;
- }
-
ret = flctl_chip_init_tail(flctl_mtd);
if (ret)
goto err_chip;
@@ -1213,7 +1212,8 @@ static int flctl_probe(struct platform_device *pdev)
if (ret)
goto err_chip;

- ret = mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+ ret = mtd_device_register(flctl_mtd, flctl->pdata->parts,
+ flctl->pdata->nr_parts);
if (ret)
goto cleanup_nand;

diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index c759d403cbc0..c9f486c6c019 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -148,6 +148,7 @@ struct sh_flctl {
struct dev_pm_qos_request pm_qos;
void __iomem *reg;
resource_size_t fifo;
+ struct sh_flctl_platform_data *pdata;

uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
int read_bytes;
--
2.14.1


2018-07-20 15:20:17

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 02/35] mtd: rawnand: cafe: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/cafe_nand.c | 130 +++++++++++++++++++++++----------------
1 file changed, 76 insertions(+), 54 deletions(-)

diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index ac0be933a490..c303c261dd8d 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -71,7 +71,9 @@ struct cafe_priv {
unsigned char *dmabuf;
};

-static int usedma = 1;
+#define CAFE_DEFAULT_DMA 1
+
+static int usedma = CAFE_DEFAULT_DMA;
module_param(usedma, int, 0644);

static int skipbbt = 0;
@@ -593,6 +595,76 @@ static int cafe_mul(int x)
return gf4096_mul(x, 0xe01);
}

+static int cafe_nand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
+ int err = 0;
+
+ cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
+ &cafe->dmaaddr, GFP_KERNEL);
+ if (!cafe->dmabuf)
+ return -ENOMEM;
+
+ /* Set up DMA address */
+ cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
+ cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
+
+ cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+ cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+ /* Restore the DMA flag */
+ usedma = CAFE_DEFAULT_DMA;
+
+ cafe->ctl2 = BIT(27); /* Reed-Solomon ECC */
+ if (mtd->writesize == 2048)
+ cafe->ctl2 |= BIT(29); /* 2KiB page size */
+
+ /* Set up ECC according to the type of chip we found */
+ mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
+ if (mtd->writesize == 2048) {
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+ } else if (mtd->writesize == 512) {
+ cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+ cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+ } else {
+ dev_warn(&cafe->pdev->dev,
+ "Unexpected NAND flash writesize %d. Aborting\n",
+ mtd->writesize);
+ err = -ENOTSUPP;
+ goto out_free_dma;
+ }
+
+ cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+ cafe->nand.ecc.size = mtd->writesize;
+ cafe->nand.ecc.bytes = 14;
+ cafe->nand.ecc.strength = 4;
+ cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+ cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+ cafe->nand.ecc.read_page = cafe_nand_read_page;
+ cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+ return 0;
+
+ out_free_dma:
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+
+ return err;
+}
+
+static void cafe_nand_detach_chip(struct nand_chip *chip)
+{
+ struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+ dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+}
+
+static const struct nand_controller_ops cafe_nand_controller_ops = {
+ .attach_chip = cafe_nand_attach_chip,
+ .detach_chip = cafe_nand_detach_chip,
+};
+
static int cafe_nand_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -600,7 +672,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
struct cafe_priv *cafe;
uint32_t ctrl;
int err = 0;
- int old_dma;

/* Very old versions shared the same PCI ident for all three
functions on the chip. Verify the class too... */
@@ -708,62 +779,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe_readl(cafe, GLOBAL_CTRL),
cafe_readl(cafe, GLOBAL_IRQ_MASK));

- /* Do not use the DMA for the nand_scan_ident() */
- old_dma = usedma;
+ /* Do not use the DMA during the NAND identification */
usedma = 0;

/* Scan to find existence of the device */
- err = nand_scan_ident(mtd, 2, NULL);
+ cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
+ err = nand_scan(mtd, 2);
if (err)
goto out_irq;

- cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
- &cafe->dmaaddr, GFP_KERNEL);
- if (!cafe->dmabuf) {
- err = -ENOMEM;
- goto out_irq;
- }
-
- /* Set up DMA address */
- cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
- cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
-
- cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
- cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
-
- /* Restore the DMA flag */
- usedma = old_dma;
-
- cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
- if (mtd->writesize == 2048)
- cafe->ctl2 |= 1<<29; /* 2KiB page size */
-
- /* Set up ECC according to the type of chip we found */
- mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
- if (mtd->writesize == 2048) {
- cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
- cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
- } else if (mtd->writesize == 512) {
- cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
- cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
- } else {
- pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
- mtd->writesize);
- goto out_free_dma;
- }
- cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
- cafe->nand.ecc.size = mtd->writesize;
- cafe->nand.ecc.bytes = 14;
- cafe->nand.ecc.strength = 4;
- cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
- cafe->nand.ecc.write_oob = cafe_nand_write_oob;
- cafe->nand.ecc.read_page = cafe_nand_read_page;
- cafe->nand.ecc.read_oob = cafe_nand_read_oob;
-
- err = nand_scan_tail(mtd);
- if (err)
- goto out_free_dma;
-
pci_set_drvdata(pdev, mtd);

mtd->name = "cafe_nand";
@@ -775,8 +799,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,

out_cleanup_nand:
nand_cleanup(&cafe->nand);
- out_free_dma:
- dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
out_irq:
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
--
2.14.1


2018-07-20 15:20:32

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 08/35] mtd: rawnand: gpmi: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 56 ++++++++++++++++++------------
1 file changed, 33 insertions(+), 23 deletions(-)

diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 6294d018df65..1c1ebbc82824 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -744,9 +744,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
* [2] Allocate a read/write data buffer.
* The gpmi_alloc_dma_buffer can be called twice.
* We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
- * is called before the nand_scan_ident; and we allocate a buffer
- * of the real NAND page size when the gpmi_alloc_dma_buffer is
- * called after the nand_scan_ident.
+ * is called before the NAND identification; and we allocate a
+ * buffer of the real NAND page size when the gpmi_alloc_dma_buffer
+ * is called after.
*/
this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
GFP_DMA | GFP_KERNEL);
@@ -1865,6 +1865,34 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
return 0;
}

+static int gpmi_nand_attach_chip(struct nand_chip *chip)
+{
+ struct gpmi_nand_data *this = nand_get_controller_data(chip);
+ int ret;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (of_property_read_bool(this->dev->of_node,
+ "fsl,no-blockmark-swap"))
+ this->swap_block_mark = false;
+ }
+ dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+ this->swap_block_mark ? "en" : "dis");
+
+ ret = gpmi_init_last(this);
+ if (ret)
+ return ret;
+
+ chip->options |= NAND_SKIP_BBTSCAN;
+
+ return 0;
+}
+
+static const struct nand_controller_ops gpmi_nand_controller_ops = {
+ .attach_chip = gpmi_nand_attach_chip,
+};
+
static int gpmi_nand_init(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
@@ -1905,26 +1933,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;

- ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
- if (ret)
- goto err_out;
-
- if (chip->bbt_options & NAND_BBT_USE_FLASH) {
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- if (of_property_read_bool(this->dev->of_node,
- "fsl,no-blockmark-swap"))
- this->swap_block_mark = false;
- }
- dev_dbg(this->dev, "Blockmark swapping %sabled\n",
- this->swap_block_mark ? "en" : "dis");
-
- ret = gpmi_init_last(this);
- if (ret)
- goto err_out;
-
- chip->options |= NAND_SKIP_BBTSCAN;
- ret = nand_scan_tail(mtd);
+ chip->dummy_controller.ops = &gpmi_nand_controller_ops;
+ ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;

--
2.14.1


2018-07-20 15:20:39

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 05/35] mtd: rawnand: fsl_elbc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/fsl_elbc_nand.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 0aa54a949653..44893e49b386 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -637,9 +637,9 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}

-static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_elbc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -706,6 +706,10 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
return 0;
}

+static const struct nand_controller_ops fsl_elbc_controller_ops = {
+ .attach_chip = fsl_elbc_attach_chip,
+};
+
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
@@ -910,15 +914,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
if (ret)
goto err;

- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- goto err;
-
- ret = fsl_elbc_chip_init_tail(mtd);
- if (ret)
- goto err;
-
- ret = nand_scan_tail(mtd);
+ priv->chip.controller->ops = &fsl_elbc_controller_ops;
+ ret = nand_scan(mtd, 1);
if (ret)
goto err;

--
2.14.1


2018-07-20 15:20:43

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 09/35] mtd: rawnand: hisi504: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/hisi504_nand.c | 78 +++++++++++++++++++++----------------
1 file changed, 44 insertions(+), 34 deletions(-)

diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index a1e009c8e556..950dc7789296 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -709,9 +709,50 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
return 0;
}

+static int hisi_nfc_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct hinfc_host *host = nand_get_controller_data(chip);
+ int flag;
+
+ host->buffer = dmam_alloc_coherent(host->dev,
+ mtd->writesize + mtd->oobsize,
+ &host->dma_buffer, GFP_KERNEL);
+ if (!host->buffer)
+ return -ENOMEM;
+
+ host->dma_oob = host->dma_buffer + mtd->writesize;
+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+ flag = hinfc_read(host, HINFC504_CON);
+ flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+ switch (mtd->writesize) {
+ case 2048:
+ flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
+ break;
+ /*
+ * TODO: add more pagesize support,
+ * default pagesize has been set in hisi_nfc_host_init
+ */
+ default:
+ dev_err(host->dev, "NON-2KB page size nand flash\n");
+ return -EINVAL;
+ }
+ hinfc_write(host, flag, HINFC504_CON);
+
+ if (chip->ecc.mode == NAND_ECC_HW)
+ hisi_nfc_ecc_probe(host);
+
+ return 0;
+}
+
+static const struct nand_controller_ops hisi_nfc_controller_ops = {
+ .attach_chip = hisi_nfc_attach_chip,
+};
+
static int hisi_nfc_probe(struct platform_device *pdev)
{
- int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
+ int ret = 0, irq, max_chips = HINFC504_MAX_CHIP;
struct device *dev = &pdev->dev;
struct hinfc_host *host;
struct nand_chip *chip;
@@ -769,42 +810,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
return ret;
}

- ret = nand_scan_ident(mtd, max_chips, NULL);
+ chip->dummy_controller.ops = &hisi_nfc_controller_ops;
+ ret = nand_scan(mtd, max_chips);
if (ret)
return ret;

- host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
- &host->dma_buffer, GFP_KERNEL);
- if (!host->buffer)
- return -ENOMEM;
-
- host->dma_oob = host->dma_buffer + mtd->writesize;
- memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-
- flag = hinfc_read(host, HINFC504_CON);
- flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
- switch (mtd->writesize) {
- case 2048:
- flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
- /*
- * TODO: add more pagesize support,
- * default pagesize has been set in hisi_nfc_host_init
- */
- default:
- dev_err(dev, "NON-2KB page size nand flash\n");
- return -EINVAL;
- }
- hinfc_write(host, flag, HINFC504_CON);
-
- if (chip->ecc.mode == NAND_ECC_HW)
- hisi_nfc_ecc_probe(host);
-
- ret = nand_scan_tail(mtd);
- if (ret) {
- dev_err(dev, "nand_scan_tail failed: %d\n", ret);
- return ret;
- }
-
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "Err MTD partition=%d\n", ret);
--
2.14.1


2018-07-20 15:20:51

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 06/35] mtd: rawnand: fsl_ifc: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/fsl_ifc_nand.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index 96130d91e32c..24f59d0066af 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -714,9 +714,9 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}

-static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_ifc_attach_chip(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);

dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
@@ -757,6 +757,10 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
return 0;
}

+static const struct nand_controller_ops fsl_ifc_controller_ops = {
+ .attach_chip = fsl_ifc_attach_chip,
+};
+
static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
{
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
@@ -1046,15 +1050,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
if (ret)
goto err;

- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- goto err;
-
- ret = fsl_ifc_chip_init_tail(mtd);
- if (ret)
- goto err;
-
- ret = nand_scan_tail(mtd);
+ priv->chip.controller->ops = &fsl_ifc_controller_ops;
+ ret = nand_scan(mtd, 1);
if (ret)
goto err;

--
2.14.1


2018-07-20 15:20:58

by Miquel Raynal

[permalink] [raw]
Subject: [PATCH v4 01/35] mtd: rawnand: brcmnand: convert driver to nand_scan()

Two helpers have been added to the core to make ECC-related
configuration between the detection phase and the final NAND scan. Use
these hooks and convert the driver to just use nand_scan() instead of
both nand_scan_ident() and nand_scan_tail().

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/mtd/nand/raw/brcmnand/brcmnand.c | 47 +++++++++++++++++++-------------
1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 2e5efa0f9ea2..071f09af56dc 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2208,6 +2208,32 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
return 0;
}

+static int brcmnand_attach_chip(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct brcmnand_host *host = nand_get_controller_data(chip);
+ int ret;
+
+ if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+
+ if (brcmnand_setup_dev(host))
+ return -ENXIO;
+
+ chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
+
+ /* only use our internal HW threshold */
+ mtd->bitflip_threshold = 1;
+
+ ret = brcmstb_choose_ecc_layout(host);
+
+ return ret;
+}
+
+static const struct nand_controller_ops brcmnand_controller_ops = {
+ .attach_chip = brcmnand_attach_chip,
+};
+
static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
{
struct brcmnand_controller *ctrl = host->ctrl;
@@ -2267,10 +2293,6 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);

- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
- return ret;
-
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
@@ -2279,21 +2301,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
*/
chip->options |= NAND_USE_BOUNCE_BUFFER;

- if (chip->bbt_options & NAND_BBT_USE_FLASH)
- chip->bbt_options |= NAND_BBT_NO_OOB;
-
- if (brcmnand_setup_dev(host))
- return -ENXIO;
-
- chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
- /* only use our internal HW threshold */
- mtd->bitflip_threshold = 1;
-
- ret = brcmstb_choose_ecc_layout(host);
- if (ret)
- return ret;
-
- ret = nand_scan_tail(mtd);
+ ret = nand_scan(mtd, 1);
if (ret)
return ret;

@@ -2434,6 +2442,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
nand_controller_init(&ctrl->controller);
+ ctrl->controller.ops = &brcmnand_controller_ops;
INIT_LIST_HEAD(&ctrl->host_list);

/* NAND register range */
--
2.14.1


2018-07-21 06:24:48

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 01/35] mtd: rawnand: brcmnand: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:53 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/brcmnand/brcmnand.c | 47 +++++++++++++++++++-------------
> 1 file changed, 28 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> index 2e5efa0f9ea2..071f09af56dc 100644
> --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> @@ -2208,6 +2208,32 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
> return 0;
> }
>
> +static int brcmnand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct brcmnand_host *host = nand_get_controller_data(chip);
> + int ret;
> +
> + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + if (brcmnand_setup_dev(host))
> + return -ENXIO;
> +
> + chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
> +
> + /* only use our internal HW threshold */
> + mtd->bitflip_threshold = 1;
> +
> + ret = brcmstb_choose_ecc_layout(host);
> +
> + return ret;
> +}
> +
> +static const struct nand_controller_ops brcmnand_controller_ops = {
> + .attach_chip = brcmnand_attach_chip,
> +};
> +
> static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> {
> struct brcmnand_controller *ctrl = host->ctrl;
> @@ -2267,10 +2293,6 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> nand_writereg(ctrl, cfg_offs,
> nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret)
> - return ret;
> -
> chip->options |= NAND_NO_SUBPAGE_WRITE;
> /*
> * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
> @@ -2279,21 +2301,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
> */
> chip->options |= NAND_USE_BOUNCE_BUFFER;
>

Any reason for not moving the above chunk in brcmnand_attach_chip()?

Since ->attach_chip() is called between nand_scan_ident() and
nand_scan_tail() in nand_scan(), I'd recommend simply copying all the
code found between those 2 calls (applies to all drivers).

> - if (chip->bbt_options & NAND_BBT_USE_FLASH)
> - chip->bbt_options |= NAND_BBT_NO_OOB;
> -
> - if (brcmnand_setup_dev(host))
> - return -ENXIO;
> -
> - chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
> - /* only use our internal HW threshold */
> - mtd->bitflip_threshold = 1;
> -
> - ret = brcmstb_choose_ecc_layout(host);
> - if (ret)
> - return ret;
> -
> - ret = nand_scan_tail(mtd);
> + ret = nand_scan(mtd, 1);
> if (ret)
> return ret;
>
> @@ -2434,6 +2442,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
> init_completion(&ctrl->done);
> init_completion(&ctrl->dma_done);
> nand_controller_init(&ctrl->controller);
> + ctrl->controller.ops = &brcmnand_controller_ops;
> INIT_LIST_HEAD(&ctrl->host_list);
>
> /* NAND register range */


2018-07-21 06:39:00

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 02/35] mtd: rawnand: cafe: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:54 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/cafe_nand.c | 130 +++++++++++++++++++++++----------------
> 1 file changed, 76 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
> index ac0be933a490..c303c261dd8d 100644
> --- a/drivers/mtd/nand/raw/cafe_nand.c
> +++ b/drivers/mtd/nand/raw/cafe_nand.c
> @@ -71,7 +71,9 @@ struct cafe_priv {
> unsigned char *dmabuf;
> };
>
> -static int usedma = 1;
> +#define CAFE_DEFAULT_DMA 1
> +
> +static int usedma = CAFE_DEFAULT_DMA;

Not sure you need a macro for that.

> module_param(usedma, int, 0644);
>
> static int skipbbt = 0;
> @@ -593,6 +595,76 @@ static int cafe_mul(int x)
> return gf4096_mul(x, 0xe01);
> }
>
> +static int cafe_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct cafe_priv *cafe = nand_get_controller_data(chip);
> + int err = 0;
> +
> + cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
> + &cafe->dmaaddr, GFP_KERNEL);
> + if (!cafe->dmabuf)
> + return -ENOMEM;
> +
> + /* Set up DMA address */
> + cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
> + cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
> +
> + cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
> + cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
> +
> + /* Restore the DMA flag */
> + usedma = CAFE_DEFAULT_DMA;

This is wrong. The user might have passed a different value to usedma
when loading the module (or on the kernel cmdline), and you're simply
ignoring it. I see 2 solutions to solve that:

1/ add a ->usedma field to the cafe_priv struct which you initialize to
0 in the probe function (already done if you kzalloc() the struct)
and update it here:

cafe->usedma = usedma.

then you have to patch all places where usedma was tested and
replace this test by a test on cafe->usedma

2/ add a static in old_usedma which you assign to usedma value in the
probe and then restore the usedma value here:

usedma = old_usedma

I prefer option #1.

2018-07-21 06:46:57

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 03/35] mtd: rawnand: davinci: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:55 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Also change the unused "struct device *dev" parameter of the driver
> structure into a platform device to reuse it in the ->attach_chip()
> hook.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/davinci_nand.c | 195 +++++++++++++++++++-----------------
> 1 file changed, 102 insertions(+), 93 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
> index 626c9363e460..40145e206a6b 100644
> --- a/drivers/mtd/nand/raw/davinci_nand.c
> +++ b/drivers/mtd/nand/raw/davinci_nand.c
> @@ -53,7 +53,7 @@
> struct davinci_nand_info {
> struct nand_chip chip;
>
> - struct device *dev;
> + struct platform_device *pdev;

For the record, there's a to_platform_device() macro you can use to get
a platform_device object from a device one, so this change was not
really needed. Actually, you should not even need a ->dev field here
because it can be retrieved from mtd->dev.parent. Anyway, if you
patched all places using davinci->dev to now use &davinci->pdev->dev
we should be good.

Reviewed-by: Boris Brezillon <[email protected]>

>
> bool is_readmode;
>
> @@ -605,6 +605,104 @@ static struct davinci_nand_pdata
> }
> #endif
>
> +static int davinci_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct davinci_nand_info *info = to_davinci_nand(mtd);
> + struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
> + int ret = 0;
> +
> + if (IS_ERR(pdata))
> + return PTR_ERR(pdata);
> +
> + switch (info->chip.ecc.mode) {
> + case NAND_ECC_NONE:
> + pdata->ecc_bits = 0;
> + break;
> + case NAND_ECC_SOFT:
> + pdata->ecc_bits = 0;
> + /*
> + * This driver expects Hamming based ECC when ecc_mode is set
> + * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
> + * avoid adding an extra ->ecc_algo field to
> + * davinci_nand_pdata.
> + */
> + info->chip.ecc.algo = NAND_ECC_HAMMING;
> + break;
> + case NAND_ECC_HW:
> + if (pdata->ecc_bits == 4) {
> + /*
> + * No sanity checks: CPUs must support this,
> + * and the chips may not use NAND_BUSWIDTH_16.
> + */
> +
> + /* No sharing 4-bit hardware between chipselects yet */
> + spin_lock_irq(&davinci_nand_lock);
> + if (ecc4_busy)
> + ret = -EBUSY;
> + else
> + ecc4_busy = true;
> + spin_unlock_irq(&davinci_nand_lock);
> +
> + if (ret == -EBUSY)
> + return ret;
> +
> + info->chip.ecc.calculate = nand_davinci_calculate_4bit;
> + info->chip.ecc.correct = nand_davinci_correct_4bit;
> + info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
> + info->chip.ecc.bytes = 10;
> + info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
> + info->chip.ecc.algo = NAND_ECC_BCH;
> + } else {
> + /* 1bit ecc hamming */
> + info->chip.ecc.calculate = nand_davinci_calculate_1bit;
> + info->chip.ecc.correct = nand_davinci_correct_1bit;
> + info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
> + info->chip.ecc.bytes = 3;
> + info->chip.ecc.algo = NAND_ECC_HAMMING;
> + }
> + info->chip.ecc.size = 512;
> + info->chip.ecc.strength = pdata->ecc_bits;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + /*
> + * Update ECC layout if needed ... for 1-bit HW ECC, the default
> + * is OK, but it allocates 6 bytes when only 3 are needed (for
> + * each 512 bytes). For the 4-bit HW ECC, that default is not
> + * usable: 10 bytes are needed, not 6.
> + */
> + if (pdata->ecc_bits == 4) {
> + int chunks = mtd->writesize / 512;
> +
> + if (!chunks || mtd->oobsize < 16) {
> + dev_dbg(&info->pdev->dev, "too small\n");
> + return -EINVAL;
> + }
> +
> + /* For small page chips, preserve the manufacturer's
> + * badblock marking data ... and make sure a flash BBT
> + * table marker fits in the free bytes.
> + */
> + if (chunks == 1) {
> + mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
> + } else if (chunks == 4 || chunks == 8) {
> + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> + info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
> + } else {
> + return -EIO;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static const struct nand_controller_ops davinci_nand_controller_ops = {
> + .attach_chip = davinci_nand_attach_chip,
> +};
> +
> static int nand_davinci_probe(struct platform_device *pdev)
> {
> struct davinci_nand_pdata *pdata;
> @@ -658,7 +756,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
> return -EADDRNOTAVAIL;
> }
>
> - info->dev = &pdev->dev;
> + info->pdev = pdev;
> info->base = base;
> info->vaddr = vaddr;
>
> @@ -708,97 +806,13 @@ static int nand_davinci_probe(struct platform_device *pdev)
> spin_unlock_irq(&davinci_nand_lock);
>
> /* Scan to find existence of the device(s) */
> - ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
> + info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
> + ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
> if (ret < 0) {
> dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
> return ret;
> }
>
> - switch (info->chip.ecc.mode) {
> - case NAND_ECC_NONE:
> - pdata->ecc_bits = 0;
> - break;
> - case NAND_ECC_SOFT:
> - pdata->ecc_bits = 0;
> - /*
> - * This driver expects Hamming based ECC when ecc_mode is set
> - * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
> - * avoid adding an extra ->ecc_algo field to
> - * davinci_nand_pdata.
> - */
> - info->chip.ecc.algo = NAND_ECC_HAMMING;
> - break;
> - case NAND_ECC_HW:
> - if (pdata->ecc_bits == 4) {
> - /* No sanity checks: CPUs must support this,
> - * and the chips may not use NAND_BUSWIDTH_16.
> - */
> -
> - /* No sharing 4-bit hardware between chipselects yet */
> - spin_lock_irq(&davinci_nand_lock);
> - if (ecc4_busy)
> - ret = -EBUSY;
> - else
> - ecc4_busy = true;
> - spin_unlock_irq(&davinci_nand_lock);
> -
> - if (ret == -EBUSY)
> - return ret;
> -
> - info->chip.ecc.calculate = nand_davinci_calculate_4bit;
> - info->chip.ecc.correct = nand_davinci_correct_4bit;
> - info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
> - info->chip.ecc.bytes = 10;
> - info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
> - info->chip.ecc.algo = NAND_ECC_BCH;
> - } else {
> - /* 1bit ecc hamming */
> - info->chip.ecc.calculate = nand_davinci_calculate_1bit;
> - info->chip.ecc.correct = nand_davinci_correct_1bit;
> - info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
> - info->chip.ecc.bytes = 3;
> - info->chip.ecc.algo = NAND_ECC_HAMMING;
> - }
> - info->chip.ecc.size = 512;
> - info->chip.ecc.strength = pdata->ecc_bits;
> - break;
> - default:
> - return -EINVAL;
> - }
> -
> - /* Update ECC layout if needed ... for 1-bit HW ECC, the default
> - * is OK, but it allocates 6 bytes when only 3 are needed (for
> - * each 512 bytes). For the 4-bit HW ECC, that default is not
> - * usable: 10 bytes are needed, not 6.
> - */
> - if (pdata->ecc_bits == 4) {
> - int chunks = mtd->writesize / 512;
> -
> - if (!chunks || mtd->oobsize < 16) {
> - dev_dbg(&pdev->dev, "too small\n");
> - ret = -EINVAL;
> - goto err;
> - }
> -
> - /* For small page chips, preserve the manufacturer's
> - * badblock marking data ... and make sure a flash BBT
> - * table marker fits in the free bytes.
> - */
> - if (chunks == 1) {
> - mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
> - } else if (chunks == 4 || chunks == 8) {
> - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> - info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
> - } else {
> - ret = -EIO;
> - goto err;
> - }
> - }
> -
> - ret = nand_scan_tail(mtd);
> - if (ret < 0)
> - goto err;
> -
> if (pdata->parts)
> ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
> else
> @@ -815,11 +829,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
> err_cleanup_nand:
> nand_cleanup(&info->chip);
>
> -err:
> - spin_lock_irq(&davinci_nand_lock);
> - if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
> - ecc4_busy = false;
> - spin_unlock_irq(&davinci_nand_lock);
> return ret;
> }
>


2018-07-21 06:48:14

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

On Fri, 20 Jul 2018 17:14:56 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/denali.c | 138 +++++++++++++++++++++++-------------------
> 1 file changed, 77 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
> index 4d53f41ada08..2fa92c297a66 100644
> --- a/drivers/mtd/nand/raw/denali.c
> +++ b/drivers/mtd/nand/raw/denali.c
> @@ -1205,62 +1205,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
> return 0;
> }
>
> -int denali_init(struct denali_nand_info *denali)
> +static int denali_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &denali->nand;
> struct mtd_info *mtd = nand_to_mtd(chip);
> - u32 features = ioread32(denali->reg + FEATURES);
> + struct denali_nand_info *denali = mtd_to_denali(mtd);
> int ret;
>
> - mtd->dev.parent = denali->dev;
> - denali_hw_init(denali);
> -
> - init_completion(&denali->complete);
> - spin_lock_init(&denali->irq_lock);
> -
> - denali_clear_irq_all(denali);
> -
> - ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
> - IRQF_SHARED, DENALI_NAND_NAME, denali);
> - if (ret) {
> - dev_err(denali->dev, "Unable to request IRQ\n");
> - return ret;
> - }
> -
> - denali_enable_irq(denali);
> - denali_reset_banks(denali);
> -
> - denali->active_bank = DENALI_INVALID_BANK;
> -
> - nand_set_flash_node(chip, denali->dev->of_node);
> - /* Fallback to the default name if DT did not give "label" property */
> - if (!mtd->name)
> - mtd->name = "denali-nand";
> -
> - chip->select_chip = denali_select_chip;
> - chip->read_byte = denali_read_byte;
> - chip->write_byte = denali_write_byte;
> - chip->read_word = denali_read_word;
> - chip->cmd_ctrl = denali_cmd_ctrl;
> - chip->dev_ready = denali_dev_ready;
> - chip->waitfunc = denali_waitfunc;
> -
> - if (features & FEATURES__INDEX_ADDR) {
> - denali->host_read = denali_indexed_read;
> - denali->host_write = denali_indexed_write;
> - } else {
> - denali->host_read = denali_direct_read;
> - denali->host_write = denali_direct_write;
> - }
> -
> - /* clk rate info is needed for setup_data_interface */
> - if (denali->clk_rate && denali->clk_x_rate)
> - chip->setup_data_interface = denali_setup_data_interface;
> -
> - ret = nand_scan_ident(mtd, denali->max_banks, NULL);
> - if (ret)
> - goto disable_irq;
> -
> if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
> denali->dma_avail = 1;
>
> @@ -1293,7 +1243,7 @@ int denali_init(struct denali_nand_info *denali)
> mtd->oobsize - denali->oob_skip_bytes);
> if (ret) {
> dev_err(denali->dev, "Failed to setup ECC settings.\n");
> - goto disable_irq;
> + return ret;
> }
>
> dev_dbg(denali->dev,
> @@ -1337,7 +1287,7 @@ int denali_init(struct denali_nand_info *denali)
>
> ret = denali_multidev_fixup(denali);
> if (ret)
> - goto disable_irq;
> + return ret;
>
> /*
> * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
> @@ -1345,26 +1295,92 @@ int denali_init(struct denali_nand_info *denali)
> * guarantee DMA-safe alignment.
> */
> denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
> - if (!denali->buf) {
> - ret = -ENOMEM;
> - goto disable_irq;
> + if (!denali->buf)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +static void denali_detach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct denali_nand_info *denali = mtd_to_denali(mtd);
> +
> + kfree(denali->buf);
> +}
> +
> +static const struct nand_controller_ops denali_controller_ops = {
> + .attach_chip = denali_attach_chip,
> + .detach_chip = denali_detach_chip,
> +};
> +
> +int denali_init(struct denali_nand_info *denali)
> +{
> + struct nand_chip *chip = &denali->nand;
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + u32 features = ioread32(denali->reg + FEATURES);
> + int ret;
> +
> + mtd->dev.parent = denali->dev;
> + denali_hw_init(denali);
> +
> + init_completion(&denali->complete);
> + spin_lock_init(&denali->irq_lock);
> +
> + denali_clear_irq_all(denali);
> +
> + ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
> + IRQF_SHARED, DENALI_NAND_NAME, denali);
> + if (ret) {
> + dev_err(denali->dev, "Unable to request IRQ\n");
> + return ret;
> + }
> +
> + denali_enable_irq(denali);
> + denali_reset_banks(denali);
> +
> + denali->active_bank = DENALI_INVALID_BANK;
> +
> + nand_set_flash_node(chip, denali->dev->of_node);
> + /* Fallback to the default name if DT did not give "label" property */
> + if (!mtd->name)
> + mtd->name = "denali-nand";
> +
> + chip->select_chip = denali_select_chip;
> + chip->read_byte = denali_read_byte;
> + chip->write_byte = denali_write_byte;
> + chip->read_word = denali_read_word;
> + chip->cmd_ctrl = denali_cmd_ctrl;
> + chip->dev_ready = denali_dev_ready;
> + chip->waitfunc = denali_waitfunc;
> +
> + if (features & FEATURES__INDEX_ADDR) {
> + denali->host_read = denali_indexed_read;
> + denali->host_write = denali_indexed_write;
> + } else {
> + denali->host_read = denali_direct_read;
> + denali->host_write = denali_direct_write;
> }
>
> - ret = nand_scan_tail(mtd);
> + /* clk rate info is needed for setup_data_interface */
> + if (denali->clk_rate && denali->clk_x_rate)
> + chip->setup_data_interface = denali_setup_data_interface;
> +
> + chip->dummy_controller.ops = &denali_controller_ops;
> + ret = nand_scan(mtd, denali->max_banks);
> if (ret)
> - goto free_buf;
> + goto disable_irq;
>
> ret = mtd_device_register(mtd, NULL, 0);
> if (ret) {
> dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
> goto cleanup_nand;
> }
> +
> return 0;
>
> cleanup_nand:
> nand_cleanup(chip);
> -free_buf:
> - kfree(denali->buf);
> disable_irq:
> denali_disable_irq(denali);
>


2018-07-21 06:51:35

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 05/35] mtd: rawnand: fsl_elbc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:57 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/fsl_elbc_nand.c | 19 ++++++++-----------
> 1 file changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
> index 0aa54a949653..44893e49b386 100644
> --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
> +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
> @@ -637,9 +637,9 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
> return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
> }
>
> -static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
> +static int fsl_elbc_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> + struct mtd_info *mtd = nand_to_mtd(chip);
> struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
> struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> @@ -706,6 +706,10 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)

Looks like fsl_elbc_chip_init_tail() was returning -1 here [1]. Please
change that for a -ENOTSUPP. With that fixed:

Reviewed-by: Boris Brezillon <[email protected]>

> return 0;
> }
>
> +static const struct nand_controller_ops fsl_elbc_controller_ops = {
> + .attach_chip = fsl_elbc_attach_chip,
> +};
> +
> static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
> uint8_t *buf, int oob_required, int page)
> {
> @@ -910,15 +914,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
> if (ret)
> goto err;
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret)
> - goto err;
> -
> - ret = fsl_elbc_chip_init_tail(mtd);
> - if (ret)
> - goto err;
> -
> - ret = nand_scan_tail(mtd);
> + priv->chip.controller->ops = &fsl_elbc_controller_ops;
> + ret = nand_scan(mtd, 1);
> if (ret)
> goto err;
>

[1]https://elixir.bootlin.com/linux/v4.18-rc5/source/drivers/mtd/nand/raw/fsl_elbc_nand.c#L699

2018-07-21 06:55:25

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 06/35] mtd: rawnand: fsl_ifc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:58 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/fsl_ifc_nand.c | 19 ++++++++-----------
> 1 file changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
> index 96130d91e32c..24f59d0066af 100644
> --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
> +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
> @@ -714,9 +714,9 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
> return nand_prog_page_end_op(chip);
> }
>
> -static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
> +static int fsl_ifc_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> + struct mtd_info *mtd = nand_to_mtd(chip);
> struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
>
> dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
> @@ -757,6 +757,10 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
> return 0;
> }
>
> +static const struct nand_controller_ops fsl_ifc_controller_ops = {
> + .attach_chip = fsl_ifc_attach_chip,
> +};
> +
> static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
> {
> struct fsl_ifc_ctrl *ctrl = priv->ctrl;
> @@ -1046,15 +1050,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
> if (ret)
> goto err;
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret)
> - goto err;
> -
> - ret = fsl_ifc_chip_init_tail(mtd);
> - if (ret)
> - goto err;
> -
> - ret = nand_scan_tail(mtd);
> + priv->chip.controller->ops = &fsl_ifc_controller_ops;
> + ret = nand_scan(mtd, 1);
> if (ret)
> goto err;
>


2018-07-21 06:56:56

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 07/35] mtd: rawnand: fsmc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:14:59 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/fsmc_nand.c | 148 +++++++++++++++++++++------------------
> 1 file changed, 78 insertions(+), 70 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
> index 59524d181bfe..f418236fa020 100644
> --- a/drivers/mtd/nand/raw/fsmc_nand.c
> +++ b/drivers/mtd/nand/raw/fsmc_nand.c
> @@ -919,6 +919,82 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
> return 0;
> }
>
> +static int fsmc_nand_attach_chip(struct nand_chip *nand)
> +{
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
> +
> + if (AMBA_REV_BITS(host->pid) >= 8) {
> + switch (mtd->oobsize) {
> + case 16:
> + case 64:
> + case 128:
> + case 224:
> + case 256:
> + break;
> + default:
> + dev_warn(host->dev,
> + "No oob scheme defined for oobsize %d\n",
> + mtd->oobsize);
> + return -EINVAL;
> + }
> +
> + mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
> +
> + return 0;
> + }
> +
> + switch (nand->ecc.mode) {
> + case NAND_ECC_HW:
> + dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
> + nand->ecc.calculate = fsmc_read_hwecc_ecc1;
> + nand->ecc.correct = nand_correct_data;
> + nand->ecc.bytes = 3;
> + nand->ecc.strength = 1;
> + break;
> +
> + case NAND_ECC_SOFT:
> + if (nand->ecc.algo == NAND_ECC_BCH) {
> + dev_info(host->dev,
> + "Using 4-bit SW BCH ECC scheme\n");
> + break;
> + }
> +
> + case NAND_ECC_ON_DIE:
> + break;
> +
> + default:
> + dev_err(host->dev, "Unsupported ECC mode!\n");
> + return -ENOTSUPP;
> + }
> +
> + /*
> + * Don't set layout for BCH4 SW ECC. This will be
> + * generated later in nand_bch_init() later.
> + */
> + if (nand->ecc.mode == NAND_ECC_HW) {
> + switch (mtd->oobsize) {
> + case 16:
> + case 64:
> + case 128:
> + mtd_set_ooblayout(mtd,
> + &fsmc_ecc1_ooblayout_ops);
> + break;
> + default:
> + dev_warn(host->dev,
> + "No oob scheme defined for oobsize %d\n",
> + mtd->oobsize);
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops fsmc_nand_controller_ops = {
> + .attach_chip = fsmc_nand_attach_chip,
> +};
> +
> /*
> * fsmc_nand_probe - Probe function
> * @pdev: platform device structure
> @@ -1048,76 +1124,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
> /*
> * Scan to find existence of the device
> */
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret) {
> - dev_err(&pdev->dev, "No NAND Device found!\n");
> - goto release_dma_write_chan;
> - }
> -
> - if (AMBA_REV_BITS(host->pid) >= 8) {
> - switch (mtd->oobsize) {
> - case 16:
> - case 64:
> - case 128:
> - case 224:
> - case 256:
> - break;
> - default:
> - dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
> - mtd->oobsize);
> - ret = -EINVAL;
> - goto release_dma_write_chan;
> - }
> -
> - mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
> - } else {
> - switch (nand->ecc.mode) {
> - case NAND_ECC_HW:
> - dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
> - nand->ecc.calculate = fsmc_read_hwecc_ecc1;
> - nand->ecc.correct = nand_correct_data;
> - nand->ecc.bytes = 3;
> - nand->ecc.strength = 1;
> - break;
> -
> - case NAND_ECC_SOFT:
> - if (nand->ecc.algo == NAND_ECC_BCH) {
> - dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
> - break;
> - }
> -
> - case NAND_ECC_ON_DIE:
> - break;
> -
> - default:
> - dev_err(&pdev->dev, "Unsupported ECC mode!\n");
> - goto release_dma_write_chan;
> - }
> -
> - /*
> - * Don't set layout for BCH4 SW ECC. This will be
> - * generated later in nand_bch_init() later.
> - */
> - if (nand->ecc.mode == NAND_ECC_HW) {
> - switch (mtd->oobsize) {
> - case 16:
> - case 64:
> - case 128:
> - mtd_set_ooblayout(mtd,
> - &fsmc_ecc1_ooblayout_ops);
> - break;
> - default:
> - dev_warn(&pdev->dev,
> - "No oob scheme defined for oobsize %d\n",
> - mtd->oobsize);
> - ret = -EINVAL;
> - goto release_dma_write_chan;
> - }
> - }
> - }
> -
> - /* Second stage of scan to fill MTD data-structures */
> - ret = nand_scan_tail(mtd);
> + nand->dummy_controller.ops = &fsmc_nand_controller_ops;
> + ret = nand_scan(mtd, 1);
> if (ret)
> goto release_dma_write_chan;
>


2018-07-21 06:57:29

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 08/35] mtd: rawnand: gpmi: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:00 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 56 ++++++++++++++++++------------
> 1 file changed, 33 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> index 6294d018df65..1c1ebbc82824 100644
> --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
> @@ -744,9 +744,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
> * [2] Allocate a read/write data buffer.
> * The gpmi_alloc_dma_buffer can be called twice.
> * We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
> - * is called before the nand_scan_ident; and we allocate a buffer
> - * of the real NAND page size when the gpmi_alloc_dma_buffer is
> - * called after the nand_scan_ident.
> + * is called before the NAND identification; and we allocate a
> + * buffer of the real NAND page size when the gpmi_alloc_dma_buffer
> + * is called after.
> */
> this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
> GFP_DMA | GFP_KERNEL);
> @@ -1865,6 +1865,34 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
> return 0;
> }
>
> +static int gpmi_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct gpmi_nand_data *this = nand_get_controller_data(chip);
> + int ret;
> +
> + if (chip->bbt_options & NAND_BBT_USE_FLASH) {
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + if (of_property_read_bool(this->dev->of_node,
> + "fsl,no-blockmark-swap"))
> + this->swap_block_mark = false;
> + }
> + dev_dbg(this->dev, "Blockmark swapping %sabled\n",
> + this->swap_block_mark ? "en" : "dis");
> +
> + ret = gpmi_init_last(this);
> + if (ret)
> + return ret;
> +
> + chip->options |= NAND_SKIP_BBTSCAN;
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops gpmi_nand_controller_ops = {
> + .attach_chip = gpmi_nand_attach_chip,
> +};
> +
> static int gpmi_nand_init(struct gpmi_nand_data *this)
> {
> struct nand_chip *chip = &this->nand;
> @@ -1905,26 +1933,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
> if (ret)
> goto err_out;
>
> - ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
> - if (ret)
> - goto err_out;
> -
> - if (chip->bbt_options & NAND_BBT_USE_FLASH) {
> - chip->bbt_options |= NAND_BBT_NO_OOB;
> -
> - if (of_property_read_bool(this->dev->of_node,
> - "fsl,no-blockmark-swap"))
> - this->swap_block_mark = false;
> - }
> - dev_dbg(this->dev, "Blockmark swapping %sabled\n",
> - this->swap_block_mark ? "en" : "dis");
> -
> - ret = gpmi_init_last(this);
> - if (ret)
> - goto err_out;
> -
> - chip->options |= NAND_SKIP_BBTSCAN;
> - ret = nand_scan_tail(mtd);
> + chip->dummy_controller.ops = &gpmi_nand_controller_ops;
> + ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
> if (ret)
> goto err_out;
>


2018-07-21 07:01:08

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 09/35] mtd: rawnand: hisi504: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:01 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/hisi504_nand.c | 78 +++++++++++++++++++++----------------
> 1 file changed, 44 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
> index a1e009c8e556..950dc7789296 100644
> --- a/drivers/mtd/nand/raw/hisi504_nand.c
> +++ b/drivers/mtd/nand/raw/hisi504_nand.c
> @@ -709,9 +709,50 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
> return 0;
> }
>
> +static int hisi_nfc_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct hinfc_host *host = nand_get_controller_data(chip);
> + int flag;
> +
> + host->buffer = dmam_alloc_coherent(host->dev,
> + mtd->writesize + mtd->oobsize,
> + &host->dma_buffer, GFP_KERNEL);
> + if (!host->buffer)
> + return -ENOMEM;
> +
> + host->dma_oob = host->dma_buffer + mtd->writesize;
> + memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
> +
> + flag = hinfc_read(host, HINFC504_CON);
> + flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
> + switch (mtd->writesize) {
> + case 2048:
> + flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
> + break;
> + /*
> + * TODO: add more pagesize support,
> + * default pagesize has been set in hisi_nfc_host_init
> + */
> + default:
> + dev_err(host->dev, "NON-2KB page size nand flash\n");
> + return -EINVAL;

We should probably return ENOTSUPP, but that's not related to the
change you do, so let's keep that for later.

> + }
> + hinfc_write(host, flag, HINFC504_CON);
> +
> + if (chip->ecc.mode == NAND_ECC_HW)
> + hisi_nfc_ecc_probe(host);
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops hisi_nfc_controller_ops = {
> + .attach_chip = hisi_nfc_attach_chip,
> +};
> +
> static int hisi_nfc_probe(struct platform_device *pdev)
> {
> - int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
> + int ret = 0, irq, max_chips = HINFC504_MAX_CHIP;
> struct device *dev = &pdev->dev;
> struct hinfc_host *host;
> struct nand_chip *chip;
> @@ -769,42 +810,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
> return ret;
> }
>
> - ret = nand_scan_ident(mtd, max_chips, NULL);
> + chip->dummy_controller.ops = &hisi_nfc_controller_ops;
> + ret = nand_scan(mtd, max_chips);
> if (ret)
> return ret;
>
> - host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
> - &host->dma_buffer, GFP_KERNEL);
> - if (!host->buffer)
> - return -ENOMEM;
> -
> - host->dma_oob = host->dma_buffer + mtd->writesize;
> - memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
> -
> - flag = hinfc_read(host, HINFC504_CON);
> - flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
> - switch (mtd->writesize) {
> - case 2048:
> - flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
> - /*
> - * TODO: add more pagesize support,
> - * default pagesize has been set in hisi_nfc_host_init
> - */
> - default:
> - dev_err(dev, "NON-2KB page size nand flash\n");
> - return -EINVAL;
> - }
> - hinfc_write(host, flag, HINFC504_CON);
> -
> - if (chip->ecc.mode == NAND_ECC_HW)
> - hisi_nfc_ecc_probe(host);
> -
> - ret = nand_scan_tail(mtd);
> - if (ret) {
> - dev_err(dev, "nand_scan_tail failed: %d\n", ret);
> - return ret;
> - }
> -
> ret = mtd_device_register(mtd, NULL, 0);
> if (ret) {
> dev_err(dev, "Err MTD partition=%d\n", ret);


2018-07-21 15:24:31

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 10/35] mtd: rawnand: jz4780: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:02 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> Acked-by: Harvey Hunt <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/jz4780_nand.c | 34 ++++++++++++++++------------------
> 1 file changed, 16 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
> index 49841dad347c..db4fa60bd52a 100644
> --- a/drivers/mtd/nand/raw/jz4780_nand.c
> +++ b/drivers/mtd/nand/raw/jz4780_nand.c
> @@ -158,9 +158,8 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
> return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
> }
>
> -static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
> +static int jz4780_nand_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &nand->chip;
> struct mtd_info *mtd = nand_to_mtd(chip);
> struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
> int eccbytes;
> @@ -171,7 +170,8 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
> switch (chip->ecc.mode) {
> case NAND_ECC_HW:
> if (!nfc->bch) {
> - dev_err(dev, "HW BCH selected, but BCH controller not found\n");
> + dev_err(nfc->dev,
> + "HW BCH selected, but BCH controller not found\n");
> return -ENODEV;
> }
>
> @@ -180,15 +180,16 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
> chip->ecc.correct = jz4780_nand_ecc_correct;
> /* fall through */
> case NAND_ECC_SOFT:
> - dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
> - (nfc->bch) ? "hardware BCH" : "software ECC",
> - chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
> + dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
> + (nfc->bch) ? "hardware BCH" : "software ECC",
> + chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
> break;
> case NAND_ECC_NONE:
> - dev_info(dev, "not using ECC\n");
> + dev_info(nfc->dev, "not using ECC\n");
> break;
> default:
> - dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
> + dev_err(nfc->dev, "ECC mode %d not supported\n",
> + chip->ecc.mode);
> return -EINVAL;
> }
>
> @@ -200,7 +201,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
> eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
>
> if (eccbytes > mtd->oobsize - 2) {
> - dev_err(dev,
> + dev_err(nfc->dev,
> "invalid ECC config: required %d ECC bytes, but only %d are available",
> eccbytes, mtd->oobsize - 2);
> return -EINVAL;
> @@ -211,6 +212,10 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
> return 0;
> }
>
> +static const struct nand_controller_ops jz4780_nand_controller_ops = {
> + .attach_chip = jz4780_nand_attach_chip,
> +};
> +
> static int jz4780_nand_init_chip(struct platform_device *pdev,
> struct jz4780_nand_controller *nfc,
> struct device_node *np,
> @@ -280,15 +285,8 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
> chip->controller = &nfc->controller;
> nand_set_flash_node(chip, np);
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (ret)
> - return ret;
> -
> - ret = jz4780_nand_init_ecc(nand, dev);
> - if (ret)
> - return ret;
> -
> - ret = nand_scan_tail(mtd);
> + chip->controller->ops = &jz4780_nand_controller_ops;
> + ret = nand_scan(mtd, 1);
> if (ret)
> return ret;
>


2018-07-21 15:27:46

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 11/35] mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:03 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/lpc32xx_mlc.c | 109 ++++++++++++++++++++-----------------
> 1 file changed, 59 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
> index 052d123a8304..6f73136fa863 100644
> --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
> +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
> @@ -184,6 +184,7 @@ static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
> };
>
> struct lpc32xx_nand_host {
> + struct platform_device *pdev;
> struct nand_chip nand_chip;
> struct lpc32xx_mlc_platform_data *pdata;
> struct clk *clk;
> @@ -653,6 +654,58 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
> return ncfg;
> }
>
> +static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
> + struct device *dev = &host->pdev->dev;
> +
> + host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
> + if (!host->dma_buf)
> + return -ENOMEM;
> +
> + host->dummy_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
> + if (!host->dummy_buf)
> + return -ENOMEM;
> +
> + chip->ecc.mode = NAND_ECC_HW;
> + chip->ecc.size = 512;
> + mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
> + host->mlcsubpages = mtd->writesize / 512;
> +
> + /* initially clear interrupt status */
> + readb(MLC_IRQ_SR(host->io_base));
> +
> + init_completion(&host->comp_nand);
> + init_completion(&host->comp_controller);
> +
> + host->irq = platform_get_irq(host->pdev, 0);
> + if (host->irq < 0) {
> + dev_err(dev, "failed to get platform irq\n");
> + return -EINVAL;
> + }
> +
> + if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
> + IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
> + dev_err(dev, "Error requesting NAND IRQ\n");
> + return -ENXIO;
> + }
> +
> + return 0;
> +}
> +
> +static void lpc32xx_nand_detach_chip(struct nand_chip *chip)
> +{
> + struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
> +
> + free_irq(host->irq, host);

Now you call 2 times free_irq() in the ->remove() path.

> +}
> +
> +static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
> + .attach_chip = lpc32xx_nand_attach_chip,
> + .detach_chip = lpc32xx_nand_detach_chip,
> +};
> +
> /*
> * Probe for NAND controller
> */
> @@ -669,6 +722,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
> if (!host)
> return -ENOMEM;
>
> + host->pdev = pdev;
> +
> rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> host->io_base = devm_ioremap_resource(&pdev->dev, rc);
> if (IS_ERR(host->io_base))
> @@ -749,58 +804,14 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
> }
>
> /*
> - * Scan to find existance of the device and
> - * Get the type of NAND device SMALL block or LARGE block
> + * Scan to find existence of the device and get the type of NAND device:
> + * SMALL block or LARGE block.
> */
> - res = nand_scan_ident(mtd, 1, NULL);
> + nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
> + res = nand_scan(mtd, 1);
> if (res)
> goto release_dma_chan;
>
> - host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
> - if (!host->dma_buf) {
> - res = -ENOMEM;
> - goto release_dma_chan;
> - }
> -
> - host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
> - if (!host->dummy_buf) {
> - res = -ENOMEM;
> - goto release_dma_chan;
> - }
> -
> - nand_chip->ecc.mode = NAND_ECC_HW;
> - nand_chip->ecc.size = 512;
> - mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
> - host->mlcsubpages = mtd->writesize / 512;
> -

Starting here...

> - /* initially clear interrupt status */
> - readb(MLC_IRQ_SR(host->io_base));
> -
> - init_completion(&host->comp_nand);
> - init_completion(&host->comp_controller);
> -
> - host->irq = platform_get_irq(pdev, 0);
> - if (host->irq < 0) {
> - dev_err(&pdev->dev, "failed to get platform irq\n");
> - res = -EINVAL;
> - goto release_dma_chan;
> - }
> -
> - if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
> - IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
> - dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
> - res = -ENXIO;
> - goto release_dma_chan;
> - }

till there: maybe we should just move this block before nand_scan().
Registering an IRQ handler is not really something you should do in
->attach_chip() IMO.

> -
> - /*
> - * Fills out all the uninitialized function pointers with the defaults
> - * And scans for a bad block table if appropriate.
> - */
> - res = nand_scan_tail(mtd);
> - if (res)
> - goto free_irq;
> -
> mtd->name = DRV_NAME;
>
> res = mtd_device_register(mtd, host->ncfg->parts,
> @@ -812,8 +823,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
>
> cleanup_nand:
> nand_cleanup(nand_chip);
> -free_irq:
> - free_irq(host->irq, host);
> release_dma_chan:
> if (use_dma)
> dma_release_channel(host->dma_chan);


2018-07-21 15:29:37

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 12/35] mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:04 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/lpc32xx_slc.c | 77 +++++++++++++++++++++-----------------
> 1 file changed, 42 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
> index 42820aa1abab..a4e8b7e75135 100644
> --- a/drivers/mtd/nand/raw/lpc32xx_slc.c
> +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
> @@ -779,6 +779,46 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
> return ncfg;
> }
>
> +static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
> +
> + /* OOB and ECC CPU and DMA work areas */
> + host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
> +
> + /*
> + * Small page FLASH has a unique OOB layout, but large and huge
> + * page FLASH use the standard layout. Small page FLASH uses a
> + * custom BBT marker layout.
> + */
> + if (mtd->writesize <= 512)
> + mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
> +
> + /* These sizes remain the same regardless of page size */
> + chip->ecc.size = 256;
> + chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
> + chip->ecc.prepad = 0;
> + chip->ecc.postpad = 0;
> +
> + /*
> + * Use a custom BBT marker setup for small page FLASH that
> + * won't interfere with the ECC layout. Large and huge page
> + * FLASH use the standard layout.
> + */
> + if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
> + mtd->writesize <= 512) {
> + chip->bbt_td = &bbt_smallpage_main_descr;
> + chip->bbt_md = &bbt_smallpage_mirror_descr;
> + }
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
> + .attach_chip = lpc32xx_nand_attach_chip,
> +};
> +
> /*
> * Probe for NAND controller
> */
> @@ -884,41 +924,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
> }
>
> /* Find NAND device */
> - res = nand_scan_ident(mtd, 1, NULL);
> - if (res)
> - goto release_dma;
> -
> - /* OOB and ECC CPU and DMA work areas */
> - host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
> -
> - /*
> - * Small page FLASH has a unique OOB layout, but large and huge
> - * page FLASH use the standard layout. Small page FLASH uses a
> - * custom BBT marker layout.
> - */
> - if (mtd->writesize <= 512)
> - mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
> -
> - /* These sizes remain the same regardless of page size */
> - chip->ecc.size = 256;
> - chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
> - chip->ecc.prepad = chip->ecc.postpad = 0;
> -
> - /*
> - * Use a custom BBT marker setup for small page FLASH that
> - * won't interfere with the ECC layout. Large and huge page
> - * FLASH use the standard layout.
> - */
> - if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
> - mtd->writesize <= 512) {
> - chip->bbt_td = &bbt_smallpage_main_descr;
> - chip->bbt_md = &bbt_smallpage_mirror_descr;
> - }
> -
> - /*
> - * Fills out all the uninitialized function pointers with the defaults
> - */
> - res = nand_scan_tail(mtd);
> + chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
> + res = nand_scan(mtd, 1);
> if (res)
> goto release_dma;
>


2018-07-21 16:59:45

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 13/35] mtd: rawnand: marvell: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:05 +0200
Miquel Raynal <[email protected]> wrote:

>
> - ret = nand_scan_tail(mtd);
> + chip->controller->ops = &marvell_nand_controller_ops;

Assigning ->ops to &marvell_nand_controller_ops should be done only
once in the probe function (here [1]). With that fixed, you can add

Reviewed-by: Boris Brezillon <[email protected]>

> + ret = nand_scan(mtd, marvell_nand->nsels);
> if (ret) {
> - dev_err(dev, "nand_scan_tail failed: %d\n", ret);
> + dev_err(dev, "could not scan the nand chip\n");
> return ret;
> }
>


2018-07-21 17:11:44

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:06 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> 1 file changed, 44 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> index 7bc6be3f6ec0..967418f945ea 100644
> --- a/drivers/mtd/nand/raw/mtk_nand.c
> +++ b/drivers/mtd/nand/raw/mtk_nand.c
> @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> return 0;
> }
>
> +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct device *dev = mtd->dev.parent;
> + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> + int len;
> + int ret;
> +
> + if (chip->options & NAND_BUSWIDTH_16) {
> + dev_err(dev, "16bits buswidth not supported");
> + return -EINVAL;
> + }
> +
> + /* store bbt magic in page, cause OOB is not protected */
> + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + ret = mtk_nfc_ecc_init(dev, mtd);
> + if (ret)
> + return ret;
> +
> + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> + if (ret)
> + return ret;
> +
> + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> +
> + len = mtd->writesize + mtd->oobsize;
> + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> + if (!nfc->buffer)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> + .attach_chip = mtk_nfc_attach_chip,
> +};
> +
> static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> struct device_node *np)
> {
> struct mtk_nfc_nand_chip *chip;
> struct nand_chip *nand;
> struct mtd_info *mtd;
> - int nsels, len;
> + int nsels;
> u32 tmp;
> int ret;
> int i;
> @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
>
> nand = &chip->nand;
> nand->controller = &nfc->controller;
> + nand->controller->ops = &mtk_nfc_controller_ops;

Just like for the marvell driver, this assignment should be moved here
[1]. Also, it looks like this driver is open-coding
nand_controller_init(), probably something we should fix (in a separate
patch).

With this fixed:

Reviewed-by: Boris Brezillon <[email protected]>

>
> nand_set_flash_node(nand, np);
> nand_set_controller_data(nand, nfc);
> @@ -1324,36 +1366,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
>
> mtk_nfc_hw_init(nfc);
>
> - ret = nand_scan_ident(mtd, nsels, NULL);
> - if (ret)
> - return ret;
> -
> - /* store bbt magic in page, cause OOB is not protected */
> - if (nand->bbt_options & NAND_BBT_USE_FLASH)
> - nand->bbt_options |= NAND_BBT_NO_OOB;
> -
> - ret = mtk_nfc_ecc_init(dev, mtd);
> - if (ret)
> - return -EINVAL;
> -
> - if (nand->options & NAND_BUSWIDTH_16) {
> - dev_err(dev, "16bits buswidth not supported");
> - return -EINVAL;
> - }
> -
> - ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
> - if (ret)
> - return ret;
> -
> - mtk_nfc_set_fdm(&chip->fdm, mtd);
> - mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
> -
> - len = mtd->writesize + mtd->oobsize;
> - nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> - if (!nfc->buffer)
> - return -ENOMEM;
> -
> - ret = nand_scan_tail(mtd);
> + ret = nand_scan(mtd, nsels);
> if (ret)
> return ret;
>


2018-07-21 17:20:24

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 15/35] mtd: rawnand: mxc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:07 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/mxc_nand.c | 136 +++++++++++++++++++++-------------------
> 1 file changed, 71 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
> index c6eff61e909d..4c9214dea424 100644
> --- a/drivers/mtd/nand/raw/mxc_nand.c
> +++ b/drivers/mtd/nand/raw/mxc_nand.c
> @@ -1691,6 +1691,74 @@ static int mxcnd_probe_dt(struct mxc_nand_host *host)
> }
> #endif
>
> +static int mxcnd_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct mxc_nand_host *host = nand_get_controller_data(chip);
> + struct device *dev = mtd->dev.parent;
> +
> + switch (chip->ecc.mode) {
> + case NAND_ECC_HW:
> + chip->ecc.read_page = mxc_nand_read_page;
> + chip->ecc.read_page_raw = mxc_nand_read_page_raw;
> + chip->ecc.read_oob = mxc_nand_read_oob;
> + chip->ecc.write_page = mxc_nand_write_page_ecc;
> + chip->ecc.write_page_raw = mxc_nand_write_page_raw;
> + chip->ecc.write_oob = mxc_nand_write_oob;
> + break;
> +
> + case NAND_ECC_SOFT:
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + if (chip->bbt_options & NAND_BBT_USE_FLASH) {
> + chip->bbt_td = &bbt_main_descr;
> + chip->bbt_md = &bbt_mirror_descr;
> + }
> +
> + /* Allocate the right size buffer now */
> + devm_kfree(dev, (void *)host->data_buf);
> + host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
> + GFP_KERNEL);
> + if (!host->data_buf)
> + return -ENOMEM;
> +
> + /* Call preset again, with correct writesize chip time */
> + host->devtype_data->preset(mtd);
> +
> + if (!chip->ecc.bytes) {
> + if (host->eccsize == 8)
> + chip->ecc.bytes = 18;
> + else if (host->eccsize == 4)
> + chip->ecc.bytes = 9;
> + }
> +
> + /*
> + * Experimentation shows that i.MX NFC can only handle up to 218 oob
> + * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
> + * into copying invalid data to/from the spare IO buffer, as this
> + * might cause ECC data corruption when doing sub-page write to a
> + * partially written page.
> + */
> + host->used_oobsize = min(mtd->oobsize, 218U);
> +
> + if (chip->ecc.mode == NAND_ECC_HW) {
> + if (is_imx21_nfc(host) || is_imx27_nfc(host))
> + chip->ecc.strength = 1;
> + else
> + chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
> + }
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops mxcnd_controller_ops = {
> + .attach_chip = mxcnd_attach_chip,
> +};
> +
> static int mxcnd_probe(struct platform_device *pdev)
> {
> struct nand_chip *this;
> @@ -1830,71 +1898,9 @@ static int mxcnd_probe(struct platform_device *pdev)
> host->devtype_data->irq_control(host, 1);
> }
>
> - /* first scan to find the device and get the page size */
> - err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
> - if (err)
> - goto escan;
> -
> - switch (this->ecc.mode) {
> - case NAND_ECC_HW:
> - this->ecc.read_page = mxc_nand_read_page;
> - this->ecc.read_page_raw = mxc_nand_read_page_raw;
> - this->ecc.read_oob = mxc_nand_read_oob;
> - this->ecc.write_page = mxc_nand_write_page_ecc;
> - this->ecc.write_page_raw = mxc_nand_write_page_raw;
> - this->ecc.write_oob = mxc_nand_write_oob;
> - break;
> -
> - case NAND_ECC_SOFT:
> - break;
> -
> - default:
> - err = -EINVAL;
> - goto escan;
> - }
> -
> - if (this->bbt_options & NAND_BBT_USE_FLASH) {
> - this->bbt_td = &bbt_main_descr;
> - this->bbt_md = &bbt_mirror_descr;
> - }
> -
> - /* allocate the right size buffer now */
> - devm_kfree(&pdev->dev, (void *)host->data_buf);
> - host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
> - GFP_KERNEL);
> - if (!host->data_buf) {
> - err = -ENOMEM;
> - goto escan;
> - }
> -
> - /* Call preset again, with correct writesize this time */
> - host->devtype_data->preset(mtd);
> -
> - if (!this->ecc.bytes) {
> - if (host->eccsize == 8)
> - this->ecc.bytes = 18;
> - else if (host->eccsize == 4)
> - this->ecc.bytes = 9;
> - }
> -
> - /*
> - * Experimentation shows that i.MX NFC can only handle up to 218 oob
> - * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
> - * into copying invalid data to/from the spare IO buffer, as this
> - * might cause ECC data corruption when doing sub-page write to a
> - * partially written page.
> - */
> - host->used_oobsize = min(mtd->oobsize, 218U);
> -
> - if (this->ecc.mode == NAND_ECC_HW) {
> - if (is_imx21_nfc(host) || is_imx27_nfc(host))
> - this->ecc.strength = 1;
> - else
> - this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
> - }
> -
> - /* second phase scan */
> - err = nand_scan_tail(mtd);
> + /* Scan the NAND device */
> + this->dummy_controller.ops = &mxcnd_controller_ops;
> + err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
> if (err)
> goto escan;
>


2018-07-21 17:23:04

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 16/35] mtd: rawnand: nandsim: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:08 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/nandsim.c | 82 +++++++++++++++++++++++-------------------
> 1 file changed, 45 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
> index 8a3b36cfe5ea..71ac034aee9c 100644
> --- a/drivers/mtd/nand/raw/nandsim.c
> +++ b/drivers/mtd/nand/raw/nandsim.c
> @@ -2192,6 +2192,48 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
> return;
> }
>
> +static int ns_attach_chip(struct nand_chip *chip)
> +{
> + unsigned int eccsteps, eccbytes;
> +
> + if (!bch)
> + return 0;
> +
> + if (!mtd_nand_has_bch()) {
> + NS_ERR("BCH ECC support is disabled\n");
> + return -EINVAL;
> + }
> +
> + /* Use 512-byte ecc blocks */
> + eccsteps = nsmtd->writesize / 512;
> + eccbytes = ((bch * 13) + 7) / 8;
> +
> + /* Do not bother supporting small page devices */
> + if (nsmtd->oobsize < 64 || !eccsteps) {
> + NS_ERR("BCH not available on small page devices\n");
> + return -EINVAL;
> + }
> +
> + if (((eccbytes * eccsteps) + 2) > nsmtd->oobsize) {
> + NS_ERR("Invalid BCH value %u\n", bch);
> + return -EINVAL;
> + }
> +
> + chip->ecc.mode = NAND_ECC_SOFT;
> + chip->ecc.algo = NAND_ECC_BCH;
> + chip->ecc.size = 512;
> + chip->ecc.strength = bch;
> + chip->ecc.bytes = eccbytes;
> +
> + NS_INFO("Using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops ns_controller_ops = {
> + .attach_chip = ns_attach_chip,
> +};
> +
> /*
> * Module initialization function
> */
> @@ -2276,44 +2318,10 @@ static int __init ns_init_module(void)
> if ((retval = parse_gravepages()) != 0)
> goto error;
>
> - retval = nand_scan_ident(nsmtd, 1, NULL);
> + chip->dummy_controller.ops = &ns_controller_ops;
> + retval = nand_scan(nsmtd, 1);
> if (retval) {
> - NS_ERR("cannot scan NAND Simulator device\n");
> - goto error;
> - }
> -
> - if (bch) {
> - unsigned int eccsteps, eccbytes;
> - if (!mtd_nand_has_bch()) {
> - NS_ERR("BCH ECC support is disabled\n");
> - retval = -EINVAL;
> - goto error;
> - }
> - /* use 512-byte ecc blocks */
> - eccsteps = nsmtd->writesize/512;
> - eccbytes = (bch*13+7)/8;
> - /* do not bother supporting small page devices */
> - if ((nsmtd->oobsize < 64) || !eccsteps) {
> - NS_ERR("bch not available on small page devices\n");
> - retval = -EINVAL;
> - goto error;
> - }
> - if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
> - NS_ERR("invalid bch value %u\n", bch);
> - retval = -EINVAL;
> - goto error;
> - }
> - chip->ecc.mode = NAND_ECC_SOFT;
> - chip->ecc.algo = NAND_ECC_BCH;
> - chip->ecc.size = 512;
> - chip->ecc.strength = bch;
> - chip->ecc.bytes = eccbytes;
> - NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
> - }
> -
> - retval = nand_scan_tail(nsmtd);
> - if (retval) {
> - NS_ERR("can't register NAND Simulator\n");
> + NS_ERR("Could not scan NAND Simulator device\n");
> goto error;
> }
>


2018-07-21 17:36:06

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 17/35] mtd: rawnand: omap2: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:09 +0200
Miquel Raynal <[email protected]> wrote:

> static int omap_nand_probe(struct platform_device *pdev)
> {
> struct omap_nand_info *info;
> struct mtd_info *mtd;
> struct nand_chip *nand_chip;
> int err;
> - dma_cap_mask_t mask;
> struct resource *res;
> struct device *dev = &pdev->dev;
> - int min_oobbytes = BADBLOCK_MARKER_LENGTH;
> - int oobbytes_per_step;
>
> info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
> GFP_KERNEL);
> @@ -1967,6 +2221,7 @@ static int omap_nand_probe(struct platform_device *pdev)
> info->phys_base = res->start;
>
> nand_chip->controller = &omap_gpmc_controller;
> + nand_chip->controller->ops = &omap_nand_controller_ops;

Move this assignment here [1].

>
> nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
> nand_chip->cmd_ctrl = omap_hwcontrol;

[1]https://elixir.bootlin.com/linux/v4.18-rc5/source/drivers/mtd/nand/raw/omap2.c#L148

2018-07-21 17:40:21

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 18/35] mtd: rawnand: s3c2410: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:10 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/s3c2410.c | 30 +++++++++++++-----------------
> 1 file changed, 13 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
> index e8bf64832213..c21e8892394a 100644
> --- a/drivers/mtd/nand/raw/s3c2410.c
> +++ b/drivers/mtd/nand/raw/s3c2410.c
> @@ -915,20 +915,19 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
> }
>
> /**
> - * s3c2410_nand_update_chip - post probe update
> - * @info: The controller instance.
> - * @nmtd: The driver version of the MTD instance.
> + * s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
> + * @chip: The NAND chip
> *
> - * This routine is called after the chip probe has successfully completed
> - * and the relevant per-chip information updated. This call ensure that
> + * This hook is called by the core after the identification of the NAND chip,
> + * once the relevant per-chip information is up to date.. This call ensure that
> * we update the internal state accordingly.
> *
> * The internal state is currently limited to the ECC state information.
> */
> -static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
> - struct s3c2410_nand_mtd *nmtd)
> +static int s3c2410_nand_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &nmtd->chip;
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
>
> switch (chip->ecc.mode) {
>
> @@ -998,6 +997,10 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
> return 0;
> }
>
> +static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
> + .attach_chip = s3c2410_nand_attach_chip,
> +};
> +
> static const struct of_device_id s3c24xx_nand_dt_ids[] = {
> {
> .compatible = "samsung,s3c2410-nand",
> @@ -1095,6 +1098,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
> platform_set_drvdata(pdev, info);
>
> nand_controller_init(&info->controller);
> + info->controller.ops = &s3c24xx_nand_controller_ops;
>
> /* get the clock source and enable it */
>
> @@ -1166,15 +1170,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
> mtd->dev.parent = &pdev->dev;
> s3c2410_nand_init_chip(info, nmtd, sets);
>
> - err = nand_scan_ident(mtd, (sets) ? sets->nr_chips : 1, NULL);
> - if (err)
> - goto exit_error;
> -
> - err = s3c2410_nand_update_chip(info, nmtd);
> - if (err < 0)
> - goto exit_error;
> -
> - err = nand_scan_tail(mtd);
> + err = nand_scan(mtd, sets ? sets->nr_chips : 1);
> if (err)
> goto exit_error;
>


2018-07-21 17:49:48

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 19/35] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function

On Fri, 20 Jul 2018 17:15:11 +0200
Miquel Raynal <[email protected]> wrote:

> @@ -1007,6 +1007,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
> struct sh_flctl *flctl = mtd_to_flctl(mtd);
> struct nand_chip *chip = &flctl->chip;
>
> + if (chip->options & NAND_BUSWIDTH_16) {
> + /*
> + * NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
> + * Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
> + * flctl->flcmncr_base to pdata->flcmncr_val.
> + */
> + flctl->pdata->flcmncr_val |= SEL_16BIT;
> + flctl->flcmncr_base = flctl->pdata->flcmncr_val;

pdata->flcmncr_val is not used after this point. I think you can just do

flctl->flcmncr_base |= SEL_16BIT;

and get rid of the ftcl->pdata field you add in this patch.

> + }
> +



2018-07-21 17:51:19

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 20/35] mtd: rawnand: sh_flctl: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:12 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/sh_flctl.c | 19 ++++++++-----------
> 1 file changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
> index d37d1d3ccbf9..663c75005ac9 100644
> --- a/drivers/mtd/nand/raw/sh_flctl.c
> +++ b/drivers/mtd/nand/raw/sh_flctl.c
> @@ -1002,10 +1002,10 @@ static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> flctl->index += len;
> }
>
> -static int flctl_chip_init_tail(struct mtd_info *mtd)
> +static int flctl_chip_attach_chip(struct nand_chip *chip)
> {
> + struct mtd_info *mtd = nand_to_mtd(chip);
> struct sh_flctl *flctl = mtd_to_flctl(mtd);
> - struct nand_chip *chip = &flctl->chip;
>
> if (chip->options & NAND_BUSWIDTH_16) {
> /*
> @@ -1073,6 +1073,10 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
> return 0;
> }
>
> +static const struct nand_controller_ops flctl_nand_controller_ops = {
> + .attach_chip = flctl_chip_attach_chip,
> +};
> +
> static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
> {
> struct sh_flctl *flctl = dev_id;
> @@ -1200,15 +1204,8 @@ static int flctl_probe(struct platform_device *pdev)
>
> flctl_setup_dma(flctl);
>
> - ret = nand_scan_ident(flctl_mtd, 1, NULL);
> - if (ret)
> - goto err_chip;
> -
> - ret = flctl_chip_init_tail(flctl_mtd);
> - if (ret)
> - goto err_chip;
> -
> - ret = nand_scan_tail(flctl_mtd);
> + nand->dummy_controller.ops = &flctl_nand_controller_ops;
> + ret = nand_scan(flctl_mtd, 1);
> if (ret)
> goto err_chip;
>


2018-07-21 17:51:58

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 21/35] mtd: rawnand: sunxi: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:13 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/sunxi_nand.c | 43 +++++++++++++++++----------------------
> 1 file changed, 19 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
> index 07f3ff9a28f2..a4d23381003d 100644
> --- a/drivers/mtd/nand/raw/sunxi_nand.c
> +++ b/drivers/mtd/nand/raw/sunxi_nand.c
> @@ -1816,12 +1816,21 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
> }
> }
>
> -static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
> - struct device_node *np)
> +static int sunxi_nand_attach_chip(struct nand_chip *nand)
> {
> - struct nand_chip *nand = mtd_to_nand(mtd);
> + struct mtd_info *mtd = nand_to_mtd(nand);
> + struct nand_ecc_ctrl *ecc = &nand->ecc;
> + struct device_node *np = nand_get_flash_node(nand);
> int ret;
>
> + if (nand->bbt_options & NAND_BBT_USE_FLASH)
> + nand->bbt_options |= NAND_BBT_NO_OOB;
> +
> + if (nand->options & NAND_NEED_SCRAMBLING)
> + nand->options |= NAND_NO_SUBPAGE_WRITE;
> +
> + nand->options |= NAND_SUBPAGE_READ;
> +
> if (!ecc->size) {
> ecc->size = nand->ecc_step_ds;
> ecc->strength = nand->ecc_strength_ds;
> @@ -1846,6 +1855,10 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
> return 0;
> }
>
> +static const struct nand_controller_ops sunxi_nand_controller_ops = {
> + .attach_chip = sunxi_nand_attach_chip,
> +};
> +
> static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
> struct device_node *np)
> {
> @@ -1911,6 +1924,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
> /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
> nand->chip_delay = 200;
> nand->controller = &nfc->controller;
> + nand->controller->ops = &sunxi_nand_controller_ops;
> +
> /*
> * Set the ECC mode to the default value in case nothing is specified
> * in the DT.
> @@ -1927,30 +1942,10 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
> mtd = nand_to_mtd(nand);
> mtd->dev.parent = dev;
>
> - ret = nand_scan_ident(mtd, nsels, NULL);
> + ret = nand_scan(mtd, nsels);
> if (ret)
> return ret;
>
> - if (nand->bbt_options & NAND_BBT_USE_FLASH)
> - nand->bbt_options |= NAND_BBT_NO_OOB;
> -
> - if (nand->options & NAND_NEED_SCRAMBLING)
> - nand->options |= NAND_NO_SUBPAGE_WRITE;
> -
> - nand->options |= NAND_SUBPAGE_READ;
> -
> - ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
> - if (ret) {
> - dev_err(dev, "ECC init failed: %d\n", ret);
> - return ret;
> - }
> -
> - ret = nand_scan_tail(mtd);
> - if (ret) {
> - dev_err(dev, "nand_scan_tail failed: %d\n", ret);
> - return ret;
> - }
> -
> ret = mtd_device_register(mtd, NULL, 0);
> if (ret) {
> dev_err(dev, "failed to register mtd device: %d\n", ret);


2018-07-21 17:54:18

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 22/35] mtd: rawnand: tango: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:14 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/tango_nand.c | 40 +++++++++++++++++++++++----------------
> 1 file changed, 24 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
> index dd7a26efdf4f..a448d0797cd5 100644
> --- a/drivers/mtd/nand/raw/tango_nand.c
> +++ b/drivers/mtd/nand/raw/tango_nand.c
> @@ -517,6 +517,28 @@ static int tango_set_timings(struct mtd_info *mtd, int csline,
> return 0;
> }
>
> +static int tango_attach_chip(struct nand_chip *chip)
> +{
> + struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> + ecc->mode = NAND_ECC_HW;
> + ecc->algo = NAND_ECC_BCH;
> + ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
> +
> + ecc->read_page_raw = tango_read_page_raw;
> + ecc->write_page_raw = tango_write_page_raw;
> + ecc->read_page = tango_read_page;
> + ecc->write_page = tango_write_page;
> + ecc->read_oob = tango_read_oob;
> + ecc->write_oob = tango_write_oob;
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops tango_controller_ops = {
> + .attach_chip = tango_attach_chip,
> +};
> +
> static int chip_init(struct device *dev, struct device_node *np)
> {
> u32 cs;
> @@ -560,28 +582,14 @@ static int chip_init(struct device *dev, struct device_node *np)
> NAND_NO_SUBPAGE_WRITE |
> NAND_WAIT_TCCS;
> chip->controller = &nfc->hw;
> + chip->controller->ops = &tango_controller_ops;

Move this assignment here [1]. With that fixed:

Reviewed-by: Boris Brezillon <[email protected]>

> tchip->base = nfc->pbus_base + (cs * 256);
>
> nand_set_flash_node(chip, np);
> mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
> mtd->dev.parent = dev;
>
> - err = nand_scan_ident(mtd, 1, NULL);
> - if (err)
> - return err;
> -
> - ecc->mode = NAND_ECC_HW;
> - ecc->algo = NAND_ECC_BCH;
> - ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
> -
> - ecc->read_page_raw = tango_read_page_raw;
> - ecc->write_page_raw = tango_write_page_raw;
> - ecc->read_page = tango_read_page;
> - ecc->write_page = tango_write_page;
> - ecc->read_oob = tango_read_oob;
> - ecc->write_oob = tango_write_oob;
> -
> - err = nand_scan_tail(mtd);
> + err = nand_scan(mtd, 1);
> if (err)
> return err;
>

[1]https://elixir.bootlin.com/linux/v4.18-rc5/source/drivers/mtd/nand/raw/tango_nand.c#L657

2018-07-21 17:55:13

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 23/35] mtd: rawnand: txx9ndfmc: rename nand controller internal structure

On Fri, 20 Jul 2018 17:15:15 +0200
Miquel Raynal <[email protected]> wrote:

> As already done in the core, calling a struct nand_controller
> 'hw_control' is misleading. Use the same name as in nand_base.c:
> 'controller'.
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/txx9ndfmc.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
> index 8f5bbbac4612..9019022774f7 100644
> --- a/drivers/mtd/nand/raw/txx9ndfmc.c
> +++ b/drivers/mtd/nand/raw/txx9ndfmc.c
> @@ -73,7 +73,7 @@ struct txx9ndfmc_drvdata {
> void __iomem *base;
> unsigned char hold; /* in gbusclock */
> unsigned char spw; /* in gbusclock */
> - struct nand_controller hw_control;
> + struct nand_controller controller;
> };
>
> static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
> @@ -303,7 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
> (gbusclk + 500000) / 1000000, hold, spw);
>
> - nand_controller_init(&drvdata->hw_control);
> + nand_controller_init(&drvdata->controller);
>
> platform_set_drvdata(dev, drvdata);
> txx9ndfmc_initialize(dev);
> @@ -337,7 +337,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> chip->ecc.bytes = 3;
> chip->ecc.strength = 1;
> chip->chip_delay = 100;
> - chip->controller = &drvdata->hw_control;
> + chip->controller = &drvdata->controller;
>
> nand_set_controller_data(chip, txx9_priv);
> txx9_priv->dev = dev;


2018-07-21 17:57:14

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 24/35] mtd: rawnand: txx9ndfmc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:16 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/txx9ndfmc.c | 29 +++++++++++++++--------------
> 1 file changed, 15 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
> index 9019022774f7..0134beb1136d 100644
> --- a/drivers/mtd/nand/raw/txx9ndfmc.c
> +++ b/drivers/mtd/nand/raw/txx9ndfmc.c
> @@ -254,23 +254,23 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
> #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
> DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
>
> -static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
> +static int txx9ndfmc_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - int ret;
> + struct mtd_info *mtd = nand_to_mtd(chip);
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (!ret) {
> - if (mtd->writesize >= 512) {
> - /* Hardware ECC 6 byte ECC per 512 Byte data */
> - chip->ecc.size = 512;
> - chip->ecc.bytes = 6;
> - }
> - ret = nand_scan_tail(mtd);
> + if (mtd->writesize >= 512) {
> + /* Hardware ECC 6 byte ECC per 512 Byte data */
> + chip->ecc.size = 512;
> + chip->ecc.bytes = 6;
> }
> - return ret;
> +
> + return 0;
> }
>
> +static const struct nand_controller_ops txx9ndfmc_controller_ops = {
> + .attach_chip = txx9ndfmc_attach_chip,
> +};
> +
> static int __init txx9ndfmc_probe(struct platform_device *dev)
> {
> struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
> @@ -304,6 +304,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> (gbusclk + 500000) / 1000000, hold, spw);
>
> nand_controller_init(&drvdata->controller);
> + drvdata->controller.ops = &txx9ndfmc_controller_ops;
>
> platform_set_drvdata(dev, drvdata);
> txx9ndfmc_initialize(dev);
> @@ -332,7 +333,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> chip->ecc.correct = txx9ndfmc_correct_data;
> chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
> chip->ecc.mode = NAND_ECC_HW;
> - /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
> + /* nand_scan() will overwrite ecc.size and ecc.bytes */
> chip->ecc.size = 256;
> chip->ecc.bytes = 3;
> chip->ecc.strength = 1;
> @@ -359,7 +360,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> if (plat->wide_mask & (1 << i))
> chip->options |= NAND_BUSWIDTH_16;
>
> - if (txx9ndfmc_nand_scan(mtd)) {
> + if (nand_scan(mtd, 1)) {
> kfree(txx9_priv->mtdname);
> kfree(txx9_priv);
> continue;


2018-07-21 18:05:22

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 24/35] mtd: rawnand: txx9ndfmc: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:16 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/txx9ndfmc.c | 29 +++++++++++++++--------------
> 1 file changed, 15 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
> index 9019022774f7..0134beb1136d 100644
> --- a/drivers/mtd/nand/raw/txx9ndfmc.c
> +++ b/drivers/mtd/nand/raw/txx9ndfmc.c
> @@ -254,23 +254,23 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
> #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
> DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
>
> -static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
> +static int txx9ndfmc_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - int ret;
> + struct mtd_info *mtd = nand_to_mtd(chip);
>
> - ret = nand_scan_ident(mtd, 1, NULL);
> - if (!ret) {
> - if (mtd->writesize >= 512) {
> - /* Hardware ECC 6 byte ECC per 512 Byte data */
> - chip->ecc.size = 512;
> - chip->ecc.bytes = 6;
> - }
> - ret = nand_scan_tail(mtd);
> + if (mtd->writesize >= 512) {
> + /* Hardware ECC 6 byte ECC per 512 Byte data */
> + chip->ecc.size = 512;
> + chip->ecc.bytes = 6;
> }
> - return ret;
> +
> + return 0;
> }
>
> +static const struct nand_controller_ops txx9ndfmc_controller_ops = {
> + .attach_chip = txx9ndfmc_attach_chip,
> +};
> +
> static int __init txx9ndfmc_probe(struct platform_device *dev)
> {
> struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
> @@ -304,6 +304,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> (gbusclk + 500000) / 1000000, hold, spw);
>
> nand_controller_init(&drvdata->controller);
> + drvdata->controller.ops = &txx9ndfmc_controller_ops;
>
> platform_set_drvdata(dev, drvdata);
> txx9ndfmc_initialize(dev);
> @@ -332,7 +333,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> chip->ecc.correct = txx9ndfmc_correct_data;
> chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
> chip->ecc.mode = NAND_ECC_HW;
> - /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
> + /* nand_scan() will overwrite ecc.size and ecc.bytes */
> chip->ecc.size = 256;
> chip->ecc.bytes = 3;

I had a hard time understanding what was the point of assigning
values that would later be overwritten. Actually the comment is
inaccurate, it's only overwritten if mtd->writesize >= 512. Can you had
a patch that moves this block in txx9ndfmc_nand_scan() before doing the
->attach_chip() conversion?

> chip->ecc.strength = 1;
> @@ -359,7 +360,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
> if (plat->wide_mask & (1 << i))
> chip->options |= NAND_BUSWIDTH_16;
>
> - if (txx9ndfmc_nand_scan(mtd)) {
> + if (nand_scan(mtd, 1)) {
> kfree(txx9_priv->mtdname);
> kfree(txx9_priv);
> continue;


2018-07-21 18:08:02

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 25/35] mtd: rawnand: vf610: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:17 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/vf610_nfc.c | 127 ++++++++++++++++++++-------------------
> 1 file changed, 66 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
> index d5a22fc96878..6f6dcbf9095b 100644
> --- a/drivers/mtd/nand/raw/vf610_nfc.c
> +++ b/drivers/mtd/nand/raw/vf610_nfc.c
> @@ -747,6 +747,69 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
> }
> }
>
> +static int vf610_nfc_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct vf610_nfc *nfc = mtd_to_nfc(mtd);
> +
> + vf610_nfc_init_controller(nfc);
> +
> + /* Bad block options. */
> + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + /* Single buffer only, max 256 OOB minus ECC status */
> + if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
> + dev_err(nfc->dev, "Unsupported flash page size\n");
> + return -ENXIO;
> + }
> +
> + if (chip->ecc.mode != NAND_ECC_HW)
> + return 0;
> +
> + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
> + dev_err(nfc->dev, "Unsupported flash with hwecc\n");
> + return -ENXIO;
> + }
> +
> + if (chip->ecc.size != mtd->writesize) {
> + dev_err(nfc->dev, "Step size needs to be page size\n");
> + return -ENXIO;
> + }
> +
> + /* Only 64 byte ECC layouts known */
> + if (mtd->oobsize > 64)
> + mtd->oobsize = 64;
> +
> + /* Use default large page ECC layout defined in NAND core */
> + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> + if (chip->ecc.strength == 32) {
> + nfc->ecc_mode = ECC_60_BYTE;
> + chip->ecc.bytes = 60;
> + } else if (chip->ecc.strength == 24) {
> + nfc->ecc_mode = ECC_45_BYTE;
> + chip->ecc.bytes = 45;
> + } else {
> + dev_err(nfc->dev, "Unsupported ECC strength\n");
> + return -ENXIO;
> + }
> +
> + chip->ecc.read_page = vf610_nfc_read_page;
> + chip->ecc.write_page = vf610_nfc_write_page;
> + chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
> + chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
> + chip->ecc.read_oob = vf610_nfc_read_oob;
> + chip->ecc.write_oob = vf610_nfc_write_oob;
> +
> + chip->ecc.size = PAGE_2K;
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops vf610_nfc_controller_ops = {
> + .attach_chip = vf610_nfc_attach_chip,
> +};
> +
> static int vf610_nfc_probe(struct platform_device *pdev)
> {
> struct vf610_nfc *nfc;
> @@ -827,67 +890,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
>
> vf610_nfc_preinit_controller(nfc);
>
> - /* first scan to find the device and get the page size */
> - err = nand_scan_ident(mtd, 1, NULL);
> - if (err)
> - goto err_disable_clk;
> -
> - vf610_nfc_init_controller(nfc);
> -
> - /* Bad block options. */
> - if (chip->bbt_options & NAND_BBT_USE_FLASH)
> - chip->bbt_options |= NAND_BBT_NO_OOB;
> -
> - /* Single buffer only, max 256 OOB minus ECC status */
> - if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
> - dev_err(nfc->dev, "Unsupported flash page size\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - if (chip->ecc.mode == NAND_ECC_HW) {
> - if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
> - dev_err(nfc->dev, "Unsupported flash with hwecc\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - if (chip->ecc.size != mtd->writesize) {
> - dev_err(nfc->dev, "Step size needs to be page size\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - /* Only 64 byte ECC layouts known */
> - if (mtd->oobsize > 64)
> - mtd->oobsize = 64;
> -
> - /* Use default large page ECC layout defined in NAND core */
> - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> - if (chip->ecc.strength == 32) {
> - nfc->ecc_mode = ECC_60_BYTE;
> - chip->ecc.bytes = 60;
> - } else if (chip->ecc.strength == 24) {
> - nfc->ecc_mode = ECC_45_BYTE;
> - chip->ecc.bytes = 45;
> - } else {
> - dev_err(nfc->dev, "Unsupported ECC strength\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - chip->ecc.read_page = vf610_nfc_read_page;
> - chip->ecc.write_page = vf610_nfc_write_page;
> - chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
> - chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
> - chip->ecc.read_oob = vf610_nfc_read_oob;
> - chip->ecc.write_oob = vf610_nfc_write_oob;
> -
> - chip->ecc.size = PAGE_2K;
> - }
> -
> - /* second phase scan */
> - err = nand_scan_tail(mtd);
> + /* Scan the NAND chip */
> + chip->dummy_controller.ops = &vf610_nfc_controller_ops;
> + err = nand_scan(mtd, 1);
> if (err)
> goto err_disable_clk;
>


2018-07-22 06:42:21

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 26/35] mtd: rawnand: atmel: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:18 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/atmel/nand-controller.c | 83 ++++++++++++++--------------
> 1 file changed, 40 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
> index 855cc7729c43..0bc7e2abc885 100644
> --- a/drivers/mtd/nand/raw/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
> @@ -202,7 +202,7 @@ struct atmel_nand_controller_ops {
> int (*remove)(struct atmel_nand_controller *nc);
> void (*nand_init)(struct atmel_nand_controller *nc,
> struct atmel_nand *nand);
> - int (*ecc_init)(struct atmel_nand *nand);
> + int (*ecc_init)(struct nand_chip *chip);
> int (*setup_data_interface)(struct atmel_nand *nand, int csline,
> const struct nand_data_interface *conf);
> };
> @@ -1133,9 +1133,8 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
> return 0;
> }
>
> -static int atmel_nand_ecc_init(struct atmel_nand *nand)
> +static int atmel_nand_ecc_init(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &nand->base;
> struct atmel_nand_controller *nc;
> int ret;
>
> @@ -1170,12 +1169,11 @@ static int atmel_nand_ecc_init(struct atmel_nand *nand)
> return 0;
> }
>
> -static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
> +static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &nand->base;
> int ret;
>
> - ret = atmel_nand_ecc_init(nand);
> + ret = atmel_nand_ecc_init(chip);
> if (ret)
> return ret;
>
> @@ -1558,22 +1556,6 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
> chip->select_chip = atmel_hsmc_nand_select_chip;
> }
>
> -static int atmel_nand_detect(struct atmel_nand *nand)
> -{
> - struct nand_chip *chip = &nand->base;
> - struct mtd_info *mtd = nand_to_mtd(chip);
> - struct atmel_nand_controller *nc;
> - int ret;
> -
> - nc = to_nand_controller(chip->controller);
> -
> - ret = nand_scan_ident(mtd, nand->numcs, NULL);
> - if (ret)
> - dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
> -
> - return ret;
> -}
> -
> static int atmel_nand_unregister(struct atmel_nand *nand)
> {
> struct nand_chip *chip = &nand->base;
> @@ -1595,7 +1577,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
> struct nand_chip *chip = &nand->base;
> struct mtd_info *mtd = nand_to_mtd(chip);
> struct atmel_nand_controller *nc;
> - int ret;
>
> nc = to_nand_controller(chip->controller);
>
> @@ -1626,21 +1607,6 @@ static int atmel_nand_register(struct atmel_nand *nand)
> }
> }
>
> - ret = nand_scan_tail(mtd);
> - if (ret) {
> - dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
> - return ret;
> - }
> -
> - ret = mtd_device_register(mtd, NULL, 0);
> - if (ret) {
> - dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
> - nand_cleanup(chip);
> - return ret;
> - }
> -
> - list_add_tail(&nand->node, &nc->chips);
> -

You can move all the code in atmel_nand_register() directly in
atmel_nand_controller_add_nand() + rename atmel_nand_unregister() into
atmel_nand_controller_remove_nand(). This should be done in a separate
patch so that the transition to nand_scan() is easier to review.

> return 0;
> }
>
> @@ -1755,6 +1721,8 @@ static int
> atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
> struct atmel_nand *nand)
> {
> + struct nand_chip *chip = &nand->base;
> + struct mtd_info *mtd = nand_to_mtd(chip);
> int ret;
>
> /* No card inserted, skip this NAND. */
> @@ -1765,15 +1733,30 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
>
> nc->caps->ops->nand_init(nc, nand);
>
> - ret = atmel_nand_detect(nand);
> - if (ret)
> + ret = nand_scan(mtd, nand->numcs);
> + if (ret) {
> + dev_err(nc->dev, "NAND scan failed: %d\n", ret);
> return ret;
> + }
>
> - ret = nc->caps->ops->ecc_init(nand);
> + ret = atmel_nand_register(nand);
> if (ret)
> - return ret;
> + goto cleanup_nand;
> +
> + ret = mtd_device_register(mtd, NULL, 0);
> + if (ret) {
> + dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
> + goto cleanup_nand;
> + }
> +
> + list_add_tail(&nand->node, &nc->chips);
> +
> + return 0;
> +
> +cleanup_nand:
> + nand_cleanup(chip);
>
> - return atmel_nand_register(nand);
> + return ret;
> }
>
> static int
> @@ -1958,6 +1941,19 @@ static const struct of_device_id atmel_matrix_of_ids[] = {
> { /* sentinel */ },
> };
>
> +static int atmel_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct atmel_nand_controller *nc;
> +
> + nc = to_nand_controller(chip->controller);
> +
> + return nc->caps->ops->ecc_init(chip);
> +}
> +
> +static const struct nand_controller_ops atmel_nand_controller_ops = {
> + .attach_chip = atmel_nand_attach_chip,
> +};
> +
> static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
> struct platform_device *pdev,
> const struct atmel_nand_controller_caps *caps)
> @@ -1967,6 +1963,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
> int ret;
>
> nand_controller_init(&nc->base);
> + nc->base.ops = &atmel_nand_controller_ops;
> INIT_LIST_HEAD(&nc->chips);
> nc->dev = dev;
> nc->caps = caps;


2018-07-22 06:45:50

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 27/35] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()

On Fri, 20 Jul 2018 17:15:19 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan_with_ids()
> (alternative to nand_scan() for passing a flash IDs table) instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/sm_common.c | 39 +++++++++++++++++++++++++--------------
> 1 file changed, 25 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
> index 7f5044a79f01..d05e3f976a5e 100644
> --- a/drivers/mtd/nand/raw/sm_common.c
> +++ b/drivers/mtd/nand/raw/sm_common.c
> @@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
> {NULL}
> };
>
> -int sm_register_device(struct mtd_info *mtd, int smartmedia)
> +static int sm_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - int ret;
> -
> - chip->options |= NAND_SKIP_BBTSCAN;
> -
> - /* Scan for card properties */
> - ret = nand_scan_ident(mtd, 1, smartmedia ?
> - nand_smartmedia_flash_ids : nand_xd_flash_ids);
> -
> - if (ret)
> - return ret;
> + struct mtd_info *mtd = nand_to_mtd(chip);
>
> /* Bad block marker position */
> chip->badblockpos = 0x05;
> @@ -187,12 +177,33 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
> else
> return -ENODEV;
>
> - ret = nand_scan_tail(mtd);
> + return 0;
> +}
>
> +static const struct nand_controller_ops sm_controller_ops = {
> + .attach_chip = sm_attach_chip,
> +};
> +
> +int sm_register_device(struct mtd_info *mtd, int smartmedia)
> +{
> + struct nand_chip *chip = mtd_to_nand(mtd);
> + struct nand_flash_dev *flash_ids;
> + int ret;
> +
> + chip->options |= NAND_SKIP_BBTSCAN;
> +
> + /* Scan for card properties */
> + chip->dummy_controller.ops = &sm_controller_ops;
> + flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
> + ret = nand_scan_with_ids(mtd, 1, flash_ids);
> if (ret)
> return ret;
>
> - return mtd_device_register(mtd, NULL, 0);
> + ret = mtd_device_register(mtd, NULL, 0);
> + if (ret)
> + nand_release(mtd);
> +
> + return ret;
> }
> EXPORT_SYMBOL_GPL(sm_register_device);
>


2018-07-22 08:51:35

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 28/35] mtd: rawnand: allow exiting immediately nand_scan_ident()

On Fri, 20 Jul 2018 17:15:20 +0200
Miquel Raynal <[email protected]> wrote:

> Some driver (eg. docg4) will need to handle themselves the
> identification phase. As part of the migration to use nand_scan()
> everywhere (which will unconditionnaly call nand_scan_ident()), we add
> a condition at the start of nand_scan_ident() to just "do nothing" if
> the maxchips parameters is zero, meaning that the driver does not want
> the core to handle this phase.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/nand_base.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index dea41fa25be1..e7f135c100c2 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -5926,7 +5926,7 @@ static int nand_dt_init(struct nand_chip *chip)
> /**
> * nand_scan_ident - [NAND Interface] Scan for the NAND device
> * @mtd: MTD device structure
> - * @maxchips: number of chips to scan for
> + * @maxchips: number of chips to scan for, returns immediately if 0
> * @table: alternative NAND ID table
> *
> * This is the first phase of the normal nand_scan() function. It reads the
> @@ -5940,6 +5940,14 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> struct nand_chip *chip = mtd_to_nand(mtd);
> int ret;
>
> + /*
> + * If the number of chips to scan for is null, just return silently.

^ zero


> + * This is for specific drivers that must handle this part of the
> + * probe process themselves (e.g docg4).
> + */

I think that description of the special case maxchips == 0 should be
placed in the kernel doc header.

> + if (!maxchips)
> + return 0;

Can we move this check in nand_scan_with_ids()?

> +
> /* Enforce the right timings for reset/detection */
> onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
>


2018-07-22 08:53:24

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 29/35] mtd: rawnand: docg4: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:21 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/docg4.c | 55 ++++++++++++++++++++++++++------------------
> 1 file changed, 32 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
> index 4dccdfba6140..fec4353ff4ef 100644
> --- a/drivers/mtd/nand/raw/docg4.c
> +++ b/drivers/mtd/nand/raw/docg4.c
> @@ -1227,10 +1227,9 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
> * required within a nand driver because they are performed by the nand
> * infrastructure code as part of nand_scan(). In this case they need
> * to be initialized here because we skip call to nand_scan_ident() (the
> - * first half of nand_scan()). The call to nand_scan_ident() is skipped
> - * because for this device the chip id is not read in the manner of a
> - * standard nand device. Unfortunately, nand_scan_ident() does other
> - * things as well, such as call nand_set_defaults().
> + * first half of nand_scan()). The call to nand_scan_ident() could be
> + * skipped because for this device the chip id is not read in the manner
> + * of a standard nand device.
> */
>
> struct nand_chip *nand = mtd_to_nand(mtd);
> @@ -1315,6 +1314,27 @@ static int __init read_id_reg(struct mtd_info *mtd)
>
> static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
>
> +static int docg4_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
> +
> + init_mtd_structs(mtd);
> +
> + /* Initialize kernel BCH algorithm */
> + doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
> + if (!doc->bch)
> + return -EINVAL;
> +

You need a ->detach_chip() hook to free the BCH context, don't you?

> + reset(mtd);
> +
> + return read_id_reg(mtd);
> +}
> +
> +static const struct nand_controller_ops docg4_controller_ops = {
> + .attach_chip = docg4_attach_chip,
> +};
> +
> static int __init probe_docg4(struct platform_device *pdev)
> {
> struct mtd_info *mtd;
> @@ -1350,26 +1370,16 @@ static int __init probe_docg4(struct platform_device *pdev)
> mtd->dev.parent = &pdev->dev;
> doc->virtadr = virtadr;
> doc->dev = dev;
> -
> - init_mtd_structs(mtd);
> -
> - /* initialize kernel bch algorithm */
> - doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
> - if (doc->bch == NULL) {
> - retval = -EINVAL;
> - goto free_nand;
> - }
> -
> platform_set_drvdata(pdev, doc);
>
> - reset(mtd);
> - retval = read_id_reg(mtd);
> - if (retval == -ENODEV) {
> - dev_warn(dev, "No diskonchip G4 device found.\n");
> - goto free_bch;
> - }
> -
> - retval = nand_scan_tail(mtd);
> + /*
> + * Asking for 0 chips is useless here but it warns the user that the use
> + * of the nand_scan() function is a bit abused here because the
> + * initialization is actually a bit specific and re-handled again in the
> + * ->attach_chip() hook. It will probably leak some memory though.

I don't get the last part. Is there really a memory leak? In that case
we should find a solution to prevent that.

> + */
> + nand->dummy_controller.ops = &docg4_controller_ops;
> + retval = nand_scan(mtd, 0);
> if (retval)
> goto free_bch;
>
> @@ -1389,7 +1399,6 @@ static int __init probe_docg4(struct platform_device *pdev)
> nand_cleanup(nand);
> free_bch:
> free_bch(doc->bch);

This should be done in the ->detach_chip() hook.

> -free_nand:
> kfree(nand);
> unmap:
> iounmap(virtadr);


2018-07-22 09:00:59

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 30/35] mtd: rawnand: qcom: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:22 +0200
Miquel Raynal <[email protected]> wrote:

>
> -static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
> - struct qcom_nand_host *host,
> - struct device_node *dn)
> +static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
> + struct qcom_nand_host *host,
> + struct device_node *dn)
> {
> struct nand_chip *chip = &host->chip;
> struct mtd_info *mtd = nand_to_mtd(chip);
> @@ -2824,36 +2828,20 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
> chip->block_markbad = qcom_nandc_block_markbad;
>
> chip->controller = &nandc->controller;
> + chip->controller->ops = &qcom_nandc_ops;

This assignment should be moved here [1].

Once fixed you can add

Reviewed-by: Boris Brezillon <[email protected]>


[1]https://elixir.bootlin.com/linux/v4.18-rc5/source/drivers/mtd/nand/raw/qcom_nandc.c#L2574

2018-07-22 09:30:38

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 31/35] mtd: rawnand: jz4740: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:23 +0200
Miquel Raynal <[email protected]> wrote:

> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/jz4740_nand.c | 46 ++++++++++++++++++++++++--------------
> 1 file changed, 29 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
> index 9bb8a89e09f9..8f821fdf8a1c 100644
> --- a/drivers/mtd/nand/raw/jz4740_nand.c
> +++ b/drivers/mtd/nand/raw/jz4740_nand.c
> @@ -59,6 +59,7 @@
>
> struct jz_nand {
> struct nand_chip chip;
> + struct platform_device *pdev;

You don't need this field. You can just do
to_platform_device(mtd->dev.parent) to get the platform_device.

> void __iomem *base;
> struct resource *mem;
>
> @@ -329,8 +330,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
> writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
>
> if (chipnr == 0) {
> - /* Detect first chip. */
> - ret = nand_scan_ident(mtd, 1, NULL);
> + /* Detect the first chip and register it */
> + ret = nand_scan(mtd, 1);
> if (ret)
> goto notfound_id;
>
> @@ -367,6 +368,25 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
> return ret;
> }
>
> +static int jz_nand_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct jz_nand *nand = mtd_to_jz_nand(mtd);
> + struct device *dev = mtd->dev.parent;
> + struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
> +
> + if (pdata && pdata->ident_callback) {
> + pdata->ident_callback(nand->pdev, mtd, &pdata->partitions,
> + &pdata->num_partitions);
> + }

Curly braces are not needed.

> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops jz_nand_controller_ops = {
> + .attach_chip = jz_nand_attach_chip,
> +};
> +
> static int jz_nand_probe(struct platform_device *pdev)
> {
> int ret;
> @@ -397,6 +417,7 @@ static int jz_nand_probe(struct platform_device *pdev)
> mtd = nand_to_mtd(chip);
> mtd->dev.parent = &pdev->dev;
> mtd->name = "jz4740-nand";
> + nand->pdev = pdev;
>
> chip->ecc.hwctl = jz_nand_hwctl;
> chip->ecc.calculate = jz_nand_calculate_ecc_rs;
> @@ -410,6 +431,7 @@ static int jz_nand_probe(struct platform_device *pdev)
> chip->chip_delay = 50;
> chip->cmd_ctrl = jz_nand_cmd_ctrl;
> chip->select_chip = jz_nand_select_chip;
> + chip->dummy_controller.ops = &jz_nand_controller_ops;
>
> if (nand->busy_gpio)
> chip->dev_ready = jz_nand_dev_ready;
> @@ -450,20 +472,10 @@ static int jz_nand_probe(struct platform_device *pdev)
> else
> nand->banks[chipnr] = 0;
> }
> +
> if (chipnr == 0) {
> dev_err(&pdev->dev, "No NAND chips found\n");
> - goto err_iounmap_mmio;
> - }
> -
> - if (pdata && pdata->ident_callback) {
> - pdata->ident_callback(pdev, mtd, &pdata->partitions,
> - &pdata->num_partitions);
> - }
> -
> - ret = nand_scan_tail(mtd);
> - if (ret) {
> - dev_err(&pdev->dev, "Failed to scan NAND\n");
> - goto err_unclaim_banks;
> + goto err_nand_release;
> }

As for the atmel driver, I'd prefer to have one patch to moves
nand_scan_ident() and nand_scan_tail() in the same function so that the
transition to nand_scan()+attach_chip is easier to review.

>
> ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
> @@ -471,15 +483,13 @@ static int jz_nand_probe(struct platform_device *pdev)
>
> if (ret) {
> dev_err(&pdev->dev, "Failed to add mtd device\n");
> - goto err_nand_release;
> + goto err_unclaim_banks;
> }
>
> dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
>
> return 0;
>
> -err_nand_release:
> - nand_release(mtd);
> err_unclaim_banks:
> while (chipnr--) {
> unsigned char bank = nand->banks[chipnr];
> @@ -487,6 +497,8 @@ static int jz_nand_probe(struct platform_device *pdev)
> nand->bank_base[bank - 1]);
> }
> writel(0, nand->base + JZ_REG_NAND_CTRL);
> +err_nand_release:
> + nand_release(mtd);
> err_iounmap_mmio:
> jz_nand_iounmap_resource(nand->mem, nand->base);
> err_free:


2018-07-22 09:32:24

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 32/35] mtd: rawnand: tegra: convert driver to nand_scan()

On Fri, 20 Jul 2018 17:15:24 +0200
Miquel Raynal <[email protected]> wrote:

> + chip = &nand->chip;
> + chip->controller = &ctrl->controller;
> + chip->controller->ops = &tegra_nand_controller_ops;

Should be moved next to the controller initialization.


2018-07-22 10:33:40

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 33/35] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore

On Fri, 20 Jul 2018 17:15:25 +0200
Miquel Raynal <[email protected]> wrote:

> Both nand_scan_ident() and nand_scan_tail() helpers used to be called
> directly from controller drivers that needed to tweak some ECC-related
> parameters before nand_scan_tail(). This separation prevented dynamic
> allocations during the phase of NAND identification, which was
> inconvenient.
>
> All controller drivers have been moved to use nand_scan(), in
> conjunction with the chip->ecc.[attach|detach]_chip() hooks that
> actually do the required tweaking sequence between both ident/tail
> calls, allowing programmers to use dynamic allocation as they need all
> across the scanning sequence.
>
> Declare nand_scan_[ident|tail]() statically now.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/nand_base.c | 16 +++++++++-------
> include/linux/mtd/rawnand.h | 9 ++-------
> 2 files changed, 11 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index e7f135c100c2..da99232702a4 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -5924,7 +5924,7 @@ static int nand_dt_init(struct nand_chip *chip)
> }
>
> /**
> - * nand_scan_ident - [NAND Interface] Scan for the NAND device
> + * nand_scan_ident - Scan for the NAND device
> * @mtd: MTD device structure
> * @maxchips: number of chips to scan for, returns immediately if 0
> * @table: alternative NAND ID table
> @@ -5932,9 +5932,13 @@ static int nand_dt_init(struct nand_chip *chip)
> * This is the first phase of the normal nand_scan() function. It reads the
> * flash ID and sets up MTD fields accordingly.
> *
> + * This helper used to be called directly from controller drivers that needed
> + * to tweak some ECC-related parameters before nand_scan_tail(). This separation
> + * prevented dynamic allocations during this phase which was unconvenient and
> + * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
> */
> -int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> - struct nand_flash_dev *table)
> +static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> + struct nand_flash_dev *table)
> {
> int i, nand_maf_id, nand_dev_id;
> struct nand_chip *chip = mtd_to_nand(mtd);
> @@ -6016,7 +6020,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
>
> return 0;
> }
> -EXPORT_SYMBOL(nand_scan_ident);
>
> static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
> {
> @@ -6393,14 +6396,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
> }
>
> /**
> - * nand_scan_tail - [NAND Interface] Scan for the NAND device
> + * nand_scan_tail - Scan for the NAND device
> * @mtd: MTD device structure
> *
> * This is the second phase of the normal nand_scan() function. It fills out
> * all the uninitialized function pointers with the defaults and scans for a
> * bad block table if appropriate.
> */
> -int nand_scan_tail(struct mtd_info *mtd)
> +static int nand_scan_tail(struct mtd_info *mtd)
> {
> struct nand_chip *chip = mtd_to_nand(mtd);
> struct nand_ecc_ctrl *ecc = &chip->ecc;
> @@ -6724,7 +6727,6 @@ int nand_scan_tail(struct mtd_info *mtd)
>
> return ret;
> }
> -EXPORT_SYMBOL(nand_scan_tail);
>
> static int nand_attach(struct nand_chip *chip)
> {
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index a20c78e25878..a928771a7ae4 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -36,14 +36,9 @@ static inline int nand_scan(struct mtd_info *mtd, int max_chips)
> }
>
> /*
> - * Separate phases of nand_scan(), allowing board driver to intervene
> - * and override command or ECC setup according to flash type.
> + * Unregister the MTD device and free resources held by the NAND device, must be
> + * called on error after a successful nand_scan().

Nope. You're mixing nand_cleanup() and nand_release(). nand_release()
should not be used because it ignores mtd_device_unregister() and might
call nand_cleanup() on an object that is still being exposed to the MTD
layer. Your comment applies to nand_cleanup() though ;-).

> */
> -int nand_scan_ident(struct mtd_info *mtd, int max_chips,
> - struct nand_flash_dev *table);
> -int nand_scan_tail(struct mtd_info *mtd);
> -
> -/* Unregister the MTD device and free resources held by the NAND device */
> void nand_release(struct mtd_info *mtd);
>
> /* Internal helper for board drivers which need to override command function */


2018-07-22 10:35:14

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 34/35] mtd: rawnand: allocate model parameter dynamically

On Fri, 20 Jul 2018 17:15:26 +0200
Miquel Raynal <[email protected]> wrote:

> Thanks to the migration of all drivers to use nand_scan() and the
> related nand_controller_ops, we can now allocate data during the
> detection phase. Let's do it first for the NAND model parameter which
> is allocated in nand_detect().
>
> Signed-off-by: Miquel Raynal <[email protected]>

Reviewed-by: Boris Brezillon <[email protected]>

> ---
> drivers/mtd/nand/raw/nand_base.c | 52 +++++++++++++++++++++++++++++++---------
> include/linux/mtd/rawnand.h | 2 +-
> 2 files changed, 42 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index da99232702a4..8645f655e5b0 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -5225,8 +5225,11 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
>
> sanitize_string(p->manufacturer, sizeof(p->manufacturer));
> sanitize_string(p->model, sizeof(p->model));
> - strncpy(chip->parameters.model, p->model,
> - sizeof(chip->parameters.model) - 1);
> + chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
> + if (!chip->parameters.model) {
> + ret = -ENOMEM;
> + goto free_onfi_param_page;
> + }
>
> mtd->writesize = le32_to_cpu(p->byte_per_page);
>
> @@ -5356,8 +5359,11 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
>
> sanitize_string(p->manufacturer, sizeof(p->manufacturer));
> sanitize_string(p->model, sizeof(p->model));
> - strncpy(chip->parameters.model, p->model,
> - sizeof(chip->parameters.model) - 1);
> + chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
> + if (!chip->parameters.model) {
> + ret = -ENOMEM;
> + goto free_jedec_param_page;
> + }
>
> mtd->writesize = le32_to_cpu(p->byte_per_page);
>
> @@ -5546,8 +5552,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
> chip->onfi_timing_mode_default =
> type->onfi_timing_mode_default;
>
> - strncpy(chip->parameters.model, type->name,
> - sizeof(chip->parameters.model) - 1);
> + chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
> + if (!chip->parameters.model)
> + return false;
>
> return true;
> }
> @@ -5706,8 +5713,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
> if (!type->name)
> return -ENODEV;
>
> - strncpy(chip->parameters.model, type->name,
> - sizeof(chip->parameters.model) - 1);
> + chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
> + if (!chip->parameters.model)
> + return -ENOMEM;
>
> chip->chipsize = (uint64_t)type->chipsize << 20;
>
> @@ -5737,7 +5745,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
> mtd->name);
> pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
> (chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
> - return -EINVAL;
> + ret = -EINVAL;
> +
> + goto free_detect_allocation;
> }
>
> nand_decode_bbm_options(chip);
> @@ -5774,6 +5784,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
> (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
> mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
> return 0;
> +
> +free_detect_allocation:
> + kfree(chip->parameters.model);
> +
> + return ret;
> }
>
> static const char * const nand_ecc_modes[] = {
> @@ -6021,6 +6036,11 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> return 0;
> }
>
> +static void nand_scan_ident_cleanup(struct nand_chip *chip)
> +{
> + kfree(chip->parameters.model);
> +}
> +
> static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
> {
> struct nand_chip *chip = mtd_to_nand(mtd);
> @@ -6764,11 +6784,18 @@ int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
>
> ret = nand_attach(chip);
> if (ret)
> - return ret;
> + goto cleanup_ident;
>
> ret = nand_scan_tail(mtd);
> if (ret)
> - nand_detach(chip);
> + goto detach_chip;
> +
> + return 0;
> +
> +detach_chip:
> + nand_detach(chip);
> +cleanup_ident:
> + nand_scan_ident_cleanup(chip);
>
> return ret;
> }
> @@ -6800,6 +6827,9 @@ void nand_cleanup(struct nand_chip *chip)
>
> /* Free controller specific allocations after chip identification */
> nand_detach(chip);
> +
> + /* Free identification phase allocations */
> + nand_scan_ident_cleanup(chip);
> }
>
> EXPORT_SYMBOL_GPL(nand_cleanup);
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index a928771a7ae4..5723d940a47d 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -482,7 +482,7 @@ struct onfi_params {
> */
> struct nand_parameters {
> /* Generic parameters */
> - char model[100];
> + const char *model;
> bool supports_set_get_features;
> DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER);
> DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);


2018-07-22 10:36:55

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 35/35] mtd: rawnand: allocate dynamically ONFI parameters during detection

On Fri, 20 Jul 2018 17:15:27 +0200
Miquel Raynal <[email protected]> wrote:

> Now that it is possible to do dynamic allocations during the
> identification phase, convert the onfi_params structure (which is only
> needed with ONFI compliant chips) into a pointer that will be allocated
> only if needed.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/nand_base.c | 54 +++++++++++++++++++++++--------------
> drivers/mtd/nand/raw/nand_micron.c | 6 ++---
> drivers/mtd/nand/raw/nand_timings.c | 12 ++++-----
> include/linux/mtd/rawnand.h | 6 ++---
> 4 files changed, 46 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index 8645f655e5b0..ed9e2f1578e6 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -5151,6 +5151,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
> {
> struct mtd_info *mtd = nand_to_mtd(chip);
> struct nand_onfi_params *p;
> + struct onfi_params *onfi;
> + int onfi_version = 0;
> char id[4];
> int i, ret, val;
>
> @@ -5206,21 +5208,19 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
> /* Check version */
> val = le16_to_cpu(p->revision);
> if (val & ONFI_VERSION_2_3)
> - chip->parameters.onfi.version = 23;
> + onfi_version = 23;
> else if (val & ONFI_VERSION_2_2)
> - chip->parameters.onfi.version = 22;
> + onfi_version = 22;
> else if (val & ONFI_VERSION_2_1)
> - chip->parameters.onfi.version = 21;
> + onfi_version = 21;
> else if (val & ONFI_VERSION_2_0)
> - chip->parameters.onfi.version = 20;
> + onfi_version = 20;
> else if (val & ONFI_VERSION_1_0)
> - chip->parameters.onfi.version = 10;
> + onfi_version = 10;
>
> - if (!chip->parameters.onfi.version) {
> + if (!onfi_version) {
> pr_info("unsupported ONFI version: %d\n", val);
> goto free_onfi_param_page;
> - } else {
> - ret = 1;
> }
>
> sanitize_string(p->manufacturer, sizeof(p->manufacturer));
> @@ -5257,7 +5257,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
> if (p->ecc_bits != 0xff) {
> chip->ecc_strength_ds = p->ecc_bits;
> chip->ecc_step_ds = 512;
> - } else if (chip->parameters.onfi.version >= 21 &&
> + } else if (onfi_version >= 21 &&
> (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
>
> /*
> @@ -5284,19 +5284,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
> bitmap_set(chip->parameters.set_feature_list,
> ONFI_FEATURE_ADDR_TIMING_MODE, 1);
> }
> - chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
> - chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
> - chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
> - chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
> - chip->parameters.onfi.async_timing_mode =
> - le16_to_cpu(p->async_timing_mode);
> - chip->parameters.onfi.vendor_revision =
> - le16_to_cpu(p->vendor_revision);
> - memcpy(chip->parameters.onfi.vendor, p->vendor,
> - sizeof(p->vendor));
>
> + onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
> + if (!onfi) {
> + ret = -ENOMEM;
> + goto free_model;
> + }
> +
> + onfi->version = onfi_version;
> + onfi->tPROG = le16_to_cpu(p->t_prog);
> + onfi->tBERS = le16_to_cpu(p->t_bers);
> + onfi->tR = le16_to_cpu(p->t_r);
> + onfi->tCCS = le16_to_cpu(p->t_ccs);
> + onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
> + onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
> + memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
> + chip->parameters.onfi = onfi;
> +
> + /* Identification done, free the full ONFI parameter page and exit */
> + kfree(p);
> +
> + return 1;
> +
> +free_model:
> + kfree(chip->parameters.model);
> free_onfi_param_page:
> kfree(p);
> +
> return ret;
> }
>
> @@ -5693,7 +5707,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
> }
> }
>
> - chip->parameters.onfi.version = 0;
> if (!type->name || !type->pagesize) {
> /* Check if the chip is ONFI compliant */
> ret = nand_flash_detect_onfi(chip);
> @@ -6039,6 +6052,7 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> static void nand_scan_ident_cleanup(struct nand_chip *chip)
> {
> kfree(chip->parameters.model);
> + kfree(chip->parameters.onfi);
> }
>
> static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
> diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
> index 656947d91841..8466a1740b3b 100644
> --- a/drivers/mtd/nand/raw/nand_micron.c
> +++ b/drivers/mtd/nand/raw/nand_micron.c
> @@ -88,9 +88,9 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
> static int micron_nand_onfi_init(struct nand_chip *chip)
> {
> struct nand_parameters *p = &chip->parameters;
> - struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
> + struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;
>
> - if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
> + if (p->onfi && p->onfi->vendor_revision) {

I think p->onfi != NULL guarantees that p->onfi->vendor_revision != 0.
if (p->onfi) should be enough.

Looks good otherwise.

Reviewed-by: Boris Brezillon <[email protected]>

> chip->read_retries = micron->read_retry_options;
> chip->setup_read_retry = micron_nand_setup_read_retry;
> }
> @@ -382,7 +382,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
> u8 id[5];
> int ret;
>
> - if (!chip->parameters.onfi.version)
> + if (!chip->parameters.onfi)
> return MICRON_ON_DIE_UNSUPPORTED;
>
> if (chip->bits_per_cell != 1)
> diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
> index 9bb599106a31..ebc7b5f76f77 100644
> --- a/drivers/mtd/nand/raw/nand_timings.c
> +++ b/drivers/mtd/nand/raw/nand_timings.c
> @@ -294,6 +294,7 @@ int onfi_fill_data_interface(struct nand_chip *chip,
> int timing_mode)
> {
> struct nand_data_interface *iface = &chip->data_interface;
> + struct onfi_params *onfi = chip->parameters.onfi;
>
> if (type != NAND_SDR_IFACE)
> return -EINVAL;
> @@ -308,17 +309,16 @@ int onfi_fill_data_interface(struct nand_chip *chip,
> * tPROG, tBERS, tR and tCCS.
> * These information are part of the ONFI parameter page.
> */
> - if (chip->parameters.onfi.version) {
> - struct nand_parameters *params = &chip->parameters;
> + if (onfi) {
> struct nand_sdr_timings *timings = &iface->timings.sdr;
>
> /* microseconds -> picoseconds */
> - timings->tPROG_max = 1000000ULL * params->onfi.tPROG;
> - timings->tBERS_max = 1000000ULL * params->onfi.tBERS;
> - timings->tR_max = 1000000ULL * params->onfi.tR;
> + timings->tPROG_max = 1000000ULL * onfi->tPROG;
> + timings->tBERS_max = 1000000ULL * onfi->tBERS;
> + timings->tR_max = 1000000ULL * onfi->tR;
>
> /* nanoseconds -> picoseconds */
> - timings->tCCS_min = 1000UL * params->onfi.tCCS;
> + timings->tCCS_min = 1000UL * onfi->tCCS;
> } else {
> struct nand_sdr_timings *timings = &iface->timings.sdr;
> /*
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index 5723d940a47d..8074cbd4e3fe 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -488,7 +488,7 @@ struct nand_parameters {
> DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
>
> /* ONFI parameters */
> - struct onfi_params onfi;
> + struct onfi_params *onfi;
> };
>
> /* The maximum expected count of bytes in the NAND ID sequence */
> @@ -1618,10 +1618,10 @@ struct platform_nand_data {
> /* return the supported asynchronous timing mode. */
> static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
> {
> - if (!chip->parameters.onfi.version)
> + if (!chip->parameters.onfi)
> return ONFI_TIMING_MODE_UNKNOWN;
>
> - return chip->parameters.onfi.async_timing_mode;
> + return chip->parameters.onfi->async_timing_mode;
> }
>
> int onfi_fill_data_interface(struct nand_chip *chip,


2018-07-25 08:58:57

by Stefan Agner

[permalink] [raw]
Subject: Re: [PATCH v4 25/35] mtd: rawnand: vf610: convert driver to nand_scan()

On 20.07.2018 17:15, Miquel Raynal wrote:
> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().

Reviewed-by: Stefan Agner <[email protected]>

>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/vf610_nfc.c | 127 ++++++++++++++++++++-------------------
> 1 file changed, 66 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
> index d5a22fc96878..6f6dcbf9095b 100644
> --- a/drivers/mtd/nand/raw/vf610_nfc.c
> +++ b/drivers/mtd/nand/raw/vf610_nfc.c
> @@ -747,6 +747,69 @@ static void vf610_nfc_init_controller(struct
> vf610_nfc *nfc)
> }
> }
>
> +static int vf610_nfc_attach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct vf610_nfc *nfc = mtd_to_nfc(mtd);
> +
> + vf610_nfc_init_controller(nfc);
> +
> + /* Bad block options. */
> + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> + chip->bbt_options |= NAND_BBT_NO_OOB;
> +
> + /* Single buffer only, max 256 OOB minus ECC status */
> + if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
> + dev_err(nfc->dev, "Unsupported flash page size\n");
> + return -ENXIO;
> + }
> +
> + if (chip->ecc.mode != NAND_ECC_HW)
> + return 0;
> +
> + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
> + dev_err(nfc->dev, "Unsupported flash with hwecc\n");
> + return -ENXIO;
> + }
> +
> + if (chip->ecc.size != mtd->writesize) {
> + dev_err(nfc->dev, "Step size needs to be page size\n");
> + return -ENXIO;
> + }
> +
> + /* Only 64 byte ECC layouts known */
> + if (mtd->oobsize > 64)
> + mtd->oobsize = 64;
> +
> + /* Use default large page ECC layout defined in NAND core */
> + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> + if (chip->ecc.strength == 32) {
> + nfc->ecc_mode = ECC_60_BYTE;
> + chip->ecc.bytes = 60;
> + } else if (chip->ecc.strength == 24) {
> + nfc->ecc_mode = ECC_45_BYTE;
> + chip->ecc.bytes = 45;
> + } else {
> + dev_err(nfc->dev, "Unsupported ECC strength\n");
> + return -ENXIO;
> + }
> +
> + chip->ecc.read_page = vf610_nfc_read_page;
> + chip->ecc.write_page = vf610_nfc_write_page;
> + chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
> + chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
> + chip->ecc.read_oob = vf610_nfc_read_oob;
> + chip->ecc.write_oob = vf610_nfc_write_oob;
> +
> + chip->ecc.size = PAGE_2K;
> +
> + return 0;
> +}
> +
> +static const struct nand_controller_ops vf610_nfc_controller_ops = {
> + .attach_chip = vf610_nfc_attach_chip,
> +};
> +
> static int vf610_nfc_probe(struct platform_device *pdev)
> {
> struct vf610_nfc *nfc;
> @@ -827,67 +890,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
>
> vf610_nfc_preinit_controller(nfc);
>
> - /* first scan to find the device and get the page size */
> - err = nand_scan_ident(mtd, 1, NULL);
> - if (err)
> - goto err_disable_clk;
> -
> - vf610_nfc_init_controller(nfc);
> -
> - /* Bad block options. */
> - if (chip->bbt_options & NAND_BBT_USE_FLASH)
> - chip->bbt_options |= NAND_BBT_NO_OOB;
> -
> - /* Single buffer only, max 256 OOB minus ECC status */
> - if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
> - dev_err(nfc->dev, "Unsupported flash page size\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - if (chip->ecc.mode == NAND_ECC_HW) {
> - if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
> - dev_err(nfc->dev, "Unsupported flash with hwecc\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - if (chip->ecc.size != mtd->writesize) {
> - dev_err(nfc->dev, "Step size needs to be page size\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - /* Only 64 byte ECC layouts known */
> - if (mtd->oobsize > 64)
> - mtd->oobsize = 64;
> -
> - /* Use default large page ECC layout defined in NAND core */
> - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
> - if (chip->ecc.strength == 32) {
> - nfc->ecc_mode = ECC_60_BYTE;
> - chip->ecc.bytes = 60;
> - } else if (chip->ecc.strength == 24) {
> - nfc->ecc_mode = ECC_45_BYTE;
> - chip->ecc.bytes = 45;
> - } else {
> - dev_err(nfc->dev, "Unsupported ECC strength\n");
> - err = -ENXIO;
> - goto err_disable_clk;
> - }
> -
> - chip->ecc.read_page = vf610_nfc_read_page;
> - chip->ecc.write_page = vf610_nfc_write_page;
> - chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
> - chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
> - chip->ecc.read_oob = vf610_nfc_read_oob;
> - chip->ecc.write_oob = vf610_nfc_write_oob;
> -
> - chip->ecc.size = PAGE_2K;
> - }
> -
> - /* second phase scan */
> - err = nand_scan_tail(mtd);
> + /* Scan the NAND chip */
> + chip->dummy_controller.ops = &vf610_nfc_controller_ops;
> + err = nand_scan(mtd, 1);
> if (err)
> goto err_disable_clk;

2018-07-25 09:45:28

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

Hi.


2018-07-21 0:14 GMT+09:00 Miquel Raynal <[email protected]>:
> Two helpers have been added to the core to make ECC-related
> configuration between the detection phase and the final NAND scan. Use
> these hooks and convert the driver to just use nand_scan() instead of
> both nand_scan_ident() and nand_scan_tail().
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/mtd/nand/raw/denali.c | 138 +++++++++++++++++++++++-------------------
> 1 file changed, 77 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
> index 4d53f41ada08..2fa92c297a66 100644
> --- a/drivers/mtd/nand/raw/denali.c
> +++ b/drivers/mtd/nand/raw/denali.c
> @@ -1205,62 +1205,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
> return 0;
> }
>
> -int denali_init(struct denali_nand_info *denali)
> +static int denali_attach_chip(struct nand_chip *chip)
> {
> - struct nand_chip *chip = &denali->nand;
> struct mtd_info *mtd = nand_to_mtd(chip);
> - u32 features = ioread32(denali->reg + FEATURES);
> + struct denali_nand_info *denali = mtd_to_denali(mtd);
> int ret;
>
> - mtd->dev.parent = denali->dev;
> - denali_hw_init(denali);
> -
> - init_completion(&denali->complete);
> - spin_lock_init(&denali->irq_lock);
> -
> - denali_clear_irq_all(denali);
> -
> - ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
> - IRQF_SHARED, DENALI_NAND_NAME, denali);
> - if (ret) {
> - dev_err(denali->dev, "Unable to request IRQ\n");
> - return ret;
> - }
> -
> - denali_enable_irq(denali);
> - denali_reset_banks(denali);
> -
> - denali->active_bank = DENALI_INVALID_BANK;
> -
> - nand_set_flash_node(chip, denali->dev->of_node);
> - /* Fallback to the default name if DT did not give "label" property */
> - if (!mtd->name)
> - mtd->name = "denali-nand";
> -
> - chip->select_chip = denali_select_chip;
> - chip->read_byte = denali_read_byte;
> - chip->write_byte = denali_write_byte;
> - chip->read_word = denali_read_word;
> - chip->cmd_ctrl = denali_cmd_ctrl;
> - chip->dev_ready = denali_dev_ready;
> - chip->waitfunc = denali_waitfunc;
> -
> - if (features & FEATURES__INDEX_ADDR) {
> - denali->host_read = denali_indexed_read;
> - denali->host_write = denali_indexed_write;
> - } else {
> - denali->host_read = denali_direct_read;
> - denali->host_write = denali_direct_write;
> - }
> -
> - /* clk rate info is needed for setup_data_interface */
> - if (denali->clk_rate && denali->clk_x_rate)
> - chip->setup_data_interface = denali_setup_data_interface;
> -
> - ret = nand_scan_ident(mtd, denali->max_banks, NULL);
> - if (ret)
> - goto disable_irq;
> -
> if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
> denali->dma_avail = 1;
>
> @@ -1293,7 +1243,7 @@ int denali_init(struct denali_nand_info *denali)
> mtd->oobsize - denali->oob_skip_bytes);
> if (ret) {
> dev_err(denali->dev, "Failed to setup ECC settings.\n");
> - goto disable_irq;
> + return ret;
> }
>
> dev_dbg(denali->dev,
> @@ -1337,7 +1287,7 @@ int denali_init(struct denali_nand_info *denali)
>
> ret = denali_multidev_fixup(denali);
> if (ret)
> - goto disable_irq;
> + return ret;
>
> /*
> * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
> @@ -1345,26 +1295,92 @@ int denali_init(struct denali_nand_info *denali)
> * guarantee DMA-safe alignment.
> */
> denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
> - if (!denali->buf) {
> - ret = -ENOMEM;
> - goto disable_irq;
> + if (!denali->buf)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +static void denali_detach_chip(struct nand_chip *chip)
> +{
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + struct denali_nand_info *denali = mtd_to_denali(mtd);
> +
> + kfree(denali->buf);
> +}
> +
> +static const struct nand_controller_ops denali_controller_ops = {
> + .attach_chip = denali_attach_chip,
> + .detach_chip = denali_detach_chip,
> +};
> +
> +int denali_init(struct denali_nand_info *denali)
> +{
> + struct nand_chip *chip = &denali->nand;
> + struct mtd_info *mtd = nand_to_mtd(chip);
> + u32 features = ioread32(denali->reg + FEATURES);
> + int ret;
> +
> + mtd->dev.parent = denali->dev;
> + denali_hw_init(denali);
> +
> + init_completion(&denali->complete);
> + spin_lock_init(&denali->irq_lock);
> +
> + denali_clear_irq_all(denali);
> +
> + ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
> + IRQF_SHARED, DENALI_NAND_NAME, denali);
> + if (ret) {
> + dev_err(denali->dev, "Unable to request IRQ\n");
> + return ret;
> + }
> +
> + denali_enable_irq(denali);
> + denali_reset_banks(denali);
> +
> + denali->active_bank = DENALI_INVALID_BANK;
> +
> + nand_set_flash_node(chip, denali->dev->of_node);
> + /* Fallback to the default name if DT did not give "label" property */
> + if (!mtd->name)
> + mtd->name = "denali-nand";
> +
> + chip->select_chip = denali_select_chip;
> + chip->read_byte = denali_read_byte;
> + chip->write_byte = denali_write_byte;
> + chip->read_word = denali_read_word;
> + chip->cmd_ctrl = denali_cmd_ctrl;
> + chip->dev_ready = denali_dev_ready;
> + chip->waitfunc = denali_waitfunc;
> +
> + if (features & FEATURES__INDEX_ADDR) {
> + denali->host_read = denali_indexed_read;
> + denali->host_write = denali_indexed_write;
> + } else {
> + denali->host_read = denali_direct_read;
> + denali->host_write = denali_direct_write;
> }
>
> - ret = nand_scan_tail(mtd);
> + /* clk rate info is needed for setup_data_interface */
> + if (denali->clk_rate && denali->clk_x_rate)
> + chip->setup_data_interface = denali_setup_data_interface;
> +
> + chip->dummy_controller.ops = &denali_controller_ops;
> + ret = nand_scan(mtd, denali->max_banks);
> if (ret)
> - goto free_buf;
> + goto disable_irq;
>
> ret = mtd_device_register(mtd, NULL, 0);
> if (ret) {
> dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
> goto cleanup_nand;
> }
> +
> return 0;
>
> cleanup_nand:
> nand_cleanup(chip);
> -free_buf:
> - kfree(denali->buf);
> disable_irq:
> denali_disable_irq(denali);
>
> --
> 2.14.1
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/





You need to remove kfree(denali->buf)
from denali_remove(), right?



void denali_remove(struct denali_nand_info *denali)
{
struct mtd_info *mtd = nand_to_mtd(&denali->nand);

nand_release(mtd);
kfree(denali->buf); <---- REMOVE !!
denali_disable_irq(denali);
}




Otherwise, denali_remove() will free denali->buf twice
because kfree(denali->buf) is called from denali_detach_chip().






--
Best Regards
Masahiro Yamada

2018-07-25 09:52:40

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

On Wed, 25 Jul 2018 18:42:44 +0900
Masahiro Yamada <[email protected]> wrote:

>
> You need to remove kfree(denali->buf)
> from denali_remove(), right?

Absolutely.

>
> void denali_remove(struct denali_nand_info *denali)
> {
> struct mtd_info *mtd = nand_to_mtd(&denali->nand);
>
> nand_release(mtd);
> kfree(denali->buf); <---- REMOVE !!
> denali_disable_irq(denali);
> }
>
>
> Otherwise, denali_remove() will free denali->buf twice
> because kfree(denali->buf) is called from denali_detach_chip().


2018-07-25 12:48:39

by Miquel Raynal

[permalink] [raw]
Subject: Re: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

Hi Boris,

Boris Brezillon <[email protected]> wrote on Wed, 25 Jul 2018
11:51:16 +0200:

> On Wed, 25 Jul 2018 18:42:44 +0900
> Masahiro Yamada <[email protected]> wrote:
>
> >
> > You need to remove kfree(denali->buf)
> > from denali_remove(), right?
>
> Absolutely.
>
> >
> > void denali_remove(struct denali_nand_info *denali)
> > {
> > struct mtd_info *mtd = nand_to_mtd(&denali->nand);
> >
> > nand_release(mtd);
> > kfree(denali->buf); <---- REMOVE !!
> > denali_disable_irq(denali);
> > }
> >
> >
> > Otherwise, denali_remove() will free denali->buf twice
> > because kfree(denali->buf) is called from denali_detach_chip().
>

Absolutely, thanks for reviewing!

I'll apply with this changed.

Miquèl

2018-07-25 14:18:48

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH v4 04/35] mtd: rawnand: denali: convert to nand_scan()

2018-07-25 21:47 GMT+09:00 Miquel Raynal <[email protected]>:
> Hi Boris,
>
> Boris Brezillon <[email protected]> wrote on Wed, 25 Jul 2018
> 11:51:16 +0200:
>
>> On Wed, 25 Jul 2018 18:42:44 +0900
>> Masahiro Yamada <[email protected]> wrote:
>>
>> >
>> > You need to remove kfree(denali->buf)
>> > from denali_remove(), right?
>>
>> Absolutely.
>>
>> >
>> > void denali_remove(struct denali_nand_info *denali)
>> > {
>> > struct mtd_info *mtd = nand_to_mtd(&denali->nand);
>> >
>> > nand_release(mtd);
>> > kfree(denali->buf); <---- REMOVE !!
>> > denali_disable_irq(denali);
>> > }
>> >
>> >
>> > Otherwise, denali_remove() will free denali->buf twice
>> > because kfree(denali->buf) is called from denali_detach_chip().
>>
>
> Absolutely, thanks for reviewing!
>
> I'll apply with this changed.
>
> Miquèl


Assuming you will fix this,

Acked-by: Masahiro Yamada <[email protected]>


--
Best Regards
Masahiro Yamada

2018-07-26 06:08:41

by xiaolei li

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

On Sat, 2018-07-21 at 19:10 +0200, Boris Brezillon wrote:
> On Fri, 20 Jul 2018 17:15:06 +0200
> Miquel Raynal <[email protected]> wrote:
>
> > Two helpers have been added to the core to make ECC-related
> > configuration between the detection phase and the final NAND scan. Use
> > these hooks and convert the driver to just use nand_scan() instead of
> > both nand_scan_ident() and nand_scan_tail().
> >
> > Signed-off-by: Miquel Raynal <[email protected]>
> > ---
> > drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> > 1 file changed, 44 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> > index 7bc6be3f6ec0..967418f945ea 100644
> > --- a/drivers/mtd/nand/raw/mtk_nand.c
> > +++ b/drivers/mtd/nand/raw/mtk_nand.c
> > @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> > return 0;
> > }
> >
> > +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> > +{
> > + struct mtd_info *mtd = nand_to_mtd(chip);
> > + struct device *dev = mtd->dev.parent;
> > + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> > + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> > + int len;
> > + int ret;
> > +
> > + if (chip->options & NAND_BUSWIDTH_16) {
> > + dev_err(dev, "16bits buswidth not supported");
> > + return -EINVAL;
> > + }
> > +
> > + /* store bbt magic in page, cause OOB is not protected */
> > + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> > + chip->bbt_options |= NAND_BBT_NO_OOB;
> > +
> > + ret = mtk_nfc_ecc_init(dev, mtd);
> > + if (ret)
> > + return ret;
> > +
> > + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> > + if (ret)
> > + return ret;
> > +
> > + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> > + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> > +
> > + len = mtd->writesize + mtd->oobsize;
> > + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > + if (!nfc->buffer)
> > + return -ENOMEM;
> > +
> > + return 0;
> > +}
> > +
> > +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> > + .attach_chip = mtk_nfc_attach_chip,
> > +};
> > +
> > static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > struct device_node *np)
> > {
> > struct mtk_nfc_nand_chip *chip;
> > struct nand_chip *nand;
> > struct mtd_info *mtd;
> > - int nsels, len;
> > + int nsels;
> > u32 tmp;
> > int ret;
> > int i;
> > @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> >
> > nand = &chip->nand;
> > nand->controller = &nfc->controller;
> > + nand->controller->ops = &mtk_nfc_controller_ops;
>
> Just like for the marvell driver, this assignment should be moved here
> [1].
Agree to this.

> Also, it looks like this driver is open-coding
> nand_controller_init(), probably something we should fix (in a separate
> patch).
May I ask if you mean driver should use nand_hw_control_init helper to
do controller_init?

Thanks,
Xiaolei

>
> With this fixed:
>
> Reviewed-by: Boris Brezillon <[email protected]>
>
> >
> > nand_set_flash_node(nand, np);
> > nand_set_controller_data(nand, nfc);
> > @@ -1324,36 +1366,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> >
> > mtk_nfc_hw_init(nfc);
> >
> > - ret = nand_scan_ident(mtd, nsels, NULL);
> > - if (ret)
> > - return ret;
> > -
> > - /* store bbt magic in page, cause OOB is not protected */
> > - if (nand->bbt_options & NAND_BBT_USE_FLASH)
> > - nand->bbt_options |= NAND_BBT_NO_OOB;
> > -
> > - ret = mtk_nfc_ecc_init(dev, mtd);
> > - if (ret)
> > - return -EINVAL;
> > -
> > - if (nand->options & NAND_BUSWIDTH_16) {
> > - dev_err(dev, "16bits buswidth not supported");
> > - return -EINVAL;
> > - }
> > -
> > - ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
> > - if (ret)
> > - return ret;
> > -
> > - mtk_nfc_set_fdm(&chip->fdm, mtd);
> > - mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
> > -
> > - len = mtd->writesize + mtd->oobsize;
> > - nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > - if (!nfc->buffer)
> > - return -ENOMEM;
> > -
> > - ret = nand_scan_tail(mtd);
> > + ret = nand_scan(mtd, nsels);
> > if (ret)
> > return ret;
> >
>



2018-07-26 06:15:23

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

On Thu, 26 Jul 2018 14:06:41 +0800
xiaolei li <[email protected]> wrote:

> On Sat, 2018-07-21 at 19:10 +0200, Boris Brezillon wrote:
> > On Fri, 20 Jul 2018 17:15:06 +0200
> > Miquel Raynal <[email protected]> wrote:
> >
> > > Two helpers have been added to the core to make ECC-related
> > > configuration between the detection phase and the final NAND scan. Use
> > > these hooks and convert the driver to just use nand_scan() instead of
> > > both nand_scan_ident() and nand_scan_tail().
> > >
> > > Signed-off-by: Miquel Raynal <[email protected]>
> > > ---
> > > drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> > > 1 file changed, 44 insertions(+), 31 deletions(-)
> > >
> > > diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> > > index 7bc6be3f6ec0..967418f945ea 100644
> > > --- a/drivers/mtd/nand/raw/mtk_nand.c
> > > +++ b/drivers/mtd/nand/raw/mtk_nand.c
> > > @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> > > return 0;
> > > }
> > >
> > > +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> > > +{
> > > + struct mtd_info *mtd = nand_to_mtd(chip);
> > > + struct device *dev = mtd->dev.parent;
> > > + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> > > + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> > > + int len;
> > > + int ret;
> > > +
> > > + if (chip->options & NAND_BUSWIDTH_16) {
> > > + dev_err(dev, "16bits buswidth not supported");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + /* store bbt magic in page, cause OOB is not protected */
> > > + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> > > + chip->bbt_options |= NAND_BBT_NO_OOB;
> > > +
> > > + ret = mtk_nfc_ecc_init(dev, mtd);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> > > + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> > > +
> > > + len = mtd->writesize + mtd->oobsize;
> > > + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > > + if (!nfc->buffer)
> > > + return -ENOMEM;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> > > + .attach_chip = mtk_nfc_attach_chip,
> > > +};
> > > +
> > > static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > struct device_node *np)
> > > {
> > > struct mtk_nfc_nand_chip *chip;
> > > struct nand_chip *nand;
> > > struct mtd_info *mtd;
> > > - int nsels, len;
> > > + int nsels;
> > > u32 tmp;
> > > int ret;
> > > int i;
> > > @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > >
> > > nand = &chip->nand;
> > > nand->controller = &nfc->controller;
> > > + nand->controller->ops = &mtk_nfc_controller_ops;
> >
> > Just like for the marvell driver, this assignment should be moved here
> > [1].
> Agree to this.
>
> > Also, it looks like this driver is open-coding
> > nand_controller_init(), probably something we should fix (in a separate
> > patch).
> May I ask if you mean driver should use nand_hw_control_init helper to
> do controller_init?

Well, now it's named nand_controller_init(), but yes, that's what I
meant.

2018-07-26 06:48:27

by xiaolei li

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

On Thu, 2018-07-26 at 08:14 +0200, Boris Brezillon wrote:
> On Thu, 26 Jul 2018 14:06:41 +0800
> xiaolei li <[email protected]> wrote:
>
> > On Sat, 2018-07-21 at 19:10 +0200, Boris Brezillon wrote:
> > > On Fri, 20 Jul 2018 17:15:06 +0200
> > > Miquel Raynal <[email protected]> wrote:
> > >
> > > > Two helpers have been added to the core to make ECC-related
> > > > configuration between the detection phase and the final NAND scan. Use
> > > > these hooks and convert the driver to just use nand_scan() instead of
> > > > both nand_scan_ident() and nand_scan_tail().
> > > >
> > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > ---
> > > > drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> > > > 1 file changed, 44 insertions(+), 31 deletions(-)
> > > >
> > > > diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> > > > index 7bc6be3f6ec0..967418f945ea 100644
> > > > --- a/drivers/mtd/nand/raw/mtk_nand.c
> > > > +++ b/drivers/mtd/nand/raw/mtk_nand.c
> > > > @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> > > > return 0;
> > > > }
> > > >
> > > > +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> > > > +{
> > > > + struct mtd_info *mtd = nand_to_mtd(chip);
> > > > + struct device *dev = mtd->dev.parent;
> > > > + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> > > > + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> > > > + int len;
> > > > + int ret;
> > > > +
> > > > + if (chip->options & NAND_BUSWIDTH_16) {
> > > > + dev_err(dev, "16bits buswidth not supported");
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + /* store bbt magic in page, cause OOB is not protected */
> > > > + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> > > > + chip->bbt_options |= NAND_BBT_NO_OOB;
> > > > +
> > > > + ret = mtk_nfc_ecc_init(dev, mtd);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> > > > + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> > > > +
> > > > + len = mtd->writesize + mtd->oobsize;
> > > > + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > > > + if (!nfc->buffer)
> > > > + return -ENOMEM;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> > > > + .attach_chip = mtk_nfc_attach_chip,
> > > > +};
> > > > +
> > > > static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > > struct device_node *np)
> > > > {
> > > > struct mtk_nfc_nand_chip *chip;
> > > > struct nand_chip *nand;
> > > > struct mtd_info *mtd;
> > > > - int nsels, len;
> > > > + int nsels;
> > > > u32 tmp;
> > > > int ret;
> > > > int i;
> > > > @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > >
> > > > nand = &chip->nand;
> > > > nand->controller = &nfc->controller;
> > > > + nand->controller->ops = &mtk_nfc_controller_ops;
> > >
> > > Just like for the marvell driver, this assignment should be moved here
> > > [1].
> > Agree to this.
> >
>
> > > Also, it looks like this driver is open-coding
> > > nand_controller_init(), probably something we should fix (in a separate
> > > patch).
> > May I ask if you mean driver should use nand_hw_control_init helper to
> > do controller_init?
>
> Well, now it's named nand_controller_init(), but yes, that's what I
> meant.

OK. I will fix it base on this patch series later.
Thanks!



2018-07-26 06:50:53

by Miquel Raynal

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

Hi xiaolei,

xiaolei li <[email protected]> wrote on Thu, 26 Jul 2018 14:46:29
+0800:

> On Thu, 2018-07-26 at 08:14 +0200, Boris Brezillon wrote:
> > On Thu, 26 Jul 2018 14:06:41 +0800
> > xiaolei li <[email protected]> wrote:
> >
> > > On Sat, 2018-07-21 at 19:10 +0200, Boris Brezillon wrote:
> > > > On Fri, 20 Jul 2018 17:15:06 +0200
> > > > Miquel Raynal <[email protected]> wrote:
> > > >
> > > > > Two helpers have been added to the core to make ECC-related
> > > > > configuration between the detection phase and the final NAND scan. Use
> > > > > these hooks and convert the driver to just use nand_scan() instead of
> > > > > both nand_scan_ident() and nand_scan_tail().
> > > > >
> > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > ---
> > > > > drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> > > > > 1 file changed, 44 insertions(+), 31 deletions(-)
> > > > >
> > > > > diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> > > > > index 7bc6be3f6ec0..967418f945ea 100644
> > > > > --- a/drivers/mtd/nand/raw/mtk_nand.c
> > > > > +++ b/drivers/mtd/nand/raw/mtk_nand.c
> > > > > @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> > > > > return 0;
> > > > > }
> > > > >
> > > > > +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> > > > > +{
> > > > > + struct mtd_info *mtd = nand_to_mtd(chip);
> > > > > + struct device *dev = mtd->dev.parent;
> > > > > + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> > > > > + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> > > > > + int len;
> > > > > + int ret;
> > > > > +
> > > > > + if (chip->options & NAND_BUSWIDTH_16) {
> > > > > + dev_err(dev, "16bits buswidth not supported");
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > + /* store bbt magic in page, cause OOB is not protected */
> > > > > + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> > > > > + chip->bbt_options |= NAND_BBT_NO_OOB;
> > > > > +
> > > > > + ret = mtk_nfc_ecc_init(dev, mtd);
> > > > > + if (ret)
> > > > > + return ret;
> > > > > +
> > > > > + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> > > > > + if (ret)
> > > > > + return ret;
> > > > > +
> > > > > + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> > > > > + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> > > > > +
> > > > > + len = mtd->writesize + mtd->oobsize;
> > > > > + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > > > > + if (!nfc->buffer)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> > > > > + .attach_chip = mtk_nfc_attach_chip,
> > > > > +};
> > > > > +
> > > > > static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > > > struct device_node *np)
> > > > > {
> > > > > struct mtk_nfc_nand_chip *chip;
> > > > > struct nand_chip *nand;
> > > > > struct mtd_info *mtd;
> > > > > - int nsels, len;
> > > > > + int nsels;
> > > > > u32 tmp;
> > > > > int ret;
> > > > > int i;
> > > > > @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > > >
> > > > > nand = &chip->nand;
> > > > > nand->controller = &nfc->controller;
> > > > > + nand->controller->ops = &mtk_nfc_controller_ops;
> > > >
> > > > Just like for the marvell driver, this assignment should be moved here
> > > > [1].
> > > Agree to this.
> > >
> >
> > > > Also, it looks like this driver is open-coding
> > > > nand_controller_init(), probably something we should fix (in a separate
> > > > patch).
> > > May I ask if you mean driver should use nand_hw_control_init helper to
> > > do controller_init?
> >
> > Well, now it's named nand_controller_init(), but yes, that's what I
> > meant.
>
> OK. I will fix it base on this patch series later.

Nice!

Then you can just wait for the next -rc1, this series should be
available.

Thanks,
Miquèl

2018-07-26 06:56:39

by xiaolei li

[permalink] [raw]
Subject: Re: [PATCH v4 14/35] mtd: rawnand: mtk: convert driver to nand_scan()

On Thu, 2018-07-26 at 08:49 +0200, Miquel Raynal wrote:
> Hi xiaolei,
>
> xiaolei li <[email protected]> wrote on Thu, 26 Jul 2018 14:46:29
> +0800:
>
> > On Thu, 2018-07-26 at 08:14 +0200, Boris Brezillon wrote:
> > > On Thu, 26 Jul 2018 14:06:41 +0800
> > > xiaolei li <[email protected]> wrote:
> > >
> > > > On Sat, 2018-07-21 at 19:10 +0200, Boris Brezillon wrote:
> > > > > On Fri, 20 Jul 2018 17:15:06 +0200
> > > > > Miquel Raynal <[email protected]> wrote:
> > > > >
> > > > > > Two helpers have been added to the core to make ECC-related
> > > > > > configuration between the detection phase and the final NAND scan. Use
> > > > > > these hooks and convert the driver to just use nand_scan() instead of
> > > > > > both nand_scan_ident() and nand_scan_tail().
> > > > > >
> > > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > > ---
> > > > > > drivers/mtd/nand/raw/mtk_nand.c | 75 ++++++++++++++++++++++++-----------------
> > > > > > 1 file changed, 44 insertions(+), 31 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
> > > > > > index 7bc6be3f6ec0..967418f945ea 100644
> > > > > > --- a/drivers/mtd/nand/raw/mtk_nand.c
> > > > > > +++ b/drivers/mtd/nand/raw/mtk_nand.c
> > > > > > @@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
> > > > > > return 0;
> > > > > > }
> > > > > >
> > > > > > +static int mtk_nfc_attach_chip(struct nand_chip *chip)
> > > > > > +{
> > > > > > + struct mtd_info *mtd = nand_to_mtd(chip);
> > > > > > + struct device *dev = mtd->dev.parent;
> > > > > > + struct mtk_nfc *nfc = nand_get_controller_data(chip);
> > > > > > + struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
> > > > > > + int len;
> > > > > > + int ret;
> > > > > > +
> > > > > > + if (chip->options & NAND_BUSWIDTH_16) {
> > > > > > + dev_err(dev, "16bits buswidth not supported");
> > > > > > + return -EINVAL;
> > > > > > + }
> > > > > > +
> > > > > > + /* store bbt magic in page, cause OOB is not protected */
> > > > > > + if (chip->bbt_options & NAND_BBT_USE_FLASH)
> > > > > > + chip->bbt_options |= NAND_BBT_NO_OOB;
> > > > > > +
> > > > > > + ret = mtk_nfc_ecc_init(dev, mtd);
> > > > > > + if (ret)
> > > > > > + return ret;
> > > > > > +
> > > > > > + ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
> > > > > > + if (ret)
> > > > > > + return ret;
> > > > > > +
> > > > > > + mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
> > > > > > + mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
> > > > > > +
> > > > > > + len = mtd->writesize + mtd->oobsize;
> > > > > > + nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
> > > > > > + if (!nfc->buffer)
> > > > > > + return -ENOMEM;
> > > > > > +
> > > > > > + return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static const struct nand_controller_ops mtk_nfc_controller_ops = {
> > > > > > + .attach_chip = mtk_nfc_attach_chip,
> > > > > > +};
> > > > > > +
> > > > > > static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > > > > struct device_node *np)
> > > > > > {
> > > > > > struct mtk_nfc_nand_chip *chip;
> > > > > > struct nand_chip *nand;
> > > > > > struct mtd_info *mtd;
> > > > > > - int nsels, len;
> > > > > > + int nsels;
> > > > > > u32 tmp;
> > > > > > int ret;
> > > > > > int i;
> > > > > > @@ -1287,6 +1328,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
> > > > > >
> > > > > > nand = &chip->nand;
> > > > > > nand->controller = &nfc->controller;
> > > > > > + nand->controller->ops = &mtk_nfc_controller_ops;
> > > > >
> > > > > Just like for the marvell driver, this assignment should be moved here
> > > > > [1].
> > > > Agree to this.
> > > >
> > >
> > > > > Also, it looks like this driver is open-coding
> > > > > nand_controller_init(), probably something we should fix (in a separate
> > > > > patch).
> > > > May I ask if you mean driver should use nand_hw_control_init helper to
> > > > do controller_init?
> > >
> > > Well, now it's named nand_controller_init(), but yes, that's what I
> > > meant.
> >
> > OK. I will fix it base on this patch series later.
>
> Nice!
>
> Then you can just wait for the next -rc1, this series should be
> available.
>
OK. Thanks for your improvement!

Assuming ->controller->ops assignment will be fixed,

Acked-by: Xiaolei Li <[email protected]>

> Thanks,
> Miquèl



2018-07-26 19:10:31

by Boris Brezillon

[permalink] [raw]
Subject: Re: [PATCH v4 27/35] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()

On Sun, 22 Jul 2018 08:44:32 +0200
Boris Brezillon <[email protected]> wrote:

> On Fri, 20 Jul 2018 17:15:19 +0200
> Miquel Raynal <[email protected]> wrote:
>
> > Two helpers have been added to the core to make ECC-related
> > configuration between the detection phase and the final NAND scan. Use
> > these hooks and convert the driver to just use nand_scan_with_ids()
> > (alternative to nand_scan() for passing a flash IDs table) instead of
> > both nand_scan_ident() and nand_scan_tail().
> >
> > Signed-off-by: Miquel Raynal <[email protected]>
>
> Reviewed-by: Boris Brezillon <[email protected]>
>
> > ---
> > drivers/mtd/nand/raw/sm_common.c | 39 +++++++++++++++++++++++++--------------
> > 1 file changed, 25 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
> > index 7f5044a79f01..d05e3f976a5e 100644
> > --- a/drivers/mtd/nand/raw/sm_common.c
> > +++ b/drivers/mtd/nand/raw/sm_common.c
> > @@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
> > {NULL}
> > };
> >
> > -int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > +static int sm_attach_chip(struct nand_chip *chip)
> > {
> > - struct nand_chip *chip = mtd_to_nand(mtd);
> > - int ret;
> > -
> > - chip->options |= NAND_SKIP_BBTSCAN;
> > -
> > - /* Scan for card properties */
> > - ret = nand_scan_ident(mtd, 1, smartmedia ?
> > - nand_smartmedia_flash_ids : nand_xd_flash_ids);
> > -
> > - if (ret)
> > - return ret;
> > + struct mtd_info *mtd = nand_to_mtd(chip);
> >
> > /* Bad block marker position */
> > chip->badblockpos = 0x05;
> > @@ -187,12 +177,33 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > else
> > return -ENODEV;
> >
> > - ret = nand_scan_tail(mtd);
> > + return 0;
> > +}
> >
> > +static const struct nand_controller_ops sm_controller_ops = {
> > + .attach_chip = sm_attach_chip,
> > +};
> > +
> > +int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > +{
> > + struct nand_chip *chip = mtd_to_nand(mtd);
> > + struct nand_flash_dev *flash_ids;
> > + int ret;
> > +
> > + chip->options |= NAND_SKIP_BBTSCAN;
> > +
> > + /* Scan for card properties */
> > + chip->dummy_controller.ops = &sm_controller_ops;
> > + flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
> > + ret = nand_scan_with_ids(mtd, 1, flash_ids);
> > if (ret)
> > return ret;
> >
> > - return mtd_device_register(mtd, NULL, 0);
> > + ret = mtd_device_register(mtd, NULL, 0);
> > + if (ret)
> > + nand_release(mtd);

Didn't notice that while reviewing, but it would have been better to
use nand_cleanup() and do this change separately.

> > +
> > + return ret;
> > }
> > EXPORT_SYMBOL_GPL(sm_register_device);
> >
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/


2018-07-26 23:15:12

by Miquel Raynal

[permalink] [raw]
Subject: Re: [PATCH v4 27/35] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()

Hi Boris,

Boris Brezillon <[email protected]> wrote on Thu, 26 Jul 2018
21:06:55 +0200:

> On Sun, 22 Jul 2018 08:44:32 +0200
> Boris Brezillon <[email protected]> wrote:
>
> > On Fri, 20 Jul 2018 17:15:19 +0200
> > Miquel Raynal <[email protected]> wrote:
> >
> > > Two helpers have been added to the core to make ECC-related
> > > configuration between the detection phase and the final NAND scan. Use
> > > these hooks and convert the driver to just use nand_scan_with_ids()
> > > (alternative to nand_scan() for passing a flash IDs table) instead of
> > > both nand_scan_ident() and nand_scan_tail().
> > >
> > > Signed-off-by: Miquel Raynal <[email protected]>
> >
> > Reviewed-by: Boris Brezillon <[email protected]>
> >
> > > ---
> > > drivers/mtd/nand/raw/sm_common.c | 39 +++++++++++++++++++++++++--------------
> > > 1 file changed, 25 insertions(+), 14 deletions(-)
> > >
> > > diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
> > > index 7f5044a79f01..d05e3f976a5e 100644
> > > --- a/drivers/mtd/nand/raw/sm_common.c
> > > +++ b/drivers/mtd/nand/raw/sm_common.c
> > > @@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
> > > {NULL}
> > > };
> > >
> > > -int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > > +static int sm_attach_chip(struct nand_chip *chip)
> > > {
> > > - struct nand_chip *chip = mtd_to_nand(mtd);
> > > - int ret;
> > > -
> > > - chip->options |= NAND_SKIP_BBTSCAN;
> > > -
> > > - /* Scan for card properties */
> > > - ret = nand_scan_ident(mtd, 1, smartmedia ?
> > > - nand_smartmedia_flash_ids : nand_xd_flash_ids);
> > > -
> > > - if (ret)
> > > - return ret;
> > > + struct mtd_info *mtd = nand_to_mtd(chip);
> > >
> > > /* Bad block marker position */
> > > chip->badblockpos = 0x05;
> > > @@ -187,12 +177,33 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > > else
> > > return -ENODEV;
> > >
> > > - ret = nand_scan_tail(mtd);
> > > + return 0;
> > > +}
> > >
> > > +static const struct nand_controller_ops sm_controller_ops = {
> > > + .attach_chip = sm_attach_chip,
> > > +};
> > > +
> > > +int sm_register_device(struct mtd_info *mtd, int smartmedia)
> > > +{
> > > + struct nand_chip *chip = mtd_to_nand(mtd);
> > > + struct nand_flash_dev *flash_ids;
> > > + int ret;
> > > +
> > > + chip->options |= NAND_SKIP_BBTSCAN;
> > > +
> > > + /* Scan for card properties */
> > > + chip->dummy_controller.ops = &sm_controller_ops;
> > > + flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
> > > + ret = nand_scan_with_ids(mtd, 1, flash_ids);
> > > if (ret)
> > > return ret;
> > >
> > > - return mtd_device_register(mtd, NULL, 0);
> > > + ret = mtd_device_register(mtd, NULL, 0);
> > > + if (ret)
> > > + nand_release(mtd);
>
> Didn't notice that while reviewing, but it would have been better to
> use nand_cleanup() and do this change separately.

Indeed, will fix it.

Miquèl

2018-07-26 23:35:26

by Miquel Raynal

[permalink] [raw]
Subject: Re: [PATCH v4 00/35] Allow dynamic allocations during NAND chip identification phase


Miquel Raynal <[email protected]> wrote on Fri, 20 Jul 2018
17:14:52 +0200:

> Hello,
>
> This series make a quite deep change in the NAND framework. Until now,
> the NAND chip identification phase could be done in two manners from the
> controller driver perspective:
>
> 1/ Call nand_scan()
>
> or
>
> 1/ Call nand_scan_ident()
> 2/ Do some controller-dependent configuration
> 3/ Call nand_scan_tail().
>
> The fact that the identifaction could be split in two operations
> involved that in the NAND framework, it was not possible to do any
> dynamic allocation without risking a memory leak. What if the core
> allocates a structure, then the driver between nand_scan_ident() and
> nand_scan_tail() decides it cannot handle the chip and errors out?
> The structure allocated by the core is lost: it is a memory leak. One
> solution could have been to add a nand_scan_ident_cleanup() function,
> but that would mean patching all the drivers anyway to make them call
> this function when something fails between nand_scan_ident() and
> nand_scan_tail().
>
> To avoid this situation, we migrate all drivers to use nand_scan() in
> conjuction with the recently added hooks ->attach_chip() and
> ->detach_chip() that are part of the nand_controller structure
> operations. Drivers that need to tweak their configuration after
> nand_scan_ident() should implement it. Any dynamically allocated space
> in ->attach_chip() must be freed in the second hook: ->detach_chip().
>
> The ->detach_chip() does not have to be called upon error in the
> controller driver probe function. The nand_cleanup() helper already
> exists for that and will do the call if needed. Of course, this helper
> must be called on error after a successful nand_scan(), just like
> before.
>
> Once all drivers not using nand_scan() are migrated, nand_scan_ident()
> and nand_scan_tail() are unexported and only available internally.
>
> A previous work [1] removed the ONFI/JEDEC parameter pages and instead
> allocated a nand_parameters structure in nand_chip, embedding both
> generic entries and ONFI-related ones. The deal was, once dynamic
> allocation possible, allocate in nand_scan_ident() the ONFI strcuture
> only if actually needed. This is done in the last patches.
>
> This series applies on top of nand/next.
>
> Thank you,
> Miquèl
>
> [1] http://lists.infradead.org/pipermail/linux-mtd/2018-March/079456.html
>
> Changes since v3:
> =================
> * Constified all the nand_controller_ops structure definitions.
> * Fixed a build issue in fsl_elbc.
> * Added a patch in the core to prevent executing nand_scan_ident if
> maxchips is NULL.
> * Fixed the regression around the model name.
> * Used kstrdup to allocate the model.
> * The migration from char model[] to const char *model is done in a
> separate patch.
>
> Changes since v2:
> =================
> * Rebased on top of nand/next.
> * Adapted all drivers to declare statically a nand_controller_ops
> structure and assign it in the probe().
> * Added the migration of the tegra_nand.c driver.
> * Moved brcmnand controller ops affectation in the probe().
>
> Changes since v1:
> =================
> * Rebased on top of nand/next.
> * Light rewording of the cover letter about the possibility to have a
> nand_scan_ident_cleanup() function (just as example of how this series
> could have been done differently).
> * Changed the hooks to reside in the nand_hw_ctrl structure instead of
> being part of nand_ecc_ctrl as these hooks are more
> controller-related.
>
>
> Miquel Raynal (35):
> mtd: rawnand: brcmnand: convert driver to nand_scan()
> mtd: rawnand: cafe: convert driver to nand_scan()
> mtd: rawnand: davinci: convert driver to nand_scan()
> mtd: rawnand: denali: convert to nand_scan()
> mtd: rawnand: fsl_elbc: convert driver to nand_scan()
> mtd: rawnand: fsl_ifc: convert driver to nand_scan()
> mtd: rawnand: fsmc: convert driver to nand_scan()
> mtd: rawnand: gpmi: convert driver to nand_scan()
> mtd: rawnand: hisi504: convert driver to nand_scan()
> mtd: rawnand: jz4780: convert driver to nand_scan()
> mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()
> mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()
> mtd: rawnand: marvell: convert driver to nand_scan()
> mtd: rawnand: mtk: convert driver to nand_scan()
> mtd: rawnand: mxc: convert driver to nand_scan()
> mtd: rawnand: nandsim: convert driver to nand_scan()
> mtd: rawnand: omap2: convert driver to nand_scan()
> mtd: rawnand: s3c2410: convert driver to nand_scan()
> mtd: rawnand: sh_flctl: move all NAND chip related setup in one
> function
> mtd: rawnand: sh_flctl: convert driver to nand_scan()
> mtd: rawnand: sunxi: convert driver to nand_scan()
> mtd: rawnand: tango: convert driver to nand_scan()
> mtd: rawnand: txx9ndfmc: rename nand controller internal structure
> mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
> mtd: rawnand: vf610: convert driver to nand_scan()
> mtd: rawnand: atmel: convert driver to nand_scan()
> mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()
> mtd: rawnand: allow exiting immediately nand_scan_ident()
> mtd: rawnand: docg4: convert driver to nand_scan()
> mtd: rawnand: qcom: convert driver to nand_scan()
> mtd: rawnand: jz4740: convert driver to nand_scan()
> mtd: rawnand: tegra: convert driver to nand_scan()
> mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
> mtd: rawnand: allocate model parameter dynamically
> mtd: rawnand: allocate dynamically ONFI parameters during detection
>
> drivers/mtd/nand/raw/atmel/nand-controller.c | 83 ++---
> drivers/mtd/nand/raw/brcmnand/brcmnand.c | 47 ++-
> drivers/mtd/nand/raw/cafe_nand.c | 130 ++++---
> drivers/mtd/nand/raw/davinci_nand.c | 195 +++++-----
> drivers/mtd/nand/raw/denali.c | 138 +++----
> drivers/mtd/nand/raw/docg4.c | 55 +--
> drivers/mtd/nand/raw/fsl_elbc_nand.c | 19 +-
> drivers/mtd/nand/raw/fsl_ifc_nand.c | 19 +-
> drivers/mtd/nand/raw/fsmc_nand.c | 148 ++++----
> drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 56 +--
> drivers/mtd/nand/raw/hisi504_nand.c | 78 ++--
> drivers/mtd/nand/raw/jz4740_nand.c | 46 ++-
> drivers/mtd/nand/raw/jz4780_nand.c | 34 +-
> drivers/mtd/nand/raw/lpc32xx_mlc.c | 109 +++---
> drivers/mtd/nand/raw/lpc32xx_slc.c | 77 ++--
> drivers/mtd/nand/raw/marvell_nand.c | 205 ++++++-----
> drivers/mtd/nand/raw/mtk_nand.c | 75 ++--
> drivers/mtd/nand/raw/mxc_nand.c | 136 +++----
> drivers/mtd/nand/raw/nand_base.c | 132 +++++--
> drivers/mtd/nand/raw/nand_micron.c | 6 +-
> drivers/mtd/nand/raw/nand_timings.c | 12 +-
> drivers/mtd/nand/raw/nandsim.c | 82 +++--
> drivers/mtd/nand/raw/omap2.c | 521 +++++++++++++--------------
> drivers/mtd/nand/raw/qcom_nandc.c | 71 ++--
> drivers/mtd/nand/raw/s3c2410.c | 30 +-
> drivers/mtd/nand/raw/sh_flctl.c | 57 ++-
> drivers/mtd/nand/raw/sm_common.c | 39 +-
> drivers/mtd/nand/raw/sunxi_nand.c | 43 +--
> drivers/mtd/nand/raw/tango_nand.c | 40 +-
> drivers/mtd/nand/raw/tegra_nand.c | 162 +++++----
> drivers/mtd/nand/raw/txx9ndfmc.c | 35 +-
> drivers/mtd/nand/raw/vf610_nfc.c | 127 +++----
> include/linux/mtd/rawnand.h | 17 +-
> include/linux/mtd/sh_flctl.h | 1 +
> 34 files changed, 1612 insertions(+), 1413 deletions(-)
>

After doing the requested modifications applied to nand/next:
- 3-10, 12-16, 18-22, 25, 27, 30 from v4
- then the rest from v5.

Thanks,
Miquèl