linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase
@ 2018-07-19 22:59 Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
                   ` (32 more replies)
  0 siblings, 33 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 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 (33):
  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: 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 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          | 206 ++++++-----
 drivers/mtd/nand/raw/mtk_nand.c              |  75 ++--
 drivers/mtd/nand/raw/mxc_nand.c              | 136 +++----
 drivers/mtd/nand/raw/nand_base.c             | 121 +++++--
 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, 1603 insertions(+), 1412 deletions(-)

-- 
2.14.1


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 23:17   ` Boris Brezillon
  2018-07-19 22:59 ` [PATCH v3 02/33] mtd: rawnand: cafe: " Miquel Raynal
                   ` (31 subsequent siblings)
  32 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..4a69c13c83f4 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 02/33] mtd: rawnand: cafe: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 03/33] mtd: rawnand: davinci: " Miquel Raynal
                   ` (30 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..fe7511291b1a 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 03/33] mtd: rawnand: davinci: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 02/33] mtd: rawnand: cafe: " Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 04/33] mtd: rawnand: denali: convert " Miquel Raynal
                   ` (29 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..ae8b07541519 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 04/33] mtd: rawnand: denali: convert to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (2 preceding siblings ...)
  2018-07-19 22:59 ` [PATCH v3 03/33] mtd: rawnand: davinci: " Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 05/33] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
                   ` (28 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..8325e5231abc 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 05/33] mtd: rawnand: fsl_elbc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (3 preceding siblings ...)
  2018-07-19 22:59 ` [PATCH v3 04/33] mtd: rawnand: denali: convert " Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 22:59 ` [PATCH v3 06/33] mtd: rawnand: fsl_ifc: " Miquel Raynal
                   ` (27 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..11dfe9002454 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 06/33] mtd: rawnand: fsl_ifc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (4 preceding siblings ...)
  2018-07-19 22:59 ` [PATCH v3 05/33] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
