forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
powerpc/powernv: Add OPAL message log interface
OPAL provides an in-memory circular buffer containing a message log populated with various runtime messages produced by the firmware. Provide a sysfs interface /sys/firmware/opal/msglog for userspace to view the messages. Signed-off-by: Joel Stanley <[email protected]> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
- Loading branch information
Showing
4 changed files
with
128 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* PowerNV OPAL in-memory console interface | ||
* | ||
* Copyright 2014 IBM Corp. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
*/ | ||
|
||
#include <asm/io.h> | ||
#include <asm/opal.h> | ||
#include <linux/debugfs.h> | ||
#include <linux/of.h> | ||
#include <linux/types.h> | ||
#include <asm/barrier.h> | ||
|
||
/* OPAL in-memory console. Defined in OPAL source at core/console.c */ | ||
struct memcons { | ||
__be64 magic; | ||
#define MEMCONS_MAGIC 0x6630696567726173L | ||
__be64 obuf_phys; | ||
__be64 ibuf_phys; | ||
__be32 obuf_size; | ||
__be32 ibuf_size; | ||
__be32 out_pos; | ||
#define MEMCONS_OUT_POS_WRAP 0x80000000u | ||
#define MEMCONS_OUT_POS_MASK 0x00ffffffu | ||
__be32 in_prod; | ||
__be32 in_cons; | ||
}; | ||
|
||
static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj, | ||
struct bin_attribute *bin_attr, char *to, | ||
loff_t pos, size_t count) | ||
{ | ||
struct memcons *mc = bin_attr->private; | ||
const char *conbuf; | ||
size_t ret, first_read = 0; | ||
uint32_t out_pos, avail; | ||
|
||
if (!mc) | ||
return -ENODEV; | ||
|
||
out_pos = be32_to_cpu(ACCESS_ONCE(mc->out_pos)); | ||
|
||
/* Now we've read out_pos, put a barrier in before reading the new | ||
* data it points to in conbuf. */ | ||
smp_rmb(); | ||
|
||
conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys)); | ||
|
||
/* When the buffer has wrapped, read from the out_pos marker to the end | ||
* of the buffer, and then read the remaining data as in the un-wrapped | ||
* case. */ | ||
if (out_pos & MEMCONS_OUT_POS_WRAP) { | ||
|
||
out_pos &= MEMCONS_OUT_POS_MASK; | ||
avail = be32_to_cpu(mc->obuf_size) - out_pos; | ||
|
||
ret = memory_read_from_buffer(to, count, &pos, | ||
conbuf + out_pos, avail); | ||
|
||
if (ret < 0) | ||
goto out; | ||
|
||
first_read = ret; | ||
to += first_read; | ||
count -= first_read; | ||
pos -= avail; | ||
} | ||
|
||
/* Sanity check. The firmware should not do this to us. */ | ||
if (out_pos > be32_to_cpu(mc->obuf_size)) { | ||
pr_err("OPAL: memory console corruption. Aborting read.\n"); | ||
return -EINVAL; | ||
} | ||
|
||
ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos); | ||
|
||
if (ret < 0) | ||
goto out; | ||
|
||
ret += first_read; | ||
out: | ||
return ret; | ||
} | ||
|
||
static struct bin_attribute opal_msglog_attr = { | ||
.attr = {.name = "msglog", .mode = 0444}, | ||
.read = opal_msglog_read | ||
}; | ||
|
||
void __init opal_msglog_init(void) | ||
{ | ||
u64 mcaddr; | ||
struct memcons *mc; | ||
|
||
if (of_property_read_u64(opal_node, "ibm,opal-memcons", &mcaddr)) { | ||
pr_warn("OPAL: Property ibm,opal-memcons not found, no message log\n"); | ||
return; | ||
} | ||
|
||
mc = phys_to_virt(mcaddr); | ||
if (!mc) { | ||
pr_warn("OPAL: memory console address is invalid\n"); | ||
return; | ||
} | ||
|
||
if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) { | ||
pr_warn("OPAL: memory console version is invalid\n"); | ||
return; | ||
} | ||
|
||
opal_msglog_attr.private = mc; | ||
|
||
if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0) | ||
pr_warn("OPAL: sysfs file creation failed\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters