File Index
Files and directories
Sign in
FILE

papr-rtas-common.c

File preview with syntax highlighting.

linux-6.19.14/arch/powerpc/platforms/pseries/papr-rtas-common.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#define pr_fmt(fmt) "papr-common: " fmt
  4
  5#include <linux/types.h>
  6#include <linux/kernel.h>
  7#include <linux/signal.h>
  8#include <linux/slab.h>
  9#include <linux/file.h>
 10#include <linux/fs.h>
 11#include <linux/anon_inodes.h>
 12#include <linux/sched/signal.h>
 13#include "papr-rtas-common.h"
 14
 15/*
 16 * Sequence based RTAS HCALL has to issue multiple times to retrieve
 17 * complete data from the hypervisor. For some of these RTAS calls,
 18 * the OS should not interleave calls with different input until the
 19 * sequence is completed. So data is collected for these calls during
 20 * ioctl handle and export to user space with read() handle.
 21 * This file provides common functions needed for such sequence based
 22 * RTAS calls Ex: ibm,get-vpd and ibm,get-indices.
 23 */
 24
 25bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob)
 26{
 27	return blob->data && blob->len;
 28}
 29
 30void papr_rtas_blob_free(const struct papr_rtas_blob *blob)
 31{
 32	if (blob) {
 33		kvfree(blob->data);
 34		kfree(blob);
 35	}
 36}
 37
 38/**
 39 * papr_rtas_blob_extend() - Append data to a &struct papr_rtas_blob.
 40 * @blob: The blob to extend.
 41 * @data: The new data to append to @blob.
 42 * @len:  The length of @data.
 43 *
 44 * Context: May sleep.
 45 * Return: -ENOMEM on allocation failure, 0 otherwise.
 46 */
 47static int papr_rtas_blob_extend(struct papr_rtas_blob *blob,
 48				const char *data, size_t len)
 49{
 50	const size_t new_len = blob->len + len;
 51	const size_t old_len = blob->len;
 52	const char *old_ptr = blob->data;
 53	char *new_ptr;
 54
 55	new_ptr = kvrealloc(old_ptr, new_len, GFP_KERNEL_ACCOUNT);
 56	if (!new_ptr)
 57		return -ENOMEM;
 58
 59	memcpy(&new_ptr[old_len], data, len);
 60	blob->data = new_ptr;
 61	blob->len = new_len;
 62	return 0;
 63}
 64
 65/**
 66 * papr_rtas_blob_generate() - Construct a new &struct papr_rtas_blob.
 67 * @seq: work function of the caller that is called to obtain
 68 *       data with the caller RTAS call.
 69 *
 70 * The @work callback is invoked until it returns NULL. @seq is
 71 * passed to @work in its first argument on each call. When
 72 * @work returns data, it should store the data length in its
 73 * second argument.
 74 *
 75 * Context: May sleep.
 76 * Return: A completely populated &struct papr_rtas_blob, or NULL on error.
 77 */
 78static const struct papr_rtas_blob *
 79papr_rtas_blob_generate(struct papr_rtas_sequence *seq)
 80{
 81	struct papr_rtas_blob *blob;
 82	const char *buf;
 83	size_t len;
 84	int err = 0;
 85
 86	blob  = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT);
 87	if (!blob)
 88		return NULL;
 89
 90	if (!seq->work)
 91		return ERR_PTR(-EINVAL);
 92
 93
 94	while (err == 0 && (buf = seq->work(seq, &len)))
 95		err = papr_rtas_blob_extend(blob, buf, len);
 96
 97	if (err != 0 || !papr_rtas_blob_has_data(blob))
 98		goto free_blob;
 99
