linux/arch/powerpc/platforms/powernv/opal-psr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * PowerNV OPAL Power-Shift-Ratio interface
   4 *
   5 * Copyright 2017 IBM Corp.
   6 */
   7
   8#define pr_fmt(fmt)     "opal-psr: " fmt
   9
  10#include <linux/of.h>
  11#include <linux/kobject.h>
  12#include <linux/slab.h>
  13
  14#include <asm/opal.h>
  15
  16static DEFINE_MUTEX(psr_mutex);
  17
  18static struct kobject *psr_kobj;
  19
  20static struct psr_attr {
  21        u32 handle;
  22        struct kobj_attribute attr;
  23} *psr_attrs;
  24
  25static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
  26                        char *buf)
  27{
  28        struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
  29        struct opal_msg msg;
  30        int psr, ret, token;
  31
  32        token = opal_async_get_token_interruptible();
  33        if (token < 0) {
  34                pr_devel("Failed to get token\n");
  35                return token;
  36        }
  37
  38        ret = mutex_lock_interruptible(&psr_mutex);
  39        if (ret)
  40                goto out_token;
  41
  42        ret = opal_get_power_shift_ratio(psr_attr->handle, token,
  43                                            (u32 *)__pa(&psr));
  44        switch (ret) {
  45        case OPAL_ASYNC_COMPLETION:
  46                ret = opal_async_wait_response(token, &msg);
  47                if (ret) {
  48                        pr_devel("Failed to wait for the async response\n");
  49                        ret = -EIO;
  50                        goto out;
  51                }
  52                ret = opal_error_code(opal_get_async_rc(msg));
  53                if (!ret) {
  54                        ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
  55                        if (ret < 0)
  56                                ret = -EIO;
  57                }
  58                break;
  59        case OPAL_SUCCESS:
  60                ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
  61                if (ret < 0)
  62                        ret = -EIO;
  63                break;
  64        default:
  65                ret = opal_error_code(ret);
  66        }
  67
  68out:
  69        mutex_unlock(&psr_mutex);
  70out_token:
  71        opal_async_release_token(token);
  72        return ret;
  73}
  74
  75static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
  76                         const char *buf, size_t count)
  77{
  78        struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
  79        struct opal_msg msg;
  80        int psr, ret, token;
  81
  82        ret = kstrtoint(buf, 0, &psr);
  83        if (ret)
  84                return ret;
  85
  86        token = opal_async_get_token_interruptible();
  87        if (token < 0) {
  88                pr_devel("Failed to get token\n");
  89                return token;
  90        }
  91
  92        ret = mutex_lock_interruptible(&psr_mutex);
  93        if (ret)
  94                goto out_token;
  95
  96        ret = opal_set_power_shift_ratio(psr_attr->handle, token, psr);
  97        switch (ret) {
  98        case OPAL_ASYNC_COMPLETION:
  99                ret = opal_async_wait_response(token, &msg);
 100                if (ret) {
 101                        pr_devel("Failed to wait for the async response\n");
 102                        ret = -EIO;
 103                        goto out;
 104                }
 105                ret = opal_error_code(opal_get_async_rc(msg));
 106                if (!ret)
 107                        ret = count;
 108                break;
 109        case OPAL_SUCCESS:
 110                ret = count;
 111                break;
 112        default:
 113                ret = opal_error_code(ret);
 114        }
 115
 116out:
 117        mutex_unlock(&psr_mutex);
 118out_token:
 119        opal_async_release_token(token);
 120        return ret;
 121}
 122
 123void __init opal_psr_init(void)
 124{
 125        struct device_node *psr, *node;
 126        int i = 0;
 127
 128        psr = of_find_compatible_node(NULL, NULL,
 129                                      "ibm,opal-power-shift-ratio");
 130        if (!psr) {
 131                pr_devel("Power-shift-ratio node not found\n");
 132                return;
 133        }
 134
 135        psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs),
 136                            GFP_KERNEL);
 137        if (!psr_attrs)
 138                return;
 139
 140        psr_kobj = kobject_create_and_add("psr", opal_kobj);
 141        if (!psr_kobj) {
 142                pr_warn("Failed to create psr kobject\n");
 143                goto out;
 144        }
 145
 146        for_each_child_of_node(psr, node) {
 147                if (of_property_read_u32(node, "handle",
 148                                         &psr_attrs[i].handle))
 149                        goto out_kobj;
 150
 151                sysfs_attr_init(&psr_attrs[i].attr.attr);
 152                if (of_property_read_string(node, "label",
 153                                            &psr_attrs[i].attr.attr.name))
 154                        goto out_kobj;
 155                psr_attrs[i].attr.attr.mode = 0664;
 156                psr_attrs[i].attr.show = psr_show;
 157                psr_attrs[i].attr.store = psr_store;
 158                if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
 159                        pr_devel("Failed to create psr sysfs file %s\n",
 160                                 psr_attrs[i].attr.attr.name);
 161                        goto out_kobj;
 162                }
 163                i++;
 164        }
 165
 166        return;
 167out_kobj:
 168        kobject_put(psr_kobj);
 169out:
 170        kfree(psr_attrs);
 171}
 172