Commit 7b0e67f604e1829e5292e1ad7743eb18dc42ea7c

Authored by Robert Jarzmik
Committed by David Woodhouse
1 parent 1b15a5f93b

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>

Showing 2 changed files with 41 additions and 11 deletions Side-by-side Diff

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