Skip to contentSkip to conversation

arm: fix kexec for ARMv7

PATCH New Saeed Bishara 7 participants 16 messages Mar 9, 2010 – Apr 15, 2010 Arm (32-bit)

lore
Share & tools
lore
#0 lore raw

cover arm: fix kexec for ARMv7

Those two patches needed to make kexec work for ARMv7 based cpu's. The second one needed when L2 is used.

Signature · 1 line
1.6.0.4
#1 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

---
 arch/arm/mm/proc-v7.S |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/arm/mm/proc-v7.S +5 -0
index 7aaf88a..06cc36c 100644
@@ -52,6 +52,11 @@ ENTRY(cpu_v7_proc_fin)
 	bic	r0, r0, #0x1000			@ ...i............
 	bic	r0, r0, #0x0006			@ .............ca.
 	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+#ifdef CONFIG_OUTER_CACHE
+	mrc	p15, 0, r0, c1, c0, 1
+	bic	r0, r0, #0x2
+	mcr	p15, 0, r0, c1, c0, 1		@ disable L2 cache
+#endif
 	ldmfd	sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)
 
Signature · 1 line
1.6.0.4
#2 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

---
 arch/arm/boot/compressed/head.S |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/boot/compressed/head.S +1 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
 		mcr	p15, 0, r0, c1, c0, 0	@ load control register
 		mrc	p15, 0, r0, c1, c0, 0	@ and read it back
 		mov	r0, #0
+		mcr	p15, 0, r0, c8, c7, 0	@ invalidate I,D TLBs
 		mcr	p15, 0, r0, c7, c5, 4	@ ISB
 		mov	pc, r12
 
Signature · 1 line
1.6.0.4
#3 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

Quoted 13 lines · Saeed Bishara
---
 arch/arm/boot/compressed/head.S |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/boot/compressed/head.S +0 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
                mcr     p15, 0, r0, c1, c0, 0   @ load control

register

Quoted 5 lines
                mrc     p15, 0, r0, c1, c0, 0   @ and read it back
                mov     r0, #0
+               mcr     p15, 0, r0, c8, c7, 0   @ invalidate I,D TLBs
                mcr     p15, 0, r0, c7, c5, 4   @ ISB
                mov     pc, r12

The TLB invalidating is done earlier in the __armv7_mmu_cache_on function, why do you need to do it again?

Signature · 1 line
Catalin
#4 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

Quoted 6 lines · Catalin Marinas
Quoted 5 lines · Saeed Bishara

---
?arch/arm/boot/compressed/head.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)

Quoted 17 lines
Quoted 6 lines
arch/arm/boot/compressed/head.S +0 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
Quoted 7 lines

? ? ? ? ? ? ? ? mcr ? ? p15, 0, r0, c1, c0, 0 ? @ load control register
? ? ? ? ? ? ? ? mrc ? ? p15, 0, r0, c1, c0, 0 ? @ and read it back ? ? ? ? ? ? ? ? mov ? ? r0, #0
+ ? ? ? ? ? ? ? mcr ? ? p15, 0, r0, c8, c7, 0 ? @ invalidate I,D TLBs ? ? ? ? ? ? ? ? mcr ? ? p15, 0, r0, c7, c5, 4 ? @ ISB
? ? ? ? ? ? ? ? mov ? ? pc, r12

The TLB invalidating is done earlier in the __armv7_mmu_cache_on function, why do you need to do it again?

Well, the only difference between these two "invalidate"s looks like one is before control register load and one after.

We do have the problem of slow decompressing when this invalidate change is not there. I do suspect this might be Dove specific. But yet, Catalin, could you confirm the behavior difference of "invalidate" before and after MMU is actaully turned on?

#5 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

Quoted 26 lines · Eric Miao
Quoted 6 lines · Catalin Marinas
Quoted 5 lines · Saeed Bishara
---
  arch/arm/boot/compressed/head.S |    1 +
  1 files changed, 1 insertions(+), 0 deletions(-)
Quoted 17 lines
Quoted 8 lines
arch/arm/boot/compressed/head.S +0 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
                 mcr     p15, 0, r0, c1, c0, 0   @ load control

register

