* Fix nanddev_mtd_erase() function to match the changes done in

e7bfb3fdbd ("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
 -----BEGIN PGP SIGNATURE-----
 
 iQI5BAABCAAjBQJa4taLHBxib3Jpcy5icmV6aWxsb25AYm9vdGxpbi5jb20ACgkQ
 Ze02AX4ItwCTBQ//cY0GR+upuxJT7d7QZio6OMHwund2FBMiYvNeDK343PUkg/kK
 VOoJ/1CAb4RRyq+n7vyOTsApEtq8+HmbPea1M7CWos/QShHupTarLaG+r4z2Ko95
 NhroZG8F9eeYxswNTU5kTdne4XjLv1UasOmWymxUdKfHiOGwRV0aNFDLcROlDM/h
 ou5+5txr/BYD4QGFFpGsdVA4F9FP+f+lSkXxP3LazHh/0/JrBuQgUiUvnBOVGyvh
 Pgjky8Q/dToNeZA2+QPmt0TUTn02WT5+xAytfP5GdFxCd+RRpwRHvGwNVlbbSU1Z
 g7v2rurF9iebfF9UZQ7gMfQwZAvaXRWkczdJlirJdRzC+T1iXst6JTW7lzw4/BJd
 InZj+GTN67RZOQ7tEwEFmzUYyg9+FKJ+TawVaxmQqWels7GCUpKN1lgYOzqxdoBj
 YqZRq472FCifULkZqgmzqKKa050g1rfjilM5ckGkhgQBINExR2DT35rJJXuZ6Gko
 QW0K5vzKQCaElL3hNACHIejELwB9n1fyNuV21tlqIcLismrt0NGGel2ocRFVzSxr
 fk8pe7MeSiDNtlL5rCKqX7GWPz+fCsEfSCDZOVzvHQlpijRhpMo9D9DJ5ci9Itxd
 yQUTH8wI3ZVkc7eiwC1TVGrjKWRG/0Mp96l0fMOwbsiqQIjtf3hqE++oAzo=
 =myWm
 -----END PGP SIGNATURE-----

Merge tag 'mtd/fixes-for-4.17-rc3' of git://git.infradead.org/linux-mtd

Pull mtd fixes from Boris Brezillon:

 - Fix nanddev_mtd_erase() function to match the changes done in
   e7bfb3fdbd ("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
This commit is contained in:
Linus Torvalds 2018-04-27 09:15:06 -07:00
commit 245131e2d6
7 changed files with 61 additions and 31 deletions

View File

@ -45,6 +45,7 @@
#define I82802AB 0x00ad #define I82802AB 0x00ad
#define I82802AC 0x00ac #define I82802AC 0x00ac
#define PF38F4476 0x881c #define PF38F4476 0x881c
#define M28F00AP30 0x8963
/* STMicroelectronics chips */ /* STMicroelectronics chips */
#define M50LPW080 0x002F #define M50LPW080 0x002F
#define M50FLW080A 0x0080 #define M50FLW080A 0x0080
@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
extp->MinorVersion = '1'; 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 * static inline struct cfi_pri_intelext *
read_pri_intelext(struct map_info *map, __u16 adr) 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)))) (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
goto sleep; 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 */ /* 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' /* If the flash has finished erasing, then 'erase suspend'
* appears to make some (28F320) flash devices switch to * appears to make some (28F320) flash devices switch to
* 'read' mode. Make sure that we switch to 'read status' * 'read' mode. Make sure that we switch to 'read status'
* mode so we get the right data. --rmk * 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->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING; chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1; chip->erase_suspended = 1;
for (;;) { 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)) if (map_word_andequal(map, status, status_OK, status_OK))
break; 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 sending the 0x70 (Read Status) command to an erasing
chip and expecting it to be ignored, that's what we chip and expecting it to be ignored, that's what we
do. */ do. */
map_write(map, CMD(0xd0), adr); map_write(map, CMD(0xd0), chip->in_progress_block_addr);
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), chip->in_progress_block_addr);
chip->oldstate = FL_READY; chip->oldstate = FL_READY;
chip->state = FL_ERASING; chip->state = FL_ERASING;
break; break;
@ -1933,6 +1954,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xD0), adr); map_write(map, CMD(0xD0), adr);
chip->state = FL_ERASING; chip->state = FL_ERASING;
chip->erase_suspended = 0; 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, ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, len, adr, len,

