diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 9 | ||||
-rw-r--r-- | arch/s390/Makefile | 4 | ||||
-rw-r--r-- | arch/s390/appldata/appldata_base.c | 119 | ||||
-rw-r--r-- | arch/s390/include/asm/ccwdev.h | 19 | ||||
-rw-r--r-- | arch/s390/include/asm/ccwgroup.h | 10 | ||||
-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/mm/pgtable.c | 19 | ||||
-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 |
16 files changed, 533 insertions, 36 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/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 1dfc7100c7ee..264528e4f58d 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Exports appldata_register_ops() and appldata_unregister_ops() for the | 5 | * Exports appldata_register_ops() and appldata_unregister_ops() for the |
6 | * data gathering modules. | 6 | * data gathering modules. |
7 | * | 7 | * |
8 | * Copyright IBM Corp. 2003, 2008 | 8 | * Copyright IBM Corp. 2003, 2009 |
9 | * | 9 | * |
10 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | 10 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> |
11 | */ | 11 | */ |
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/notifier.h> | 26 | #include <linux/notifier.h> |
27 | #include <linux/cpu.h> | 27 | #include <linux/cpu.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/suspend.h> | ||
30 | #include <linux/platform_device.h> | ||
29 | #include <asm/appldata.h> | 31 | #include <asm/appldata.h> |
30 | #include <asm/timer.h> | 32 | #include <asm/timer.h> |
31 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
@@ -41,6 +43,9 @@ | |||
41 | 43 | ||
42 | #define TOD_MICRO 0x01000 /* nr. of TOD clock units | 44 | #define TOD_MICRO 0x01000 /* nr. of TOD clock units |
43 | for 1 microsecond */ | 45 | for 1 microsecond */ |
46 | |||
47 | static struct platform_device *appldata_pdev; | ||
48 | |||
44 | /* | 49 | /* |
45 | * /proc entries (sysctl) | 50 | * /proc entries (sysctl) |
46 | */ | 51 | */ |
@@ -86,6 +91,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0); | |||
86 | static DEFINE_SPINLOCK(appldata_timer_lock); | 91 | static DEFINE_SPINLOCK(appldata_timer_lock); |
87 | static int appldata_interval = APPLDATA_CPU_INTERVAL; | 92 | static int appldata_interval = APPLDATA_CPU_INTERVAL; |
88 | static int appldata_timer_active; | 93 | static int appldata_timer_active; |
94 | static int appldata_timer_suspended = 0; | ||
89 | 95 | ||
90 | /* | 96 | /* |
91 | * Work queue | 97 | * Work queue |
@@ -475,6 +481,93 @@ void appldata_unregister_ops(struct appldata_ops *ops) | |||
475 | /********************** module-ops management <END> **************************/ | 481 | /********************** module-ops management <END> **************************/ |
476 | 482 | ||
477 | 483 | ||
484 | /**************************** suspend / resume *******************************/ | ||
485 | static int appldata_freeze(struct device *dev) | ||
486 | { | ||
487 | struct appldata_ops *ops; | ||
488 | int rc; | ||
489 | struct list_head *lh; | ||
490 | |||
491 | get_online_cpus(); | ||
492 | spin_lock(&appldata_timer_lock); | ||
493 | if (appldata_timer_active) { | ||
494 | __appldata_vtimer_setup(APPLDATA_DEL_TIMER); | ||
495 | appldata_timer_suspended = 1; | ||
496 | } | ||
497 | spin_unlock(&appldata_timer_lock); | ||
498 | put_online_cpus(); | ||
499 | |||
500 | mutex_lock(&appldata_ops_mutex); | ||
501 | list_for_each(lh, &appldata_ops_list) { | ||
502 | ops = list_entry(lh, struct appldata_ops, list); | ||
503 | if (ops->active == 1) { | ||
504 | rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, | ||
505 | (unsigned long) ops->data, ops->size, | ||
506 | ops->mod_lvl); | ||
507 | if (rc != 0) | ||
508 | pr_err("Stopping the data collection for %s " | ||
509 | "failed with rc=%d\n", ops->name, rc); | ||
510 | } | ||
511 | } | ||
512 | mutex_unlock(&appldata_ops_mutex); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int appldata_restore(struct device *dev) | ||
517 | { | ||
518 | struct appldata_ops *ops; | ||
519 | int rc; | ||
520 | struct list_head *lh; | ||
521 | |||
522 | get_online_cpus(); | ||
523 | spin_lock(&appldata_timer_lock); | ||
524 | if (appldata_timer_suspended) { | ||
525 | __appldata_vtimer_setup(APPLDATA_ADD_TIMER); | ||
526 | appldata_timer_suspended = 0; | ||
527 | } | ||
528 | spin_unlock(&appldata_timer_lock); | ||
529 | put_online_cpus(); | ||
530 | |||
531 | mutex_lock(&appldata_ops_mutex); | ||
532 | list_for_each(lh, &appldata_ops_list) { | ||
533 | ops = list_entry(lh, struct appldata_ops, list); | ||
534 | if (ops->active == 1) { | ||
535 | ops->callback(ops->data); // init record | ||
536 | rc = appldata_diag(ops->record_nr, | ||
537 | APPLDATA_START_INTERVAL_REC, | ||
538 | (unsigned long) ops->data, ops->size, | ||
539 | ops->mod_lvl); | ||
540 | if (rc != 0) { | ||
541 | pr_err("Starting the data collection for %s " | ||
542 | "failed with rc=%d\n", ops->name, rc); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | mutex_unlock(&appldata_ops_mutex); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int appldata_thaw(struct device *dev) | ||
551 | { | ||
552 | return appldata_restore(dev); | ||
553 | } | ||
554 | |||
555 | static struct dev_pm_ops appldata_pm_ops = { | ||
556 | .freeze = appldata_freeze, | ||
557 | .thaw = appldata_thaw, | ||
558 | .restore = appldata_restore, | ||
559 | }; | ||
560 | |||
561 | static struct platform_driver appldata_pdrv = { | ||
562 | .driver = { | ||
563 | .name = "appldata", | ||
564 | .owner = THIS_MODULE, | ||
565 | .pm = &appldata_pm_ops, | ||
566 | }, | ||
567 | }; | ||
568 | /************************* suspend / resume <END> ****************************/ | ||
569 | |||
570 | |||
478 | /******************************* init / exit *********************************/ | 571 | /******************************* init / exit *********************************/ |
479 | 572 | ||
480 | static void __cpuinit appldata_online_cpu(int cpu) | 573 | static void __cpuinit appldata_online_cpu(int cpu) |
@@ -531,11 +624,23 @@ static struct notifier_block __cpuinitdata appldata_nb = { | |||
531 | */ | 624 | */ |
532 | static int __init appldata_init(void) | 625 | static int __init appldata_init(void) |
533 | { | 626 | { |
534 | int i; | 627 | int i, rc; |
628 | |||
629 | rc = platform_driver_register(&appldata_pdrv); | ||
630 | if (rc) | ||
631 | return rc; | ||
535 | 632 | ||
633 | appldata_pdev = platform_device_register_simple("appldata", -1, NULL, | ||
634 | 0); | ||
635 | if (IS_ERR(appldata_pdev)) { | ||
636 | rc = PTR_ERR(appldata_pdev); | ||
637 | goto out_driver; | ||
638 | } | ||
536 | appldata_wq = create_singlethread_workqueue("appldata"); | 639 | appldata_wq = create_singlethread_workqueue("appldata"); |
537 | if (!appldata_wq) | 640 | if (!appldata_wq) { |
538 | return -ENOMEM; | 641 | rc = -ENOMEM; |
642 | goto out_device; | ||
643 | } | ||
539 | 644 | ||
540 | get_online_cpus(); | 645 | get_online_cpus(); |
541 | for_each_online_cpu(i) | 646 | for_each_online_cpu(i) |
@@ -547,6 +652,12 @@ static int __init appldata_init(void) | |||
547 | 652 | ||
548 | appldata_sysctl_header = register_sysctl_table(appldata_dir_table); | 653 | appldata_sysctl_header = register_sysctl_table(appldata_dir_table); |
549 | return 0; | 654 | return 0; |
655 | |||
656 | out_device: | ||
657 | platform_device_unregister(appldata_pdev); | ||
658 | out_driver: | ||
659 | platform_driver_unregister(&appldata_pdrv); | ||
660 | return rc; | ||
550 | } | 661 | } |
551 | 662 | ||
552 | __initcall(appldata_init); | 663 | __initcall(appldata_init); |
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index ba007d8df941..2a5419551176 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h | |||
@@ -1,11 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * include/asm-s390/ccwdev.h | 2 | * Copyright IBM Corp. 2002, 2009 |
3 | * include/asm-s390x/ccwdev.h | ||
4 | * | 3 | * |
5 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Author(s): Arnd Bergmann <arndb@de.ibm.com> |
6 | * Author(s): Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * | 5 | * |
8 | * Interface for CCW device drivers | 6 | * Interface for CCW device drivers |
9 | */ | 7 | */ |
10 | #ifndef _S390_CCWDEV_H_ | 8 | #ifndef _S390_CCWDEV_H_ |
11 | #define _S390_CCWDEV_H_ | 9 | #define _S390_CCWDEV_H_ |
@@ -104,6 +102,11 @@ struct ccw_device { | |||
104 | * @set_offline: called when setting device offline | 102 | * @set_offline: called when setting device offline |
105 | * @notify: notify driver of device state changes | 103 | * @notify: notify driver of device state changes |
106 | * @shutdown: called at device shutdown | 104 | * @shutdown: called at device shutdown |
105 | * @prepare: prepare for pm state transition | ||
106 | * @complete: undo work done in @prepare | ||
107 | * @freeze: callback for freezing during hibernation snapshotting | ||
108 | * @thaw: undo work done in @freeze | ||
109 | * @restore: callback for restoring after hibernation | ||
107 | * @driver: embedded device driver structure | 110 | * @driver: embedded device driver structure |
108 | * @name: device driver name | 111 | * @name: device driver name |
109 | */ | 112 | */ |
@@ -116,6 +119,11 @@ struct ccw_driver { | |||
116 | int (*set_offline) (struct ccw_device *); | 119 | int (*set_offline) (struct ccw_device *); |
117 | int (*notify) (struct ccw_device *, int); | 120 | int (*notify) (struct ccw_device *, int); |
118 | void (*shutdown) (struct ccw_device *); | 121 | void (*shutdown) (struct ccw_device *); |
122 | int (*prepare) (struct ccw_device *); | ||
123 | void (*complete) (struct ccw_device *); | ||
124 | int (*freeze)(struct ccw_device *); | ||
125 | int (*thaw) (struct ccw_device *); | ||
126 | int (*restore)(struct ccw_device *); | ||
119 | struct device_driver driver; | 127 | struct device_driver driver; |
120 | char *name; | 128 | char *name; |
121 | }; | 129 | }; |
@@ -184,6 +192,7 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *); | |||
184 | #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver) | 192 | #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver) |
185 | 193 | ||
186 | extern struct ccw_device *ccw_device_probe_console(void); | 194 | extern struct ccw_device *ccw_device_probe_console(void); |
195 | extern int ccw_device_force_console(void); | ||
187 | 196 | ||
188 | // FIXME: these have to go | 197 | // FIXME: these have to go |
189 | extern int _ccw_device_get_subchannel_number(struct ccw_device *); | 198 | extern int _ccw_device_get_subchannel_number(struct ccw_device *); |
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index a27f68985a79..c79c1e787b86 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h | |||
@@ -38,6 +38,11 @@ struct ccwgroup_device { | |||
38 | * @set_online: function called when device is set online | 38 | * @set_online: function called when device is set online |
39 | * @set_offline: function called when device is set offline | 39 | * @set_offline: function called when device is set offline |
40 | * @shutdown: function called when device is shut down | 40 | * @shutdown: function called when device is shut down |
41 | * @prepare: prepare for pm state transition | ||
42 | * @complete: undo work done in @prepare | ||
43 | * @freeze: callback for freezing during hibernation snapshotting | ||
44 | * @thaw: undo work done in @freeze | ||
45 | * @restore: callback for restoring after hibernation | ||
41 | * @driver: embedded driver structure | 46 | * @driver: embedded driver structure |
42 | */ | 47 | */ |
43 | struct ccwgroup_driver { | 48 | struct ccwgroup_driver { |
@@ -51,6 +56,11 @@ struct ccwgroup_driver { | |||
51 | int (*set_online) (struct ccwgroup_device *); | 56 | int (*set_online) (struct ccwgroup_device *); |
52 | int (*set_offline) (struct ccwgroup_device *); | 57 | int (*set_offline) (struct ccwgroup_device *); |
53 | void (*shutdown)(struct ccwgroup_device *); | 58 | void (*shutdown)(struct ccwgroup_device *); |
59 | int (*prepare) (struct ccwgroup_device *); | ||
60 | void (*complete) (struct ccwgroup_device *); | ||
61 | int (*freeze)(struct ccwgroup_device *); | ||
62 | int (*thaw) (struct ccwgroup_device *); | ||
63 | int (*restore)(struct ccwgroup_device *); | ||
54 | 64 | ||
55 | struct device_driver driver; | 65 | struct device_driver driver; |
56 | }; | 66 | }; |
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/mm/pgtable.c b/arch/s390/mm/pgtable.c index 4ca8e826bf30..565667207985 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -313,3 +313,22 @@ int s390_enable_sie(void) | |||
313 | return 0; | 313 | return 0; |
314 | } | 314 | } |
315 | EXPORT_SYMBOL_GPL(s390_enable_sie); | 315 | EXPORT_SYMBOL_GPL(s390_enable_sie); |
316 | |||
317 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
318 | #ifdef CONFIG_HIBERNATION | ||
319 | bool kernel_page_present(struct page *page) | ||
320 | { | ||
321 | unsigned long addr; | ||
322 | int cc; | ||
323 | |||
324 | addr = page_to_phys(page); | ||
325 | asm("lra %1,0(%1)\n" | ||
326 | "ipm %0\n" | ||
327 | "srl %0,28" | ||
328 | :"=d"(cc),"+a"(addr)::"cc"); | ||
329 | return cc == 0; | ||
330 | } | ||
331 | |||
332 | #endif /* CONFIG_HIBERNATION */ | ||
333 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
334 | |||
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 | ||