mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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>
This commit is contained in:
parent
1b15a5f93b
commit
7b0e67f604
2 changed files with 41 additions and 11 deletions
|
@ -875,6 +875,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
|||
ops->retlen = 0;
|
||||
ret = 0;
|
||||
skip = from % DOC_LAYOUT_PAGE_SIZE;
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
while (!ret && (len > 0 || ooblen > 0)) {
|
||||
calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
|
||||
docg3->reliable);
|
||||
|
@ -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);
|
||||
ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto out;
|
||||
ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
|
||||
if (ret < 0)
|
||||
goto err_in_read;
|
||||
|
@ -950,11 +951,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
|||
skip = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
return ret;
|
||||
err_in_read:
|
||||
doc_read_page_finish(docg3);
|
||||
err:
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1194,7 +1196,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
|
|||
int block0, block1, page, ret, ofs = 0;
|
||||
|
||||
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;
|
||||
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)
|
|||
ret = 0;
|
||||
calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
|
||||
docg3->reliable);
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
doc_set_device_id(docg3, docg3->device_id);
|
||||
doc_set_reliable_mode(docg3);
|
||||
for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
|
||||
info->state = MTD_ERASING;
|
||||
|
@ -1213,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
|
|||
block0 += 2;
|
||||
block1 += 2;
|
||||
}
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
|
||||
if (ret)
|
||||
goto reset_err;
|
||||
|
@ -1399,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct docg3 *docg3 = mtd->priv;
|
||||
int block0, block1, page, ret, pofs = 0, autoecc, oobdelta;
|
||||
int ret, autoecc, oobdelta;
|
||||
u8 *oobbuf = ops->oobbuf;
|
||||
u8 *buf = ops->datbuf;
|
||||
size_t len, ooblen;
|
||||
|
@ -1451,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||
if (autoecc < 0)
|
||||
return autoecc;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
while (!ret && len > 0) {
|
||||
memset(oob, 0, sizeof(oob));
|
||||
if (ofs == docg3->oob_write_ofs)
|
||||
|
@ -1471,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||
}
|
||||
ops->retlen += DOC_LAYOUT_PAGE_SIZE;
|
||||
}
|
||||
err:
|
||||
|
||||
doc_set_device_id(docg3, 0);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1529,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev,
|
|||
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
||||
int dps0;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
doc_set_device_id(docg3, docg3->device_id);
|
||||
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
||||
doc_set_device_id(docg3, 0);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
|
||||
return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
|
||||
}
|
||||
|
@ -1542,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev,
|
|||
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
||||
int dps1;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
doc_set_device_id(docg3, docg3->device_id);
|
||||
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
||||
doc_set_device_id(docg3, 0);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
|
||||
return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
|
||||
}
|
||||
|
@ -1559,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev,
|
|||
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
doc_set_device_id(docg3, docg3->device_id);
|
||||
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
||||
doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
|
||||
doc_set_device_id(docg3, 0);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1576,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev,
|
|||
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
doc_set_device_id(docg3, docg3->device_id);
|
||||
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
||||
doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
|
||||
doc_set_device_id(docg3, 0);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1634,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
|
|||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||
|
||||
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,
|
||||
"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)
|
|||
{
|
||||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||
|
||||
int pos = 0;
|
||||
int pctrl = doc_register_readb(docg3, DOC_ASICMODE);
|
||||
int mode = pctrl & 0x03;
|
||||
int pos = 0, pctrl, mode;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
pctrl = doc_register_readb(docg3, DOC_ASICMODE);
|
||||
mode = pctrl & 0x03;
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
|
||||
pos += seq_printf(s,
|
||||
"%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)
|
|||
{
|
||||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||
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);
|
||||
return pos;
|
||||
|
@ -1699,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
|||
int pos = 0;
|
||||
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
|
||||
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
protect = doc_register_readb(docg3, DOC_PROTECTION);
|
||||
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
||||
dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
|
||||
|
@ -1706,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
|||
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
||||
dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
|
||||
dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
|
||||
pos += seq_printf(s, "Protection = 0x%02x (",
|
||||
protect);
|
||||
|
@ -2022,6 +2049,7 @@ static int __init docg3_probe(struct platform_device *pdev)
|
|||
if (!cascade)
|
||||
goto nomem1;
|
||||
cascade->base = base;
|
||||
mutex_init(&cascade->lock);
|
||||
cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
|
||||
DOC_ECC_BCH_PRIMPOLY);
|
||||
if (!cascade->bch)
|
||||
|
|
|
@ -273,11 +273,13 @@
|
|||
* @floors: floors (ie. one physical docg3 chip is one floor)
|
||||
* @base: IO space to access all chips in the cascade
|
||||
* @bch: the BCH correcting control structure
|
||||
* @lock: lock to protect docg3 IO space from concurrent accesses
|
||||
*/
|
||||
struct docg3_cascade {
|
||||
struct mtd_info *floors[DOC_MAX_NBFLOORS];
|
||||
void __iomem *base;
|
||||
struct bch_control *bch;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue