aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/smp.c
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 /arch/s390/kernel/smp.c
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>
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r--arch/s390/kernel/smp.c70
1 files changed, 40 insertions, 30 deletions
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;