Commit 245131e2 authored by Linus Torvalds's avatar Linus Torvalds

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
   e7bfb3fd ("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
parents 0f940fac f6997bec
......@@ -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,
......
......@@ -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,
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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);
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment