Commit 7b0e67f6 authored by Robert Jarzmik's avatar Robert Jarzmik Committed by David Woodhouse

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: default avatarRobert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 1b15a5f9
...@@ -875,6 +875,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -875,6 +875,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
ops->retlen = 0; ops->retlen = 0;
ret = 0; ret = 0;
skip = from % DOC_LAYOUT_PAGE_SIZE; skip = from % DOC_LAYOUT_PAGE_SIZE;
mutex_lock(&docg3->cascade->lock);
while (!ret && (len > 0 || ooblen > 0)) { while (!ret && (len > 0 || ooblen > 0)) {
calc_block_sector(from - skip, &block0, &block1, &page, &ofs, calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
docg3->reliable); docg3->reliable);
...@@ -882,7 +883,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -882,7 +883,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
if (ret < 0) if (ret < 0)
goto err; goto out;
ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
if (ret < 0) if (ret < 0)
goto err_in_read; goto err_in_read;
...@@ -950,11 +951,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -950,11 +951,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
skip = 0; skip = 0;
} }
out:
mutex_unlock(&docg3->cascade->lock);
return ret; return ret;
err_in_read: err_in_read:
doc_read_page_finish(docg3); doc_read_page_finish(docg3);
err: goto out;
return ret;
} }
/** /**
...@@ -1194,7 +1196,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) ...@@ -1194,7 +1196,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
int block0, block1, page, ret, ofs = 0; int block0, block1, page, ret, ofs = 0;
doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); 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; info->state = MTD_ERASE_PENDING;
calc_block_sector(info->addr + info->len, &block0, &block1, &page, 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,6 +1207,8 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
ret = 0; ret = 0;
calc_block_sector(info->addr, &block0, &block1, &page, &ofs, calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
docg3->reliable); docg3->reliable);
mutex_lock(&docg3->cascade->lock);
doc_set_device_id(docg3, docg3->device_id);
doc_set_reliable_mode(docg3); doc_set_reliable_mode(docg3);
for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
info->state = MTD_ERASING; info->state = MTD_ERASING;
...@@ -1213,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) ...@@ -1213,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
block0 += 2; block0 += 2;
block1 += 2; block1 += 2;
} }
mutex_unlock(&docg3->cascade->lock);
if (ret) if (ret)
goto reset_err; goto reset_err;
...@@ -1399,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1399,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct docg3 *docg3 = mtd->priv; struct docg3 *docg3 = mtd->priv;
int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; int ret, autoecc, oobdelta;
u8 *oobbuf = ops->oobbuf; u8 *oobbuf = ops->oobbuf;
u8 *buf = ops->datbuf; u8 *buf = ops->datbuf;
size_t len, ooblen; size_t len, ooblen;
...@@ -1451,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1451,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
if (autoecc < 0) if (autoecc < 0)
return autoecc; return autoecc;
mutex_lock(&docg3->cascade->lock);
while (!ret && len > 0) { while (!ret && len > 0) {
memset(oob, 0, sizeof(oob)); memset(oob, 0, sizeof(oob));
if (ofs == docg3->oob_write_ofs) if (ofs == docg3->oob_write_ofs)
...@@ -1471,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1471,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
} }
ops->retlen += DOC_LAYOUT_PAGE_SIZE; ops->retlen += DOC_LAYOUT_PAGE_SIZE;
} }
err:
doc_set_device_id(docg3, 0); doc_set_device_id(docg3, 0);
mutex_unlock(&docg3->cascade->lock);
return ret; return ret;
} }
...@@ -1529,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev, ...@@ -1529,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev,
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
int dps0; int dps0;
mutex_lock(&docg3->cascade->lock);
doc_set_device_id(docg3, docg3->device_id); doc_set_device_id(docg3, docg3->device_id);
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
doc_set_device_id(docg3, 0); doc_set_device_id(docg3, 0);
mutex_unlock(&docg3->cascade->lock);
return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
} }
...@@ -1542,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev, ...@@ -1542,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev,
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
int dps1; int dps1;
mutex_lock(&docg3->cascade->lock);
doc_set_device_id(docg3, docg3->device_id); doc_set_device_id(docg3, docg3->device_id);
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
doc_set_device_id(docg3, 0); doc_set_device_id(docg3, 0);
mutex_unlock(&docg3->cascade->lock);
return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
} }
...@@ -1559,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev, ...@@ -1559,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev,
if (count != DOC_LAYOUT_DPS_KEY_LENGTH) if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
return -EINVAL; return -EINVAL;
mutex_lock(&docg3->cascade->lock);
doc_set_device_id(docg3, docg3->device_id); doc_set_device_id(docg3, docg3->device_id);
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
doc_writeb(docg3, buf[i], DOC_DPS0_KEY); doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
doc_set_device_id(docg3, 0); doc_set_device_id(docg3, 0);
mutex_unlock(&docg3->cascade->lock);
return count; return count;
} }
...@@ -1576,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev, ...@@ -1576,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev,
if (count != DOC_LAYOUT_DPS_KEY_LENGTH) if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
return -EINVAL; return -EINVAL;
mutex_lock(&docg3->cascade->lock);
doc_set_device_id(docg3, docg3->device_id); doc_set_device_id(docg3, docg3->device_id);
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
doc_writeb(docg3, buf[i], DOC_DPS1_KEY); doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
doc_set_device_id(docg3, 0); doc_set_device_id(docg3, 0);
mutex_unlock(&docg3->cascade->lock);
return count; return count;
} }
...@@ -1634,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p) ...@@ -1634,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0; 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, pos += seq_printf(s,
"FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", "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,9 +1670,12 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0; int pos = 0, pctrl, mode;
int pctrl = doc_register_readb(docg3, DOC_ASICMODE);
int mode = pctrl & 0x03; mutex_lock(&docg3->cascade->lock);
pctrl = doc_register_readb(docg3, DOC_ASICMODE);
mode = pctrl & 0x03;
mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, pos += seq_printf(s,
"%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", "%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,7 +1707,11 @@ static int dbg_device_id_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0; 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); pos += seq_printf(s, "DeviceId = %d\n", id);
return pos; return pos;
...@@ -1699,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p) ...@@ -1699,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
int pos = 0; int pos = 0;
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
mutex_lock(&docg3->cascade->lock);
protect = doc_register_readb(docg3, DOC_PROTECTION); protect = doc_register_readb(docg3, DOC_PROTECTION);
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); 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,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, "Protection = 0x%02x (", pos += seq_printf(s, "Protection = 0x%02x (",
protect); protect);
...@@ -2022,6 +2049,7 @@ static int __init docg3_probe(struct platform_device *pdev) ...@@ -2022,6 +2049,7 @@ static int __init docg3_probe(struct platform_device *pdev)
if (!cascade) if (!cascade)
goto nomem1; goto nomem1;
cascade->base = base; cascade->base = base;
mutex_init(&cascade->lock);
cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
DOC_ECC_BCH_PRIMPOLY); DOC_ECC_BCH_PRIMPOLY);
if (!cascade->bch) if (!cascade->bch)
......
...@@ -273,11 +273,13 @@ ...@@ -273,11 +273,13 @@
* @floors: floors (ie. one physical docg3 chip is one floor) * @floors: floors (ie. one physical docg3 chip is one floor)
* @base: IO space to access all chips in the cascade * @base: IO space to access all chips in the cascade
* @bch: the BCH correcting control structure * @bch: the BCH correcting control structure
* @lock: lock to protect docg3 IO space from concurrent accesses
*/ */
struct docg3_cascade { struct docg3_cascade {
struct mtd_info *floors[DOC_MAX_NBFLOORS]; struct mtd_info *floors[DOC_MAX_NBFLOORS];
void __iomem *base; void __iomem *base;
struct bch_control *bch; struct bch_control *bch;
struct mutex lock;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment