mtd: nand: kill the the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE for nand_buffers{}
authorHuang Shijie <b32955@freescale.com>
Mon, 13 Jan 2014 06:27:12 +0000 (14:27 +0800)
committerBrian Norris <computersforpeace@gmail.com>
Tue, 11 Mar 2014 05:42:22 +0000 (22:42 -0700)
The patch converts the arrays to buffer pointers for nand_buffers{}.

The cafe_nand.c is the only NAND_OWN_BUFFERS user which allocates
nand_buffers{} itself.

This patch disables the DMA for nand_scan_ident, and restores the DMA
status after we finish the nand_scan_ident. This way, we can get page
size and OOB size and use them to allocate cafe->dmabuf.

Since the cafe_nand.c uses the NAND_ECC_HW_SYNDROME ECC mode, we do not
allocate the buffers for @ecccalc and @ecccode.

Signed-off-by: Huang Shijie <b32955@freescale.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/nand_base.c
include/linux/mtd/nand.h

index f2f64addb5e87119d8b72e9122565ae3ec9150f9..4e66726da9aa8bc55658bed57a3d56d1849d6793 100644 (file)
@@ -627,6 +627,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        struct cafe_priv *cafe;
        uint32_t ctrl;
        int err = 0;
+       int old_dma;
+       struct nand_buffers *nbuf;
 
        /* Very old versions shared the same PCI ident for all three
           functions on the chip. Verify the class too... */
@@ -655,13 +657,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                err = -ENOMEM;
                goto out_free_mtd;
        }
-       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers),
-                                         &cafe->dmaaddr, GFP_KERNEL);
-       if (!cafe->dmabuf) {
-               err = -ENOMEM;
-               goto out_ior;
-       }
-       cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
 
        cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
        if (!cafe->rs) {
@@ -721,7 +716,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                          "CAFE NAND", mtd);
        if (err) {
                dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-               goto out_free_dma;
+               goto out_ior;
        }
 
        /* Disable master reset, enable NAND clock */
@@ -735,6 +730,32 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
        cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
 
+       /* Enable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+               cafe_readl(cafe, GLOBAL_CTRL),
+               cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+       /* Do not use the DMA for the nand_scan_ident() */
+       old_dma = usedma;
+       usedma = 0;
+
+       /* Scan to find existence of the device */
+       if (nand_scan_ident(mtd, 2, NULL)) {
+               err = -ENXIO;
+               goto out_irq;
+       }
+
+       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
+                               2112 + sizeof(struct nand_buffers) +
+                               mtd->writesize + mtd->oobsize,
+                               &cafe->dmaaddr, GFP_KERNEL);
+       if (!cafe->dmabuf) {
+               err = -ENOMEM;
+               goto out_irq;
+       }
+       cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112;
+
        /* Set up DMA address */
        cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
        if (sizeof(cafe->dmaaddr) > 4)
@@ -746,16 +767,13 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
                cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
 
-       /* Enable NAND IRQ in global IRQ mask register */
-       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
-       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
-               cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+       /* this driver does not need the @ecccalc and @ecccode */
+       nbuf->ecccalc = NULL;
+       nbuf->ecccode = NULL;
+       nbuf->databuf = (uint8_t *)(nbuf + 1);
 
-       /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 2, NULL)) {
-               err = -ENXIO;
-               goto out_irq;
-       }
+       /* Restore the DMA flag */
+       usedma = old_dma;
 
        cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
        if (mtd->writesize == 2048)
@@ -773,7 +791,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        } else {
                printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
                       mtd->writesize);
-               goto out_irq;
+               goto out_free_dma;
        }
        cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
        cafe->nand.ecc.size = mtd->writesize;
@@ -790,7 +808,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        err = nand_scan_tail(mtd);
        if (err)
-               goto out_irq;
+               goto out_free_dma;
 
        pci_set_drvdata(pdev, mtd);
 
@@ -799,12 +817,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        goto out;
 
+ out_free_dma:
+       dma_free_coherent(&cafe->pdev->dev,
+                       2112 + sizeof(struct nand_buffers) +
+                       mtd->writesize + mtd->oobsize,
+                       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);
        free_irq(pdev->irq, mtd);
- out_free_dma:
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
  out_ior:
        pci_iounmap(pdev, cafe->mmio);
  out_free_mtd:
@@ -824,7 +845,10 @@ static void cafe_nand_remove(struct pci_dev *pdev)
        nand_release(mtd);
        free_rs(cafe->rs);
        pci_iounmap(pdev, cafe->mmio);
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+       dma_free_coherent(&cafe->pdev->dev,
+                       2112 + sizeof(struct nand_buffers) +
+                       mtd->writesize + mtd->oobsize,
+                       cafe->dmabuf, cafe->dmaaddr);
        kfree(mtd);
 }
 
index 9715a7ba164a042abbba49fd842e9400a677d6fe..deeaa1cc4a85796e72f9fc09903113682d412f56 100644 (file)
@@ -3696,15 +3696,26 @@ int nand_scan_tail(struct mtd_info *mtd)
        int i;
        struct nand_chip *chip = mtd->priv;
        struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct nand_buffers *nbuf;
 
        /* New bad blocks should be marked in OOB, flash-based BBT, or both */
        BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
                        !(chip->bbt_options & NAND_BBT_USE_FLASH));
 
-       if (!(chip->options & NAND_OWN_BUFFERS))
-               chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
-       if (!chip->buffers)
-               return -ENOMEM;
+       if (!(chip->options & NAND_OWN_BUFFERS)) {
+               nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+                               + mtd->oobsize * 3, GFP_KERNEL);
+               if (!nbuf)
+                       return -ENOMEM;
+               nbuf->ecccalc = (uint8_t *)(nbuf + 1);
+               nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
+               nbuf->databuf = nbuf->ecccode + mtd->oobsize;
+
+               chip->buffers = nbuf;
+       } else {
+               if (!chip->buffers)
+                       return -ENOMEM;
+       }
 
        /* Set the internal oob buffer location, just after the page data */
        chip->oob_poi = chip->buffers->databuf + mtd->writesize;
index 32f8612469d8d2d2c5a659f9326551bcbbd8806b..520ebca11f5d8e8e630e60771881e5d912441533 100644 (file)
@@ -435,17 +435,17 @@ struct nand_ecc_ctrl {
 
 /**
  * struct nand_buffers - buffer structure for read/write
- * @ecccalc:   buffer for calculated ECC
- * @ecccode:   buffer for ECC read from flash
- * @databuf:   buffer for data - dynamically sized
+ * @ecccalc:   buffer pointer for calculated ECC, size is oobsize.
+ * @ecccode:   buffer pointer for ECC read from flash, size is oobsize.
+ * @databuf:   buffer pointer for data, size is (page size + oobsize).
  *
  * Do not change the order of buffers. databuf and oobrbuf must be in
  * consecutive order.
  */
 struct nand_buffers {
-       uint8_t ecccalc[NAND_MAX_OOBSIZE];
-       uint8_t ecccode[NAND_MAX_OOBSIZE];
-       uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+       uint8_t *ecccalc;
+       uint8_t *ecccode;
+       uint8_t *databuf;
 };
 
 /**