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