aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2012-03-22 16:00:53 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-03-26 20:03:27 -0400
commit7b0e67f604e1829e5292e1ad7743eb18dc42ea7c (patch)
tree48cb065f253ed6552e8e5805bba7647eb25a8ad7
parent1b15a5f93bbd9a6f5346cfa449720a7e32115f86 (diff)
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 <robert.jarzmik@free.fr> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/devices/docg3.c50
-rw-r--r--drivers/mtd/devices/docg3.h2
2 files changed, 41 insertions, 11 deletions
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,
875 ops->retlen = 0; 875 ops->retlen = 0;
876 ret = 0; 876 ret = 0;
877 skip = from % DOC_LAYOUT_PAGE_SIZE; 877 skip = from % DOC_LAYOUT_PAGE_SIZE;
878 mutex_lock(&docg3->cascade->lock);
878 while (!ret && (len > 0 || ooblen > 0)) { 879 while (!ret && (len > 0 || ooblen > 0)) {
879 calc_block_sector(from - skip, &block0, &block1, &page, &ofs, 880 calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
880 docg3->reliable); 881 docg3->reliable);
@@ -882,7 +883,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
882 nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); 883 nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
883 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); 884 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
884 if (ret < 0) 885 if (ret < 0)
885 goto err; 886 goto out;
886 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); 887 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
887 if (ret < 0) 888 if (ret < 0)
888 goto err_in_read; 889 goto err_in_read;
@@ -950,11 +951,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
950 skip = 0; 951 skip = 0;
951 } 952 }
952 953
954out:
955 mutex_unlock(&docg3->cascade->lock);
953 return ret; 956 return ret;
954err_in_read: 957err_in_read:
955 doc_read_page_finish(docg3); 958 doc_read_page_finish(docg3);
956err: 959 goto out;
957 return ret;
958} 960}
959 961
960/** 962/**
@@ -1194,7 +1196,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
1194 int block0, block1, page, ret, ofs = 0; 1196 int block0, block1, page, ret, ofs = 0;
1195 1197
1196 doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); 1198 doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len);
1197 doc_set_device_id(docg3, docg3->device_id);
1198 1199
1199 info->state = MTD_ERASE_PENDING; 1200 info->state = MTD_ERASE_PENDING;
1200 calc_block_sector(info->addr + info->len, &block0, &block1, &page, 1201 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)
1206 ret = 0; 1207 ret = 0;
1207 calc_block_sector(info->addr, &block0, &block1, &page, &ofs, 1208 calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
1208 docg3->reliable); 1209 docg3->reliable);
1210 mutex_lock(&docg3->cascade->lock);
1211 doc_set_device_id(docg3, docg3->device_id);
1209 doc_set_reliable_mode(docg3); 1212 doc_set_reliable_mode(docg3);
1210 for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { 1213 for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
1211 info->state = MTD_ERASING; 1214 info->state = MTD_ERASING;
@@ -1213,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
1213 block0 += 2; 1216 block0 += 2;
1214 block1 += 2; 1217 block1 += 2;
1215 } 1218 }
1219 mutex_unlock(&docg3->cascade->lock);
1216 1220
1217 if (ret) 1221 if (ret)
1218 goto reset_err; 1222 goto reset_err;
@@ -1399,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
1399 struct mtd_oob_ops *ops) 1403 struct mtd_oob_ops *ops)
1400{ 1404{
1401 struct docg3 *docg3 = mtd->priv; 1405 struct docg3 *docg3 = mtd->priv;
1402 int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; 1406 int ret, autoecc, oobdelta;
1403 u8 *oobbuf = ops->oobbuf; 1407 u8 *oobbuf = ops->oobbuf;
1404 u8 *buf = ops->datbuf; 1408 u8 *buf = ops->datbuf;
1405 size_t len, ooblen; 1409 size_t len, ooblen;
@@ -1451,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
1451 if (autoecc < 0) 1455 if (autoecc < 0)
1452 return autoecc; 1456 return autoecc;
1453 1457
1458 mutex_lock(&docg3->cascade->lock);
1454 while (!ret && len > 0) { 1459 while (!ret && len > 0) {
1455 memset(oob, 0, sizeof(oob)); 1460 memset(oob, 0, sizeof(oob));
1456 if (ofs == docg3->oob_write_ofs) 1461 if (ofs == docg3->oob_write_ofs)
@@ -1471,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
1471 } 1476 }
1472 ops->retlen += DOC_LAYOUT_PAGE_SIZE; 1477 ops->retlen += DOC_LAYOUT_PAGE_SIZE;
1473 } 1478 }
1474err: 1479
1475 doc_set_device_id(docg3, 0); 1480 doc_set_device_id(docg3, 0);
1481 mutex_unlock(&docg3->cascade->lock);
1476 return ret; 1482 return ret;
1477} 1483}
1478 1484
@@ -1529,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev,
1529 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); 1535 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
1530 int dps0; 1536 int dps0;
1531 1537
1538 mutex_lock(&docg3->cascade->lock);
1532 doc_set_device_id(docg3, docg3->device_id); 1539 doc_set_device_id(docg3, docg3->device_id);
1533 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); 1540 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
1534 doc_set_device_id(docg3, 0); 1541 doc_set_device_id(docg3, 0);
1542 mutex_unlock(&docg3->cascade->lock);
1535 1543
1536 return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); 1544 return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
1537} 1545}
@@ -1542,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev,
1542 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); 1550 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
1543 int dps1; 1551 int dps1;
1544 1552
1553 mutex_lock(&docg3->cascade->lock);
1545 doc_set_device_id(docg3, docg3->device_id); 1554 doc_set_device_id(docg3, docg3->device_id);
1546 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); 1555 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
1547 doc_set_device_id(docg3, 0); 1556 doc_set_device_id(docg3, 0);
1557 mutex_unlock(&docg3->cascade->lock);
1548 1558
1549 return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); 1559 return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
1550} 1560}
@@ -1559,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev,
1559 if (count != DOC_LAYOUT_DPS_KEY_LENGTH) 1569 if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
1560 return -EINVAL; 1570 return -EINVAL;
1561 1571
1572 mutex_lock(&docg3->cascade->lock);
1562 doc_set_device_id(docg3, docg3->device_id); 1573 doc_set_device_id(docg3, docg3->device_id);
1563 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) 1574 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
1564 doc_writeb(docg3, buf[i], DOC_DPS0_KEY); 1575 doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
1565 doc_set_device_id(docg3, 0); 1576 doc_set_device_id(docg3, 0);
1577 mutex_unlock(&docg3->cascade->lock);
1566 return count; 1578 return count;
1567} 1579}
1568 1580
@@ -1576,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev,
1576 if (count != DOC_LAYOUT_DPS_KEY_LENGTH) 1588 if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
1577 return -EINVAL; 1589 return -EINVAL;
1578 1590
1591 mutex_lock(&docg3->cascade->lock);
1579 doc_set_device_id(docg3, docg3->device_id); 1592 doc_set_device_id(docg3, docg3->device_id);
1580 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) 1593 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
1581 doc_writeb(docg3, buf[i], DOC_DPS1_KEY); 1594 doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
1582 doc_set_device_id(docg3, 0); 1595 doc_set_device_id(docg3, 0);
1596 mutex_unlock(&docg3->cascade->lock);
1583 return count; 1597 return count;
1584} 1598}
1585 1599
@@ -1634,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
1634 struct docg3 *docg3 = (struct docg3 *)s->private; 1648 struct docg3 *docg3 = (struct docg3 *)s->private;
1635 1649
1636 int pos = 0; 1650 int pos = 0;
1637 u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); 1651 u8 fctrl;
1652
1653 mutex_lock(&docg3->cascade->lock);
1654 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
1655 mutex_unlock(&docg3->cascade->lock);
1638 1656
1639 pos += seq_printf(s, 1657 pos += seq_printf(s,
1640 "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", 1658 "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)
1652{ 1670{
1653 struct docg3 *docg3 = (struct docg3 *)s->private; 1671 struct docg3 *docg3 = (struct docg3 *)s->private;
1654 1672
1655 int pos = 0; 1673 int pos = 0, pctrl, mode;
1656 int pctrl = doc_register_readb(docg3, DOC_ASICMODE); 1674
1657 int mode = pctrl & 0x03; 1675 mutex_lock(&docg3->cascade->lock);
1676 pctrl = doc_register_readb(docg3, DOC_ASICMODE);
1677 mode = pctrl & 0x03;
1678 mutex_unlock(&docg3->cascade->lock);
1658 1679
1659 pos += seq_printf(s, 1680 pos += seq_printf(s,
1660 "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", 1681 "%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)
1686{ 1707{
1687 struct docg3 *docg3 = (struct docg3 *)s->private; 1708 struct docg3 *docg3 = (struct docg3 *)s->private;
1688 int pos = 0; 1709 int pos = 0;
1689 int id = doc_register_readb(docg3, DOC_DEVICESELECT); 1710 int id;
1711
1712 mutex_lock(&docg3->cascade->lock);
1713 id = doc_register_readb(docg3, DOC_DEVICESELECT);
1714 mutex_unlock(&docg3->cascade->lock);
1690 1715
1691 pos += seq_printf(s, "DeviceId = %d\n", id); 1716 pos += seq_printf(s, "DeviceId = %d\n", id);
1692 return pos; 1717 return pos;
@@ -1699,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
1699 int pos = 0; 1724 int pos = 0;
1700 int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; 1725 int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
1701 1726
1727 mutex_lock(&docg3->cascade->lock);
1702 protect = doc_register_readb(docg3, DOC_PROTECTION); 1728 protect = doc_register_readb(docg3, DOC_PROTECTION);
1703 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); 1729 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
1704 dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); 1730 dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
@@ -1706,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
1706 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); 1732 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
1707 dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); 1733 dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
1708 dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); 1734 dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
1735 mutex_unlock(&docg3->cascade->lock);
1709 1736
1710 pos += seq_printf(s, "Protection = 0x%02x (", 1737 pos += seq_printf(s, "Protection = 0x%02x (",
1711 protect); 1738 protect);
@@ -2022,6 +2049,7 @@ static int __init docg3_probe(struct platform_device *pdev)
2022 if (!cascade) 2049 if (!cascade)
2023 goto nomem1; 2050 goto nomem1;
2024 cascade->base = base; 2051 cascade->base = base;
2052 mutex_init(&cascade->lock);
2025 cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, 2053 cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
2026 DOC_ECC_BCH_PRIMPOLY); 2054 DOC_ECC_BCH_PRIMPOLY);
2027 if (!cascade->bch) 2055 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 @@
273 * @floors: floors (ie. one physical docg3 chip is one floor) 273 * @floors: floors (ie. one physical docg3 chip is one floor)
274 * @base: IO space to access all chips in the cascade 274 * @base: IO space to access all chips in the cascade
275 * @bch: the BCH correcting control structure 275 * @bch: the BCH correcting control structure
276 * @lock: lock to protect docg3 IO space from concurrent accesses
276 */ 277 */
277struct docg3_cascade { 278struct docg3_cascade {
278 struct mtd_info *floors[DOC_MAX_NBFLOORS]; 279 struct mtd_info *floors[DOC_MAX_NBFLOORS];
279 void __iomem *base; 280 void __iomem *base;
280 struct bch_control *bch; 281 struct bch_control *bch;
282 struct mutex lock;
281}; 283};
282 284
283/** 285/**