1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Request power readings for resources in a computing environment via 4 * diag 0x324. diag 0x324 stores the power readings in the power information 5 * block (pib). 6 * 7 * Copyright IBM Corp. 2024 8 */ 9 10 #define pr_fmt(fmt) "diag324: " fmt 11 #include <linux/fs.h> 12 #include <linux/gfp.h> 13 #include <linux/ioctl.h> 14 #include <linux/jiffies.h> 15 #include <linux/kernel.h> 16 #include <linux/ktime.h> 17 #include <linux/string.h> 18 #include <linux/slab.h> 19 #include <linux/timer.h> 20 #include <linux/types.h> 21 #include <linux/uaccess.h> 22 #include <linux/vmalloc.h> 23 24 #include <asm/diag.h> 25 #include <asm/sclp.h> 26 #include <asm/timex.h> 27 #include <uapi/asm/diag.h> 28 #include "diag_ioctl.h" 29 30 enum subcode { 31 DIAG324_SUBC_0 = 0, 32 DIAG324_SUBC_1 = 1, 33 DIAG324_SUBC_2 = 2, 34 }; 35 36 enum retcode { 37 DIAG324_RET_SUCCESS = 0x0001, 38 DIAG324_RET_SUBC_NOTAVAIL = 0x0103, 39 DIAG324_RET_INSUFFICIENT_SIZE = 0x0104, 40 DIAG324_RET_READING_UNAVAILABLE = 0x0105, 41 }; 42 43 union diag324_response { 44 u64 response; 45 struct { 46 u64 installed : 32; 47 u64 : 16; 48 u64 rc : 16; 49 } sc0; 50 struct { 51 u64 format : 16; 52 u64 : 16; 53 u64 pib_len : 16; 54 u64 rc : 16; 55 } sc1; 56 struct { 57 u64 : 48; 58 u64 rc : 16; 59 } sc2; 60 }; 61 62 union diag324_request { 63 u64 request; 64 struct { 65 u64 : 32; 66 u64 allocated : 16; 67 u64 : 12; 68 u64 sc : 4; 69 } sc2; 70 }; 71 72 struct pib { 73 u32 : 8; 74 u32 num : 8; 75 u32 len : 16; 76 u32 : 24; 77 u32 hlen : 8; 78 u64 : 64; 79 u64 intv; 80 u8 r[]; 81 } __packed; 82 83 struct pibdata { 84 struct pib *pib; 85 ktime_t expire; 86 u64 sequence; 87 size_t len; 88 int rc; 89 }; 90 91 static DEFINE_MUTEX(pibmutex); 92 static struct pibdata pibdata; 93 94 #define PIBWORK_DELAY (5 * NSEC_PER_SEC) 95 96 static void pibwork_handler(struct work_struct *work); 97 static DECLARE_DELAYED_WORK(pibwork, pibwork_handler); 98 99 static unsigned long diag324(unsigned long subcode, void *addr) 100 { 101 union register_pair rp = { .even = (unsigned long)addr }; 102 103 diag_stat_inc(DIAG_STAT_X324); 104 asm volatile("diag %[rp],%[subcode],0x324\n" 105 : [rp] "+d" (rp.pair) 106 : [subcode] "d" (subcode) 107 : "memory"); 108 return rp.odd; 109 } 110 111 static void pibwork_handler(struct work_struct *work) 112 { 113 struct pibdata *data = &pibdata; 114 ktime_t timedout; 115 116 mutex_lock(&pibmutex); 117 timedout = ktime_add_ns(data->expire, PIBWORK_DELAY); 118 if (ktime_before(ktime_get(), timedout)) { 119 mod_delayed_work(system_wq, &pibwork, nsecs_to_jiffies(PIBWORK_DELAY)); 120 goto out; 121 } 122 vfree(data->pib); 123 data->pib = NULL; 124 out: 125 mutex_unlock(&pibmutex); 126 } 127 128 static void pib_update(struct pibdata *data) 129 { 130 union diag324_request req = { .sc2.sc = DIAG324_SUBC_2, .sc2.allocated = data->len }; 131 union diag324_response res; 132 int rc; 133 134 memset(data->pib, 0, data->len); 135 res.response = diag324(req.request, data->pib); 136 switch (res.sc2.rc) { 137 case DIAG324_RET_SUCCESS: 138 rc = 0; 139 break; 140 case DIAG324_RET_SUBC_NOTAVAIL: 141 rc = -ENOENT; 142 break; 143 case DIAG324_RET_INSUFFICIENT_SIZE: 144 rc = -EMSGSIZE; 145 break; 146 case DIAG324_RET_READING_UNAVAILABLE: 147 rc = -EBUSY; 148 break; 149 default: 150 rc = -EINVAL; 151 } 152 data->rc = rc; 153 } 154 155 long diag324_pibbuf(unsigned long arg) 156 { 157 struct diag324_pib __user *udata = (struct diag324_pib __user *)arg; 158 struct pibdata *data = &pibdata; 159 static bool first = true; 160 u64 address; 161 int rc; 162 163 if (!data->len) 164 return -EOPNOTSUPP; 165 if (get_user(address, &udata->address)) 166 return -EFAULT; 167 mutex_lock(&pibmutex); 168 rc = -ENOMEM; 169 if (!data->pib) 170 data->pib = vmalloc(data->len); 171 if (!data->pib) 172 goto out; 173 if (first || ktime_after(ktime_get(), data->expire)) { 174 pib_update(data); 175 data->sequence++; 176 data->expire = ktime_add_ns(ktime_get(), tod_to_ns(data->pib->intv)); 177 mod_delayed_work(system_wq, &pibwork, nsecs_to_jiffies(PIBWORK_DELAY)); 178 first = false; 179 } 180 rc = data->rc; 181 if (rc != 0 && rc != -EBUSY) 182 goto out; 183 rc = copy_to_user((void __user *)address, data->pib, data->pib->len); 184 rc |= put_user(data->sequence, &udata->sequence); 185 if (rc) 186 rc = -EFAULT; 187 out: 188 mutex_unlock(&pibmutex); 189 return rc; 190 } 191 192 long diag324_piblen(unsigned long arg) 193 { 194 struct pibdata *data = &pibdata; 195 196 if (!data->len) 197 return -EOPNOTSUPP; 198 if (put_user(data->len, (size_t __user *)arg)) 199 return -EFAULT; 200 return 0; 201 } 202 203 static int __init diag324_init(void) 204 { 205 union diag324_response res; 206 unsigned long installed; 207 208 if (!sclp.has_diag324) 209 return -EOPNOTSUPP; 210 res.response = diag324(DIAG324_SUBC_0, NULL); 211 if (res.sc0.rc != DIAG324_RET_SUCCESS) 212 return -EOPNOTSUPP; 213 installed = res.response; 214 if (!test_bit_inv(DIAG324_SUBC_1, &installed)) 215 return -EOPNOTSUPP; 216 if (!test_bit_inv(DIAG324_SUBC_2, &installed)) 217 return -EOPNOTSUPP; 218 res.response = diag324(DIAG324_SUBC_1, NULL); 219 if (res.sc1.rc != DIAG324_RET_SUCCESS) 220 return -EOPNOTSUPP; 221 pibdata.len = res.sc1.pib_len; 222 return 0; 223 } 224 device_initcall(diag324_init); 225