Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/pseries/papr-rtas-common.c
26481 views
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
25
bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob)
26
{
27
return blob->data && blob->len;
28
}
29
30
void 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
*/
47
static 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
*/
78
static const struct papr_rtas_blob *
79
papr_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;
101
free_blob:
102
papr_rtas_blob_free(blob);
103
return NULL;
104
}
105
106
int 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
*/
132
static 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
*/
169
const 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
*/
203
long 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
struct file *file;
209
long ret;
210
int fd;
211
212
blob = papr_rtas_retrieve(seq);
213
if (IS_ERR(blob))
214
return PTR_ERR(blob);
215
216
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
217
if (fd < 0) {
218
ret = fd;
219
goto free_blob;
220
}
221
222
file = anon_inode_getfile_fmode(name, fops, (void *)blob,
223
O_RDONLY, FMODE_LSEEK | FMODE_PREAD);
224
if (IS_ERR(file)) {
225
ret = PTR_ERR(file);
226
goto put_fd;
227
}
228
229
fd_install(fd, file);
230
return fd;
231
232
put_fd:
233
put_unused_fd(fd);
234
free_blob:
235
papr_rtas_blob_free(blob);
236
return ret;
237
}
238
239
/*
240
* papr_rtas_sequence_should_stop() - Determine whether RTAS retrieval
241
* sequence should continue.
242
*
243
* Examines the sequence error state and outputs of the last call to
244
* the specific RTAS to determine whether the sequence in progress
245
* should continue or stop.
246
*
247
* Return: True if the sequence has encountered an error or if all data
248
* for this sequence has been retrieved. False otherwise.
249
*/
250
bool papr_rtas_sequence_should_stop(const struct papr_rtas_sequence *seq,
251
s32 status, bool init_state)
252
{
253
bool done;
254
255
if (seq->error)
256
return true;
257
258
switch (status) {
259
case RTAS_SEQ_COMPLETE:
260
if (init_state)
261
done = false; /* Initial state. */
262
else
263
done = true; /* All data consumed. */
264
break;
265
case RTAS_SEQ_MORE_DATA:
266
done = false; /* More data available. */
267
break;
268
default:
269
done = true; /* Error encountered. */
270
break;
271
}
272
273
return done;
274
}
275
276
/*
277
* User space read to retrieve data for the corresponding RTAS call.
278
* papr_rtas_blob is filled with the data using the corresponding RTAS
279
* call sequence API.
280
*/
281
ssize_t papr_rtas_common_handle_read(struct file *file,
282
char __user *buf, size_t size, loff_t *off)
283
{
284
const struct papr_rtas_blob *blob = file->private_data;
285
286
/* We should not instantiate a handle without any data attached. */
287
if (!papr_rtas_blob_has_data(blob)) {
288
pr_err_once("handle without data\n");
289
return -EIO;
290
}
291
292
return simple_read_from_buffer(buf, size, off, blob->data, blob->len);
293
}
294
295
int papr_rtas_common_handle_release(struct inode *inode,
296
struct file *file)
297
{
298
const struct papr_rtas_blob *blob = file->private_data;
299
300
papr_rtas_blob_free(blob);
301
302
return 0;
303
}
304
305
loff_t papr_rtas_common_handle_seek(struct file *file, loff_t off,
306
int whence)
307
{
308
const struct papr_rtas_blob *blob = file->private_data;
309
310
return fixed_size_llseek(file, off, whence, blob->len);
311
}
312
313