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