Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powernv/opal-elog.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Error log support on PowerNV.
4
*
5
* Copyright 2013,2014 IBM Corp.
6
*/
7
#include <linux/kernel.h>
8
#include <linux/init.h>
9
#include <linux/interrupt.h>
10
#include <linux/of.h>
11
#include <linux/slab.h>
12
#include <linux/sysfs.h>
13
#include <linux/fs.h>
14
#include <linux/vmalloc.h>
15
#include <linux/fcntl.h>
16
#include <linux/kobject.h>
17
#include <linux/uaccess.h>
18
#include <asm/opal.h>
19
20
struct elog_obj {
21
struct kobject kobj;
22
struct bin_attribute raw_attr;
23
uint64_t id;
24
uint64_t type;
25
size_t size;
26
char *buffer;
27
};
28
#define to_elog_obj(x) container_of(x, struct elog_obj, kobj)
29
30
struct elog_attribute {
31
struct attribute attr;
32
ssize_t (*show)(struct elog_obj *elog, struct elog_attribute *attr,
33
char *buf);
34
ssize_t (*store)(struct elog_obj *elog, struct elog_attribute *attr,
35
const char *buf, size_t count);
36
};
37
#define to_elog_attr(x) container_of(x, struct elog_attribute, attr)
38
39
static ssize_t elog_id_show(struct elog_obj *elog_obj,
40
struct elog_attribute *attr,
41
char *buf)
42
{
43
return sprintf(buf, "0x%llx\n", elog_obj->id);
44
}
45
46
static const char *elog_type_to_string(uint64_t type)
47
{
48
switch (type) {
49
case 0: return "PEL";
50
default: return "unknown";
51
}
52
}
53
54
static ssize_t elog_type_show(struct elog_obj *elog_obj,
55
struct elog_attribute *attr,
56
char *buf)
57
{
58
return sprintf(buf, "0x%llx %s\n",
59
elog_obj->type,
60
elog_type_to_string(elog_obj->type));
61
}
62
63
static ssize_t elog_ack_show(struct elog_obj *elog_obj,
64
struct elog_attribute *attr,
65
char *buf)
66
{
67
return sprintf(buf, "ack - acknowledge log message\n");
68
}
69
70
static ssize_t elog_ack_store(struct elog_obj *elog_obj,
71
struct elog_attribute *attr,
72
const char *buf,
73
size_t count)
74
{
75
/*
76
* Try to self remove this attribute. If we are successful,
77
* delete the kobject itself.
78
*/
79
if (sysfs_remove_file_self(&elog_obj->kobj, &attr->attr)) {
80
opal_send_ack_elog(elog_obj->id);
81
kobject_put(&elog_obj->kobj);
82
}
83
return count;
84
}
85
86
static struct elog_attribute id_attribute =
87
__ATTR(id, 0444, elog_id_show, NULL);
88
static struct elog_attribute type_attribute =
89
__ATTR(type, 0444, elog_type_show, NULL);
90
static struct elog_attribute ack_attribute =
91
__ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store);
92
93
static struct kset *elog_kset;
94
95
static ssize_t elog_attr_show(struct kobject *kobj,
96
struct attribute *attr,
97
char *buf)
98
{
99
struct elog_attribute *attribute;
100
struct elog_obj *elog;
101
102
attribute = to_elog_attr(attr);
103
elog = to_elog_obj(kobj);
104
105
if (!attribute->show)
106
return -EIO;
107
108
return attribute->show(elog, attribute, buf);
109
}
110
111
static ssize_t elog_attr_store(struct kobject *kobj,
112
struct attribute *attr,
113
const char *buf, size_t len)
114
{
115
struct elog_attribute *attribute;
116
struct elog_obj *elog;
117
118
attribute = to_elog_attr(attr);
119
elog = to_elog_obj(kobj);
120
121
if (!attribute->store)
122
return -EIO;
123
124
return attribute->store(elog, attribute, buf, len);
125
}
126
127
static const struct sysfs_ops elog_sysfs_ops = {
128
.show = elog_attr_show,
129
.store = elog_attr_store,
130
};
131
132
static void elog_release(struct kobject *kobj)
133
{
134
struct elog_obj *elog;
135
136
elog = to_elog_obj(kobj);
137
kfree(elog->buffer);
138
kfree(elog);
139
}
140
141
static struct attribute *elog_default_attrs[] = {
142
&id_attribute.attr,
143
&type_attribute.attr,
144
&ack_attribute.attr,
145
NULL,
146
};
147
ATTRIBUTE_GROUPS(elog_default);
148
149
static const struct kobj_type elog_ktype = {
150
.sysfs_ops = &elog_sysfs_ops,
151
.release = &elog_release,
152
.default_groups = elog_default_groups,
153
};
154
155
/* Maximum size of a single log on FSP is 16KB */
156
#define OPAL_MAX_ERRLOG_SIZE 16384
157
158
static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
159
const struct bin_attribute *bin_attr,
160
char *buffer, loff_t pos, size_t count)
161
{
162
int opal_rc;
163
164
struct elog_obj *elog = to_elog_obj(kobj);
165
166
/* We may have had an error reading before, so let's retry */
167
if (!elog->buffer) {
168
elog->buffer = kzalloc(elog->size, GFP_KERNEL);
169
if (!elog->buffer)
170
return -EIO;
171
172
opal_rc = opal_read_elog(__pa(elog->buffer),
173
elog->size, elog->id);
174
if (opal_rc != OPAL_SUCCESS) {
175
pr_err_ratelimited("ELOG: log read failed for log-id=%llx\n",
176
elog->id);
177
kfree(elog->buffer);
178
elog->buffer = NULL;
179
return -EIO;
180
}
181
}
182
183
memcpy(buffer, elog->buffer + pos, count);
184
185
return count;
186
}
187
188
static void create_elog_obj(uint64_t id, size_t size, uint64_t type)
189
{
190
struct elog_obj *elog;
191
int rc;
192
193
elog = kzalloc(sizeof(*elog), GFP_KERNEL);
194
if (!elog)
195
return;
196
197
elog->kobj.kset = elog_kset;
198
199
kobject_init(&elog->kobj, &elog_ktype);
200
201
sysfs_bin_attr_init(&elog->raw_attr);
202
203
elog->raw_attr.attr.name = "raw";
204
elog->raw_attr.attr.mode = 0400;
205
elog->raw_attr.size = size;
206
elog->raw_attr.read = raw_attr_read;
207
208
elog->id = id;
209
elog->size = size;
210
elog->type = type;
211
212
elog->buffer = kzalloc(elog->size, GFP_KERNEL);
213
214
if (elog->buffer) {
215
rc = opal_read_elog(__pa(elog->buffer),
216
elog->size, elog->id);
217
if (rc != OPAL_SUCCESS) {
218
pr_err("ELOG: log read failed for log-id=%llx\n",
219
elog->id);
220
kfree(elog->buffer);
221
elog->buffer = NULL;
222
}
223
}
224
225
rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
226
if (rc) {
227
kobject_put(&elog->kobj);
228
return;
229
}
230
231
/*
232
* As soon as the sysfs file for this elog is created/activated there is
233
* a chance the opal_errd daemon (or any userspace) might read and
234
* acknowledge the elog before kobject_uevent() is called. If that
235
* happens then there is a potential race between
236
* elog_ack_store->kobject_put() and kobject_uevent() which leads to a
237
* use-after-free of a kernfs object resulting in a kernel crash.
238
*
239
* To avoid that, we need to take a reference on behalf of the bin file,
240
* so that our reference remains valid while we call kobject_uevent().
241
* We then drop our reference before exiting the function, leaving the
242
* bin file to drop the last reference (if it hasn't already).
243
*/
244
245
/* Take a reference for the bin file */
246
kobject_get(&elog->kobj);
247
rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
248
if (rc == 0) {
249
kobject_uevent(&elog->kobj, KOBJ_ADD);
250
} else {
251
/* Drop the reference taken for the bin file */
252
kobject_put(&elog->kobj);
253
}
254
255
/* Drop our reference */
256
kobject_put(&elog->kobj);
257
258
return;
259
}
260
261
static irqreturn_t elog_event(int irq, void *data)
262
{
263
__be64 size;
264
__be64 id;
265
__be64 type;
266
uint64_t elog_size;
267
uint64_t log_id;
268
uint64_t elog_type;
269
int rc;
270
char name[2+16+1];
271
struct kobject *kobj;
272
273
rc = opal_get_elog_size(&id, &size, &type);
274
if (rc != OPAL_SUCCESS) {
275
pr_err("ELOG: OPAL log info read failed\n");
276
return IRQ_HANDLED;
277
}
278
279
elog_size = be64_to_cpu(size);
280
log_id = be64_to_cpu(id);
281
elog_type = be64_to_cpu(type);
282
283
WARN_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
284
285
if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
286
elog_size = OPAL_MAX_ERRLOG_SIZE;
287
288
sprintf(name, "0x%llx", log_id);
289
290
/* we may get notified twice, let's handle
291
* that gracefully and not create two conflicting
292
* entries.
293
*/
294
kobj = kset_find_obj(elog_kset, name);
295
if (kobj) {
296
/* Drop reference added by kset_find_obj() */
297
kobject_put(kobj);
298
return IRQ_HANDLED;
299
}
300
301
create_elog_obj(log_id, elog_size, elog_type);
302
303
return IRQ_HANDLED;
304
}
305
306
int __init opal_elog_init(void)
307
{
308
int rc = 0, irq;
309
310
/* ELOG not supported by firmware */
311
if (!opal_check_token(OPAL_ELOG_READ))
312
return -1;
313
314
elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
315
if (!elog_kset) {
316
pr_warn("%s: failed to create elog kset\n", __func__);
317
return -1;
318
}
319
320
irq = opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL));
321
if (!irq) {
322
pr_err("%s: Can't register OPAL event irq (%d)\n",
323
__func__, irq);
324
return irq;
325
}
326
327
rc = request_threaded_irq(irq, NULL, elog_event,
328
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "opal-elog", NULL);
329
if (rc) {
330
pr_err("%s: Can't request OPAL event irq (%d)\n",
331
__func__, rc);
332
return rc;
333
}
334
335
/* We are now ready to pull error logs from opal. */
336
if (opal_check_token(OPAL_ELOG_RESEND))
337
opal_resend_pending_logs();
338
339
return 0;
340
}
341
342