Commit 7b0e67f604e1829e5292e1ad7743eb18dc42ea7c
Committed by
David Woodhouse
1 parent
1b15a5f93b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 | /** |