Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+39 −11
Original line number Original line Diff line number Diff line
@@ -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,
		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,
		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)
	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)
	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)
		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,
			 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,
	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,
		}
		}
		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,
	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,
	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,
	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,
	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)
	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)
{
{
	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)
{
{
	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)
	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)
	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)
	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)
+2 −0
Original line number Original line Diff line number Diff line
@@ -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;
};
};


/**
/**