1/*
2 * Error log support on PowerNV.
3 *
4 * Copyright 2013,2014 IBM Corp.
5 *
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.
10 */
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/of.h>
14#include <linux/slab.h>
15#include <linux/sysfs.h>
16#include <linux/fs.h>
17#include <linux/vmalloc.h>
18#include <linux/fcntl.h>
19#include <linux/kobject.h>
20#include <asm/uaccess.h>
21#include <asm/opal.h>
22
23struct elog_obj {
24	struct kobject kobj;
25	struct bin_attribute raw_attr;
26	uint64_t id;
27	uint64_t type;
28	size_t size;
29	char *buffer;
30};
31#define to_elog_obj(x) container_of(x, struct elog_obj, kobj)
32
33struct elog_attribute {
34	struct attribute attr;
35	ssize_t (*show)(struct elog_obj *elog, struct elog_attribute *attr,
36			char *buf);
37	ssize_t (*store)(struct elog_obj *elog, struct elog_attribute *attr,
38			 const char *buf, size_t count);
39};
40#define to_elog_attr(x) container_of(x, struct elog_attribute, attr)
41
42static ssize_t elog_id_show(struct elog_obj *elog_obj,
43			    struct elog_attribute *attr,
44			    char *buf)
45{
46	return sprintf(buf, "0x%llx\n", elog_obj->id);
47}
48
49static const char *elog_type_to_string(uint64_t type)
50{
51	switch (type) {
52	case 0: return "PEL";
53	default: return "unknown";
54	}
55}
56
57static ssize_t elog_type_show(struct elog_obj *elog_obj,
58			      struct elog_attribute *attr,
59			      char *buf)
60{
61	return sprintf(buf, "0x%llx %s\n",
62		       elog_obj->type,
63		       elog_type_to_string(elog_obj->type));
64}
65
66static ssize_t elog_ack_show(struct elog_obj *elog_obj,
67			     struct elog_attribute *attr,
68			     char *buf)
69{
70	return sprintf(buf, "ack - acknowledge log message\n");
71}
72
73static ssize_t elog_ack_store(struct elog_obj *elog_obj,
74			      struct elog_attribute *attr,
75			      const char *buf,
76			      size_t count)
77{
78	opal_send_ack_elog(elog_obj->id);
79	sysfs_remove_file_self(&elog_obj->kobj, &attr->attr);
80	kobject_put(&elog_obj->kobj);
81	return count;
82}
83
84static struct elog_attribute id_attribute =
85	__ATTR(id, S_IRUGO, elog_id_show, NULL);
86static struct elog_attribute type_attribute =
87	__ATTR(type, S_IRUGO, elog_type_show, NULL);
88static struct elog_attribute ack_attribute =
89	__ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store);
90
91static struct kset *elog_kset;
92
93static ssize_t elog_attr_show(struct kobject *kobj,
94			      struct attribute *attr,
95			      char *buf)
96{
97	struct elog_attribute *attribute;
98	struct elog_obj *elog;
99
100	attribute = to_elog_attr(attr);
101	elog = to_elog_obj(kobj);
102
103	if (!attribute->show)
104		return -EIO;
105
106	return attribute->show(elog, attribute, buf);
107}
108
109static ssize_t elog_attr_store(struct kobject *kobj,
110			       struct attribute *attr,
111			       const char *buf, size_t len)
112{
113	struct elog_attribute *attribute;
114	struct elog_obj *elog;
115
116	attribute = to_elog_attr(attr);
117	elog = to_elog_obj(kobj);
118
119	if (!attribute->store)
120		return -EIO;
121
122	return attribute->store(elog, attribute, buf, len);
123}
124
125static const struct sysfs_ops elog_sysfs_ops = {
126	.show = elog_attr_show,
127	.store = elog_attr_store,
128};
129
130static void elog_release(struct kobject *kobj)
131{
132	struct elog_obj *elog;
133
134	elog = to_elog_obj(kobj);
135	kfree(elog->buffer);
136	kfree(elog);
137}
138
139static struct attribute *elog_default_attrs[] = {
140	&id_attribute.attr,
141	&type_attribute.attr,
142	&ack_attribute.attr,
143	NULL,
144};
145
146static struct kobj_type elog_ktype = {
147	.sysfs_ops = &elog_sysfs_ops,
148	.release = &elog_release,
149	.default_attrs = elog_default_attrs,
150};
151
152/* Maximum size of a single log on FSP is 16KB */
153#define OPAL_MAX_ERRLOG_SIZE	16384
154
155static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
156			     struct bin_attribute *bin_attr,
157			     char *buffer, loff_t pos, size_t count)
158{
159	int opal_rc;
160
161	struct elog_obj *elog = to_elog_obj(kobj);
162
163	/* We may have had an error reading before, so let's retry */
164	if (!elog->buffer) {
165		elog->buffer = kzalloc(elog->size, GFP_KERNEL);
166		if (!elog->buffer)
167			return -EIO;
168
169		opal_rc = opal_read_elog(__pa(elog->buffer),
170					 elog->size, elog->id);
171		if (opal_rc != OPAL_SUCCESS) {
172			pr_err("ELOG: log read failed for log-id=%llx\n",
173			       elog->id);
174			kfree(elog->buffer);
175			elog->buffer = NULL;
176			return -EIO;
177		}
178	}
179
180	memcpy(buffer, elog->buffer + pos, count);
181
182	return count;
183}
184
185static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
186{
187	struct elog_obj *elog;
188	int rc;
189
190	elog = kzalloc(sizeof(*elog), GFP_KERNEL);
191	if (!elog)
192		return NULL;
193
194	elog->kobj.kset = elog_kset;
195
196	kobject_init(&elog->kobj, &elog_ktype);
197
198	sysfs_bin_attr_init(&elog->raw_attr);
199
200	elog->raw_attr.attr.name = "raw";
201	elog->raw_attr.attr.mode = 0400;
202	elog->raw_attr.size = size;
203	elog->raw_attr.read = raw_attr_read;
204
205	elog->id = id;
206	elog->size = size;
207	elog->type = type;
208
209	elog->buffer = kzalloc(elog->size, GFP_KERNEL);
210
211	if (elog->buffer) {
212		rc = opal_read_elog(__pa(elog->buffer),
213					 elog->size, elog->id);
214		if (rc != OPAL_SUCCESS) {
215			pr_err("ELOG: log read failed for log-id=%llx\n",
216			       elog->id);
217			kfree(elog->buffer);
218			elog->buffer = NULL;
219		}
220	}
221
222	rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
223	if (rc) {
224		kobject_put(&elog->kobj);
225		return NULL;
226	}
227
228	rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
229	if (rc) {
230		kobject_put(&elog->kobj);
231		return NULL;
232	}
233
234	kobject_uevent(&elog->kobj, KOBJ_ADD);
235
236	return elog;
237}
238
239static void elog_work_fn(struct work_struct *work)
240{
241	__be64 size;
242	__be64 id;
243	__be64 type;
244	uint64_t elog_size;
245	uint64_t log_id;
246	uint64_t elog_type;
247	int rc;
248	char name[2+16+1];
249
250	rc = opal_get_elog_size(&id, &size, &type);
251	if (rc != OPAL_SUCCESS) {
252		pr_err("ELOG: OPAL log info read failed\n");
253		return;
254	}
255
256	elog_size = be64_to_cpu(size);
257	log_id = be64_to_cpu(id);
258	elog_type = be64_to_cpu(type);
259
260	WARN_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
261
262	if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
263		elog_size  =  OPAL_MAX_ERRLOG_SIZE;
264
265	sprintf(name, "0x%llx", log_id);
266
267	/* we may get notified twice, let's handle
268	 * that gracefully and not create two conflicting
269	 * entries.
270	 */
271	if (kset_find_obj(elog_kset, name))
272		return;
273
274	create_elog_obj(log_id, elog_size, elog_type);
275}
276
277static DECLARE_WORK(elog_work, elog_work_fn);
278
279static int elog_event(struct notifier_block *nb,
280				unsigned long events, void *change)
281{
282	/* check for error log event */
283	if (events & OPAL_EVENT_ERROR_LOG_AVAIL)
284		schedule_work(&elog_work);
285	return 0;
286}
287
288static struct notifier_block elog_nb = {
289	.notifier_call  = elog_event,
290	.next           = NULL,
291	.priority       = 0
292};
293
294int __init opal_elog_init(void)
295{
296	int rc = 0;
297
298	/* ELOG not supported by firmware */
299	if (!opal_check_token(OPAL_ELOG_READ))
300		return -1;
301
302	elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
303	if (!elog_kset) {
304		pr_warn("%s: failed to create elog kset\n", __func__);
305		return -1;
306	}
307
308	rc = opal_notifier_register(&elog_nb);
309	if (rc) {
310		pr_err("%s: Can't register OPAL event notifier (%d)\n",
311		__func__, rc);
312		return rc;
313	}
314
315	/* We are now ready to pull error logs from opal. */
316	if (opal_check_token(OPAL_ELOG_RESEND))
317		opal_resend_pending_logs();
318
319	return 0;
320}
321