Merge tag 'mtd/fixes-for-4.17-rc3' of git://git.infradead.org/linux-mtd
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 Apr 2018 16:15:06 +0000 (09:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 Apr 2018 16:15:06 +0000 (09:15 -0700)
Pull mtd fixes from Boris Brezillon:

 - Fix nanddev_mtd_erase() function to match the changes done in
   e7bfb3fdbde3 ("mtd: Stop updating erase_info->state and calling
   mtd_erase_callback()")

 - Fix a memory leak in the Tango NAND controller driver

 - Fix read/write to a suspended erase block in the CFI driver

 - Fix the DT parsing logic in the Marvell NAND controller driver

* tag 'mtd/fixes-for-4.17-rc3' of git://git.infradead.org/linux-mtd:
  mtd: rawnand: marvell: fix the chip-select DT parsing logic
  mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block.
  mtd: cfi: cmdset_0001: Workaround Micron Erase suspend bug.
  mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block.
  mtd: spi-nor: cadence-quadspi: Fix page fault kernel panic
  mtd: nand: Fix nanddev_mtd_erase()
  mtd: rawnand: tango: Fix struct clk memory leak

drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/nand/core.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/tango_nand.c
drivers/mtd/spi-nor/cadence-quadspi.c
include/linux/mtd/flashchip.h

index d4c07b85f18e598ef8c0f85e8ce6fd70c9709396..f5695be14499855a2a54071004e8107c3289f680 100644 (file)
@@ -45,6 +45,7 @@
 #define I82802AB       0x00ad
 #define I82802AC       0x00ac
 #define PF38F4476      0x881c
+#define M28F00AP30     0x8963
 /* STMicroelectronics chips */
 #define M50LPW080       0x002F
 #define M50FLW080A     0x0080
@@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
                extp->MinorVersion = '1';
 }
 
+static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip)
+{
+       /*
+        * Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t
+        * Erase Supend for their small Erase Blocks(0x8000)
+        */
+       if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30)
+               return 1;
+       return 0;
+}
+
 static inline struct cfi_pri_intelext *
 read_pri_intelext(struct map_info *map, __u16 adr)
 {
@@ -831,21 +843,30 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
                     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
                        goto sleep;
 
+               /* Do not allow suspend iff read/write to EB address */
+               if ((adr & chip->in_progress_block_mask) ==
+                   chip->in_progress_block_addr)
+                       goto sleep;
+
+               /* do not suspend small EBs, buggy Micron Chips */
+               if (cfi_is_micron_28F00AP30(cfi, chip) &&
+                   (chip->in_progress_block_mask == ~(0x8000-1)))
+                       goto sleep;
 
                /* Erase suspend */
-               map_write(map, CMD(0xB0), adr);
+               map_write(map, CMD(0xB0), chip->in_progress_block_addr);
 
                /* If the flash has finished erasing, then 'erase suspend'
                 * appears to make some (28F320) flash devices switch to
                 * 'read' mode.  Make sure that we switch to 'read status'
                 * mode so we get the right data. --rmk
                 */
-               map_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), chip->in_progress_block_addr);
                chip->oldstate = FL_ERASING;
                chip->state = FL_ERASE_SUSPENDING;
                chip->erase_suspended = 1;
                for (;;) {
-                       status = map_read(map, adr);
+                       status = map_read(map, chip->in_progress_block_addr);
                        if (map_word_andequal(map, status, status_OK, status_OK))
                                break;
 
@@ -1041,8 +1062,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
                   sending the 0x70 (Read Status) command to an erasing
                   chip and expecting it to be ignored, that's what we
                   do. */
-               map_write(map, CMD(0xd0), adr);
-               map_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0xd0), chip->in_progress_block_addr);
+               map_write(map, CMD(0x70), chip->in_progress_block_addr);
                chip->oldstate = FL_READY;
                chip->state = FL_ERASING;
                break;
@@ -1933,6 +1954,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        map_write(map, CMD(0xD0), adr);
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
+       chip->in_progress_block_addr = adr;
+       chip->in_progress_block_mask = ~(len - 1);
 
        ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
                                   adr, len,
index 668e2cbc155bbe008858ba9a11a5467fb5fc39ba..692902df259892a78e69964cf1069867d7336acc 100644 (file)
@@ -816,9 +816,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
                        goto sleep;
 