Quoted 5 lines
                 mrc     p15, 0, r0, c1, c0, 0   @ and read it back
                 mov     r0, #0

+ mcr p15, 0, r0, c8, c7, 0 @ invalidate I,D TLBs
mcr p15, 0, r0, c7, c5, 4 @ ISB
mov pc, r12

The TLB invalidating is done earlier in the __armv7_mmu_cache_on function, why do you need to do it again?

Quoted 8 lines

Well, the only difference between these two "invalidate"s looks like one is before control register load and one after.

We do have the problem of slow decompressing when this invalidate change is not there. I do suspect this might be Dove specific. But yet, Catalin, could you confirm the behavior difference of "invalidate" before and after MMU is actaully turned on?

I also met this slow decompressing issue without this patch when I was trying kexec on Freescale imx51 babbage board.

Sascha, do you have any comments on this?

Thanks,

Signature · 5 lines
Bryan Wu <[email protected]>
Kernel Developer    +86.138-1617-6545 Mobile
Ubuntu Kernel Team | Hardware Enablement Team
Canonical Ltd.      www.canonical.com
Ubuntu - Linux for human beings | www.ubuntu.com
#6 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

In reply to Saeed Bishara
Quoted 10 lines · Saeed Bishara
---
 arch/arm/boot/compressed/head.S |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/boot/compressed/head.S +0 -0
index 4fddc50..a1ab79f 100644

arch/arm/boot/compressed/head.S __armv7_mmu_cache_on: · line 495

Quoted 7 lines
arch/arm/boot/compressed/head.S +1 -0
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
 		mcr	p15, 0, r0, c1, c0, 0	@ load control register
 		mrc	p15, 0, r0, c1, c0, 0	@ and read it back
 		mov	r0, #0
+		mcr	p15, 0, r0, c8, c7, 0	@ invalidate I,D TLBs
 		mcr	p15, 0, r0, c7, c5, 4	@ ISB
 		mov	pc, r12
 

This can't be unconditional - if we're running on PMSA (iow, uclinux) we should not execute this instruction. Notice that the previous one is conditional.

The other question is whether this should be done before or after the ISB - if it's done before, my understanding is that it could occur unordered with respect to the MMU being enabled - if that's indeed the problem.

#7 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

Quoted 6 lines · Russell King - ARM Linux
Quoted 5 lines · Saeed Bishara
---
 arch/arm/boot/compressed/head.S |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
Quoted 17 lines

arch/arm/boot/compressed/head.S __armv7_mmu_cache_on: · line 495

Quoted 12 lines
arch/arm/boot/compressed/head.S +1 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
              mcr     p15, 0, r0, c1, c0, 0   @ load control register
              mrc     p15, 0, r0, c1, c0, 0   @ and read it back
              mov     r0, #0
+             mcr     p15, 0, r0, c8, c7, 0   @ invalidate I,D TLBs
              mcr     p15, 0, r0, c7, c5, 4   @ ISB
              mov     pc, r12
 

This can't be unconditional - if we're running on PMSA (iow, uclinux) we should not execute this instruction. Notice that the previous one is conditional.

This is true and needs to be fixed.

Quoted 5 lines

The other question is whether this should be done before or after the ISB - if it's done before, my understanding is that it could occur unordered with respect to the MMU being enabled - if that's indeed the problem.

Another noticeable difference is the slow decompressing happens so far on kexec only, a normal boot without this additional "invalidate" does not exhibit such slowness. This leads to me to suspect that the MMU state might not be same between a normal bootup and a kexec soft reboot.

I may overlooked, but it looks to me that after a 1:1 mapping of ther user space area (from 0x0000_0000 to TASK_SIZE, which I guess will cause some other issue if the kexec kernel start entry starts beyond TASK_SIZE?), the MMU is NOT actually turned off through the reset. This might cause weird behavior with the original sequence of __armv7_mmu_cache_on ??

#8 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

Quoted 34 lines · Eric Miao
Quoted 6 lines · Russell King - ARM Linux
Quoted 5 lines · Saeed Bishara

---
?arch/arm/boot/compressed/head.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)

Quoted 17 lines
Quoted 5 lines
arch/arm/boot/compressed/head.S +0 -0
index 4fddc50..a1ab79f 100644
@@ -489,6 +489,7 @@ __armv7_mmu_cache_on:
Quoted 7 lines

