Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

Paul Parsons and committed by
David Woodhouse
876fe76d e7d9377e

+26 -19
+6 -14
arch/arm/mach-omap1/flash.c
··· 15 15 16 16 void omap1_set_vpp(struct platform_device *pdev, int enable) 17 17 { 18 - static int count; 19 18 u32 l; 20 19 21 - if (enable) { 22 - if (count++ == 0) { 23 - l = omap_readl(EMIFS_CONFIG); 24 - l |= OMAP_EMIFS_CONFIG_WP; 25 - omap_writel(l, EMIFS_CONFIG); 26 - } 27 - } else { 28 - if (count && (--count == 0)) { 29 - l = omap_readl(EMIFS_CONFIG); 30 - l &= ~OMAP_EMIFS_CONFIG_WP; 31 - omap_writel(l, EMIFS_CONFIG); 32 - } 33 - } 20 + l = omap_readl(EMIFS_CONFIG); 21 + if (enable) 22 + l |= OMAP_EMIFS_CONFIG_WP; 23 + else 24 + l &= ~OMAP_EMIFS_CONFIG_WP; 25 + omap_writel(l, EMIFS_CONFIG); 34 26 }
-3
arch/arm/mach-s3c2410/nor-simtec.c
··· 35 35 static void simtec_nor_vpp(struct platform_device *pdev, int vpp) 36 36 { 37 37 unsigned int val; 38 - unsigned long flags; 39 38 40 - local_irq_save(flags); 41 39 val = __raw_readb(BAST_VA_CTRL3); 42 40 43 41 printk(KERN_DEBUG "%s(%d)\n", __func__, vpp); ··· 46 48 val &= ~BAST_CPLD_CTRL3_ROMWEN; 47 49 48 50 __raw_writeb(val, BAST_VA_CTRL3); 49 - local_irq_restore(flags); 50 51 } 51 52 52 53 static struct physmap_flash_data simtec_nor_pdata = {
+20 -2
drivers/mtd/maps/physmap.c
··· 27 27 struct mtd_info *mtd[MAX_RESOURCES]; 28 28 struct mtd_info *cmtd; 29 29 struct map_info map[MAX_RESOURCES]; 30 + spinlock_t vpp_lock; 31 + int vpp_refcnt; 30 32 }; 31 33 32 34 static int physmap_flash_remove(struct platform_device *dev) ··· 65 63 { 66 64 struct platform_device *pdev; 67 65 struct physmap_flash_data *physmap_data; 66 + struct physmap_flash_info *info; 67 + unsigned long flags; 68 68 69 69 pdev = (struct platform_device *)map->map_priv_1; 70 70 physmap_data = pdev->dev.platform_data; 71 71 72 - if (physmap_data->set_vpp) 73 - physmap_data->set_vpp(pdev, state); 72 + if (!physmap_data->set_vpp) 73 + return; 74 + 75 + info = platform_get_drvdata(pdev); 76 + 77 + spin_lock_irqsave(&info->vpp_lock, flags); 78 + if (state) { 79 + if (++info->vpp_refcnt == 1) /* first nested 'on' */ 80 + physmap_data->set_vpp(pdev, 1); 81 + } else { 82 + if (--info->vpp_refcnt == 0) /* last nested 'off' */ 83 + physmap_data->set_vpp(pdev, 0); 84 + } 85 + spin_unlock_irqrestore(&info->vpp_lock, flags); 74 86 } 75 87 76 88 static const char *rom_probe_types[] = { ··· 187 171 } 188 172 if (err) 189 173 goto err_out; 174 + 175 + spin_lock_init(&info->vpp_lock); 190 176 191 177 part_types = physmap_data->part_probe_types ? : part_probe_types; 192 178