@ 2018-07-19 22:59 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 07/33] mtd: rawnand: fsmc: " Miquel Raynal
                   ` (26 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 22:59 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..4434a0e8ba48 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 07/33] mtd: rawnand: fsmc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (5 preceding siblings ...)
  2018-07-19 22:59 ` [PATCH v3 06/33] mtd: rawnand: fsl_ifc: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 08/33] mtd: rawnand: gpmi: " Miquel Raynal
                   ` (25 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..020495e6cd55 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 08/33] mtd: rawnand: gpmi: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (6 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 07/33] mtd: rawnand: fsmc: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 09/33] mtd: rawnand: hisi504: " Miquel Raynal
                   ` (24 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..5da2fd6e37cc 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 09/33] mtd: rawnand: hisi504: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (7 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 08/33] mtd: rawnand: gpmi: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 10/33] mtd: rawnand: jz4780: " Miquel Raynal
                   ` (23 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..34867e91df84 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 10/33] mtd: rawnand: jz4780: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (8 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 09/33] mtd: rawnand: hisi504: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 11/33] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
                   ` (22 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
Acked-by: Harvey Hunt <harveyhuntnexus@gmail.com>
---
 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..aca4214a6e18 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 11/33] mtd: rawnand: lpc32xx_mlc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (9 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 10/33] mtd: rawnand: jz4780: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 12/33] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
                   ` (21 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..099f1dd308c6 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 12/33] mtd: rawnand: lpc32xx_slc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (10 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 11/33] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 13/33] mtd: rawnand: marvell: " Miquel Raynal
                   ` (20 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..41c135567e8c 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 13/33] mtd: rawnand: marvell: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (11 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 12/33] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 14/33] mtd: rawnand: mtk: " Miquel Raynal
                   ` (19 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/raw/marvell_nand.c | 206 +++++++++++++++++++-----------------
 1 file changed, 109 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index bd5f9a4b7b16..1a4aeb08352a 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -319,6 +319,7 @@ struct marvell_nfc_caps {
  */
 struct marvell_nfc {
 	struct nand_controller controller;
+	struct nand_controller_ops ops;
 	struct device *dev;
 	void __iomem *regs;
 	struct clk *core_clk;
@@ -2290,6 +2291,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 +2538,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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 14/33] mtd: rawnand: mtk: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (12 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 13/33] mtd: rawnand: marvell: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 15/33] mtd: rawnand: mxc: " Miquel Raynal
                   ` (18 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..4376adc433a6 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 15/33] mtd: rawnand: mxc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (13 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 14/33] mtd: rawnand: mtk: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 16/33] mtd: rawnand: nandsim: " Miquel Raynal
                   ` (17 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..62823fe30d80 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 16/33] mtd: rawnand: nandsim: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (14 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 15/33] mtd: rawnand: mxc: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 17/33] mtd: rawnand: omap2: " Miquel Raynal
                   ` (16 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..62162b4f223c 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 17/33] mtd: rawnand: omap2: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (15 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 16/33] mtd: rawnand: nandsim: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 18/33] mtd: rawnand: s3c2410: " Miquel Raynal
                   ` (15 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..8ce6546b58ec 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 18/33] mtd: rawnand: s3c2410: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (16 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 17/33] mtd: rawnand: omap2: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 19/33] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
                   ` (14 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..9ce505fa02e0 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 19/33] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (17 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 18/33] mtd: rawnand: s3c2410: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 20/33] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
                   ` (13 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 20/33] mtd: rawnand: sh_flctl: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (18 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 19/33] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 21/33] mtd: rawnand: sunxi: " Miquel Raynal
                   ` (12 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..aa9fd92818d9 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 21/33] mtd: rawnand: sunxi: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (19 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 20/33] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 22/33] mtd: rawnand: tango: " Miquel Raynal
                   ` (11 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..de2bf752142b 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 22/33] mtd: rawnand: tango: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (20 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 21/33] mtd: rawnand: sunxi: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 23/33] mtd: rawnand: txx9ndfmc: rename nand controller internal structure Miquel Raynal
                   ` (10 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..d06d1aa918ed 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 23/33] mtd: rawnand: txx9ndfmc: rename nand controller internal structure
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (21 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 22/33] mtd: rawnand: tango: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 24/33] mtd: rawnand: txx9ndfmc: convert driver to nand_scan() Miquel Raynal
                   ` (9 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 24/33] mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (22 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 23/33] mtd: rawnand: txx9ndfmc: rename nand controller internal structure Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 25/33] mtd: rawnand: vf610: " Miquel Raynal
                   ` (8 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..4b2d9418d14a 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 25/33] mtd: rawnand: vf610: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (23 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 24/33] mtd: rawnand: txx9ndfmc: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 26/33] mtd: rawnand: atmel: " Miquel Raynal
                   ` (7 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..61c5e353ff93 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 26/33] mtd: rawnand: atmel: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (24 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 25/33] mtd: rawnand: vf610: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 27/33] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
                   ` (6 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..35cac010e39a 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 27/33] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (25 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 26/33] mtd: rawnand: atmel: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
                   ` (5 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..92e04acfea3b 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (26 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 27/33] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:27   ` Boris Brezillon
  2018-07-19 23:00 ` [PATCH v3 29/33] mtd: rawnand: qcom: " Miquel Raynal
                   ` (4 subsequent siblings)
  32 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..2f6fcd4efab2 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 29/33] mtd: rawnand: qcom: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (27 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 30/33] mtd: rawnand: jz4740: " Miquel Raynal
                   ` (3 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..aa66e51afdb8 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 30/33] mtd: rawnand: jz4740: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (28 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 29/33] mtd: rawnand: qcom: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 31/33] mtd: rawnand: tegra: " Miquel Raynal
                   ` (2 subsequent siblings)
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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..72f5783a7da8 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 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 31/33] mtd: rawnand: tegra: convert driver to nand_scan()
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (29 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 30/33] mtd: rawnand: jz4740: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
  2018-07-19 23:00 ` [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
  32 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (30 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 31/33] mtd: rawnand: tegra: " Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:45   ` Boris Brezillon
  2018-07-19 23:00 ` [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
  32 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/raw/nand_base.c | 60 +++++++++++++++++++++++++++++++---------
 include/linux/mtd/rawnand.h      | 11 ++------
 2 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index dea41fa25be1..dfee2556a8a8 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -5151,6 +5151,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	struct nand_onfi_params *p;
+	char *model;
 	char id[4];
 	int i, ret, val;
 
@@ -5225,8 +5226,15 @@ 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);
+	model = kmemdup(p->model, sizeof(p->model), GFP_KERNEL);
+	if (!model) {
+		ret = -ENOMEM;
+		goto free_onfi_param_page;
+	}
+
+	chip->parameters.model = model;
+	if (!mtd->name)
+		mtd->name = chip->parameters.model;
 
 	mtd->writesize = le32_to_cpu(p->byte_per_page);
 
@@ -5306,6 +5314,7 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
 	struct nand_jedec_params *p;
 	struct jedec_ecc_info *ecc;
 	int jedec_version = 0;
+	char *model;
 	char id[5];
 	int i, val, ret;
 
@@ -5356,8 +5365,16 @@ 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);
+	model = kzalloc(sizeof(p->model), GFP_KERNEL);
+	if (!p) {
+		ret = -ENOMEM;
+		goto free_jedec_param_page;
+	}
+
+	strncpy(model, p->model, sizeof(model) - 1);
+	chip->parameters.model = model;
+	if (!mtd->name)
+		mtd->name = chip->parameters.model;
 
 	mtd->writesize = le32_to_cpu(p->byte_per_page);
 
@@ -5924,7 +5941,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
  * @table: alternative NAND ID table
@@ -5932,9 +5949,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);
@@ -6008,7 +6029,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 
 	return 0;
 }
-EXPORT_SYMBOL(nand_scan_ident);
+
+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)
 {
@@ -6385,14 +6410,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;
@@ -6716,7 +6741,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 
 	return ret;
 }
-EXPORT_SYMBOL(nand_scan_tail);
 
 static int nand_attach(struct nand_chip *chip)
 {
@@ -6754,11 +6778,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;
 }
@@ -6790,6 +6821,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 a20c78e25878..5723d940a47d 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 */
@@ -487,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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection
  2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
                   ` (31 preceding siblings ...)
  2018-07-19 23:00 ` [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
@ 2018-07-19 23:00 ` Miquel Raynal
  2018-07-19 23:42   ` Boris Brezillon
  32 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-07-19 23:00 UTC (permalink / raw)
  To: Wenyou Yang, Josh Wu, Tudor Ambarus, Boris Brezillon,
	Miquel Raynal, Richard Weinberger, David Woodhouse, Brian Norris,
	Marek Vasut, Nicolas Ferre, Alexandre Belloni, Kamal Dasu,
	Masahiro Yamada, Han Xu, Harvey Hunt, Vladimir Zapolskiy,
	Sylvain Lemieux, Xiaolei Li, Matthias Brugger, Maxime Ripard,
	Chen-Yu Tsai, Marc Gonzalez, Mans Rullgard, Stefan Agner
  Cc: linux-mtd, linux-arm-kernel, linux-kernel,
	bcm-kernel-feedback-list, linux-mediatek

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 <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/raw/nand_base.c    | 61 ++++++++++++++++++++++---------------
 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, 48 insertions(+), 37 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index dfee2556a8a8..4dc248769abb 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 *model;
 	char id[4];
 	int i, ret, val;
@@ -5207,21 +5209,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));
@@ -5262,7 +5262,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)) {
 
 		/*
@@ -5289,19 +5289,32 @@ 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(model);
 free_onfi_param_page:
 	kfree(p);
+
 	return ret;
 }
 
@@ -5562,9 +5575,7 @@ static bool find_full_id_nand(struct nand_chip *chip,
 		chip->ecc_step_ds = NAND_ECC_STEP(type);
 		chip->onfi_timing_mode_default =
 					type->onfi_timing_mode_default;
-
-		strncpy(chip->parameters.model, type->name,
-			sizeof(chip->parameters.model) - 1);
+		chip->parameters.model = type->name;
 
 		return true;
 	}
@@ -5703,7 +5714,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);
@@ -5723,8 +5733,7 @@ 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 = type->name;
 
 	chip->chipsize = (uint64_t)type->chipsize << 20;
 
@@ -6033,6 +6042,8 @@ 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan()
  2018-07-19 22:59 ` [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 23:17   ` Boris Brezillon
  2018-07-20  7:12     ` Miquel Raynal
  0 siblings, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2018-07-19 23:17 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

On Fri, 20 Jul 2018 00:59:54 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> +
> +static struct nand_controller_ops brcmnand_controller_ops = {

static const ...

The same comment applies to all patches of this series.

> +	.attach_chip = brcmnand_attach_chip,
> +};


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan()
  2018-07-19 23:00 ` [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
@ 2018-07-19 23:27   ` Boris Brezillon
  2018-07-20  7:17     ` Miquel Raynal
  0 siblings, 1 reply; 41+ messages in thread
From: Boris Brezillon @ 2018-07-19 23:27 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

On Fri, 20 Jul 2018 01:00:21 +0200
Miquel Raynal <miquel.raynal@bootlin.com> 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 <miquel.raynal@bootlin.com>
> ---
>  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..2f6fcd4efab2 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 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;

Hm, not sure this works. The driver only calls nand_scan_tail(), but
you replace that by a call to nand_scan(), which will call both
nand_scan_ident() and nand_scan_tail(), and I'm pretty sure
nand_scan_ident() will fail here.

>  
> @@ -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);


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection
  2018-07-19 23:00 ` [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
@ 2018-07-19 23:42   ` Boris Brezillon
  0 siblings, 0 replies; 41+ messages in thread
From: Boris Brezillon @ 2018-07-19 23:42 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

On Fri, 20 Jul 2018 01:00:26 +0200
Miquel Raynal <miquel.raynal@bootlin.com> 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 <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/raw/nand_base.c    | 61 ++++++++++++++++++++++---------------
>  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, 48 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index dfee2556a8a8..4dc248769abb 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 *model;
>  	char id[4];
>  	int i, ret, val;
> @@ -5207,21 +5209,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));
> @@ -5262,7 +5262,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)) {
>  
>  		/*
> @@ -5289,19 +5289,32 @@ 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(model);
>  free_onfi_param_page:
>  	kfree(p);
> +
>  	return ret;
>  }
>  
> @@ -5562,9 +5575,7 @@ static bool find_full_id_nand(struct nand_chip *chip,
>  		chip->ecc_step_ds = NAND_ECC_STEP(type);
>  		chip->onfi_timing_mode_default =
>  					type->onfi_timing_mode_default;
> -
> -		strncpy(chip->parameters.model, type->name,
> -			sizeof(chip->parameters.model) - 1);
> +		chip->parameters.model = type->name;
>  
>  		return true;
>  	}
> @@ -5703,7 +5714,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);
> @@ -5723,8 +5733,7 @@ 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);

Okay, so you have regression in patch 32, because
chip->parameters.model has been turned into a const char *, but you
keep copying things into this pointer without allocating the buffer
before.

> +	chip->parameters.model = type->name;

Uh, that's wrong. You free chip->parameters.model in the cleanup, but
you do not allocate it here. You should use kstrdup(type->name) here.

>  
>  	chip->chipsize = (uint64_t)type->chipsize << 20;
>  
> @@ -6033,6 +6042,8 @@ 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,


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
  2018-07-19 23:00 ` [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
@ 2018-07-19 23:45   ` Boris Brezillon
  0 siblings, 0 replies; 41+ messages in thread
From: Boris Brezillon @ 2018-07-19 23:45 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

On Fri, 20 Jul 2018 01:00:25 +0200
Miquel Raynal <miquel.raynal@bootlin.com> 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.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/raw/nand_base.c | 60 +++++++++++++++++++++++++++++++---------
>  include/linux/mtd/rawnand.h      | 11 ++------
>  2 files changed, 50 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index dea41fa25be1..dfee2556a8a8 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -5151,6 +5151,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
>  	struct nand_onfi_params *p;
> +	char *model;
>  	char id[4];
>  	int i, ret, val;
>  
> @@ -5225,8 +5226,15 @@ 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);
> +	model = kmemdup(p->model, sizeof(p->model), GFP_KERNEL);
> +	if (!model) {
> +		ret = -ENOMEM;
> +		goto free_onfi_param_page;
> +	}
> +
> +	chip->parameters.model = model;
> +	if (!mtd->name)
> +		mtd->name = chip->parameters.model;
>  
>  	mtd->writesize = le32_to_cpu(p->byte_per_page);
>  
> @@ -5306,6 +5314,7 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
>  	struct nand_jedec_params *p;
>  	struct jedec_ecc_info *ecc;
>  	int jedec_version = 0;
> +	char *model;
>  	char id[5];
>  	int i, val, ret;
>  
> @@ -5356,8 +5365,16 @@ 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);
> +	model = kzalloc(sizeof(p->model), GFP_KERNEL);
> +	if (!p) {
> +		ret = -ENOMEM;
> +		goto free_jedec_param_page;
> +	}
> +
> +	strncpy(model, p->model, sizeof(model) - 1);
> +	chip->parameters.model = model;
> +	if (!mtd->name)
> +		mtd->name = chip->parameters.model;

All changes related to the the char model[] -> const char *mode
transition should be done in a separate commit. Plus, as pointed in
patch 33, you have a regression here.

>  
>  	mtd->writesize = le32_to_cpu(p->byte_per_page);
>  
> @@ -5924,7 +5941,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
>   * @table: alternative NAND ID table
> @@ -5932,9 +5949,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);
> @@ -6008,7 +6029,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(nand_scan_ident);
> +
> +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)
>  {
> @@ -6385,14 +6410,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;
> @@ -6716,7 +6741,6 @@ int nand_scan_tail(struct mtd_info *mtd)
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL(nand_scan_tail);
>  
>  static int nand_attach(struct nand_chip *chip)
>  {
> @@ -6754,11 +6778,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;
>  }
> @@ -6790,6 +6821,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 a20c78e25878..5723d940a47d 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 */
> @@ -487,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);


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan()
  2018-07-19 23:17   ` Boris Brezillon
@ 2018-07-20  7:12     ` Miquel Raynal
  0 siblings, 0 replies; 41+ messages in thread
From: Miquel Raynal @ 2018-07-20  7:12 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

Hi Boris,

Boris Brezillon <boris.brezillon@bootlin.com> wrote on Fri, 20 Jul 2018
01:17:19 +0200:

> On Fri, 20 Jul 2018 00:59:54 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > +
> > +static struct nand_controller_ops brcmnand_controller_ops = {  
> 
> static const ...

Mmmh right, I'll constify every controller_ops definition.

> 
> The same comment applies to all patches of this series.
> 
> > +	.attach_chip = brcmnand_attach_chip,
> > +};  
> 


Miquèl

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan()
  2018-07-19 23:27   ` Boris Brezillon
@ 2018-07-20  7:17     ` Miquel Raynal
  2018-07-20  7:35       ` Boris Brezillon
  0 siblings, 1 reply; 41+ messages in thread
From: Miquel Raynal @ 2018-07-20  7:17 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

Hi Boris,

Boris Brezillon <boris.brezillon@bootlin.com> wrote on Fri, 20 Jul 2018
01:27:32 +0200:

> On Fri, 20 Jul 2018 01:00:21 +0200
> Miquel Raynal <miquel.raynal@bootlin.com> 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 <miquel.raynal@bootlin.com>
> > ---
> >  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..2f6fcd4efab2 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 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;  
> 
> Hm, not sure this works. The driver only calls nand_scan_tail(), but
> you replace that by a call to nand_scan(), which will call both
> nand_scan_ident() and nand_scan_tail(), and I'm pretty sure
> nand_scan_ident() will fail here.

I know docg4 is a bit specific and could maybe be moved out of the raw/
subdirectory. But in the meantime I don't want to block the series for
this. The better I can propose right now (open to other ideas as
well) would be to return 0 in nand_scan_ident() if the maxchip parameter
is 0 which is the case only in this driver AFAIS.

Miquèl

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan()
  2018-07-20  7:17     ` Miquel Raynal
@ 2018-07-20  7:35       ` Boris Brezillon
  0 siblings, 0 replies; 41+ messages in thread
From: Boris Brezillon @ 2018-07-20  7:35 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Wenyou Yang, Josh Wu, Tudor Ambarus, Richard Weinberger,
	David Woodhouse, Brian Norris, Marek Vasut, Nicolas Ferre,
	Alexandre Belloni, Kamal Dasu, Masahiro Yamada, Han Xu,
	Harvey Hunt, Vladimir Zapolskiy, Sylvain Lemieux, Xiaolei Li,
	Matthias Brugger, Maxime Ripard, Chen-Yu Tsai, Marc Gonzalez,
	Mans Rullgard, Stefan Agner, linux-mtd, linux-arm-kernel,
	linux-kernel, bcm-kernel-feedback-list, linux-mediatek

On Fri, 20 Jul 2018 09:17:45 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <boris.brezillon@bootlin.com> wrote on Fri, 20 Jul 2018
> 01:27:32 +0200:
> 
> > On Fri, 20 Jul 2018 01:00:21 +0200
> > Miquel Raynal <miquel.raynal@bootlin.com> 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 <miquel.raynal@bootlin.com>
> > > ---
> > >  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..2f6fcd4efab2 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 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;    
> > 
> > Hm, not sure this works. The driver only calls nand_scan_tail(), but
> > you replace that by a call to nand_scan(), which will call both
> > nand_scan_ident() and nand_scan_tail(), and I'm pretty sure
> > nand_scan_ident() will fail here.  
> 
> I know docg4 is a bit specific and could maybe be moved out of the raw/
> subdirectory. But in the meantime I don't want to block the series for
> this. The better I can propose right now (open to other ideas as
> well) would be to return 0 in nand_scan_ident() if the maxchip parameter
> is 0 which is the case only in this driver AFAIS.

Sounds good. Just document this particular case in nand_scan_ident()
kernel-doc header.

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2018-07-20  7:35 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-19 22:59 [PATCH v3 00/33] Allow dynamic allocations during NAND chip identification phase Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 01/33] mtd: rawnand: brcmnand: convert driver to nand_scan() Miquel Raynal
2018-07-19 23:17   ` Boris Brezillon
2018-07-20  7:12     ` Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 02/33] mtd: rawnand: cafe: " Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 03/33] mtd: rawnand: davinci: " Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 04/33] mtd: rawnand: denali: convert " Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 05/33] mtd: rawnand: fsl_elbc: convert driver " Miquel Raynal
2018-07-19 22:59 ` [PATCH v3 06/33] mtd: rawnand: fsl_ifc: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 07/33] mtd: rawnand: fsmc: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 08/33] mtd: rawnand: gpmi: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 09/33] mtd: rawnand: hisi504: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 10/33] mtd: rawnand: jz4780: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 11/33] mtd: rawnand: lpc32xx_mlc: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 12/33] mtd: rawnand: lpc32xx_slc: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 13/33] mtd: rawnand: marvell: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 14/33] mtd: rawnand: mtk: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 15/33] mtd: rawnand: mxc: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 16/33] mtd: rawnand: nandsim: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 17/33] mtd: rawnand: omap2: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 18/33] mtd: rawnand: s3c2410: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 19/33] mtd: rawnand: sh_flctl: move all NAND chip related setup in one function Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 20/33] mtd: rawnand: sh_flctl: convert driver to nand_scan() Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 21/33] mtd: rawnand: sunxi: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 22/33] mtd: rawnand: tango: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 23/33] mtd: rawnand: txx9ndfmc: rename nand controller internal structure Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 24/33] mtd: rawnand: txx9ndfmc: convert driver to nand_scan() Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 25/33] mtd: rawnand: vf610: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 26/33] mtd: rawnand: atmel: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 27/33] mtd: rawnand: sm_common: convert driver to nand_scan_with_ids() Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 28/33] mtd: rawnand: docg4: convert driver to nand_scan() Miquel Raynal
2018-07-19 23:27   ` Boris Brezillon
2018-07-20  7:17     ` Miquel Raynal
2018-07-20  7:35       ` Boris Brezillon
2018-07-19 23:00 ` [PATCH v3 29/33] mtd: rawnand: qcom: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 30/33] mtd: rawnand: jz4740: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 31/33] mtd: rawnand: tegra: " Miquel Raynal
2018-07-19 23:00 ` [PATCH v3 32/33] mtd: rawnand: do not export nand_scan_[ident|tail]() anymore Miquel Raynal
2018-07-19 23:45   ` Boris Brezillon
2018-07-19 23:00 ` [PATCH v3 33/33] mtd: rawnand: allocate dynamically ONFI parameters during detection Miquel Raynal
2018-07-19 23:42   ` Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).