diff options
author | Kamal Dasu <kdasu.kdev@gmail.com> | 2019-05-16 12:41:47 -0400 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2019-06-27 20:06:40 +0200 |
commit | c1ac2dc34b51a9d2191067bbf2aebc8e8ddada70 (patch) | |
tree | 40670febf23c30c78e86936a4be58d71be1d5545 /drivers/mtd | |
parent | 9f897bfdd89f5f08a12fa263a7f57fbf8ad9292f (diff) | |
download | lwn-c1ac2dc34b51a9d2191067bbf2aebc8e8ddada70.tar.gz lwn-c1ac2dc34b51a9d2191067bbf2aebc8e8ddada70.zip |
mtd: rawnand: brcmnand: When oops in progress use pio and interrupt polling
If mtd_oops is in progress, switch to polling during NAND command
completion instead of relying on DMA/interrupts so that the mtd_oops
buffer can be completely written in the assigned NAND partition.
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/raw/brcmnand/brcmnand.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 93ac1b5b8862..e7b955a79996 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -151,6 +151,7 @@ struct brcmnand_controller { u32 nand_cs_nand_xor; u32 corr_stat_threshold; u32 flash_dma_mode; + bool pio_poll_mode; }; struct brcmnand_cfg { @@ -815,6 +816,20 @@ static inline bool has_flash_dma(struct brcmnand_controller *ctrl) return ctrl->flash_dma_base; } +static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl) +{ + if (ctrl->pio_poll_mode) + return; + + if (has_flash_dma(ctrl)) { + ctrl->flash_dma_base = 0; + disable_irq(ctrl->dma_irq); + } + + disable_irq(ctrl->irq); + ctrl->pio_poll_mode = true; +} + static inline bool flash_dma_buf_ok(const void *buf) { return buf && !is_vmalloc_addr(buf) && @@ -1229,15 +1244,42 @@ static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat, /* intentionally left blank */ } +static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip) +{ + struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; + struct mtd_info *mtd = nand_to_mtd(chip); + bool err = false; + int sts; + + if (mtd->oops_panic_write) { + /* switch to interrupt polling and PIO mode */ + disable_ctrl_irqs(ctrl); + sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, + NAND_CTRL_RDY, 0); + err = (sts < 0) ? true : false; + } else { + unsigned long timeo = msecs_to_jiffies( + NAND_POLL_STATUS_TIMEOUT_MS); + /* wait for completion interrupt */ + sts = wait_for_completion_timeout(&ctrl->done, timeo); + err = (sts <= 0) ? true : false; + } + + return err; +} + static int brcmnand_waitfunc(struct nand_chip *chip) { struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; - unsigned long timeo = msecs_to_jiffies(100); + bool err = false; dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending); - if (ctrl->cmd_pending && - wait_for_completion_timeout(&ctrl->done, timeo) <= 0) { + if (ctrl->cmd_pending) + err = brcmstb_nand_wait_for_completion(chip); + + if (err) { u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START) >> brcmnand_cmd_shift(ctrl); |