1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #define pr_fmt(fmt) "papr-indices: " fmt 4 5 #include <linux/build_bug.h> 6 #include <linux/file.h> 7 #include <linux/fs.h> 8 #include <linux/init.h> 9 #include <linux/lockdep.h> 10 #include <linux/kernel.h> 11 #include <linux/miscdevice.h> 12 #include <linux/signal.h> 13 #include <linux/slab.h> 14 #include <linux/string.h> 15 #include <linux/string_helpers.h> 16 #include <linux/uaccess.h> 17 #include <asm/machdep.h> 18 #include <asm/rtas-work-area.h> 19 #include <asm/rtas.h> 20 #include <uapi/asm/papr-indices.h> 21 #include "papr-rtas-common.h" 22 23 /* 24 * Function-specific return values for ibm,set-dynamic-indicator and 25 * ibm,get-dynamic-sensor-state RTAS calls. 26 * PAPR+ v2.13 7.3.18 and 7.3.19. 27 */ 28 #define RTAS_IBM_DYNAMIC_INDICE_NO_INDICATOR -3 29 30 /** 31 * struct rtas_get_indices_params - Parameters (in and out) for 32 * ibm,get-indices. 33 * @is_sensor: In: Caller-provided whether sensor or indicator. 34 * @indice_type:In: Caller-provided indice (sensor or indicator) token 35 * @work_area: In: Caller-provided work area buffer for results. 36 * @next: In: Sequence number. Out: Next sequence number. 37 * @status: Out: RTAS call status. 38 */ 39 struct rtas_get_indices_params { 40 u8 is_sensor; 41 u32 indice_type; 42 struct rtas_work_area *work_area; 43 u32 next; 44 s32 status; 45 }; 46 47 /* 48 * rtas_ibm_get_indices() - Call ibm,get-indices to fill a work area buffer. 49 * @params: See &struct rtas_ibm_get_indices_params. 50 * 51 * Calls ibm,get-indices until it errors or successfully deposits data 52 * into the supplied work area. Handles RTAS retry statuses. Maps RTAS 53 * error statuses to reasonable errno values. 54 * 55 * The caller is expected to invoke rtas_ibm_get_indices() multiple times 56 * to retrieve all indices data for the provided indice type. Only one 57 * sequence should be in progress at any time; starting a new sequence 58 * will disrupt any sequence already in progress. Serialization of 59 * indices retrieval sequences is the responsibility of the caller. 60 * 61 * The caller should inspect @params.status to determine whether more 62 * calls are needed to complete the sequence. 63 * 64 * Context: May sleep. 65 * Return: -ve on error, 0 otherwise. 66 */ 67 static int rtas_ibm_get_indices(struct rtas_get_indices_params *params) 68 { 69 struct rtas_work_area *work_area = params->work_area; 70 const s32 token = rtas_function_token(RTAS_FN_IBM_GET_INDICES); 71 u32 rets; 72 s32 fwrc; 73 int ret; 74 75 if (token == RTAS_UNKNOWN_SERVICE) 76 return -ENOENT; 77 78 lockdep_assert_held(&rtas_ibm_get_indices_lock); 79 80 do { 81 fwrc = rtas_call(token, 5, 2, &rets, params->is_sensor, 82 params->indice_type, 83 rtas_work_area_phys(work_area), 84 rtas_work_area_size(work_area), 85 params->next); 86 } while (rtas_busy_delay(fwrc)); 87 88 switch (fwrc) { 89 case RTAS_HARDWARE_ERROR: 90 ret = -EIO; 91 break; 92 case RTAS_INVALID_PARAMETER: /* Indicator type is not supported */ 93 ret = -EINVAL; 94 break; 95 case RTAS_SEQ_START_OVER: 96 ret = -EAGAIN; 97 pr_info_ratelimited("Indices changed during retrieval, retrying\n"); 98 params->next = 1; 99 break; 100 case RTAS_SEQ_MORE_DATA: 101 params->next = rets; 102 ret = 0; 103 break; 104 case RTAS_SEQ_COMPLETE: 105 params->next = 0; 106 ret = 0; 107 break; 108 default: 109 ret = -EIO; 110 pr_err_ratelimited("unexpected ibm,get-indices status %d\n", fwrc); 111 break; 112 } 113 114 params->status = fwrc; 115 return ret; 116 } 117 118 /* 119 * Internal indices sequence APIs. A sequence is a series of calls to 120 * ibm,get-indices for a given location code. The sequence ends when 121 * an error is encountered or all indices for the input has been 122 * returned. 123 */ 124 125 /* 126 * indices_sequence_begin() - Begin a indices retrieval sequence. 127 * 128 * Context: May sleep. 129 */ 130 static void indices_sequence_begin(struct papr_rtas_sequence *seq) 131 { 132 struct rtas_get_indices_params *param; 133 134 param = (struct rtas_get_indices_params *)seq->params; 135 /* 136 * We could allocate the work area before acquiring the 137 * function lock, but that would allow concurrent requests to 138 * exhaust the limited work area pool for no benefit. So 139 * allocate the work area under the lock. 140 */ 141 mutex_lock(&rtas_ibm_get_indices_lock); 142 param->work_area = rtas_work_area_alloc(RTAS_GET_INDICES_BUF_SIZE); 143 param->next = 1; 144 param->status = 0; 145 } 146 147 /* 148 * indices_sequence_end() - Finalize a indices retrieval sequence. 149 * 150 * Releases resources obtained by indices_sequence_begin(). 151 */ 152 static void indices_sequence_end(struct papr_rtas_sequence *seq) 153 { 154 struct rtas_get_indices_params *param; 155 156 param = (struct rtas_get_indices_params *)seq->params; 157 rtas_work_area_free(param->work_area); 158 mutex_unlock(&rtas_ibm_get_indices_lock); 159 } 160 161 /* 162 * Work function to be passed to papr_rtas_blob_generate(). 163 * 164 * ibm,get-indices RTAS call fills the work area with the certain 165 * format but does not return the bytes written in the buffer. So 166 * instead of kernel parsing this work area to determine the buffer 167 * length, copy the complete work area (RTAS_GET_INDICES_BUF_SIZE) 168 * to the blob and let the user space to obtain the data. 169 * Means RTAS_GET_INDICES_BUF_SIZE data will be returned for each 170 * read(). 171 */ 172 173 static const char *indices_sequence_fill_work_area(struct papr_rtas_sequence *seq, 174 size_t *len) 175 { 176 struct rtas_get_indices_params *p; 177 bool init_state; 178 179 p = (struct rtas_get_indices_params *)seq->params; 180 init_state = (p->next == 1) ? true : false; 181 182 if (papr_rtas_sequence_should_stop(seq, p->status, init_state)) 183 return NULL; 184 if (papr_rtas_sequence_set_err(seq, rtas_ibm_get_indices(p))) 185 return NULL; 186 187 *len = RTAS_GET_INDICES_BUF_SIZE; 188 return rtas_work_area_raw_buf(p->work_area); 189 } 190 191 /* 192 * papr_indices_handle_read - returns indices blob data to the user space 193 * 194 * ibm,get-indices RTAS call fills the work area with the certian 195 * format but does not return the bytes written in the buffer and 196 * copied RTAS_GET_INDICES_BUF_SIZE data to the blob for each RTAS 197 * call. So send RTAS_GET_INDICES_BUF_SIZE buffer to the user space 198 * for each read(). 199 */ 200 static ssize_t papr_indices_handle_read(struct file *file, 201 char __user *buf, size_t size, loff_t *off) 202 { 203 const struct papr_rtas_blob *blob = file->private_data; 204 205 /* we should not instantiate a handle without any data attached. */ 206 if (!papr_rtas_blob_has_data(blob)) { 207 pr_err_once("handle without data\n"); 208 return -EIO; 209 } 210 211 if (size < RTAS_GET_INDICES_BUF_SIZE) { 212 pr_err_once("Invalid buffer length %ld, expect %d\n", 213 size, RTAS_GET_INDICES_BUF_SIZE); 214 return -EINVAL; 215 } else if (size > RTAS_GET_INDICES_BUF_SIZE) 216 size = RTAS_GET_INDICES_BUF_SIZE; 217 218 return simple_read_from_buffer(buf, size, off, blob->data, blob->len); 219 } 220 221 static const struct file_operations papr_indices_handle_ops = { 222 .read = papr_indices_handle_read, 223 .llseek = papr_rtas_common_handle_seek, 224 .release = papr_rtas_common_handle_release, 225 }; 226 227 /* 228 * papr_indices_create_handle() - Create a fd-based handle for reading 229 * indices data 230 * @ubuf: Input parameters to RTAS call such as whether sensor or indicator 231 * and indice type in user memory 232 * 233 * Handler for PAPR_INDICES_IOC_GET ioctl command. Validates @ubuf 234 * and instantiates an immutable indices "blob" for it. The blob is 235 * attached to a file descriptor for reading by user space. The memory 236 * backing the blob is freed when the file is released. 237 * 238 * The entire requested indices is retrieved by this call and all 239 * necessary RTAS interactions are performed before returning the fd 240 * to user space. This keeps the read handler simple and ensures that 241 * the kernel can prevent interleaving of ibm,get-indices call sequences. 242 * 243 * Return: The installed fd number if successful, -ve errno otherwise. 244 */ 245 static long papr_indices_create_handle(struct papr_indices_io_block __user *ubuf) 246 { 247 struct papr_rtas_sequence seq = {}; 248 struct rtas_get_indices_params params = {}; 249 int fd; 250 251 if (get_user(params.is_sensor, &ubuf->indices.is_sensor)) 252 return -EFAULT; 253 254 if (get_user(params.indice_type, &ubuf->indices.indice_type)) 255 return -EFAULT; 256 257 seq = (struct papr_rtas_sequence) { 258 .begin = indices_sequence_begin, 259 .end = indices_sequence_end, 260 .work = indices_sequence_fill_work_area, 261 }; 262 263 seq.params = ¶ms; 264 fd = papr_rtas_setup_file_interface(&seq, 265 &papr_indices_handle_ops, "[papr-indices]"); 266 267 return fd; 268 } 269 270 /* 271 * Create work area with the input parameters. This function is used 272 * for both ibm,set-dynamic-indicator and ibm,get-dynamic-sensor-state 273 * RTAS Calls. 274 */ 275 static struct rtas_work_area * 276 papr_dynamic_indice_buf_from_user(struct papr_indices_io_block __user *ubuf, 277 struct papr_indices_io_block *kbuf) 278 { 279 struct rtas_work_area *work_area; 280 u32 length; 281 __be32 len_be; 282 283 if (copy_from_user(kbuf, ubuf, sizeof(*kbuf))) 284 return ERR_PTR(-EFAULT); 285 286 287 if (!string_is_terminated(kbuf->dynamic_param.location_code_str, 288 ARRAY_SIZE(kbuf->dynamic_param.location_code_str))) 289 return ERR_PTR(-EINVAL); 290 291 /* 292 * The input data in the work area should be as follows: 293 * - 32-bit integer length of the location code string, 294 * including NULL. 295 * - Location code string, NULL terminated, identifying the 296 * token (sensor or indicator). 297 * PAPR 2.13 - R1–7.3.18–5 ibm,set-dynamic-indicator 298 * - R1–7.3.19–5 ibm,get-dynamic-sensor-state 299 */ 300 /* 301 * Length that user space passed should also include NULL 302 * terminator. 303 */ 304 length = strlen(kbuf->dynamic_param.location_code_str) + 1; 305 if (length > LOC_CODE_SIZE) 306 return ERR_PTR(-EINVAL); 307 308 len_be = cpu_to_be32(length); 309 310 work_area = rtas_work_area_alloc(LOC_CODE_SIZE + sizeof(u32)); 311 memcpy(rtas_work_area_raw_buf(work_area), &len_be, sizeof(u32)); 312 memcpy((rtas_work_area_raw_buf(work_area) + sizeof(u32)), 313 &kbuf->dynamic_param.location_code_str, length); 314 315 return work_area; 316 } 317 318 /** 319 * papr_dynamic_indicator_ioc_set - ibm,set-dynamic-indicator RTAS Call 320 * PAPR 2.13 7.3.18 321 * 322 * @ubuf: Input parameters to RTAS call such as indicator token and 323 * new state. 324 * 325 * Returns success or -errno. 326 */ 327 static long papr_dynamic_indicator_ioc_set(struct papr_indices_io_block __user *ubuf) 328 { 329 struct papr_indices_io_block kbuf; 330 struct rtas_work_area *work_area; 331 s32 fwrc, token, ret; 332 333 token = rtas_function_token(RTAS_FN_IBM_SET_DYNAMIC_INDICATOR); 334 if (token == RTAS_UNKNOWN_SERVICE) 335 return -ENOENT; 336 337 mutex_lock(&rtas_ibm_set_dynamic_indicator_lock); 338 work_area = papr_dynamic_indice_buf_from_user(ubuf, &kbuf); 339 if (IS_ERR(work_area)) { 340 ret = PTR_ERR(work_area); 341 goto out; 342 } 343 344 do { 345 fwrc = rtas_call(token, 3, 1, NULL, 346 kbuf.dynamic_param.token, 347 kbuf.dynamic_param.state, 348 rtas_work_area_phys(work_area)); 349 } while (rtas_busy_delay(fwrc)); 350 351 rtas_work_area_free(work_area); 352 353 switch (fwrc) { 354 case RTAS_SUCCESS: 355 ret = 0; 356 break; 357 case RTAS_IBM_DYNAMIC_INDICE_NO_INDICATOR: /* No such indicator */ 358 ret = -EOPNOTSUPP; 359 break; 360 default: 361 pr_err("unexpected ibm,set-dynamic-indicator result %d\n", 362 fwrc); 363 fallthrough; 364 case RTAS_HARDWARE_ERROR: /* Hardware/platform error */ 365 ret = -EIO; 366 break; 367 } 368 369 out: 370 mutex_unlock(&rtas_ibm_set_dynamic_indicator_lock); 371 return ret; 372 } 373 374 /** 375 * papr_dynamic_sensor_ioc_get - ibm,get-dynamic-sensor-state RTAS Call 376 * PAPR 2.13 7.3.19 377 * 378 * @ubuf: Input parameters to RTAS call such as sensor token 379 * Copies the state in user space buffer. 380 * 381 * 382 * Returns success or -errno. 383 */ 384 385 static long papr_dynamic_sensor_ioc_get(struct papr_indices_io_block __user *ubuf) 386 { 387 struct papr_indices_io_block kbuf; 388 struct rtas_work_area *work_area; 389 s32 fwrc, token, ret; 390 u32 rets; 391 392 token = rtas_function_token(RTAS_FN_IBM_GET_DYNAMIC_SENSOR_STATE); 393 if (token == RTAS_UNKNOWN_SERVICE) 394 return -ENOENT; 395 396 mutex_lock(&rtas_ibm_get_dynamic_sensor_state_lock); 397 work_area = papr_dynamic_indice_buf_from_user(ubuf, &kbuf); 398 if (IS_ERR(work_area)) { 399 ret = PTR_ERR(work_area); 400 goto out; 401 } 402 403 do { 404 fwrc = rtas_call(token, 2, 2, &rets, 405 kbuf.dynamic_param.token, 406 rtas_work_area_phys(work_area)); 407 } while (rtas_busy_delay(fwrc)); 408 409 rtas_work_area_free(work_area); 410 411 switch (fwrc) { 412 case RTAS_SUCCESS: 413 if (put_user(rets, &ubuf->dynamic_param.state)) 414 ret = -EFAULT; 415 else 416 ret = 0; 417 break; 418 case RTAS_IBM_DYNAMIC_INDICE_NO_INDICATOR: /* No such indicator */ 419 ret = -EOPNOTSUPP; 420 break; 421 default: 422 pr_err("unexpected ibm,get-dynamic-sensor result %d\n", 423 fwrc); 424 fallthrough; 425 case RTAS_HARDWARE_ERROR: /* Hardware/platform error */ 426 ret = -EIO; 427 break; 428 } 429 430 out: 431 mutex_unlock(&rtas_ibm_get_dynamic_sensor_state_lock); 432 return ret; 433 } 434 435 /* 436 * Top-level ioctl handler for /dev/papr-indices. 437 */ 438 static long papr_indices_dev_ioctl(struct file *filp, unsigned int ioctl, 439 unsigned long arg) 440 { 441 void __user *argp = (__force void __user *)arg; 442 long ret; 443 444 switch (ioctl) { 445 case PAPR_INDICES_IOC_GET: 446 ret = papr_indices_create_handle(argp); 447 break; 448 case PAPR_DYNAMIC_SENSOR_IOC_GET: 449 ret = papr_dynamic_sensor_ioc_get(argp); 450 break; 451 case PAPR_DYNAMIC_INDICATOR_IOC_SET: 452 if (filp->f_mode & FMODE_WRITE) 453 ret = papr_dynamic_indicator_ioc_set(argp); 454 else 455 ret = -EBADF; 456 break; 457 default: 458 ret = -ENOIOCTLCMD; 459 break; 460 } 461 462 return ret; 463 } 464 465 static const struct file_operations papr_indices_ops = { 466 .unlocked_ioctl = papr_indices_dev_ioctl, 467 }; 468 469 static struct miscdevice papr_indices_dev = { 470 .minor = MISC_DYNAMIC_MINOR, 471 .name = "papr-indices", 472 .fops = &papr_indices_ops, 473 }; 474 475 static __init int papr_indices_init(void) 476 { 477 if (!rtas_function_implemented(RTAS_FN_IBM_GET_INDICES)) 478 return -ENODEV; 479 480 if (!rtas_function_implemented(RTAS_FN_IBM_SET_DYNAMIC_INDICATOR)) 481 return -ENODEV; 482 483 if (!rtas_function_implemented(RTAS_FN_IBM_GET_DYNAMIC_SENSOR_STATE)) 484 return -ENODEV; 485 486 return misc_register(&papr_indices_dev); 487 } 488 machine_device_initcall(pseries, papr_indices_init); 489