From 3c3c10bba1e4ccb75b41442e45c1a072f6cded19 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 30 Jan 2012 14:58:32 +0200 Subject: mtd: add leading underscore to all mtd functions This patch renames all MTD functions by adding a "_" prefix: mtd->erase -> mtd->_erase mtd->read_oob -> mtd->_read_oob ... The reason is that we are re-working the MTD API and from now on it is an error to use MTD function pointers directly - we have a corresponding API call for every pointer. By adding a leading "_" we achieve the following: 1. Make sure we convert every direct pointer users 2. A leading "_" suggests that this interface is internal and it becomes less likely that people will use them directly 3. Make sure all the out-of-tree modules stop compiling and the owners spot the big API change and amend them. Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index ad11ef0a81f4..3746ae8ff0a2 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1820,12 +1820,12 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->writesize = DOC_LAYOUT_PAGE_SIZE; mtd->oobsize = DOC_LAYOUT_OOB_SIZE; mtd->owner = THIS_MODULE; - mtd->erase = doc_erase; - mtd->read = doc_read; - mtd->write = doc_write; - mtd->read_oob = doc_read_oob; - mtd->write_oob = doc_write_oob; - mtd->block_isbad = doc_block_isbad; + mtd->_erase = doc_erase; + mtd->_read = doc_read; + mtd->_write = doc_write; + mtd->_read_oob = doc_read_oob; + mtd->_write_oob = doc_write_oob; + mtd->_block_isbad = doc_block_isbad; mtd->ecclayout = &docg3_oobinfo; } -- cgit v1.2.3 From 82c4c58d6f1a78e8de875272a19ab9220b8066aa Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Feb 2012 09:44:32 +0200 Subject: mtd: docg3: initialize writebufsize The writebufsize concept was introduce by commit "0e4ca7e mtd: add writebufsize field to mtd_info struct" and it represents the maximum amount of data the device writes to the media at a time. This is an important parameter for UBIFS which is used during recovery and which basically defines how big a corruption caused by a power cut can be. Set it to be equivalent to mtd->writesize because this is the maximum amount of data the driver writes at a time. Signed-off-by: Artem Bityutskiy Acked-by: Robert Jarzmik Cc: stable@kernel.org [3.2+] Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 3746ae8ff0a2..fc7932b33da4 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1817,7 +1817,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; if (docg3->reliable == 2) mtd->erasesize /= 2; - mtd->writesize = DOC_LAYOUT_PAGE_SIZE; + mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE; mtd->oobsize = DOC_LAYOUT_OOB_SIZE; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; -- cgit v1.2.3 From 31716a5ad32771be8339832b62aa030c263c6dac Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 3 Mar 2012 21:57:33 +0100 Subject: mtd: docg3 trivial renaming Change the name of the mtd so that it is simpler, and is easier to cope with by mtdparts. Signed-off-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index fc7932b33da4..3eafef383a39 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1804,7 +1804,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) switch (chip_id) { case DOC_CHIPID_G3: - mtd->name = kasprintf(GFP_KERNEL, "DiskOnChip G3 floor %d", + mtd->name = kasprintf(GFP_KERNEL, "docg3.%d", docg3->device_id); docg3->max_block = 2047; break; -- cgit v1.2.3 From d107bc34f4953852834f086968fc7963125d6943 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 11 Mar 2012 11:28:45 +0100 Subject: mtd: docg3 reduce read alignment burden The read function was so far requiring the reads to be aligned on page boundaries, and be page length multiples in size. Relieve these constraints to ease the userspace ubifs programs runs, which read ubifs headers of 64 bytes. Artem: squashed a later fix from Robert Jarzmik into this patch. Signed-off-by: Robert Jarzmik Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 3eafef383a39..2c1d0fca6757 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -734,7 +734,7 @@ err: * doc_read_page_getbytes - Reads bytes from a prepared page * @docg3: the device * @len: the number of bytes to be read (must be a multiple of 4) - * @buf: the buffer to be filled in + * @buf: the buffer to be filled in (or NULL is forget bytes) * @first: 1 if first time read, DOC_READADDRESS should be set * */ @@ -849,7 +849,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct docg3 *docg3 = mtd->priv; - int block0, block1, page, ret, ofs = 0; + int block0, block1, page, ret, skip, ofs = 0; u8 *oobbuf = ops->oobbuf; u8 *buf = ops->datbuf; size_t len, ooblen, nbdata, nboob; @@ -869,8 +869,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n", from, ops->mode, buf, len, oobbuf, ooblen); - if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) || - (from % DOC_LAYOUT_PAGE_SIZE)) + if (ooblen % DOC_LAYOUT_OOB_SIZE) return -EINVAL; ret = -EINVAL; @@ -882,10 +881,11 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ops->oobretlen = 0; ops->retlen = 0; ret = 0; + skip = from % DOC_LAYOUT_PAGE_SIZE; while (!ret && (len > 0 || ooblen > 0)) { - calc_block_sector(from, &block0, &block1, &page, &ofs, + calc_block_sector(from - skip, &block0, &block1, &page, &ofs, docg3->reliable); - nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); if (ret < 0) @@ -893,10 +893,14 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); if (ret < 0) goto err_in_read; - ret = doc_read_page_getbytes(docg3, nbdata, buf, 1); + ret = doc_read_page_getbytes(docg3, skip, NULL, 1); + if (ret < skip) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); if (ret < nbdata) goto err_in_read; - doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata, + doc_read_page_getbytes(docg3, + DOC_LAYOUT_PAGE_SIZE - nbdata - skip, NULL, 0); ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); if (ret < nboob) @@ -950,6 +954,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, len -= nbdata; ooblen -= nboob; from += DOC_LAYOUT_PAGE_SIZE; + skip = 0; } return ret; -- cgit v1.2.3 From 6a918bade9dab40aaef80559bd1169c69e8d69cb Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Sun, 11 Mar 2012 14:21:11 -0700 Subject: mtd: flash drivers set ecc strength Flash device drivers initialize 'ecc_strength' in struct mtd_info, which is the maximum number of bit errors that can be corrected in one writesize region. Drivers using the nand interface intitialize 'strength' in struct nand_ecc_ctrl, which is the maximum number of bit errors that can be corrected in one ecc step. Nand infrastructure code translates this to 'ecc_strength'. Also for nand drivers, the nand infrastructure code sets ecc.strength for ecc modes NAND_ECC_SOFT, NAND_ECC_SOFT_BCH, and NAND_ECC_NONE. It is set in the driver for all other modes. Signed-off-by: Mike Dunn Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/doc2000.c | 1 + drivers/mtd/devices/doc2001.c | 1 + drivers/mtd/devices/doc2001plus.c | 1 + drivers/mtd/devices/docg3.c | 1 + drivers/mtd/mtdpart.c | 1 + drivers/mtd/nand/alauda.c | 1 + drivers/mtd/nand/atmel_nand.c | 1 + drivers/mtd/nand/bcm_umi_nand.c | 8 ++++++++ drivers/mtd/nand/bf5xx_nand.c | 2 ++ drivers/mtd/nand/cafe_nand.c | 1 + drivers/mtd/nand/cs553x_nand.c | 2 ++ drivers/mtd/nand/davinci_nand.c | 1 + drivers/mtd/nand/denali.c | 3 +++ drivers/mtd/nand/diskonchip.c | 1 + drivers/mtd/nand/docg4.c | 1 + drivers/mtd/nand/fsl_elbc_nand.c | 6 ++++++ drivers/mtd/nand/fsmc_nand.c | 2 ++ drivers/mtd/nand/jz4740_nand.c | 5 +++++ drivers/mtd/nand/mxc_nand.c | 7 +++++++ drivers/mtd/nand/nand_base.c | 7 ++++++- drivers/mtd/nand/ndfc.c | 1 + drivers/mtd/nand/omap2.c | 1 + drivers/mtd/nand/pxa3xx_nand.c | 1 + drivers/mtd/nand/r852.c | 1 + drivers/mtd/nand/rtc_from4.c | 1 + drivers/mtd/nand/s3c2410.c | 1 + drivers/mtd/nand/sh_flctl.c | 1 + drivers/mtd/nand/sharpsl.c | 1 + drivers/mtd/nand/tmio_nand.c | 1 + drivers/mtd/nand/txx9ndfmc.c | 1 + drivers/mtd/onenand/onenand_base.c | 1 + 31 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 7ad7b054800c..a4eb8b5b85ec 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -564,6 +564,7 @@ void DoC2k_init(struct mtd_info *mtd) mtd->flags = MTD_CAP_NANDFLASH; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 7bff54e62cd5..f6927955dab0 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -348,6 +348,7 @@ void DoCMil_init(struct mtd_info *mtd) mtd->erasesize = 0x2000; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 4a03d869ad03..04eb2e4aa50f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -469,6 +469,7 @@ void DoCMilPlus_init(struct mtd_info *mtd) mtd->flags = MTD_CAP_NANDFLASH; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 2c1d0fca6757..349bbfa74d0d 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1832,6 +1832,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->_write_oob = doc_write_oob; mtd->_block_isbad = doc_block_isbad; mtd->ecclayout = &docg3_oobinfo; + mtd->ecc_strength = DOC_ECC_BCH_T; } /** diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 226d28a618d8..9651c06de0a9 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, } slave->mtd.ecclayout = master->ecclayout; + slave->mtd.ecc_strength = master->ecc_strength; if (master->_block_isbad) { uint64_t offs = 0; diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index ac38f73fde3b..4f20e1d8bef1 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c @@ -591,6 +591,7 @@ static int alauda_init_media(struct alauda *al) mtd->_block_isbad = alauda_isbad; mtd->priv = al; mtd->owner = THIS_MODULE; + mtd->ecc_strength = 1; err = mtd_device_register(mtd, NULL, 0); if (err) { diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 7769519a54a7..662abf08061a 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -554,6 +554,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->ecc.hwctl = atmel_nand_hwctl; nand_chip->ecc.read_page = atmel_nand_read_page; nand_chip->ecc.bytes = 4; + nand_chip->ecc.strength = 1; } nand_chip->chip_delay = 20; /* 20us command delay time */ diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index ee81b6333f6a..fc600431f519 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -476,6 +476,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } + + /* + * FIXME: ecc strength value of 6 bits per 512 bytes of data is a + * conservative guess, given 13 ecc bytes and using bch alg. + * (Assume Galois field order m=15 to allow a margin of error.) + */ + this->ecc.strength = 6; + #endif /* Now finish off the scan, now that ecc.layout has been initialized. */ diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index dd899cb5d366..d7b86b925de5 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -702,9 +702,11 @@ static int bf5xx_nand_scan(struct mtd_info *mtd) if (likely(mtd->writesize >= 512)) { chip->ecc.size = 512; chip->ecc.bytes = 6; + chip->ecc.strength = 2; } else { chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET)); SSYNC(); } diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index c23c07c5b391..2a96e1a12062 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -783,6 +783,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; cafe->nand.ecc.size = mtd->writesize; cafe->nand.ecc.bytes = 14; + cafe->nand.ecc.strength = 4; cafe->nand.ecc.hwctl = (void *)cafe_nand_bug; cafe->nand.ecc.calculate = (void *)cafe_nand_bug; cafe->nand.ecc.correct = (void *)cafe_nand_bug; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index e2b7c9e4c5c2..821c34c62500 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -248,6 +248,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_ior; } + this->ecc.strength = 1; + new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); cs553x_mtd[cs] = new_mtd; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index b81afc748fff..d94b03c207af 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -641,6 +641,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.bytes = 3; } info->chip.ecc.size = 512; + info->chip.ecc.strength = pdata->ecc_bits; break; default: ret = -EINVAL; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3984d488f9ab..a9e57d686297 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1590,6 +1590,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ECC_15BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE)))) { /* if MLC OOB size is large enough, use 15bit ECC*/ + denali->nand.ecc.strength = 15; denali->nand.ecc.layout = &nand_15bit_oob; denali->nand.ecc.bytes = ECC_15BITS; iowrite32(15, denali->flash_reg + ECC_CORRECTION); @@ -1600,12 +1601,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) " contain 8bit ECC correction codes"); goto failed_req_irq; } else { + denali->nand.ecc.strength = 8; denali->nand.ecc.layout = &nand_8bit_oob; denali->nand.ecc.bytes = ECC_8BITS; iowrite32(8, denali->flash_reg + ECC_CORRECTION); } denali->nand.ecc.bytes *= denali->devnum; + denali->nand.ecc.strength *= denali->devnum; denali->nand.ecc.layout->eccbytes *= denali->mtd.writesize / ECC_SECTOR_SIZE; denali->nand.ecc.layout->oobfree[0].offset = diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index df921e7a496c..e2ca067631cf 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1653,6 +1653,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; + nand->ecc.strength = 2; nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 9b3a64904668..b08202664543 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -1191,6 +1191,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->ecc.size = DOCG4_PAGE_SIZE; nand->ecc.prepad = 8; nand->ecc.bytes = 8; + nand->ecc.strength = DOCG4_T; nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 7195ee6efe12..80b5264f0a32 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -813,6 +813,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0; chip->ecc.size = 512; chip->ecc.bytes = 3; + chip->ecc.strength = 1; + /* + * FIXME: can hardware ecc correct 4 bitflips if page size is + * 2k? Then does hardware report number of corrections for this + * case? If so, ecc_stats reporting needs to be fixed as well. + */ } else { /* otherwise fall back to default software ECC */ chip->ecc.mode = NAND_ECC_SOFT; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 341086c22e90..588e3733c3a4 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -863,10 +863,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.calculate = fsmc_read_hwecc_ecc4; nand->ecc.correct = fsmc_bch8_correct_data; nand->ecc.bytes = 13; + nand->ecc.strength = 8; } else { nand->ecc.calculate = fsmc_read_hwecc_ecc1; nand->ecc.correct = nand_correct_data; nand->ecc.bytes = 3; + nand->ecc.strength = 1; } /* diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index cc50e35cdc3d..e4147e8acb7c 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -332,6 +332,11 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; chip->ecc.size = 512; chip->ecc.bytes = 9; + chip->ecc.strength = 2; + /* + * FIXME: ecc_strength value of 2 bits per 512 bytes of data is a + * conservative guess, given 9 ecc bytes and reed-solomon alg. + */ if (pdata) chip->ecc.layout = pdata->ecc_layout; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 3c4c0533191d..cc0678a967c1 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1225,6 +1225,13 @@ static int __init mxcnd_probe(struct platform_device *pdev) goto escan; } + if (this->ecc.mode == NAND_ECC_HW) { + if (nfc_is_v1()) + this->ecc.strength = 1; + else + this->ecc.strength = (host->eccsize == 4) ? 4 : 8; + } + /* Register the partitions */ mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, pdata->nr_parts); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1e907dc8638a..8008853756c9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3350,6 +3350,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.size) chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; break; case NAND_ECC_SOFT_BCH: @@ -3384,6 +3385,8 @@ int nand_scan_tail(struct mtd_info *mtd) pr_warn("BCH ECC initialization failed!\n"); BUG(); } + chip->ecc.strength = + chip->ecc.bytes*8 / fls(8*chip->ecc.size); break; case NAND_ECC_NONE: @@ -3397,6 +3400,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.write_oob = nand_write_oob_std; chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; + chip->ecc.strength = 0; break; default: @@ -3478,8 +3482,9 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->_block_markbad = nand_block_markbad; mtd->writebufsize = mtd->writesize; - /* propagate ecc.layout to mtd_info */ + /* propagate ecc info to mtd_info */ mtd->ecclayout = chip->ecc.layout; + mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ec688548c880..2b6f632cf274 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -179,6 +179,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; chip->priv = ndfc; ndfc->mtd.priv = chip; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index d2e7a7da81f8..c2b0bba9d8b3 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1058,6 +1058,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) { info->nand.ecc.bytes = 3; info->nand.ecc.size = 512; + info->nand.ecc.strength = 1; info->nand.ecc.calculate = omap_calculate_ecc; info->nand.ecc.hwctl = omap_enable_hwecc; info->nand.ecc.correct = omap_correct_data; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index d3bdc909c939..def50caa6f84 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1002,6 +1002,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) KEEP_CONFIG: chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = host->page_size; + chip->ecc.strength = 1; chip->options = NAND_NO_AUTOINCR; chip->options |= NAND_NO_READRDY; diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 769a4e096b3c..c2040187c813 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -891,6 +891,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) chip->ecc.mode = NAND_ECC_HW_SYNDROME; chip->ecc.size = R852_DMA_LEN; chip->ecc.bytes = SM_OOB_SIZE; + chip->ecc.strength = 2; chip->ecc.hwctl = r852_ecc_hwctl; chip->ecc.calculate = r852_ecc_calculate; chip->ecc.correct = r852_ecc_correct; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index f309addc2fa0..e55b5cfbe145 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -527,6 +527,7 @@ static int __init rtc_from4_init(void) this->ecc.mode = NAND_ECC_HW_SYNDROME; this->ecc.size = 512; this->ecc.bytes = 8; + this->ecc.strength = 3; /* return the status of extra status and ECC checks */ this->errstat = rtc_from4_errstat; /* set the nand_oobinfo to support FPGA H/W error detection */ diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 97623be04e0f..91121f33f743 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -823,6 +823,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->ecc.calculate = s3c2410_nand_calculate_ecc; chip->ecc.correct = s3c2410_nand_correct_data; chip->ecc.mode = NAND_ECC_HW; + chip->ecc.strength = 1; switch (info->cpu_type) { case TYPE_S3C2410: diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2ee9a1b50a22..e9b2b260de3a 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -825,6 +825,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) chip->ecc.size = 512; chip->ecc.bytes = 10; + chip->ecc.strength = 4; chip->ecc.read_page = flctl_read_page_hwecc; chip->ecc.write_page = flctl_write_page_hwecc; chip->ecc.mode = NAND_ECC_HW; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 2d269a53f8bb..3421e3762a5a 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -167,6 +167,7 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; this->ecc.bytes = 3; + this->ecc.strength = 1; this->badblock_pattern = data->badblock_pattern; this->ecc.layout = data->ecc_layout; this->ecc.hwctl = sharpsl_nand_enable_hwecc; diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 060848a91db7..5aa518081c51 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -430,6 +430,7 @@ static int tmio_probe(struct platform_device *dev) nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; nand_chip->ecc.bytes = 6; + nand_chip->ecc.strength = 2; nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; nand_chip->ecc.calculate = tmio_nand_calculate_ecc; nand_chip->ecc.correct = tmio_nand_correct_data; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 8db0acbae6fa..26398dcf21cf 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -356,6 +356,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */ chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; chip->chip_delay = 100; chip->controller = &drvdata->hw_control; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a1592cf755f3..3d781b87b358 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -4080,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->oobavail = this->ecclayout->oobavail; mtd->ecclayout = this->ecclayout; + mtd->ecc_strength = 1; /* Fill in remaining MTD driver data */ mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH; -- cgit v1.2.3 From 30053b87d5b97aca28dd7a59982cbb161eaf01c6 Mon Sep 17 00:00:00 2001 From: Ryosuke Saito Date: Thu, 15 Mar 2012 19:19:03 +0900 Subject: mtd: fix section mismatch for doc_probe_device doc_probe_device() is only called from docg3_probe() which is in .init.text, so it must be in the same section to avoid a section mismatch warning. Signed-off-by: Ryosuke Saito Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 349bbfa74d0d..f5930caa38e7 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1847,8 +1847,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is * launched. */ -static struct mtd_info *doc_probe_device(void __iomem *base, int floor, - struct device *dev) +static struct mtd_info * __init +doc_probe_device(void __iomem *base, int floor, struct device *dev) { int ret, bbt_nbpages; u16 chip_id, chip_id_inv; -- cgit v1.2.3 From a7baef1211b0ac218299965481e7cff9d68c1edd Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 22 Mar 2012 21:00:50 +0100 Subject: mtd: docg3 fix inbound calculations The last erase block was not accessible, as the out of bound check was incorrectly rejecting the last block. The read/write/erase offset checks were forbidding the usage of the last block, because of the calculation which was considering the byte after the last instead of the last byte. Signed-off-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index f5930caa38e7..62e01113c317 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -872,11 +872,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, if (ooblen % DOC_LAYOUT_OOB_SIZE) return -EINVAL; - ret = -EINVAL; - calc_block_sector(from + len, &block0, &block1, &page, &ofs, - docg3->reliable); - if (block1 > docg3->max_block) - goto err; + if (from + len > mtd->size) + return -EINVAL; ops->oobretlen = 0; ops->retlen = 0; @@ -1207,7 +1204,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) calc_block_sector(info->addr + info->len, &block0, &block1, &page, &ofs, docg3->reliable); ret = -EINVAL; - if (block1 > docg3->max_block || page || ofs) + if (info->addr + info->len > mtd->size || page || ofs) goto reset_err; ret = 0; @@ -1443,12 +1440,8 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, if (len && ooblen && (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta)) return -EINVAL; - - ret = -EINVAL; - calc_block_sector(ofs + len, &block0, &block1, &page, &pofs, - docg3->reliable); - if (block1 > docg3->max_block) - goto err; + if (ofs + len > mtd->size) + return -EINVAL; ops->oobretlen = 0; ops->retlen = 0; -- cgit v1.2.3 From a2b3d284ed65b9ada18fd2ffb66daffe9c0ff168 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 22 Mar 2012 21:00:51 +0100 Subject: mtd: docg3 increase write/erase timeout After several tries with ubifs, it appears empirically that constructor provided figures for erase/write timeouts are underestimated. A timeout of 100ms seems to work with a 5 years worn chip, and no timeouts occur anymore. Signed-off-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 62e01113c317..be88eb6217cb 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1116,10 +1116,10 @@ static int doc_get_op_status(struct docg3 *docg3) */ static int doc_write_erase_wait_status(struct docg3 *docg3) { - int status, ret = 0; + int i, status, ret = 0; - if (!doc_is_ready(docg3)) - usleep_range(3000, 3000); + for (i = 0; !doc_is_ready(docg3) && i < 5; i++) + msleep(20); if (!doc_is_ready(docg3)) { doc_dbg("Timeout reached and the chip is still not ready\n"); ret = -EAGAIN; -- cgit v1.2.3 From 1b15a5f93bbd9a6f5346cfa449720a7e32115f86 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 22 Mar 2012 21:00:52 +0100 Subject: mtd: docg3 refactor cascade floors structure Group floors into a common cascade structure. This will provide a common structure to store common data to all cascaded docg3 chips, like IO addressing, locking protection. Signed-off-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 88 +++++++++++++++++++++++---------------------- drivers/mtd/devices/docg3.h | 18 ++++++++-- 2 files changed, 61 insertions(+), 45 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index be88eb6217cb..935d4c6e9321 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -80,14 +80,9 @@ static struct nand_ecclayout docg3_oobinfo = { .oobavail = 8, }; -/** - * struct docg3_bch - BCH engine - */ -static struct bch_control *docg3_bch; - static inline u8 doc_readb(struct docg3 *docg3, u16 reg) { - u8 val = readb(docg3->base + reg); + u8 val = readb(docg3->cascade->base + reg); trace_docg3_io(0, 8, reg, (int)val); return val; @@ -95,7 +90,7 @@ static inline u8 doc_readb(struct docg3 *docg3, u16 reg) static inline u16 doc_readw(struct docg3 *docg3, u16 reg) { - u16 val = readw(docg3->base + reg); + u16 val = readw(docg3->cascade->base + reg); trace_docg3_io(0, 16, reg, (int)val); return val; @@ -103,13 +98,13 @@ static inline u16 doc_readw(struct docg3 *docg3, u16 reg) static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) { - writeb(val, docg3->base + reg); + writeb(val, docg3->cascade->base + reg); trace_docg3_io(1, 8, reg, val); } static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) { - writew(val, docg3->base + reg); + writew(val, docg3->cascade->base + reg); trace_docg3_io(1, 16, reg, val); } @@ -643,7 +638,8 @@ static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc) for (i = 0; i < DOC_ECC_BCH_SIZE; i++) ecc[i] = bitrev8(hwecc[i]); - numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES, + numerrs = decode_bch(docg3->cascade->bch, NULL, + DOC_ECC_BCH_COVERED_BYTES, NULL, ecc, NULL, errorpos); BUG_ON(numerrs == -EINVAL); if (numerrs < 0) @@ -1599,13 +1595,13 @@ static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = { }; static int doc_register_sysfs(struct platform_device *pdev, - struct mtd_info **floors) + struct docg3_cascade *cascade) { int ret = 0, floor, i = 0; struct device *dev = &pdev->dev; - for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor]; - floor++) + for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && + cascade->floors[floor]; floor++) for (i = 0; !ret && i < 4; i++) ret = device_create_file(dev, &doc_sys_attrs[floor][i]); if (!ret) @@ -1619,12 +1615,12 @@ static int doc_register_sysfs(struct platform_device *pdev, } static void doc_unregister_sysfs(struct platform_device *pdev, - struct mtd_info **floors) + struct docg3_cascade *cascade) { struct device *dev = &pdev->dev; int floor, i; - for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor]; + for (floor = 0; floor < DOC_MAX_NBFLOORS && cascade->floors[floor]; floor++) for (i = 0; i < 4; i++) device_remove_file(dev, &doc_sys_attrs[floor][i]); @@ -1833,6 +1829,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) * @base: the io space where the device is probed * @floor: the floor of the probed device * @dev: the device + * @cascade: the cascade of chips this devices will belong to * * Checks whether a device at the specified IO range, and floor is available. * @@ -1841,7 +1838,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) * launched. */ static struct mtd_info * __init -doc_probe_device(void __iomem *base, int floor, struct device *dev) +doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev) { int ret, bbt_nbpages; u16 chip_id, chip_id_inv; @@ -1864,7 +1861,7 @@ doc_probe_device(void __iomem *base, int floor, struct device *dev) docg3->dev = dev; docg3->device_id = floor; - docg3->base = base; + docg3->cascade = cascade; doc_set_device_id(docg3, docg3->device_id); if (!floor) doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); @@ -1881,7 +1878,7 @@ doc_probe_device(void __iomem *base, int floor, struct device *dev) switch (chip_id) { case DOC_CHIPID_G3: doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n", - base, floor); + docg3->cascade->base, floor); break; default: doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); @@ -1926,10 +1923,12 @@ static void doc_release_device(struct mtd_info *mtd) static int docg3_resume(struct platform_device *pdev) { int i; + struct docg3_cascade *cascade; struct mtd_info **docg3_floors, *mtd; struct docg3 *docg3; - docg3_floors = platform_get_drvdata(pdev); + cascade = platform_get_drvdata(pdev); + docg3_floors = cascade->floors; mtd = docg3_floors[0]; docg3 = mtd->priv; @@ -1951,11 +1950,13 @@ static int docg3_resume(struct platform_device *pdev) static int docg3_suspend(struct platform_device *pdev, pm_message_t state) { int floor, i; + struct docg3_cascade *cascade; struct mtd_info **docg3_floors, *mtd; struct docg3 *docg3; u8 ctrl, pwr_down; - docg3_floors = platform_get_drvdata(pdev); + cascade = platform_get_drvdata(pdev); + docg3_floors = cascade->floors; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { mtd = docg3_floors[floor]; if (!mtd) @@ -2005,7 +2006,7 @@ static int __init docg3_probe(struct platform_device *pdev) struct resource *ress; void __iomem *base; int ret, floor, found = 0; - struct mtd_info **docg3_floors; + struct docg3_cascade *cascade; ret = -ENXIO; ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2016,17 +2017,18 @@ static int __init docg3_probe(struct platform_device *pdev) base = ioremap(ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS, - GFP_KERNEL); - if (!docg3_floors) + cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, + GFP_KERNEL); + if (!cascade) goto nomem1; - docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, + cascade->base = base; + cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, DOC_ECC_BCH_PRIMPOLY); - if (!docg3_bch) + if (!cascade->bch) goto nomem2; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { - mtd = doc_probe_device(base, floor, dev); + mtd = doc_probe_device(cascade, floor, dev); if (IS_ERR(mtd)) { ret = PTR_ERR(mtd); goto err_probe; @@ -2037,7 +2039,7 @@ static int __init docg3_probe(struct platform_device *pdev) else continue; } - docg3_floors[floor] = mtd; + cascade->floors[floor] = mtd; ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); if (ret) @@ -2045,26 +2047,26 @@ static int __init docg3_probe(struct platform_device *pdev) found++; } - ret = doc_register_sysfs(pdev, docg3_floors); + ret = doc_register_sysfs(pdev, cascade); if (ret) goto err_probe; if (!found) goto notfound; - platform_set_drvdata(pdev, docg3_floors); - doc_dbg_register(docg3_floors[0]->priv); + platform_set_drvdata(pdev, cascade); + doc_dbg_register(cascade->floors[0]->priv); return 0; notfound: ret = -ENODEV; dev_info(dev, "No supported DiskOnChip found\n"); err_probe: - free_bch(docg3_bch); + kfree(cascade->bch); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) - if (docg3_floors[floor]) - doc_release_device(docg3_floors[floor]); + if (cascade->floors[floor]) + doc_release_device(cascade->floors[floor]); nomem2: - kfree(docg3_floors); + kfree(cascade); nomem1: iounmap(base); noress: @@ -2079,19 +2081,19 @@ noress: */ static int __exit docg3_release(struct platform_device *pdev) { - struct mtd_info **docg3_floors = platform_get_drvdata(pdev); - struct docg3 *docg3 = docg3_floors[0]->priv; - void __iomem *base = docg3->base; + struct docg3_cascade *cascade = platform_get_drvdata(pdev); + struct docg3 *docg3 = cascade->floors[0]->priv; + void __iomem *base = cascade->base; int floor; - doc_unregister_sysfs(pdev, docg3_floors); + doc_unregister_sysfs(pdev, cascade); doc_dbg_unregister(docg3); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) - if (docg3_floors[floor]) - doc_release_device(docg3_floors[floor]); + if (cascade->floors[floor]) + doc_release_device(cascade->floors[floor]); - kfree(docg3_floors); - free_bch(docg3_bch); + free_bch(docg3->cascade->bch); + kfree(cascade); iounmap(base); return 0; } diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h index db0da436b493..642e60667cfd 100644 --- a/drivers/mtd/devices/docg3.h +++ b/drivers/mtd/devices/docg3.h @@ -22,6 +22,8 @@ #ifndef _MTD_DOCG3_H #define _MTD_DOCG3_H +#include + /* * Flash memory areas : * - 0x0000 .. 0x07ff : IPL @@ -266,10 +268,22 @@ */ #define DOC_LAYOUT_DPS_KEY_LENGTH 8 +/** + * struct docg3_cascade - Cascade of 1 to 4 docg3 chips + * @floors: floors (ie. one physical docg3 chip is one floor) + * @base: IO space to access all chips in the cascade + * @bch: the BCH correcting control structure + */ +struct docg3_cascade { + struct mtd_info *floors[DOC_MAX_NBFLOORS]; + void __iomem *base; + struct bch_control *bch; +}; + /** * struct docg3 - DiskOnChip driver private data * @dev: the device currently under control - * @base: mapped IO space + * @cascade: the cascade this device belongs to * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) * @if_cfg: if true, reads are on 16bits, else reads are on 8bits @@ -287,7 +301,7 @@ */ struct docg3 { struct device *dev; - void __iomem *base; + struct docg3_cascade *cascade; unsigned int device_id:4; unsigned int if_cfg:1; unsigned int reliable:2; -- cgit v1.2.3 From 7b0e67f604e1829e5292e1ad7743eb18dc42ea7c Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 22 Mar 2012 21:00:53 +0100 Subject: mtd: docg3 add protection against concurrency As docg3 is intolerant against reentrancy, especially because of its weird register access (ie. a register read is performed by a first register write), each access to the docg3 IO space must be locked. Lock the IO space with a mutex, shared by all chips on the same cascade, as they all share the same IO space. Signed-off-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/docg3.c | 50 +++++++++++++++++++++++++++++++++++---------- drivers/mtd/devices/docg3.h | 2 ++ 2 files changed, 41 insertions(+), 11 deletions(-) (limited to 'drivers/mtd/devices/docg3.c') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 935d4c6e9321..8272c02668d6 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -875,6 +875,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ops->retlen = 0; ret = 0; skip = from % DOC_LAYOUT_PAGE_SIZE; + mutex_lock(&docg3->cascade->lock); while (!ret && (len > 0 || ooblen > 0)) { calc_block_sector(from - skip, &block0, &block1, &page, &ofs, docg3->reliable); @@ -882,7 +883,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); if (ret < 0) - goto err; + goto out; ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); if (ret < 0) goto err_in_read; @@ -950,11 +951,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, skip = 0; } +out: + mutex_unlock(&docg3->cascade->lock); return ret; err_in_read: doc_read_page_finish(docg3); -err: - return ret; + goto out; } /** @@ -1194,7 +1196,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) int block0, block1, page, ret, ofs = 0; doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); - doc_set_device_id(docg3, docg3->device_id); info->state = MTD_ERASE_PENDING; calc_block_sector(info->addr + info->len, &block0, &block1, &page, @@ -1206,6 +1207,8 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) ret = 0; calc_block_sector(info->addr, &block0, &block1, &page, &ofs, docg3->reliable); + mutex_lock(&docg3->cascade->lock); + doc_set_device_id(docg3, docg3->device_id); doc_set_reliable_mode(docg3); for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { info->state = MTD_ERASING; @@ -1213,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) block0 += 2; block1 += 2; } + mutex_unlock(&docg3->cascade->lock); if (ret) goto reset_err; @@ -1399,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct mtd_oob_ops *ops) { struct docg3 *docg3 = mtd->priv; - int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; + int ret, autoecc, oobdelta; u8 *oobbuf = ops->oobbuf; u8 *buf = ops->datbuf; size_t len, ooblen; @@ -1451,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, if (autoecc < 0) return autoecc; + mutex_lock(&docg3->cascade->lock); while (!ret && len > 0) { memset(oob, 0, sizeof(oob)); if (ofs == docg3->oob_write_ofs) @@ -1471,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, } ops->retlen += DOC_LAYOUT_PAGE_SIZE; } -err: + doc_set_device_id(docg3, 0); + mutex_unlock(&docg3->cascade->lock); return ret; } @@ -1529,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev, struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); int dps0; + mutex_lock(&docg3->cascade->lock); doc_set_device_id(docg3, docg3->device_id); dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); doc_set_device_id(docg3, 0); + mutex_unlock(&docg3->cascade->lock); return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); } @@ -1542,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev, struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); int dps1; + mutex_lock(&docg3->cascade->lock); doc_set_device_id(docg3, docg3->device_id); dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); doc_set_device_id(docg3, 0); + mutex_unlock(&docg3->cascade->lock); return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); } @@ -1559,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev, if (count != DOC_LAYOUT_DPS_KEY_LENGTH) return -EINVAL; + mutex_lock(&docg3->cascade->lock); doc_set_device_id(docg3, docg3->device_id); for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) doc_writeb(docg3, buf[i], DOC_DPS0_KEY); doc_set_device_id(docg3, 0); + mutex_unlock(&docg3->cascade->lock); return count; } @@ -1576,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev, if (count != DOC_LAYOUT_DPS_KEY_LENGTH) return -EINVAL; + mutex_lock(&docg3->cascade->lock); doc_set_device_id(docg3, docg3->device_id); for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) doc_writeb(docg3, buf[i], DOC_DPS1_KEY); doc_set_device_id(docg3, 0); + mutex_unlock(&docg3->cascade->lock); return count; } @@ -1634,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p) struct docg3 *docg3 = (struct docg3 *)s->private; int pos = 0; - u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + u8 fctrl; + + mutex_lock(&docg3->cascade->lock); + fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + mutex_unlock(&docg3->cascade->lock); pos += seq_printf(s, "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", @@ -1652,9 +1670,12 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; - int pos = 0; - int pctrl = doc_register_readb(docg3, DOC_ASICMODE); - int mode = pctrl & 0x03; + int pos = 0, pctrl, mode; + + mutex_lock(&docg3->cascade->lock); + pctrl = doc_register_readb(docg3, DOC_ASICMODE); + mode = pctrl & 0x03; + mutex_unlock(&docg3->cascade->lock); pos += seq_printf(s, "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", @@ -1686,7 +1707,11 @@ static int dbg_device_id_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; int pos = 0; - int id = doc_register_readb(docg3, DOC_DEVICESELECT); + int id; + + mutex_lock(&docg3->cascade->lock); + id = doc_register_readb(docg3, DOC_DEVICESELECT); + mutex_unlock(&docg3->cascade->lock); pos += seq_printf(s, "DeviceId = %d\n", id); return pos; @@ -1699,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p) int pos = 0; int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; + mutex_lock(&docg3->cascade->lock); protect = doc_register_readb(docg3, DOC_PROTECTION); dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); @@ -1706,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p) dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); + mutex_unlock(&docg3->cascade->lock); pos += seq_printf(s, "Protection = 0x%02x (", protect); @@ -2022,6 +2049,7 @@ static int __init docg3_probe(struct platform_device *pdev) if (!cascade) goto nomem1; cascade->base = base; + mutex_init(&cascade->lock); cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, DOC_ECC_BCH_PRIMPOLY); if (!cascade->bch) diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h index 642e60667cfd..19fb93f96a3a 100644 --- a/drivers/mtd/devices/docg3.h +++ b/drivers/mtd/devices/docg3.h @@ -273,11 +273,13 @@ * @floors: floors (ie. one physical docg3 chip is one floor) * @base: IO space to access all chips in the cascade * @bch: the BCH correcting control structure + * @lock: lock to protect docg3 IO space from concurrent accesses */ struct docg3_cascade { struct mtd_info *floors[DOC_MAX_NBFLOORS]; void __iomem *base; struct bch_control *bch; + struct mutex lock; }; /** -- cgit v1.2.3