Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / nand / pxa3xx_nand.c
index c28d4e29af1a549dfd0c59fd20870da3a7a676f9..4cabdc9fda9076ceff440af42e028fb1073f9ed7 100644 (file)
 #define NAND_STOP_DELAY                (2 * HZ/50)
 #define PAGE_CHUNK_SIZE                (2048)
 
+/*
+ * Define a buffer size for the initial command that detects the flash device:
+ * STATUS, READID and PARAM. The largest of these is the PARAM command,
+ * needing 256 bytes.
+ */
+#define INIT_BUFFER_SIZE       256
+
 /* registers and bit definitions */
 #define NDCR           (0x00) /* Control register */
 #define NDTR0CS0       (0x04) /* Timing Parameter 0 for CS0 */
@@ -164,6 +171,7 @@ struct pxa3xx_nand_info {
 
        unsigned int            buf_start;
        unsigned int            buf_count;
+       unsigned int            buf_size;
 
        /* DMA information */
        int                     drcmr_dat;
@@ -540,7 +548,6 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        info->oob_size          = 0;
        info->use_ecc           = 0;
        info->use_spare         = 1;
-       info->use_dma           = (use_dma) ? 1 : 0;
        info->is_ready          = 0;
        info->retcode           = ERR_NONE;
        if (info->cs != 0)
@@ -912,26 +919,20 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
        return 0;
 }
 
-/* the maximum possible buffer size for large page with OOB data
- * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
- * data buffer and the DMA descriptor
- */
-#define MAX_BUFF_SIZE  PAGE_SIZE
-
 #ifdef ARCH_HAS_DMA
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
        struct platform_device *pdev = info->pdev;
-       int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
+       int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc);
 
        if (use_dma == 0) {
-               info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+               info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
                if (info->data_buff == NULL)
                        return -ENOMEM;
                return 0;
        }
 
-       info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
+       info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size,
                                &info->data_buff_phys, GFP_KERNEL);
        if (info->data_buff == NULL) {
                dev_err(&pdev->dev, "failed to allocate dma buffer\n");
@@ -945,11 +946,16 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
                                pxa3xx_nand_data_dma_irq, info);
        if (info->data_dma_ch < 0) {
                dev_err(&pdev->dev, "failed to request data dma\n");
-               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
+               dma_free_coherent(&pdev->dev, info->buf_size,
                                info->data_buff, info->data_buff_phys);
                return info->data_dma_ch;
        }
 
+       /*
+        * Now that DMA buffers are allocated we turn on
+        * DMA proper for I/O operations.
+        */
+       info->use_dma = 1;
        return 0;
 }
 
@@ -958,7 +964,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
        struct platform_device *pdev = info->pdev;
        if (use_dma) {
                pxa_free_dma(info->data_dma_ch);
-               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
+               dma_free_coherent(&pdev->dev, info->buf_size,
                                  info->data_buff, info->data_buff_phys);
        } else {
                kfree(info->data_buff);
@@ -967,7 +973,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
 #else
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
-       info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
        if (info->data_buff == NULL)
                return -ENOMEM;
        return 0;
@@ -1081,7 +1087,16 @@ KEEP_CONFIG:
        else
                host->col_addr_cycles = 1;
 
+       /* release the initial buffer */
+       kfree(info->data_buff);
+
+       /* allocate the real data + oob buffer */
+       info->buf_size = mtd->writesize + mtd->oobsize;
+       ret = pxa3xx_nand_init_buff(info);
+       if (ret)
+               return ret;
        info->oob_buff = info->data_buff + mtd->writesize;
+
        if ((mtd->size >> chip->page_shift) > 65536)
                host->row_addr_cycles = 3;
        else
@@ -1187,15 +1202,18 @@ static int alloc_nand_resource(struct platform_device *pdev)
        }
        info->mmio_phys = r->start;
 
-       ret = pxa3xx_nand_init_buff(info);
-       if (ret)
+       /* Allocate a buffer to allow flash detection */
+       info->buf_size = INIT_BUFFER_SIZE;
+       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+       if (info->data_buff == NULL) {
+               ret = -ENOMEM;
                goto fail_disable_clk;
+       }
 
        /* initialize all interrupts to be disabled */
        disable_int(info, NDSR_MASK);
 
-       ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED,
-                         pdev->name, info);
+       ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
                goto fail_free_buf;
@@ -1207,7 +1225,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
 fail_free_buf:
        free_irq(irq, info);
-       pxa3xx_nand_free_buff(info);
+       kfree(info->data_buff);
 fail_disable_clk:
        clk_disable_unprepare(info->clk);
        return ret;
@@ -1412,7 +1430,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
 static struct platform_driver pxa3xx_nand_driver = {
        .driver = {
                .name   = "pxa3xx-nand",
-               .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids),
+               .of_match_table = pxa3xx_nand_dt_ids,
        },
        .probe          = pxa3xx_nand_probe,
        .remove         = pxa3xx_nand_remove,