0001
0002
0003
0004
0005
0006
0007
0008 #include <asm/io.h>
0009 #include <asm/opal.h>
0010 #include <linux/debugfs.h>
0011 #include <linux/of.h>
0012 #include <linux/types.h>
0013 #include <asm/barrier.h>
0014
0015 #include "powernv.h"
0016
0017
0018 struct memcons {
0019 __be64 magic;
0020 #define MEMCONS_MAGIC 0x6630696567726173L
0021 __be64 obuf_phys;
0022 __be64 ibuf_phys;
0023 __be32 obuf_size;
0024 __be32 ibuf_size;
0025 __be32 out_pos;
0026 #define MEMCONS_OUT_POS_WRAP 0x80000000u
0027 #define MEMCONS_OUT_POS_MASK 0x00ffffffu
0028 __be32 in_prod;
0029 __be32 in_cons;
0030 };
0031
0032 static struct memcons *opal_memcons = NULL;
0033
0034 ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count)
0035 {
0036 const char *conbuf;
0037 ssize_t ret;
0038 size_t first_read = 0;
0039 uint32_t out_pos, avail;
0040
0041 if (!mc)
0042 return -ENODEV;
0043
0044 out_pos = be32_to_cpu(READ_ONCE(mc->out_pos));
0045
0046
0047
0048 smp_rmb();
0049
0050 conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
0051
0052
0053
0054
0055 if (out_pos & MEMCONS_OUT_POS_WRAP) {
0056
0057 out_pos &= MEMCONS_OUT_POS_MASK;
0058 avail = be32_to_cpu(mc->obuf_size) - out_pos;
0059
0060 ret = memory_read_from_buffer(to, count, &pos,
0061 conbuf + out_pos, avail);
0062
0063 if (ret < 0)
0064 goto out;
0065
0066 first_read = ret;
0067 to += first_read;
0068 count -= first_read;
0069 pos -= avail;
0070
0071 if (count <= 0)
0072 goto out;
0073 }
0074
0075
0076 if (out_pos > be32_to_cpu(mc->obuf_size)) {
0077 pr_err("OPAL: memory console corruption. Aborting read.\n");
0078 return -EINVAL;
0079 }
0080
0081 ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos);
0082
0083 if (ret < 0)
0084 goto out;
0085
0086 ret += first_read;
0087 out:
0088 return ret;
0089 }
0090
0091 ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
0092 {
0093 return memcons_copy(opal_memcons, to, pos, count);
0094 }
0095
0096 static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
0097 struct bin_attribute *bin_attr, char *to,
0098 loff_t pos, size_t count)
0099 {
0100 return opal_msglog_copy(to, pos, count);
0101 }
0102
0103 static struct bin_attribute opal_msglog_attr = {
0104 .attr = {.name = "msglog", .mode = 0400},
0105 .read = opal_msglog_read
0106 };
0107
0108 struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name)
0109 {
0110 u64 mcaddr;
0111 struct memcons *mc;
0112
0113 if (of_property_read_u64(node, mc_prop_name, &mcaddr)) {
0114 pr_warn("%s property not found, no message log\n",
0115 mc_prop_name);
0116 goto out_err;
0117 }
0118
0119 mc = phys_to_virt(mcaddr);
0120 if (!mc) {
0121 pr_warn("memory console address is invalid\n");
0122 goto out_err;
0123 }
0124
0125 if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
0126 pr_warn("memory console version is invalid\n");
0127 goto out_err;
0128 }
0129
0130 return mc;
0131
0132 out_err:
0133 return NULL;
0134 }
0135
0136 u32 __init memcons_get_size(struct memcons *mc)
0137 {
0138 return be32_to_cpu(mc->ibuf_size) + be32_to_cpu(mc->obuf_size);
0139 }
0140
0141 void __init opal_msglog_init(void)
0142 {
0143 opal_memcons = memcons_init(opal_node, "ibm,opal-memcons");
0144 if (!opal_memcons) {
0145 pr_warn("OPAL: memcons failed to load from ibm,opal-memcons\n");
0146 return;
0147 }
0148
0149 opal_msglog_attr.size = memcons_get_size(opal_memcons);
0150 }
0151
0152 void __init opal_msglog_sysfs_init(void)
0153 {
0154 if (!opal_memcons) {
0155 pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
0156 return;
0157 }
0158
0159 if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0)
0160 pr_warn("OPAL: sysfs file creation failed\n");
0161 }