100	return blob;
101free_blob:
102	papr_rtas_blob_free(blob);
103	return NULL;
104}
105
106int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, int err)
107{
108	/* Preserve the first error recorded. */
109	if (seq->error == 0)
110		seq->error = err;
111
112	return seq->error;
113}
114
115/*
116 * Higher-level retrieval code below. These functions use the
117 * papr_rtas_blob_* and sequence_* APIs defined above to create fd-based
118 * handles for consumption by user space.
119 */
120
121/**
122 * papr_rtas_run_sequence() - Run a single retrieval sequence.
123 * @seq:	Functions of the caller to complete the sequence
124 *
125 * Context: May sleep. Holds a mutex and an RTAS work area for its
126 *          duration. Typically performs multiple sleepable slab
127 *          allocations.
128 *
129 * Return: A populated &struct papr_rtas_blob on success. Encoded error
130 * pointer otherwise.
131 */
132static const struct papr_rtas_blob *papr_rtas_run_sequence(struct papr_rtas_sequence *seq)
133{
134	const struct papr_rtas_blob *blob;
135
136	if (seq->begin)
137		seq->begin(seq);
138
139	blob = papr_rtas_blob_generate(seq);
140	if (!blob)
141		papr_rtas_sequence_set_err(seq, -ENOMEM);
142
143	if (seq->end)
144		seq->end(seq);
145
146
147	if (seq->error) {
148		papr_rtas_blob_free(blob);
149		return ERR_PTR(seq->error);
150	}
151
152	return blob;
153}
154
155/**
156 * papr_rtas_retrieve() - Return the data blob that is exposed to
157 * user space.
158 * @seq: RTAS call specific functions to be invoked until the
159 *       sequence is completed.
160 *
161 * Run sequences against @param until a blob is successfully
162 * instantiated, or a hard error is encountered, or a fatal signal is
163 * pending.
164 *
165 * Context: May sleep.
166 * Return: A fully populated data blob when successful. Encoded error
167 * pointer otherwise.
168 */
169const struct papr_rtas_blob *papr_rtas_retrieve(struct papr_rtas_sequence *seq)
170{
171	const struct papr_rtas_blob *blob;
172
173	/*
174	 * EAGAIN means the sequence returns error with a -4 (data
175	 * changed and need to start the sequence) status from RTAS calls
176	 * and we should attempt a new sequence. PAPR+ (v2.13 R1–7.3.20–5
177	 * - ibm,get-vpd, R1–7.3.17–6 - ibm,get-indices) indicates that
178	 * this should be a transient condition, not something that
179	 * happens continuously. But we'll stop trying on a fatal signal.
180	 */
181	do {
182		blob = papr_rtas_run_sequence(seq);
183		if (!IS_ERR(blob)) /* Success. */
184			break;
185		if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */
186			break;
187		cond_resched();
188	} while (!fatal_signal_pending(current));
189
190	return blob;
191}
192
193/**
194 * papr_rtas_setup_file_interface - Complete the sequence and obtain
195 * the data and export to user space with fd-based handles. Then the
196 * user spave gets the data with read() handle.
197 * @seq: RTAS call specific functions to get the data.
198 * @fops: RTAS call specific file operations such as read().
199 * @name: RTAS call specific char device node.
200 *
201 * Return: FD handle for consumption by user space
202 */
203long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq,
204				const struct file_operations *fops,
205				char *name)
206{
207	const struct papr_rtas_blob *blob;
208	int fd;
209
210	blob = papr_rtas_retrieve(seq);
211	if (IS_ERR(blob))
212		return PTR_ERR(blob);
213
214	fd = FD_ADD(O_RDONLY | O_CLOEXEC,
215		   anon_inode_getfile_fmode(name, fops, (void *)blob, O_RDONLY,
216					    FMODE_LSEEK | FMODE_PREAD));
217	if (fd < 0)
218		papr_rtas_blob_free(blob);
219	return fd;
220}
221
222/*
223 * papr_rtas_sequence_should_stop() - Determine whether RTAS retrieval
224 *                                    sequence should continue.
225 *
226 * Examines the sequence error state and outputs of the last call to
227 * the specific RTAS to determine whether the sequence in progress
228 * should continue or stop.
229 *
230 * Return: True if the sequence has encountered an error or if all data
231 *         for this sequence has been retrieved. False otherwise.
232 */
233bool papr_rtas_sequence_should_stop(const struct papr_rtas_sequence *seq,
234				s32 status, bool init_state)
235{
236	bool done;
237
238	if (seq->error)
239		return true;
240
241	switch (status) {
242	case RTAS_SEQ_COMPLETE:
243		if (init_state)
244			done = false; /* Initial state. */
245		else
246			done = true; /* All data consumed. */
247		break;
248	case RTAS_SEQ_MORE_DATA:
249		done = false; /* More data available. */
250		break;
251	default:
252		done = true; /* Error encountered. */
253		break;
254	}
255
256	return done;
257}
258
259/*
260 * User space read to retrieve data for the corresponding RTAS call.
261 * papr_rtas_blob is filled with the data using the corresponding RTAS
262 * call sequence API.
263 */
264ssize_t papr_rtas_common_handle_read(struct file *file,
265	       char __user *buf, size_t size, loff_t *off)
266{
267	const struct papr_rtas_blob *blob = file->private_data;
268
269	/* We should not instantiate a handle without any data attached. */
270	if (!papr_rtas_blob_has_data(blob)) {
271		pr_err_once("handle without data\n");
272		return -EIO;
273	}
274
275	return simple_read_from_buffer(buf, size, off, blob->data, blob->len);
276}
277
278int papr_rtas_common_handle_release(struct inode *inode,
279		struct file *file)
280{
281	const struct papr_rtas_blob *blob = file->private_data;
282
283	papr_rtas_blob_free(blob);
284
285	return 0;
286}
287
288loff_t papr_rtas_common_handle_seek(struct file *file, loff_t off,
289					int whence)
290{
291	const struct papr_rtas_blob *blob = file->private_data;
292
293	return fixed_size_llseek(file, off, whence, blob->len);
294}
~/ Read-only file preview.