[U-Boot] [PATCH] ARM1136: Fix cache_flush() error and correct cpu_init_crit() comments

The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to "Clean and Invalidate Entire Data Cache". So change the ARM1136 cache_flush() function to use the "mcr p15, 0, rn, c7, c7, 0 @ Clean & invalidate D-Cache" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davis gdavis@mvista.com --- arch/arm/cpu/arm1136/cpu.c | 8 ++++---- arch/arm/cpu/arm1136/start.S | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index ade7f46..a00698f 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -69,8 +69,8 @@ int cleanup_before_linux (void)
static void cache_flush(void) { - unsigned long i = 0; - - asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ - asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */ + asm ( + " mcr p15, 0, %0, c7, c14, 0 @ Clean & invalidate D-Cache\n" + " mcr p15, 0, %0, c7, c10, 4 @ DSB\n" + : : "r" (0) : "memory"); } diff --git a/arch/arm/cpu/arm1136/start.S b/arch/arm/cpu/arm1136/start.S index 957f438..922d01c 100644 --- a/arch/arm/cpu/arm1136/start.S +++ b/arch/arm/cpu/arm1136/start.S @@ -226,8 +226,8 @@ cpu_init_crit: * flush v4 I/D caches */ mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ - mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */ + mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
/* * disable MMU stuff and caches

Hi George,
On 05.05.2010 23:09, George G. Davis wrote:
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches
... Also flushes the branch target cache"
" when in fact the intent is to "Clean and Invalidate Entire Data Cache".
Why don't we have to invalidate/flush the I- and BT-Cache here? I.e. why is it sufficient to clean & invalidate the D-Cache here, only, and remove the existing I- and BT-Cache invalidation/flushing?
What's about just adding an additional clean of the data cache before the 'invalidate all':
+ asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */ asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */
?
Thanks for finding this and best regards
Dirk

Hello Dirk,
On Mon, May 10, 2010 at 10:02 AM, Dirk Behme dirk.behme@googlemail.com wrote:
Hi George,
On 05.05.2010 23:09, George G. Davis wrote:
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches
... Also flushes the branch target cache"
" when in fact the intent is to "Clean and Invalidate Entire Data Cache".
Why don't we have to invalidate/flush the I- and BT-Cache here? I.e. why is it sufficient to clean & invalidate the D-Cache here, only, and remove the existing I- and BT-Cache invalidation/flushing?
Quite frankly I thought for sure that it was handled elsewhere but now that I look I see that it's not. Meanwhile, I don't think U-Boot is typically susceptible to self-modifying-code issues anyway (?) and this isn't likely required but I suppose lack of I+BTB invalidation could be an issue in some cases, e.g. loading and running a new version of U-Boot from RAM? So better to be safe and restore the I+BTB invalidation here.
What's about just adding an additional clean of the data cache before the 'invalidate all':
- asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */
?
That works for me.
If there is no more feedback, I'll resubmit an updated patch.
Thansk!
-- Regards, George
Thanks for finding this and best regards
Dirk

Dear "George G. Davis",
In message AANLkTimWgVcvJX0DlG7iC5XQB-cRZdUQxPvWUe3LPREx@mail.gmail.com you wrote:
Why don't we have to invalidate/flush the I- and BT-Cache here? I.e. why
is it sufficient to clean & invalidate the D-Cache here, only, and remove the existing I- and BT-Cache invalidation/flushing?
Quite frankly I thought for sure that it was handled elsewhere but now that I look I see that it's not. Meanwhile, I don't think U-Boot is typically susceptible to self-modifying-code issues anyway (?) and
What has self-modifying-code to do with it? Proper cache handling is mandatory in manyother siutuations as well, including when you load code (Linux kernel, standalone applications) and then try to execute these, or when dealing with I/O buffers, DMA, etc.
this isn't likely required but I suppose lack of I+BTB invalidation
I think it is mandatory.
Best regards,
Wolfgang Denk

Hello Wolfgang,
On Tue, May 11, 2010 at 4:56 AM, Wolfgang Denk wd@denx.de wrote:
Dear "George G. Davis",
In message AANLkTimWgVcvJX0DlG7iC5XQB-cRZdUQxPvWUe3LPREx@mail.gmail.com you wrote:
Why don't we have to invalidate/flush the I- and BT-Cache here? I.e.
why
is it sufficient to clean & invalidate the D-Cache here, only, and remove the existing I- and BT-Cache invalidation/flushing?
Quite frankly I thought for sure that it was handled elsewhere but now that I look I see that it's not. Meanwhile, I don't think U-Boot is typically susceptible to self-modifying-code issues anyway (?) and
What has self-modifying-code to do with it? Proper cache handling is mandatory in manyother siutuations as well, including when you load code (Linux kernel, standalone applications) and then try to execute these, or when dealing with I/O buffers, DMA, etc.
this isn't likely required but I suppose lack of I+BTB invalidation
I think it is mandatory.
Yes, you're right. New patch on the way shortly...
-- Regards, George
Best regards,
Wolfgang Denk
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de A direct quote from the Boss: "We passed over a lot of good people to get the ones we hired."

