Skip to content

Commit

Permalink
[POWERPC] powermac: Suspend to disk on G5
Browse files Browse the repository at this point in the history
Powermac G5 suspend to disk implementation.  The code is platform
agnostic but only tested on powermac, no other 64-bit powerpc
machines.

Because nvidiafb still breaks suspend I have marked it EXPERIMENTAL on
powermac and because I can't test it and some lowlevel code will need
changes it is BROKEN on all other 64-bit platforms.

Signed-off-by: Johannes Berg <[email protected]>
Acked-by: Benjamin Herrenschmidt <[email protected]>
Signed-off-by: Paul Mackerras <[email protected]>
  • Loading branch information
jmberg authored and paulusmack committed May 7, 2007
1 parent 7e11580 commit 543b9fd
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 6 deletions.
5 changes: 5 additions & 0 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ config DEFAULT_UIMAGE
Used to allow a board to specify it wants a uImage built by default
default n

config PPC64_SWSUSP
bool
depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
default y

menu "Processor support"
choice
prompt "Processor Type"
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
obj-$(CONFIG_TAU) += tau_6xx.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
obj32-$(CONFIG_MODULES) += module_32.o

ifeq ($(CONFIG_PPC_MERGE),y)
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
#include <linux/types.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/suspend.h>
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
#else
#include <linux/ptrace.h>
#include <linux/suspend.h>
#endif

#include <asm/io.h>
Expand Down Expand Up @@ -257,11 +257,11 @@ int main(void)
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));

#ifndef CONFIG_PPC64
DEFINE(pbe_address, offsetof(struct pbe, address));
DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
DEFINE(pbe_next, offsetof(struct pbe, next));

#ifndef CONFIG_PPC64
DEFINE(TASK_SIZE, TASK_SIZE);
DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
#endif /* ! CONFIG_PPC64 */
Expand Down
5 changes: 4 additions & 1 deletion arch/powerpc/kernel/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@
#include <asm/smp.h>

#ifdef CONFIG_HOTPLUG_CPU
/* this is used for software suspend, and that shuts down
* CPUs even while the system is still booting... */
#define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \
system_state == SYSTEM_RUNNING)
(system_state == SYSTEM_RUNNING \
|| system_state == SYSTEM_BOOTING))
#else
#define cpu_should_die() 0
#endif
Expand Down
9 changes: 9 additions & 0 deletions arch/powerpc/kernel/swsusp.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,20 @@ void save_processor_state(void)
flush_fp_to_thread(current);
flush_altivec_to_thread(current);
flush_spe_to_thread(current);

#ifdef CONFIG_PPC64
hard_irq_disable();
#endif

}

void restore_processor_state(void)
{
#ifdef CONFIG_PPC32
set_context(current->active_mm->context.id, current->active_mm->pgd);
#endif

#ifdef CONFIG_PPC64
hard_irq_enable();
#endif
}
24 changes: 24 additions & 0 deletions arch/powerpc/kernel/swsusp_64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* PowerPC 64-bit swsusp implementation
*
* Copyright 2006 Johannes Berg <[email protected]>
*
* GPLv2
*/

#include <asm/system.h>
#include <asm/iommu.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

void do_after_copyback(void)
{
iommu_restore();
touch_softlockup_watchdog();
mb();
}

void _iommu_save(void)
{
iommu_save();
}
228 changes: 228 additions & 0 deletions arch/powerpc/kernel/swsusp_asm64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
* PowerPC 64-bit swsusp implementation
*
* Copyright 2006 Johannes Berg <[email protected]>
*
* GPLv2
*/

#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
#include <asm/thread_info.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>

/*
* Structure for storing CPU registers on the save area.
*/
#define SL_r1 0x00 /* stack pointer */
#define SL_PC 0x08
#define SL_MSR 0x10
#define SL_SDR1 0x18
#define SL_XER 0x20
#define SL_TB 0x40
#define SL_r2 0x48
#define SL_CR 0x50
#define SL_LR 0x58
#define SL_r12 0x60
#define SL_r13 0x68
#define SL_r14 0x70
#define SL_r15 0x78
#define SL_r16 0x80
#define SL_r17 0x88
#define SL_r18 0x90
#define SL_r19 0x98
#define SL_r20 0xa0
#define SL_r21 0xa8
#define SL_r22 0xb0
#define SL_r23 0xb8
#define SL_r24 0xc0
#define SL_r25 0xc8
#define SL_r26 0xd0
#define SL_r27 0xd8
#define SL_r28 0xe0
#define SL_r29 0xe8
#define SL_r30 0xf0
#define SL_r31 0xf8
#define SL_SIZE SL_r31+8

/* these macros rely on the save area being
* pointed to by r11 */
#define SAVE_SPECIAL(special) \
mf##special r0 ;\
std r0, SL_##special(r11)
#define RESTORE_SPECIAL(special) \
ld r0, SL_##special(r11) ;\
mt##special r0
#define SAVE_REGISTER(reg) \
std reg, SL_##reg(r11)
#define RESTORE_REGISTER(reg) \
ld reg, SL_##reg(r11)

/* space for storing cpu state */
.section .data
.align 5
swsusp_save_area:
.space SL_SIZE

