mtd: maps: physmap: Add reference counter to set_vpp()
authorPaul Parsons <lost.distance@yahoo.com>
Wed, 7 Mar 2012 14:12:08 +0000 (14:12 +0000)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 26 Mar 2012 23:52:28 +0000 (00:52 +0100)
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>
arch/arm/mach-omap1/flash.c
arch/arm/mach-s3c2410/nor-simtec.c
drivers/mtd/maps/physmap.c

index 1749cb37dda0365985e6da1cc79e632f8564061b..4665bfcd2ce973fcdb35d64a3c6375df110a56d2 100644 (file)
 
 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);
 }
index ad9f750f1e556077c0f8331a5c17e8ac272e97c3..605aaccd0973df9d71be8c172a02f86da9f7f6b2 100644 (file)
@@ -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 = {
index abc562653b31777d4ea6d4217335d14b64ec8b15..7e9233c503ab763832fbfead6cb687177f668dc0 100644 (file)
@@ -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,