Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Robert Jarzmik and committed by
David Woodhouse
7b0e67f6 1b15a5f9

+41 -11
+39 -11
drivers/mtd/devices/docg3.c
··· 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); ··· 883 882 nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); 884 883 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); 885 884 if (ret < 0) 886 - goto err; 885 + goto out; 887 886 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); 888 887 if (ret < 0) 889 888 goto err_in_read; ··· 951 950 skip = 0; 952 951 } 953 952 953 + out: 954 + mutex_unlock(&docg3->cascade->lock); 954 955 return ret; 955 956 err_in_read: 956 957 doc_read_page_finish(docg3); 957 - err: 958 - return ret; 958 + goto out; 959 959 } 960 960 961 961 /** ··· 1196 1194 int block0, block1, page, ret, ofs = 0; 1197 1195 1198 1196 doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); 1199 - doc_set_device_id(docg3, docg3->device_id); 1200 1197 1201 1198 info->state = MTD_ERASE_PENDING; 1202 1199 calc_block_sector(info->addr + info->len, &block0, &block1, &page, ··· 1207 1206 ret = 0; 1208 1207 calc_block_sector(info->addr, &block0, &block1, &page, &ofs, 1209 1208 docg3->reliable); 1209 + mutex_lock(&docg3->cascade->lock); 1210 + doc_set_device_id(docg3, docg3->device_id); 1210 1211 doc_set_reliable_mode(docg3); 1211 1212 for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { 1212 1213 info->state = MTD_ERASING; ··· 1216 1213 block0 += 2; 1217 1214 block1 += 2; 1218 1215 } 1216 + mutex_unlock(&docg3->cascade->lock); 1219 1217 1220 1218 if (ret) 1221 1219 goto reset_err; ··· 1403 1399 struct mtd_oob_ops *ops) 1404 1400 { 1405 1401 struct docg3 *docg3 = mtd->priv; 1406 - int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; 1402 + int ret, autoecc, oobdelta; 1407 1403 u8 *oobbuf = ops->oobbuf; 1408 1404 u8 *buf = ops->datbuf; 1409 1405 size_t len, ooblen; ··· 1455 1451 if (autoecc < 0) 1456 1452 return autoecc; 1457 1453 1454 + mutex_lock(&docg3->cascade->lock); 1458 1455 while (!ret && len > 0) { 1459 1456 memset(oob, 0, sizeof(oob)); 1460 1457 if (ofs == docg3->oob_write_ofs) ··· 1476 1471 } 1477 1472 ops->retlen += DOC_LAYOUT_PAGE_SIZE; 1478 1473 } 1479 - err: 1474 + 1480 1475 doc_set_device_id(docg3, 0); 1476 + mutex_unlock(&docg3->cascade->lock); 1481 1477 return ret; 1482 1478 } 1483 1479 ··· 1535 1529 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); 1536 1530 int dps0; 1537 1531 1532 + mutex_lock(&docg3->cascade->lock); 1538 1533 doc_set_device_id(docg3, docg3->device_id); 1539 1534 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); 1540 1535 doc_set_device_id(docg3, 0); 1536 + mutex_unlock(&docg3->cascade->lock); 1541 1537 1542 1538 return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); 1543 1539 } ··· 1550 1542 struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); 1551 1543 int dps1; 1552 1544 1545 + mutex_lock(&docg3->cascade->lock); 1553 1546 doc_set_device_id(docg3, docg3->device_id); 1554 1547 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); 1555 1548 doc_set_device_id(docg3, 0); 1549 + mutex_unlock(&docg3->cascade->lock); 1556 1550 1557 1551 return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); 1558 1552 } ··· 1569 1559 if (count != DOC_LAYOUT_DPS_KEY_LENGTH) 1570 1560 return -EINVAL; 1571 1561 1562 + mutex_lock(&docg3->cascade->lock); 1572 1563 doc_set_device_id(docg3, docg3->device_id); 1573 1564 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) 1574 1565 doc_writeb(docg3, buf[i], DOC_DPS0_KEY); 1575 1566 doc_set_device_id(docg3, 0); 1567 + mutex_unlock(&docg3->cascade->lock); 1576 1568 return count; 1577 1569 } 1578 1570 ··· 1588 1576 if (count != DOC_LAYOUT_DPS_KEY_LENGTH) 1589 1577 return -EINVAL; 1590 1578 1579 + mutex_lock(&docg3->cascade->lock); 1591 1580 doc_set_device_id(docg3, docg3->device_id); 1592 1581 for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) 1593 1582 doc_writeb(docg3, buf[i], DOC_DPS1_KEY); 1594 1583 doc_set_device_id(docg3, 0); 1584 + mutex_unlock(&docg3->cascade->lock); 1595 1585 return count; 1596 1586 } 1597 1587 ··· 1648 1634 struct docg3 *docg3 = (struct docg3 *)s->private; 1649 1635 1650 1636 int pos = 0; 1651 - u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); 1637 + u8 fctrl; 1638 + 1639 + mutex_lock(&docg3->cascade->lock); 1640 + fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); 1641 + mutex_unlock(&docg3->cascade->lock); 1652 1642 1653 1643 pos += seq_printf(s, 1654 1644 "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", ··· 1670 1652 { 1671 1653 struct docg3 *docg3 = (struct docg3 *)s->private; 1672 1654 1673 - int pos = 0; 1674 - int pctrl = doc_register_readb(docg3, DOC_ASICMODE); 1675 - int mode = pctrl & 0x03; 1655 + int pos = 0, pctrl, mode; 1656 + 1657 + mutex_lock(&docg3->cascade->lock); 1658 + pctrl = doc_register_readb(docg3, DOC_ASICMODE); 1659 + mode = pctrl & 0x03; 1660 + mutex_unlock(&docg3->cascade->lock); 1676 1661 1677 1662 pos += seq_printf(s, 1678 1663 "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", ··· 1707 1686 { 1708 1687 struct docg3 *docg3 = (struct docg3 *)s->private; 1709 1688 int pos = 0; 1710 - int id = doc_register_readb(docg3, DOC_DEVICESELECT); 1689 + int id; 1690 + 1691 + mutex_lock(&docg3->cascade->lock); 1692 + id = doc_register_readb(docg3, DOC_DEVICESELECT); 1693 + mutex_unlock(&docg3->cascade->lock); 1711 1694 1712 1695 pos += seq_printf(s, "DeviceId = %d\n", id); 1713 1696 return pos; ··· 1724 1699 int pos = 0; 1725 1700 int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; 1726 1701 1702 + mutex_lock(&docg3->cascade->lock); 1727 1703 protect = doc_register_readb(docg3, DOC_PROTECTION); 1728 1704 dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); 1729 1705 dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); ··· 1732 1706 dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); 1733 1707 dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); 1734 1708 dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); 1709 + mutex_unlock(&docg3->cascade->lock); 1735 1710 1736 1711 pos += seq_printf(s, "Protection = 0x%02x (", 1737 1712 protect); ··· 2049 2022 if (!cascade) 2050 2023 goto nomem1; 2051 2024 cascade->base = base; 2025 + mutex_init(&cascade->lock); 2052 2026 cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, 2053 2027 DOC_ECC_BCH_PRIMPOLY); 2054 2028 if (!cascade->bch)
+2
drivers/mtd/devices/docg3.h
··· 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 /**