Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powernv/opal-msglog.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* PowerNV OPAL in-memory console interface
4
*
5
* Copyright 2014 IBM Corp.
6
*/
7
8
#include <asm/io.h>
9
#include <asm/opal.h>
10
#include <linux/debugfs.h>
11
#include <linux/of.h>
12
#include <linux/types.h>
13
#include <asm/barrier.h>
14
15
#include "powernv.h"
16
17
/* OPAL in-memory console. Defined in OPAL source at core/console.c */
18
struct memcons {
19
__be64 magic;
20
#define MEMCONS_MAGIC 0x6630696567726173L
21
__be64 obuf_phys;
22
__be64 ibuf_phys;
23
__be32 obuf_size;
24
__be32 ibuf_size;
25
__be32 out_pos;
26
#define MEMCONS_OUT_POS_WRAP 0x80000000u
27
#define MEMCONS_OUT_POS_MASK 0x00ffffffu
28
__be32 in_prod;
29
__be32 in_cons;
30
};
31
32
static struct memcons *opal_memcons = NULL;
33
34
ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count)
35
{
36
const char *conbuf;
37
ssize_t ret;
38
size_t first_read = 0;
39
uint32_t out_pos, avail;
40
41
if (!mc)
42
return -ENODEV;
43
44
out_pos = be32_to_cpu(READ_ONCE(mc->out_pos));
45
46
/* Now we've read out_pos, put a barrier in before reading the new
47
* data it points to in conbuf. */
48
smp_rmb();
49
50
conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
51
52
/* When the buffer has wrapped, read from the out_pos marker to the end
53
* of the buffer, and then read the remaining data as in the un-wrapped
54
* case. */
55
if (out_pos & MEMCONS_OUT_POS_WRAP) {
56
57
out_pos &= MEMCONS_OUT_POS_MASK;
58
avail = be32_to_cpu(mc->obuf_size) - out_pos;
59
60
ret = memory_read_from_buffer(to, count, &pos,
61
conbuf + out_pos, avail);
62
63
if (ret < 0)
64
goto out;
65
66
first_read = ret;
67
to += first_read;
68
count -= first_read;
69
pos -= avail;
70
71
if (count <= 0)
72
goto out;
73
}
74
75
/* Sanity check. The firmware should not do this to us. */
76
if (out_pos > be32_to_cpu(mc->obuf_size)) {
77
pr_err("OPAL: memory console corruption. Aborting read.\n");
78
return -EINVAL;
79
}
80
81
ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos);
82
83
if (ret < 0)
84
goto out;
85
86
ret += first_read;
87
out:
88
return ret;
89
}
90
91
ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
92
{
93
return memcons_copy(opal_memcons, to, pos, count);
94
}
95
96
static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
97
const struct bin_attribute *bin_attr, char *to,
98
loff_t pos, size_t count)
99
{
100
return opal_msglog_copy(to, pos, count);
101
}
102
103
static struct bin_attribute opal_msglog_attr __ro_after_init = {
104
.attr = {.name = "msglog", .mode = 0400},
105
.read = opal_msglog_read
106
};
107
108
struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name)
109
{
110
u64 mcaddr;
111
struct memcons *mc;
112
113
if (of_property_read_u64(node, mc_prop_name, &mcaddr)) {
114
pr_warn("%s property not found, no message log\n",
115
mc_prop_name);
116
goto out_err;
117
}
118
119
mc = phys_to_virt(mcaddr);
120
if (!mc) {
121
pr_warn("memory console address is invalid\n");
122
goto out_err;
123
}
124
125
if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
126
pr_warn("memory console version is invalid\n");
127
goto out_err;
128
}
129
130
return mc;
131
132
out_err:
133
return NULL;
134
}
135
136
u32 __init memcons_get_size(struct memcons *mc)
137
{
138
return be32_to_cpu(mc->ibuf_size) + be32_to_cpu(mc->obuf_size);
139
}
140
141
void __init opal_msglog_init(void)
142
{
143
opal_memcons = memcons_init(opal_node, "ibm,opal-memcons");
144
if (!opal_memcons) {
145
pr_warn("OPAL: memcons failed to load from ibm,opal-memcons\n");
146
return;
147
}
148
149
opal_msglog_attr.size = memcons_get_size(opal_memcons);
150
}
151
152
void __init opal_msglog_sysfs_init(void)
153
{
154
if (!opal_memcons) {
155
pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
156
return;
157
}
158
159
if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0)
160
pr_warn("OPAL: sysfs file creation failed\n");
161
}
162
163