2 * PowerNV OPAL Powercap interface
4 * Copyright 2017 IBM Corp.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define pr_fmt(fmt) "opal-powercap: " fmt
15 #include <linux/kobject.h>
16 #include <linux/slab.h>
20 DEFINE_MUTEX(powercap_mutex
);
22 static struct kobject
*powercap_kobj
;
24 struct powercap_attr
{
26 struct kobj_attribute attr
;
30 struct attribute_group pg
;
31 struct powercap_attr
*pattrs
;
34 static ssize_t
powercap_show(struct kobject
*kobj
, struct kobj_attribute
*attr
,
37 struct powercap_attr
*pcap_attr
= container_of(attr
,
38 struct powercap_attr
, attr
);
43 token
= opal_async_get_token_interruptible();
45 pr_devel("Failed to get token\n");
49 ret
= mutex_lock_interruptible(&powercap_mutex
);
53 ret
= opal_get_powercap(pcap_attr
->handle
, token
, (u32
*)__pa(&pcap
));
55 case OPAL_ASYNC_COMPLETION
:
56 ret
= opal_async_wait_response(token
, &msg
);
58 pr_devel("Failed to wait for the async response\n");
62 ret
= opal_error_code(opal_get_async_rc(msg
));
64 ret
= sprintf(buf
, "%u\n", be32_to_cpu(pcap
));
70 ret
= sprintf(buf
, "%u\n", be32_to_cpu(pcap
));
75 ret
= opal_error_code(ret
);
79 mutex_unlock(&powercap_mutex
);
81 opal_async_release_token(token
);
85 static ssize_t
powercap_store(struct kobject
*kobj
,
86 struct kobj_attribute
*attr
, const char *buf
,
89 struct powercap_attr
*pcap_attr
= container_of(attr
,
90 struct powercap_attr
, attr
);
95 ret
= kstrtoint(buf
, 0, &pcap
);
99 token
= opal_async_get_token_interruptible();
101 pr_devel("Failed to get token\n");
105 ret
= mutex_lock_interruptible(&powercap_mutex
);
109 ret
= opal_set_powercap(pcap_attr
->handle
, token
, pcap
);
111 case OPAL_ASYNC_COMPLETION
:
112 ret
= opal_async_wait_response(token
, &msg
);
114 pr_devel("Failed to wait for the async response\n");
118 ret
= opal_error_code(opal_get_async_rc(msg
));
126 ret
= opal_error_code(ret
);
130 mutex_unlock(&powercap_mutex
);
132 opal_async_release_token(token
);
136 static void powercap_add_attr(int handle
, const char *name
,
137 struct powercap_attr
*attr
)
139 attr
->handle
= handle
;
140 sysfs_attr_init(&attr
->attr
.attr
);
141 attr
->attr
.attr
.name
= name
;
142 attr
->attr
.attr
.mode
= 0444;
143 attr
->attr
.show
= powercap_show
;
146 void __init
opal_powercap_init(void)
148 struct device_node
*powercap
, *node
;
151 powercap
= of_find_compatible_node(NULL
, NULL
, "ibm,opal-powercap");
153 pr_devel("Powercap node not found\n");
157 pcaps
= kcalloc(of_get_child_count(powercap
), sizeof(*pcaps
),
162 powercap_kobj
= kobject_create_and_add("powercap", opal_kobj
);
163 if (!powercap_kobj
) {
164 pr_warn("Failed to create powercap kobject\n");
169 for_each_child_of_node(powercap
, node
) {
172 bool has_cur
= false, has_min
= false, has_max
= false;
174 if (!of_property_read_u32(node
, "powercap-min", &min
)) {
179 if (!of_property_read_u32(node
, "powercap-max", &max
)) {
184 if (!of_property_read_u32(node
, "powercap-current", &cur
)) {
189 pcaps
[i
].pattrs
= kcalloc(j
, sizeof(struct powercap_attr
),
191 if (!pcaps
[i
].pattrs
)
192 goto out_pcaps_pattrs
;
194 pcaps
[i
].pg
.attrs
= kcalloc(j
+ 1, sizeof(struct attribute
*),
196 if (!pcaps
[i
].pg
.attrs
) {
197 kfree(pcaps
[i
].pattrs
);
198 goto out_pcaps_pattrs
;
202 pcaps
[i
].pg
.name
= node
->name
;
204 powercap_add_attr(min
, "powercap-min",
205 &pcaps
[i
].pattrs
[j
]);
206 pcaps
[i
].pg
.attrs
[j
] = &pcaps
[i
].pattrs
[j
].attr
.attr
;
211 powercap_add_attr(max
, "powercap-max",
212 &pcaps
[i
].pattrs
[j
]);
213 pcaps
[i
].pg
.attrs
[j
] = &pcaps
[i
].pattrs
[j
].attr
.attr
;
218 powercap_add_attr(cur
, "powercap-current",
219 &pcaps
[i
].pattrs
[j
]);
220 pcaps
[i
].pattrs
[j
].attr
.attr
.mode
|= 0220;
221 pcaps
[i
].pattrs
[j
].attr
.store
= powercap_store
;
222 pcaps
[i
].pg
.attrs
[j
] = &pcaps
[i
].pattrs
[j
].attr
.attr
;
226 if (sysfs_create_group(powercap_kobj
, &pcaps
[i
].pg
)) {
227 pr_warn("Failed to create powercap attribute group %s\n",
229 goto out_pcaps_pattrs
;
238 kfree(pcaps
[i
].pattrs
);
239 kfree(pcaps
[i
].pg
.attrs
);
241 kobject_put(powercap_kobj
);