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