Commit c1ac2dc3 authored by Kamal Dasu's avatar Kamal Dasu Committed by Miquel Raynal
Browse files

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: default avatarKamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
parent 9f897bfd
Loading
Loading
Loading
Loading
+45 −3
Original line number Diff line number Diff line
@@ -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);