0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "opal-powercap: " fmt
0009
0010 #include <linux/of.h>
0011 #include <linux/kobject.h>
0012 #include <linux/slab.h>
0013
0014 #include <asm/opal.h>
0015
0016 static DEFINE_MUTEX(powercap_mutex);
0017
0018 static struct kobject *powercap_kobj;
0019
0020 struct powercap_attr {
0021 u32 handle;
0022 struct kobj_attribute attr;
0023 };
0024
0025 static struct pcap {
0026 struct attribute_group pg;
0027 struct powercap_attr *pattrs;
0028 } *pcaps;
0029
0030 static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr,
0031 char *buf)
0032 {
0033 struct powercap_attr *pcap_attr = container_of(attr,
0034 struct powercap_attr, attr);
0035 struct opal_msg msg;
0036 u32 pcap;
0037 int ret, token;
0038
0039 token = opal_async_get_token_interruptible();
0040 if (token < 0) {
0041 pr_devel("Failed to get token\n");
0042 return token;
0043 }
0044
0045 ret = mutex_lock_interruptible(&powercap_mutex);
0046 if (ret)
0047 goto out_token;
0048
0049 ret = opal_get_powercap(pcap_attr->handle, token, (u32 *)__pa(&pcap));
0050 switch (ret) {
0051 case OPAL_ASYNC_COMPLETION:
0052 ret = opal_async_wait_response(token, &msg);
0053 if (ret) {
0054 pr_devel("Failed to wait for the async response\n");
0055 ret = -EIO;
0056 goto out;
0057 }
0058 ret = opal_error_code(opal_get_async_rc(msg));
0059 if (!ret) {
0060 ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
0061 if (ret < 0)
0062 ret = -EIO;
0063 }
0064 break;
0065 case OPAL_SUCCESS:
0066 ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
0067 if (ret < 0)
0068 ret = -EIO;
0069 break;
0070 default:
0071 ret = opal_error_code(ret);
0072 }
0073
0074 out:
0075 mutex_unlock(&powercap_mutex);
0076 out_token:
0077 opal_async_release_token(token);
0078 return ret;
0079 }
0080
0081 static ssize_t powercap_store(struct kobject *kobj,
0082 struct kobj_attribute *attr, const char *buf,
0083 size_t count)
0084 {
0085 struct powercap_attr *pcap_attr = container_of(attr,
0086 struct powercap_attr, attr);
0087 struct opal_msg msg;
0088 u32 pcap;
0089 int ret, token;
0090
0091 ret = kstrtoint(buf, 0, &pcap);
0092 if (ret)
0093 return ret;
0094
0095 token = opal_async_get_token_interruptible();
0096 if (token < 0) {
0097 pr_devel("Failed to get token\n");
0098 return token;
0099 }
0100
0101 ret = mutex_lock_interruptible(&powercap_mutex);
0102 if (ret)
0103 goto out_token;
0104
0105 ret = opal_set_powercap(pcap_attr->handle, token, pcap);
0106 switch (ret) {
0107 case OPAL_ASYNC_COMPLETION:
0108 ret = opal_async_wait_response(token, &msg);
0109 if (ret) {
0110 pr_devel("Failed to wait for the async response\n");
0111 ret = -EIO;
0112 goto out;
0113 }
0114 ret = opal_error_code(opal_get_async_rc(msg));
0115 if (!ret)
0116 ret = count;
0117 break;
0118 case OPAL_SUCCESS:
0119 ret = count;
0120 break;
0121 default:
0122 ret = opal_error_code(ret);
0123 }
0124
0125 out:
0126 mutex_unlock(&powercap_mutex);
0127 out_token:
0128 opal_async_release_token(token);
0129 return ret;
0130 }
0131
0132 static void __init powercap_add_attr(int handle, const char *name,
0133 struct powercap_attr *attr)
0134 {
0135 attr->handle = handle;
0136 sysfs_attr_init(&attr->attr.attr);
0137 attr->attr.attr.name = name;
0138 attr->attr.attr.mode = 0444;
0139 attr->attr.show = powercap_show;
0140 }
0141
0142 void __init opal_powercap_init(void)
0143 {
0144 struct device_node *powercap, *node;
0145 int i = 0;
0146
0147 powercap = of_find_compatible_node(NULL, NULL, "ibm,opal-powercap");
0148 if (!powercap) {
0149 pr_devel("Powercap node not found\n");
0150 return;
0151 }
0152
0153 pcaps = kcalloc(of_get_child_count(powercap), sizeof(*pcaps),
0154 GFP_KERNEL);
0155 if (!pcaps)
0156 return;
0157
0158 powercap_kobj = kobject_create_and_add("powercap", opal_kobj);
0159 if (!powercap_kobj) {
0160 pr_warn("Failed to create powercap kobject\n");
0161 goto out_pcaps;
0162 }
0163
0164 i = 0;
0165 for_each_child_of_node(powercap, node) {
0166 u32 cur, min, max;
0167 int j = 0;
0168 bool has_cur = false, has_min = false, has_max = false;
0169
0170 if (!of_property_read_u32(node, "powercap-min", &min)) {
0171 j++;
0172 has_min = true;
0173 }
0174
0175 if (!of_property_read_u32(node, "powercap-max", &max)) {
0176 j++;
0177 has_max = true;
0178 }
0179
0180 if (!of_property_read_u32(node, "powercap-current", &cur)) {
0181 j++;
0182 has_cur = true;
0183 }
0184
0185 pcaps[i].pattrs = kcalloc(j, sizeof(struct powercap_attr),
0186 GFP_KERNEL);
0187 if (!pcaps[i].pattrs)
0188 goto out_pcaps_pattrs;
0189
0190 pcaps[i].pg.attrs = kcalloc(j + 1, sizeof(struct attribute *),
0191 GFP_KERNEL);
0192 if (!pcaps[i].pg.attrs) {
0193 kfree(pcaps[i].pattrs);
0194 goto out_pcaps_pattrs;
0195 }
0196
0197 j = 0;
0198 pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node);
0199 if (has_min) {
0200 powercap_add_attr(min, "powercap-min",
0201 &pcaps[i].pattrs[j]);
0202 pcaps[i].pg.attrs[j] = &pcaps[i].pattrs[j].attr.attr;
0203 j++;
0204 }
0205
0206 if (has_max) {
0207 powercap_add_attr(max, "powercap-max",
0208 &pcaps[i].pattrs[j]);
0209 pcaps[i].pg.attrs[j] = &pcaps[i].pattrs[j].attr.attr;
0210 j++;
0211 }
0212
0213 if (has_cur) {
0214 powercap_add_attr(cur, "powercap-current",
0215 &pcaps[i].pattrs[j]);
0216 pcaps[i].pattrs[j].attr.attr.mode |= 0220;
0217 pcaps[i].pattrs[j].attr.store = powercap_store;
0218 pcaps[i].pg.attrs[j] = &pcaps[i].pattrs[j].attr.attr;
0219 j++;
0220 }
0221
0222 if (sysfs_create_group(powercap_kobj, &pcaps[i].pg)) {
0223 pr_warn("Failed to create powercap attribute group %s\n",
0224 pcaps[i].pg.name);
0225 goto out_pcaps_pattrs;
0226 }
0227 i++;
0228 }
0229
0230 return;
0231
0232 out_pcaps_pattrs:
0233 while (--i >= 0) {
0234 kfree(pcaps[i].pattrs);
0235 kfree(pcaps[i].pg.attrs);
0236 kfree(pcaps[i].pg.name);
0237 }
0238 kobject_put(powercap_kobj);
0239 out_pcaps:
0240 kfree(pcaps);
0241 }