1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

s390/ctlreg: allow to call system_ctl_set/clear_bit() early

Allow to call system_ctl_set_bit() and system_clt_clear_bit() early, so
that users do not have to take care when the control register save area
has been initialized. Users are supposed to use system_ctl_set_bit() and
system:clt_clear_bit() for all control register changes which are supposed
to be seen globally.

Depending on the system state such calls will change:

- local control register contents
- save area and local control register contents
- save area and global control register contents

Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
Heiko Carstens 2023-09-11 21:40:06 +02:00 committed by Vasily Gorbik
parent d11d5c8c84
commit cce2c8606f

View file

@ -3,9 +3,12 @@
* Copyright IBM Corp. 1999, 2023
*/
#include <linux/irqflags.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/cache.h>
#include <asm/abs_lowcore.h>
#include <asm/ctlreg.h>
@ -28,6 +31,8 @@ void system_ctlreg_unlock(void)
spin_unlock(&system_ctl_lock);
}
static bool system_ctlreg_area_init __ro_after_init;
void __init system_ctlreg_init_save_area(struct lowcore *lc)
{
struct lowcore *abs_lc;
@ -36,6 +41,7 @@ void __init system_ctlreg_init_save_area(struct lowcore *lc)
__local_ctl_store(0, 15, lc->cregs_save_area);
__local_ctl_store(0, 15, abs_lc->cregs_save_area);
put_abs_lowcore(abs_lc);
system_ctlreg_area_init = true;
}
struct ctl_bit_parms {
@ -55,6 +61,23 @@ static void ctl_bit_callback(void *info)
__local_ctl_load(0, 15, regs);
}
static void system_ctl_bit_update(void *info)
{
unsigned long flags;
if (system_state == SYSTEM_BOOTING) {
/*
* For very early calls do not call on_each_cpu()
* since not everything might be setup.
*/
local_irq_save(flags);
ctl_bit_callback(info);
local_irq_restore(flags);
} else {
on_each_cpu(ctl_bit_callback, info, 1);
}
}
void system_ctl_set_clear_bit(unsigned int cr, unsigned int bit, bool set)
{
struct ctl_bit_parms pp = { .cr = cr, };
@ -62,12 +85,16 @@ void system_ctl_set_clear_bit(unsigned int cr, unsigned int bit, bool set)
pp.orval = set ? 1UL << bit : 0;
pp.andval = set ? -1UL : ~(1UL << bit);
system_ctlreg_lock();
abs_lc = get_abs_lowcore();
abs_lc->cregs_save_area[cr].val &= pp.andval;
abs_lc->cregs_save_area[cr].val |= pp.orval;
put_abs_lowcore(abs_lc);
on_each_cpu(ctl_bit_callback, &pp, 1);
system_ctlreg_unlock();
if (system_ctlreg_area_init) {
system_ctlreg_lock();
abs_lc = get_abs_lowcore();
abs_lc->cregs_save_area[cr].val &= pp.andval;
abs_lc->cregs_save_area[cr].val |= pp.orval;
put_abs_lowcore(abs_lc);
system_ctl_bit_update(&pp);
system_ctlreg_unlock();
} else {
system_ctl_bit_update(&pp);
}
}
EXPORT_SYMBOL(system_ctl_set_clear_bit);