diff options
author | Paul Parsons <lost.distance@yahoo.com> | 2012-03-07 09:12:08 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-03-26 19:52:28 -0400 |
commit | 876fe76d793d03077eb61ba3afab4a383f46c554 (patch) | |
tree | fb7d98bd746ebd1c3c5919f10a998e8f2dbd9e8b /drivers | |
parent | e7d9377e0440c25805dcc5b0af189a87beb69f5e (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/maps/physmap.c | 22 |
1 files changed, 20 insertions, 2 deletions
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 { | |||
27 | struct mtd_info *mtd[MAX_RESOURCES]; | 27 | struct mtd_info *mtd[MAX_RESOURCES]; |
28 | struct mtd_info *cmtd; | 28 | struct mtd_info *cmtd; |
29 | struct map_info map[MAX_RESOURCES]; | 29 | struct map_info map[MAX_RESOURCES]; |
30 | spinlock_t vpp_lock; | ||
31 | int vpp_refcnt; | ||
30 | }; | 32 | }; |
31 | 33 | ||
32 | static int physmap_flash_remove(struct platform_device *dev) | 34 | static int physmap_flash_remove(struct platform_device *dev) |
@@ -63,12 +65,26 @@ static void physmap_set_vpp(struct map_info *map, int state) | |||
63 | { | 65 | { |
64 | struct platform_device *pdev; | 66 | struct platform_device *pdev; |
65 | struct physmap_flash_data *physmap_data; | 67 | struct physmap_flash_data *physmap_data; |
68 | struct physmap_flash_info *info; | ||
69 | unsigned long flags; | ||
66 | 70 | ||
67 | pdev = (struct platform_device *)map->map_priv_1; | 71 | pdev = (struct platform_device *)map->map_priv_1; |
68 | physmap_data = pdev->dev.platform_data; | 72 | physmap_data = pdev->dev.platform_data; |
69 | 73 | ||
70 | if (physmap_data->set_vpp) | 74 | if (!physmap_data->set_vpp) |
71 | physmap_data->set_vpp(pdev, state); | 75 | return; |
76 | |||
77 | info = platform_get_drvdata(pdev); | ||
78 | |||
79 | spin_lock_irqsave(&info->vpp_lock, flags); | ||
80 | if (state) { | ||
81 | if (++info->vpp_refcnt == 1) /* first nested 'on' */ | ||
82 | physmap_data->set_vpp(pdev, 1); | ||
83 | } else { | ||
84 | if (--info->vpp_refcnt == 0) /* last nested 'off' */ | ||
85 | physmap_data->set_vpp(pdev, 0); | ||
86 | } | ||
87 | spin_unlock_irqrestore(&info->vpp_lock, flags); | ||
72 | } | 88 | } |
73 | 89 | ||
74 | static const char *rom_probe_types[] = { | 90 | static const char *rom_probe_types[] = { |
@@ -172,6 +188,8 @@ static int physmap_flash_probe(struct platform_device *dev) | |||
172 | if (err) | 188 | if (err) |
173 | goto err_out; | 189 | goto err_out; |
174 | 190 | ||
191 | spin_lock_init(&info->vpp_lock); | ||
192 | |||
175 | part_types = physmap_data->part_probe_types ? : part_probe_types; | 193 | part_types = physmap_data->part_probe_types ? : part_probe_types; |
176 | 194 | ||
177 | mtd_device_parse_register(info->cmtd, part_types, 0, | 195 | mtd_device_parse_register(info->cmtd, part_types, 0, |