? ? ? ? ? ? ? mcr ? ? p15, 0, r0, c1, c0, 0 ? @ load control register ? ? ? ? ? ? ? mrc ? ? p15, 0, r0, c1, c0, 0 ? @ and read it back ? ? ? ? ? ? ? mov ? ? r0, #0
+ ? ? ? ? ? ? mcr ? ? p15, 0, r0, c8, c7, 0 ? @ invalidate I,D TLBs ? ? ? ? ? ? ? mcr ? ? p15, 0, r0, c7, c5, 4 ? @ ISB
? ? ? ? ? ? ? mov ? ? pc, r12

This can't be unconditional - if we're running on PMSA (iow, uclinux) we should not execute this instruction. ?Notice that the previous one is conditional.

This is true and needs to be fixed.

Quoted 5 lines

The other question is whether this should be done before or after the ISB - if it's done before, my understanding is that it could occur unordered with respect to the MMU being enabled - if that's indeed the problem.

Quoted 5 lines

Another noticeable difference is the slow decompressing happens so far on kexec only, a normal boot without this additional "invalidate" does not exhibit such slowness. This leads to me to suspect that the MMU state might not be same between a normal bootup and a kexec soft reboot.

BTW: this happens on imx51 as well, so I suspect it's not Marvell dove specific.

Quoted 6 lines

I may overlooked, but it looks to me that after a 1:1 mapping of ther user space area (from 0x0000_0000 to TASK_SIZE, which I guess will cause some other issue if the kexec kernel start entry starts beyond TASK_SIZE?), the MMU is NOT actually turned off through the reset. This might cause weird behavior with the original sequence of __armv7_mmu_cache_on ??

#9 lore raw

PATCH 2/2 arm: invalidate TLBs when enabling mmu

In reply to Eric Miao
Quoted 10 lines · Eric Miao

Another noticeable difference is the slow decompressing happens so far on kexec only, a normal boot without this additional "invalidate" does not exhibit such slowness. This leads to me to suspect that the MMU state might not be same between a normal bootup and a kexec soft reboot.

I may overlooked, but it looks to me that after a 1:1 mapping of ther user space area (from 0x0000_0000 to TASK_SIZE, which I guess will cause some other issue if the kexec kernel start entry starts beyond TASK_SIZE?), the MMU is NOT actually turned off through the reset. This might cause weird behavior with the original sequence of __armv7_mmu_cache_on ??

For kexec:

        cpu_proc_fin();
        setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
        cpu_reset(reboot_code_buffer_phys);

cpu_proc_fin() disables interrupts, flushes the cache and then disables caches.

setup_mm_for_reboot() creates 1:1 mappings for the entire user address space, which ends up being strongly ordered.

cpu_reset() is supposed to invalidate I/D caches, invalidate TLBs, and disable the MMU prior to calling the passed address. However, neither ARMv6 nor ARMv7 does this - and I'm confused as to why not.

#10 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

In reply to Saeed Bishara
Quoted 10 lines · Saeed Bishara
---
 arch/arm/mm/proc-v7.S |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/arm/mm/proc-v7.S +0 -0
index 7aaf88a..06cc36c 100644

arch/arm/mm/proc-v7.S ENTRY(cpu_v7_proc_fin) · line 61

Quoted 10 lines
arch/arm/mm/proc-v7.S +5 -0
@@ -52,6 +52,11 @@ ENTRY(cpu_v7_proc_fin)
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x0006                 @ .............ca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
+#ifdef CONFIG_OUTER_CACHE
+       mrc     p15, 0, r0, c1, c0, 1
+       bic     r0, r0, #0x2
+       mcr     p15, 0, r0, c1, c0, 1           @ disable L2 cache
+#endif
        ldmfd   sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)

NACK.

I'm not sure why kexec doesn't work but bit 1 in this register has different meanings on Cortex-A8 and A9.

