diff options
Diffstat (limited to 'arch/arm/kernel/sleep.S')
-rw-r--r-- | arch/arm/kernel/sleep.S | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 3f4a517f5b97..714664b2b2ee 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -8,62 +8,96 @@ .text /* - * 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 + * Save CPU state for a suspend + * r1 = v:p offset + * r2 = suspend function arg0 + * r3 = suspend function */ ENTRY(__cpu_suspend) stmfd sp!, {r4 - r11, lr} #ifdef MULTI_CPU ldr r10, =processor - ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state + ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function #else - ldr r4, =cpu_suspend_size + ldr r5, =cpu_suspend_size + ldr ip, =cpu_do_resume #endif - 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 + 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!, {r1, r6, ip} @ save v:p, 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 #ifdef CONFIG_SMP ALT_SMP(mrc p15, 0, lr, c0, c0, 5) ALT_UP(mov lr, #0) and lr, lr, #15 - add r3, r3, lr, lsl #2 + 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 #endif - bl __cpu_suspend_save adr lr, BSYM(cpu_suspend_abort) ldmfd sp!, {r0, pc} @ call suspend fn ENDPROC(__cpu_suspend) .ltorg cpu_suspend_abort: - ldmia sp!, {r1 - r3} @ pop phys pgd, virt SP, phys resume fn - teq r0, #0 - moveq r0, #1 @ force non-zero value + ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn mov sp, r2 ldmfd sp!, {r4 - r11, pc} 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 */ - .align 5 ENTRY(cpu_resume_mmu) +#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE + 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 +#endif ldr r3, =cpu_resume_after_mmu - 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 + 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 + mov pc, r3 @ jump to virtual address +ENDPROC(cpu_resume_turn_mmu_on) cpu_resume_after_mmu: - bl cpu_init +#ifndef CONFIG_ARCH_HAS_SUSPEND_PAGETABLE + str r5, [r2, r4, lsl #2] @ restore old mapping +#endif + mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache mov r0, #0 @ return zero on success ldmfd sp!, {r4 - r11, pc} ENDPROC(cpu_resume_after_mmu) @@ -88,7 +122,7 @@ 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 phys pgd, stack, resume fn + @ load v:p, stack, resume fn ARM( ldmia r0!, {r1, sp, pc} ) THUMB( ldmia r0!, {r1, r2, r3} ) THUMB( mov sp, r2 ) |