.section ".toc","aw"
swsusp_save_area_ptr:
.tc swsusp_save_area[TC],swsusp_save_area
restore_pblist_ptr:
.tc restore_pblist[TC],restore_pblist

.section .text
.align 5
_GLOBAL(swsusp_arch_suspend)
ld r11,swsusp_save_area_ptr@toc(r2)
SAVE_SPECIAL(LR)
SAVE_REGISTER(r1)
SAVE_SPECIAL(CR)
SAVE_SPECIAL(TB)
SAVE_REGISTER(r2)
SAVE_REGISTER(r12)
SAVE_REGISTER(r13)
SAVE_REGISTER(r14)
SAVE_REGISTER(r15)
SAVE_REGISTER(r16)
SAVE_REGISTER(r17)
SAVE_REGISTER(r18)
SAVE_REGISTER(r19)
SAVE_REGISTER(r20)
SAVE_REGISTER(r21)
SAVE_REGISTER(r22)
SAVE_REGISTER(r23)
SAVE_REGISTER(r24)
SAVE_REGISTER(r25)
SAVE_REGISTER(r26)
SAVE_REGISTER(r27)
SAVE_REGISTER(r28)
SAVE_REGISTER(r29)
SAVE_REGISTER(r30)
SAVE_REGISTER(r31)
SAVE_SPECIAL(MSR)
SAVE_SPECIAL(SDR1)
SAVE_SPECIAL(XER)

/* we push the stack up 128 bytes but don't store the
* stack pointer on the stack like a real stackframe */
addi r1,r1,-128

bl _iommu_save
bl swsusp_save

/* restore LR */
ld r11,swsusp_save_area_ptr@toc(r2)
RESTORE_SPECIAL(LR)
addi r1,r1,128

blr

/* Resume code */
_GLOBAL(swsusp_arch_resume)
/* Stop pending alitvec streams and memory accesses */
BEGIN_FTR_SECTION
DSSALL
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
sync

ld r12,restore_pblist_ptr@toc(r2)
ld r12,0(r12)

cmpdi r12,0
beq- nothing_to_copy
li r15,512
copyloop:
ld r13,pbe_address(r12)
ld r14,pbe_orig_address(r12)

mtctr r15
li r10,0
copy_page_loop:
ldx r0,r10,r13
stdx r0,r10,r14
addi r10,r10,8
bdnz copy_page_loop

ld r12,pbe_next(r12)
cmpdi r12,0
bne+ copyloop
nothing_to_copy:

/* flush caches */
lis r3, 0x10
mtctr r3
li r3, 0
ori r3, r3, CONFIG_KERNEL_START>>48
li r0, 48
sld r3, r3, r0
li r0, 0
1:
dcbf r0,r3
addi r3,r3,0x20
bdnz 1b

sync

tlbia

ld r11,swsusp_save_area_ptr@toc(r2)

RESTORE_SPECIAL(CR)

/* restore timebase */
/* load saved tb */
ld r1, SL_TB(r11)
/* get upper 32 bits of it */
srdi r2, r1, 32
/* clear tb lower to avoid wrap */
li r0, 0
mttbl r0
/* set tb upper */
mttbu r2
/* set tb lower */
mttbl r1

/* restore registers */
RESTORE_REGISTER(r1)
RESTORE_REGISTER(r2)
RESTORE_REGISTER(r12)
RESTORE_REGISTER(r13)
RESTORE_REGISTER(r14)
RESTORE_REGISTER(r15)
RESTORE_REGISTER(r16)
RESTORE_REGISTER(r17)
RESTORE_REGISTER(r18)
RESTORE_REGISTER(r19)
RESTORE_REGISTER(r20)
RESTORE_REGISTER(r21)
RESTORE_REGISTER(r22)
RESTORE_REGISTER(r23)
RESTORE_REGISTER(r24)
RESTORE_REGISTER(r25)
RESTORE_REGISTER(r26)
RESTORE_REGISTER(r27)
RESTORE_REGISTER(r28)
RESTORE_REGISTER(r29)
RESTORE_REGISTER(r30)
RESTORE_REGISTER(r31)
/* can't use RESTORE_SPECIAL(MSR) */
ld r0, SL_MSR(r11)
mtmsrd r0, 0
RESTORE_SPECIAL(SDR1)
RESTORE_SPECIAL(XER)

sync

addi r1,r1,-128
bl slb_flush_and_rebolt
bl do_after_copyback
addi r1,r1,128

ld r11,swsusp_save_area_ptr@toc(r2)
RESTORE_SPECIAL(LR)

li r3, 0
blr
2 changes: 1 addition & 1 deletion include/linux/suspend.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H

#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
#include <asm/suspend.h>
#endif
#include <linux/swap.h>
Expand Down
4 changes: 2 additions & 2 deletions kernel/power/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ config PM_SYSFS_DEPRECATED

config SOFTWARE_SUSPEND
bool "Software Suspend"
depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
---help---
Enable the suspend to disk (STD) functionality.

Expand Down Expand Up @@ -134,7 +134,7 @@ config PM_STD_PARTITION

config SUSPEND_SMP
bool
depends on HOTPLUG_CPU && X86 && PM
depends on HOTPLUG_CPU && (X86 || PPC64) && PM
default y

config APM_EMULATION
Expand Down

0 comments on commit 543b9fd

Please sign in to comment.