diff options
Diffstat (limited to 'drivers/mtd/nand/raw')
-rw-r--r-- | drivers/mtd/nand/raw/atmel/nand-controller.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/atmel/pmecc.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/brcmnand/brcmnand.c | 62 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/fsmc_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/nand_hynix.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/qcom_nandc.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/renesas-nand-controller.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/rockchip-nand-controller.c | 15 |
8 files changed, 78 insertions, 25 deletions
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index dedcca87defc..84ab4a83cbd6 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -373,7 +373,7 @@ static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc, dma_cookie_t cookie; buf_dma = dma_map_single(nc->dev, buf, len, dir); - if (dma_mapping_error(nc->dev, dev_dma)) { + if (dma_mapping_error(nc->dev, buf_dma)) { dev_err(nc->dev, "Failed to prepare a buffer for DMA access\n"); goto err; diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index 3c7dee1be21d..0b402823b619 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -143,6 +143,7 @@ struct atmel_pmecc_caps { int nstrengths; int el_offset; bool correct_erased_chunks; + bool clk_ctrl; }; struct atmel_pmecc { @@ -843,6 +844,10 @@ static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev, if (IS_ERR(pmecc->regs.errloc)) return ERR_CAST(pmecc->regs.errloc); + /* pmecc data setup time */ + if (caps->clk_ctrl) + writel(PMECC_CLK_133MHZ, pmecc->regs.base + ATMEL_PMECC_CLK); + /* Disable all interrupts before registering the PMECC handler. */ writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR); atmel_pmecc_reset(pmecc); @@ -896,6 +901,7 @@ static struct atmel_pmecc_caps at91sam9g45_caps = { .strengths = atmel_pmecc_strengths, .nstrengths = 5, .el_offset = 0x8c, + .clk_ctrl = true, }; static struct atmel_pmecc_caps sama5d4_caps = { diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 62bdda3be92f..835653bdd5ab 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -29,6 +29,7 @@ #include <linux/static_key.h> #include <linux/list.h> #include <linux/log2.h> +#include <linux/string_choices.h> #include "brcmnand.h" @@ -359,6 +360,7 @@ enum brcmnand_reg { BRCMNAND_CORR_THRESHOLD_EXT, BRCMNAND_UNCORR_COUNT, BRCMNAND_CORR_COUNT, + BRCMNAND_READ_ERROR_COUNT, BRCMNAND_CORR_EXT_ADDR, BRCMNAND_CORR_ADDR, BRCMNAND_UNCORR_EXT_ADDR, @@ -389,6 +391,7 @@ static const u16 brcmnand_regs_v21[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0, [BRCMNAND_UNCORR_COUNT] = 0, [BRCMNAND_CORR_COUNT] = 0, + [BRCMNAND_READ_ERROR_COUNT] = 0, [BRCMNAND_CORR_EXT_ADDR] = 0x60, [BRCMNAND_CORR_ADDR] = 0x64, [BRCMNAND_UNCORR_EXT_ADDR] = 0x68, @@ -419,6 +422,7 @@ static const u16 brcmnand_regs_v33[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0, [BRCMNAND_UNCORR_COUNT] = 0, [BRCMNAND_CORR_COUNT] = 0, + [BRCMNAND_READ_ERROR_COUNT] = 0x80, [BRCMNAND_CORR_EXT_ADDR] = 0x70, [BRCMNAND_CORR_ADDR] = 0x74, [BRCMNAND_UNCORR_EXT_ADDR] = 0x78, @@ -449,6 +453,7 @@ static const u16 brcmnand_regs_v50[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0, [BRCMNAND_UNCORR_COUNT] = 0, [BRCMNAND_CORR_COUNT] = 0, + [BRCMNAND_READ_ERROR_COUNT] = 0x80, [BRCMNAND_CORR_EXT_ADDR] = 0x70, [BRCMNAND_CORR_ADDR] = 0x74, [BRCMNAND_UNCORR_EXT_ADDR] = 0x78, @@ -479,6 +484,7 @@ static const u16 brcmnand_regs_v60[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0xc4, [BRCMNAND_UNCORR_COUNT] = 0xfc, [BRCMNAND_CORR_COUNT] = 0x100, + [BRCMNAND_READ_ERROR_COUNT] = 0x104, [BRCMNAND_CORR_EXT_ADDR] = 0x10c, [BRCMNAND_CORR_ADDR] = 0x110, [BRCMNAND_UNCORR_EXT_ADDR] = 0x114, @@ -509,6 +515,7 @@ static const u16 brcmnand_regs_v71[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0, [BRCMNAND_UNCORR_COUNT] = 0xfc, [BRCMNAND_CORR_COUNT] = 0x100, + [BRCMNAND_READ_ERROR_COUNT] = 0x104, [BRCMNAND_CORR_EXT_ADDR] = 0x10c, [BRCMNAND_CORR_ADDR] = 0x110, [BRCMNAND_UNCORR_EXT_ADDR] = 0x114, @@ -539,6 +546,7 @@ static const u16 brcmnand_regs_v72[] = { [BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0, [BRCMNAND_UNCORR_COUNT] = 0xfc, [BRCMNAND_CORR_COUNT] = 0x100, + [BRCMNAND_READ_ERROR_COUNT] = 0x104, [BRCMNAND_CORR_EXT_ADDR] = 0x10c, [BRCMNAND_CORR_ADDR] = 0x110, [BRCMNAND_UNCORR_EXT_ADDR] = 0x114, @@ -959,11 +967,11 @@ static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs, return offs_cs0 + cs * ctrl->reg_spacing + cs_offs; } -static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl) +static inline u32 brcmnand_corr_total(struct brcmnand_controller *ctrl) { - if (ctrl->nand_version < 0x0600) - return 1; - return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT); + if (ctrl->nand_version < 0x400) + return 0; + return brcmnand_read_reg(ctrl, BRCMNAND_READ_ERROR_COUNT); } static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val) @@ -1462,7 +1470,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) int ret; if (old_wp != wp) { - dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off"); + dev_dbg(ctrl->dev, "WP %s\n", str_on_off(wp)); old_wp = wp; } @@ -1492,7 +1500,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) if (ret) dev_err_ratelimited(&host->pdev->dev, "nand #WP expected %s\n", - wp ? "on" : "off"); + str_on_off(wp)); } } @@ -1869,8 +1877,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, unsigned int trans = len >> FC_SHIFT; dma_addr_t pa; - dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ? - "read" : "write"), buf, oob); + dev_dbg(ctrl->dev, "EDU %s %p:%p\n", + str_read_write(edu_cmd == EDU_CMD_READ), buf, oob); pa = dma_map_single(ctrl->dev, buf, len, dir); if (dma_mapping_error(ctrl->dev, pa)) { @@ -2066,15 +2074,20 @@ static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf, */ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, u64 addr, unsigned int trans, u32 *buf, - u8 *oob, u64 *err_addr) + u8 *oob, u64 *err_addr, unsigned int *corr) { struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; int i, ret = 0; + unsigned int prev_corr; + + if (corr) + *corr = 0; brcmnand_clear_ecc_addr(ctrl); for (i = 0; i < trans; i++, addr += FC_BYTES) { + prev_corr = brcmnand_corr_total(ctrl); brcmnand_set_cmd_addr(mtd, addr); /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */ brcmnand_send_cmd(host, CMD_PAGE_READ); @@ -2099,13 +2112,16 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, if (*err_addr) ret = -EBADMSG; - } + else { + *err_addr = brcmnand_get_correcc_addr(ctrl); - if (!ret) { - *err_addr = brcmnand_get_correcc_addr(ctrl); + if (*err_addr) { + ret = -EUCLEAN; - if (*err_addr) - ret = -EUCLEAN; + if (corr && (brcmnand_corr_total(ctrl) - prev_corr) > *corr) + *corr = brcmnand_corr_total(ctrl) - prev_corr; + } + } } } @@ -2173,6 +2189,8 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, int err; bool retry = true; bool edu_err = false; + unsigned int corrected = 0; /* max corrected bits per subpage */ + unsigned int prev_tot = brcmnand_corr_total(ctrl); dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf); @@ -2200,9 +2218,11 @@ try_dmaread: memset(oob, 0x99, mtd->oobsize); err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf, - oob, &err_addr); + oob, &err_addr, &corrected); } + mtd->ecc_stats.corrected += brcmnand_corr_total(ctrl) - prev_tot; + if (mtd_is_eccerr(err)) { /* * On controller version and 7.0, 7.1 , DMA read after a @@ -2240,16 +2260,20 @@ try_dmaread: } if (mtd_is_bitflip(err)) { - unsigned int corrected = brcmnand_count_corrected(ctrl); - /* in case of EDU correctable error we read again using PIO */ if (edu_err) err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf, - oob, &err_addr); + oob, &err_addr, &corrected); dev_dbg(ctrl->dev, "corrected error at 0x%llx\n", (unsigned long long)err_addr); - mtd->ecc_stats.corrected += corrected; + /* + * if flipped bits accumulator is not supported but we detected + * a correction, increase stat by 1 to match previous behavior. + */ + if (brcmnand_corr_total(ctrl) == prev_tot) + mtd->ecc_stats.corrected++; + /* Always exceed the software-imposed threshold */ return max(mtd->bitflip_threshold, corrected); } diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index d579d5dd60d6..df61db8ce466 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -503,6 +503,8 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, dma_dev = chan->device; dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction); + if (dma_mapping_error(dma_dev->dev, dma_addr)) + return -EINVAL; if (direction == DMA_TO_DEVICE) { dma_src = dma_addr; diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index c02e50608816..b663659b2f49 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -377,9 +377,9 @@ static int hynix_nand_rr_init(struct nand_chip *chip) /* * We only support read-retry for 1xnm NANDs, and those NANDs all - * expose a valid JEDEC ID. + * expose a valid JEDEC ID. SLC NANDs don't require read-retry. */ - if (valid_jedecid) { + if (valid_jedecid && nanddev_bits_per_cell(&chip->base) > 1) { u8 nand_tech = chip->id.data[5] >> 4; /* 1xnm technology */ diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 1003cf118c01..4dd6f1a4e797 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int cwperpage, bad_block_byte, ret; bool wide_bus; - int ecc_mode = 1; + int ecc_mode = ECC_MODE_8BIT; /* controller only supports 512 bytes data steps */ ecc->size = NANDC_STEP_SIZE; @@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) if (ecc->strength >= 8) { /* 8 bit ECC defaults to BCH ECC on all platforms */ host->bch_enabled = true; - ecc_mode = 1; + ecc_mode = ECC_MODE_8BIT; if (wide_bus) { host->ecc_bytes_hw = 14; @@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) if (nandc->props->ecc_modes & ECC_BCH_4BIT) { /* BCH */ host->bch_enabled = true; - ecc_mode = 0; + ecc_mode = ECC_MODE_4BIT; if (wide_bus) { host->ecc_bytes_hw = 8; diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c index 44f6603736d1..ac8c1b80d7be 100644 --- a/drivers/mtd/nand/raw/renesas-nand-controller.c +++ b/drivers/mtd/nand/raw/renesas-nand-controller.c @@ -426,6 +426,9 @@ static int rnandc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf, /* Configure DMA */ dma_addr = dma_map_single(rnandc->dev, rnandc->buf, mtd->writesize, DMA_FROM_DEVICE); + if (dma_mapping_error(rnandc->dev, dma_addr)) + return -ENOMEM; + writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG); writel(mtd->writesize, rnandc->regs + DMA_CNT_REG); writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG); @@ -606,6 +609,9 @@ static int rnandc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf, /* Configure DMA */ dma_addr = dma_map_single(rnandc->dev, (void *)rnandc->buf, mtd->writesize, DMA_TO_DEVICE); + if (dma_mapping_error(rnandc->dev, dma_addr)) + return -ENOMEM; + writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG); writel(mtd->writesize, rnandc->regs + DMA_CNT_REG); writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG); diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 63e7b9e39a5a..c5d7cd8a6cab 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -656,9 +656,16 @@ static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf, mtd->writesize, DMA_TO_DEVICE); + if (dma_mapping_error(nfc->dev, dma_data)) + return -ENOMEM; + dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, ecc->steps * oob_step, DMA_TO_DEVICE); + if (dma_mapping_error(nfc->dev, dma_oob)) { + dma_unmap_single(nfc->dev, dma_data, mtd->writesize, DMA_TO_DEVICE); + return -ENOMEM; + } reinit_completion(&nfc->done); writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); @@ -772,9 +779,17 @@ static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on, dma_data = dma_map_single(nfc->dev, nfc->page_buf, mtd->writesize, DMA_FROM_DEVICE); + if (dma_mapping_error(nfc->dev, dma_data)) + return -ENOMEM; + dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, ecc->steps * oob_step, DMA_FROM_DEVICE); + if (dma_mapping_error(nfc->dev, dma_oob)) { + dma_unmap_single(nfc->dev, dma_data, mtd->writesize, + DMA_FROM_DEVICE); + return -ENOMEM; + } /* * The first blocks (4, 8 or 16 depending on the device) |