diff options
Diffstat (limited to 'drivers/mtd/devices/docg3.c')
| -rw-r--r-- | drivers/mtd/devices/docg3.c | 294 |
1 files changed, 156 insertions, 138 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index ad11ef0a81f..91a169c44b3 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); } @@ -128,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) { @@ -232,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) @@ -388,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) { @@ -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) @@ -685,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) @@ -734,14 +730,26 @@ 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 + * @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; } @@ -843,17 +851,18 @@ 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) { 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; u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; + int max_bitflips = 0; if (buf) len = ops->len; @@ -869,58 +878,54 @@ 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; - 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; ret = 0; - while (!ret && (len > 0 || ooblen > 0)) { - calc_block_sector(from, &block0, &block1, &page, &ofs, + skip = from % DOC_LAYOUT_PAGE_SIZE; + mutex_lock(&docg3->cascade->lock); + while (ret >= 0 && (len > 0 || ooblen > 0)) { + 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) - goto err; + goto out; 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, 0); + if (ret < skip) + goto err_in_read; + 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, - NULL, 0); - ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); + doc_read_page_getbytes(docg3, + DOC_LAYOUT_PAGE_SIZE - nbdata - skip, + 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)) @@ -938,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; } } @@ -950,13 +956,15 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, len -= nbdata; ooblen -= nboob; from += DOC_LAYOUT_PAGE_SIZE; + skip = 0; } +out: + mutex_unlock(&docg3->cascade->lock); return ret; err_in_read: doc_read_page_finish(docg3); -err: - return ret; + goto out; } /** @@ -971,7 +979,7 @@ err: * 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,15 +1117,15 @@ 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) { - 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; @@ -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) @@ -1196,18 +1204,19 @@ 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, &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; 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; @@ -1215,6 +1224,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; @@ -1395,13 +1405,13 @@ 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) { 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; @@ -1430,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)) @@ -1438,12 +1448,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; @@ -1457,6 +1463,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) @@ -1477,8 +1484,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; } @@ -1535,9 +1543,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)); } @@ -1548,9 +1558,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)); } @@ -1565,10 +1577,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; } @@ -1582,18 +1596,20 @@ 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; } #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] = { @@ -1601,13 +1617,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) @@ -1621,12 +1637,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]); @@ -1640,7 +1656,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", @@ -1658,9 +1678,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 (", @@ -1692,7 +1715,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; @@ -1705,6 +1732,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); @@ -1712,6 +1740,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); @@ -1804,7 +1833,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; @@ -1817,16 +1846,17 @@ 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; - 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; + mtd->ecc_strength = DOC_ECC_BCH_T; } /** @@ -1834,6 +1864,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,8 +1872,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(struct docg3_cascade *cascade, int floor, struct device *dev) { int ret, bbt_nbpages; u16 chip_id, chip_id_inv; @@ -1865,7 +1896,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor, 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); @@ -1882,7 +1913,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor, 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); @@ -1922,15 +1953,17 @@ 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) { 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; @@ -1952,11 +1985,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) @@ -2006,28 +2041,30 @@ 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); 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; - docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS, + cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, GFP_KERNEL); - if (!docg3_floors) - goto nomem1; - docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, + if (!cascade) + 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 (!docg3_bch) - goto nomem2; + if (!cascade->bch) + return ret; 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; @@ -2038,7 +2075,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) @@ -2046,29 +2083,24 @@ 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); + free_bch(cascade->bch); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) - if (docg3_floors[floor]) - doc_release_device(docg3_floors[floor]); -nomem2: - kfree(docg3_floors); -nomem1: - iounmap(base); -noress: + if (cascade->floors[floor]) + doc_release_device(cascade->floors[floor]); return ret; } @@ -2080,20 +2112,17 @@ 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; 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); - iounmap(base); + free_bch(docg3->cascade->bch); return 0; } @@ -2107,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>"); |
