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 */
rtas_ibm_get_indices(struct rtas_get_indices_params * params)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 */
indices_sequence_begin(struct papr_rtas_sequence * seq)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 */
indices_sequence_end(struct papr_rtas_sequence * seq)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
indices_sequence_fill_work_area(struct papr_rtas_sequence * seq,size_t * len)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 */
papr_indices_handle_read(struct file * file,char __user * buf,size_t size,loff_t * off)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 */
papr_indices_create_handle(struct papr_indices_io_block __user * ubuf)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 *
papr_dynamic_indice_buf_from_user(struct papr_indices_io_block __user * ubuf,struct papr_indices_io_block * kbuf)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 */
papr_dynamic_indicator_ioc_set(struct papr_indices_io_block __user * ubuf)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
papr_dynamic_sensor_ioc_get(struct papr_indices_io_block __user * ubuf)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 */
papr_indices_dev_ioctl(struct file * filp,unsigned int ioctl,unsigned long arg)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
papr_indices_init(void)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