Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PowerNV OPAL Power-Shift-Ratio interface
0004  *
0005  * Copyright 2017 IBM Corp.
0006  */
0007 
0008 #define pr_fmt(fmt)     "opal-psr: " 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(psr_mutex);
0017 
0018 static struct kobject *psr_kobj;
0019 
0020 static struct psr_attr {
0021     u32 handle;
0022     struct kobj_attribute attr;
0023 } *psr_attrs;
0024 
0025 static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
0026             char *buf)
0027 {
0028     struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
0029     struct opal_msg msg;
0030     int psr, ret, token;
0031 
0032     token = opal_async_get_token_interruptible();
0033     if (token < 0) {
0034         pr_devel("Failed to get token\n");
0035         return token;
0036     }
0037 
0038     ret = mutex_lock_interruptible(&psr_mutex);
0039     if (ret)
0040         goto out_token;
0041 
0042     ret = opal_get_power_shift_ratio(psr_attr->handle, token,
0043                         (u32 *)__pa(&psr));
0044     switch (ret) {
0045     case OPAL_ASYNC_COMPLETION:
0046         ret = opal_async_wait_response(token, &msg);
0047         if (ret) {
0048             pr_devel("Failed to wait for the async response\n");
0049             ret = -EIO;
0050             goto out;
0051         }
0052         ret = opal_error_code(opal_get_async_rc(msg));
0053         if (!ret) {
0054             ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
0055             if (ret < 0)
0056                 ret = -EIO;
0057         }
0058         break;
0059     case OPAL_SUCCESS:
0060         ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
0061         if (ret < 0)
0062             ret = -EIO;
0063         break;
0064     default:
0065         ret = opal_error_code(ret);
0066     }
0067 
0068 out:
0069     mutex_unlock(&psr_mutex);
0070 out_token:
0071     opal_async_release_token(token);
0072     return ret;
0073 }
0074 
0075 static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
0076              const char *buf, size_t count)
0077 {
0078     struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
0079     struct opal_msg msg;
0080     int psr, ret, token;
0081 
0082     ret = kstrtoint(buf, 0, &psr);
0083     if (ret)
0084         return ret;
0085 
0086     token = opal_async_get_token_interruptible();
0087     if (token < 0) {
0088         pr_devel("Failed to get token\n");
0089         return token;
0090     }
0091 
0092     ret = mutex_lock_interruptible(&psr_mutex);
0093     if (ret)
0094         goto out_token;
0095 
0096     ret = opal_set_power_shift_ratio(psr_attr->handle, token, psr);
0097     switch (ret) {
0098     case OPAL_ASYNC_COMPLETION:
0099         ret = opal_async_wait_response(token, &msg);
0100         if (ret) {
0101             pr_devel("Failed to wait for the async response\n");
0102             ret = -EIO;
0103             goto out;
0104         }
0105         ret = opal_error_code(opal_get_async_rc(msg));
0106         if (!ret)
0107             ret = count;
0108         break;
0109     case OPAL_SUCCESS:
0110         ret = count;
0111         break;
0112     default:
0113         ret = opal_error_code(ret);
0114     }
0115 
0116 out:
0117     mutex_unlock(&psr_mutex);
0118 out_token:
0119     opal_async_release_token(token);
0120     return ret;
0121 }
0122 
0123 void __init opal_psr_init(void)
0124 {
0125     struct device_node *psr, *node;
0126     int i = 0;
0127 
0128     psr = of_find_compatible_node(NULL, NULL,
0129                       "ibm,opal-power-shift-ratio");
0130     if (!psr) {
0131         pr_devel("Power-shift-ratio node not found\n");
0132         return;
0133     }
0134 
0135     psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs),
0136                 GFP_KERNEL);
0137     if (!psr_attrs)
0138         return;
0139 
0140     psr_kobj = kobject_create_and_add("psr", opal_kobj);
0141     if (!psr_kobj) {
0142         pr_warn("Failed to create psr kobject\n");
0143         goto out;
0144     }
0145 
0146     for_each_child_of_node(psr, node) {
0147         if (of_property_read_u32(node, "handle",
0148                      &psr_attrs[i].handle))
0149             goto out_kobj;
0150 
0151         sysfs_attr_init(&psr_attrs[i].attr.attr);
0152         if (of_property_read_string(node, "label",
0153                         &psr_attrs[i].attr.attr.name))
0154             goto out_kobj;
0155         psr_attrs[i].attr.attr.mode = 0664;
0156         psr_attrs[i].attr.show = psr_show;
0157         psr_attrs[i].attr.store = psr_store;
0158         if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
0159             pr_devel("Failed to create psr sysfs file %s\n",
0160                  psr_attrs[i].attr.attr.name);
0161             goto out_kobj;
0162         }
0163         i++;
0164     }
0165 
0166     return;
0167 out_kobj:
0168     kobject_put(psr_kobj);
0169 out:
0170     kfree(psr_attrs);
0171 }