diff options
author | Paul Parsons <lost.distance@yahoo.com> | 2012-03-07 14:12:08 +0000 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-03-27 00:52:28 +0100 |
commit | 876fe76d793d03077eb61ba3afab4a383f46c554 (patch) | |
tree | fb7d98bd746ebd1c3c5919f10a998e8f2dbd9e8b | |
parent | e7d9377e0440c25805dcc5b0af189a87beb69f5e (diff) | |
download | linux-876fe76d793d03077eb61ba3afab4a383f46c554.tar.gz linux-876fe76d793d03077eb61ba3afab4a383f46c554.tar.bz2 linux-876fe76d793d03077eb61ba3afab4a383f46c554.zip |
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>
-rw-r--r-- | arch/arm/mach-omap1/flash.c | 20 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/nor-simtec.c | 3 | ||||
-rw-r--r-- | drivers/mtd/maps/physmap.c | 22 |
3 files changed, 26 insertions, 19 deletions
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c index 1749cb37dda0..4665bfcd2ce9 100644 --- a/arch/arm/mach-omap1/flash.c +++ b/arch/arm/mach-omap1/flash.c @@ -15,20 +15,12 @@ void omap1_set_vpp(struct platform_device *pdev, int enable) { - static int count; u32 l; - if (enable) { - if (count++ == 0) { - l = omap_readl(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); - } - } + l = omap_readl(EMIFS_CONFIG); + if (enable) + l |= OMAP_EMIFS_CONFIG_WP; + else + l &= ~OMAP_EMIFS_CONFIG_WP; + omap_writel(l, EMIFS_CONFIG); } diff --git a/arch/arm/mach-s3c2410/nor-simtec.c b/arch/arm/mach-s3c2410/nor-simtec.c index ad9f750f1e55..605aaccd0973 100644 --- a/arch/arm/mach-s3c2410/nor-simtec.c +++ b/arch/arm/mach-s3c2410/nor-simtec.c @@ -35,9 +35,7 @@ static void simtec_nor_vpp(struct platform_device *pdev, int vpp) { unsigned int val; - unsigned long flags; - local_irq_save(flags); val = __raw_readb(BAST_VA_CTRL3); 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; __raw_writeb(val, BAST_VA_CTRL3); - local_irq_restore(flags); } static struct physmap_flash_data simtec_nor_pdata = { diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index abc562653b31..7e9233c503ab 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -27,6 +27,8 @@ struct physmap_flash_info { struct mtd_info *mtd[MAX_RESOURCES]; struct mtd_info *cmtd; struct map_info map[MAX_RESOURCES]; + spinlock_t vpp_lock; + int vpp_refcnt; }; 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 physmap_flash_data *physmap_data; + struct physmap_flash_info *info; + unsigned long flags; pdev = (struct platform_device *)map->map_priv_1; physmap_data = pdev->dev.platform_data; - if (physmap_data->set_vpp) - physmap_data->set_vpp(pdev, state); + if (!physmap_data->set_vpp) + 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[] = { @@ -172,6 +188,8 @@ static int physmap_flash_probe(struct platform_device *dev) if (err) goto err_out; + spin_lock_init(&info->vpp_lock); + part_types = physmap_data->part_probe_types ? : part_probe_types; mtd_device_parse_register(info->cmtd, part_types, 0, |