Add L2 cache cleaning to generic CPU suspend
Subsystems (2)
cover Add L2 cache cleaning to generic CPU suspend
Some systems (such as OMAP) preserve the L2 cache across a suspend/ resume cycle. This means they do not perform L2 cache maintanence in their suspend finisher function.
However, the side effect is that the saved CPU state is not readable by the resume code because it is sitting in the L2 cache.
This patch series adds L2 cache cleaning to the generic CPU suspend/ resume support code, making it possible to use this on systems with L2 cache enabled without having to clean/invalidate the entire L2 cache.
We also add a separate page table, allocated at boot time, for the resume process to use so we don't have to fiddle about with tweaking entries in the current processes page table. Moreover, the current processes page table may be in use by another CPU in the system if these paths are used from cpuidle or hotplug, so changing the page table is technically unsound.
Overall, this makes it possible for OMAP4 systems to use this code.
The first four patches in this set are already merged into Linus' tree as bug fixes, and are included here for completeness given that the kernel.org infrastructure is currently offline.
This has (so far) only been tested on OMAP4. Further testing on OMAP3 and Assabet will follow.
PATCH 1/11 ARM: pm: CPU specific code should not overwrite r1 (v:p offset)
r1 stores the v:p offset from the CPU invariant resume code, and is expected to be preserved by the CPU specific code. Overwriting it is not a good idea.
We've managed to get away with it on sa1100 platforms because most happen to have PHYS_OFFSET == PAGE_OFFSET, but that may not be the case depending on kernel configuration. So fix this latent bug.
This fixes xsc3 as well which was saving and restoring this register independently.
--- arch/arm/mm/proc-sa1100.S | 10 +++++----- arch/arm/mm/proc-xsc3.S | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-)
arch/arm/mm/proc-sa1100.S +5 -5
@@ -182,11 +182,11 @@ ENDPROC(cpu_sa1100_do_suspend) ENTRY(cpu_sa1100_do_resume) ldmia r0, {r4 - r7} @ load cp regs - mov r1, #0 - mcr p15, 0, r1, c8, c7, 0 @ flush I+D TLBs - mcr p15, 0, r1, c7, c7, 0 @ flush I&D cache - mcr p15, 0, r1, c9, c0, 0 @ invalidate RB - mcr p15, 0, r1, c9, c0, 5 @ allow user space to use RB + mov ip, #0 + mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs + mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache + mcr p15, 0, ip, c9, c0, 0 @ invalidate RB + mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB mcr p15, 0, r4, c3, c0, 0 @ domain ID mcr p15, 0, r5, c2, c0, 0 @ translation table base addr
arch/arm/mm/proc-xsc3.S +3 -3
@@ -406,7 +406,7 @@ ENTRY(cpu_xsc3_set_pte_ext) .align .globl cpu_xsc3_suspend_size -.equ cpu_xsc3_suspend_size, 4 * 8 +.equ cpu_xsc3_suspend_size, 4 * 7 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_xsc3_do_suspend) stmfd sp!, {r4 - r10, lr}
@@ -418,12 +418,12 @@ ENTRY(cpu_xsc3_do_suspend) mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg mrc p15, 0, r10, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit - stmia r0, {r1, r4 - r10} @ store v:p offset + cp regs + stmia r0, {r4 - r10} @ store cp regs ldmia sp!, {r4 - r10, pc} ENDPROC(cpu_xsc3_do_suspend) ENTRY(cpu_xsc3_do_resume) - ldmia r0, {r1, r4 - r10} @ load v:p offset + cp regs + ldmia r0, {r4 - r10} @ load cp regs mov ip, #0 mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
Signature · 1 line
1.7.4.4
PATCH 2/11 ARM: pm: arm920/926: fix number of registers saved
In reply to Russell King - ARM LinuxARM920 and ARM926 save four registers, not three. Fix the size of the suspend region required.
--- arch/arm/mm/proc-arm920.S | 2 +- arch/arm/mm/proc-arm926.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
arch/arm/mm/proc-arm920.S +1 -1
@@ -379,7 +379,7 @@ ENTRY(cpu_arm920_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm920_suspend_size -.equ cpu_arm920_suspend_size, 4 * 3 +.equ cpu_arm920_suspend_size, 4 * 4 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm920_do_suspend) stmfd sp!, {r4 - r7, lr}
arch/arm/mm/proc-arm926.S +1 -1
@@ -394,7 +394,7 @@ ENTRY(cpu_arm926_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm926_suspend_size -.equ cpu_arm926_suspend_size, 4 * 3 +.equ cpu_arm926_suspend_size, 4 * 4 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm926_do_suspend) stmfd sp!, {r4 - r7, lr}
Signature · 1 line
1.7.4.4
PATCH 3/11 ARM: pm: some ARMv7 requires a dsb in resume to ensure correctness
In reply to Russell King - ARM LinuxAdd a dsb after the isb to ensure that the previous writes to the CP15 registers take effect before we enable the MMU.
--- arch/arm/mm/proc-v7.S | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/mm/proc-v7.S +1 -0
@@ -255,6 +255,7 @@ ENTRY(cpu_v7_do_resume) mcr p15, 0, r4, c10, c2, 0 @ write PRRR mcr p15, 0, r5, c10, c2, 1 @ write NMRR isb + dsb mov r0, r9 @ control register mov r2, r7, lsr #14 @ get TTB0 base mov r2, r2, lsl #14
Signature · 1 line
1.7.4.4
PATCH 3/11 ARM: pm: some ARMv7 requires a dsb in resume to ensure correctness
Quoted 13 lines · Russell King - ARM Linux
Add a dsb after the isb to ensure that the previous writes to the CP15 registers take effect before we enable the MMU.
Signed-off-by Russell King <[email protected]>---
?arch/arm/mm/proc-v7.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)arch/arm/mm/proc-v7.S +0
-0@@ -255,6 +255,7 @@ ENTRY(cpu_v7_do_resume)
Quoted 4 lines
? ? ? ?mcr ? ? p15, 0, r4, c10, c2, 0 ?@ write PRRR ? ? ? ?mcr ? ? p15, 0, r5, c10, c2, 1 ?@ write NMRR ? ? ? ?isb
+ ? ? ? dsb
Isn't an ISB enough here? We usually have the DSB for some background operations like cache maintenance.
Signature · 1 line
Catalin
PATCH 3/11 ARM: pm: some ARMv7 requires a dsb in resume to ensure correctness
Quoted 10 lines · Catalin Marinas
Quoted 8 lines · Russell King - ARM Linux
Add a dsb after the isb to ensure that the previous writes to the CP15 registers take effect before we enable the MMU.
Signed-off-by Russell King <[email protected]>---
?arch/arm/mm/proc-v7.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)
Quoted 12 lines
Quoted 9 lines
arch/arm/mm/proc-v7.S +0
-0@@ -255,6 +255,7 @@ ENTRY(cpu_v7_do_resume)? ? ? ?mcr ? ? p15, 0, r4, c10, c2, 0 ?@ write PRRR ? ? ? ?mcr ? ? p15, 0, r5, c10, c2, 1 ?@ write NMRR ? ? ? ?isb
+ ? ? ? dsbIsn't an ISB enough here? We usually have the DSB for some background operations like cache maintenance.
That depends whether you're including the effects of the cache maintanence instructions in this. The ARM ARM tells me that a DSB is required to ensure that all cache maintanence is issued before the dsb is complete at the point that the dsb is executed.
So for architectural compliance, yes, a dsb is required. The isb is also required to ensure that instruction cache maintanence is properly visible.
PATCH 3/11 ARM: pm: some ARMv7 requires a dsb in resume to ensure correctness
Quoted 24 lines · Russell King - ARM Linux
Quoted 10 lines · Catalin Marinas
Quoted 8 lines · Russell King - ARM Linux
Add a dsb after the isb to ensure that the previous writes to the CP15 registers take effect before we enable the MMU.
Signed-off-by Russell King <[email protected]>---
?arch/arm/mm/proc-v7.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)Quoted 12 lines
Quoted 9 lines
arch/arm/mm/proc-v7.S +0
-0@@ -255,6 +255,7 @@ ENTRY(cpu_v7_do_resume)? ? ? ?mcr ? ? p15, 0, r4, c10, c2, 0 ?@ write PRRR ? ? ? ?mcr ? ? p15, 0, r5, c10, c2, 1 ?@ write NMRR ? ? ? ?isb
+ ? ? ? dsbIsn't an ISB enough here? We usually have the DSB for some background operations like cache maintenance.
Quoted 8 lines
That depends whether you're including the effects of the cache maintanence instructions in this. ?The ARM ARM tells me that a DSB is required to ensure that all cache maintanence is issued before the dsb is complete at the point that the dsb is executed.
So for architectural compliance, yes, a dsb is required. ?The isb is also required to ensure that instruction cache maintanence is properly visible.
That's correct, I got the wrong impression that there was a DSB earlier in the code after he TLB and cache maintenance, but that's not the case, so a DSB here is needed.
Signature · 1 line
Catalin
PATCH 3/11 ARM: pm: some ARMv7 requires a dsb in resume to ensure correctness
In reply to Russell King - ARM LinuxQuoted 24 lines · Russell King - ARM Linux
Quoted 10 lines · Catalin Marinas
Quoted 8 lines · Russell King - ARM Linux
Add a dsb after the isb to ensure that the previous writes to the CP15 registers take effect before we enable the MMU.
Signed-off-by Russell King <[email protected]>---
?arch/arm/mm/proc-v7.S | ? ?1 +
?1 files changed, 1 insertions(+), 0 deletions(-)Quoted 12 lines
Quoted 9 lines
arch/arm/mm/proc-v7.S +0
-0@@ -255,6 +255,7 @@ ENTRY(cpu_v7_do_resume)? ? ? ?mcr ? ? p15, 0, r4, c10, c2, 0 ?@ write PRRR ? ? ? ?mcr ? ? p15, 0, r5, c10, c2, 1 ?@ write NMRR ? ? ? ?isb
+ ? ? ? dsbIsn't an ISB enough here? We usually have the DSB for some background operations like cache maintenance.
Quoted 4 lines
That depends whether you're including the effects of the cache maintanence instructions in this. ?The ARM ARM tells me that a DSB is required to ensure that all cache maintanence is issued before the dsb is complete at the point that the dsb is executed.
Another minor point, in general we would use the DSB before the ISB (but that's when the I-cache is enabled).
Signature · 1 line
Catalin
PATCH 4/11 ARM: pm: avoid writing the auxillary control register for ARMv7
In reply to Russell King - ARM LinuxFor ARMv7 kernels running in the non-secure world, writing to the auxillary control register causes an abort, so we must avoid directly writing the auxillary control register. If the ACR has already been reinitialized by SoC code, don't try to restore it.
--- arch/arm/mm/proc-v7.S | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
arch/arm/mm/proc-v7.S +3 -1
@@ -248,7 +248,9 @@ ENTRY(cpu_v7_do_resume) mcr p15, 0, r7, c2, c0, 0 @ TTB 0 mcr p15, 0, r8, c2, c0, 1 @ TTB 1 mcr p15, 0, ip, c2, c0, 2 @ TTB control register - mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register + teq r4, r10 @ Is it already set? + mcrne p15, 0, r10, c1, c0, 1 @ No, so write it mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control ldr r4, =PRRR @ PRRR ldr r5, =NMRR @ NMRR
Signature · 1 line
1.7.4.4
PATCH 5/11 ARM: pm: force non-zero return value from __cpu_suspend when aborting
In reply to Russell King - ARM LinuxEnsure that the return value from __cpu_suspend is non-zero when aborting. Zero indicates a successful suspend occurred.
--- arch/arm/kernel/sleep.S | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/arm/kernel/sleep.S +2 -0
@@ -61,6 +61,8 @@ ENDPROC(__cpu_suspend) cpu_suspend_abort: ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn + teq r0, #0 + moveq r0, #1 @ force non-zero value mov sp, r2 ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_suspend_abort)
Signature · 1 line
1.7.4.4
PATCH 6/11 ARM: pm: preallocate a page table for suspend/resume
In reply to Russell King - ARM LinuxPreallocate a page table and setup an identity mapping for the MMU enable code. This means we don't have to "borrow" a page table to do this, avoiding complexities with L2 cache coherency.
--- arch/arm/include/asm/suspend.h | 17 +------------- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/sleep.S | 33 ++++++++++----------------- arch/arm/kernel/suspend.c | 47 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/proc-arm920.S | 4 --- arch/arm/mm/proc-arm926.S | 4 --- arch/arm/mm/proc-sa1100.S | 4 --- arch/arm/mm/proc-v6.S | 6 ----- arch/arm/mm/proc-v7.S | 6 ----- arch/arm/mm/proc-xsc3.S | 6 ----- arch/arm/mm/proc-xscale.S | 4 --- 11 files changed, 61 insertions(+), 72 deletions(-) create mode 100644 arch/arm/kernel/suspend.c
arch/arm/include/asm/suspend.h +1 -16
@@ -1,22 +1,7 @@#ifndef __ASM_ARM_SUSPEND_H#define __ASM_ARM_SUSPEND_H -#include <asm/memory.h> -#include <asm/tlbflush.h> -extern void cpu_resume (void ); - -/* -* Hide the first two arguments to __cpu_suspend - these are an implementation -* detail which platform code shouldn't have to know about. -*/ -static inline int cpu_suspend (unsigned long arg,int (*fn)(unsigned long )) -{ -extern int __cpu_suspend (int ,long ,unsigned long , -int (*)(unsigned long )); -int ret =__cpu_suspend (0 ,PHYS_OFFSET -PAGE_OFFSET , arg, fn); -flush_tlb_all (); -return ret; -} +extern int cpu_suspend (unsigned long ,int (*)(unsigned long ));#endif
arch/arm/kernel/Makefile +1 -1
@@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o -obj-$(CONFIG_PM_SLEEP) += sleep.o +obj-$(CONFIG_PM_SLEEP) += sleep.o suspend.o obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
arch/arm/kernel/sleep.S +12 -21
@@ -27,7 +27,7 @@ ENTRY(__cpu_suspend) sub sp, sp, r5 @ allocate CPU state on stack mov r0, sp @ save pointer to CPU save block add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn + stmfd sp!, {r6, ip} @ save virt SP, phys resume fn ldr r5, =sleep_save_sp add r6, sp, r1 @ convert SP to phys stmfd sp!, {r2, r3} @ save suspend func arg and pointer
@@ -60,7 +60,7 @@ ENDPROC(__cpu_suspend) .ltorg cpu_suspend_abort: - ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn + ldmia sp!, {r2 - r3} @ pop virt SP, phys resume fn teq r0, #0 moveq r0, #1 @ force non-zero value mov sp, r2
@@ -74,28 +74,19 @@ ENDPROC(cpu_suspend_abort) * r3 = L1 section flags */ ENTRY(cpu_resume_mmu) - adr r4, cpu_resume_turn_mmu_on - mov r4, r4, lsr #20 - orr r3, r3, r4, lsl #20 - ldr r5, [r2, r4, lsl #2] @ save old mapping - str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code - sub r2, r2, r1 ldr r3, =cpu_resume_after_mmu - bic r1, r0, #CR_C @ ensure D-cache is disabled b cpu_resume_turn_mmu_on ENDPROC(cpu_resume_mmu) .ltorg .align 5 -cpu_resume_turn_mmu_on: - mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc - mrc p15, 0, r1, c0, c0, 0 @ read id reg - mov r1, r1 - mov r1, r1 +ENTRY(cpu_resume_turn_mmu_on) + mcr p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc + mrc p15, 0, r0, c0, c0, 0 @ read id reg + mov r0, r0 + mov r0, r0 mov pc, r3 @ jump to virtual address ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: - str r5, [r2, r4, lsl #2] @ restore old mapping - mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache bl cpu_init @ restore the und/abt/irq banked regs mov r0, #0 @ return zero on success ldmfd sp!, {r4 - r11, pc}
@@ -121,11 +112,11 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off - @ load v:p, stack, resume fn - ARM( ldmia r0!, {r1, sp, pc} ) -THUMB( ldmia r0!, {r1, r2, r3} ) -THUMB( mov sp, r2 ) -THUMB( bx r3 ) + @ load stack, resume fn + ARM( ldmia r0!, {sp, pc} ) +THUMB( ldmia r0!, {r2, r3} ) +THUMB( mov sp, r2 ) +THUMB( bx r3 ) ENDPROC(cpu_resume) sleep_save_sp:
arch/arm/kernel/suspend.c new file +47 -0
47 lines not on this page · raw message
arch/arm/mm/proc-arm920.S +0 -4
@@ -400,10 +400,6 @@ ENTRY(cpu_arm920_do_resume) mcr p15, 0, r5, c3, c0, 0 @ Domain ID mcr p15, 0, r6, c2, c0, 0 @ TTB address mov r0, r7 @ control register - mov r2, r6, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ - PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_arm920_do_resume) #endif
arch/arm/mm/proc-arm926.S +0 -4
@@ -415,10 +415,6 @@ ENTRY(cpu_arm926_do_resume) mcr p15, 0, r5, c3, c0, 0 @ Domain ID mcr p15, 0, r6, c2, c0, 0 @ TTB address mov r0, r7 @ control register - mov r2, r6, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ - PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_arm926_do_resume) #endif
arch/arm/mm/proc-sa1100.S +0 -4
@@ -192,10 +192,6 @@ ENTRY(cpu_sa1100_do_resume) mcr p15, 0, r5, c2, c0, 0 @ translation table base addr mcr p15, 0, r6, c13, c0, 0 @ PID mov r0, r7 @ control register - mov r2, r5, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ - PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_sa1100_do_resume) #endif
arch/arm/mm/proc-v6.S +0 -6
@@ -161,14 +161,8 @@ ENTRY(cpu_v6_do_resume) mcr p15, 0, ip, c2, c0, 2 @ TTB control register mcr p15, 0, ip, c7, c5, 4 @ ISB mov r0, r11 @ control register - mov r2, r7, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, cpu_resume_l1_flags b cpu_resume_mmu ENDPROC(cpu_v6_do_resume) -cpu_resume_l1_flags: - ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) - ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) #endif string cpu_v6_name, "ARMv6-compatible processor"
arch/arm/mm/proc-v7.S +0 -6
@@ -259,14 +259,8 @@ ENTRY(cpu_v7_do_resume) isb dsb mov r0, r9 @ control register - mov r2, r7, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, cpu_resume_l1_flags b cpu_resume_mmu ENDPROC(cpu_v7_do_resume) -cpu_resume_l1_flags: - ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) - ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) #endif __CPUINIT
arch/arm/mm/proc-xsc3.S +0 -6
@@ -435,13 +435,7 @@ ENTRY(cpu_xsc3_do_resume) mcr p15, 0, r7, c3, c0, 0 @ domain ID mcr p15, 0, r8, c2, c0, 0 @ translation table base addr mcr p15, 0, r9, c1, c0, 1 @ auxiliary control reg - - @ temporarily map resume_turn_on_mmu into the page table, - @ otherwise prefetch abort occurs after MMU is turned on mov r0, r10 @ control register - mov r2, r8, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, =0x542e @ section flags b cpu_resume_mmu ENDPROC(cpu_xsc3_do_resume) #endif
arch/arm/mm/proc-xscale.S +0 -4
@@ -548,10 +548,6 @@ ENTRY(cpu_xscale_do_resume) mcr p15, 0, r8, c2, c0, 0 @ translation table base addr mcr p15, 0, r9, c1, c1, 0 @ auxiliary control reg mov r0, r10 @ control register - mov r2, r8, lsr #14 @ get TTB0 base - mov r2, r2, lsl #14 - ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \ - PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE b cpu_resume_mmu ENDPROC(cpu_xscale_do_resume) #endif
Signature · 1 line
1.7.4.4
PATCH 7/11 ARM: pm: only use preallocated page table during resume
In reply to Russell King - ARM LinuxOnly use the preallocated page table during the resume, not while suspending. This avoids the overhead of having to switch unnecessarily to the resume page table in the suspend path.
--- arch/arm/kernel/sleep.S | 19 +++++++++---------- arch/arm/kernel/suspend.c | 14 ++++++++------ arch/arm/mm/proc-arm920.S | 17 ++++++++--------- arch/arm/mm/proc-arm926.S | 17 ++++++++--------- arch/arm/mm/proc-sa1100.S | 21 ++++++++++----------- arch/arm/mm/proc-v6.S | 31 ++++++++++++++++--------------- arch/arm/mm/proc-v7.S | 33 +++++++++++++++++---------------- arch/arm/mm/proc-xsc3.S | 22 +++++++++++----------- arch/arm/mm/proc-xscale.S | 21 ++++++++++----------- 9 files changed, 97 insertions(+), 98 deletions(-)
arch/arm/kernel/sleep.S +9 -10
@@ -9,12 +9,14 @@ /* * Save CPU state for a suspend + * r0 = phys addr of temporary page tables * r1 = v:p offset * r2 = suspend function arg0 * r3 = suspend function */ ENTRY(__cpu_suspend) stmfd sp!, {r4 - r11, lr} + mov r4, r0 #ifdef MULTI_CPU ldr r10, =processor ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
@@ -27,7 +29,7 @@ ENTRY(__cpu_suspend) sub sp, sp, r5 @ allocate CPU state on stack mov r0, sp @ save pointer to CPU save block add ip, ip, r1 @ convert resume fn to phys - stmfd sp!, {r6, ip} @ save virt SP, phys resume fn + stmfd sp!, {r4, r6, ip} @ save phys pgd, virt SP, phys resume fn ldr r5, =sleep_save_sp add r6, sp, r1 @ convert SP to phys stmfd sp!, {r2, r3} @ save suspend func arg and pointer
@@ -60,7 +62,7 @@ ENDPROC(__cpu_suspend) .ltorg cpu_suspend_abort: - ldmia sp!, {r2 - r3} @ pop virt SP, phys resume fn + ldmia sp!, {r1 - r3} @ pop phys pgd, virt SP, phys resume fn teq r0, #0 moveq r0, #1 @ force non-zero value mov sp, r2
@@ -69,9 +71,6 @@ ENDPROC(cpu_suspend_abort) /* * r0 = control register value - * r1 = v:p offset (preserved by cpu_do_resume) - * r2 = phys page table base - * r3 = L1 section flags */ ENTRY(cpu_resume_mmu) ldr r3, =cpu_resume_after_mmu
@@ -112,11 +111,11 @@ ENTRY(cpu_resume) ldr r0, sleep_save_sp @ stack phys addr #endif setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off - @ load stack, resume fn - ARM( ldmia r0!, {sp, pc} ) -THUMB( ldmia r0!, {r2, r3} ) -THUMB( mov sp, r2 ) -THUMB( bx r3 ) + @ load phys pgd, stack, resume fn + ARM( ldmia r0!, {r1, sp, pc} ) +THUMB( ldmia r0!, {r1, r2, r3} ) +THUMB( mov sp, r2 ) +THUMB( bx r3 ) ENDPROC(cpu_resume) sleep_save_sp:
arch/arm/kernel/suspend.c +8 -6
@@ -24,13 +24,15 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))return -EINVAL ;/* -* Temporarily switch the page tables to our suspend page -* tables, which contain the temporary identity mapping -* required for resuming. +* Provide a temporary page table with an identity mapping for +* the MMU-enable code, required for resuming. On successful +* resume (indicated by a zero return code), we need to switch +* back to the correct page tables. */ -cpu_switch_mm (suspend_pgd, mm); - ret =__cpu_suspend (0 ,PHYS_OFFSET -PAGE_OFFSET , arg, fn); -cpu_switch_mm (mm->pgd, mm); + ret =__cpu_suspend (virt_to_phys (suspend_pgd), +PHYS_OFFSET -PAGE_OFFSET , arg, fn); +if (ret ==0 ) +cpu_switch_mm (mm->pgd, mm);return ret; }
arch/arm/mm/proc-arm920.S +8 -9
@@ -379,27 +379,26 @@ ENTRY(cpu_arm920_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm920_suspend_size -.equ cpu_arm920_suspend_size, 4 * 4 +.equ cpu_arm920_suspend_size, 4 * 3 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm920_do_suspend) - stmfd sp!, {r4 - r7, lr} + stmfd sp!, {r4 - r6, lr} mrc p15, 0, r4, c13, c0, 0 @ PID mrc p15, 0, r5, c3, c0, 0 @ Domain ID - mrc p15, 0, r6, c2, c0, 0 @ TTB address - mrc p15, 0, r7, c1, c0, 0 @ Control register - stmia r0, {r4 - r7} - ldmfd sp!, {r4 - r7, pc} + mrc p15, 0, r6, c1, c0, 0 @ Control register + stmia r0, {r4 - r6} + ldmfd sp!, {r4 - r6, pc} ENDPROC(cpu_arm920_do_suspend) ENTRY(cpu_arm920_do_resume) mov ip, #0 mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches - ldmia r0, {r4 - r7} + ldmia r0, {r4 - r6} mcr p15, 0, r4, c13, c0, 0 @ PID mcr p15, 0, r5, c3, c0, 0 @ Domain ID - mcr p15, 0, r6, c2, c0, 0 @ TTB address - mov r0, r7 @ control register + mcr p15, 0, r1, c2, c0, 0 @ TTB address + mov r0, r6 @ control register b cpu_resume_mmu ENDPROC(cpu_arm920_do_resume) #endif
arch/arm/mm/proc-arm926.S +8 -9
@@ -394,27 +394,26 @@ ENTRY(cpu_arm926_set_pte_ext) /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ .globl cpu_arm926_suspend_size -.equ cpu_arm926_suspend_size, 4 * 4 +.equ cpu_arm926_suspend_size, 4 * 3 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_arm926_do_suspend) - stmfd sp!, {r4 - r7, lr} + stmfd sp!, {r4 - r6, lr} mrc p15, 0, r4, c13, c0, 0 @ PID mrc p15, 0, r5, c3, c0, 0 @ Domain ID - mrc p15, 0, r6, c2, c0, 0 @ TTB address - mrc p15, 0, r7, c1, c0, 0 @ Control register - stmia r0, {r4 - r7} - ldmfd sp!, {r4 - r7, pc} + mrc p15, 0, r6, c1, c0, 0 @ Control register + stmia r0, {r4 - r6} + ldmfd sp!, {r4 - r6, pc} ENDPROC(cpu_arm926_do_suspend) ENTRY(cpu_arm926_do_resume) mov ip, #0 mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches - ldmia r0, {r4 - r7} + ldmia r0, {r4 - r6} mcr p15, 0, r4, c13, c0, 0 @ PID mcr p15, 0, r5, c3, c0, 0 @ Domain ID - mcr p15, 0, r6, c2, c0, 0 @ TTB address - mov r0, r7 @ control register + mcr p15, 0, r1, c2, c0, 0 @ TTB address + mov r0, r6 @ control register b cpu_resume_mmu ENDPROC(cpu_arm926_do_resume) #endif
arch/arm/mm/proc-sa1100.S +10 -11
@@ -168,20 +168,19 @@ ENTRY(cpu_sa1100_set_pte_ext) mov pc, lr .globl cpu_sa1100_suspend_size -.equ cpu_sa1100_suspend_size, 4*4 +.equ cpu_sa1100_suspend_size, 4 * 3 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_sa1100_do_suspend) - stmfd sp!, {r4 - r7, lr} + stmfd sp!, {r4 - r6, lr} mrc p15, 0, r4, c3, c0, 0 @ domain ID - mrc p15, 0, r5, c2, c0, 0 @ translation table base addr - mrc p15, 0, r6, c13, c0, 0 @ PID - mrc p15, 0, r7, c1, c0, 0 @ control reg - stmia r0, {r4 - r7} @ store cp regs - ldmfd sp!, {r4 - r7, pc} + mrc p15, 0, r5, c13, c0, 0 @ PID + mrc p15, 0, r6, c1, c0, 0 @ control reg + stmia r0, {r4 - r6} @ store cp regs + ldmfd sp!, {r4 - r6, pc} ENDPROC(cpu_sa1100_do_suspend) ENTRY(cpu_sa1100_do_resume) - ldmia r0, {r4 - r7} @ load cp regs + ldmia r0, {r4 - r6} @ load cp regs mov ip, #0 mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache
@@ -189,9 +188,9 @@ ENTRY(cpu_sa1100_do_resume) mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB mcr p15, 0, r4, c3, c0, 0 @ domain ID - mcr p15, 0, r5, c2, c0, 0 @ translation table base addr - mcr p15, 0, r6, c13, c0, 0 @ PID - mov r0, r7 @ control register + mcr p15, 0, r1, c2, c0, 0 @ translation table base addr + mcr p15, 0, r5, c13, c0, 0 @ PID + mov r0, r6 @ control register b cpu_resume_mmu ENDPROC(cpu_sa1100_do_resume) #endif
arch/arm/mm/proc-v6.S +16 -15
@@ -128,20 +128,19 @@ ENTRY(cpu_v6_set_pte_ext) /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */ .globl cpu_v6_suspend_size -.equ cpu_v6_suspend_size, 4 * 8 +.equ cpu_v6_suspend_size, 4 * 7 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_v6_do_suspend) - stmfd sp!, {r4 - r11, lr} + stmfd sp!, {r4 - r10, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID mrc p15, 0, r5, c13, c0, 1 @ Context ID mrc p15, 0, r6, c3, c0, 0 @ Domain ID - mrc p15, 0, r7, c2, c0, 0 @ Translation table base 0 - mrc p15, 0, r8, c2, c0, 1 @ Translation table base 1 - mrc p15, 0, r9, c1, c0, 1 @ auxiliary control register - mrc p15, 0, r10, c1, c0, 2 @ co-processor access control - mrc p15, 0, r11, c1, c0, 0 @ control register - stmia r0, {r4 - r11} - ldmfd sp!, {r4- r11, pc} + mrc p15, 0, r7, c2, c0, 1 @ Translation table base 1 + mrc p15, 0, r8, c1, c0, 1 @ auxiliary control register + mrc p15, 0, r9, c1, c0, 2 @ co-processor access control + mrc p15, 0, r10, c1, c0, 0 @ control register + stmia r0, {r4 - r10} + ldmfd sp!, {r4- r10, pc} ENDPROC(cpu_v6_do_suspend) ENTRY(cpu_v6_do_resume)
@@ -150,17 +149,19 @@ ENTRY(cpu_v6_do_resume) mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, ip, c7, c10, 4 @ drain write buffer - ldmia r0, {r4 - r11} + ldmia r0, {r4 - r10} mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID mcr p15, 0, r5, c13, c0, 1 @ Context ID mcr p15, 0, r6, c3, c0, 0 @ Domain ID - mcr p15, 0, r7, c2, c0, 0 @ Translation table base 0 - mcr p15, 0, r8, c2, c0, 1 @ Translation table base 1 - mcr p15, 0, r9, c1, c0, 1 @ auxiliary control register - mcr p15, 0, r10, c1, c0, 2 @ co-processor access control + ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP) + ALT_UP(orr r1, r1, #TTB_FLAGS_UP) + mcr p15, 0, r1, c2, c0, 0 @ Translation table base 0 + mcr p15, 0, r7, c2, c0, 1 @ Translation table base 1 + mcr p15, 0, r8, c1, c0, 1 @ auxiliary control register + mcr p15, 0, r9, c1, c0, 2 @ co-processor access control mcr p15, 0, ip, c2, c0, 2 @ TTB control register mcr p15, 0, ip, c7, c5, 4 @ ISB - mov r0, r11 @ control register + mov r0, r10 @ control register b cpu_resume_mmu ENDPROC(cpu_v6_do_resume) #endif
arch/arm/mm/proc-v7.S +17 -16
@@ -217,22 +217,21 @@ ENDPROC(cpu_v7_set_pte_ext) /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */ .globl cpu_v7_suspend_size -.equ cpu_v7_suspend_size, 4 * 9 +.equ cpu_v7_suspend_size, 4 * 8 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_v7_do_suspend) - stmfd sp!, {r4 - r11, lr} + stmfd sp!, {r4 - r10, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID mrc p15, 0, r5, c13, c0, 1 @ Context ID mrc p15, 0, r6, c13, c0, 3 @ User r/o thread ID stmia r0!, {r4 - r6} mrc p15, 0, r6, c3, c0, 0 @ Domain ID - mrc p15, 0, r7, c2, c0, 0 @ TTB 0 - mrc p15, 0, r8, c2, c0, 1 @ TTB 1 - mrc p15, 0, r9, c1, c0, 0 @ Control register - mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register - mrc p15, 0, r11, c1, c0, 2 @ Co-processor access control - stmia r0, {r6 - r11} - ldmfd sp!, {r4 - r11, pc} + mrc p15, 0, r7, c2, c0, 1 @ TTB 1 + mrc p15, 0, r8, c1, c0, 0 @ Control register + mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control + stmia r0, {r6 - r10} + ldmfd sp!, {r4 - r10, pc} ENDPROC(cpu_v7_do_suspend) ENTRY(cpu_v7_do_resume)
@@ -243,22 +242,24 @@ ENTRY(cpu_v7_do_resume) mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID mcr p15, 0, r5, c13, c0, 1 @ Context ID mcr p15, 0, r6, c13, c0, 3 @ User r/o thread ID - ldmia r0, {r6 - r11} + ldmia r0, {r6 - r10} mcr p15, 0, r6, c3, c0, 0 @ Domain ID - mcr p15, 0, r7, c2, c0, 0 @ TTB 0 - mcr p15, 0, r8, c2, c0, 1 @ TTB 1 + ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP) + ALT_UP(orr r1, r1, #TTB_FLAGS_UP) + mcr p15, 0, r1, c2, c0, 0 @ TTB 0 + mcr p15, 0, r7, c2, c0, 1 @ TTB 1 mcr p15, 0, ip, c2, c0, 2 @ TTB control register mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register - teq r4, r10 @ Is it already set? - mcrne p15, 0, r10, c1, c0, 1 @ No, so write it - mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control + teq r4, r9 @ Is it already set? + mcrne p15, 0, r9, c1, c0, 1 @ No, so write it + mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control ldr r4, =PRRR @ PRRR ldr r5, =NMRR @ NMRR mcr p15, 0, r4, c10, c2, 0 @ write PRRR mcr p15, 0, r5, c10, c2, 1 @ write NMRR isb dsb - mov r0, r9 @ control register + mov r0, r8 @ control register b cpu_resume_mmu ENDPROC(cpu_v7_do_resume) #endif
arch/arm/mm/proc-xsc3.S +11 -11
@@ -406,24 +406,23 @@ ENTRY(cpu_xsc3_set_pte_ext) .align .globl cpu_xsc3_suspend_size -.equ cpu_xsc3_suspend_size, 4 * 7 +.equ cpu_xsc3_suspend_size, 4 * 6 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_xsc3_do_suspend) - stmfd sp!, {r4 - r10, lr} + stmfd sp!, {r4 - r9, lr} mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode mrc p15, 0, r5, c15, c1, 0 @ CP access reg mrc p15, 0, r6, c13, c0, 0 @ PID mrc p15, 0, r7, c3, c0, 0 @ domain ID - mrc p15, 0, r8, c2, c0, 0 @ translation table base addr - mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg - mrc p15, 0, r10, c1, c0, 0 @ control reg + mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg + mrc p15, 0, r9, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit - stmia r0, {r4 - r10} @ store cp regs - ldmia sp!, {r4 - r10, pc} + stmia r0, {r4 - r9} @ store cp regs + ldmia sp!, {r4 - r9, pc} ENDPROC(cpu_xsc3_do_suspend) ENTRY(cpu_xsc3_do_resume) - ldmia r0, {r4 - r10} @ load cp regs + ldmia r0, {r4 - r9} @ load cp regs mov ip, #0 mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
@@ -433,9 +432,10 @@ ENTRY(cpu_xsc3_do_resume) mcr p15, 0, r5, c15, c1, 0 @ CP access reg mcr p15, 0, r6, c13, c0, 0 @ PID mcr p15, 0, r7, c3, c0, 0 @ domain ID - mcr p15, 0, r8, c2, c0, 0 @ translation table base addr - mcr p15, 0, r9, c1, c0, 1 @ auxiliary control reg - mov r0, r10 @ control register + orr r1, r1, #0x18 @ cache the page table in L2 + mcr p15, 0, r1, c2, c0, 0 @ translation table base addr + mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg + mov r0, r9 @ control register b cpu_resume_mmu ENDPROC(cpu_xsc3_do_resume) #endif
arch/arm/mm/proc-xscale.S +10 -11
@@ -520,24 +520,23 @@ ENTRY(cpu_xscale_set_pte_ext) .align .globl cpu_xscale_suspend_size -.equ cpu_xscale_suspend_size, 4 * 7 +.equ cpu_xscale_suspend_size, 4 * 6 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_xscale_do_suspend) - stmfd sp!, {r4 - r10, lr} + stmfd sp!, {r4 - r9, lr} mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode mrc p15, 0, r5, c15, c1, 0 @ CP access reg mrc p15, 0, r6, c13, c0, 0 @ PID mrc p15, 0, r7, c3, c0, 0 @ domain ID - mrc p15, 0, r8, c2, c0, 0 @ translation table base addr - mrc p15, 0, r9, c1, c1, 0 @ auxiliary control reg - mrc p15, 0, r10, c1, c0, 0 @ control reg + mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mrc p15, 0, r9, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit - stmia r0, {r4 - r10} @ store cp regs - ldmfd sp!, {r4 - r10, pc} + stmia r0, {r4 - r9} @ store cp regs + ldmfd sp!, {r4 - r9, pc} ENDPROC(cpu_xscale_do_suspend) ENTRY(cpu_xscale_do_resume) - ldmia r0, {r4 - r10} @ load cp regs + ldmia r0, {r4 - r9} @ load cp regs mov ip, #0 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
@@ -545,9 +544,9 @@ ENTRY(cpu_xscale_do_resume) mcr p15, 0, r5, c15, c1, 0 @ CP access reg mcr p15, 0, r6, c13, c0, 0 @ PID mcr p15, 0, r7, c3, c0, 0 @ domain ID - mcr p15, 0, r8, c2, c0, 0 @ translation table base addr - mcr p15, 0, r9, c1, c1, 0 @ auxiliary control reg - mov r0, r10 @ control register + mcr p15, 0, r1, c2, c0, 0 @ translation table base addr + mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mov r0, r9 @ control register b cpu_resume_mmu ENDPROC(cpu_xscale_do_resume) #endif
Signature · 1 line
1.7.4.4
PATCH 8/11 ARM: pm: no need to save/restore context ID register
In reply to Russell King - ARM LinuxThere is no need to save and restore the context ID register on ARMv6 and ARMv7 with a temporary page table as we write the context ID register when we switch back to the real page tables for the thread.
Moreover, the temporary page tables do not contain any non-global mappings, so the context ID value should not be used. To be safe, initialize the register to a reserved context ID value.
--- arch/arm/mm/proc-v6.S | 33 ++++++++++++++++----------------- arch/arm/mm/proc-v7.S | 13 ++++++------- 2 files changed, 22 insertions(+), 24 deletions(-)
arch/arm/mm/proc-v6.S +16 -17
@@ -128,19 +128,18 @@ ENTRY(cpu_v6_set_pte_ext) /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */ .globl cpu_v6_suspend_size -.equ cpu_v6_suspend_size, 4 * 7 +.equ cpu_v6_suspend_size, 4 * 6 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_v6_do_suspend) - stmfd sp!, {r4 - r10, lr} + stmfd sp!, {r4 - r9, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID - mrc p15, 0, r5, c13, c0, 1 @ Context ID - mrc p15, 0, r6, c3, c0, 0 @ Domain ID - mrc p15, 0, r7, c2, c0, 1 @ Translation table base 1 - mrc p15, 0, r8, c1, c0, 1 @ auxiliary control register - mrc p15, 0, r9, c1, c0, 2 @ co-processor access control - mrc p15, 0, r10, c1, c0, 0 @ control register - stmia r0, {r4 - r10} - ldmfd sp!, {r4- r10, pc} + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 1 @ Translation table base 1 + mrc p15, 0, r7, c1, c0, 1 @ auxiliary control register + mrc p15, 0, r8, c1, c0, 2 @ co-processor access control + mrc p15, 0, r9, c1, c0, 0 @ control register + stmia r0, {r4 - r9} + ldmfd sp!, {r4- r9, pc} ENDPROC(cpu_v6_do_suspend) ENTRY(cpu_v6_do_resume)
@@ -149,19 +148,19 @@ ENTRY(cpu_v6_do_resume) mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, ip, c7, c10, 4 @ drain write buffer - ldmia r0, {r4 - r10} + mcr p15, 0, ip, c13, 0, 1 @ set reserved context ID + ldmia r0, {r4 - r9} mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID - mcr p15, 0, r5, c13, c0, 1 @ Context ID - mcr p15, 0, r6, c3, c0, 0 @ Domain ID + mcr p15, 0, r5, c3, c0, 0 @ Domain ID ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP) ALT_UP(orr r1, r1, #TTB_FLAGS_UP) mcr p15, 0, r1, c2, c0, 0 @ Translation table base 0 - mcr p15, 0, r7, c2, c0, 1 @ Translation table base 1 - mcr p15, 0, r8, c1, c0, 1 @ auxiliary control register - mcr p15, 0, r9, c1, c0, 2 @ co-processor access control + mcr p15, 0, r6, c2, c0, 1 @ Translation table base 1 + mcr p15, 0, r7, c1, c0, 1 @ auxiliary control register + mcr p15, 0, r8, c1, c0, 2 @ co-processor access control mcr p15, 0, ip, c2, c0, 2 @ TTB control register mcr p15, 0, ip, c7, c5, 4 @ ISB - mov r0, r10 @ control register + mov r0, r9 @ control register b cpu_resume_mmu ENDPROC(cpu_v6_do_resume) #endif
arch/arm/mm/proc-v7.S +6 -7
@@ -217,14 +217,13 @@ ENDPROC(cpu_v7_set_pte_ext) /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */ .globl cpu_v7_suspend_size -.equ cpu_v7_suspend_size, 4 * 8 +.equ cpu_v7_suspend_size, 4 * 7 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_v7_do_suspend) stmfd sp!, {r4 - r10, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID - mrc p15, 0, r5, c13, c0, 1 @ Context ID - mrc p15, 0, r6, c13, c0, 3 @ User r/o thread ID - stmia r0!, {r4 - r6} + mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID + stmia r0!, {r4 - r5} mrc p15, 0, r6, c3, c0, 0 @ Domain ID mrc p15, 0, r7, c2, c0, 1 @ TTB 1 mrc p15, 0, r8, c1, c0, 0 @ Control register
@@ -238,10 +237,10 @@ ENTRY(cpu_v7_do_resume) mov ip, #0 mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache - ldmia r0!, {r4 - r6} + mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID + ldmia r0!, {r4 - r5} mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID - mcr p15, 0, r5, c13, c0, 1 @ Context ID - mcr p15, 0, r6, c13, c0, 3 @ User r/o thread ID + mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID ldmia r0, {r6 - r10} mcr p15, 0, r6, c3, c0, 0 @ Domain ID ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
Signature · 1 line
1.7.4.4
PATCH 8/11 ARM: pm: no need to save/restore context ID register
Quoted 48 lines · Russell King - ARM Linux
There is no need to save and restore the context ID register on ARMv6 and ARMv7 with a temporary page table as we write the context ID register when we switch back to the real page tables for the thread.
Moreover, the temporary page tables do not contain any non-global mappings, so the context ID value should not be used. To be safe, initialize the register to a reserved context ID value.
Signed-off-by Russell King<[email protected]>--- arch/arm/mm/proc-v6.S | 33 ++++++++++++++++----------------- arch/arm/mm/proc-v7.S | 13 ++++++------- 2 files changed, 22 insertions(+), 24 deletions(-)arch/arm/mm/proc-v6.S +9
-10@@ -128,19 +128,18 @@ ENTRY(cpu_v6_set_pte_ext) /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */ .globl cpu_v6_suspend_size -.equ cpu_v6_suspend_size, 4 * 7 +.equ cpu_v6_suspend_size, 4 * 6 #ifdef CONFIG_PM_SLEEP ENTRY(cpu_v6_do_suspend) - stmfd sp!, {r4 - r10, lr} + stmfd sp!, {r4 - r9, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID - mrc p15, 0, r5, c13, c0, 1 @ Context ID - mrc p15, 0, r6, c3, c0, 0 @ Domain ID - mrc p15, 0, r7, c2, c0, 1 @ Translation table base 1 - mrc p15, 0, r8, c1, c0, 1 @ auxiliary control register - mrc p15, 0, r9, c1, c0, 2 @ co-processor access control - mrc p15, 0, r10, c1, c0, 0 @ control register - stmia r0, {r4 - r10} - ldmfd sp!, {r4- r10, pc} + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 1 @ Translation table base 1 + mrc p15, 0, r7, c1, c0, 1 @ auxiliary control register + mrc p15, 0, r8, c1, c0, 2 @ co-processor access control + mrc p15, 0, r9, c1, c0, 0 @ control register + stmia r0, {r4 - r9} + ldmfd sp!, {r4- r9, pc} ENDPROC(cpu_v6_do_suspend) ENTRY(cpu_v6_do_resume)
arch/arm/mm/proc-v6.S ENTRY(cpu_v6_do_resume) · line 151
Quoted 5 lines
arch/arm/mm/proc-v6.S +1
-1@@ -149,19 +148,19 @@ ENTRY(cpu_v6_do_resume) mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, ip, c7, c10, 4 @ drain write buffer - ldmia r0, {r4 - r10} + mcr p15, 0, ip, c13, 0, 1 @ set reserved context ID
Typo which results in build error.
Error: co-processor register expected -- `mcr p15,0,ip,c13,0,1'
You can fold below fix.
arch/arm/mm/proc-v6.S +1 -1
@@ -148,7 +148,7 @@ ENTRY(cpu_v6_do_resume) mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, ip, c7, c10, 4 @ drain write buffer - mcr p15, 0, ip, c13, 0, 1 @ set reserved context ID + mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID ldmia r0, {r4 - r9} mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID mcr p15, 0, r5, c3, c0, 0 @ Domain ID
Signature · 4 lines
1.7.4.1 Regards Santosh
PATCH 8/11 ARM: pm: no need to save/restore context ID register
Quoted 4 lines · Santosh
Typo which results in build error.
Error: co-processor register expected -- `mcr p15,0,ip,c13,0,1'You can fold below fix.
Kevin already reported this, and I've already folded this fix in. Thanks.
PATCH 9/11 ARM: pm: get rid of cpu_resume_turn_mmu_on
In reply to Russell King - ARM LinuxWe don't require cpu_resume_turn_mmu_on as we can combine the ldr instruction with the following code provided we ensure that cpu_resume_mmu is aligned for older CPUs. Note that we also align to a 32-byte boundary to ensure that the code can't cross a section boundary.
--- arch/arm/kernel/sleep.S | 8 ++------ arch/arm/kernel/suspend.c | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-)
arch/arm/kernel/sleep.S +2 -6
@@ -72,19 +72,15 @@ ENDPROC(cpu_suspend_abort) /* * r0 = control register value */ + .align 5 ENTRY(cpu_resume_mmu) ldr r3, =cpu_resume_after_mmu - b cpu_resume_turn_mmu_on -ENDPROC(cpu_resume_mmu) - .ltorg - .align 5 -ENTRY(cpu_resume_turn_mmu_on) mcr p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc mrc p15, 0, r0, c0, c0, 0 @ read id reg mov r0, r0 mov r0, r0 mov pc, r3 @ jump to virtual address -ENDPROC(cpu_resume_turn_mmu_on) +ENDPROC(cpu_resume_mmu) cpu_resume_after_mmu: bl cpu_init @ restore the und/abt/irq banked regs mov r0, #0 @ return zero on success
arch/arm/kernel/suspend.c +2 -2
@@ -9,7 +9,7 @@static pgd_t *suspend_pgd;extern int __cpu_suspend (int ,long ,unsigned long ,int (*)(unsigned long )); -extern void cpu_resume_turn_mmu_on (void ); +extern void cpu_resume_mmu (void );/* * Hide the first two arguments to __cpu_suspend - these are an implementation
@@ -41,7 +41,7 @@ static int __init cpu_suspend_init(void) { suspend_pgd =pgd_alloc (&init_mm);if (suspend_pgd) { -unsigned long addr =virt_to_phys (cpu_resume_turn_mmu_on); +unsigned long addr =virt_to_phys (cpu_resume_mmu);identity_mapping_add (suspend_pgd, addr, addr +SECTION_SIZE ); }return suspend_pgd ?0 : -ENOMEM ;
Signature · 1 line
1.7.4.4
PATCH 10/11 ARM: pm: convert some assembly to C
In reply to Russell King - ARM LinuxConvert some of the sleep.S guts to C code, which makes it easier to use our macros and to add L2 cache handling. We provide a helper function, __cpu_suspend_save(), which deals with saving the common state, setting up for resume, and flushing caches.
The remainder left as assembly code is the saving of the CPU general purpose registers, and allocating space on the stack to save the CPU specific registers and resume state.
--- arch/arm/include/asm/proc-fns.h | 8 ++++++ arch/arm/kernel/sleep.S | 53 ++++++++++++-------------------------- arch/arm/kernel/suspend.c | 24 +++++++++++++++-- 3 files changed, 46 insertions(+), 39 deletions(-)
arch/arm/include/asm/proc-fns.h +8 -0
@@ -81,6 +81,10 @@ extern void cpu_dcache_clean_area(void *, int);extern void cpu_do_switch_mm (unsigned long pgd_phys,struct mm_struct *mm);extern void cpu_set_pte_ext (pte_t *ptep,pte_t pte,unsigned int ext);extern void cpu_reset (unsigned long addr) __attribute__((noreturn)); + +/* These three are private to arch/arm/kernel/suspend.c */ +extern void cpu_do_suspend (void *); +extern void cpu_do_resume (void *);#else #define cpu_proc_init processor._proc_init#define cpu_proc_fin processor._proc_fin
@@ -89,6 +93,10 @@ extern void cpu_reset(unsigned long addr) __attribute__((noreturn));#define cpu_dcache_clean_area processor.dcache_clean_area#define cpu_set_pte_ext processor.set_pte_ext#define cpu_do_switch_mm processor.switch_mm + +/* These three are private to arch/arm/kernel/suspend.c */ +#define cpu_do_suspend processor.do_suspend +#define cpu_do_resume processor.do_resume#endif extern void cpu_resume (void );
arch/arm/kernel/sleep.S +17 -36
71 lines not on this page · raw message
arch/arm/kernel/suspend.c +21 -3
@@ -8,10 +8,29 @@static pgd_t *suspend_pgd; -extern int __cpu_suspend (int ,long ,unsigned long ,int (*)(unsigned long )); +extern int __cpu_suspend (unsigned long ,int (*)(unsigned long ));extern void cpu_resume_mmu (void );/* +* This is called by __cpu_suspend() to save the state, and do whatever +* flushing is required to ensure that when the CPU goes to sleep we have +* the necessary data available when the caches are not searched. +*/ +void __cpu_suspend_save (u32 *ptr,u32 ptrsz,u32 sp,u32 *save_ptr) +{ + *save_ptr =virt_to_phys (ptr); + +/* This must correspond to the LDM in cpu_resume() assembly */ + *ptr++ =virt_to_phys (suspend_pgd); + *ptr++ = sp; + *ptr++ =virt_to_phys (cpu_do_resume); + +cpu_do_suspend (ptr); + +flush_cache_all (); +} + +/* * Hide the first two arguments to __cpu_suspend - these are an implementation * detail which platform code shouldn't have to know about. */
@@ -29,8 +48,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))* resume (indicated by a zero return code), we need to switch * back to the correct page tables. */ - ret =__cpu_suspend (virt_to_phys (suspend_pgd), -PHYS_OFFSET -PAGE_OFFSET , arg, fn); + ret =__cpu_suspend (arg, fn);if (ret ==0 )cpu_switch_mm (mm->pgd, mm);
Signature · 1 line
1.7.4.4
PATCH 10/11 ARM: pm: convert some assembly to C
Hi Russell,
Quoted 16 lines · Russell King - ARM Linux
Convert some of the
sleep.Sguts to C code, which makes it easier to use our macros and to add L2 cache handling. We provide a helper function,__cpu_suspend_save(), which deals with saving the common state, setting up for resume, and flushing caches.The remainder left as assembly code is the saving of the CPU general purpose registers, and allocating space on the stack to save the CPU specific registers and resume state.
Signed-off-by Russell King <[email protected]>--- arch/arm/include/asm/proc-fns.h | 8 ++++++ arch/arm/kernel/sleep.S | 53 ++++++++++++-------------------------- arch/arm/kernel/suspend.c | 24 +++++++++++++++-- 3 files changed, 46 insertions(+), 39 deletions(-)
[...]
Quoted 36 lines
arch/arm/kernel/suspend.c +20
-1@@ -8,10 +8,29 @@static pgd_t *suspend_pgd; -extern int __cpu_suspend (int ,long ,unsigned long ,int (*)(unsigned long )); +extern int __cpu_suspend (unsigned long ,int (*)(unsigned long ));extern void cpu_resume_mmu (void );/* +* This is called by __cpu_suspend() to save the state, and do whatever +* flushing is required to ensure that when the CPU goes to sleep we have +* the necessary data available when the caches are not searched. +*/ +void __cpu_suspend_save (u32 *ptr,u32 ptrsz,u32 sp,u32 *save_ptr) +{ + *save_ptr =virt_to_phys (ptr); + +/* This must correspond to the LDM in cpu_resume() assembly */ + *ptr++ =virt_to_phys (suspend_pgd); + *ptr++ = sp; + *ptr++ =virt_to_phys (cpu_do_resume); + +cpu_do_suspend (ptr); + +flush_cache_all (); +} + +/* * Hide the first two arguments to __cpu_suspend - these are an implementation * detail which platform code shouldn't have to know about. */
arch/arm/kernel/suspend.c int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) · line 53
Quoted 8 lines
arch/arm/kernel/suspend.c +1
-2@@ -29,8 +48,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))* resume (indicated by a zero return code), we need to switch * back to the correct page tables. */ - ret =__cpu_suspend (virt_to_phys (suspend_pgd), -PHYS_OFFSET -PAGE_OFFSET , arg, fn); + ret =__cpu_suspend (arg, fn);if (ret ==0 )cpu_switch_mm (mm->pgd, mm);
It is still early testing, but without a local tlb flush here I am getting random segmentation faults in user space.
My fear is that 1:1 global TLB entries cause issues if user space processes happen to map those pages at addresses overlapping 1:1 mapping set-up for resume and we do not flush the TLB.
With the tlb flush the whole patchset works with nary a blemish, from cpuidle.
Still a question mark so please give me the benefit of the doubt.
Many thanks,
Lorenzo
PATCH 10/11 ARM: pm: convert some assembly to C
Quoted 7 lines · Lorenzo Pieralisi
Quoted 7 lines
arch/arm/kernel/suspend.c +1
-2@@ -29,8 +48,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))* resume (indicated by a zero return code), we need to switch * back to the correct page tables. */ - ret =__cpu_suspend (virt_to_phys (suspend_pgd), -PHYS_OFFSET -PAGE_OFFSET , arg, fn); + ret =__cpu_suspend (arg, fn);
Quoted 8 lines
arch/arm/kernel/suspend.c int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) · line 53
Quoted 2 lines
arch/arm/kernel/suspend.c +0
-0if (ret ==0 )cpu_switch_mm (mm->pgd, mm);It is still early testing, but without a local tlb flush here I am getting random segmentation faults in user space.
My fear is that 1:1 global TLB entries cause issues if user space processes happen to map those pages at addresses overlapping 1:1 mapping set-up for resume and we do not flush the TLB.
Yes, having the global TLB entry potentially in userspace is a problem. I don't think we can get around this any other way than by calling local_flush_tlb_all() here. I'll post an updated series shortly.
PATCH 11/11 ARM: pm: add L2 cache cleaning for suspend
In reply to Russell King - ARM LinuxWe need to ensure that state is pushed out from the L2 cache when suspending so that the resume paths can access their data before the MMU and caches have been re-initialized. Add the necessary calls to __cpu_suspend_save().
--- arch/arm/kernel/suspend.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
arch/arm/kernel/suspend.c +3 -0
@@ -28,6 +28,9 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)cpu_do_suspend (ptr);flush_cache_all (); +outer_clean_range (*save_ptr, *save_ptr + ptrsz); +outer_clean_range (virt_to_phys (save_ptr), +virt_to_phys (save_ptr) +sizeof (*save_ptr)); }/*
Signature · 1 line
1.7.4.4
cover Add L2 cache cleaning to generic CPU suspend
In reply to Russell King - ARM LinuxHi Russell,
Quoted 4 lines · Russell King - ARM Linux
Some systems (such as OMAP) preserve the L2 cache across a suspend/ resume cycle. This means they do not perform L2 cache maintanence in their suspend finisher function.
Quoted 8 lines
However, the side effect is that the saved CPU state is not readable by the resume code because it is sitting in the L2 cache.
This patch series adds L2 cache cleaning to the generic CPU suspend/ resume support code, making it possible to use this on systems with L2 cache enabled without having to clean/invalidate the entire L2 cache.
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic cpu_suspend() to clean/invalidate the entire L2 cache.
outer_flush_all(); outer_disable();
But there is a wired thing on using generic cpu_resume(). I have to invalidate L1 before calling into cpu_resume() like below.
ENTRY(imx6q_cpu_resume)
bl v7_invalidate_l1
b cpu_resumeENDPROC(imx6q_cpu_resume)
ENTRY(imx6q_secondary_startup)
bl v7_invalidate_l1
b secondary_startupENDPROC(imx6q_secondary_startup)
The v7_invalidate_l1() is the function copied from mach-tegra/headsmp.S, which has to be called before calling secondary_startup to boot secondary cores (same situation between Tegra and i.MX6Q).
/*
* Tegra specific entry point for secondary CPUs.
* The secondary kernel init calls v7_flush_dcache_all before it enables
* the L1; however, the L1 comes out of reset in an undefined state, so
* the clean + invalidate performed by v7_flush_dcache_all causes a bunch
* of cache lines with uninitialized data and uninitialized tags to get
* written out to memory, which does really unpleasant things to the main
* processor. We fix this by performing an invalidate, rather than a
* clean + invalidate, before jumping into the kernel.
*/
ENTRY(v7_invalidate_l1)
mov r0, #0
mcr p15, 2, r0, c0, c0, 0
mrc p15, 1, r0, c0, c0, 0 ldr r1, =0x7fff
and r2, r1, r0, lsr #13
ldr r1, =0x3ff
and r3, r1, r0, lsr #3 @ NumWays - 1
add r2, r2, #1 @ NumSets
and r0, r0, #0x7
add r0, r0, #4 @ SetShift
clz r1, r3 @ WayShift
add r4, r3, #1 @ NumWays
1: sub r2, r2, #1 @ NumSets--
mov r3, r4 @ Temp = NumWays
2: subs r3, r3, #1 @ Temp--
mov r5, r3, lsl r1
mov r6, r2, lsl r0
orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
mcr p15, 0, r5, c7, c6, 2
bgt 2b
cmp r2, #0
bgt 1b dsb
isb
mov pc, lrENDPROC(v7_invalidate_l1)
Before applying this patch series, I have something like below actually working.
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);
I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes. But unfortunately, I'm running into Oops when resuming back. And I also have Oops with imx_set_cpu_jump(0, cpu_resume) which means skipping the v7_invalidate_l1() and calling generic cpu_resume() only.
I know the key point of the whole thing is that we need to invalidate L1 before either booting secondary cores or resuming the primary core on i.MX6Q. But I really need some help to understand why, and the best solution to that.
Signature · 2 lines
Regards, Shawn
cover Add L2 cache cleaning to generic CPU suspend
Quoted 16 lines · Shawn Guo
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic
cpu_suspend()to clean/invalidate the entire L2 cache.outer_flush_all(); outer_disable();But there is a wired thing on using generic
cpu_resume(). I have to invalidate L1 before calling intocpu_resume()like below.
ENTRY(imx6q_cpu_resume)
blv7_invalidate_l1
bcpu_resumeENDPROC(imx6q_cpu_resume)
Quoted 8 lines
ENTRY(imx6q_secondary_startup)
blv7_invalidate_l1
bsecondary_startupENDPROC(imx6q_secondary_startup)The
v7_invalidate_l1()is the function copied frommach-tegra/headsmp.S, which has to be called before callingsecondary_startupto boot secondary cores (same situation between Tegra and i.MX6Q).
Presumably that's because your L1 cache contains randomized data with random validity (and presumably random dirtyness) at boot time - something which unfortunately the ARM ARM permits. I don't think we can go to the extent of dealing with this in the generic code as it would unnecessarily perturb those implementations which either the boot loader has already sorted out that issue, or which don't have the issue at all.
Quoted 4 lines
Before applying this patch series, I have something like below actually working.
Quoted 8 lines
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes.
That should be the case.
Quoted 4 lines
But unfortunately, I'm
running into Oops when resuming back. And I also have Oops withimx_set_cpu_jump(0, cpu_resume)which means skipping thev7_invalidate_l1()and calling genericcpu_resume()only.
Do you have a copy of the oops?
cover Add L2 cache cleaning to generic CPU suspend
Quoted 26 lines · Russell King - ARM Linux
Quoted 16 lines · Shawn Guo
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic
cpu_suspend()to clean/invalidate the entire L2 cache.outer_flush_all(); outer_disable();But there is a wired thing on using generic
cpu_resume(). I have to invalidate L1 before calling intocpu_resume()like below.
ENTRY(imx6q_cpu_resume)
blv7_invalidate_l1
bcpu_resumeENDPROC(imx6q_cpu_resume)Quoted 8 lines
ENTRY(imx6q_secondary_startup)
blv7_invalidate_l1
bsecondary_startupENDPROC(imx6q_secondary_startup)The
v7_invalidate_l1()is the function copied frommach-tegra/headsmp.S, which has to be called before callingsecondary_startupto boot secondary cores (same situation between Tegra and i.MX6Q).
Quoted 7 lines
Presumably that's because your L1 cache contains randomized data with random validity (and presumably random dirtyness) at boot time - something which unfortunately the ARM ARM permits. I don't think we can go to the extent of dealing with this in the generic code as it would unnecessarily perturb those implementations which either the boot loader has already sorted out that issue, or which don't have the issue at all.
Yes, agreed. It seems that Tegra and i.MX6Q are the only two CA9MP cases here. But is it possible to maintain this v7_invalidate_l1() function in cache-v7.S, so that we do not need to duplicate it in platform codes?
Quoted 13 lines
Quoted 4 lines
Before applying this patch series, I have something like below actually working.
Quoted 8 lines
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes.
Quoted 9 lines
That should be the case.
Quoted 4 lines
But unfortunately, I'm
running into Oops when resuming back. And I also have Oops withimx_set_cpu_jump(0, cpu_resume)which means skipping thev7_invalidate_l1()and calling genericcpu_resume()only.Do you have a copy of the oops?
root@freescale ~$ echo mem > /sys/power/state
PM: Syncing filesystems ... done.
PM: Preparing system for mem sleep
Freezing user space processes ... (elapsed 0.01 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
PM: Entering mem sleep
PM: suspend of devices complete after 0.402 msecs
PM: suspend devices took 0.000 seconds
PM: late suspend of devices complete after 0.276 msecs Disabling non-boot CPUs ...
CPU1: shutdown
CPU2: shutdown
CPU3: shutdown
Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = eb308000 [00000000] *pgd=7b11d831, *pte=00000000, *ppte=00000000 Internal error: Oops: 80000005 [#1] SMP Modules linked in: CPU: 0 Not tainted (3.1.0-rc4+ #319) PC is at 0x0 LR is at cpu_init+0x28/0x74 pc : [<00000000>] lr : [<80010544>] psr: 800001f3
sp : eb3dbe70 ip : eb3dbe4c fp : eb2b2560
r10: 8001d8dc r9 : 8001ef68 r8 : 00000004
r7 : 00000003 r6 : 00000000 r5 : eb0b8b60 r4 : 804865d0 r3 : 80012758 r2 : eb3dbe34 r1 : 7b8f806a r0 : 00000000
Flags: Nzcv IRQs off FIQs off Mode SVC_32 ISA Thumb Segment user
Control: 10c53c7d Table: 7b8f804a DAC: 00000015
Process login (pid: 445, stack limit = 0xeb3da2f0)
Stack: (0xeb3dbe70 to 0xeb3dc000)
be60: ffffffff 00000000 eb3dbeac eb3dbe88
be80: 8008adc8 8008a5f8 eb3dbeb4 eb3dbe98 801dbec0 eb0a01e0 eb406600 00000000
bea0: 00000000 00000003 eb3dbed4 eb3dbeb8 80063ffc 80063c78 0000006d eb321000
bec0: 8000e34c 8004d730 eb3dbee4 00000b04 800bc9e4 eb868140 ffffffff 00000000
bee0: eb3dbf70 eb8286c0 00000004 eb806bc0 eb3dbf0c eb3dbf00 801d7344 800633a8
bf00: eb3dbf2c 00000003 2aad7000 00000000 eb3da000 eb0b91e0 00000007 00001000
bf20: eb3dbf64 eb3dbf30 801dbff4 80311644 80000013 eb0b8b9c eb3da000 2aaeb000
bf40: 800a71ec 80025538 800aae40 eb181000 eb3dbfb0 00000000 eb3dbfb0 eb0df000
bf60: 00020000 00000000 00000024 00000100 02012080 00000008 02012080 00000005
bf80: 8000e504 00000000 eb3dbfa4 eb3dbf98 8009fb74 8009f9d8 00000000 eb3dbfa8
bfa0: 8000e380 8002f8a8 7e837d90 00000000 00000000 00000000 00a69008 00000000
bfc0: 00000004 2ab06000 2acb95f8 00000004 00000004 0201029c 00000001 00000000
bfe0: 00000004 7ebc0478 2ac0798c 2ac53e6c 60000010 00000001 00000000 00000000
Backtrace: frame pointer underflow [<eb2b02d4>] (0xeb2b02d4) from [<2571140e>] (0x2571140e) Backtrace aborted due to bad frame pointer <2551140e> Code: bad PC value ---[ end trace b4510fc09c2ffbd1 ]--- Fixing recursive fault but reboot is needed! Unable to handle kernel NULL pointer dereference at virtual address 00000010 pgd = eb308000 [00000010] *pgd=7b11d831, *pte=00000000, *ppte=00000000 Internal error: Oops: 5 [#2] SMP Modules linked in: CPU: 0 Tainted: G D (3.1.0-rc4+ #319) PC is at find_busiest_group+0xd0/0xa4c LR is at 0x0 pc : [<80023810>] lr : [<00000000>] psr: 600001d3
sp : eb3dba58 ip : 00000000 fp : eb3dbb44
r10: 80415ba0 r9 : eb346000 r8 : 80427b3c
r7 : 80427d10 r6 : 00000010 r5 : 80415ba0 r4 : 00000000 r3 : 00000000 r2 : 00000000 r1 : 00000024 r0 : eb3dbaf4
Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment user
Control: 10c53c7d Table: 7b8f804a DAC: 00000015 Process login (pid: 445, stack limit = 0xeb3da2f0)
Stack: (0xeb3dba58 to 0xeb3dc000)
ba40: eb926500 0000000a
ba60: eb3dba84 eb3dba70 eb3dbb90 00000002 00000000 00000000 00000000 00000000
ba80: 00000000 8020475c eb346000 eb3dba98 80017d90 00000000 80415ba0 80427ab0
baa0: 80415ba0 eb3dbab0 802048a4 00000000 00000000 00000000 00000000 00000000
bac0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
bae0: 00000000 00000000 00000000 00000000 00000000 00001f61 8042d8b4 8042d8b4
bb00: 00001f61 80443ae0 eb3dbb34 eb3dbb18 8004d4b0 80311644 8002b684 8166e0e4
bb20: eb2b2560 eb3da000 80427d10 eb2b26dc eb346000 00000000 eb3dbbc4 eb3dbb48
bb40: 80024240 8002374c 8166e0e4 eb3dbc0c eb3da000 00000002 eb3dbb8c 8166eba0
bb60: eb346000 80415ba0 8166e0e4 80427b3c 80427d10 80427d10 80415ba0 00000020
bb80: eb3dbbac 00000000 8001e5f0 8001ef20 ffffffb5 00000000 eb2b2560 8166eba0
bba0: eb2b2560 eb3da000 80427d10 eb2b26dc eb346000 00000000 eb3dbc3c eb3dbbc8
bbc0: 8030f5ac 80024198 eb3dbc0c 8042d8b4 eb2b2560 eb2b02d8 000bc20f 00000000
bbe0: 00000001 8041a080 80415ba0 80415ba0 ffff9442 00000006 fffffffc 80415ba0
bc00: 80415ba0 804150c0 eb3dbc2c 00000001 8030ed50 eb2b2560 0000000b 00000000
bc20: fffffffc eb3dbc9b 00000020 eb3da000 eb3dbc74 eb3dbc40 8002f534 8030ef88
bc40: eb3da000 00000000 fffffffc eb3dbc9b 00000020 fffffff8 eb3dbc74 eb3dbc68
bc60: 8002b50c fffffffc eb3dbcfc eb3dbc78 80011c88 8002ee9c eb3da2f0 0000000b
bc80: 00000004 7f000000 00000000 00000004 8039a080 8039a088 62000005 50206461
bca0: 61762043 0065756c eb3dbccc eb3dbcb8 8030ed50 8002bdd0 80000005 eb3dbcd4
bcc0: eb3dbcfc eb3dbce0 800147cc 8030ed38 803ad880 eb3dbe28 00000000 00000000
bce0: 80000005 eb0b8b60 eb0b8b98 eb2b2560 eb3dbd24 eb3dbd00 8001485c 800119fc
bd00: eb3dbe28 eb0b8b60 eb3dbe28 00000000 00010000 80000005 eb3dbd5c eb3dbd28
bd20: 800149c0 800147ec eb922d80 eb44fd30 00000000 80000005 8042af98 00000000
bd40: eb3dbe28 00000004 8001ef68 8001d8dc eb3dbd7c eb3dbd60 80014b74 80014878
bd60: 00000005 8042af98 00000000 eb3dbe28 eb3dbe24 eb3dbd80 800085c4 80014adc
bd80: 8032433c 00000000 eb3dbdac eb3dbd98 80074b6c 80074ad8 80074b48 fffffffa
bda0: eb90d9e0 00000000 eb3dbdec eb3dbdb8 80027170 80311644 00000001 40000093
bdc0: 800401b4 80027408 eb3dbdec eb3dbdd8 80040248 80040198 80415ba0 80415ba0
bde0: 8020add0 8020ad10 00000000 8048d5c0 0000003f 0000003e eb93a000 8048dee4
be00: eb8295a0 eb3da000 00000000 800001f3 ffffffff eb3dbe5c eb2b2560 eb3dbe28
be20: 8000e018 80008590 00000000 7b8f806a eb3dbe34 80012758 804865d0 eb0b8b60
be40: 00000000 00000003 00000004 8001ef68 8001d8dc eb2b2560 eb3dbe4c eb3dbe70
be60: 80010544 00000000 800001f3 ffffffff ffffffff 00000000 eb3dbeac eb3dbe88
be80: 8008adc8 8008a5f8 eb3dbeb4 eb3dbe98 801dbec0 eb0a01e0 eb406600 00000000
bea0: 00000000 00000003 eb3dbed4 eb3dbeb8 80063ffc 80063c78 0000006d eb321000
bec0: 8000e34c 8004d730 eb3dbee4 00000b04 800bc9e4 eb868140 ffffffff 00000000
bee0: eb3dbf70 eb8286c0 00000004 eb806bc0 eb3dbf0c eb3dbf00 801d7344 800633a8
bf00: eb3dbf2c 00000003 2aad7000 00000000 eb3da000 eb0b91e0 00000007 00001000
bf20: eb3dbf64 eb3dbf30 801dbff4 80311644 80000013 eb0b8b9c eb3da000 2aaeb000
bf40: 800a71ec 80025538 800aae40 eb181000 eb3dbfb0 00000000 eb3dbfb0 eb0df000
bf60: 00020000 00000000 00000024 00000100 02012080 00000008 02012080 00000005
bf80: 8000e504 00000000 eb3dbfa4 eb3dbf98 8009fb74 8009f9d8 00000000 eb3dbfa8
bfa0: 8000e380 8002f8a8 7e837d90 00000000 00000000 00000000 00a69008 00000000
bfc0: 00000004 2ab06000 2acb95f8 00000004 00000004 0201029c 00000001 00000000
bfe0: 00000004 7ebc0478 2ac0798c 2ac53e6c 60000010 00000001 00000000 00000000
Backtrace: [<80023740>] (find_busiest_group+0x0/0xa4c) from [<80024240>] (load_balance+0xb4
/0x5ac)
[<8002418c>] (load_balance+0x0/0x5ac) from [<8030f5ac>] (schedule+0x630/0x6a8) [<8030ef7c>] (schedule+0x0/0x6a8) from [<8002f534>] (do_exit+0x6a4/0x6f0) [<8002ee90>] (do_exit+0x0/0x6f0) from [<80011c88>] (die+0x298/0x2ec)
r7:fffffffc
[<800119f0>] (die+0x0/0x2ec) from [<8001485c>] (__do_kernel_fault+0x7c/0x8c) [<800147e0>] (__do_kernel_fault+0x0/0x8c) from [<800149c0>] (do_page_fault+0x154 /0x1f8)
r8:80000005 r7:00010000 r6:00000000 r5:eb3dbe28 r4:eb0b8b60
r3:eb3dbe28
[<8001486c>] (do_page_fault+0x0/0x1f8) from [<80014b74>] (do_translation_fault+0 xa4/0xa8)
[<80014ad0>] (do_translation_fault+0x0/0xa8) from [<800085c4>] (do_PrefetchAbort +0x40/0xa4)
r7:eb3dbe28 r6:00000000 r5:8042af98 r4:00000005
[<80008584>] (do_PrefetchAbort+0x0/0xa4) from [<8000e018>] (__pabt_svc+0x38/0x80 )
Exception stack(0xeb3dbe28 to 0xeb3dbe70)
be20: 00000000 7b8f806a eb3dbe34 80012758 804865d0 eb0b8b60
be40: 00000000 00000003 00000004 8001ef68 8001d8dc eb2b2560 eb3dbe4c eb3dbe70
be60: 80010544 00000000 800001f3 ffffffff
r7:eb3dbe5c r6:ffffffff r5:800001f3 r4:00000000
Backtrace aborted due to bad frame pointer <eb2b2560>
Code: e51b20c8 e3a01024 e28e6010 e51b30cc (e7965002) ---[ end trace b4510fc09c2ffbd2 ]--- Fixing recursive fault but reboot is needed! Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = eb308000 [00000008] *pgd=7b11d831, *pte=00000000, *ppte=00000000 Internal error: Oops: 5 [#3] SMP Modules linked in: CPU: 0 Tainted: G D (3.1.0-rc4+ #319) PC is at rb_next+0xc/0x74 LR is at pick_next_task_fair+0xd8/0x114 pc : [<801dbb18>] lr : [<80022230>] psr: 600001d3
sp : eb3db778 ip : eb3db788 fp : eb3db784
r10: 00000000 r9 : 80313ac0 r8 : eb2b26dc
r7 : 80427d10 r6 : 00000000 r5 : 8166eba0 r4 : 00000000 r3 : 80022158 r2 : ffffffff r1 : 00000000 r0 : 00000008
Flags: nZCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment user
Control: 10c53c7d Table: 7b8f804a DAC: 00000015 Process login (pid: 445, stack limit = 0xeb3da2f0)
Stack: (0xeb3db778 to 0xeb3dc000)
b760: eb3db7a4 eb3db788
b780: 80022230 801dbb18 8166eba0 eb2b2560 eb3da000 80427d10 eb3db81c eb3db7a8
b7a0: 8030f450 80022164 00000000 8042d8b4 8039a085 ffffffff ffffffff 8039a087
b7c0: 00000001 0039a085 80415ba0 80415ba0 0000000b 00000000 00000001 80415ba0
b7e0: 80415ba0 804150c0 eb3db80c eb3db7f8 8030ed50 eb2b2560 0000000b 00000000
b800: 00000001 eb3db8aa 00000000 eb3da000 eb3db854 eb3db820 8002f534 8030ef88
b820: eb3da000 00000000 00000001 eb3db8aa 00000000 80023812 eb3db854 eb3db848
b840: 8002b50c 00000001 eb3db8dc eb3db858 80011c88 8002ee9c eb3da2f0 0000000b
b860: 00000004 7f000000 00000000 00000008 8039a080 8039a088 65000005 32623135
b880: 20386330 30613365 34323031 38326520 31303665 35652030 30336231 28206363
b8a0: 36393765 32303035 80002029 8030ed38 803ad880 eb3dba10 00000010 00000000
b8c0: 00000005 eb0b8b60 eb0b8b98 eb2b2560 eb3db904 eb3db8e0 8001485c 800119fc
b8e0: eb3dba10 eb0b8b60 eb3dba10 00000010 00010000 00000005 eb3db93c eb3db908
b900: 800149c0 800147ec eb3db930 eb3db918 801df694 00000005 00000010 8042af48
b920: 00000005 eb3dba10 eb346000 80415ba0 eb3db95c eb3db940 80014b74 80014878
b940: 00000005 00000010 8042af48 00000005 eb3dba0c eb3db960 80008520 80014adc
b960: 00000000 eb3db991 80443f0c 80443b39 00000000 ffffffff eb3dba94 eb3db988
b980: 801de75c 801de3d0 ffffffff ffffffff 327830f8 31313735 00653034 00001831
b9a0: 0000001c 80427afc eb3dba0c 0000184d 8042d8b4 8042d8b4 0000184d 80443ae0
b9c0: eb3db9ec eb3db9d0 8004d4b0 80311644 8002b684 8002b51c 0000184d 0000184d
b9e0: eb3dba24 eb3db9f0 eb3dba0c 80023810 600001d3 ffffffff eb3dba44 80427b3c
ba00: eb3dbb44 eb3dba10 8000de98 800084f0 eb3dbaf4 00000024 00000000 00000000
ba20: 00000000 80415ba0 00000010 80427d10 80427b3c eb346000 80415ba0 eb3dbb44
ba40: 00000000 eb3dba58 00000000 80023810 600001d3 ffffffff eb926500 0000000a
ba60: eb3dba84 eb3dba70 eb3dbb90 00000002 00000000 00000000 00000000 00000000
ba80: 00000000 8020475c eb346000 eb3dba98 80017d90 00000000 80415ba0 80427ab0
baa0: 80415ba0 eb3dbab0 802048a4 00000000 00000000 00000000 00000000 00000000
bac0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
bae0: 00000000 00000000 00000000 00000000 00000000 00001f61 8042d8b4 8042d8b4
bb00: 00001f61 80443ae0 eb3dbb34 eb3dbb18 8004d4b0 80311644 8002b684 8166e0e4
bb20: eb2b2560 eb3da000 80427d10 eb2b26dc eb346000 00000000 eb3dbbc4 eb3dbb48
bb40: 80024240 8002374c 8166e0e4 eb3dbc0c eb3da000 00000002 eb3dbb8c 8166eba0
bb60: eb346000 80415ba0 8166e0e4 80427b3c 80427d10 80427d10 80415ba0 00000020
bb80: eb3dbbac 00000000 8001e5f0 8001ef20 ffffffb5 00000000 eb2b2560 8166eba0
bba0: eb2b2560 eb3da000 80427d10 eb2b26dc eb346000 00000000 eb3dbc3c eb3dbbc8
bbc0: 8030f5ac 80024198 eb3dbc0c 8042d8b4 eb2b2560 eb2b02d8 000bc20f 00000000
bbe0: 00000001 8041a080 80415ba0 80415ba0 ffff9442 00000006 fffffffc 80415ba0
bc00: 80415ba0 804150c0 eb3dbc2c 00000001 8030ed50 eb2b2560 0000000b 00000000
bc20: fffffffc eb3dbc9b 00000020 eb3da000 eb3dbc74 eb3dbc40 8002f534 8030ef88
bc40: eb3da000 00000000 fffffffc eb3dbc9b 00000020 fffffff8 eb3dbc74 eb3dbc68
bc60: 8002b50c fffffffc eb3dbcfc eb3dbc78 80011c88 8002ee9c eb3da2f0 0000000b
bc80: 00000004 7f000000 00000000 00000004 8039a080 8039a088 62000005 50206461
bca0: 61762043 0065756c eb3dbccc eb3dbcb8 8030ed50 8002bdd0 80000005 eb3dbcd4
bcc0: eb3dbcfc eb3dbce0 800147cc 8030ed38 803ad880 eb3dbe28 00000000 00000000
bce0: 80000005 eb0b8b60 eb0b8b98 eb2b2560 eb3dbd24 eb3dbd00 8001485c 800119fc
bd00: eb3dbe28 eb0b8b60 eb3dbe28 00000000 00010000 80000005 eb3dbd5c eb3dbd28
bd20: 800149c0 800147ec eb922d80 eb44fd30 00000000 80000005 8042af98 00000000
bd40: eb3dbe28 00000004 8001ef68 8001d8dc eb3dbd7c eb3dbd60 80014b74 80014878
bd60: 00000005 8042af98 00000000 eb3dbe28 eb3dbe24 eb3dbd80 800085c4 80014adc
bd80: 8032433c 00000000 eb3dbdac eb3dbd98 80074b6c 80074ad8 80074b48 fffffffa
bda0: eb90d9e0 00000000 eb3dbdec eb3dbdb8 80027170 80311644 00000001 40000093
bdc0: 800401b4 80027408 eb3dbdec eb3dbdd8 80040248 80040198 80415ba0 80415ba0
bde0: 8020add0 8020ad10 00000000 8048d5c0 0000003f 0000003e eb93a000 8048dee4
be00: eb8295a0 eb3da000 00000000 800001f3 ffffffff eb3dbe5c eb2b2560 eb3dbe28
be20: 8000e018 80008590 00000000 7b8f806a eb3dbe34 80012758 804865d0 eb0b8b60
be40: 00000000 00000003 00000004 8001ef68 8001d8dc eb2b2560 eb3dbe4c eb3dbe70
be60: 80010544 00000000 800001f3 ffffffff ffffffff 00000000 eb3dbeac eb3dbe88
be80: 8008adc8 8008a5f8 eb3dbeb4 eb3dbe98 801dbec0 eb0a01e0 eb406600 00000000
bea0: 00000000 00000003 eb3dbed4 eb3dbeb8 80063ffc 80063c78 0000006d eb321000
bec0: 8000e34c 8004d730 eb3dbee4 00000b04 800bc9e4 eb868140 ffffffff 00000000
bee0: eb3dbf70 eb8286c0 00000004 eb806bc0 eb3dbf0c eb3dbf00 801d7344 800633a8
bf00: eb3dbf2c 00000003 2aad7000 00000000 eb3da000 eb0b91e0 00000007 00001000
bf20: eb3dbf64 eb3dbf30 801dbff4 80311644 80000013 eb0b8b9c eb3da000 2aaeb000
bf40: 800a71ec 80025538 800aae40 eb181000 eb3dbfb0 00000000 eb3dbfb0 eb0df000
bf60: 00020000 00000000 00000024 00000100 02012080 00000008 02012080 00000005
bf80: 8000e504 00000000 eb3dbfa4 eb3dbf98 8009fb74 8009f9d8 00000000 eb3dbfa8
bfa0: 8000e380 8002f8a8 7e837d90 00000000 00000000 00000000 00a69008 00000000
bfc0: 00000004 2ab06000 2acb95f8 00000004 00000004 0201029c 00000001 00000000
bfe0: 00000004 7ebc0478 2ac0798c 2ac53e6c 60000010 00000001 00000000 00000000
Backtrace: [<801dbb0c>] (rb_next+0x0/0x74) from [<80022230>] (pick_next_task_fair+0xd8/0x11
4)
[<80022158>] (pick_next_task_fair+0x0/0x114) from [<8030f450>] (schedule+0x4d4/0 x6a8)
r7:80427d10 r6:eb3da000 r5:eb2b2560 r4:8166eba0
[<8030ef7c>] (schedule+0x0/0x6a8) from [<8002f534>] (do_exit+0x6a4/0x6f0) [<8002ee90>] (do_exit+0x0/0x6f0) from [<80011c88>] (die+0x298/0x2ec)
r7:00000001
[<800119f0>] (die+0x0/0x2ec) from [<8001485c>] (__do_kernel_fault+0x7c/0x8c) [<800147e0>] (__do_kernel_fault+0x0/0x8c) from [<800149c0>] (do_page_fault+0x154 /0x1f8)
r8:00000005 r7:00010000 r6:00000010 r5:eb3dba10 r4:eb0b8b60
r3:eb3dba10
[<8001486c>] (do_page_fault+0x0/0x1f8) from [<80014b74>] (do_translation_fault+0 xa4/0xa8)
[<80014ad0>] (do_translation_fault+0x0/0xa8) from [<80008520>] (do_DataAbort+0x3 c/0xa0)
r7:00000005 r6:8042af48 r5:00000010 r4:00000005
[<800084e4>] (do_DataAbort+0x0/0xa0) from [<8000de98>] (__dabt_svc+0x38/0x60)
Exception stack(0xeb3dba10 to 0xeb3dba58)
ba00: eb3dbaf4 00000024 00000000 00000000
ba20: 00000000 80415ba0 00000010 80427d10 80427b3c eb346000 80415ba0 eb3dbb44
ba40: 00000000 eb3dba58 00000000 80023810 600001d3 ffffffff
r8:80427b3c r7:eb3dba44 r6:ffffffff r5:600001d3 r4:80023810
[<80023740>] (find_busiest_group+0x0/0xa4c) from [<80024240>] (load_balance+0xb4 /0x5ac)
[<8002418c>] (load_balance+0x0/0x5ac) from [<8030f5ac>] (schedule+0x630/0x6a8) [<8030ef7c>] (schedule+0x0/0x6a8) from [<8002f534>] (do_exit+0x6a4/0x6f0) [<8002ee90>] (do_exit+0x0/0x6f0) from [<80011c88>] (die+0x298/0x2ec)
r7:fffffffc
[<800119f0>] (die+0x0/0x2ec) from [<8001485c>] (__do_kernel_fault+0x7c/0x8c) [<800147e0>] (__do_kernel_fault+0x0/0x8c) from [<800149c0>] (do_page_fault+0x154 /0x1f8)
r8:80000005 r7:00010000 r6:00000000 r5:eb3dbe28 r4:eb0b8b60
r3:eb3dbe28
[<8001486c>] (do_page_fault+0x0/0x1f8) from [<80014b74>] (do_translation_fault+0 xa4/0xa8)
[<80014ad0>] (do_translation_fault+0x0/0xa8) from [<800085c4>] (do_PrefetchAbort +0x40/0xa4)
r7:eb3dbe28 r6:00000000 r5:8042af98 r4:00000005
[<80008584>] (do_PrefetchAbort+0x0/0xa4) from [<8000e018>] (__pabt_svc+0x38/0x80 )
Exception stack(0xeb3dbe28 to 0xeb3dbe70)
be20: 00000000 7b8f806a eb3dbe34 80012758 804865d0 eb0b8b60
be40: 00000000 00000003 00000004 8001ef68 8001d8dc eb2b2560 eb3dbe4c eb3dbe70
be60: 80010544 00000000 800001f3 ffffffff
r7:eb3dbe5c r6:ffffffff r5:800001f3 r4:00000000
Backtrace aborted due to bad frame pointer <eb2b2560>
Code: e89da800 e1a0c00d e92dd800 e24cb004 (e5903000) ---[ end trace b4510fc09c2ffbd3 ]---
Fixing recursive fault but reboot is needed!
Signature · 2 lines
Regards, Shawn
cover Add L2 cache cleaning to generic CPU suspend
Quoted 34 lines · Shawn Guo
Quoted 26 lines · Russell King - ARM Linux
Quoted 16 lines · Shawn Guo
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic
cpu_suspend()to clean/invalidate the entire L2 cache.outer_flush_all(); outer_disable();But there is a wired thing on using generic
cpu_resume(). I have to invalidate L1 before calling intocpu_resume()like below.
ENTRY(imx6q_cpu_resume)
blv7_invalidate_l1
bcpu_resumeENDPROC(imx6q_cpu_resume)Quoted 8 lines
ENTRY(imx6q_secondary_startup)
blv7_invalidate_l1
bsecondary_startupENDPROC(imx6q_secondary_startup)The
v7_invalidate_l1()is the function copied frommach-tegra/headsmp.S, which has to be called before callingsecondary_startupto boot secondary cores (same situation between Tegra and i.MX6Q).Quoted 7 lines
Presumably that's because your L1 cache contains randomized data with random validity (and presumably random dirtyness) at boot time - something which unfortunately the ARM ARM permits. I don't think we can go to the extent of dealing with this in the generic code as it would unnecessarily perturb those implementations which either the boot loader has already sorted out that issue, or which don't have the issue at all.
Quoted 28 lines
Yes, agreed. It seems that Tegra and i.MX6Q are the only two CA9MP cases here. But is it possible to maintain this
v7_invalidate_l1()function incache-v7.S, so that we do not need to duplicate it in platform codes?Quoted 22 lines
Quoted 4 lines
Before applying this patch series, I have something like below actually working.
Quoted 8 lines
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes.
That should be the case.
Quoted 4 lines
But unfortunately, I'm
running into Oops when resuming back. And I also have Oops withimx_set_cpu_jump(0, cpu_resume)which means skipping thev7_invalidate_l1()and calling genericcpu_resume()only.Do you have a copy of the oops?
Hi Russell,
After following your great debugging clue that we need to enable L2 before calling into generic cpu_resume(), now this patch series works great for imx6q. Thanks a lot, and here is my tag.
Signature · 2 lines
Regards, Shawn
cover Add L2 cache cleaning to generic CPU suspend
Quoted 63 lines · Shawn Guo
Quoted 34 lines · Shawn Guo
Quoted 26 lines · Russell King - ARM Linux
Quoted 16 lines · Shawn Guo
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic
cpu_suspend()to clean/invalidate the entire L2 cache.outer_flush_all(); outer_disable();But there is a wired thing on using generic
cpu_resume(). I have to invalidate L1 before calling intocpu_resume()like below.
ENTRY(imx6q_cpu_resume)
blv7_invalidate_l1
bcpu_resumeENDPROC(imx6q_cpu_resume)Quoted 8 lines
ENTRY(imx6q_secondary_startup)
blv7_invalidate_l1
bsecondary_startupENDPROC(imx6q_secondary_startup)The
v7_invalidate_l1()is the function copied frommach-tegra/headsmp.S, which has to be called before callingsecondary_startupto boot secondary cores (same situation between Tegra and i.MX6Q).Quoted 7 lines
Presumably that's because your L1 cache contains randomized data with random validity (and presumably random dirtyness) at boot time - something which unfortunately the ARM ARM permits. I don't think we can go to the extent of dealing with this in the generic code as it would unnecessarily perturb those implementations which either the boot loader has already sorted out that issue, or which don't have the issue at all.
Quoted 28 lines
Yes, agreed. It seems that Tegra and i.MX6Q are the only two CA9MP cases here. But is it possible to maintain this
v7_invalidate_l1()function incache-v7.S, so that we do not need to duplicate it in platform codes?Quoted 22 lines
Quoted 4 lines
Before applying this patch series, I have something like below actually working.
Quoted 8 lines
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes.
That should be the case.
Quoted 4 lines
But unfortunately, I'm
running into Oops when resuming back. And I also have Oops withimx_set_cpu_jump(0, cpu_resume)which means skipping thev7_invalidate_l1()and calling genericcpu_resume()only.Do you have a copy of the oops?
Quoted 7 lines
Hi Russell,
After following your great debugging clue that we need to enable L2 before calling into generic
cpu_resume(), now this patch series works great for imx6q. Thanks a lot, and here is my tag.Tested-by Shawn Guo <[email protected]>
Is that for all these patches?
cover Add L2 cache cleaning to generic CPU suspend
Quoted 66 lines · Russell King - ARM Linux
Quoted 65 lines · Shawn Guo
Quoted 34 lines · Shawn Guo
Quoted 26 lines · Russell King - ARM Linux
Quoted 16 lines · Shawn Guo
This is also the case on i.MX6Q, which L2 cache is retained during a suspend/resume cycle. Currently, I have to call into the following before calling generic
cpu_suspend()to clean/invalidate the entire L2 cache.outer_flush_all(); outer_disable();But there is a wired thing on using generic
cpu_resume(). I have to invalidate L1 before calling intocpu_resume()like below.
ENTRY(imx6q_cpu_resume)
blv7_invalidate_l1
bcpu_resumeENDPROC(imx6q_cpu_resume)Quoted 8 lines
ENTRY(imx6q_secondary_startup)
blv7_invalidate_l1
bsecondary_startupENDPROC(imx6q_secondary_startup)The
v7_invalidate_l1()is the function copied frommach-tegra/headsmp.S, which has to be called before callingsecondary_startupto boot secondary cores (same situation between Tegra and i.MX6Q).Quoted 7 lines
Presumably that's because your L1 cache contains randomized data with random validity (and presumably random dirtyness) at boot time - something which unfortunately the ARM ARM permits. I don't think we can go to the extent of dealing with this in the generic code as it would unnecessarily perturb those implementations which either the boot loader has already sorted out that issue, or which don't have the issue at all.
Quoted 28 lines
Yes, agreed. It seems that Tegra and i.MX6Q are the only two CA9MP cases here. But is it possible to maintain this
v7_invalidate_l1()function incache-v7.S, so that we do not need to duplicate it in platform codes?Quoted 22 lines
Quoted 4 lines
Before applying this patch series, I have something like below actually working.
Quoted 8 lines
outer_flush_all(); outer_disable(); imx_set_cpu_jump(0, imx6q_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish);I expect with you patches applied, I can still have it work with simply removing those two lines outer cache codes.
That should be the case.
Quoted 4 lines
But unfortunately, I'm
running into Oops when resuming back. And I also have Oops withimx_set_cpu_jump(0, cpu_resume)which means skipping thev7_invalidate_l1()and calling genericcpu_resume()only.Do you have a copy of the oops?
Hi Russell,
Quoted 8 lines
Quoted 5 lines
After following your great debugging clue that we need to enable L2 before calling into generic
cpu_resume(), now this patch series works great for imx6q. Thanks a lot, and here is my tag.Tested-by Shawn Guo <[email protected]>Is that for all these patches?
Yes, it is.
Signature · 2 lines
Regards, Shawn
cover Add L2 cache cleaning to generic CPU suspend
In reply to Russell King - ARM LinuxQuoted 19 lines · Russell King - ARM Linux
Some systems (such as OMAP) preserve the L2 cache across a suspend/ resume cycle. This means they do not perform L2 cache maintanence in their suspend finisher function.
However, the side effect is that the saved CPU state is not readable by the resume code because it is sitting in the L2 cache.
This patch series adds L2 cache cleaning to the generic CPU suspend/ resume support code, making it possible to use this on systems with L2 cache enabled without having to clean/invalidate the entire L2 cache.
We also add a separate page table, allocated at boot time, for the resume process to use so we don't have to fiddle about with tweaking entries in the current processes page table. Moreover, the current processes page table may be in use by another CPU in the system if these paths are used from cpuidle or hotplug, so changing the page table is technically unsound.
Quoted 8 lines
Overall, this makes it possible for OMAP4 systems to use this code.
The first four patches in this set are already merged into Linus' tree as bug fixes, and are included here for completeness given that the kernel.org infrastructure is currently offline.
This has (so far) only been tested on OMAP4. Further testing on OMAP3 and Assabet will follow.
Thanks a lot Russell for this series. I have tested the entire series with OMAP4 S2R and CPUIDLE and it works great.
Regards
Santosh
cover Add L2 cache cleaning to generic CPU suspend
Quoted 4 lines · Santosh
Thanks a lot Russell for this series. I have tested the entire series with OMAP4 S2R and CPUIDLE and it works great.
Tested-by Santosh Shilimkar <[email protected]>
Thanks. I've merged added that to the non-fixes stuff (which Linus hasn't pulled) and the series into the for-next branch.