From: George G. Davis gdavis@mvista.com
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to clean and invalidate all caches. So add an "mcr p15, 0, %0, c7, c10, 0" instruction to "Clean Entire Data Cache" prior to the "Invalidate Both Caches" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davis gdavis@mvista.com --- arch/arm/cpu/arm1136/cpu.c | 1 + arch/arm/cpu/arm1136/start.S | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index ade7f46..2b91631 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -71,6 +71,7 @@ static void cache_flush(void) { unsigned long i = 0;
+ asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */ asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */ } diff --git a/arch/arm/cpu/arm1136/start.S b/arch/arm/cpu/arm1136/start.S index 957f438..922d01c 100644 --- a/arch/arm/cpu/arm1136/start.S +++ b/arch/arm/cpu/arm1136/start.S @@ -226,8 +226,8 @@ cpu_init_crit: * flush v4 I/D caches */ mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ - mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */ + mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
/* * disable MMU stuff and caches

On 11.05.2010 16:15, gdavis@mvista.com wrote:
From: George G. Davisgdavis@mvista.com
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to clean and invalidate all caches. So add an "mcr p15, 0, %0, c7, c10, 0" instruction to "Clean Entire Data Cache" prior to the "Invalidate Both Caches" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davisgdavis@mvista.com
Acked-by: Dirk Behme dirk.behme@googlemail.com
Thanks
Dirk
arch/arm/cpu/arm1136/cpu.c | 1 + arch/arm/cpu/arm1136/start.S | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index ade7f46..2b91631 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -71,6 +71,7 @@ static void cache_flush(void) { unsigned long i = 0;
- asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */ asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */ }
diff --git a/arch/arm/cpu/arm1136/start.S b/arch/arm/cpu/arm1136/start.S index 957f438..922d01c 100644 --- a/arch/arm/cpu/arm1136/start.S +++ b/arch/arm/cpu/arm1136/start.S @@ -226,8 +226,8 @@ cpu_init_crit: * flush v4 I/D caches */ mov r0, #0
- mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
- mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */
mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
/*
- disable MMU stuff and caches

Ping,
On Thu, May 13, 2010 at 11:41:13AM +0200, Dirk Behme wrote:
On 11.05.2010 16:15, gdavis@mvista.com wrote:
From: George G. Davisgdavis@mvista.com
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to clean and invalidate all caches. So add an "mcr p15, 0, %0, c7, c10, 0" instruction to "Clean Entire Data Cache" prior to the "Invalidate Both Caches" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davisgdavis@mvista.com
Acked-by: Dirk Behme dirk.behme@googlemail.com
Is this OK now or does it need more work? Perhaps I should CC the u-boot/u-boot-arm.git fork maintainer?
TIA!
-- Regards, George
Thanks
Dirk
arch/arm/cpu/arm1136/cpu.c | 1 + arch/arm/cpu/arm1136/start.S | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/arm1136/cpu.c b/arch/arm/cpu/arm1136/cpu.c index ade7f46..2b91631 100644 --- a/arch/arm/cpu/arm1136/cpu.c +++ b/arch/arm/cpu/arm1136/cpu.c @@ -71,6 +71,7 @@ static void cache_flush(void) { unsigned long i = 0;
- asm ("mcr p15, 0, %0, c7, c10, 0": :"r" (i)); /* clean entire data cache */ asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); /* invalidate both caches and flush btb */ asm ("mcr p15, 0, %0, c7, c10, 4": :"r" (i)); /* mem barrier to sync things */
} diff --git a/arch/arm/cpu/arm1136/start.S b/arch/arm/cpu/arm1136/start.S index 957f438..922d01c 100644 --- a/arch/arm/cpu/arm1136/start.S +++ b/arch/arm/cpu/arm1136/start.S @@ -226,8 +226,8 @@ cpu_init_crit: * flush v4 I/D caches */ mov r0, #0
- mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
- mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
mcr p15, 0, r0, c7, c7, 0 /* Invalidate I+D+BTB caches */
mcr p15, 0, r0, c8, c7, 0 /* Invalidate Unified TLB */
/*
- disable MMU stuff and caches

gdavis@mvista.com wrote:
From: George G. Davis gdavis@mvista.com
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to clean and invalidate all caches. So add an "mcr p15, 0, %0, c7, c10, 0" instruction to "Clean Entire Data Cache" prior to the "Invalidate Both Caches" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davis gdavis@mvista.com
Applied to arm/master Thanks Tom

Hi Tom,
On Tue, Jun 01, 2010 at 09:38:56AM -0500, Tom Rix wrote:
gdavis@mvista.com wrote:
From: George G. Davis gdavis@mvista.com
The ARM1136 cache_flush() function uses the "mcr p15, 0, rn, c7, c7, 0" instruction which means "Invalidate Both Caches" when in fact the intent is to clean and invalidate all caches. So add an "mcr p15, 0, %0, c7, c10, 0" instruction to "Clean Entire Data Cache" prior to the "Invalidate Both Caches" instruction to insure that memory is consistent with any dirty cache lines.
Also fix a couple of "flush v*" comments in ARM1136 cpu_init_crit() so that they correctly describe the actual ARM1136 CP15 C7 Cache Operations used.
Signed-off-by: George G. Davis gdavis@mvista.com
Applied to arm/master
Er, woops, Dirk's Acked-by was not included. I reckon I should have resumitted with that included but to late now.
Thanks!
-- Regards, George
Thanks Tom
participants (5)
-
Dirk Behme
-
gdavis@mvista.com
-
George G. Davis
-
Tom Rix
-
Wolfgang Denk