diff options
| author | Hans-Joachim Picht <hans@linux.vnet.ibm.com> | 2009-06-16 04:30:52 -0400 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:31:22 -0400 |
| commit | 155af2f95f905c830688dd0ca7c7cac4107334fd (patch) | |
| tree | 4304a39e713d1594903e838830c4029715cc7a2a | |
| parent | c369527f18f8560bd3580be2676cb55b54b02ee6 (diff) | |
[S390] s390: hibernation support for s390
This patch introduces the hibernation backend support to the
s390 architecture. Now it is possible to suspend a mainframe Linux
guest using the following command:
echo disk > /sys/power/state
Signed-off-by: Hans-Joachim Picht <hans@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
| -rw-r--r-- | arch/s390/Kconfig | 9 | ||||
| -rw-r--r-- | arch/s390/Makefile | 4 | ||||
| -rw-r--r-- | arch/s390/include/asm/suspend.h | 10 | ||||
| -rw-r--r-- | arch/s390/include/asm/system.h | 22 | ||||
| -rw-r--r-- | arch/s390/kernel/early.c | 6 | ||||
| -rw-r--r-- | arch/s390/kernel/mem_detect.c | 19 | ||||
| -rw-r--r-- | arch/s390/kernel/smp.c | 38 | ||||
| -rw-r--r-- | arch/s390/power/Makefile | 8 | ||||
| -rw-r--r-- | arch/s390/power/suspend.c | 40 | ||||
| -rw-r--r-- | arch/s390/power/swsusp.c | 30 | ||||
| -rw-r--r-- | arch/s390/power/swsusp_64.c | 17 | ||||
| -rw-r--r-- | arch/s390/power/swsusp_asm64.S | 199 |
12 files changed, 375 insertions, 27 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 99dc3ded6b49..a14dba0e4d67 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -348,6 +348,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG | |||
| 348 | config ARCH_ENABLE_MEMORY_HOTREMOVE | 348 | config ARCH_ENABLE_MEMORY_HOTREMOVE |
| 349 | def_bool y | 349 | def_bool y |
| 350 | 350 | ||
| 351 | config ARCH_HIBERNATION_POSSIBLE | ||
| 352 | def_bool y if 64BIT | ||
| 353 | |||
| 351 | source "mm/Kconfig" | 354 | source "mm/Kconfig" |
| 352 | 355 | ||
| 353 | comment "I/O subsystem configuration" | 356 | comment "I/O subsystem configuration" |
| @@ -592,6 +595,12 @@ config SECCOMP | |||
| 592 | 595 | ||
| 593 | endmenu | 596 | endmenu |
| 594 | 597 | ||
| 598 | menu "Power Management" | ||
| 599 | |||
| 600 | source "kernel/power/Kconfig" | ||
| 601 | |||
| 602 | endmenu | ||
| 603 | |||
| 595 | source "net/Kconfig" | 604 | source "net/Kconfig" |
| 596 | 605 | ||
| 597 | config PCMCIA | 606 | config PCMCIA |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 578c61f15a4b..0ff387cebf88 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
| @@ -88,7 +88,9 @@ LDFLAGS_vmlinux := -e start | |||
| 88 | head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o | 88 | head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o |
| 89 | 89 | ||
| 90 | core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ | 90 | core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ |
| 91 | arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ | 91 | arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \ |
| 92 | arch/s390/power/ | ||
| 93 | |||
| 92 | libs-y += arch/s390/lib/ | 94 | libs-y += arch/s390/lib/ |
| 93 | drivers-y += drivers/s390/ | 95 | drivers-y += drivers/s390/ |
| 94 | drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ | 96 | drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/ |
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h new file mode 100644 index 000000000000..dc75c616eafe --- /dev/null +++ b/arch/s390/include/asm/suspend.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef __ASM_S390_SUSPEND_H | ||
| 2 | #define __ASM_S390_SUSPEND_H | ||
| 3 | |||
| 4 | static inline int arch_prepare_suspend(void) | ||
| 5 | { | ||
| 6 | return 0; | ||
| 7 | } | ||
| 8 | |||
| 9 | #endif | ||
| 10 | |||
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 3a8b26eb1f2e..4fb83c1cdb77 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * include/asm-s390/system.h | 2 | * Copyright IBM Corp. 1999, 2009 |
| 3 | * | 3 | * |
| 4 | * S390 version | 4 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 5 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
| 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | ||
| 7 | * | ||
| 8 | * Derived from "include/asm-i386/system.h" | ||
| 9 | */ | 5 | */ |
| 10 | 6 | ||
| 11 | #ifndef __ASM_SYSTEM_H | 7 | #ifndef __ASM_SYSTEM_H |
| @@ -469,6 +465,20 @@ extern psw_t sysc_restore_trace_psw; | |||
| 469 | extern psw_t io_restore_trace_psw; | 465 | extern psw_t io_restore_trace_psw; |
| 470 | #endif | 466 | #endif |
| 471 | 467 | ||
| 468 | static inline int tprot(unsigned long addr) | ||
| 469 | { | ||
| 470 | int rc = -EFAULT; | ||
| 471 | |||
| 472 | asm volatile( | ||
| 473 | " tprot 0(%1),0\n" | ||
| 474 | "0: ipm %0\n" | ||
| 475 | " srl %0,28\n" | ||
| 476 | "1:\n" | ||
| 477 | EX_TABLE(0b,1b) | ||
| 478 | : "+d" (rc) : "a" (addr) : "cc"); | ||
| 479 | return rc; | ||
| 480 | } | ||
| 481 | |||
| 472 | #endif /* __KERNEL__ */ | 482 | #endif /* __KERNEL__ */ |
| 473 | 483 | ||
| 474 | #endif | 484 | #endif |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index fb263736826c..f9b144049dc9 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/s390/kernel/early.c | 2 | * arch/s390/kernel/early.c |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
| 5 | * Author(s): Hongjie Yang <hongjie@us.ibm.com>, | 5 | * Author(s): Hongjie Yang <hongjie@us.ibm.com>, |
| 6 | * Heiko Carstens <heiko.carstens@de.ibm.com> | 6 | * Heiko Carstens <heiko.carstens@de.ibm.com> |
| 7 | */ | 7 | */ |
| @@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void) | |||
| 210 | machine_flags |= MACHINE_FLAG_VM; | 210 | machine_flags |= MACHINE_FLAG_VM; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | static __init void early_pgm_check_handler(void) | 213 | static void early_pgm_check_handler(void) |
| 214 | { | 214 | { |
| 215 | unsigned long addr; | 215 | unsigned long addr; |
| 216 | const struct exception_table_entry *fixup; | 216 | const struct exception_table_entry *fixup; |
| @@ -222,7 +222,7 @@ static __init void early_pgm_check_handler(void) | |||
| 222 | S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; | 222 | S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static noinline __init void setup_lowcore_early(void) | 225 | void setup_lowcore_early(void) |
| 226 | { | 226 | { |
| 227 | psw_t psw; | 227 | psw_t psw; |
| 228 | 228 | ||
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c index 9872999c66d1..559af0d07878 100644 --- a/arch/s390/kernel/mem_detect.c +++ b/arch/s390/kernel/mem_detect.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2008 | 2 | * Copyright IBM Corp. 2008, 2009 |
| 3 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | 3 | * |
| 4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
| 4 | */ | 5 | */ |
| 5 | 6 | ||
| 6 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| @@ -9,20 +10,6 @@ | |||
| 9 | #include <asm/sclp.h> | 10 | #include <asm/sclp.h> |
| 10 | #include <asm/setup.h> | 11 | #include <asm/setup.h> |
| 11 | 12 | ||
| 12 | static inline int tprot(unsigned long addr) | ||
| 13 | { | ||
| 14 | int rc = -EFAULT; | ||
| 15 | |||
| 16 | asm volatile( | ||
| 17 | " tprot 0(%1),0\n" | ||
| 18 | "0: ipm %0\n" | ||
| 19 | " srl %0,28\n" | ||
| 20 | "1:\n" | ||
| 21 | EX_TABLE(0b,1b) | ||
| 22 | : "+d" (rc) : "a" (addr) : "cc"); | ||
| 23 | return rc; | ||
| 24 | } | ||
| 25 | |||
| 26 | #define ADDR2G (1ULL << 31) | 13 | #define ADDR2G (1ULL << 31) |
| 27 | 14 | ||
| 28 | static void find_memory_chunks(struct mem_chunk chunk[]) | 15 | static void find_memory_chunks(struct mem_chunk chunk[]) |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index cc8c484984e3..fd8e3111a4e8 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/s390/kernel/smp.c | 2 | * arch/s390/kernel/smp.c |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 1999,2007 | 4 | * Copyright IBM Corp. 1999, 2009 |
| 5 | * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 5 | * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), |
| 6 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | 6 | * Martin Schwidefsky (schwidefsky@de.ibm.com) |
| 7 | * Heiko Carstens (heiko.carstens@de.ibm.com) | 7 | * Heiko Carstens (heiko.carstens@de.ibm.com) |
| @@ -1031,6 +1031,42 @@ out: | |||
| 1031 | static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, | 1031 | static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, |
| 1032 | dispatching_store); | 1032 | dispatching_store); |
| 1033 | 1033 | ||
| 1034 | /* | ||
| 1035 | * If the resume kernel runs on another cpu than the suspended kernel, | ||
| 1036 | * we have to switch the cpu IDs in the logical map. | ||
| 1037 | */ | ||
| 1038 | void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id, | ||
| 1039 | struct _lowcore *suspend_lowcore) | ||
| 1040 | { | ||
| 1041 | int cpu, suspend_cpu_id, resume_cpu_id; | ||
| 1042 | u32 suspend_phys_cpu_id; | ||
| 1043 | |||
| 1044 | suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr]; | ||
| 1045 | suspend_cpu_id = suspend_lowcore->cpu_nr; | ||
| 1046 | |||
| 1047 | for_each_present_cpu(cpu) { | ||
| 1048 | if (__cpu_logical_map[cpu] == resume_phys_cpu_id) { | ||
| 1049 | resume_cpu_id = cpu; | ||
| 1050 | goto found; | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | panic("Could not find resume cpu in logical map.\n"); | ||
| 1054 | |||
| 1055 | found: | ||
| 1056 | printk("Resume cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id); | ||
| 1057 | printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id); | ||
| 1058 | |||
| 1059 | __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id; | ||
| 1060 | __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id; | ||
| 1061 | |||
| 1062 | lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id; | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | u32 smp_get_phys_cpu_id(void) | ||
| 1066 | { | ||
| 1067 | return __cpu_logical_map[smp_processor_id()]; | ||
| 1068 | } | ||
| 1069 | |||
| 1034 | static int __init topology_init(void) | 1070 | static int __init topology_init(void) |
| 1035 | { | 1071 | { |
| 1036 | int cpu; | 1072 | int cpu; |
diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile new file mode 100644 index 000000000000..973bb45a8fec --- /dev/null +++ b/arch/s390/power/Makefile | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | # | ||
| 2 | # Makefile for s390 PM support | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_HIBERNATION) += suspend.o | ||
| 6 | obj-$(CONFIG_HIBERNATION) += swsusp.o | ||
| 7 | obj-$(CONFIG_HIBERNATION) += swsusp_64.o | ||
| 8 | obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o | ||
diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c new file mode 100644 index 000000000000..b3351eceebbe --- /dev/null +++ b/arch/s390/power/suspend.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * Suspend support specific for s390. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2009 | ||
| 5 | * | ||
| 6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/suspend.h> | ||
| 11 | #include <linux/reboot.h> | ||
| 12 | #include <linux/pfn.h> | ||
| 13 | #include <asm/sections.h> | ||
| 14 | #include <asm/ipl.h> | ||
| 15 | |||
| 16 | /* | ||
| 17 | * References to section boundaries | ||
| 18 | */ | ||
| 19 | extern const void __nosave_begin, __nosave_end; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * check if given pfn is in the 'nosave' or in the read only NSS section | ||
| 23 | */ | ||
| 24 | int pfn_is_nosave(unsigned long pfn) | ||
| 25 | { | ||
| 26 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; | ||
| 27 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) | ||
| 28 | >> PAGE_SHIFT; | ||
| 29 | unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; | ||
| 30 | unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); | ||
| 31 | |||
| 32 | if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) | ||
| 33 | return 1; | ||
| 34 | if (pfn >= stext_pfn && pfn <= eshared_pfn) { | ||
| 35 | if (ipl_info.type == IPL_TYPE_NSS) | ||
| 36 | return 1; | ||
| 37 | } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) | ||
| 38 | return 1; | ||
| 39 | return 0; | ||
| 40 | } | ||
diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c new file mode 100644 index 000000000000..e6a4fe9f5f24 --- /dev/null +++ b/arch/s390/power/swsusp.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Support for suspend and resume on s390 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2009 | ||
| 5 | * | ||
| 6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | |||
| 11 | /* | ||
| 12 | * save CPU registers before creating a hibernation image and before | ||
| 13 | * restoring the memory state from it | ||
| 14 | */ | ||
| 15 | void save_processor_state(void) | ||
| 16 | { | ||
| 17 | /* implentation contained in the | ||
| 18 | * swsusp_arch_suspend function | ||
| 19 | */ | ||
| 20 | } | ||
| 21 | |||
| 22 | /* | ||
| 23 | * restore the contents of CPU registers | ||
| 24 | */ | ||
| 25 | void restore_processor_state(void) | ||
| 26 | { | ||
| 27 | /* implentation contained in the | ||
| 28 | * swsusp_arch_resume function | ||
| 29 | */ | ||
| 30 | } | ||
diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c new file mode 100644 index 000000000000..9516a517d72f --- /dev/null +++ b/arch/s390/power/swsusp_64.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | /* | ||
| 2 | * Support for suspend and resume on s390 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2009 | ||
| 5 | * | ||
| 6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <asm/system.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | |||
| 13 | void do_after_copyback(void) | ||
| 14 | { | ||
| 15 | mb(); | ||
| 16 | } | ||
| 17 | |||
diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/power/swsusp_asm64.S new file mode 100644 index 000000000000..3c74e7d827c9 --- /dev/null +++ b/arch/s390/power/swsusp_asm64.S | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | /* | ||
| 2 | * S390 64-bit swsusp implementation | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2009 | ||
| 5 | * | ||
| 6 | * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> | ||
| 7 | * Michael Holzheu <holzheu@linux.vnet.ibm.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <asm/page.h> | ||
| 11 | #include <asm/ptrace.h> | ||
| 12 | #include <asm/asm-offsets.h> | ||
| 13 | |||
| 14 | /* | ||
| 15 | * Save register context in absolute 0 lowcore and call swsusp_save() to | ||
| 16 | * create in-memory kernel image. The context is saved in the designated | ||
| 17 | * "store status" memory locations (see POP). | ||
| 18 | * We return from this function twice. The first time during the suspend to | ||
| 19 | * disk process. The second time via the swsusp_arch_resume() function | ||
| 20 | * (see below) in the resume process. | ||
| 21 | * This function runs with disabled interrupts. | ||
| 22 | */ | ||
| 23 | .section .text | ||
| 24 | .align 2 | ||
| 25 | .globl swsusp_arch_suspend | ||
| 26 | swsusp_arch_suspend: | ||
| 27 | stmg %r6,%r15,__SF_GPRS(%r15) | ||
| 28 | lgr %r1,%r15 | ||
| 29 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
| 30 | stg %r1,__SF_BACKCHAIN(%r15) | ||
| 31 | |||
| 32 | /* Deactivate DAT */ | ||
| 33 | stnsm __SF_EMPTY(%r15),0xfb | ||
| 34 | |||
| 35 | /* Switch off lowcore protection */ | ||
| 36 | stctg %c0,%c0,__SF_EMPTY(%r15) | ||
| 37 | ni __SF_EMPTY+4(%r15),0xef | ||
| 38 | lctlg %c0,%c0,__SF_EMPTY(%r15) | ||
| 39 | |||
| 40 | /* Store prefix register on stack */ | ||
| 41 | stpx __SF_EMPTY(%r15) | ||
| 42 | |||
| 43 | /* Setup base register for lowcore (absolute 0) */ | ||
| 44 | llgf %r1,__SF_EMPTY(%r15) | ||
| 45 | |||
| 46 | /* Get pointer to save area */ | ||
| 47 | aghi %r1,0x1000 | ||
| 48 | |||
| 49 | /* Store registers */ | ||
| 50 | mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ | ||
| 51 | stfpc 0x31c(%r1) /* store fpu control */ | ||
| 52 | std 0,0x200(%r1) /* store f0 */ | ||
| 53 | std 1,0x208(%r1) /* store f1 */ | ||
| 54 | std 2,0x210(%r1) /* store f2 */ | ||
| 55 | std 3,0x218(%r1) /* store f3 */ | ||
| 56 | std 4,0x220(%r1) /* store f4 */ | ||
| 57 | std 5,0x228(%r1) /* store f5 */ | ||
| 58 | std 6,0x230(%r1) /* store f6 */ | ||
| 59 | std 7,0x238(%r1) /* store f7 */ | ||
| 60 | std 8,0x240(%r1) /* store f8 */ | ||
| 61 | std 9,0x248(%r1) /* store f9 */ | ||
| 62 | std 10,0x250(%r1) /* store f10 */ | ||
| 63 | std 11,0x258(%r1) /* store f11 */ | ||
| 64 | std 12,0x260(%r1) /* store f12 */ | ||
| 65 | std 13,0x268(%r1) /* store f13 */ | ||
| 66 | std 14,0x270(%r1) /* store f14 */ | ||
| 67 | std 15,0x278(%r1) /* store f15 */ | ||
| 68 | stam %a0,%a15,0x340(%r1) /* store access registers */ | ||
| 69 | stctg %c0,%c15,0x380(%r1) /* store control registers */ | ||
| 70 | stmg %r0,%r15,0x280(%r1) /* store general registers */ | ||
| 71 | |||
| 72 | stpt 0x328(%r1) /* store timer */ | ||
| 73 | stckc 0x330(%r1) /* store clock comparator */ | ||
| 74 | |||
| 75 | /* Activate DAT */ | ||
| 76 | stosm __SF_EMPTY(%r15),0x04 | ||
| 77 | |||
| 78 | /* Set prefix page to zero */ | ||
| 79 | xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) | ||
| 80 | spx __SF_EMPTY(%r15) | ||
| 81 | |||
| 82 | /* Setup lowcore */ | ||
| 83 | brasl %r14,setup_lowcore_early | ||
| 84 | |||
| 85 | /* Save image */ | ||
| 86 | brasl %r14,swsusp_save | ||
| 87 | |||
| 88 | /* Switch on lowcore protection */ | ||
| 89 | stctg %c0,%c0,__SF_EMPTY(%r15) | ||
| 90 | oi __SF_EMPTY+4(%r15),0x10 | ||
| 91 | lctlg %c0,%c0,__SF_EMPTY(%r15) | ||
| 92 | |||
| 93 | /* Restore prefix register and return */ | ||
| 94 | lghi %r1,0x1000 | ||
| 95 | spx 0x318(%r1) | ||
| 96 | lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) | ||
| 97 | lghi %r2,0 | ||
| 98 | br %r14 | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Restore saved memory image to correct place and restore register context. | ||
| 102 | * Then we return to the function that called swsusp_arch_suspend(). | ||
| 103 | * swsusp_arch_resume() runs with disabled interrupts. | ||
| 104 | */ | ||
| 105 | .globl swsusp_arch_resume | ||
| 106 | swsusp_arch_resume: | ||
| 107 | stmg %r6,%r15,__SF_GPRS(%r15) | ||
| 108 | lgr %r1,%r15 | ||
| 109 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
| 110 | stg %r1,__SF_BACKCHAIN(%r15) | ||
| 111 | |||
| 112 | /* Save boot cpu number */ | ||
| 113 | brasl %r14,smp_get_phys_cpu_id | ||
| 114 | lgr %r10,%r2 | ||
| 115 | |||
| 116 | /* Deactivate DAT */ | ||
| 117 | stnsm __SF_EMPTY(%r15),0xfb | ||
| 118 | |||
| 119 | /* Switch off lowcore protection */ | ||
| 120 | stctg %c0,%c0,__SF_EMPTY(%r15) | ||
| 121 | ni __SF_EMPTY+4(%r15),0xef | ||
| 122 | lctlg %c0,%c0,__SF_EMPTY(%r15) | ||
| 123 | |||
| 124 | /* Set prefix page to zero */ | ||
| 125 | xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) | ||
| 126 | spx __SF_EMPTY(%r15) | ||
| 127 | |||
| 128 | /* Restore saved image */ | ||
| 129 | larl %r1,restore_pblist | ||
| 130 | lg %r1,0(%r1) | ||
| 131 | ltgr %r1,%r1 | ||
| 132 | jz 2f | ||
| 133 | 0: | ||
| 134 | lg %r2,8(%r1) | ||
| 135 | lg %r4,0(%r1) | ||
| 136 | lghi %r3,PAGE_SIZE | ||
| 137 | lghi %r5,PAGE_SIZE | ||
| 138 | 1: | ||
| 139 | mvcle %r2,%r4,0 | ||
| 140 | jo 1b | ||
| 141 | lg %r1,16(%r1) | ||
| 142 | ltgr %r1,%r1 | ||
| 143 | jnz 0b | ||
| 144 | 2: | ||
| 145 | ptlb /* flush tlb */ | ||
| 146 | |||
| 147 | /* Restore registers */ | ||
| 148 | lghi %r13,0x1000 /* %r1 = pointer to save arae */ | ||
| 149 | |||
| 150 | spt 0x328(%r13) /* reprogram timer */ | ||
| 151 | //sckc 0x330(%r13) /* set clock comparator */ | ||
| 152 | |||
| 153 | lctlg %c0,%c15,0x380(%r13) /* load control registers */ | ||
| 154 | lam %a0,%a15,0x340(%r13) /* load access registers */ | ||
| 155 | |||
| 156 | lfpc 0x31c(%r13) /* load fpu control */ | ||
| 157 | ld 0,0x200(%r13) /* load f0 */ | ||
| 158 | ld 1,0x208(%r13) /* load f1 */ | ||
| 159 | ld 2,0x210(%r13) /* load f2 */ | ||
| 160 | ld 3,0x218(%r13) /* load f3 */ | ||
| 161 | ld 4,0x220(%r13) /* load f4 */ | ||
| 162 | ld 5,0x228(%r13) /* load f5 */ | ||
| 163 | ld 6,0x230(%r13) /* load f6 */ | ||
| 164 | ld 7,0x238(%r13) /* load f7 */ | ||
| 165 | ld 8,0x240(%r13) /* load f8 */ | ||
| 166 | ld 9,0x248(%r13) /* load f9 */ | ||
| 167 | ld 10,0x250(%r13) /* load f10 */ | ||
| 168 | ld 11,0x258(%r13) /* load f11 */ | ||
| 169 | ld 12,0x260(%r13) /* load f12 */ | ||
| 170 | ld 13,0x268(%r13) /* load f13 */ | ||
| 171 | ld 14,0x270(%r13) /* load f14 */ | ||
| 172 | ld 15,0x278(%r13) /* load f15 */ | ||
| 173 | |||
| 174 | /* Load old stack */ | ||
| 175 | lg %r15,0x2f8(%r13) | ||
| 176 | |||
| 177 | /* Pointer to save arae */ | ||
| 178 | lghi %r13,0x1000 | ||
| 179 | |||
| 180 | /* Switch CPUs */ | ||
| 181 | lgr %r2,%r10 /* get cpu id */ | ||
| 182 | llgf %r3,0x318(%r13) | ||
| 183 | brasl %r14,smp_switch_boot_cpu_in_resume | ||
| 184 | |||
| 185 | /* Restore prefix register */ | ||
| 186 | spx 0x318(%r13) | ||
| 187 | |||
| 188 | /* Switch on lowcore protection */ | ||
| 189 | stctg %c0,%c0,__SF_EMPTY(%r15) | ||
| 190 | oi __SF_EMPTY+4(%r15),0x10 | ||
| 191 | lctlg %c0,%c0,__SF_EMPTY(%r15) | ||
| 192 | |||
| 193 | /* Activate DAT */ | ||
| 194 | stosm __SF_EMPTY(%r15),0x04 | ||
| 195 | |||
| 196 | /* Return 0 */ | ||
| 197 | lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) | ||
| 198 | lghi %r2,0 | ||
| 199 | br %r14 | ||
