FILE
ctlreg.c
File preview with syntax highlighting.
linux-6.19.14/arch/s390/kernel/ctlreg.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright IBM Corp. 1999, 2023 4 */ 5 6#include <linux/irqflags.h> 7#include <linux/spinlock.h> 8#include <linux/export.h> 9#include <linux/kernel.h> 10#include <linux/init.h> 11#include <linux/smp.h> 12#include <linux/cache.h> 13#include <asm/abs_lowcore.h> 14#include <asm/ctlreg.h> 15 16/* 17 * ctl_lock guards access to global control register contents which 18 * are kept in the control register save area within absolute lowcore 19 * at physical address zero. 20 */ 21static DEFINE_SPINLOCK(system_ctl_lock); 22 23void system_ctlreg_lock(void) 24 __acquires(&system_ctl_lock) 25{ 26 spin_lock(&system_ctl_lock); 27} 28 29void system_ctlreg_unlock(void) 30 __releases(&system_ctl_lock) 31{ 32 spin_unlock(&system_ctl_lock); 33} 34 35static bool system_ctlreg_area_init __ro_after_init; 36 37void __init system_ctlreg_init_save_area(struct lowcore *lc) 38{ 39 struct lowcore *abs_lc; 40 41 abs_lc = get_abs_lowcore(); 42 __local_ctl_store(0, 15, lc->cregs_save_area); 43 __local_ctl_store(0, 15, abs_lc->cregs_save_area); 44 put_abs_lowcore(abs_lc); 45 system_ctlreg_area_init = true; 46} 47 48struct ctlreg_parms { 49 unsigned long andval; 50 unsigned long orval; 51 unsigned long val; 52 int request; 53 int cr; 54}; 55 56static void ctlreg_callback(void *info) 57{ 58 struct ctlreg_parms *pp = info; 59 struct ctlreg regs[16]; 60 61 __local_ctl_store(0, 15, regs); 62 if (pp->request == CTLREG_LOAD) { 63 regs[pp->cr].val = pp->val; 64 } else { 65 regs[pp->cr].val &= pp->andval; 66 regs[pp->cr].val |= pp->orval; 67 } 68 __local_ctl_load(0, 15, regs); 69} 70 71static void system_ctlreg_update(void *info) 72{ 73 unsigned long flags; 74 75 if (system_state == SYSTEM_BOOTING) { 76 /* 77 * For very early calls do not call on_each_cpu() 78 * since not everything might be setup. 79 */ 80 local_irq_save(flags); 81 ctlreg_callback(info); 82 local_irq_restore(flags); 83 } else { 84 on_each_cpu(ctlreg_callback, info, 1); 85 } 86} 87 88void system_ctlreg_modify(unsigned int cr, unsigned long data, int request) 89{ 90 struct ctlreg_parms pp = { .cr = cr, .request = request, }; 91 struct lowcore *abs_lc; 92 93 switch (request) { 94 case CTLREG_SET_BIT: 95 pp.orval = 1UL << data; 96 pp.andval = -1UL; 97 break; 98 case CTLREG_CLEAR_BIT: 99 pp.orval = 0; 100 pp.andval = ~(1UL << data); 101 break; 102 case CTLREG_LOAD: 103 pp.val = data; 104 break; 105 } 106 if (system_ctlreg_area_init) { 107 system_ctlreg_lock(); 108 abs_lc = get_abs_lowcore(); 109 if (request == CTLREG_LOAD) { 110 abs_lc->cregs_save_area[cr].val = pp.val; 111 } else { 112 abs_lc->cregs_save_area[cr].val &= pp.andval; 113 abs_lc->cregs_save_area[cr].val |= pp.orval; 114 } 115 put_abs_lowcore(abs_lc); 116 system_ctlreg_update(&pp); 117 system_ctlreg_unlock(); 118 } else { 119 system_ctlreg_update(&pp); 120 } 121} 122EXPORT_SYMBOL(system_ctlreg_modify);
~/
Read-only file preview.