xref: /linux/arch/powerpc/platforms/pseries/papr-indices.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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 = &params;
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