mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-11 07:30:16 +00:00
s390/smp: enable DAT before CPU restart callback is called
The restart interrupt is triggered whenever a secondary CPU is brought online, a remote function call dispatched from another CPU or a manual PSW restart is initiated and causes the system to kdump. The handling routine is always called with DAT turned off. It then initializes the stack frame and invokes a callback. The existing callbacks handle DAT as follows: * __do_restart() and __machine_kexec() turn in on upon entry; * __ipl_run(), __reipl_run() and __dump_run() do not turn it right away, but all of them call diag308() - which turns DAT on, but only if kasan is enabled; In addition to the described complexity all callbacks (and the functions they call) should avoid kasan instrumentation while DAT is off. This update enables DAT in the assembler restart handler and relieves any callbacks (which are mostly C functions) from dealing with DAT altogether. There are four types of CPU restart that initialize control registers in different ways: 1. Start of secondary CPU on boot - control registers are inherited from the IPL CPU; 2. Restart of online CPU - control registers of the CPU being restarted are kept; 3. Hotplug of offline CPU - control registers are inherited from the starting CPU; 4. Start of offline CPU triggered by manual PSW restart - the control registers are read from the absolute lowcore and contain the boot time IPL CPU values updated with all follow-up calls of smp_ctl_set_bit() and smp_ctl_clear_bit() routines; In first three cases contents of the control registers is the most recent. In the latter case control registers are good enough to facilitate successful completion of kdump operation. Suggested-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
e7dc78d3d9
commit
915fea04f9
@ -124,7 +124,8 @@ struct lowcore {
|
||||
/* Restart function and parameter. */
|
||||
__u64 restart_fn; /* 0x0370 */
|
||||
__u64 restart_data; /* 0x0378 */
|
||||
__u64 restart_source; /* 0x0380 */
|
||||
__u32 restart_source; /* 0x0380 */
|
||||
__u32 restart_flags; /* 0x0384 */
|
||||
|
||||
/* Address space pointer. */
|
||||
__u64 kernel_asce; /* 0x0388 */
|
||||
|
@ -26,6 +26,8 @@
|
||||
#define _CIF_MCCK_GUEST BIT(CIF_MCCK_GUEST)
|
||||
#define _CIF_DEDICATED_CPU BIT(CIF_DEDICATED_CPU)
|
||||
|
||||
#define RESTART_FLAG_CTLREGS _AC(1 << 0, U)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
|
@ -116,6 +116,7 @@ int main(void)
|
||||
OFFSET(__LC_RESTART_FN, lowcore, restart_fn);
|
||||
OFFSET(__LC_RESTART_DATA, lowcore, restart_data);
|
||||
OFFSET(__LC_RESTART_SOURCE, lowcore, restart_source);
|
||||
OFFSET(__LC_RESTART_FLAGS, lowcore, restart_flags);
|
||||
OFFSET(__LC_KERNEL_ASCE, lowcore, kernel_asce);
|
||||
OFFSET(__LC_USER_ASCE, lowcore, user_asce);
|
||||
OFFSET(__LC_LPP, lowcore, lpp);
|
||||
|
@ -624,12 +624,15 @@ ENTRY(mcck_int_handler)
|
||||
4: j 4b
|
||||
ENDPROC(mcck_int_handler)
|
||||
|
||||
#
|
||||
# PSW restart interrupt handler
|
||||
#
|
||||
ENTRY(restart_int_handler)
|
||||
ALTERNATIVE "", ".insn s,0xb2800000,_LPP_OFFSET", 40
|
||||
stg %r15,__LC_SAVE_AREA_RESTART
|
||||
TSTMSK __LC_RESTART_FLAGS,RESTART_FLAG_CTLREGS,4
|
||||
jz 0f
|
||||
la %r15,4095
|
||||
lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r15)
|
||||
0: larl %r15,.Lstosm_tmp
|
||||
stosm 0(%r15),0x04 # turn dat on, keep irqs off
|
||||
lg %r15,__LC_RESTART_STACK
|
||||
xc STACK_FRAME_OVERHEAD(__PT_SIZE,%r15),STACK_FRAME_OVERHEAD(%r15)
|
||||
stmg %r0,%r14,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
|
||||
@ -638,7 +641,7 @@ ENTRY(restart_int_handler)
|
||||
xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
|
||||
lg %r1,__LC_RESTART_FN # load fn, parm & source cpu
|
||||
lg %r2,__LC_RESTART_DATA
|
||||
lg %r3,__LC_RESTART_SOURCE
|
||||
lgf %r3,__LC_RESTART_SOURCE
|
||||
ltgr %r3,%r3 # test source cpu address
|
||||
jm 1f # negative -> skip source stop
|
||||
0: sigp %r4,%r3,SIGP_SENSE # sigp sense to source cpu
|
||||
|
@ -179,8 +179,6 @@ static inline int __diag308(unsigned long subcode, void *addr)
|
||||
|
||||
int diag308(unsigned long subcode, void *addr)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_KASAN))
|
||||
__arch_local_irq_stosm(0x04); /* enable DAT */
|
||||
diag_stat_inc(DIAG_STAT_X308);
|
||||
return __diag308(subcode, addr);
|
||||
}
|
||||
@ -1843,7 +1841,6 @@ static struct kobj_attribute on_restart_attr = __ATTR_RW(on_restart);
|
||||
|
||||
static void __do_restart(void *ignore)
|
||||
{
|
||||
__arch_local_irq_stosm(0x04); /* enable DAT */
|
||||
smp_send_stop();
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
crash_kexec(NULL);
|
||||
|
@ -263,7 +263,6 @@ static void __do_machine_kexec(void *data)
|
||||
*/
|
||||
static void __machine_kexec(void *data)
|
||||
{
|
||||
__arch_local_irq_stosm(0x04); /* enable DAT */
|
||||
pfault_fini();
|
||||
tracing_off();
|
||||
debug_locks_off();
|
||||
|
@ -465,7 +465,7 @@ static void __init setup_lowcore_dat_off(void)
|
||||
lc->restart_stack = (unsigned long) restart_stack;
|
||||
lc->restart_fn = (unsigned long) do_restart;
|
||||
lc->restart_data = 0;
|
||||
lc->restart_source = -1UL;
|
||||
lc->restart_source = -1U;
|
||||
|
||||
mcck_stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE);
|
||||
if (!mcck_stack)
|
||||
@ -494,12 +494,19 @@ static void __init setup_lowcore_dat_off(void)
|
||||
|
||||
static void __init setup_lowcore_dat_on(void)
|
||||
{
|
||||
struct lowcore *lc = lowcore_ptr[0];
|
||||
|
||||
__ctl_clear_bit(0, 28);
|
||||
S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT;
|
||||
S390_lowcore.svc_new_psw.mask |= PSW_MASK_DAT;
|
||||
S390_lowcore.program_new_psw.mask |= PSW_MASK_DAT;
|
||||
S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT;
|
||||
__ctl_store(S390_lowcore.cregs_save_area, 0, 15);
|
||||
__ctl_set_bit(0, 28);
|
||||
mem_assign_absolute(S390_lowcore.restart_flags, RESTART_FLAG_CTLREGS);
|
||||
mem_assign_absolute(S390_lowcore.program_new_psw, lc->program_new_psw);
|
||||
memcpy_absolute(&S390_lowcore.cregs_save_area, lc->cregs_save_area,
|
||||
sizeof(S390_lowcore.cregs_save_area));
|
||||
}
|
||||
|
||||
static struct resource code_resource = {
|
||||
|
@ -252,6 +252,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
|
||||
cpumask_set_cpu(cpu, &init_mm.context.cpu_attach_mask);
|
||||
cpumask_set_cpu(cpu, mm_cpumask(&init_mm));
|
||||
lc->cpu_nr = cpu;
|
||||
lc->restart_flags = RESTART_FLAG_CTLREGS;
|
||||
lc->spinlock_lockval = arch_spin_lockval(cpu);
|
||||
lc->spinlock_index = 0;
|
||||
lc->percpu_offset = __per_cpu_offset[cpu];
|
||||
@ -297,7 +298,7 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data)
|
||||
lc->restart_stack = lc->nodat_stack;
|
||||
lc->restart_fn = (unsigned long) func;
|
||||
lc->restart_data = (unsigned long) data;
|
||||
lc->restart_source = -1UL;
|
||||
lc->restart_source = -1U;
|
||||
pcpu_sigp_retry(pcpu, SIGP_RESTART, 0);
|
||||
}
|
||||
|
||||
@ -311,12 +312,12 @@ static void __pcpu_delegate(pcpu_delegate_fn *func, void *data)
|
||||
func(data); /* should not return */
|
||||
}
|
||||
|
||||
static void __no_sanitize_address pcpu_delegate(struct pcpu *pcpu,
|
||||
pcpu_delegate_fn *func,
|
||||
void *data, unsigned long stack)
|
||||
static void pcpu_delegate(struct pcpu *pcpu,
|
||||
pcpu_delegate_fn *func,
|
||||
void *data, unsigned long stack)
|
||||
{
|
||||
struct lowcore *lc = lowcore_ptr[pcpu - pcpu_devices];
|
||||
unsigned long source_cpu = stap();
|
||||
unsigned int source_cpu = stap();
|
||||
|
||||
__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT);
|
||||
if (pcpu->address == source_cpu) {
|
||||
@ -569,6 +570,9 @@ static void smp_ctl_bit_callback(void *info)
|
||||
__ctl_load(cregs, 0, 15);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(ctl_lock);
|
||||
static unsigned long ctlreg;
|
||||
|
||||
/*
|
||||
* Set a bit in a control register of all cpus
|
||||
*/
|
||||
@ -576,6 +580,11 @@ void smp_ctl_set_bit(int cr, int bit)
|
||||
{
|
||||
struct ec_creg_mask_parms parms = { 1UL << bit, -1UL, cr };
|
||||
|
||||
spin_lock(&ctl_lock);
|
||||
memcpy_absolute(&ctlreg, &S390_lowcore.cregs_save_area[cr], sizeof(ctlreg));
|
||||
__set_bit(bit, &ctlreg);
|
||||
memcpy_absolute(&S390_lowcore.cregs_save_area[cr], &ctlreg, sizeof(ctlreg));
|
||||
spin_unlock(&ctl_lock);
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_ctl_set_bit);
|
||||
@ -587,6 +596,11 @@ void smp_ctl_clear_bit(int cr, int bit)
|
||||
{
|
||||
struct ec_creg_mask_parms parms = { 0, ~(1UL << bit), cr };
|
||||
|
||||
spin_lock(&ctl_lock);
|
||||
memcpy_absolute(&ctlreg, &S390_lowcore.cregs_save_area[cr], sizeof(ctlreg));
|
||||
__clear_bit(bit, &ctlreg);
|
||||
memcpy_absolute(&S390_lowcore.cregs_save_area[cr], &ctlreg, sizeof(ctlreg));
|
||||
spin_unlock(&ctl_lock);
|
||||
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_ctl_clear_bit);
|
||||
@ -895,14 +909,13 @@ static void smp_init_secondary(void)
|
||||
/*
|
||||
* Activate a secondary processor.
|
||||
*/
|
||||
static void __no_sanitize_address smp_start_secondary(void *cpuvoid)
|
||||
static void smp_start_secondary(void *cpuvoid)
|
||||
{
|
||||
S390_lowcore.restart_stack = (unsigned long) restart_stack;
|
||||
S390_lowcore.restart_fn = (unsigned long) do_restart;
|
||||
S390_lowcore.restart_data = 0;
|
||||
S390_lowcore.restart_source = -1UL;
|
||||
__ctl_load(S390_lowcore.cregs_save_area, 0, 15);
|
||||
__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_DAT);
|
||||
S390_lowcore.restart_source = -1U;
|
||||
S390_lowcore.restart_flags = 0;
|
||||
call_on_stack_noreturn(smp_init_secondary, S390_lowcore.kernel_stack);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user