Also, on Cortex-A8, it means L2EN but this refers to the inner L2 rather than the outer cache (that's configurable via the L2 Auxiliary Cache Control Register but the Linux meaning of outer cache is a separate device outside the CPU acting as a cache controller).

Signature · 1 line
Catalin
#11 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

Quoted 24 lines · Catalin Marinas
Quoted 10 lines · Saeed Bishara
---
 arch/arm/mm/proc-v7.S |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/arm/mm/proc-v7.S +0 -0
index 7aaf88a..06cc36c 100644

arch/arm/mm/proc-v7.S ENTRY(cpu_v7_proc_fin) · line 61

Quoted 10 lines
arch/arm/mm/proc-v7.S +5 -0
@@ -52,6 +52,11 @@ ENTRY(cpu_v7_proc_fin)
        bic     r0, r0, #0x1000                 @ ...i............
        bic     r0, r0, #0x0006                 @ .............ca.
        mcr     p15, 0, r0, c1, c0, 0           @ disable caches
+#ifdef CONFIG_OUTER_CACHE
+       mrc     p15, 0, r0, c1, c0, 1
+       bic     r0, r0, #0x2
+       mcr     p15, 0, r0, c1, c0, 1           @ disable L2 cache
+#endif
        ldmfd   sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)

NACK.

Quoted 7 lines

I'm not sure why kexec doesn't work but bit 1 in this register has different meanings on Cortex-A8 and A9.

Also, on Cortex-A8, it means L2EN but this refers to the inner L2 rather than the outer cache (that's configurable via the L2 Auxiliary Cache Control Register but the Linux meaning of outer cache is a separate device outside the CPU acting as a cache controller).

Plus there are two other ways to disable the inner L2 and then L2EN won't work like I replied earlier.

Regards,

Tony

#12 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

In reply to Saeed Bishara
Quoted 10 lines · Saeed Bishara
---
 arch/arm/mm/proc-v7.S |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/arm/mm/proc-v7.S +0 -0
index 7aaf88a..06cc36c 100644

arch/arm/mm/proc-v7.S ENTRY(cpu_v7_proc_fin) · line 61

Quoted 10 lines
arch/arm/mm/proc-v7.S +5 -0
@@ -52,6 +52,11 @@ ENTRY(cpu_v7_proc_fin)
 	bic	r0, r0, #0x1000			@ ...i............
 	bic	r0, r0, #0x0006			@ .............ca.
 	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+#ifdef CONFIG_OUTER_CACHE
+	mrc	p15, 0, r0, c1, c0, 1
+	bic	r0, r0, #0x2
+	mcr	p15, 0, r0, c1, c0, 1		@ disable L2 cache
+#endif
 	ldmfd	sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)

This one is a bit tricky. I know of three different ways to disable the L2 cache depending on the hardware. One of them is what you have above. The second is via SMI, and then the first one won't work. The third is via external secure monitor calls used on some omaps at least. And in the third case the first two methods won't work.

AFAIK disabling the c bit should also disable the outer cache. Anybody know if there's something else to it?

I'm currently thinking we should call outer_clean_range before hitting cpu_v6_proc_fin, then disable cache.

Regards,

Tony

#13 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

Quoted 5 lines

From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- bounces at lists.infradead.org] On Behalf Of Tony Lindgren
Sent: Wednesday, March 10, 2010 3:53 PM

Quoted 14 lines

arch/arm/mm/proc-v7.S ENTRY(cpu_v7_proc_fin) · line 61

Quoted 7 lines
arch/arm/mm/proc-v7.S +5 -0
+#ifdef CONFIG_OUTER_CACHE
+   mrc     p15, 0, r0, c1, c0, 1
+   bic     r0, r0, #0x2
+   mcr     p15, 0, r0, c1, c0, 1           @ disable L2 cache
+#endif
    ldmfd   sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)

This one is a bit tricky. I know of three different ways to disable the L2 cache depending on the hardware. One of them is what you have above. The second is via SMI, and then the first one won't work. The third is via external secure monitor calls used on some omaps at least. And in the third case the first two methods won't work.

On A8 cores with integrated L2 cache the L2EN bit is banked after r0px series (you won't find r0 systems anywhere). As such the above code is good on OMAP3 and many other A8's. Other bits in this same register have issues which you warn of. But not the L2EN.

On A9 which uses outer cache the above won't work. The external PL310 (or variant) is memory mapped. To handle a different sequence is needed all together.

Regards,
Richard W.

#14 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

Quoted 20 lines · Woodruff, Richard
Quoted 5 lines

From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- bounces at lists.infradead.org] On Behalf Of Tony Lindgren
Sent: Wednesday, March 10, 2010 3:53 PM

