Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powernv/opal-psr.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* PowerNV OPAL Power-Shift-Ratio interface
4
*
5
* Copyright 2017 IBM Corp.
6
*/
7
8
#define pr_fmt(fmt) "opal-psr: " fmt
9
10
#include <linux/of.h>
11
#include <linux/kobject.h>
12
#include <linux/slab.h>
13
14
#include <asm/opal.h>
15
16
static DEFINE_MUTEX(psr_mutex);
17
18
static struct kobject *psr_kobj;
19
20
static struct psr_attr {
21
u32 handle;
22
struct kobj_attribute attr;
23
} *psr_attrs;
24
25
static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
26
char *buf)
27
{
28
struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
29
struct opal_msg msg;
30
int psr, ret, token;
31
32
token = opal_async_get_token_interruptible();
33
if (token < 0) {
34
pr_devel("Failed to get token\n");
35
return token;
36
}
37
38
ret = mutex_lock_interruptible(&psr_mutex);
39
if (ret)
40
goto out_token;
41
42
ret = opal_get_power_shift_ratio(psr_attr->handle, token,
43
(u32 *)__pa(&psr));
44
switch (ret) {
45
case OPAL_ASYNC_COMPLETION:
46
ret = opal_async_wait_response(token, &msg);
47
if (ret) {
48
pr_devel("Failed to wait for the async response\n");
49
ret = -EIO;
50
goto out;
51
}
52
ret = opal_error_code(opal_get_async_rc(msg));
53
if (!ret) {
54
ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
55
if (ret < 0)
56
ret = -EIO;
57
}
58
break;
59
case OPAL_SUCCESS:
60
ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
61
if (ret < 0)
62
ret = -EIO;
63
break;
64
default:
65
ret = opal_error_code(ret);
66
}
67
68
out:
69
mutex_unlock(&psr_mutex);
70
out_token:
71
opal_async_release_token(token);
72
return ret;
73
}
74
75
static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
76
const char *buf, size_t count)
77
{
78
struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
79
struct opal_msg msg;
80
int psr, ret, token;
81
82
ret = kstrtoint(buf, 0, &psr);
83
if (ret)
84
return ret;
85
86
token = opal_async_get_token_interruptible();
87
if (token < 0) {
88
pr_devel("Failed to get token\n");
89
return token;
90
}
91
92
ret = mutex_lock_interruptible(&psr_mutex);
93
if (ret)
94
goto out_token;
95
96
ret = opal_set_power_shift_ratio(psr_attr->handle, token, psr);
97
switch (ret) {
98
case OPAL_ASYNC_COMPLETION:
99
ret = opal_async_wait_response(token, &msg);
100
if (ret) {
101
pr_devel("Failed to wait for the async response\n");
102
ret = -EIO;
103
goto out;
104
}
105
ret = opal_error_code(opal_get_async_rc(msg));
106
if (!ret)
107
ret = count;
108
break;
109
case OPAL_SUCCESS:
110
ret = count;
111
break;
112
default:
113
ret = opal_error_code(ret);
114
}
115
116
out:
117
mutex_unlock(&psr_mutex);
118
out_token:
119
opal_async_release_token(token);
120
return ret;
121
}
122
123
void __init opal_psr_init(void)
124
{
125
struct device_node *psr, *node;
126
int i = 0;
127
128
psr = of_find_compatible_node(NULL, NULL,
129
"ibm,opal-power-shift-ratio");
130
if (!psr) {
131
pr_devel("Power-shift-ratio node not found\n");
132
return;
133
}
134
135
psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs),
136
GFP_KERNEL);
137
if (!psr_attrs)
138
goto out_put_psr;
139
140
psr_kobj = kobject_create_and_add("psr", opal_kobj);
141
if (!psr_kobj) {
142
pr_warn("Failed to create psr kobject\n");
143
goto out;
144
}
145
146
for_each_child_of_node(psr, node) {
147
if (of_property_read_u32(node, "handle",
148
&psr_attrs[i].handle))
149
goto out_kobj;
150
151
sysfs_attr_init(&psr_attrs[i].attr.attr);
152
if (of_property_read_string(node, "label",
153
&psr_attrs[i].attr.attr.name))
154
goto out_kobj;
155
psr_attrs[i].attr.attr.mode = 0664;
156
psr_attrs[i].attr.show = psr_show;
157
psr_attrs[i].attr.store = psr_store;
158
if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
159
pr_devel("Failed to create psr sysfs file %s\n",
160
psr_attrs[i].attr.attr.name);
161
goto out_kobj;
162
}
163
i++;
164
}
165
of_node_put(psr);
166
167
return;
168
out_kobj:
169
of_node_put(node);
170
kobject_put(psr_kobj);
171
out:
172
kfree(psr_attrs);
173
out_put_psr:
174
of_node_put(psr);
175
}
176
177