aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2015-05-26 13:05:23 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-06-25 03:39:26 -0400
commit1592a8e456436024b6c662f423ce672e672169bb (patch)
tree2afa9f14819db46b7e11e918e5f69124dc31f71c
parent1d1858d2444770154d311e8df5849d44f957dba3 (diff)
s390/kdump: fix nosmt kernel parameter
It turned out that SIGP set-multi-threading can only be done once. Therefore switching to a different MT level after switching to sclp.mtid_prev in the dump case fails. As a symptom specifying the "nosmt" parameter currently fails for the kdump kernel and the kernel starts with multi-threading enabled. So fix this and issue diag 308 subcode 1 call after collecting the CPU states for the dump. Also enhance the diag308_reset() function to be usable also with enabled lowcore protection and prefix register != 0. After the reset it is possible to switch the MT level again. We have to do the reset very early in order not to kill the already initialized console. Therefore instead of kmalloc() the corresponding memblock functions have to be used. To avoid copying the sclp cpu code into sclp_early, we now use the simple sigp loop method for CPU detection. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/ipl.h1
-rw-r--r--arch/s390/include/asm/smp.h1
-rw-r--r--arch/s390/kernel/base.S21
-rw-r--r--arch/s390/kernel/crash_dump.c25
-rw-r--r--arch/s390/kernel/setup.c5
-rw-r--r--arch/s390/kernel/smp.c70
-rw-r--r--drivers/s390/char/zcore.c2
7 files changed, 64 insertions, 61 deletions
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index ece606c2ee86..39ae6a359747 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -94,7 +94,6 @@ struct dump_save_areas {
94}; 94};
95 95
96extern struct dump_save_areas dump_save_areas; 96extern struct dump_save_areas dump_save_areas;
97struct save_area_ext *dump_save_area_create(int cpu);
98 97
99extern void do_reipl(void); 98extern void do_reipl(void);
100extern void do_halt(void); 99extern void do_halt(void);
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index b3bd0282dd98..409830692862 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -29,6 +29,7 @@ extern void smp_call_ipl_cpu(void (*func)(void *), void *);
29 29
30extern int smp_find_processor_id(u16 address); 30extern int smp_find_processor_id(u16 address);
31extern int smp_store_status(int cpu); 31extern int smp_store_status(int cpu);
32extern void smp_save_dump_cpus(void);
32extern int smp_vcpu_scheduled(int cpu); 33extern int smp_vcpu_scheduled(int cpu);
33extern void smp_yield_cpu(int cpu); 34extern void smp_yield_cpu(int cpu);
34extern void smp_cpu_set_polarization(int cpu, int val); 35extern void smp_cpu_set_polarization(int cpu, int val);
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
index daed3fde42ec..326f717df587 100644
--- a/arch/s390/kernel/base.S
+++ b/arch/s390/kernel/base.S
@@ -78,15 +78,20 @@ s390_base_pgm_handler_fn:
78# 78#
79# Calls diag 308 subcode 1 and continues execution 79# Calls diag 308 subcode 1 and continues execution
80# 80#
81# The following conditions must be ensured before calling this function:
82# * Prefix register = 0
83# * Lowcore protection is disabled
84#
85ENTRY(diag308_reset) 81ENTRY(diag308_reset)
86 larl %r4,.Lctlregs # Save control registers 82 larl %r4,.Lctlregs # Save control registers
87 stctg %c0,%c15,0(%r4) 83 stctg %c0,%c15,0(%r4)
84 lg %r2,0(%r4) # Disable lowcore protection
85 nilh %r2,0xefff
86 larl %r4,.Lctlreg0
87 stg %r2,0(%r4)
88 lctlg %c0,%c0,0(%r4)
88 larl %r4,.Lfpctl # Floating point control register 89 larl %r4,.Lfpctl # Floating point control register
89 stfpc 0(%r4) 90 stfpc 0(%r4)
91 larl %r4,.Lprefix # Save prefix register
92 stpx 0(%r4)
93 larl %r4,.Lprefix_zero # Set prefix register to 0
94 spx 0(%r4)
90 larl %r4,.Lcontinue_psw # Save PSW flags 95 larl %r4,.Lcontinue_psw # Save PSW flags
91 epsw %r2,%r3 96 epsw %r2,%r3
92 stm %r2,%r3,0(%r4) 97 stm %r2,%r3,0(%r4)
@@ -106,6 +111,8 @@ ENTRY(diag308_reset)
106 lctlg %c0,%c15,0(%r4) 111 lctlg %c0,%c15,0(%r4)
107 larl %r4,.Lfpctl # Restore floating point ctl register 112 larl %r4,.Lfpctl # Restore floating point ctl register
108 lfpc 0(%r4) 113 lfpc 0(%r4)
114 larl %r4,.Lprefix # Restore prefix register
115 spx 0(%r4)
109 larl %r4,.Lcontinue_psw # Restore PSW flags 116 larl %r4,.Lcontinue_psw # Restore PSW flags
110 lpswe 0(%r4) 117 lpswe 0(%r4)
111.Lcontinue: 118.Lcontinue:
@@ -122,10 +129,16 @@ ENTRY(diag308_reset)
122 129
123 .section .bss 130 .section .bss
124.align 8 131.align 8
132.Lctlreg0:
133 .quad 0
125.Lctlregs: 134.Lctlregs:
126 .rept 16 135 .rept 16
127 .quad 0 136 .quad 0
128 .endr 137 .endr
129.Lfpctl: 138.Lfpctl:
130 .long 0 139 .long 0
140.Lprefix:
141 .long 0
142.Lprefix_zero:
143 .long 0
131 .previous 144 .previous
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index f56cd733b6e1..0c6c01eb3613 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -45,31 +45,6 @@ static struct memblock_type oldmem_type = {
45struct dump_save_areas dump_save_areas; 45struct dump_save_areas dump_save_areas;
46 46
47/* 47/*
48 * Allocate and add a save area for a CPU
49 */
50struct save_area_ext *dump_save_area_create(int cpu)
51{
52 struct save_area_ext **save_areas, *save_area;
53
54 save_area = kmalloc(sizeof(*save_area), GFP_KERNEL);
55 if (!save_area)
56 return NULL;
57 if (cpu + 1 > dump_save_areas.count) {
58 dump_save_areas.count = cpu + 1;
59 save_areas = krealloc(dump_save_areas.areas,
60 dump_save_areas.count * sizeof(void *),
61 GFP_KERNEL | __GFP_ZERO);
62 if (!save_areas) {
63 kfree(save_area);
64 return NULL;
65 }
66 dump_save_areas.areas = save_areas;
67 }
68 dump_save_areas.areas[cpu] = save_area;
69 return save_area;
70}
71
72/*
73 * Return physical address for virtual address 48 * Return physical address for virtual address
74 */ 49 */
75static inline void *load_real_addr(void *addr) 50static inline void *load_real_addr(void *addr)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index af4f41d52cde..ca070d260af2 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -868,6 +868,11 @@ void __init setup_arch(char **cmdline_p)
868 868
869 check_initrd(); 869 check_initrd();
870 reserve_crashkernel(); 870 reserve_crashkernel();
871 /*
872 * Be aware that smp_save_dump_cpus() triggers a system reset.
873 * Therefore CPU and device initialization should be done afterwards.
874 */
875 smp_save_dump_cpus();
871 876
872 setup_resources(); 877 setup_resources();
873 setup_vmcoreinfo(); 878 setup_vmcoreinfo();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b34a1473df70..24ad89df7e5f 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -31,6 +31,7 @@
31#include <linux/cpu.h> 31#include <linux/cpu.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/crash_dump.h> 33#include <linux/crash_dump.h>
34#include <linux/memblock.h>
34#include <asm/asm-offsets.h> 35#include <asm/asm-offsets.h>
35#include <asm/switch_to.h> 36#include <asm/switch_to.h>
36#include <asm/facility.h> 37#include <asm/facility.h>
@@ -531,15 +532,12 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
531 532
532#ifdef CONFIG_CRASH_DUMP 533#ifdef CONFIG_CRASH_DUMP
533 534
534static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) 535static void __smp_store_cpu_state(struct save_area_ext *sa_ext, u16 address,
536 int is_boot_cpu)
535{ 537{
536 void *lc = pcpu_devices[0].lowcore; 538 void *lc = (void *)(unsigned long) store_prefix();
537 struct save_area_ext *sa_ext;
538 unsigned long vx_sa; 539 unsigned long vx_sa;
539 540
540 sa_ext = dump_save_area_create(cpu);
541 if (!sa_ext)
542 panic("could not allocate memory for save area\n");
543 if (is_boot_cpu) { 541 if (is_boot_cpu) {
544 /* Copy the registers of the boot CPU. */ 542 /* Copy the registers of the boot CPU. */
545 copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), 543 copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
@@ -554,12 +552,12 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu)
554 if (!MACHINE_HAS_VX) 552 if (!MACHINE_HAS_VX)
555 return; 553 return;
556 /* Get the VX registers */ 554 /* Get the VX registers */
557 vx_sa = __get_free_page(GFP_KERNEL); 555 vx_sa = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
558 if (!vx_sa) 556 if (!vx_sa)
559 panic("could not allocate memory for VX save area\n"); 557 panic("could not allocate memory for VX save area\n");
560 __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL); 558 __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL);
561 memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs)); 559 memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs));
562 free_page(vx_sa); 560 memblock_free(vx_sa, PAGE_SIZE);
563} 561}
564 562
565/* 563/*
@@ -589,10 +587,11 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu)
589 * old system. The ELF sections are picked up by the crash_dump code 587 * old system. The ELF sections are picked up by the crash_dump code
590 * via elfcorehdr_addr. 588 * via elfcorehdr_addr.
591 */ 589 */
592static void __init smp_store_cpu_states(struct sclp_core_info *info) 590void __init smp_save_dump_cpus(void)
593{ 591{
594 unsigned int cpu, address, i, j; 592 int addr, cpu, boot_cpu_addr, max_cpu_addr;
595 int is_boot_cpu; 593 struct save_area_ext *sa_ext;
594 bool is_boot_cpu;
596 595
597 if (is_kdump_kernel()) 596 if (is_kdump_kernel())
598 /* Previous system stored the CPU states. Nothing to do. */ 597 /* Previous system stored the CPU states. Nothing to do. */
@@ -602,22 +601,34 @@ static void __init smp_store_cpu_states(struct sclp_core_info *info)
602 return; 601 return;
603 /* Set multi-threading state to the previous system. */ 602 /* Set multi-threading state to the previous system. */
604 pcpu_set_smt(sclp.mtid_prev); 603 pcpu_set_smt(sclp.mtid_prev);
605 /* Collect CPU states. */ 604 max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev;
606 cpu = 0; 605 for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) {
607 for (i = 0; i < info->configured; i++) { 606 if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) ==
608 /* Skip CPUs with different CPU type. */ 607 SIGP_CC_NOT_OPERATIONAL)
609 if (sclp.has_core_type && info->core[i].type != boot_core_type)
610 continue; 608 continue;
611 for (j = 0; j <= smp_cpu_mtid; j++, cpu++) { 609 cpu += 1;
612 address = (info->core[i].core_id << smp_cpu_mt_shift) + j;
613 is_boot_cpu = (address == pcpu_devices[0].address);
614 if (is_boot_cpu && !OLDMEM_BASE)
615 /* Skip boot CPU for standard zfcp dump. */
616 continue;
617 /* Get state for this CPu. */
618 __smp_store_cpu_state(cpu, address, is_boot_cpu);
619 }
620 } 610 }
611 dump_save_areas.areas = (void *)memblock_alloc(sizeof(void *) * cpu, 8);
612 dump_save_areas.count = cpu;
613 boot_cpu_addr = stap();
614 for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) {
615 if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) ==
616 SIGP_CC_NOT_OPERATIONAL)
617 continue;
618 sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8);
619 dump_save_areas.areas[cpu] = sa_ext;
620 if (!sa_ext)
621 panic("could not allocate memory for save area\n");
622 is_boot_cpu = (addr == boot_cpu_addr);
623 cpu += 1;
624 if (is_boot_cpu && !OLDMEM_BASE)
625 /* Skip boot CPU for standard zfcp dump. */
626 continue;
627 /* Get state for this CPU. */
628 __smp_store_cpu_state(sa_ext, addr, is_boot_cpu);
629 }
630 diag308_reset();
631 pcpu_set_smt(0);
621} 632}
622 633
623int smp_store_status(int cpu) 634int smp_store_status(int cpu)
@@ -637,6 +648,10 @@ int smp_store_status(int cpu)
637 return 0; 648 return 0;
638} 649}
639 650
651#else
652void smp_save_dump_cpus(void)
653{
654}
640#endif /* CONFIG_CRASH_DUMP */ 655#endif /* CONFIG_CRASH_DUMP */
641 656
642void smp_cpu_set_polarization(int cpu, int val) 657void smp_cpu_set_polarization(int cpu, int val)
@@ -735,11 +750,6 @@ static void __init smp_detect_cpus(void)
735 panic("Could not find boot CPU type"); 750 panic("Could not find boot CPU type");
736 } 751 }
737 752
738#ifdef CONFIG_CRASH_DUMP
739 /* Collect CPU state of previous system */
740 smp_store_cpu_states(info);
741#endif
742
743 /* Set multi-threading state for the current system */ 753 /* Set multi-threading state for the current system */
744 mtid = boot_core_type ? sclp.mtid : sclp.mtid_cp; 754 mtid = boot_core_type ? sclp.mtid : sclp.mtid_cp;
745 mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1; 755 mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1;
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 9a3dd95029cc..823f41fc4bbd 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -154,7 +154,7 @@ static int __init init_cpu_info(enum arch_id arch)
154 154
155 /* get info for boot cpu from lowcore, stored in the HSA */ 155 /* get info for boot cpu from lowcore, stored in the HSA */
156 156
157 sa_ext = dump_save_area_create(0); 157 sa_ext = dump_save_areas.areas[0];
158 if (!sa_ext) 158 if (!sa_ext)
159 return -ENOMEM; 159 return -ENOMEM;
160 if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base, 160 if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,