1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright IBM Corp. 1999, 2023 4 */ 5 6 #include <linux/spinlock.h> 7 #include <linux/init.h> 8 #include <linux/smp.h> 9 #include <asm/abs_lowcore.h> 10 #include <asm/ctlreg.h> 11 12 /* 13 * ctl_lock guards access to global control register contents which 14 * are kept in the control register save area within absolute lowcore 15 * at physical address zero. 16 */ 17 static DEFINE_SPINLOCK(system_ctl_lock); 18 19 void system_ctlreg_lock(void) 20 __acquires(&system_ctl_lock) 21 { 22 spin_lock(&system_ctl_lock); 23 } 24 25 void system_ctlreg_unlock(void) 26 __releases(&system_ctl_lock) 27 { 28 spin_unlock(&system_ctl_lock); 29 } 30 31 void __init system_ctlreg_init_save_area(struct lowcore *lc) 32 { 33 struct lowcore *abs_lc; 34 35 abs_lc = get_abs_lowcore(); 36 __local_ctl_store(0, 15, lc->cregs_save_area); 37 __local_ctl_store(0, 15, abs_lc->cregs_save_area); 38 put_abs_lowcore(abs_lc); 39 } 40 41 struct ctl_bit_parms { 42 unsigned long orval; 43 unsigned long andval; 44 int cr; 45 }; 46 47 static void ctl_bit_callback(void *info) 48 { 49 struct ctl_bit_parms *pp = info; 50 struct ctlreg regs[16]; 51 52 __local_ctl_store(0, 15, regs); 53 regs[pp->cr].val &= pp->andval; 54 regs[pp->cr].val |= pp->orval; 55 __local_ctl_load(0, 15, regs); 56 } 57 58 void system_ctl_set_clear_bit(unsigned int cr, unsigned int bit, bool set) 59 { 60 struct ctl_bit_parms pp = { .cr = cr, }; 61 struct lowcore *abs_lc; 62 63 pp.orval = set ? 1UL << bit : 0; 64 pp.andval = set ? -1UL : ~(1UL << bit); 65 system_ctlreg_lock(); 66 abs_lc = get_abs_lowcore(); 67 abs_lc->cregs_save_area[cr].val &= pp.andval; 68 abs_lc->cregs_save_area[cr].val |= pp.orval; 69 put_abs_lowcore(abs_lc); 70 on_each_cpu(ctl_bit_callback, &pp, 1); 71 system_ctlreg_unlock(); 72 } 73 EXPORT_SYMBOL(system_ctl_set_clear_bit); 74