From f5fa68d9674156ddaafa12a058ccc93c8866d5f9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 27 Aug 2011 11:17:36 +0100 Subject: ARM: pm: force non-zero return value from __cpu_suspend when aborting Ensure that the return value from __cpu_suspend is non-zero when aborting. Zero indicates a successful suspend occurred. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index dc902f2..46a9f46 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -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) -- cgit v0.10.2 From e8ce0eb5e2254b85415e4b58e73f24a5d13846a1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 26 Aug 2011 20:28:52 +0100 Subject: ARM: pm: preallocate a page table for suspend/resume Preallocate 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. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index b0e4e1a..1c0a551 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -1,22 +1,7 @@ #ifndef __ASM_ARM_SUSPEND_H #define __ASM_ARM_SUSPEND_H -#include -#include - 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 diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index f7887dc..787b888 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -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 diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 46a9f46..8cf13de 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -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: diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c new file mode 100644 index 0000000..0a33f10 --- /dev/null +++ b/arch/arm/kernel/suspend.c @@ -0,0 +1,48 @@ +#include + +#include +#include +#include +#include +#include + +static pgd_t *suspend_pgd; + +extern int __cpu_suspend(int, long, unsigned long, int (*)(unsigned long)); +extern void cpu_resume_turn_mmu_on(void); + +/* + * Hide the first two arguments to __cpu_suspend - these are an implementation + * detail which platform code shouldn't have to know about. + */ +int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) +{ + struct mm_struct *mm = current->active_mm; + int ret; + + if (!suspend_pgd) + return -EINVAL; + + /* + * Temporarily switch the page tables to our suspend page + * tables, which contain the temporary identity mapping + * required for resuming. + */ + cpu_switch_mm(suspend_pgd, mm); + ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn); + cpu_switch_mm(mm->pgd, mm); + local_flush_tlb_all(); + + return ret; +} + +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); + identity_mapping_add(suspend_pgd, addr, addr + SECTION_SIZE); + } + return suspend_pgd ? 0 : -ENOMEM; +} +core_initcall(cpu_suspend_init); diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 2e6849b..035d57b 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -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 diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index cd8f79c..48add84 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -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 diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 69e7f2e..52f73fb 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -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 diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index a923aa0..414e369 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -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" diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 9049c07..21d6910 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -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 diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 755e1bf..efd4949 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -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 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index fbc06e5..37dbada 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -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 -- cgit v0.10.2 From de8e71ca4f2e17329f6718ae88d5c8336cb249ee Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 27 Aug 2011 22:39:09 +0100 Subject: ARM: pm: only use preallocated page table during resume Only 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. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 8cf13de..25d42df 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -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: diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 0a33f10..2beda56 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -24,14 +24,17 @@ 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); - local_flush_tlb_all(); + ret = __cpu_suspend(virt_to_phys(suspend_pgd), + PHYS_OFFSET - PAGE_OFFSET, arg, fn); + if (ret == 0) { + cpu_switch_mm(mm->pgd, mm); + local_flush_tlb_all(); + } return ret; } diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 035d57b..88fb3d9 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -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 diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index 48add84..9f8fd91 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -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 diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 52f73fb..7d91545 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -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 diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 414e369..2e27b46 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -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 diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 21d6910..b56004f 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -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 diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index efd4949..abf0507 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -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 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 37dbada..3277904 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -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 -- cgit v0.10.2 From 1aede681ac159884c77817d33230eed9185b6f6c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 28 Aug 2011 10:30:34 +0100 Subject: ARM: pm: no need to save/restore context ID register 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. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 2e27b46..d061d2f 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -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, c0, 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 diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index b56004f..6af366c 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -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) -- cgit v0.10.2 From 62b2d07c0ea9db40a1787d2d0ab49f03c3e0613c Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Aug 2011 23:26:18 +0100 Subject: ARM: pm: get rid of cpu_resume_turn_mmu_on We 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. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 25d42df..c9a43ca 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -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 diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 2beda56..ed4160b 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -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 @@ -43,7 +43,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; -- cgit v0.10.2 From abda1bd5f4e04054ce083c298fcd68a743e9df03 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 1 Sep 2011 11:52:33 +0100 Subject: ARM: pm: convert some assembly to C Convert 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. Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 633d1cb..9e92cb2 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -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); diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index c9a43ca..020e99c 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -8,54 +8,35 @@ .text /* - * Save CPU state for a suspend - * r0 = phys addr of temporary page tables - * r1 = v:p offset - * r2 = suspend function arg0 - * r3 = suspend function + * Save CPU state for a suspend. This saves the CPU general purpose + * registers, and allocates space on the kernel stack to save the CPU + * specific registers and some other data for resume. + * r0 = suspend function arg0 + * r1 = 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 - ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function + ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state #else - ldr r5, =cpu_suspend_size - ldr ip, =cpu_do_resume + ldr r4, =cpu_suspend_size #endif - mov r6, sp @ current virtual SP - 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!, {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 + mov r5, sp @ current virtual SP + add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn + sub sp, sp, r4 @ allocate CPU state on stack + stmfd sp!, {r0, r1} @ save suspend func arg and pointer + add r0, sp, #8 @ save pointer to save block + mov r1, r4 @ size of save block + mov r2, r5 @ virtual SP + ldr r3, =sleep_save_sp #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - str r6, [r5, lr, lsl #2] @ save phys SP -#else - str r6, [r5] @ save phys SP -#endif -#ifdef MULTI_CPU - mov lr, pc - ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state -#else - bl cpu_do_suspend -#endif - - @ flush data cache -#ifdef MULTI_CACHE - ldr r10, =cpu_cache - mov lr, pc - ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] -#else - bl __cpuc_flush_kern_all + add r3, r3, lr, lsl #2 #endif + bl __cpu_suspend_save adr lr, BSYM(cpu_suspend_abort) ldmfd sp!, {r0, pc} @ call suspend fn ENDPROC(__cpu_suspend) diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index ed4160b..2d60f19 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -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); local_flush_tlb_all(); -- cgit v0.10.2 From 8e6f83bbdf770014c070c5a41c8e89617cb2a66b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 1 Sep 2011 11:57:59 +0100 Subject: ARM: pm: add L2 cache cleaning for suspend We 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(). Tested-by: Santosh Shilimkar Tested-by: Shawn Guo Tested-by: Lorenzo Pieralisi Signed-off-by: Russell King diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 2d60f19..93a22d2 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -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)); } /* -- cgit v0.10.2