View 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)))) (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
goto sleep; goto sleep;
/* We could check to see if we're trying to access the sector /* Do not allow suspend iff read/write to EB address */
* that is currently being erased. However, no user will try if ((adr & chip->in_progress_block_mask) ==
* anything like that so we just wait for the timeout. */ chip->in_progress_block_addr)
goto sleep;
/* Erase suspend */ /* Erase suspend */
/* It's harmless to issue the Erase-Suspend and Erase-Resume /* 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->state = FL_ERASING;
chip->erase_suspended = 0; chip->erase_suspended = 0;
chip->in_progress_block_addr = adr; chip->in_progress_block_addr = adr;
chip->in_progress_block_mask = ~(map->size - 1);
INVALIDATE_CACHE_UDELAY(map, chip, INVALIDATE_CACHE_UDELAY(map, chip,
adr, map->size, 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->state = FL_ERASING;
chip->erase_suspended = 0; chip->erase_suspended = 0;
chip->in_progress_block_addr = adr; chip->in_progress_block_addr = adr;
chip->in_progress_block_mask = ~(len - 1);
INVALIDATE_CACHE_UDELAY(map, chip, INVALIDATE_CACHE_UDELAY(map, chip,
adr, len, adr, len,

View File

@ -162,7 +162,6 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
ret = nanddev_erase(nand, &pos); ret = nanddev_erase(nand, &pos);
if (ret) { if (ret) {
einfo->fail_addr = nanddev_pos_to_offs(nand, &pos); einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
einfo->state = MTD_ERASE_FAILED;
return ret; return ret;
} }
@ -170,8 +169,6 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
nanddev_pos_next_eraseblock(nand, &pos); nanddev_pos_next_eraseblock(nand, &pos);
} }
einfo->state = MTD_ERASE_DONE;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nanddev_mtd_erase); EXPORT_SYMBOL_GPL(nanddev_mtd_erase);

View 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 * The legacy "num-cs" property indicates the number of CS on the only
* chip connected to the controller (legacy bindings does not support * chip connected to the controller (legacy bindings does not support
* more than one chip). CS are only incremented one by one while the RB * more than one chip). The CS and RB pins are always the #0.
* pin is always the #0.
* *
* When not using legacy bindings, a couple of "reg" and "nand-rb" * When not using legacy bindings, a couple of "reg" and "nand-rb"
* properties must be filled. For each chip, expressed as a subnode, * properties must be filled. For each chip, expressed as a subnode,
* "reg" points to the CS lines and "nand-rb" to the RB line. * "reg" points to the CS lines and "nand-rb" to the RB line.
*/ */
if (pdata) { if (pdata || nfc->caps->legacy_of_bindings) {
nsels = 1; nsels = 1;
} else if (nfc->caps->legacy_of_bindings && } else {
!of_get_property(np, "num-cs", &nsels)) { nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
dev_err(dev, "missing num-cs property\n"); if (nsels <= 0) {
return -EINVAL; dev_err(dev, "missing/invalid reg property\n");
} else if (!of_get_property(np, "reg", &nsels)) { return -EINVAL;
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;
} }
/* Alloc the nand chip structure */ /* Alloc the nand chip structure */

View File

@ -645,7 +645,7 @@ static int tango_nand_probe(struct platform_device *pdev)
writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE); 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)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);

View 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 *reg_base = cqspi->iobase;
void __iomem *ahb_base = cqspi->ahb_base; void __iomem *ahb_base = cqspi->ahb_base;
unsigned int remaining = n_rx; unsigned int remaining = n_rx;
unsigned int mod_bytes = n_rx % 4;
unsigned int bytes_to_read = 0; unsigned int bytes_to_read = 0;
u8 *rxbuf_end = rxbuf + n_rx;
int ret = 0; int ret = 0;
writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); 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) { while (bytes_to_read != 0) {
unsigned int word_remain = round_down(remaining, 4);
bytes_to_read *= cqspi->fifo_width; bytes_to_read *= cqspi->fifo_width;
bytes_to_read = bytes_to_read > remaining ? bytes_to_read = bytes_to_read > remaining ?
remaining : bytes_to_read; remaining : bytes_to_read;
ioread32_rep(ahb_base, rxbuf, bytes_to_read = round_down(bytes_to_read, 4);
DIV_ROUND_UP(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; rxbuf += bytes_to_read;
remaining -= bytes_to_read; remaining -= bytes_to_read;
bytes_to_read = cqspi_get_rd_sram_level(cqspi); bytes_to_read = cqspi_get_rd_sram_level(cqspi);

View File

@ -85,6 +85,7 @@ struct flchip {
unsigned int write_suspended:1; unsigned int write_suspended:1;
unsigned int erase_suspended:1; unsigned int erase_suspended:1;
unsigned long in_progress_block_addr; unsigned long in_progress_block_addr;
unsigned long in_progress_block_mask;
struct mutex mutex; struct mutex mutex;
wait_queue_head_t wq; /* Wait on here when we're waiting for the chip wait_queue_head_t wq; /* Wait on here when we're waiting for the chip