1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Request memory topology information via diag0x310. 4 * 5 * Copyright IBM Corp. 2025 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/types.h> 10 #include <linux/uaccess.h> 11 #include <linux/vmalloc.h> 12 #include <asm/diag.h> 13 #include <asm/sclp.h> 14 #include <uapi/asm/diag.h> 15 #include "diag_ioctl.h" 16 17 #define DIAG310_LEVELMIN 1 18 #define DIAG310_LEVELMAX 6 19 20 enum diag310_sc { 21 DIAG310_SUBC_0 = 0, 22 DIAG310_SUBC_1 = 1, 23 DIAG310_SUBC_4 = 4, 24 DIAG310_SUBC_5 = 5 25 }; 26 27 enum diag310_retcode { 28 DIAG310_RET_SUCCESS = 0x0001, 29 DIAG310_RET_BUSY = 0x0101, 30 DIAG310_RET_OPNOTSUPP = 0x0102, 31 DIAG310_RET_SC4_INVAL = 0x0401, 32 DIAG310_RET_SC4_NODATA = 0x0402, 33 DIAG310_RET_SC5_INVAL = 0x0501, 34 DIAG310_RET_SC5_NODATA = 0x0502, 35 DIAG310_RET_SC5_ESIZE = 0x0503 36 }; 37 38 union diag310_response { 39 u64 response; 40 struct { 41 u64 result : 32; 42 u64 : 16; 43 u64 rc : 16; 44 }; 45 }; 46 47 union diag310_req_subcode { 48 u64 subcode; 49 struct { 50 u64 : 48; 51 u64 st : 8; 52 u64 sc : 8; 53 }; 54 }; 55 56 union diag310_req_size { 57 u64 size; 58 struct { 59 u64 page_count : 32; 60 u64 : 32; 61 }; 62 }; 63 64 static inline unsigned long diag310(unsigned long subcode, unsigned long size, void *addr) 65 { 66 union register_pair rp = { .even = (unsigned long)addr, .odd = size }; 67 68 diag_stat_inc(DIAG_STAT_X310); 69 asm volatile("diag %[rp],%[subcode],0x310\n" 70 : [rp] "+d" (rp.pair) 71 : [subcode] "d" (subcode) 72 : "memory"); 73 return rp.odd; 74 } 75 76 static int diag310_result_to_errno(unsigned int result) 77 { 78 switch (result) { 79 case DIAG310_RET_BUSY: 80 return -EBUSY; 81 case DIAG310_RET_OPNOTSUPP: 82 return -EOPNOTSUPP; 83 default: 84 return -EINVAL; 85 } 86 } 87 88 static int diag310_get_subcode_mask(unsigned long *mask) 89 { 90 union diag310_response res; 91 92 res.response = diag310(DIAG310_SUBC_0, 0, NULL); 93 if (res.rc != DIAG310_RET_SUCCESS) 94 return diag310_result_to_errno(res.rc); 95 *mask = res.response; 96 return 0; 97 } 98 99 static int diag310_get_memtop_stride(unsigned long *stride) 100 { 101 union diag310_response res; 102 103 res.response = diag310(DIAG310_SUBC_1, 0, NULL); 104 if (res.rc != DIAG310_RET_SUCCESS) 105 return diag310_result_to_errno(res.rc); 106 *stride = res.result; 107 return 0; 108 } 109 110 static int diag310_get_memtop_size(unsigned long *pages, unsigned long level) 111 { 112 union diag310_req_subcode req = { .sc = DIAG310_SUBC_4, .st = level }; 113 union diag310_response res; 114 115 res.response = diag310(req.subcode, 0, NULL); 116 switch (res.rc) { 117 case DIAG310_RET_SUCCESS: 118 *pages = res.result; 119 return 0; 120 case DIAG310_RET_SC4_NODATA: 121 return -ENODATA; 122 case DIAG310_RET_SC4_INVAL: 123 return -EINVAL; 124 default: 125 return diag310_result_to_errno(res.rc); 126 } 127 } 128 129 static int diag310_store_topology_map(void *buf, unsigned long pages, unsigned long level) 130 { 131 union diag310_req_subcode req_sc = { .sc = DIAG310_SUBC_5, .st = level }; 132 union diag310_req_size req_size = { .page_count = pages }; 133 union diag310_response res; 134 135 res.response = diag310(req_sc.subcode, req_size.size, buf); 136 switch (res.rc) { 137 case DIAG310_RET_SUCCESS: 138 return 0; 139 case DIAG310_RET_SC5_NODATA: 140 return -ENODATA; 141 case DIAG310_RET_SC5_ESIZE: 142 return -EOVERFLOW; 143 case DIAG310_RET_SC5_INVAL: 144 return -EINVAL; 145 default: 146 return diag310_result_to_errno(res.rc); 147 } 148 } 149 150 static int diag310_check_features(void) 151 { 152 static int features_available; 153 unsigned long mask; 154 int rc; 155 156 if (READ_ONCE(features_available)) 157 return 0; 158 if (!sclp.has_diag310) 159 return -EOPNOTSUPP; 160 rc = diag310_get_subcode_mask(&mask); 161 if (rc) 162 return rc; 163 if (!test_bit_inv(DIAG310_SUBC_1, &mask)) 164 return -EOPNOTSUPP; 165 if (!test_bit_inv(DIAG310_SUBC_4, &mask)) 166 return -EOPNOTSUPP; 167 if (!test_bit_inv(DIAG310_SUBC_5, &mask)) 168 return -EOPNOTSUPP; 169 WRITE_ONCE(features_available, 1); 170 return 0; 171 } 172 173 static int memtop_get_stride_len(unsigned long *res) 174 { 175 static unsigned long memtop_stride; 176 unsigned long stride; 177 int rc; 178 179 stride = READ_ONCE(memtop_stride); 180 if (!stride) { 181 rc = diag310_get_memtop_stride(&stride); 182 if (rc) 183 return rc; 184 WRITE_ONCE(memtop_stride, stride); 185 } 186 *res = stride; 187 return 0; 188 } 189 190 static int memtop_get_page_count(unsigned long *res, unsigned long level) 191 { 192 static unsigned long memtop_pages[DIAG310_LEVELMAX]; 193 unsigned long pages; 194 int rc; 195 196 if (level > DIAG310_LEVELMAX || level < DIAG310_LEVELMIN) 197 return -EINVAL; 198 pages = READ_ONCE(memtop_pages[level - 1]); 199 if (!pages) { 200 rc = diag310_get_memtop_size(&pages, level); 201 if (rc) 202 return rc; 203 WRITE_ONCE(memtop_pages[level - 1], pages); 204 } 205 *res = pages; 206 return 0; 207 } 208 209 long diag310_memtop_stride(unsigned long arg) 210 { 211 size_t __user *argp = (void __user *)arg; 212 unsigned long stride; 213 int rc; 214 215 rc = diag310_check_features(); 216 if (rc) 217 return rc; 218 rc = memtop_get_stride_len(&stride); 219 if (rc) 220 return rc; 221 if (put_user(stride, argp)) 222 return -EFAULT; 223 return 0; 224 } 225 226 long diag310_memtop_len(unsigned long arg) 227 { 228 size_t __user *argp = (void __user *)arg; 229 unsigned long pages, level; 230 int rc; 231 232 rc = diag310_check_features(); 233 if (rc) 234 return rc; 235 if (get_user(level, argp)) 236 return -EFAULT; 237 rc = memtop_get_page_count(&pages, level); 238 if (rc) 239 return rc; 240 if (put_user(pages * PAGE_SIZE, argp)) 241 return -EFAULT; 242 return 0; 243 } 244 245 long diag310_memtop_buf(unsigned long arg) 246 { 247 struct diag310_memtop __user *udata = (struct diag310_memtop __user *)arg; 248 unsigned long level, pages, data_size; 249 u64 address; 250 void *buf; 251 int rc; 252 253 rc = diag310_check_features(); 254 if (rc) 255 return rc; 256 if (get_user(level, &udata->nesting_lvl)) 257 return -EFAULT; 258 if (get_user(address, &udata->address)) 259 return -EFAULT; 260 rc = memtop_get_page_count(&pages, level); 261 if (rc) 262 return rc; 263 data_size = pages * PAGE_SIZE; 264 buf = __vmalloc_node(data_size, PAGE_SIZE, GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT, 265 NUMA_NO_NODE, __builtin_return_address(0)); 266 if (!buf) 267 return -ENOMEM; 268 rc = diag310_store_topology_map(buf, pages, level); 269 if (rc) 270 goto out; 271 if (copy_to_user((void __user *)address, buf, data_size)) 272 rc = -EFAULT; 273 out: 274 vfree(buf); 275 return rc; 276 } 277