Quoted 14 lines

arch/arm/mm/proc-v7.S ENTRY(cpu_v7_proc_fin) · line 61

Quoted 7 lines
arch/arm/mm/proc-v7.S +5 -0
+#ifdef CONFIG_OUTER_CACHE
+   mrc     p15, 0, r0, c1, c0, 1
+   bic     r0, r0, #0x2
+   mcr     p15, 0, r0, c1, c0, 1           @ disable L2 cache
+#endif
    ldmfd   sp!, {pc}
 ENDPROC(cpu_v7_proc_fin)

This one is a bit tricky. I know of three different ways to disable the L2 cache depending on the hardware. One of them is what you have above. The second is via SMI, and then the first one won't work. The third is via external secure monitor calls used on some omaps at least. And in the third case the first two methods won't work.

Quoted 3 lines

On A8 cores with integrated L2 cache the L2EN bit is banked after r0px series (you won't find r0 systems anywhere). As such the above code is good on OMAP3 and many other A8's. Other bits in this same register have issues which you warn of. But not the L2EN.

On A9 which uses outer cache the above won't work. The external PL310 (or variant) is memory mapped. To handle a different sequence is needed all together.

Sounds like we need something like:

ENTRY(cpu_v7_proc_fin)
...

	mcr	p15, 0, r0, c1, c0, 0	@ disable caches
	b	cpu_v7_arch_proc_fin	@ disable L2 cache
	ldmfd	sp!, {pc}

ENDPROC(cpu_v7_proc_fin)

And then cpu_v7_arch_proc_fin can be implemented for the platforms that need special handling.

Regards,

Tony

#15 lore raw

PATCH 1/2 arm: disable L2 cache in the v7 finish function

Quoted 34 lines · Tony Lindgren
Quoted 20 lines · Woodruff, Richard
Quoted 5 lines

From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- bounces at lists.infradead.org] On Behalf Of Tony Lindgren
Sent: Wednesday, March 10, 2010 3:53 PM

Quoted 14 lines
Quoted 7 lines
(quoted diff) +5 -0
+#ifdef CONFIG_OUTER_CACHE
+ ? mrc ? ? p15, 0, r0, c1, c0, 1
+ ? bic ? ? r0, r0, #0x2
+ ? mcr ? ? p15, 0, r0, c1, c0, 1 ? ? ? ? ? @ disable L2 cache
+#endif

? ? ldmfd ? sp!, {pc}
?ENDPROC(cpu_v7_proc_fin)

This one is a bit tricky. I know of three different ways to disable the L2 cache depending on the hardware. One of them is what you have above. The second is via SMI, and then the first one won't work. The third is via external secure monitor calls used on some omaps at least. And in the third case the first two methods won't work.

Quoted 3 lines

On A8 cores with integrated L2 cache the L2EN bit is banked after r0px series (you won't find r0 systems anywhere). As such the above code is good on OMAP3 and many other A8's. ?Other bits in this same register have issues which you warn of. ?But not the L2EN.

On A9 which uses outer cache the above won't work. ?The external PL310 (or variant) is memory mapped. ?To handle a different sequence is needed all together.

Sounds like we need something like:

ENTRY(cpu_v7_proc_fin)
...
? ? ? ?mcr ? ? p15, 0, r0, c1, c0, 0 ? @ disable caches ? ? ? ?b ? ? ? cpu_v7_arch_proc_fin ? ?@ disable L2 cache ? ? ? ?ldmfd ? sp!, {pc} ENDPROC(cpu_v7_proc_fin)

Quoted 3 lines

And then cpu_v7_arch_proc_fin can be implemented for the platforms that need special handling.

Yeah, sort of I agree.

For outer cache, I also doubt that we might need to flush the L2 before disabling, though this may depend on the exact behavior of the specific cache controller. Introduce something like outer_cache_fns.finish() may be something feasible.

Quoted 9 lines

Regards,

Tony

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel