diff options
author | Chris Packham <chris.packham@alliedtelesis.co.nz> | 2020-08-28 04:12:37 +0300 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2020-09-30 17:44:16 +0300 |
commit | 85a3ebbb7fe869188644498c49bf3719d9cb054d (patch) | |
tree | 88b0b7440e5e82121feecde4d77ed538096e4912 /drivers/mtd/nand/raw | |
parent | 302d8a2288529c44401d946de09526009e4f7124 (diff) | |
download | linux-85a3ebbb7fe869188644498c49bf3719d9cb054d.tar.xz |
mtd: rawnand: marvell: Support panic_write for mtdoops
Under a panic context we can't get an interrupt. Actively poll for the
RB status when performing a panic_write.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200828011237.22066-1-chris.packham@alliedtelesis.co.nz
Diffstat (limited to 'drivers/mtd/nand/raw')
-rw-r--r-- | drivers/mtd/nand/raw/marvell_nand.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index f7ff8e93a249..8d76ef41099b 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -685,9 +685,31 @@ static int marvell_nfc_wait_cmdd(struct nand_chip *chip) return marvell_nfc_end_cmd(chip, cs_flag, "CMDD"); } +static int marvell_nfc_poll_status(struct marvell_nfc *nfc, u32 mask, + u32 expected_val, unsigned long timeout_ms) +{ + unsigned long limit; + u32 st; + + limit = jiffies + msecs_to_jiffies(timeout_ms); + do { + st = readl_relaxed(nfc->regs + NDSR); + if (st & NDSR_RDY(1)) + st |= NDSR_RDY(0); + + if ((st & mask) == expected_val) + return 0; + + cpu_relax(); + } while (time_after(limit, jiffies)); + + return -ETIMEDOUT; +} + static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) { struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); + struct mtd_info *mtd = nand_to_mtd(chip); u32 pending; int ret; @@ -695,12 +717,18 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) if (!timeout_ms) timeout_ms = IRQ_TIMEOUT; - init_completion(&nfc->complete); + if (mtd->oops_panic_write) { + ret = marvell_nfc_poll_status(nfc, NDSR_RDY(0), + NDSR_RDY(0), + timeout_ms); + } else { + init_completion(&nfc->complete); - marvell_nfc_enable_int(nfc, NDCR_RDYM); - ret = wait_for_completion_timeout(&nfc->complete, - msecs_to_jiffies(timeout_ms)); - marvell_nfc_disable_int(nfc, NDCR_RDYM); + marvell_nfc_enable_int(nfc, NDCR_RDYM); + ret = wait_for_completion_timeout(&nfc->complete, + msecs_to_jiffies(timeout_ms)); + marvell_nfc_disable_int(nfc, NDCR_RDYM); + } pending = marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1)); /* |