mtd: maps: physmap: Add reference counter to set_vpp()

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Mon Mar 26 20:59:15 EDT 2012


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=876fe76d793d03077eb61ba3afab4a383f46c554
Commit:     876fe76d793d03077eb61ba3afab4a383f46c554
Parent:     e7d9377e0440c25805dcc5b0af189a87beb69f5e
Author:     Paul Parsons <lost.distance at yahoo.com>
AuthorDate: Wed Mar 7 14:12:08 2012 +0000
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Tue Mar 27 00:52:28 2012 +0100

    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 at yahoo.com>
    Signed-off-by: Artem Bityutskiy <artem.bityutskiy at linux.intel.com>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
 arch/arm/mach-omap1/flash.c        |   20 ++++++--------------
 arch/arm/mach-s3c2410/nor-simtec.c |    3 ---
 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 1749cb3..4665bfc 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 ad9f750..605aacc 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 abc5626..7e9233c 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,



More information about the linux-mtd-cvs mailing list