s390/ctlreg: move control register code to separate file

Control register handling has nothing to do with low level SMP code.
Move it to a separate file.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
Heiko Carstens 2023-09-11 21:39:55 +02:00 committed by Vasily Gorbik
parent aa36d433b7
commit 0c4d01f395
10 changed files with 75 additions and 56 deletions

View File

@ -2,6 +2,7 @@
#include <linux/sched/task.h>
#include <linux/pgtable.h>
#include <linux/kasan.h>
#include <asm/ctl_reg.h>
#include <asm/pgalloc.h>
#include <asm/facility.h>
#include <asm/sections.h>

View File

@ -74,16 +74,18 @@ static __always_inline void __ctl_clear_bit(unsigned int cr, unsigned int bit)
__ctl_load(reg, cr, cr);
}
void smp_ctl_set_clear_bit(int cr, int bit, bool set);
void ctlreg_lock(void);
void ctlreg_unlock(void);
void ctl_set_clear_bit(int cr, int bit, bool set);
static inline void ctl_set_bit(int cr, int bit)
{
smp_ctl_set_clear_bit(cr, bit, true);
ctl_set_clear_bit(cr, bit, true);
}
static inline void ctl_clear_bit(int cr, int bit)
{
smp_ctl_set_clear_bit(cr, bit, false);
ctl_set_clear_bit(cr, bit, false);
}
union ctlreg0 {

View File

@ -10,7 +10,6 @@
#define _ASM_S390_FPU_INTERNAL_H
#include <linux/string.h>
#include <asm/ctl_reg.h>
#include <asm/fpu/types.h>
static inline void save_vx_regs(__vector128 *vxrs)

View File

@ -15,7 +15,6 @@
*/
#include <asm/asm-extable.h>
#include <asm/processor.h>
#include <asm/ctl_reg.h>
#include <asm/extable.h>
#include <asm/facility.h>
#include <asm-generic/access_ok.h>

View File

@ -37,7 +37,7 @@ CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls
obj-y := head64.o traps.o time.o process.o earlypgm.o early.o setup.o idle.o vtime.o
obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o cpufeature.o
obj-y += sysinfo.o lgr.o os_info.o
obj-y += sysinfo.o lgr.o os_info.o ctlreg.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
obj-y += entry.o reipl.o kdebugfs.o alternative.o
obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o

62
arch/s390/kernel/ctlreg.c Normal file
View File

@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright IBM Corp. 1999, 2023
*/
#include <linux/spinlock.h>
#include <linux/smp.h>
#include <asm/abs_lowcore.h>
#include <asm/ctl_reg.h>
/*
* ctl_lock guards access to global control register contents which
* are kept in the control register save area within absolute lowcore
* at physical address zero.
*/
static DEFINE_SPINLOCK(ctl_lock);
void ctlreg_lock(void)
__acquires(&ctl_lock)
{
spin_lock(&ctl_lock);
}
void ctlreg_unlock(void)
__releases(&ctl_lock)
{
spin_unlock(&ctl_lock);
}
struct ctl_bit_parms {
unsigned long orval;
unsigned long andval;
int cr;
};
static void ctl_bit_callback(void *info)
{
struct ctl_bit_parms *pp = info;
unsigned long regs[16];
__ctl_store(regs, 0, 15);
regs[pp->cr] &= pp->andval;
regs[pp->cr] |= pp->orval;
__ctl_load(regs, 0, 15);
}
void ctl_set_clear_bit(int cr, int bit, bool set)
{
struct ctl_bit_parms pp = { .cr = cr, };
struct lowcore *abs_lc;
pp.orval = set ? 1UL << bit : 0;
pp.andval = set ? -1UL : ~(1UL << bit);
ctlreg_lock();
abs_lc = get_abs_lowcore();
abs_lc->cregs_save_area[cr] &= pp.andval;
abs_lc->cregs_save_area[cr] |= pp.orval;
put_abs_lowcore(abs_lc);
on_each_cpu(ctl_bit_callback, &pp, 1);
ctlreg_unlock();
}
EXPORT_SYMBOL(ctl_set_clear_bit);

View File

@ -37,6 +37,7 @@
#include <linux/crash_dump.h>
#include <linux/kprobes.h>
#include <asm/asm-offsets.h>
#include <asm/ctl_reg.h>
#include <asm/pfault.h>
#include <asm/diag.h>
#include <asm/switch_to.h>
@ -567,54 +568,6 @@ void arch_irq_work_raise(void)
}
#endif
/*
* parameter area for the set/clear control bit callbacks
*/
struct ec_creg_mask_parms {
unsigned long orval;
unsigned long andval;
int cr;
};
/*
* callback for setting/clearing control bits
*/
static void smp_ctl_bit_callback(void *info)
{
struct ec_creg_mask_parms *pp = info;
unsigned long cregs[16];
__ctl_store(cregs, 0, 15);
cregs[pp->cr] = (cregs[pp->cr] & pp->andval) | pp->orval;
__ctl_load(cregs, 0, 15);
}
static DEFINE_SPINLOCK(ctl_lock);
void smp_ctl_set_clear_bit(int cr, int bit, bool set)
{
struct ec_creg_mask_parms parms = { .cr = cr, };
struct lowcore *abs_lc;
u64 ctlreg;
if (set) {
parms.orval = 1UL << bit;
parms.andval = -1UL;
} else {
parms.orval = 0;
parms.andval = ~(1UL << bit);
}
spin_lock(&ctl_lock);
abs_lc = get_abs_lowcore();
ctlreg = abs_lc->cregs_save_area[cr];
ctlreg = (ctlreg & parms.andval) | parms.orval;
abs_lc->cregs_save_area[cr] = ctlreg;
put_abs_lowcore(abs_lc);
on_each_cpu(smp_ctl_bit_callback, &parms, 1);
spin_unlock(&ctl_lock);
}
EXPORT_SYMBOL(smp_ctl_set_clear_bit);
#ifdef CONFIG_CRASH_DUMP
int smp_store_status(int cpu)
@ -935,14 +888,14 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
* Make sure global control register contents do not change
* until new CPU has initialized control registers.
*/
spin_lock(&ctl_lock);
ctlreg_lock();
pcpu_prepare_secondary(pcpu, cpu);
pcpu_attach_task(pcpu, tidle);
pcpu_start_fn(pcpu, smp_start_secondary, NULL);
/* Wait until cpu puts itself in the online & active maps */
while (!cpu_online(cpu))
cpu_relax();
spin_unlock(&ctl_lock);
ctlreg_unlock();
return 0;
}

View File

@ -12,6 +12,7 @@
#include <linux/export.h>
#include <linux/mm.h>
#include <asm/asm-extable.h>
#include <asm/ctl_reg.h>
#ifdef CONFIG_DEBUG_ENTRY
void debug_user_asce(int exit)

View File

@ -14,6 +14,7 @@
#include <linux/sort.h>
#include <asm/cacheflush.h>
#include <asm/nospec-branch.h>
#include <asm/ctl_reg.h>
#include <asm/pgalloc.h>
#include <asm/setup.h>
#include <asm/tlbflush.h>

View File

@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <asm/processor.h>
#include <asm/ctl_reg.h>
#include <asm/lowcore.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>