// SPDX-License-Identifier: GPL-2.0
/*
* Copyright IBM Corp . 1999 , 2023
*/
#include <linux/irqflags.h>
#include <linux/spinlock.h>
#include <linux/export.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>
/*
* 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(system_ctl_lock);
void system_ctlreg_lock(void )
__acquires(&system_ctl_lock)
{
spin_lock(&system_ctl_lock);
}
void system_ctlreg_unlock(void )
__releases(&system_ctl_lock)
{
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;
abs_lc = get_abs_lowcore();
__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 ctlreg_parms {
unsigned long andval;
unsigned long orval;
unsigned long val;
int request;
int cr;
};
static void ctlreg_callback(void *info)
{
struct ctlreg_parms *pp = info;
struct ctlreg regs[16 ];
__local_ctl_store(0 , 15 , regs);
if (pp->request == CTLREG_LOAD) {
regs[pp->cr].val = pp->val;
} else {
regs[pp->cr].val &= pp->andval;
regs[pp->cr].val |= pp->orval;
}
__local_ctl_load(0 , 15 , regs);
}
static void system_ctlreg_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);
ctlreg_callback(info);
local_irq_restore(flags);
} else {
on_each_cpu(ctlreg_callback, info, 1 );
}
}
void system_ctlreg_modify(unsigned int cr, unsigned long data, int request)
{
struct ctlreg_parms pp = { .cr = cr, .request = request, };
struct lowcore *abs_lc;
switch (request) {
case CTLREG_SET_BIT:
pp.orval = 1 UL << data;
pp.andval = -1 UL;
break ;
case CTLREG_CLEAR_BIT:
pp.orval = 0 ;
pp.andval = ~(1 UL << data);
break ;
case CTLREG_LOAD:
pp.val = data;
break ;
}
if (system_ctlreg_area_init) {
system_ctlreg_lock();
abs_lc = get_abs_lowcore();
if (request == CTLREG_LOAD) {
abs_lc->cregs_save_area[cr].val = pp.val;
} else {
abs_lc->cregs_save_area[cr].val &= pp.andval;
abs_lc->cregs_save_area[cr].val |= pp.orval;
}
put_abs_lowcore(abs_lc);
system_ctlreg_update(&pp);
system_ctlreg_unlock();
} else {
system_ctlreg_update(&pp);
}
}
EXPORT_SYMBOL(system_ctlreg_modify);
Messung V0.5 in Prozent C=97 H=93 G=94
¤ Dauer der Verarbeitung: 0.8 Sekunden
(vorverarbeitet am 2026-09-30)
¤
*© Formatika GbR, Deutschland