Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/pseries/papr-platform-dump.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#define pr_fmt(fmt) "papr-platform-dump: " fmt
4
5
#include <linux/anon_inodes.h>
6
#include <linux/file.h>
7
#include <linux/fs.h>
8
#include <linux/init.h>
9
#include <linux/kernel.h>
10
#include <linux/miscdevice.h>
11
#include <asm/machdep.h>
12
#include <asm/rtas-work-area.h>
13
#include <asm/rtas.h>
14
#include <uapi/asm/papr-platform-dump.h>
15
16
/*
17
* Function-specific return values for ibm,platform-dump, derived from
18
* PAPR+ v2.13 7.3.3.4.1 "ibm,platform-dump RTAS Call".
19
*/
20
#define RTAS_IBM_PLATFORM_DUMP_COMPLETE 0 /* Complete dump retrieved. */
21
#define RTAS_IBM_PLATFORM_DUMP_CONTINUE 1 /* Continue dump */
22
#define RTAS_NOT_AUTHORIZED -9002 /* Not Authorized */
23
24
#define RTAS_IBM_PLATFORM_DUMP_START 2 /* Linux status to start dump */
25
26
/**
27
* struct ibm_platform_dump_params - Parameters (in and out) for
28
* ibm,platform-dump
29
* @work_area: In: work area buffer for results.
30
* @buf_length: In: work area buffer length in bytes
31
* @dump_tag_hi: In: Most-significant 32 bits of a Dump_Tag representing
32
* an id of the dump being processed.
33
* @dump_tag_lo: In: Least-significant 32 bits of a Dump_Tag representing
34
* an id of the dump being processed.
35
* @sequence_hi: In: Sequence number in most-significant 32 bits.
36
* Out: Next sequence number in most-significant 32 bits.
37
* @sequence_lo: In: Sequence number in Least-significant 32 bits
38
* Out: Next sequence number in Least-significant 32 bits.
39
* @bytes_ret_hi: Out: Bytes written in most-significant 32 bits.
40
* @bytes_ret_lo: Out: Bytes written in Least-significant 32 bits.
41
* @status: Out: RTAS call status.
42
* @list: Maintain the list of dumps are in progress. Can
43
* retrieve multiple dumps with different dump IDs at
44
* the same time but not with the same dump ID. This list
45
* is used to determine whether the dump for the same ID
46
* is in progress.
47
*/
48
struct ibm_platform_dump_params {
49
struct rtas_work_area *work_area;
50
u32 buf_length;
51
u32 dump_tag_hi;
52
u32 dump_tag_lo;
53
u32 sequence_hi;
54
u32 sequence_lo;
55
u32 bytes_ret_hi;
56
u32 bytes_ret_lo;
57
s32 status;
58
struct list_head list;
59
};
60
61
/*
62
* Multiple dumps with different dump IDs can be retrieved at the same
63
* time, but not with dame dump ID. platform_dump_list_mutex and
64
* platform_dump_list are used to prevent this behavior.
65
*/
66
static DEFINE_MUTEX(platform_dump_list_mutex);
67
static LIST_HEAD(platform_dump_list);
68
69
/**
70
* rtas_ibm_platform_dump() - Call ibm,platform-dump to fill a work area
71
* buffer.
72
* @params: See &struct ibm_platform_dump_params.
73
* @buf_addr: Address of dump buffer (work_area)
74
* @buf_length: Length of the buffer in bytes (min. 1024)
75
*
76
* Calls ibm,platform-dump until it errors or successfully deposits data
77
* into the supplied work area. Handles RTAS retry statuses. Maps RTAS
78
* error statuses to reasonable errno values.
79
*
80
* Can request multiple dumps with different dump IDs at the same time,
81
* but not with the same dump ID which is prevented with the check in
82
* the ioctl code (papr_platform_dump_create_handle()).
83
*
84
* The caller should inspect @params.status to determine whether more
85
* calls are needed to complete the sequence.
86
*
87
* Context: May sleep.
88
* Return: -ve on error, 0 for dump complete and 1 for continue dump
89
*/
90
static int rtas_ibm_platform_dump(struct ibm_platform_dump_params *params,
91
phys_addr_t buf_addr, u32 buf_length)
92
{
93
u32 rets[4];
94
s32 fwrc;
95
int ret = 0;
96
97
do {
98
fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP),
99
6, 5,
100
rets,
101
params->dump_tag_hi,
102
params->dump_tag_lo,
103
params->sequence_hi,
104
params->sequence_lo,
105
buf_addr,
106
buf_length);
107
} while (rtas_busy_delay(fwrc));
108
109
switch (fwrc) {
110
case RTAS_HARDWARE_ERROR:
111
ret = -EIO;
112
break;
113
case RTAS_NOT_AUTHORIZED:
114
ret = -EPERM;
115
break;
116
case RTAS_IBM_PLATFORM_DUMP_CONTINUE:
117
case RTAS_IBM_PLATFORM_DUMP_COMPLETE:
118
params->sequence_hi = rets[0];
119
params->sequence_lo = rets[1];
120
params->bytes_ret_hi = rets[2];
121
params->bytes_ret_lo = rets[3];
122
break;
123
default:
124
ret = -EIO;
125
pr_err_ratelimited("unexpected ibm,platform-dump status %d\n",
126
fwrc);
127
break;
128
}
129
130
params->status = fwrc;
131
return ret;
132
}
133
134
/*
135
* Platform dump is used with multiple RTAS calls to retrieve the
136
* complete dump for the provided dump ID. Once the complete dump is
137
* retrieved, the hypervisor returns dump complete status (0) for the
138
* last RTAS call and expects the caller issues one more call with
139
* NULL buffer to invalidate the dump so that the hypervisor can remove
140
* the dump.
141
*
142
* After the specific dump is invalidated in the hypervisor, expect the
143
* dump complete status for the new sequence - the user space initiates
144
* new request for the same dump ID.
145
*/
146
static ssize_t papr_platform_dump_handle_read(struct file *file,
147
char __user *buf, size_t size, loff_t *off)
148
{
149
struct ibm_platform_dump_params *params = file->private_data;
150
u64 total_bytes;
151
s32 fwrc;
152
153
/*
154
* Dump already completed with the previous read calls.
155
* In case if the user space issues further reads, returns
156
* -EINVAL.
157
*/
158
if (!params->buf_length) {
159
pr_warn_once("Platform dump completed for dump ID %llu\n",
160
(u64) (((u64)params->dump_tag_hi << 32) |
161
params->dump_tag_lo));
162
return -EINVAL;
163
}
164
165
/*
166
* The hypervisor returns status 0 if no more data available to
167
* download. The dump will be invalidated with ioctl (see below).
168
*/
169
if (params->status == RTAS_IBM_PLATFORM_DUMP_COMPLETE) {
170
params->buf_length = 0;
171
/*
172
* Returns 0 to the user space so that user
173
* space read stops.
174
*/
175
return 0;
176
}
177
178
if (size < SZ_1K) {
179
pr_err_once("Buffer length should be minimum 1024 bytes\n");
180
return -EINVAL;
181
} else if (size > params->buf_length) {
182
/*
183
* Allocate 4K work area. So if the user requests > 4K,
184
* resize the buffer length.
185
*/
186
size = params->buf_length;
187
}
188
189
fwrc = rtas_ibm_platform_dump(params,
190
rtas_work_area_phys(params->work_area),
191
size);
192
if (fwrc < 0)
193
return fwrc;
194
195
total_bytes = (u64) (((u64)params->bytes_ret_hi << 32) |
196
params->bytes_ret_lo);
197
198
/*
199
* Kernel or firmware bug, do not continue.
200
*/
201
if (WARN(total_bytes > size, "possible write beyond end of work area"))
202
return -EFAULT;
203
204
if (copy_to_user(buf, rtas_work_area_raw_buf(params->work_area),
205
total_bytes))
206
return -EFAULT;
207
208
return total_bytes;
209
}
210
211
static int papr_platform_dump_handle_release(struct inode *inode,
212
struct file *file)
213
{
214
struct ibm_platform_dump_params *params = file->private_data;
215
216
if (params->work_area)
217
rtas_work_area_free(params->work_area);
218
219
mutex_lock(&platform_dump_list_mutex);
220
list_del(&params->list);
221
mutex_unlock(&platform_dump_list_mutex);
222
223
kfree(params);
224
file->private_data = NULL;
225
return 0;
226
}
227
228
/*
229
* This ioctl is used to invalidate the dump assuming the user space
230
* issue this ioctl after obtain the complete dump.
231
* Issue the last RTAS call with NULL buffer to invalidate the dump
232
* which means dump will be freed in the hypervisor.
233
*/
234
static long papr_platform_dump_invalidate_ioctl(struct file *file,
235
unsigned int ioctl, unsigned long arg)
236
{
237
struct ibm_platform_dump_params *params;
238
u64 __user *argp = (void __user *)arg;
239
u64 param_dump_tag, dump_tag;
240
241
if (ioctl != PAPR_PLATFORM_DUMP_IOC_INVALIDATE)
242
return -ENOIOCTLCMD;
243
244
if (get_user(dump_tag, argp))
245
return -EFAULT;
246
247
/*
248
* private_data is freeded during release(), so should not
249
* happen.
250
*/
251
if (!file->private_data) {
252
pr_err("No valid FD to invalidate dump for the ID(%llu)\n",
253
dump_tag);
254
return -EINVAL;
255
}
256
257
params = file->private_data;
258
param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |
259
params->dump_tag_lo);
260
if (dump_tag != param_dump_tag) {
261
pr_err("Invalid dump ID(%llu) to invalidate dump\n",
262
dump_tag);
263
return -EINVAL;
264
}
265
266
if (params->status != RTAS_IBM_PLATFORM_DUMP_COMPLETE) {
267
pr_err("Platform dump is not complete, but requested "
268
"to invalidate dump for ID(%llu)\n",
269
dump_tag);
270
return -EINPROGRESS;
271
}
272
273
return rtas_ibm_platform_dump(params, 0, 0);
274
}
275
276
static const struct file_operations papr_platform_dump_handle_ops = {
277
.read = papr_platform_dump_handle_read,
278
.release = papr_platform_dump_handle_release,
279
.unlocked_ioctl = papr_platform_dump_invalidate_ioctl,
280
};
281
282
/**
283
* papr_platform_dump_create_handle() - Create a fd-based handle for
284
* reading platform dump
285
*
286
* Handler for PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE ioctl command
287
* Allocates RTAS parameter struct and work area and attached to the
288
* file descriptor for reading by user space with the multiple RTAS
289
* calls until the dump is completed. This memory allocation is freed
290
* when the file is released.
291
*
292
* Multiple dump requests with different IDs are allowed at the same
293
* time, but not with the same dump ID. So if the user space is
294
* already opened file descriptor for the specific dump ID, return
295
* -EALREADY for the next request.
296
*
297
* @dump_tag: Dump ID for the dump requested to retrieve from the
298
* hypervisor
299
*
300
* Return: The installed fd number if successful, -ve errno otherwise.
301
*/
302
static long papr_platform_dump_create_handle(u64 dump_tag)
303
{
304
struct ibm_platform_dump_params *params;
305
u64 param_dump_tag;
306
struct file *file;
307
long err;
308
int fd;
309
310
/*
311
* Return failure if the user space is already opened FD for
312
* the specific dump ID. This check will prevent multiple dump
313
* requests for the same dump ID at the same time. Generally
314
* should not expect this, but in case.
315
*/
316
list_for_each_entry(params, &platform_dump_list, list) {
317
param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |
318
params->dump_tag_lo);
319
if (dump_tag == param_dump_tag) {
320
pr_err("Platform dump for ID(%llu) is already in progress\n",
321
dump_tag);
322
return -EALREADY;
323
}
324
}
325
326
params = kzalloc(sizeof(struct ibm_platform_dump_params),
327
GFP_KERNEL_ACCOUNT);
328
if (!params)
329
return -ENOMEM;
330
331
params->work_area = rtas_work_area_alloc(SZ_4K);
332
params->buf_length = SZ_4K;
333
params->dump_tag_hi = (u32)(dump_tag >> 32);
334
params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
335
params->status = RTAS_IBM_PLATFORM_DUMP_START;
336
337
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
338
if (fd < 0) {
339
err = fd;
340
goto free_area;
341
}
342
343
file = anon_inode_getfile_fmode("[papr-platform-dump]",
344
&papr_platform_dump_handle_ops,
345
(void *)params, O_RDONLY,
346
FMODE_LSEEK | FMODE_PREAD);
347
if (IS_ERR(file)) {
348
err = PTR_ERR(file);
349
goto put_fd;
350
}
351
352
fd_install(fd, file);
353
354
list_add(&params->list, &platform_dump_list);
355
356
pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
357
current->comm, current->pid, dump_tag);
358
return fd;
359
put_fd:
360
put_unused_fd(fd);
361
free_area:
362
rtas_work_area_free(params->work_area);
363
kfree(params);
364
return err;
365
}
366
367
/*
368
* Top-level ioctl handler for /dev/papr-platform-dump.
369
*/
370
static long papr_platform_dump_dev_ioctl(struct file *filp,
371
unsigned int ioctl,
372
unsigned long arg)
373
{
374
u64 __user *argp = (void __user *)arg;
375
u64 dump_tag;
376
long ret;
377
378
if (get_user(dump_tag, argp))
379
return -EFAULT;
380
381
switch (ioctl) {
382
case PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE:
383
mutex_lock(&platform_dump_list_mutex);
384
ret = papr_platform_dump_create_handle(dump_tag);
385
mutex_unlock(&platform_dump_list_mutex);
386
break;
387
default:
388
ret = -ENOIOCTLCMD;
389
break;
390
}
391
return ret;
392
}
393
394
static const struct file_operations papr_platform_dump_ops = {
395
.unlocked_ioctl = papr_platform_dump_dev_ioctl,
396
};
397
398
static struct miscdevice papr_platform_dump_dev = {
399
.minor = MISC_DYNAMIC_MINOR,
400
.name = "papr-platform-dump",
401
.fops = &papr_platform_dump_ops,
402
};
403
404
static __init int papr_platform_dump_init(void)
405
{
406
if (!rtas_function_implemented(RTAS_FN_IBM_PLATFORM_DUMP))
407
return -ENODEV;
408
409
return misc_register(&papr_platform_dump_dev);
410
}
411
machine_device_initcall(pseries, papr_platform_dump_init);
412
413