linux/arch/powerpc/platforms/powernv/opal-elog.c
<<
>>
Prefs
   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
  20struct 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
  30struct 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
  39static 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
  46static 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
  54static 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
  63static 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
  70static 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
  86static struct elog_attribute id_attribute =
  87        __ATTR(id, 0444, elog_id_show, NULL);
  88static struct elog_attribute type_attribute =
  89        __ATTR(type, 0444, elog_type_show, NULL);
  90static struct elog_attribute ack_attribute =
  91        __ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store);
  92
  93static struct kset *elog_kset;
  94
  95static 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
 111static 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
 127static const struct sysfs_ops elog_sysfs_ops = {
 128        .show = elog_attr_show,
 129        .store = elog_attr_store,
 130};
 131
 132static 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
 141static struct attribute *elog_default_attrs[] = {
 142        &id_attribute.attr,
 143        &type_attribute.attr,
 144        &ack_attribute.attr,
 145        NULL,
 146};
 147
 148static struct kobj_type elog_ktype = {
 149        .sysfs_ops = &elog_sysfs_ops,
 150        .release = &elog_release,
 151        .default_attrs = elog_default_attrs,
 152};
 153
 154/* Maximum size of a single log on FSP is 16KB */
 155#define OPAL_MAX_ERRLOG_SIZE    16384
 156
 157static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
 158                             struct bin_attribute *bin_attr,
 159                             char *buffer, loff_t pos, size_t count)
 160{
 161        int opal_rc;
 162
 163        struct elog_obj *elog = to_elog_obj(kobj);
 164
 165        /* We may have had an error reading before, so let's retry */
 166        if (!elog->buffer) {
 167                elog->buffer = kzalloc(elog->size, GFP_KERNEL);
 168                if (!elog->buffer)
 169                        return -EIO;
 170
 171                opal_rc = opal_read_elog(__pa(elog->buffer),
 172                                         elog->size, elog->id);
 173                if (opal_rc != OPAL_SUCCESS) {
 174                        pr_err("ELOG: log read failed for log-id=%llx\n",
 175                               elog->id);
 176                        kfree(elog->buffer);
 177                        elog->buffer = NULL;
 178                        return -EIO;
 179                }
 180        }
 181
 182        memcpy(buffer, elog->buffer + pos, count);
 183
 184        return count;
 185}
 186
 187static void create_elog_obj(uint64_t id, size_t size, uint64_t type)
 188{
 189        struct elog_obj *elog;
 190        int rc;
 191
 192        elog = kzalloc(sizeof(*elog), GFP_KERNEL);
 193        if (!elog)
 194                return;
 195
 196        elog->kobj.kset = elog_kset;
 197
 198        kobject_init(&elog->kobj, &elog_ktype);
 199
 200        sysfs_bin_attr_init(&elog->raw_attr);
 201
 202        elog->raw_attr.attr.name = "raw";
 203        elog->raw_attr.attr.mode = 0400;
 204        elog->raw_attr.size = size;
 205        elog->raw_attr.read = raw_attr_read;
 206
 207        elog->id = id;
 208        elog->size = size;
 209        elog->type = type;
 210
 211        elog->buffer = kzalloc(elog->size, GFP_KERNEL);
 212
 213        if (elog->buffer) {
 214                rc = opal_read_elog(__pa(elog->buffer),
 215                                         elog->size, elog->id);
 216                if (rc != OPAL_SUCCESS) {
 217                        pr_err("ELOG: log read failed for log-id=%llx\n",
 218                               elog->id);
 219                        kfree(elog->buffer);
 220                        elog->buffer = NULL;
 221                }
 222        }
 223
 224        rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
 225        if (rc) {
 226                kobject_put(&elog->kobj);
 227                return;
 228        }
 229
 230        /*
 231         * As soon as the sysfs file for this elog is created/activated there is
 232         * a chance the opal_errd daemon (or any userspace) might read and
 233         * acknowledge the elog before kobject_uevent() is called. If that
 234         * happens then there is a potential race between
 235         * elog_ack_store->kobject_put() and kobject_uevent() which leads to a
 236         * use-after-free of a kernfs object resulting in a kernel crash.
 237         *
 238         * To avoid that, we need to take a reference on behalf of the bin file,
 239         * so that our reference remains valid while we call kobject_uevent().
 240         * We then drop our reference before exiting the function, leaving the
 241         * bin file to drop the last reference (if it hasn't already).
 242         */
 243
 244        /* Take a reference for the bin file */
 245        kobject_get(&elog->kobj);
 246        rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
 247        if (rc == 0) {
 248                kobject_uevent(&elog->kobj, KOBJ_ADD);
 249        } else {
 250                /* Drop the reference taken for the bin file */
 251                kobject_put(&elog->kobj);
 252        }
 253
 254        /* Drop our reference */
 255        kobject_put(&elog->kobj);
 256
 257        return;
 258}
 259
 260static irqreturn_t elog_event(int irq, void *data)
 261{
 262        __be64 size;
 263        __be64 id;
 264        __be64 type;
 265        uint64_t elog_size;
 266        uint64_t log_id;
 267        uint64_t elog_type;
 268        int rc;
 269        char name[2+16+1];
 270        struct kobject *kobj;
 271
 272        rc = opal_get_elog_size(&id, &size, &type);
 273        if (rc != OPAL_SUCCESS) {
 274                pr_err("ELOG: OPAL log info read failed\n");
 275                return IRQ_HANDLED;
 276        }
 277
 278        elog_size = be64_to_cpu(size);
 279        log_id = be64_to_cpu(id);
 280        elog_type = be64_to_cpu(type);
 281
 282        WARN_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
 283
 284        if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
 285                elog_size  =  OPAL_MAX_ERRLOG_SIZE;
 286
 287        sprintf(name, "0x%llx", log_id);
 288
 289        /* we may get notified twice, let's handle
 290         * that gracefully and not create two conflicting
 291         * entries.
 292         */
 293        kobj = kset_find_obj(elog_kset, name);
 294        if (kobj) {
 295                /* Drop reference added by kset_find_obj() */
 296                kobject_put(kobj);
 297                return IRQ_HANDLED;
 298        }
 299
 300        create_elog_obj(log_id, elog_size, elog_type);
 301
 302        return IRQ_HANDLED;
 303}
 304
 305int __init opal_elog_init(void)
 306{
 307        int rc = 0, irq;
 308
 309        /* ELOG not supported by firmware */
 310        if (!opal_check_token(OPAL_ELOG_READ))
 311                return -1;
 312
 313        elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
 314        if (!elog_kset) {
 315                pr_warn("%s: failed to create elog kset\n", __func__);
 316                return -1;
 317        }
 318
 319        irq = opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL));
 320        if (!irq) {
 321                pr_err("%s: Can't register OPAL event irq (%d)\n",
 322                       __func__, irq);
 323                return irq;
 324        }
 325
 326        rc = request_threaded_irq(irq, NULL, elog_event,
 327                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "opal-elog", NULL);
 328        if (rc) {
 329                pr_err("%s: Can't request OPAL event irq (%d)\n",
 330                       __func__, rc);
 331                return rc;
 332        }
 333
 334        /* We are now ready to pull error logs from opal. */
 335        if (opal_check_token(OPAL_ELOG_RESEND))
 336                opal_resend_pending_logs();
 337
 338        return 0;
 339}
 340