forked from Minki/linux
mtd: maps: physmap: Add reference counter to set_vpp()
This patch is part of a set which fixes unnecessary flash erase and write errors resulting from the MTD CFI driver turning off vpp while an erase is in progress. This patch allows physmap_set_vpp() calls to be nested by adding a reference counter. omap1_set_vpp() already used a reference counter. Since it is called from physmap_set_vpp(), omap1_set_vpp() can now be simplified. simtec_nor_vpp() already disabled hard interrupts. Since it is called from physmap_set_vpp(), simtec_nor_vpp() can now be simplified. Signed-off-by: Paul Parsons <lost.distance@yahoo.com> 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
e7d9377e04
commit
876fe76d79
@ -15,20 +15,12 @@
|
|||||||
|
|
||||||
void omap1_set_vpp(struct platform_device *pdev, int enable)
|
void omap1_set_vpp(struct platform_device *pdev, int enable)
|
||||||
{
|
{
|
||||||
static int count;
|
|
||||||
u32 l;
|
u32 l;
|
||||||
|
|
||||||
if (enable) {
|
l = omap_readl(EMIFS_CONFIG);
|
||||||
if (count++ == 0) {
|
if (enable)
|
||||||
l = omap_readl(EMIFS_CONFIG);
|
l |= OMAP_EMIFS_CONFIG_WP;
|
||||||
l |= OMAP_EMIFS_CONFIG_WP;
|
else
|
||||||
omap_writel(l, EMIFS_CONFIG);
|
l &= ~OMAP_EMIFS_CONFIG_WP;
|
||||||
}
|
omap_writel(l, EMIFS_CONFIG);
|
||||||
} else {
|
|
||||||
if (count && (--count == 0)) {
|
|
||||||
l = omap_readl(EMIFS_CONFIG);
|
|
||||||
l &= ~OMAP_EMIFS_CONFIG_WP;
|
|
||||||
omap_writel(l, EMIFS_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,7 @@
|
|||||||
static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
val = __raw_readb(BAST_VA_CTRL3);
|
val = __raw_readb(BAST_VA_CTRL3);
|
||||||
|
|
||||||
printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
|
printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
|
||||||
@ -48,7 +46,6 @@ static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
|||||||
val &= ~BAST_CPLD_CTRL3_ROMWEN;
|
val &= ~BAST_CPLD_CTRL3_ROMWEN;
|
||||||
|
|
||||||
__raw_writeb(val, BAST_VA_CTRL3);
|
__raw_writeb(val, BAST_VA_CTRL3);
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct physmap_flash_data simtec_nor_pdata = {
|
static struct physmap_flash_data simtec_nor_pdata = {
|
||||||
|
@ -27,6 +27,8 @@ struct physmap_flash_info {
|
|||||||
struct mtd_info *mtd[MAX_RESOURCES];
|
struct mtd_info *mtd[MAX_RESOURCES];
|
||||||
struct mtd_info *cmtd;
|
struct mtd_info *cmtd;
|
||||||
struct map_info map[MAX_RESOURCES];
|
struct map_info map[MAX_RESOURCES];
|
||||||
|
spinlock_t vpp_lock;
|
||||||
|
int vpp_refcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int physmap_flash_remove(struct platform_device *dev)
|
static int physmap_flash_remove(struct platform_device *dev)
|
||||||
@ -63,12 +65,26 @@ static void physmap_set_vpp(struct map_info *map, int state)
|
|||||||
{
|
{
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct physmap_flash_data *physmap_data;
|
struct physmap_flash_data *physmap_data;
|
||||||
|
struct physmap_flash_info *info;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
pdev = (struct platform_device *)map->map_priv_1;
|
pdev = (struct platform_device *)map->map_priv_1;
|
||||||
physmap_data = pdev->dev.platform_data;
|
physmap_data = pdev->dev.platform_data;
|
||||||
|
|
||||||
if (physmap_data->set_vpp)
|
if (!physmap_data->set_vpp)
|
||||||
physmap_data->set_vpp(pdev, state);
|
return;
|
||||||
|
|
||||||
|
info = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&info->vpp_lock, flags);
|
||||||
|
if (state) {
|
||||||
|
if (++info->vpp_refcnt == 1) /* first nested 'on' */
|
||||||
|
physmap_data->set_vpp(pdev, 1);
|
||||||
|
} else {
|
||||||
|
if (--info->vpp_refcnt == 0) /* last nested 'off' */
|
||||||
|
physmap_data->set_vpp(pdev, 0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&info->vpp_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *rom_probe_types[] = {
|
static const char *rom_probe_types[] = {
|
||||||
@ -172,6 +188,8 @@ static int physmap_flash_probe(struct platform_device *dev)
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
|
spin_lock_init(&info->vpp_lock);
|
||||||
|
|
||||||
part_types = physmap_data->part_probe_types ? : part_probe_types;
|
part_types = physmap_data->part_probe_types ? : part_probe_types;
|
||||||
|
|
||||||
mtd_device_parse_register(info->cmtd, part_types, 0,
|
mtd_device_parse_register(info->cmtd, part_types, 0,
|
||||||
|
Loading…
Reference in New Issue
Block a user