~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/powernv/opal-powercap.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * PowerNV OPAL Powercap interface
  3  *
  4  * Copyright 2017 IBM Corp.
  5  *
  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.
 10  */
 11 
 12 #define pr_fmt(fmt)     "opal-powercap: " fmt
 13 
 14 #include <linux/of.h>
 15 #include <linux/kobject.h>
 16 #include <linux/slab.h>
 17 
 18 #include <asm/opal.h>
 19 
 20 DEFINE_MUTEX(powercap_mutex);
 21 
 22 static struct kobject *powercap_kobj;
 23 
 24 struct powercap_attr {
 25         u32 handle;
 26         struct kobj_attribute attr;
 27 };
 28 
 29 static struct pcap {
 30         struct attribute_group pg;
 31         struct powercap_attr *pattrs;
 32 } *pcaps;
 33 
 34 static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr,
 35                              char *buf)
 36 {
 37         struct powercap_attr *pcap_attr = container_of(attr,
 38                                                 struct powercap_attr, attr);
 39         struct opal_msg msg;
 40         u32 pcap;
 41         int ret, token;
 42 
 43         token = opal_async_get_token_interruptible();
 44         if (token < 0) {
 45                 pr_devel("Failed to get token\n");
 46                 return token;
 47         }
 48 
 49         ret = mutex_lock_interruptible(&powercap_mutex);
 50         if (ret)
 51                 goto out_token;
 52 
 53         ret = opal_get_powercap(pcap_attr->handle, token, (u32 *)__pa(&pcap));
 54         switch (ret) {
 55         case OPAL_ASYNC_COMPLETION:
 56                 ret = opal_async_wait_response(token, &msg);
 57                 if (ret) {
 58                         pr_devel("Failed to wait for the async response\n");
 59                         ret = -EIO;
 60                         goto out;
 61                 }
 62                 ret = opal_error_code(opal_get_async_rc(msg));
 63                 if (!ret) {
 64                         ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
 65                         if (ret < 0)
 66                                 ret = -EIO;
 67                 }
 68                 break;
 69         case OPAL_SUCCESS:
 70                 ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
 71                 if (ret < 0)
 72                         ret = -EIO;
 73                 break;
 74         default:
 75                 ret = opal_error_code(ret);
 76         }
 77 
 78 out:
 79         mutex_unlock(&powercap_mutex);
 80 out_token:
 81         opal_async_release_token(token);
 82         return ret;
 83 }
 84 
 85 static ssize_t powercap_store(struct kobject *kobj,
 86                               struct kobj_attribute *attr, const char *buf,
 87                               size_t count)
 88 {
 89         struct powercap_attr *pcap_attr = container_of(attr,
 90                                                 struct powercap_attr, attr);
 91         struct opal_msg msg;
 92         u32 pcap;
 93         int ret, token;
 94 
 95         ret = kstrtoint(buf, 0, &pcap);
 96         if (ret)
 97                 return ret;
 98 
 99         token = opal_async_get_token_interruptible();
100         if (token < 0) {
101                 pr_devel("Failed to get token\n");
102                 return token;
103         }
104 
105         ret = mutex_lock_interruptible(&powercap_mutex);
106         if (ret)
107                 goto out_token;
108 
109         ret = opal_set_powercap(pcap_attr->handle, token, pcap);
110         switch (ret) {
111         case OPAL_ASYNC_COMPLETION:
112                 ret = opal_async_wait_response(token, &msg);
113                 if (ret) {
114                         pr_devel("Failed to wait for the async response\n");
115                         ret = -EIO;
116                         goto out;
117                 }
118                 ret = opal_error_code(opal_get_async_rc(msg));
119                 if (!ret)
120                         ret = count;
121                 break;
122         case OPAL_SUCCESS:
123                 ret = count;
124                 break;
125         default:
126                 ret = opal_error_code(ret);
127         }
128 
129 out:
130         mutex_unlock(&powercap_mutex);
131 out_token:
132         opal_async_release_token(token);
133         return ret;
134 }
135 
136 static void powercap_add_attr(int handle, const char *name,
137                               struct powercap_attr *attr)
138 {
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;
144 }
145 
146 void __init opal_powercap_init(void)
147 {
148         struct device_node *powercap, *node;
149         int i = 0;
150 
151         powercap = of_find_compatible_node(NULL, NULL, "ibm,opal-powercap");
152         if (!powercap) {
153                 pr_devel("Powercap node not found\n");
154                 return;
155         }
156 
157         pcaps = kcalloc(of_get_child_count(powercap), sizeof(*pcaps),
158                         GFP_KERNEL);
159         if (!pcaps)
160                 return;
161 
162         powercap_kobj = kobject_create_and_add("powercap", opal_kobj);
163         if (!powercap_kobj) {
164                 pr_warn("Failed to create powercap kobject\n");
165                 goto out_pcaps;
166         }
167 
168         i = 0;
169         for_each_child_of_node(powercap, node) {
170                 u32 cur, min, max;
171                 int j = 0;
172                 bool has_cur = false, has_min = false, has_max = false;
173 
174                 if (!of_property_read_u32(node, "powercap-min", &min)) {
175                         j++;
176                         has_min = true;
177                 }
178 
179                 if (!of_property_read_u32(node, "powercap-max", &max)) {
180                         j++;
181                         has_max = true;
182                 }
183 
184                 if (!of_property_read_u32(node, "powercap-current", &cur)) {
185                         j++;
186                         has_cur = true;
187                 }
188 
189                 pcaps[i].pattrs = kcalloc(j, sizeof(struct powercap_attr),
190                                           GFP_KERNEL);
191                 if (!pcaps[i].pattrs)
192                         goto out_pcaps_pattrs;
193 
194                 pcaps[i].pg.attrs = kcalloc(j + 1, sizeof(struct attribute *),
195                                             GFP_KERNEL);
196                 if (!pcaps[i].pg.attrs) {
197                         kfree(pcaps[i].pattrs);
198                         goto out_pcaps_pattrs;
199                 }
200 
201                 j = 0;
202                 pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node);
203                 if (has_min) {
204                         powercap_add_attr(min, "powercap-min",
205                                           &pcaps[i].pattrs[j]);
206                         pcaps[i].pg.attrs[j] = &pcaps[i].pattrs[j].attr.attr;
207                         j++;
208                 }
209 
210                 if (has_max) {
211                         powercap_add_attr(max, "powercap-max",
212                                           &pcaps[i].pattrs[j]);
213                         pcaps[i].pg.attrs[j] = &pcaps[i].pattrs[j].attr.attr;
214                         j++;
215                 }
216 
217                 if (has_cur) {
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;
223                         j++;
224                 }
225 
226                 if (sysfs_create_group(powercap_kobj, &pcaps[i].pg)) {
227                         pr_warn("Failed to create powercap attribute group %s\n",
228                                 pcaps[i].pg.name);
229                         goto out_pcaps_pattrs;
230                 }
231                 i++;
232         }
233 
234         return;
235 
236 out_pcaps_pattrs:
237         while (--i >= 0) {
238                 kfree(pcaps[i].pattrs);
239                 kfree(pcaps[i].pg.attrs);
240                 kfree(pcaps[i].pg.name);
241         }
242         kobject_put(powercap_kobj);
243 out_pcaps:
244         kfree(pcaps);
245 }
246 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp