MN10300: The icache invalidate functions should disable the icache first
David Howells [Fri, 18 Mar 2011 16:54:29 +0000 (16:54 +0000)]
The icache invalidate functions should disable the icache on AM33 and wait for
it to quiesce before attempting to invalidate it, and should then wait for it
to quiesce again before reenabling it, but on AM34 they should invalidate
directly.  The same goes for the dcache invalidation, but this isn't used much.

Whilst we're at it, this can be wrapped in assembler macros to remove duplicate
code.

The AM33 manual states that:

An operation that invalidates the cache, switches the writing mode, or
changes the way mode must be performed after disabling the cache,
checking the busy bit, and confirming that the cache is not in
operation.

for the dcache [sec 2.8.3.2.1].  This is not stated so for the icache [sec
2.8.3.1.1] but the example code there suggests that it is.

Whilst the AM34 manual states that the cache must be disabled for both the
icache [sec 1.8.3.2.1] and the dcache [sec 1.8.3.2.1], the Panasonic hardware
engineers say the manual is wrong and that disabling the caches for
invalidation is wrong.

Furthermore, they say that disabling the caches on the AM34 whilst running an
SMP kernel can lead to incoherency between the various CPU caches and should
thus be avoided.

Signed-off-by: David Howells <dhowells@redhat.com>

arch/mn10300/mm/cache-inv-by-reg.S
arch/mn10300/mm/cache-inv-by-tag.S
arch/mn10300/mm/cache.inc [new file with mode: 0644]

index c895086..d1f363a 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/cache.h>
 #include <asm/irqflags.h>
 #include <asm/cacheflush.h>
+#include "cache.inc"
 
 #define mn10300_local_dcache_inv_range_intr_interval \
        +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
@@ -62,10 +63,7 @@ mn10300_local_icache_inv:
        btst    CHCTR_ICEN,d0
        beq     mn10300_local_icache_inv_end
 
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
+       invalidate_icache 1
 
 mn10300_local_icache_inv_end:
        ret     [],0
@@ -87,11 +85,8 @@ mn10300_local_dcache_inv:
        btst    CHCTR_DCEN,d0
        beq     mn10300_local_dcache_inv_end
 
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
+       invalidate_dcache 1
+       
 mn10300_local_dcache_inv_end:
        ret     [],0
        .size   mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
index e9713b4..c5c8032 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/cache.h>
 #include <asm/irqflags.h>
 #include <asm/cacheflush.h>
+#include "cache.inc"
 
 #define mn10300_local_dcache_inv_range_intr_interval \
        +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
@@ -70,43 +71,7 @@ mn10300_local_icache_inv:
        btst    CHCTR_ICEN,d0
        beq     mn10300_local_icache_inv_end
 
-#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
-       LOCAL_CLI_SAVE(d1)
-
-       # disable the icache
-       and     ~CHCTR_ICEN,d0
-       movhu   d0,(a0)
-
-       # and wait for it to calm down
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-
-       # wait for the cache to finish
-       mov     CHCTR,a0
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # and reenable it
-       and     ~CHCTR_ICINV,d0
-       or      CHCTR_ICEN,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
-       LOCAL_IRQ_RESTORE(d1)
-#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       invalidate_icache 1
 
 mn10300_local_icache_inv_end:
        ret     [],0
@@ -128,43 +93,7 @@ mn10300_local_dcache_inv:
        btst    CHCTR_DCEN,d0
        beq     mn10300_local_dcache_inv_end
 
-#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
-       LOCAL_CLI_SAVE(d1)
-
-       # disable the dcache
-       and     ~CHCTR_DCEN,d0
-       movhu   d0,(a0)
-
-       # and wait for it to calm down
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_DCBUSY,d0
-       lne
-
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-
-       # wait for the cache to finish
-       mov     CHCTR,a0
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_DCBUSY,d0
-       lne
-
-       # and reenable it
-       and     ~CHCTR_DCINV,d0
-       or      CHCTR_DCEN,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
-       LOCAL_IRQ_RESTORE(d1)
-#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       invalidate_dcache 1
 
 mn10300_local_dcache_inv_end:
        ret     [],0
diff --git a/arch/mn10300/mm/cache.inc b/arch/mn10300/mm/cache.inc
new file mode 100644 (file)
index 0000000..394a119
--- /dev/null
@@ -0,0 +1,133 @@
+/* MN10300 CPU core caching macros -*- asm -*-
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+
+###############################################################################
+#
+# Invalidate the instruction cache.
+#      A0: Should hold CHCTR
+#      D0: Should have been read from CHCTR
+#      D1: Will be clobbered
+#
+# On some cores it is necessary to disable the icache whilst we do this.
+#
+###############################################################################
+       .macro invalidate_icache,disable_irq
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+       .if \disable_irq
+       # don't want an interrupt routine seeing a disabled cache
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       or      EPSW_NMID,epsw
+       nop
+       nop
+       .endif
+
+       # disable the icache
+       and     ~CHCTR_ICEN,d0
+       movhu   d0,(a0)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # invalidate
+       or      CHCTR_ICINV,d0
+       movhu   d0,(a0)
+
+       # wait for the cache to finish
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # and reenable it
+       or      CHCTR_ICEN,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+       .if \disable_irq
+       LOCAL_IRQ_RESTORE(d1)
+       .endif
+
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+       # invalidate
+       or      CHCTR_ICINV,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       .endm
+
+###############################################################################
+#
+# Invalidate the data cache.
+#      A0: Should hold CHCTR
+#      D0: Should have been read from CHCTR
+#      D1: Will be clobbered
+#
+# On some cores it is necessary to disable the dcache whilst we do this.
+#
+###############################################################################
+       .macro invalidate_dcache,disable_irq
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+       .if \disable_irq
+       # don't want an interrupt routine seeing a disabled cache
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       or      EPSW_NMID,epsw
+       nop
+       nop
+       .endif
+       
+       # disable the dcache
+       and     ~CHCTR_DCEN,d0
+       movhu   d0,(a0)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_DCBUSY,d0
+       lne
+
+       # invalidate
+       or      CHCTR_DCINV,d0
+       movhu   d0,(a0)
+
+       # wait for the cache to finish
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_DCBUSY,d0
+       lne
+
+       # and reenable it
+       or      CHCTR_DCEN,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+       .if \disable_irq
+       LOCAL_IRQ_RESTORE(d1)
+       .endif
+
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+       # invalidate
+       or      CHCTR_DCINV,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       .endm