s390/ctlreg: add system_ctl_load()
authorHeiko Carstens <hca@linux.ibm.com>
Mon, 11 Sep 2023 19:40:08 +0000 (21:40 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 19 Sep 2023 11:26:57 +0000 (13:26 +0200)
Add system_ctl_load() which can be used to load a value to a control
register system wide.

Refactor system_ctl_set_clear_bit() so it can handle all different
request types, and also rename it to system_ctlreg_modify()

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>
arch/s390/include/asm/ctlreg.h
arch/s390/kernel/ctlreg.c

index 1f25601d75a0610d245d085b4f302085d54b848b..6582b1b9b97b7127e021d09ef15ed6214f7d23e3 100644 (file)
@@ -114,17 +114,28 @@ struct lowcore;
 
 void system_ctlreg_lock(void);
 void system_ctlreg_unlock(void);
-void system_ctl_set_clear_bit(unsigned int cr, unsigned int bit, bool set);
 void system_ctlreg_init_save_area(struct lowcore *lc);
+void system_ctlreg_modify(unsigned int cr, unsigned long data, int request);
+
+enum {
+       CTLREG_SET_BIT,
+       CTLREG_CLEAR_BIT,
+       CTLREG_LOAD,
+};
 
 static inline void system_ctl_set_bit(unsigned int cr, unsigned int bit)
 {
-       system_ctl_set_clear_bit(cr, bit, true);
+       system_ctlreg_modify(cr, bit, CTLREG_SET_BIT);
 }
 
 static inline void system_ctl_clear_bit(unsigned int cr, unsigned int bit)
 {
-       system_ctl_set_clear_bit(cr, bit, false);
+       system_ctlreg_modify(cr, bit, CTLREG_CLEAR_BIT);
+}
+
+static inline void system_ctl_load(unsigned int cr, struct ctlreg *reg)
+{
+       system_ctlreg_modify(cr, reg->val, CTLREG_LOAD);
 }
 
 union ctlreg0 {
index 27ba8db1d0381deb389bd59c98ef51d9024514ee..8cc26cf2c64ac34a791e94c63489497aaaf3882d 100644 (file)
@@ -44,24 +44,30 @@ void __init system_ctlreg_init_save_area(struct lowcore *lc)
        system_ctlreg_area_init = true;
 }
 
-struct ctl_bit_parms {
-       unsigned long orval;
+struct ctlreg_parms {
        unsigned long andval;
+       unsigned long orval;
+       unsigned long val;
+       int request;
        int cr;
 };
 
-static void ctl_bit_callback(void *info)
+static void ctlreg_callback(void *info)
 {
-       struct ctl_bit_parms *pp = info;
+       struct ctlreg_parms *pp = info;
        struct ctlreg regs[16];
 
        __local_ctl_store(0, 15, regs);
-       regs[pp->cr].val &= pp->andval;
-       regs[pp->cr].val |= pp->orval;
+       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_ctl_bit_update(void *info)
+static void system_ctlreg_update(void *info)
 {
        unsigned long flags;
 
@@ -71,30 +77,45 @@ static void system_ctl_bit_update(void *info)
                 * since not everything might be setup.
                 */
                local_irq_save(flags);
-               ctl_bit_callback(info);
+               ctlreg_callback(info);
                local_irq_restore(flags);
        } else {
-               on_each_cpu(ctl_bit_callback, info, 1);
+               on_each_cpu(ctlreg_callback, info, 1);
        }
 }
 
-void system_ctl_set_clear_bit(unsigned int cr, unsigned int bit, bool set)
+void system_ctlreg_modify(unsigned int cr, unsigned long data, int request)
 {
-       struct ctl_bit_parms pp = { .cr = cr, };
+       struct ctlreg_parms pp = { .cr = cr, .request = request, };
        struct lowcore *abs_lc;
 
-       pp.orval  = set ? 1UL << bit : 0;
-       pp.andval = set ? -1UL : ~(1UL << bit);
+       switch (request) {
+       case CTLREG_SET_BIT:
+               pp.orval  = 1UL << data;
+               pp.andval = -1UL;
+               break;
+       case CTLREG_CLEAR_BIT:
+               pp.orval  = 0;
+               pp.andval = ~(1UL << data);
+               break;
+       case CTLREG_LOAD:
+               pp.val = data;
+               break;
+       }
        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;
+               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_ctl_bit_update(&pp);
+               system_ctlreg_update(&pp);
                system_ctlreg_unlock();
        } else {
-               system_ctl_bit_update(&pp);
+               system_ctlreg_update(&pp);
        }
 }
-EXPORT_SYMBOL(system_ctl_set_clear_bit);
+EXPORT_SYMBOL(system_ctlreg_modify);