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 | ||