diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-30 21:44:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-30 21:44:14 -0700 |
commit | 0161b6e0d88e04f54ada7112bb2dad1f3ae472af (patch) | |
tree | 54f3bdfdb74dc55a8165d0e46bff0ae65ebea123 /arch/s390/kernel | |
parent | 94521ca3dfa6efd4ceb4f6746bf8ead58afb1490 (diff) | |
parent | 1af135a1e70ee6e31b5c265c769448984d221cf2 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull more s390 updates from Martin Schwidefsky:
"There is one larger patch for the AP bus code to make it work with the
longer reset periods of the latest crypto cards.
A new default configuration, a naming cleanup for SMP and a few fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/kdump: fix compile for !SMP
s390/kdump: fix nosmt kernel parameter
s390: new default configuration
s390/smp: cleanup core vs. cpu in the SCLP interface
s390/smp: fix sigp cpu detection loop
s390/zcrypt: Fixed reset and interrupt handling of AP queues
s390/kdump: fix REGSET_VX_LOW vector register ELF notes
s390/bpf: Fix backward jumps
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/base.S | 21 | ||||
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 27 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 5 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 150 |
4 files changed, 103 insertions, 100 deletions
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: # # Calls diag 308 subcode 1 and continues execution # -# The following conditions must be ensured before calling this function: -# * Prefix register = 0 -# * Lowcore protection is disabled -# ENTRY(diag308_reset) larl %r4,.Lctlregs # Save control registers stctg %c0,%c15,0(%r4) + lg %r2,0(%r4) # Disable lowcore protection + nilh %r2,0xefff + larl %r4,.Lctlreg0 + stg %r2,0(%r4) + lctlg %c0,%c0,0(%r4) larl %r4,.Lfpctl # Floating point control register stfpc 0(%r4) + larl %r4,.Lprefix # Save prefix register + stpx 0(%r4) + larl %r4,.Lprefix_zero # Set prefix register to 0 + spx 0(%r4) larl %r4,.Lcontinue_psw # Save PSW flags epsw %r2,%r3 stm %r2,%r3,0(%r4) @@ -106,6 +111,8 @@ ENTRY(diag308_reset) lctlg %c0,%c15,0(%r4) larl %r4,.Lfpctl # Restore floating point ctl register lfpc 0(%r4) + larl %r4,.Lprefix # Restore prefix register + spx 0(%r4) larl %r4,.Lcontinue_psw # Restore PSW flags lpswe 0(%r4) .Lcontinue: @@ -122,10 +129,16 @@ ENTRY(diag308_reset) .section .bss .align 8 +.Lctlreg0: + .quad 0 .Lctlregs: .rept 16 .quad 0 .endr .Lfpctl: .long 0 +.Lprefix: + .long 0 +.Lprefix_zero: + .long 0 .previous diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 7a75ad4594e3..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 = { struct dump_save_areas dump_save_areas; /* - * Allocate and add a save area for a CPU - */ -struct save_area_ext *dump_save_area_create(int cpu) -{ - struct save_area_ext **save_areas, *save_area; - - save_area = kmalloc(sizeof(*save_area), GFP_KERNEL); - if (!save_area) - return NULL; - if (cpu + 1 > dump_save_areas.count) { - dump_save_areas.count = cpu + 1; - save_areas = krealloc(dump_save_areas.areas, - dump_save_areas.count * sizeof(void *), - GFP_KERNEL | __GFP_ZERO); - if (!save_areas) { - kfree(save_area); - return NULL; - } - dump_save_areas.areas = save_areas; - } - dump_save_areas.areas[cpu] = save_area; - return save_area; -} - -/* * Return physical address for virtual address */ static inline void *load_real_addr(void *addr) @@ -416,7 +391,7 @@ static void *nt_s390_vx_low(void *ptr, __vector128 *vx_regs) ptr += len; /* Copy lower halves of SIMD registers 0-15 */ for (i = 0; i < 16; i++) { - memcpy(ptr, &vx_regs[i], 8); + memcpy(ptr, &vx_regs[i].u[2], 8); ptr += 8; } return ptr; diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 73941bf42350..f7f027caaaaa 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -868,6 +868,11 @@ void __init setup_arch(char **cmdline_p) check_initrd(); reserve_crashkernel(); + /* + * Be aware that smp_save_dump_cpus() triggers a system reset. + * Therefore CPU and device initialization should be done afterwards. + */ + smp_save_dump_cpus(); setup_resources(); setup_vmcoreinfo(); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 0d9d59d4710e..6f54c175f5c9 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -31,6 +31,7 @@ #include <linux/cpu.h> #include <linux/slab.h> #include <linux/crash_dump.h> +#include <linux/memblock.h> #include <asm/asm-offsets.h> #include <asm/switch_to.h> #include <asm/facility.h> @@ -69,7 +70,7 @@ struct pcpu { u16 address; /* physical cpu address */ }; -static u8 boot_cpu_type; +static u8 boot_core_type; static struct pcpu pcpu_devices[NR_CPUS]; unsigned int smp_cpu_mt_shift; @@ -531,15 +532,12 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); #ifdef CONFIG_CRASH_DUMP -static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) +static void __smp_store_cpu_state(struct save_area_ext *sa_ext, u16 address, + int is_boot_cpu) { - void *lc = pcpu_devices[0].lowcore; - struct save_area_ext *sa_ext; + void *lc = (void *)(unsigned long) store_prefix(); unsigned long vx_sa; - sa_ext = dump_save_area_create(cpu); - if (!sa_ext) - panic("could not allocate memory for save area\n"); if (is_boot_cpu) { /* Copy the registers of the boot CPU. */ copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), @@ -554,14 +552,33 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) if (!MACHINE_HAS_VX) return; /* Get the VX registers */ - vx_sa = __get_free_page(GFP_KERNEL); + vx_sa = memblock_alloc(PAGE_SIZE, PAGE_SIZE); if (!vx_sa) panic("could not allocate memory for VX save area\n"); __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL); memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs)); - free_page(vx_sa); + memblock_free(vx_sa, PAGE_SIZE); } +int smp_store_status(int cpu) +{ + unsigned long vx_sa; + struct pcpu *pcpu; + + pcpu = pcpu_devices + cpu; + if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, + 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) + return -EIO; + if (!MACHINE_HAS_VX) + return 0; + vx_sa = __pa(pcpu->lowcore->vector_save_area_addr); + __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, + vx_sa, NULL); + return 0; +} + +#endif /* CONFIG_CRASH_DUMP */ + /* * Collect CPU state of the previous, crashed system. * There are four cases: @@ -589,10 +606,12 @@ static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) * old system. The ELF sections are picked up by the crash_dump code * via elfcorehdr_addr. */ -static void __init smp_store_cpu_states(struct sclp_cpu_info *info) +void __init smp_save_dump_cpus(void) { - unsigned int cpu, address, i, j; - int is_boot_cpu; +#ifdef CONFIG_CRASH_DUMP + int addr, cpu, boot_cpu_addr, max_cpu_addr; + struct save_area_ext *sa_ext; + bool is_boot_cpu; if (is_kdump_kernel()) /* Previous system stored the CPU states. Nothing to do. */ @@ -602,42 +621,36 @@ static void __init smp_store_cpu_states(struct sclp_cpu_info *info) return; /* Set multi-threading state to the previous system. */ pcpu_set_smt(sclp.mtid_prev); - /* Collect CPU states. */ - cpu = 0; - for (i = 0; i < info->configured; i++) { - /* Skip CPUs with different CPU type. */ - if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) + max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev; + for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { + if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == + SIGP_CC_NOT_OPERATIONAL) continue; - for (j = 0; j <= smp_cpu_mtid; j++, cpu++) { - address = (info->cpu[i].core_id << smp_cpu_mt_shift) + j; - is_boot_cpu = (address == pcpu_devices[0].address); - if (is_boot_cpu && !OLDMEM_BASE) - /* Skip boot CPU for standard zfcp dump. */ - continue; - /* Get state for this CPu. */ - __smp_store_cpu_state(cpu, address, is_boot_cpu); - } + cpu += 1; } -} - -int smp_store_status(int cpu) -{ - unsigned long vx_sa; - struct pcpu *pcpu; - - pcpu = pcpu_devices + cpu; - if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, - 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) - return -EIO; - if (!MACHINE_HAS_VX) - return 0; - vx_sa = __pa(pcpu->lowcore->vector_save_area_addr); - __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, - vx_sa, NULL); - return 0; -} - + dump_save_areas.areas = (void *)memblock_alloc(sizeof(void *) * cpu, 8); + dump_save_areas.count = cpu; + boot_cpu_addr = stap(); + for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { + if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == + SIGP_CC_NOT_OPERATIONAL) + continue; + sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8); + dump_save_areas.areas[cpu] = sa_ext; + if (!sa_ext) + panic("could not allocate memory for save area\n"); + is_boot_cpu = (addr == boot_cpu_addr); + cpu += 1; + if (is_boot_cpu && !OLDMEM_BASE) + /* Skip boot CPU for standard zfcp dump. */ + continue; + /* Get state for this CPU. */ + __smp_store_cpu_state(sa_ext, addr, is_boot_cpu); + } + diag308_reset(); + pcpu_set_smt(0); #endif /* CONFIG_CRASH_DUMP */ +} void smp_cpu_set_polarization(int cpu, int val) { @@ -649,21 +662,22 @@ int smp_cpu_get_polarization(int cpu) return pcpu_devices[cpu].polarization; } -static struct sclp_cpu_info *smp_get_cpu_info(void) +static struct sclp_core_info *smp_get_core_info(void) { static int use_sigp_detection; - struct sclp_cpu_info *info; + struct sclp_core_info *info; int address; info = kzalloc(sizeof(*info), GFP_KERNEL); - if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { + if (info && (use_sigp_detection || sclp_get_core_info(info))) { use_sigp_detection = 1; - for (address = 0; address <= MAX_CPU_ADDRESS; + for (address = 0; + address < (SCLP_MAX_CORES << smp_cpu_mt_shift); address += (1U << smp_cpu_mt_shift)) { if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) == SIGP_CC_NOT_OPERATIONAL) continue; - info->cpu[info->configured].core_id = + info->core[info->configured].core_id = address >> smp_cpu_mt_shift; info->configured++; } @@ -674,7 +688,7 @@ static struct sclp_cpu_info *smp_get_cpu_info(void) static int smp_add_present_cpu(int cpu); -static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) +static int __smp_rescan_cpus(struct sclp_core_info *info, int sysfs_add) { struct pcpu *pcpu; cpumask_t avail; @@ -685,9 +699,9 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask); cpu = cpumask_first(&avail); for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) { - if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) + if (sclp.has_core_type && info->core[i].type != boot_core_type) continue; - address = info->cpu[i].core_id << smp_cpu_mt_shift; + address = info->core[i].core_id << smp_cpu_mt_shift; for (j = 0; j <= smp_cpu_mtid; j++) { if (pcpu_find_address(cpu_present_mask, address + j)) continue; @@ -713,41 +727,37 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) static void __init smp_detect_cpus(void) { unsigned int cpu, mtid, c_cpus, s_cpus; - struct sclp_cpu_info *info; + struct sclp_core_info *info; u16 address; /* Get CPU information */ - info = smp_get_cpu_info(); + info = smp_get_core_info(); if (!info) panic("smp_detect_cpus failed to allocate memory\n"); /* Find boot CPU type */ - if (info->has_cpu_type) { + if (sclp.has_core_type) { address = stap(); for (cpu = 0; cpu < info->combined; cpu++) - if (info->cpu[cpu].core_id == address) { + if (info->core[cpu].core_id == address) { /* The boot cpu dictates the cpu type. */ - boot_cpu_type = info->cpu[cpu].type; + boot_core_type = info->core[cpu].type; break; } if (cpu >= info->combined) panic("Could not find boot CPU type"); } -#ifdef CONFIG_CRASH_DUMP - /* Collect CPU state of previous system */ - smp_store_cpu_states(info); -#endif - /* Set multi-threading state for the current system */ - mtid = boot_cpu_type ? sclp.mtid : sclp.mtid_cp; + mtid = boot_core_type ? sclp.mtid : sclp.mtid_cp; mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1; pcpu_set_smt(mtid); /* Print number of CPUs */ c_cpus = s_cpus = 0; for (cpu = 0; cpu < info->combined; cpu++) { - if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type) + if (sclp.has_core_type && + info->core[cpu].type != boot_core_type) continue; if (cpu < info->configured) c_cpus += smp_cpu_mtid + 1; @@ -884,7 +894,7 @@ void __init smp_fill_possible_mask(void) sclp_max = max(sclp.mtid, sclp.mtid_cp) + 1; sclp_max = min(smp_max_threads, sclp_max); - sclp_max = sclp.max_cpu * sclp_max ?: nr_cpu_ids; + sclp_max = sclp.max_cores * sclp_max ?: nr_cpu_ids; possible = setup_possible_cpus ?: nr_cpu_ids; possible = min(possible, sclp_max); for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++) @@ -977,7 +987,7 @@ static ssize_t cpu_configure_store(struct device *dev, case 0: if (pcpu->state != CPU_STATE_CONFIGURED) break; - rc = sclp_cpu_deconfigure(pcpu->address >> smp_cpu_mt_shift); + rc = sclp_core_deconfigure(pcpu->address >> smp_cpu_mt_shift); if (rc) break; for (i = 0; i <= smp_cpu_mtid; i++) { @@ -992,7 +1002,7 @@ static ssize_t cpu_configure_store(struct device *dev, case 1: if (pcpu->state != CPU_STATE_STANDBY) break; - rc = sclp_cpu_configure(pcpu->address >> smp_cpu_mt_shift); + rc = sclp_core_configure(pcpu->address >> smp_cpu_mt_shift); if (rc) break; for (i = 0; i <= smp_cpu_mtid; i++) { @@ -1107,10 +1117,10 @@ out: int __ref smp_rescan_cpus(void) { - struct sclp_cpu_info *info; + struct sclp_core_info *info; int nr; - info = smp_get_cpu_info(); + info = smp_get_core_info(); if (!info) return -ENOMEM; get_online_cpus(); |