diff options
Diffstat (limited to 'drivers/mtd/devices/docg3.c')
| -rw-r--r-- | drivers/mtd/devices/docg3.c | 111 |
1 files changed, 50 insertions, 61 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 8272c02668d..91a169c44b3 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -123,7 +123,7 @@ static inline void doc_flash_address(struct docg3 *docg3, u8 addr) doc_writeb(docg3, addr, DOC_FLASHADDRESS); } -static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; +static char const * const part_probes[] = { "cmdlinepart", "saftlpart", NULL }; static int doc_register_readb(struct docg3 *docg3, int reg) { @@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, u8 data8, *dst8; doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); - cdr = len & 0x3; + cdr = len & 0x1; len4 = len - cdr; if (first) @@ -383,7 +383,7 @@ static void doc_set_device_id(struct docg3 *docg3, int id) * leveling counters are stored. To access this last area of 4 bytes, a special * mode must be input to the flash ASIC. * - * Returns 0 if no error occured, -EIO else. + * Returns 0 if no error occurred, -EIO else. */ static int doc_set_extra_page_mode(struct docg3 *docg3) { @@ -681,7 +681,7 @@ out: * - one read of 512 bytes at offset 0 * - one read of 512 bytes at offset 512 + 16 * - * Returns 0 if successful, -EIO if a read error occured. + * Returns 0 if successful, -EIO if a read error occurred. */ static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, int page, int offset) @@ -732,12 +732,24 @@ err: * @len: the number of bytes to be read (must be a multiple of 4) * @buf: the buffer to be filled in (or NULL is forget bytes) * @first: 1 if first time read, DOC_READADDRESS should be set + * @last_odd: 1 if last read ended up on an odd byte + * + * Reads bytes from a prepared page. There is a trickery here : if the last read + * ended up on an odd offset in the 1024 bytes double page, ie. between the 2 + * planes, the first byte must be read apart. If a word (16bit) read was used, + * the read would return the byte of plane 2 as low *and* high endian, which + * will mess the read. * */ static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, - int first) + int first, int last_odd) { - doc_read_data_area(docg3, buf, len, first); + if (last_odd && len > 0) { + doc_read_data_area(docg3, buf, 1, first); + doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0); + } else { + doc_read_data_area(docg3, buf, len, first); + } doc_delay(docg3, 2); return len; } @@ -839,7 +851,7 @@ static void calc_block_sector(loff_t from, int *block0, int *block1, int *page, * * Reads flash memory OOB area of pages. * - * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred */ static int doc_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -850,6 +862,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, u8 *buf = ops->datbuf; size_t len, ooblen, nbdata, nboob; u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; + int max_bitflips = 0; if (buf) len = ops->len; @@ -876,7 +889,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ret = 0; skip = from % DOC_LAYOUT_PAGE_SIZE; mutex_lock(&docg3->cascade->lock); - while (!ret && (len > 0 || ooblen > 0)) { + while (ret >= 0 && (len > 0 || ooblen > 0)) { calc_block_sector(from - skip, &block0, &block1, &page, &ofs, docg3->reliable); nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); @@ -887,38 +900,32 @@ 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, skip, NULL, 1); + ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0); if (ret < skip) goto err_in_read; - ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); + ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2); if (ret < nbdata) goto err_in_read; doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata - skip, - NULL, 0); - ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); + NULL, 0, (skip + nbdata) % 2); + ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0); if (ret < nboob) goto err_in_read; doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, - NULL, 0); + NULL, 0, nboob % 2); doc_get_bch_hw_ecc(docg3, hwecc); eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); if (nboob >= DOC_LAYOUT_OOB_SIZE) { - doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - oobbuf[0], oobbuf[1], oobbuf[2], oobbuf[3], - oobbuf[4], oobbuf[5], oobbuf[6]); + doc_dbg("OOB - INFO: %*phC\n", 7, oobbuf); doc_dbg("OOB - HAMMING: %02x\n", oobbuf[7]); - doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - oobbuf[8], oobbuf[9], oobbuf[10], oobbuf[11], - oobbuf[12], oobbuf[13], oobbuf[14]); + doc_dbg("OOB - BCH_ECC: %*phC\n", 7, oobbuf + 8); doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]); } doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); - doc_dbg("ECC HW_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - hwecc[0], hwecc[1], hwecc[2], hwecc[3], hwecc[4], - hwecc[5], hwecc[6]); + doc_dbg("ECC HW_ECC: %*phC\n", 7, hwecc); ret = -EIO; if (is_prot_seq_error(docg3)) @@ -936,7 +943,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, } if (ret > 0) { mtd->ecc_stats.corrected += ret; - ret = -EUCLEAN; + max_bitflips = max(max_bitflips, ret); + ret = max_bitflips; } } @@ -971,7 +979,7 @@ err_in_read: * Reads flash memory pages. This function does not read the OOB chunk, but only * the page data. * - * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred */ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) @@ -1004,7 +1012,7 @@ static int doc_reload_bbt(struct docg3 *docg3) DOC_LAYOUT_PAGE_SIZE); if (!ret) doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, - buf, 1); + buf, 1, 0); buf += DOC_LAYOUT_PAGE_SIZE; } doc_read_page_finish(docg3); @@ -1064,10 +1072,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from) ret = doc_reset_seq(docg3); if (!ret) ret = doc_read_page_prepare(docg3, block0, block1, page, - ofs + DOC_LAYOUT_WEAR_OFFSET); + ofs + DOC_LAYOUT_WEAR_OFFSET, 0); if (!ret) ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, - buf, 1); + buf, 1, 0); doc_read_page_finish(docg3); if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) @@ -1109,7 +1117,7 @@ static int doc_get_op_status(struct docg3 *docg3) * Wait for the chip to be ready again after erase or write operation, and check * erase/write status. * - * Returns 0 if erase successfull, -EIO if erase/write issue, -ETIMEOUT if + * Returns 0 if erase successful, -EIO if erase/write issue, -ETIMEOUT if * timeout */ static int doc_write_erase_wait_status(struct docg3 *docg3) @@ -1186,7 +1194,7 @@ static int doc_erase_block(struct docg3 *docg3, int block0, int block1) * Erase a bunch of contiguous blocks, by pairs, as a "mtd" page of 1024 is * split into 2 pages of 512 bytes on 2 contiguous blocks. * - * Returns 0 if erase successful, -EINVAL if adressing error, -EIO if erase + * Returns 0 if erase successful, -EINVAL if addressing error, -EIO if erase * issue */ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) @@ -1397,7 +1405,7 @@ static int doc_backup_oob(struct docg3 *docg3, loff_t to, * Or provide data without OOB, and then a all zeroed OOB will be used (ECC will * still be filled in if asked for). * - * Returns 0 is successfull, EINVAL if length is not 14 bytes + * Returns 0 is successful, EINVAL if length is not 14 bytes */ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct mtd_oob_ops *ops) @@ -1432,7 +1440,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, oobdelta = mtd->ecclayout->oobavail; break; default: - oobdelta = 0; + return -EINVAL; } if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) || (ofs % DOC_LAYOUT_PAGE_SIZE)) @@ -1600,8 +1608,8 @@ static ssize_t dps1_insert_key(struct device *dev, #define FLOOR_SYSFS(id) { \ __ATTR(f##id##_dps0_is_keylocked, S_IRUGO, dps0_is_key_locked, NULL), \ __ATTR(f##id##_dps1_is_keylocked, S_IRUGO, dps1_is_key_locked, NULL), \ - __ATTR(f##id##_dps0_protection_key, S_IWUGO, NULL, dps0_insert_key), \ - __ATTR(f##id##_dps1_protection_key, S_IWUGO, NULL, dps1_insert_key), \ + __ATTR(f##id##_dps0_protection_key, S_IWUSR|S_IWGRP, NULL, dps0_insert_key), \ + __ATTR(f##id##_dps1_protection_key, S_IWUSR|S_IWGRP, NULL, dps1_insert_key), \ } static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = { @@ -1945,7 +1953,7 @@ static void doc_release_device(struct mtd_info *mtd) * docg3_resume - Awakens docg3 floor * @pdev: platfrom device * - * Returns 0 (always successfull) + * Returns 0 (always successful) */ static int docg3_resume(struct platform_device *pdev) { @@ -2039,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev) ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ress) { dev_err(dev, "No I/O memory resource defined\n"); - goto noress; + return ret; } - base = ioremap(ress->start, DOC_IOSPACE_SIZE); + base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, - GFP_KERNEL); + cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, + GFP_KERNEL); if (!cascade) - goto nomem1; + return ret; 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) - goto nomem2; + return ret; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { mtd = doc_probe_device(cascade, floor, dev); @@ -2089,15 +2097,10 @@ notfound: ret = -ENODEV; dev_info(dev, "No supported DiskOnChip found\n"); err_probe: - kfree(cascade->bch); + free_bch(cascade->bch); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); -nomem2: - kfree(cascade); -nomem1: - iounmap(base); -noress: return ret; } @@ -2111,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev) { 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, cascade); @@ -2121,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev) doc_release_device(cascade->floors[floor]); free_bch(docg3->cascade->bch); - kfree(cascade); - iounmap(base); return 0; } @@ -2136,18 +2136,7 @@ static struct platform_driver g3_driver = { .remove = __exit_p(docg3_release), }; -static int __init docg3_init(void) -{ - return platform_driver_probe(&g3_driver, docg3_probe); -} -module_init(docg3_init); - - -static void __exit docg3_exit(void) -{ - platform_driver_unregister(&g3_driver); -} -module_exit(docg3_exit); +module_platform_driver_probe(g3_driver, docg3_probe); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); |
