tree 3cd1afd4b23b8ed31b2b92b9d11c67a854a7be63
parent fff7afd791f6a685b3ddedb8cfb152aed85f3cf8
author Nicolas Pitre <[EMAIL PROTECTED]> Thu, 19 May 2005 18:05:47 +0100
committer Thomas Gleixner <[EMAIL PROTECTED]> Mon, 23 May 2005 13:21:35 +0200
[MTD] CFI flash locking reorg for XIP
This reworks the XIP locking to make sure no lock primitive is ever
called from XIP disabled paths even if in theory they should not
cause any reschedule. Relying on the current spinlock implementation
is rather fragile and not especially clean from an abstraction pov.
The recent RT work makes it even more obvious.
Signed-off-by: Nicolas Pitre <[EMAIL PROTECTED]>
Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
drivers/mtd/chips/cfi_cmdset_0001.c | 90 ++++++++++++++++--------------------
1 files changed, 40 insertions(+), 50 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c
b/drivers/mtd/chips/cfi_cmdset_0001.c
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0001.c,v 1.176 2005/04/27 20:01:49 tpoynor Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
*
*
* 10/10/2000 Nicolas Pitre <[EMAIL PROTECTED]>
@@ -826,10 +826,6 @@ static void put_chip(struct map_info *ma
* assembly to make sure inline functions were actually inlined and that gcc
* didn't emit calls to its own support functions). Also configuring MTD CFI
* support to a single buswidth and a single interleave is also recommended.
- * Note that not only IRQs are disabled but the preemption count is also
- * increased to prevent other locking primitives (namely spin_unlock) from
- * decrementing the preempt count to zero and scheduling the CPU away while
- * not in array mode.
*/
static void xip_disable(struct map_info *map, struct flchip *chip,
@@ -837,7 +833,6 @@ static void xip_disable(struct map_info
{
/* TODO: chips with no XIP use should ignore and return */
(void) map_read(map, adr); /* ensure mmu mapping is up to date */
- preempt_disable();
local_irq_disable();
}
@@ -852,7 +847,6 @@ static void __xipram xip_enable(struct m
(void) map_read(map, adr);
asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
local_irq_enable();
- preempt_enable();
}
/*
@@ -928,7 +922,7 @@ static void __xipram xip_udelay(struct m
(void) map_read(map, adr);
asm volatile (".rep 8; nop; .endr");
local_irq_enable();
- preempt_enable();
+ spin_unlock(chip->mutex);
asm volatile (".rep 8; nop; .endr");
cond_resched();
@@ -938,15 +932,15 @@ static void __xipram xip_udelay(struct m
* a suspended erase state. If so let's wait
* until it's done.
*/
- preempt_disable();
+ spin_lock(chip->mutex);
while (chip->state != newstate) {
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- preempt_enable();
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- preempt_disable();
+ spin_lock(chip->mutex);
}
/* Disallow XIP again */
local_irq_disable();
@@ -975,12 +969,14 @@ static void __xipram xip_udelay(struct m
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
* the flash is actively programming or erasing since we have to poll for
* the operation to complete anyway. We can't do that in a generic way with
- * a XIP setup so do it before the actual flash operation in this case.
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
*/
-#undef INVALIDATE_CACHED_RANGE
-#define INVALIDATE_CACHED_RANGE(x...)
-#define XIP_INVAL_CACHED_RANGE(map, from, size) \
- do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+ INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+ UDELAY(map, chip, adr, usec)
/*
* Extra notes:
@@ -1003,11 +999,23 @@ static void __xipram xip_udelay(struct m
#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
-
-#define UDELAY(map, chip, adr, usec) cfi_udelay(usec)
-
#define XIP_INVAL_CACHED_RANGE(x...)
+#define UDELAY(map, chip, adr, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ INVALIDATE_CACHED_RANGE(map, adr, len); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
#endif
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t
adr, size_t len)
@@ -1227,10 +1235,9 @@ static int __xipram do_write_oneword(str
map_write(map, datum, adr);
chip->state = mode;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
- UDELAY(map, chip, adr, chip->word_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
timeo = jiffies + (HZ/2);
z = 0;
@@ -1263,10 +1270,8 @@ static int __xipram do_write_oneword(str
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
z++;
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
if (!z) {
chip->word_write_time--;
@@ -1430,9 +1435,7 @@ static int __xipram do_write_buffer(stru
if (map_word_andequal(map, status, status_OK, status_OK))
break;
- spin_unlock(chip->mutex);
UDELAY(map, chip, cmd_adr, 1);
- spin_lock(chip->mutex);
if (++z > 20) {
/* Argh. Not ready for write to buffer */
@@ -1478,10 +1481,9 @@ static int __xipram do_write_buffer(stru
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ cmd_adr, len,
+ chip->buffer_write_time);
timeo = jiffies + (HZ/2);
z = 0;
@@ -1513,10 +1515,8 @@ static int __xipram do_write_buffer(stru
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- UDELAY(map, chip, cmd_adr, 1);
z++;
- spin_lock(chip->mutex);
+ UDELAY(map, chip, cmd_adr, 1);
}
if (!z) {
chip->buffer_write_time--;
@@ -1644,10 +1644,9 @@ static int __xipram do_erase_oneblock(st
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, adr, chip->erase_time*1000/2);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, len,
+ chip->erase_time*1000/2);
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1692,9 +1691,7 @@ static int __xipram do_erase_oneblock(st
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
}
/* We've broken this before. It doesn't hurt to be safe */
@@ -1866,11 +1863,8 @@ static int __xipram do_xxlock_oneblock(s
* to delay.
*/
- if (!extp || !(extp->FeatureSupport & (1 << 5))) {
- spin_unlock(chip->mutex);
+ if (!extp || !(extp->FeatureSupport & (1 << 5)))
UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
- }
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1897,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(s
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
/* Done and happy. */
@@ -1979,8 +1971,7 @@ do_otp_read(struct map_info *map, struct
}
/* let's ensure we're not reading back cached data from array mode */
- if (map->inval_cache)
- map->inval_cache(map, chip->start + offset, size);
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
xip_disable(map, chip, chip->start);
if (chip->state != FL_JEDEC_QUERY) {
@@ -1991,8 +1982,7 @@ do_otp_read(struct map_info *map, struct
xip_enable(map, chip, chip->start);
/* then ensure we don't keep OTP data in the cache */
- if (map->inval_cache)
- map->inval_cache(map, chip->start + offset, size);
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
put_chip(map, chip, chip->start);
spin_unlock(chip->mutex);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html