|
@@ -80,6 +80,10 @@ EXPORT_SYMBOL(smp_cpu_mt_shift);
|
|
|
unsigned int smp_cpu_mtid;
|
|
|
EXPORT_SYMBOL(smp_cpu_mtid);
|
|
|
|
|
|
+#ifdef CONFIG_CRASH_DUMP
|
|
|
+__vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
|
|
|
+#endif
|
|
|
+
|
|
|
static unsigned int smp_max_threads __initdata = -1U;
|
|
|
|
|
|
static int __init early_nosmt(char *s)
|
|
@@ -105,8 +109,7 @@ DEFINE_MUTEX(smp_cpu_state_mutex);
|
|
|
/*
|
|
|
* Signal processor helper functions.
|
|
|
*/
|
|
|
-static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm,
|
|
|
- u32 *status)
|
|
|
+static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm)
|
|
|
{
|
|
|
int cc;
|
|
|
|
|
@@ -538,53 +541,24 @@ EXPORT_SYMBOL(smp_ctl_clear_bit);
|
|
|
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
|
|
|
|
|
-static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext,
|
|
|
- u16 address, int is_boot_cpu)
|
|
|
-{
|
|
|
- void *lc = (void *)(unsigned long) store_prefix();
|
|
|
- unsigned long vx_sa;
|
|
|
-
|
|
|
- if (is_boot_cpu) {
|
|
|
- /* Copy the registers of the boot CPU. */
|
|
|
- copy_oldmem_kernel(&sa_ext->sa, (void *) __LC_FPREGS_SAVE_AREA,
|
|
|
- sizeof(sa_ext->sa));
|
|
|
- if (MACHINE_HAS_VX)
|
|
|
- save_vx_regs_safe(sa_ext->vx_regs);
|
|
|
- return;
|
|
|
- }
|
|
|
- /* Get the registers of a non-boot cpu. */
|
|
|
- __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL);
|
|
|
- memcpy_real(&sa_ext->sa, lc + __LC_FPREGS_SAVE_AREA, sizeof(sa_ext->sa));
|
|
|
- if (!MACHINE_HAS_VX)
|
|
|
- return;
|
|
|
- /* Get the VX registers */
|
|
|
- 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));
|
|
|
- memblock_free(vx_sa, PAGE_SIZE);
|
|
|
-}
|
|
|
-
|
|
|
int smp_store_status(int cpu)
|
|
|
{
|
|
|
- unsigned long vx_sa;
|
|
|
- struct pcpu *pcpu;
|
|
|
+ struct pcpu *pcpu = pcpu_devices + cpu;
|
|
|
+ unsigned long pa;
|
|
|
|
|
|
- pcpu = pcpu_devices + cpu;
|
|
|
- if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS,
|
|
|
- 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
|
|
+ pa = __pa(&pcpu->lowcore->floating_pt_save_area);
|
|
|
+ if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
|
|
|
+ pa) != 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);
|
|
|
+ pa = __pa(pcpu->lowcore->vector_save_area_addr);
|
|
|
+ if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
|
|
|
+ pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
|
|
|
+ return -EIO;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#endif /* CONFIG_CRASH_DUMP */
|
|
|
-
|
|
|
/*
|
|
|
* Collect CPU state of the previous, crashed system.
|
|
|
* There are four cases:
|
|
@@ -593,7 +567,7 @@ int smp_store_status(int cpu)
|
|
|
* The state for all CPUs except the boot CPU needs to be collected
|
|
|
* with sigp stop-and-store-status. The boot CPU state is located in
|
|
|
* the absolute lowcore of the memory stored in the HSA. The zcore code
|
|
|
- * will allocate the save area and copy the boot CPU state from the HSA.
|
|
|
+ * will copy the boot CPU state from the HSA.
|
|
|
* 2) stand-alone kdump for SCSI (zfcp dump with swapped memory)
|
|
|
* condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP
|
|
|
* The state for all CPUs except the boot CPU needs to be collected
|
|
@@ -611,21 +585,49 @@ int smp_store_status(int cpu)
|
|
|
* This case does not exist for s390 anymore, setup_arch explicitly
|
|
|
* deactivates the elfcorehdr= kernel parameter
|
|
|
*/
|
|
|
+static __init void smp_save_cpu_vxrs(struct save_area_ext *sa_ext, u16 addr,
|
|
|
+ bool is_boot_cpu, unsigned long page)
|
|
|
+{
|
|
|
+ __vector128 *vxrs = (__vector128 *) page;
|
|
|
+
|
|
|
+ if (is_boot_cpu)
|
|
|
+ vxrs = boot_cpu_vector_save_area;
|
|
|
+ else
|
|
|
+ __pcpu_sigp_relax(addr, SIGP_STORE_ADDITIONAL_STATUS, page);
|
|
|
+ memcpy(&sa_ext->vx_regs, vxrs, sizeof(sa_ext->vx_regs));
|
|
|
+}
|
|
|
+
|
|
|
+static __init void smp_save_cpu_regs(struct save_area_ext *sa_ext, u16 addr,
|
|
|
+ bool is_boot_cpu, unsigned long page)
|
|
|
+{
|
|
|
+ void *regs = (void *) page;
|
|
|
+
|
|
|
+ if (is_boot_cpu)
|
|
|
+ copy_oldmem_kernel(regs, (void *) __LC_FPREGS_SAVE_AREA, 512);
|
|
|
+ else
|
|
|
+ __pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, page);
|
|
|
+ memcpy(&sa_ext->sa, regs, sizeof(sa_ext->sa));
|
|
|
+}
|
|
|
+
|
|
|
void __init smp_save_dump_cpus(void)
|
|
|
{
|
|
|
-#ifdef CONFIG_CRASH_DUMP
|
|
|
int addr, cpu, boot_cpu_addr, max_cpu_addr;
|
|
|
struct save_area_ext *sa_ext;
|
|
|
+ unsigned long page;
|
|
|
bool is_boot_cpu;
|
|
|
|
|
|
if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP))
|
|
|
/* No previous system present, normal boot. */
|
|
|
return;
|
|
|
+ /* Allocate a page as dumping area for the store status sigps */
|
|
|
+ page = memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, 1UL << 31);
|
|
|
+ if (!page)
|
|
|
+ panic("could not allocate memory for save area\n");
|
|
|
/* Set multi-threading state to the previous system. */
|
|
|
pcpu_set_smt(sclp.mtid_prev);
|
|
|
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) ==
|
|
|
+ if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) ==
|
|
|
SIGP_CC_NOT_OPERATIONAL)
|
|
|
continue;
|
|
|
cpu += 1;
|
|
@@ -634,7 +636,7 @@ void __init smp_save_dump_cpus(void)
|
|
|
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) ==
|
|
|
+ if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) ==
|
|
|
SIGP_CC_NOT_OPERATIONAL)
|
|
|
continue;
|
|
|
sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8);
|
|
@@ -643,16 +645,24 @@ void __init smp_save_dump_cpus(void)
|
|
|
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);
|
|
|
+ if (MACHINE_HAS_VX)
|
|
|
+ /* Get the vector registers */
|
|
|
+ smp_save_cpu_vxrs(sa_ext, addr, is_boot_cpu, page);
|
|
|
+ /*
|
|
|
+ * For a zfcp dump OLDMEM_BASE == NULL and the registers
|
|
|
+ * of the boot CPU are stored in the HSA. To retrieve
|
|
|
+ * these registers an SCLP request is required which is
|
|
|
+ * done by drivers/s390/char/zcore.c:init_cpu_info()
|
|
|
+ */
|
|
|
+ if (!is_boot_cpu || OLDMEM_BASE)
|
|
|
+ /* Get the CPU registers */
|
|
|
+ smp_save_cpu_regs(sa_ext, addr, is_boot_cpu, page);
|
|
|
}
|
|
|
+ memblock_free(page, PAGE_SIZE);
|
|
|
diag308_reset();
|
|
|
pcpu_set_smt(0);
|
|
|
-#endif /* CONFIG_CRASH_DUMP */
|
|
|
}
|
|
|
+#endif /* CONFIG_CRASH_DUMP */
|
|
|
|
|
|
void smp_cpu_set_polarization(int cpu, int val)
|
|
|
{
|
|
@@ -676,7 +686,7 @@ static struct sclp_core_info *smp_get_core_info(void)
|
|
|
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) ==
|
|
|
+ if (__pcpu_sigp_relax(address, SIGP_SENSE, 0) ==
|
|
|
SIGP_CC_NOT_OPERATIONAL)
|
|
|
continue;
|
|
|
info->core[info->configured].core_id =
|