diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/debug.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/ipl.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/system.h | 34 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/debug.c | 40 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 22 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 6 | ||||
-rw-r--r-- | arch/s390/kernel/lgr.c | 200 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/swsusp_asm64.S | 3 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 2 |
12 files changed, 291 insertions, 31 deletions
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index 9d88db1f55d0..8a8245ed14d2 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h | |||
@@ -131,6 +131,7 @@ void debug_unregister(debug_info_t* id); | |||
131 | 131 | ||
132 | void debug_set_level(debug_info_t* id, int new_level); | 132 | void debug_set_level(debug_info_t* id, int new_level); |
133 | 133 | ||
134 | void debug_set_critical(void); | ||
134 | void debug_stop_all(void); | 135 | void debug_stop_all(void); |
135 | 136 | ||
136 | static inline debug_entry_t* | 137 | static inline debug_entry_t* |
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 6940abfbe1d9..2bd6cb897b90 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h | |||
@@ -169,5 +169,6 @@ enum diag308_rc { | |||
169 | extern int diag308(unsigned long subcode, void *addr); | 169 | extern int diag308(unsigned long subcode, void *addr); |
170 | extern void diag308_reset(void); | 170 | extern void diag308_reset(void); |
171 | extern void store_status(void); | 171 | extern void store_status(void); |
172 | extern void lgr_info_log(void); | ||
172 | 173 | ||
173 | #endif /* _ASM_S390_IPL_H */ | 174 | #endif /* _ASM_S390_IPL_H */ |
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index d73cc6b60000..2e0bb7f0f9b2 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
@@ -7,8 +7,10 @@ | |||
7 | #ifndef __ASM_SYSTEM_H | 7 | #ifndef __ASM_SYSTEM_H |
8 | #define __ASM_SYSTEM_H | 8 | #define __ASM_SYSTEM_H |
9 | 9 | ||
10 | #include <linux/preempt.h> | ||
10 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
11 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/string.h> | ||
12 | #include <asm/types.h> | 14 | #include <asm/types.h> |
13 | #include <asm/ptrace.h> | 15 | #include <asm/ptrace.h> |
14 | #include <asm/setup.h> | 16 | #include <asm/setup.h> |
@@ -248,6 +250,38 @@ static inline int test_facility(unsigned long nr) | |||
248 | return (*ptr & (0x80 >> (nr & 7))) != 0; | 250 | return (*ptr & (0x80 >> (nr & 7))) != 0; |
249 | } | 251 | } |
250 | 252 | ||
253 | /** | ||
254 | * stfle - Store facility list extended | ||
255 | * @stfle_fac_list: array where facility list can be stored | ||
256 | * @size: size of passed in array in double words | ||
257 | */ | ||
258 | static inline void stfle(u64 *stfle_fac_list, int size) | ||
259 | { | ||
260 | unsigned long nr; | ||
261 | |||
262 | preempt_disable(); | ||
263 | S390_lowcore.stfl_fac_list = 0; | ||
264 | asm volatile( | ||
265 | " .insn s,0xb2b10000,0(0)\n" /* stfl */ | ||
266 | "0:\n" | ||
267 | EX_TABLE(0b, 0b) | ||
268 | : "=m" (S390_lowcore.stfl_fac_list)); | ||
269 | nr = 4; /* bytes stored by stfl */ | ||
270 | memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); | ||
271 | if (S390_lowcore.stfl_fac_list & 0x01000000) { | ||
272 | /* More facility bits available with stfle */ | ||
273 | register unsigned long reg0 asm("0") = size - 1; | ||
274 | |||
275 | asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */ | ||
276 | : "+d" (reg0) | ||
277 | : "a" (stfle_fac_list) | ||
278 | : "memory", "cc"); | ||
279 | nr = (reg0 + 1) * 8; /* # bytes stored by stfle */ | ||
280 | } | ||
281 | memset((char *) stfle_fac_list + nr, 0, size * 8 - nr); | ||
282 | preempt_enable(); | ||
283 | } | ||
284 | |||
251 | static inline unsigned short stap(void) | 285 | static inline unsigned short stap(void) |
252 | { | 286 | { |
253 | unsigned short cpu_address; | 287 | unsigned short cpu_address; |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index d0a48268eb27..b21595090499 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | |||
23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ | 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ |
24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ | 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ |
25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ | 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ |
26 | sysinfo.o jump_label.o | 26 | sysinfo.o jump_label.o lgr.o |
27 | 27 | ||
28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 6848828b962e..19e5e9eba546 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
@@ -2,8 +2,8 @@ | |||
2 | * arch/s390/kernel/debug.c | 2 | * arch/s390/kernel/debug.c |
3 | * S/390 debug facility | 3 | * S/390 debug facility |
4 | * | 4 | * |
5 | * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, | 5 | * Copyright IBM Corp. 1999, 2012 |
6 | * IBM Corporation | 6 | * |
7 | * Author(s): Michael Holzheu (holzheu@de.ibm.com), | 7 | * Author(s): Michael Holzheu (holzheu@de.ibm.com), |
8 | * Holger Smolinski (Holger.Smolinski@de.ibm.com) | 8 | * Holger Smolinski (Holger.Smolinski@de.ibm.com) |
9 | * | 9 | * |
@@ -167,6 +167,7 @@ static debug_info_t *debug_area_last = NULL; | |||
167 | static DEFINE_MUTEX(debug_mutex); | 167 | static DEFINE_MUTEX(debug_mutex); |
168 | 168 | ||
169 | static int initialized; | 169 | static int initialized; |
170 | static int debug_critical; | ||
170 | 171 | ||
171 | static const struct file_operations debug_file_ops = { | 172 | static const struct file_operations debug_file_ops = { |
172 | .owner = THIS_MODULE, | 173 | .owner = THIS_MODULE, |
@@ -932,6 +933,11 @@ debug_stop_all(void) | |||
932 | } | 933 | } |
933 | 934 | ||
934 | 935 | ||
936 | void debug_set_critical(void) | ||
937 | { | ||
938 | debug_critical = 1; | ||
939 | } | ||
940 | |||
935 | /* | 941 | /* |
936 | * debug_event_common: | 942 | * debug_event_common: |
937 | * - write debug entry with given size | 943 | * - write debug entry with given size |
@@ -945,7 +951,11 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len) | |||
945 | 951 | ||
946 | if (!debug_active || !id->areas) | 952 | if (!debug_active || !id->areas) |
947 | return NULL; | 953 | return NULL; |
948 | spin_lock_irqsave(&id->lock, flags); | 954 | if (debug_critical) { |
955 | if (!spin_trylock_irqsave(&id->lock, flags)) | ||
956 | return NULL; | ||
957 | } else | ||
958 | spin_lock_irqsave(&id->lock, flags); | ||
949 | active = get_active_entry(id); | 959 | active = get_active_entry(id); |
950 | memset(DEBUG_DATA(active), 0, id->buf_size); | 960 | memset(DEBUG_DATA(active), 0, id->buf_size); |
951 | memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); | 961 | memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); |
@@ -968,7 +978,11 @@ debug_entry_t | |||
968 | 978 | ||
969 | if (!debug_active || !id->areas) | 979 | if (!debug_active || !id->areas) |
970 | return NULL; | 980 | return NULL; |
971 | spin_lock_irqsave(&id->lock, flags); | 981 | if (debug_critical) { |
982 | if (!spin_trylock_irqsave(&id->lock, flags)) | ||
983 | return NULL; | ||
984 | } else | ||
985 | spin_lock_irqsave(&id->lock, flags); | ||
972 | active = get_active_entry(id); | 986 | active = get_active_entry(id); |
973 | memset(DEBUG_DATA(active), 0, id->buf_size); | 987 | memset(DEBUG_DATA(active), 0, id->buf_size); |
974 | memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); | 988 | memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); |
@@ -1013,7 +1027,11 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) | |||
1013 | return NULL; | 1027 | return NULL; |
1014 | numargs=debug_count_numargs(string); | 1028 | numargs=debug_count_numargs(string); |
1015 | 1029 | ||
1016 | spin_lock_irqsave(&id->lock, flags); | 1030 | if (debug_critical) { |
1031 | if (!spin_trylock_irqsave(&id->lock, flags)) | ||
1032 | return NULL; | ||
1033 | } else | ||
1034 | spin_lock_irqsave(&id->lock, flags); | ||
1017 | active = get_active_entry(id); | 1035 | active = get_active_entry(id); |
1018 | curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active); | 1036 | curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active); |
1019 | va_start(ap,string); | 1037 | va_start(ap,string); |
@@ -1047,7 +1065,11 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | |||
1047 | 1065 | ||
1048 | numargs=debug_count_numargs(string); | 1066 | numargs=debug_count_numargs(string); |
1049 | 1067 | ||
1050 | spin_lock_irqsave(&id->lock, flags); | 1068 | if (debug_critical) { |
1069 | if (!spin_trylock_irqsave(&id->lock, flags)) | ||
1070 | return NULL; | ||
1071 | } else | ||
1072 | spin_lock_irqsave(&id->lock, flags); | ||
1051 | active = get_active_entry(id); | 1073 | active = get_active_entry(id); |
1052 | curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active); | 1074 | curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active); |
1053 | va_start(ap,string); | 1075 | va_start(ap,string); |
@@ -1428,10 +1450,10 @@ debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, | |||
1428 | rc += sprintf(out_buf + rc, "| "); | 1450 | rc += sprintf(out_buf + rc, "| "); |
1429 | for (i = 0; i < id->buf_size; i++) { | 1451 | for (i = 0; i < id->buf_size; i++) { |
1430 | unsigned char c = in_buf[i]; | 1452 | unsigned char c = in_buf[i]; |
1431 | if (!isprint(c)) | 1453 | if (isascii(c) && isprint(c)) |
1432 | rc += sprintf(out_buf + rc, "."); | ||
1433 | else | ||
1434 | rc += sprintf(out_buf + rc, "%c", c); | 1454 | rc += sprintf(out_buf + rc, "%c", c); |
1455 | else | ||
1456 | rc += sprintf(out_buf + rc, "."); | ||
1435 | } | 1457 | } |
1436 | rc += sprintf(out_buf + rc, "\n"); | 1458 | rc += sprintf(out_buf + rc, "\n"); |
1437 | return rc; | 1459 | return rc; |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 52098d6dfaa7..578eb4e6d157 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/sysinfo.h> | 29 | #include <asm/sysinfo.h> |
30 | #include <asm/cpcmd.h> | 30 | #include <asm/cpcmd.h> |
31 | #include <asm/sclp.h> | 31 | #include <asm/sclp.h> |
32 | #include <asm/system.h> | ||
32 | #include "entry.h" | 33 | #include "entry.h" |
33 | 34 | ||
34 | /* | 35 | /* |
@@ -262,25 +263,8 @@ static noinline __init void setup_lowcore_early(void) | |||
262 | 263 | ||
263 | static noinline __init void setup_facility_list(void) | 264 | static noinline __init void setup_facility_list(void) |
264 | { | 265 | { |
265 | unsigned long nr; | 266 | stfle(S390_lowcore.stfle_fac_list, |
266 | 267 | ARRAY_SIZE(S390_lowcore.stfle_fac_list)); | |
267 | S390_lowcore.stfl_fac_list = 0; | ||
268 | asm volatile( | ||
269 | " .insn s,0xb2b10000,0(0)\n" /* stfl */ | ||
270 | "0:\n" | ||
271 | EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list)); | ||
272 | memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); | ||
273 | nr = 4; /* # bytes stored by stfl */ | ||
274 | if (test_facility(7)) { | ||
275 | /* More facility bits available with stfle */ | ||
276 | register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1; | ||
277 | asm volatile(".insn s,0xb2b00000,%0" /* stfle */ | ||
278 | : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0) | ||
279 | : : "cc"); | ||
280 | nr = (reg0 + 1) * 8; /* # bytes stored by stfle */ | ||
281 | } | ||
282 | memset((char *) S390_lowcore.stfle_fac_list + nr, 0, | ||
283 | MAX_FACILITY_BIT/8 - nr); | ||
284 | } | 268 | } |
285 | 269 | ||
286 | static noinline __init void setup_hpage(void) | 270 | static noinline __init void setup_hpage(void) |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 9e2f6f7c0e5a..153e21ce2336 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/gfp.h> | 18 | #include <linux/gfp.h> |
19 | #include <linux/crash_dump.h> | 19 | #include <linux/crash_dump.h> |
20 | #include <linux/debug_locks.h> | ||
20 | #include <asm/ipl.h> | 21 | #include <asm/ipl.h> |
21 | #include <asm/smp.h> | 22 | #include <asm/smp.h> |
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <asm/reset.h> | 27 | #include <asm/reset.h> |
27 | #include <asm/sclp.h> | 28 | #include <asm/sclp.h> |
28 | #include <asm/checksum.h> | 29 | #include <asm/checksum.h> |
30 | #include <asm/debug.h> | ||
29 | #include "entry.h" | 31 | #include "entry.h" |
30 | 32 | ||
31 | #define IPL_PARM_BLOCK_VERSION 0 | 33 | #define IPL_PARM_BLOCK_VERSION 0 |
@@ -1692,6 +1694,7 @@ static struct kobj_attribute on_panic_attr = | |||
1692 | 1694 | ||
1693 | static void do_panic(void) | 1695 | static void do_panic(void) |
1694 | { | 1696 | { |
1697 | lgr_info_log(); | ||
1695 | on_panic_trigger.action->fn(&on_panic_trigger); | 1698 | on_panic_trigger.action->fn(&on_panic_trigger); |
1696 | stop_run(&on_panic_trigger); | 1699 | stop_run(&on_panic_trigger); |
1697 | } | 1700 | } |
@@ -1729,6 +1732,9 @@ static void __do_restart(void *ignore) | |||
1729 | 1732 | ||
1730 | void do_restart(void) | 1733 | void do_restart(void) |
1731 | { | 1734 | { |
1735 | tracing_off(); | ||
1736 | debug_locks_off(); | ||
1737 | lgr_info_log(); | ||
1732 | smp_call_online_cpu(__do_restart, NULL); | 1738 | smp_call_online_cpu(__do_restart, NULL); |
1733 | } | 1739 | } |
1734 | 1740 | ||
diff --git a/arch/s390/kernel/lgr.c b/arch/s390/kernel/lgr.c new file mode 100644 index 000000000000..8431b92ca3ae --- /dev/null +++ b/arch/s390/kernel/lgr.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Linux Guest Relocation (LGR) detection | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/timer.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <asm/sysinfo.h> | ||
12 | #include <asm/ebcdic.h> | ||
13 | #include <asm/system.h> | ||
14 | #include <asm/debug.h> | ||
15 | #include <asm/ipl.h> | ||
16 | |||
17 | #define LGR_TIMER_INTERVAL_SECS (30 * 60) | ||
18 | #define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */ | ||
19 | |||
20 | /* | ||
21 | * LGR info: Contains stfle and stsi data | ||
22 | */ | ||
23 | struct lgr_info { | ||
24 | /* Bit field with facility information: 4 DWORDs are stored */ | ||
25 | u64 stfle_fac_list[4]; | ||
26 | /* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */ | ||
27 | u32 level; | ||
28 | /* Level 1: CEC info (stsi 1.1.1) */ | ||
29 | char manufacturer[16]; | ||
30 | char type[4]; | ||
31 | char sequence[16]; | ||
32 | char plant[4]; | ||
33 | char model[16]; | ||
34 | /* Level 2: LPAR info (stsi 2.2.2) */ | ||
35 | u16 lpar_number; | ||
36 | char name[8]; | ||
37 | /* Level 3: VM info (stsi 3.2.2) */ | ||
38 | u8 vm_count; | ||
39 | struct { | ||
40 | char name[8]; | ||
41 | char cpi[16]; | ||
42 | } vm[VM_LEVEL_MAX]; | ||
43 | } __packed __aligned(8); | ||
44 | |||
45 | /* | ||
46 | * LGR globals | ||
47 | */ | ||
48 | static void *lgr_page; | ||
49 | static struct lgr_info lgr_info_last; | ||
50 | static struct lgr_info lgr_info_cur; | ||
51 | static struct debug_info *lgr_dbf; | ||
52 | |||
53 | /* | ||
54 | * Return number of valid stsi levels | ||
55 | */ | ||
56 | static inline int stsi_0(void) | ||
57 | { | ||
58 | int rc = stsi(NULL, 0, 0, 0); | ||
59 | |||
60 | return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Copy buffer and then convert it to ASCII | ||
65 | */ | ||
66 | static void cpascii(char *dst, char *src, int size) | ||
67 | { | ||
68 | memcpy(dst, src, size); | ||
69 | EBCASC(dst, size); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Fill LGR info with 1.1.1 stsi data | ||
74 | */ | ||
75 | static void lgr_stsi_1_1_1(struct lgr_info *lgr_info) | ||
76 | { | ||
77 | struct sysinfo_1_1_1 *si = lgr_page; | ||
78 | |||
79 | if (stsi(si, 1, 1, 1) == -ENOSYS) | ||
80 | return; | ||
81 | cpascii(lgr_info->manufacturer, si->manufacturer, | ||
82 | sizeof(si->manufacturer)); | ||
83 | cpascii(lgr_info->type, si->type, sizeof(si->type)); | ||
84 | cpascii(lgr_info->model, si->model, sizeof(si->model)); | ||
85 | cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence)); | ||
86 | cpascii(lgr_info->plant, si->plant, sizeof(si->plant)); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Fill LGR info with 2.2.2 stsi data | ||
91 | */ | ||
92 | static void lgr_stsi_2_2_2(struct lgr_info *lgr_info) | ||
93 | { | ||
94 | struct sysinfo_2_2_2 *si = lgr_page; | ||
95 | |||
96 | if (stsi(si, 2, 2, 2) == -ENOSYS) | ||
97 | return; | ||
98 | cpascii(lgr_info->name, si->name, sizeof(si->name)); | ||
99 | memcpy(&lgr_info->lpar_number, &si->lpar_number, | ||
100 | sizeof(lgr_info->lpar_number)); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Fill LGR info with 3.2.2 stsi data | ||
105 | */ | ||
106 | static void lgr_stsi_3_2_2(struct lgr_info *lgr_info) | ||
107 | { | ||
108 | struct sysinfo_3_2_2 *si = lgr_page; | ||
109 | int i; | ||
110 | |||
111 | if (stsi(si, 3, 2, 2) == -ENOSYS) | ||
112 | return; | ||
113 | for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) { | ||
114 | cpascii(lgr_info->vm[i].name, si->vm[i].name, | ||
115 | sizeof(si->vm[i].name)); | ||
116 | cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi, | ||
117 | sizeof(si->vm[i].cpi)); | ||
118 | } | ||
119 | lgr_info->vm_count = si->count; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Fill LGR info with current data | ||
124 | */ | ||
125 | static void lgr_info_get(struct lgr_info *lgr_info) | ||
126 | { | ||
127 | memset(lgr_info, 0, sizeof(*lgr_info)); | ||
128 | stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list)); | ||
129 | lgr_info->level = stsi_0(); | ||
130 | if (lgr_info->level == -ENOSYS) | ||
131 | return; | ||
132 | if (lgr_info->level >= 1) | ||
133 | lgr_stsi_1_1_1(lgr_info); | ||
134 | if (lgr_info->level >= 2) | ||
135 | lgr_stsi_2_2_2(lgr_info); | ||
136 | if (lgr_info->level >= 3) | ||
137 | lgr_stsi_3_2_2(lgr_info); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Check if LGR info has changed and if yes log new LGR info to s390dbf | ||
142 | */ | ||
143 | void lgr_info_log(void) | ||
144 | { | ||
145 | static DEFINE_SPINLOCK(lgr_info_lock); | ||
146 | unsigned long flags; | ||
147 | |||
148 | if (!spin_trylock_irqsave(&lgr_info_lock, flags)) | ||
149 | return; | ||
150 | lgr_info_get(&lgr_info_cur); | ||
151 | if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) { | ||
152 | debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur)); | ||
153 | lgr_info_last = lgr_info_cur; | ||
154 | } | ||
155 | spin_unlock_irqrestore(&lgr_info_lock, flags); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(lgr_info_log); | ||
158 | |||
159 | static void lgr_timer_set(void); | ||
160 | |||
161 | /* | ||
162 | * LGR timer callback | ||
163 | */ | ||
164 | static void lgr_timer_fn(unsigned long ignored) | ||
165 | { | ||
166 | lgr_info_log(); | ||
167 | lgr_timer_set(); | ||
168 | } | ||
169 | |||
170 | static struct timer_list lgr_timer = | ||
171 | TIMER_DEFERRED_INITIALIZER(lgr_timer_fn, 0, 0); | ||
172 | |||
173 | /* | ||
174 | * Setup next LGR timer | ||
175 | */ | ||
176 | static void lgr_timer_set(void) | ||
177 | { | ||
178 | mod_timer(&lgr_timer, jiffies + LGR_TIMER_INTERVAL_SECS * HZ); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Initialize LGR: Add s390dbf, write initial lgr_info and setup timer | ||
183 | */ | ||
184 | static int __init lgr_init(void) | ||
185 | { | ||
186 | lgr_page = (void *) __get_free_pages(GFP_KERNEL, 0); | ||
187 | if (!lgr_page) | ||
188 | return -ENOMEM; | ||
189 | lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info)); | ||
190 | if (!lgr_dbf) { | ||
191 | free_page((unsigned long) lgr_page); | ||
192 | return -ENOMEM; | ||
193 | } | ||
194 | debug_register_view(lgr_dbf, &debug_hex_ascii_view); | ||
195 | lgr_info_get(&lgr_info_last); | ||
196 | debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last)); | ||
197 | lgr_timer_set(); | ||
198 | return 0; | ||
199 | } | ||
200 | module_init(lgr_init); | ||
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index bf6fbc03ebaf..0f8cdf1268d0 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
16 | #include <linux/ftrace.h> | 16 | #include <linux/ftrace.h> |
17 | #include <linux/debug_locks.h> | ||
17 | #include <asm/cio.h> | 18 | #include <asm/cio.h> |
18 | #include <asm/setup.h> | 19 | #include <asm/setup.h> |
19 | #include <asm/pgtable.h> | 20 | #include <asm/pgtable.h> |
@@ -209,10 +210,14 @@ static void __machine_kexec(void *data) | |||
209 | struct kimage *image = data; | 210 | struct kimage *image = data; |
210 | 211 | ||
211 | pfault_fini(); | 212 | pfault_fini(); |
212 | if (image->type == KEXEC_TYPE_CRASH) | 213 | tracing_off(); |
214 | debug_locks_off(); | ||
215 | if (image->type == KEXEC_TYPE_CRASH) { | ||
216 | lgr_info_log(); | ||
213 | s390_reset_system(__do_machine_kdump, data); | 217 | s390_reset_system(__do_machine_kdump, data); |
214 | else | 218 | } else { |
215 | s390_reset_system(__do_machine_kexec, data); | 219 | s390_reset_system(__do_machine_kexec, data); |
220 | } | ||
216 | disabled_wait((unsigned long) __builtin_return_address(0)); | 221 | disabled_wait((unsigned long) __builtin_return_address(0)); |
217 | } | 222 | } |
218 | 223 | ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 734e644972ab..d15b6c937088 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/lowcore.h> | 40 | #include <asm/lowcore.h> |
41 | #include <asm/sclp.h> | 41 | #include <asm/sclp.h> |
42 | #include <asm/vdso.h> | 42 | #include <asm/vdso.h> |
43 | #include <asm/debug.h> | ||
43 | #include "entry.h" | 44 | #include "entry.h" |
44 | 45 | ||
45 | enum { | 46 | enum { |
@@ -406,6 +407,7 @@ void smp_send_stop(void) | |||
406 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); | 407 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); |
407 | trace_hardirqs_off(); | 408 | trace_hardirqs_off(); |
408 | 409 | ||
410 | debug_set_critical(); | ||
409 | cpumask_copy(&cpumask, cpu_online_mask); | 411 | cpumask_copy(&cpumask, cpu_online_mask); |
410 | cpumask_clear_cpu(smp_processor_id(), &cpumask); | 412 | cpumask_clear_cpu(smp_processor_id(), &cpumask); |
411 | 413 | ||
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index ad3c79eceed7..dd70ef046058 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S | |||
@@ -257,6 +257,9 @@ restore_registers: | |||
257 | lghi %r2,0 | 257 | lghi %r2,0 |
258 | brasl %r14,arch_set_page_states | 258 | brasl %r14,arch_set_page_states |
259 | 259 | ||
260 | /* Log potential guest relocation */ | ||
261 | brasl %r14,lgr_info_log | ||
262 | |||
260 | /* Reinitialize the channel subsystem */ | 263 | /* Reinitialize the channel subsystem */ |
261 | brasl %r14,channel_subsystem_reinit | 264 | brasl %r14,channel_subsystem_reinit |
262 | 265 | ||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 5ce3750b181f..8894ac435d8d 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/cpcmd.h> | 41 | #include <asm/cpcmd.h> |
42 | #include <asm/lowcore.h> | 42 | #include <asm/lowcore.h> |
43 | #include <asm/debug.h> | 43 | #include <asm/debug.h> |
44 | #include <asm/ipl.h> | ||
44 | #include "entry.h" | 45 | #include "entry.h" |
45 | 46 | ||
46 | void (*pgm_check_table[128])(struct pt_regs *regs); | 47 | void (*pgm_check_table[128])(struct pt_regs *regs); |
@@ -239,6 +240,7 @@ void die(struct pt_regs *regs, const char *str) | |||
239 | static int die_counter; | 240 | static int die_counter; |
240 | 241 | ||
241 | oops_enter(); | 242 | oops_enter(); |
243 | lgr_info_log(); | ||
242 | debug_stop_all(); | 244 | debug_stop_all(); |
243 | console_verbose(); | 245 | console_verbose(); |
244 | spin_lock_irq(&die_lock); | 246 | spin_lock_irq(&die_lock); |