2 * Error log support on PowerNV.
4 * Copyright 2013,2014 IBM Corp.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
15 #include <linux/slab.h>
16 #include <linux/sysfs.h>
18 #include <linux/vmalloc.h>
19 #include <linux/fcntl.h>
20 #include <linux/kobject.h>
21 #include <linux/uaccess.h>
26 struct bin_attribute raw_attr
;
32 #define to_elog_obj(x) container_of(x, struct elog_obj, kobj)
34 struct elog_attribute
{
35 struct attribute attr
;
36 ssize_t (*show
)(struct elog_obj
*elog
, struct elog_attribute
*attr
,
38 ssize_t (*store
)(struct elog_obj
*elog
, struct elog_attribute
*attr
,
39 const char *buf
, size_t count
);
41 #define to_elog_attr(x) container_of(x, struct elog_attribute, attr)
43 static ssize_t
elog_id_show(struct elog_obj
*elog_obj
,
44 struct elog_attribute
*attr
,
47 return sprintf(buf
, "0x%llx\n", elog_obj
->id
);
50 static const char *elog_type_to_string(uint64_t type
)
54 default: return "unknown";
58 static ssize_t
elog_type_show(struct elog_obj
*elog_obj
,
59 struct elog_attribute
*attr
,
62 return sprintf(buf
, "0x%llx %s\n",
64 elog_type_to_string(elog_obj
->type
));
67 static ssize_t
elog_ack_show(struct elog_obj
*elog_obj
,
68 struct elog_attribute
*attr
,
71 return sprintf(buf
, "ack - acknowledge log message\n");
74 static ssize_t
elog_ack_store(struct elog_obj
*elog_obj
,
75 struct elog_attribute
*attr
,
79 opal_send_ack_elog(elog_obj
->id
);
80 sysfs_remove_file_self(&elog_obj
->kobj
, &attr
->attr
);
81 kobject_put(&elog_obj
->kobj
);
85 static struct elog_attribute id_attribute
=
86 __ATTR(id
, 0444, elog_id_show
, NULL
);
87 static struct elog_attribute type_attribute
=
88 __ATTR(type
, 0444, elog_type_show
, NULL
);
89 static struct elog_attribute ack_attribute
=
90 __ATTR(acknowledge
, 0660, elog_ack_show
, elog_ack_store
);
92 static struct kset
*elog_kset
;
94 static ssize_t
elog_attr_show(struct kobject
*kobj
,
95 struct attribute
*attr
,
98 struct elog_attribute
*attribute
;
99 struct elog_obj
*elog
;
101 attribute
= to_elog_attr(attr
);
102 elog
= to_elog_obj(kobj
);
104 if (!attribute
->show
)
107 return attribute
->show(elog
, attribute
, buf
);
110 static ssize_t
elog_attr_store(struct kobject
*kobj
,
111 struct attribute
*attr
,
112 const char *buf
, size_t len
)
114 struct elog_attribute
*attribute
;
115 struct elog_obj
*elog
;
117 attribute
= to_elog_attr(attr
);
118 elog
= to_elog_obj(kobj
);
120 if (!attribute
->store
)
123 return attribute
->store(elog
, attribute
, buf
, len
);
126 static const struct sysfs_ops elog_sysfs_ops
= {
127 .show
= elog_attr_show
,
128 .store
= elog_attr_store
,
131 static void elog_release(struct kobject
*kobj
)
133 struct elog_obj
*elog
;
135 elog
= to_elog_obj(kobj
);
140 static struct attribute
*elog_default_attrs
[] = {
142 &type_attribute
.attr
,
147 static struct kobj_type elog_ktype
= {
148 .sysfs_ops
= &elog_sysfs_ops
,
149 .release
= &elog_release
,
150 .default_attrs
= elog_default_attrs
,
153 /* Maximum size of a single log on FSP is 16KB */
154 #define OPAL_MAX_ERRLOG_SIZE 16384
156 static ssize_t
raw_attr_read(struct file
*filep
, struct kobject
*kobj
,
157 struct bin_attribute
*bin_attr
,
158 char *buffer
, loff_t pos
, size_t count
)
162 struct elog_obj
*elog
= to_elog_obj(kobj
);
164 /* We may have had an error reading before, so let's retry */
166 elog
->buffer
= kzalloc(elog
->size
, GFP_KERNEL
);
170 opal_rc
= opal_read_elog(__pa(elog
->buffer
),
171 elog
->size
, elog
->id
);
172 if (opal_rc
!= OPAL_SUCCESS
) {
173 pr_err("ELOG: log read failed for log-id=%llx\n",
181 memcpy(buffer
, elog
->buffer
+ pos
, count
);
186 static struct elog_obj
*create_elog_obj(uint64_t id
, size_t size
, uint64_t type
)
188 struct elog_obj
*elog
;
191 elog
= kzalloc(sizeof(*elog
), GFP_KERNEL
);
195 elog
->kobj
.kset
= elog_kset
;
197 kobject_init(&elog
->kobj
, &elog_ktype
);
199 sysfs_bin_attr_init(&elog
->raw_attr
);
201 elog
->raw_attr
.attr
.name
= "raw";
202 elog
->raw_attr
.attr
.mode
= 0400;
203 elog
->raw_attr
.size
= size
;
204 elog
->raw_attr
.read
= raw_attr_read
;
210 elog
->buffer
= kzalloc(elog
->size
, GFP_KERNEL
);
213 rc
= opal_read_elog(__pa(elog
->buffer
),
214 elog
->size
, elog
->id
);
215 if (rc
!= OPAL_SUCCESS
) {
216 pr_err("ELOG: log read failed for log-id=%llx\n",
223 rc
= kobject_add(&elog
->kobj
, NULL
, "0x%llx", id
);
225 kobject_put(&elog
->kobj
);
229 rc
= sysfs_create_bin_file(&elog
->kobj
, &elog
->raw_attr
);
231 kobject_put(&elog
->kobj
);
235 kobject_uevent(&elog
->kobj
, KOBJ_ADD
);
240 static irqreturn_t
elog_event(int irq
, void *data
)
250 struct kobject
*kobj
;
252 rc
= opal_get_elog_size(&id
, &size
, &type
);
253 if (rc
!= OPAL_SUCCESS
) {
254 pr_err("ELOG: OPAL log info read failed\n");
258 elog_size
= be64_to_cpu(size
);
259 log_id
= be64_to_cpu(id
);
260 elog_type
= be64_to_cpu(type
);
262 WARN_ON(elog_size
> OPAL_MAX_ERRLOG_SIZE
);
264 if (elog_size
>= OPAL_MAX_ERRLOG_SIZE
)
265 elog_size
= OPAL_MAX_ERRLOG_SIZE
;
267 sprintf(name
, "0x%llx", log_id
);
269 /* we may get notified twice, let's handle
270 * that gracefully and not create two conflicting
273 kobj
= kset_find_obj(elog_kset
, name
);
275 /* Drop reference added by kset_find_obj() */
280 create_elog_obj(log_id
, elog_size
, elog_type
);
285 int __init
opal_elog_init(void)
289 /* ELOG not supported by firmware */
290 if (!opal_check_token(OPAL_ELOG_READ
))
293 elog_kset
= kset_create_and_add("elog", NULL
, opal_kobj
);
295 pr_warn("%s: failed to create elog kset\n", __func__
);
299 irq
= opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL
));
301 pr_err("%s: Can't register OPAL event irq (%d)\n",
306 rc
= request_threaded_irq(irq
, NULL
, elog_event
,
307 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
, "opal-elog", NULL
);
309 pr_err("%s: Can't request OPAL event irq (%d)\n",
314 /* We are now ready to pull error logs from opal. */
315 if (opal_check_token(OPAL_ELOG_RESEND
))
316 opal_resend_pending_logs();