-               /* We could check to see if we're trying to access the sector
-                * that is currently being erased. However, no user will try
-                * anything like that so we just wait for the timeout. */
+               /* Do not allow suspend iff read/write to EB address */
+               if ((adr & chip->in_progress_block_mask) ==
+                   chip->in_progress_block_addr)
+                       goto sleep;
 
                /* Erase suspend */
                /* It's harmless to issue the Erase-Suspend and Erase-Resume
@@ -2267,6 +2268,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
+       chip->in_progress_block_mask = ~(map->size - 1);
 
        INVALIDATE_CACHE_UDELAY(map, chip,
                                adr, map->size,
@@ -2356,6 +2358,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
+       chip->in_progress_block_mask = ~(len - 1);
 
        INVALIDATE_CACHE_UDELAY(map, chip,
                                adr, len,
index d0cd6f8635d722ab3c1bcfcc32184f47c8dab24c..9c9f8936b63bc37bbcbd7c6d22d6ca85d69f388f 100644 (file)
@@ -162,7 +162,6 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
                ret = nanddev_erase(nand, &pos);
                if (ret) {
                        einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
-                       einfo->state = MTD_ERASE_FAILED;
 
                        return ret;
                }
@@ -170,8 +169,6 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
                nanddev_pos_next_eraseblock(nand, &pos);
        }
 
-       einfo->state = MTD_ERASE_DONE;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
index 10e953218948836e0151f022ef8745d8b523e574..1d779a35ac8ee03152f8d9b1a4f99df753995785 100644 (file)
@@ -2299,29 +2299,20 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
        /*
         * The legacy "num-cs" property indicates the number of CS on the only
         * chip connected to the controller (legacy bindings does not support
-        * more than one chip). CS are only incremented one by one while the RB
-        * pin is always the #0.
+        * more than one chip). The CS and RB pins are always the #0.
         *
         * When not using legacy bindings, a couple of "reg" and "nand-rb"
         * properties must be filled. For each chip, expressed as a subnode,
         * "reg" points to the CS lines and "nand-rb" to the RB line.
         */
-       if (pdata) {
+       if (pdata || nfc->caps->legacy_of_bindings) {
                nsels = 1;
-       } else if (nfc->caps->legacy_of_bindings &&
-                  !of_get_property(np, "num-cs", &nsels)) {
-               dev_err(dev, "missing num-cs property\n");
-               return -EINVAL;
-       } else if (!of_get_property(np, "reg", &nsels)) {
-               dev_err(dev, "missing reg property\n");
-               return -EINVAL;
-       }
-
-       if (!pdata)
-               nsels /= sizeof(u32);
-       if (!nsels) {
-               dev_err(dev, "invalid reg property size\n");
-               return -EINVAL;
+       } else {
+               nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
+               if (nsels <= 0) {
+                       dev_err(dev, "missing/invalid reg property\n");
+                       return -EINVAL;
+               }
        }
 
        /* Alloc the nand chip structure */
index f54518ffb36af43221bc01905a731d3c9e73d968..f2052fae21c7453ae6f5fa3698fd2d38fa1884ad 100644 (file)
@@ -645,7 +645,7 @@ static int tango_nand_probe(struct platform_device *pdev)
 
        writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
 
-       clk = clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(clk);
 
index 4b8e9183489aa444edfa193d20fd004581470544..5872f31eaa60f91dae62bc1690e78aa97ca5c2a8 100644 (file)
@@ -501,7 +501,9 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf,
        void __iomem *reg_base = cqspi->iobase;
        void __iomem *ahb_base = cqspi->ahb_base;
        unsigned int remaining = n_rx;
+       unsigned int mod_bytes = n_rx % 4;
        unsigned int bytes_to_read = 0;
+       u8 *rxbuf_end = rxbuf + n_rx;
        int ret = 0;
 
        writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
@@ -530,11 +532,24 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf,
                }
 
                while (bytes_to_read != 0) {
+                       unsigned int word_remain = round_down(remaining, 4);
+
                        bytes_to_read *= cqspi->fifo_width;
                        bytes_to_read = bytes_to_read > remaining ?
                                        remaining : bytes_to_read;
-                       ioread32_rep(ahb_base, rxbuf,
-                                    DIV_ROUND_UP(bytes_to_read, 4));
+                       bytes_to_read = round_down(bytes_to_read, 4);
+                       /* Read 4 byte word chunks then single bytes */
+                       if (bytes_to_read) {
+                               ioread32_rep(ahb_base, rxbuf,
+                                            (bytes_to_read / 4));
+                       } else if (!word_remain && mod_bytes) {
+                               unsigned int temp = ioread32(ahb_base);
+
+                               bytes_to_read = mod_bytes;
+                               memcpy(rxbuf, &temp, min((unsigned int)
+                                                        (rxbuf_end - rxbuf),
+                                                        bytes_to_read));
+                       }
                        rxbuf += bytes_to_read;
                        remaining -= bytes_to_read;
                        bytes_to_read = cqspi_get_rd_sram_level(cqspi);
index b63fa457febd8d5d379ffe891e981ea2c8e912c8..3529683f691ef90c10f8ba89211341ceb60a1fe1 100644 (file)
@@ -85,6 +85,7 @@ struct flchip {
        unsigned int write_suspended:1;
        unsigned int erase_suspended:1;
        unsigned long in_progress_block_addr;
+       unsigned long in_progress_block_mask;
 
        struct mutex mutex;
        wait_queue_head_t wq; /* Wait on here when we're waiting for the chip