Path: blob/master/arch/powerpc/platforms/powernv/opal-psr.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* PowerNV OPAL Power-Shift-Ratio interface3*4* Copyright 2017 IBM Corp.5*/67#define pr_fmt(fmt) "opal-psr: " fmt89#include <linux/of.h>10#include <linux/kobject.h>11#include <linux/slab.h>1213#include <asm/opal.h>1415static DEFINE_MUTEX(psr_mutex);1617static struct kobject *psr_kobj;1819static struct psr_attr {20u32 handle;21struct kobj_attribute attr;22} *psr_attrs;2324static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,25char *buf)26{27struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);28struct opal_msg msg;29int psr, ret, token;3031token = opal_async_get_token_interruptible();32if (token < 0) {33pr_devel("Failed to get token\n");34return token;35}3637ret = mutex_lock_interruptible(&psr_mutex);38if (ret)39goto out_token;4041ret = opal_get_power_shift_ratio(psr_attr->handle, token,42(u32 *)__pa(&psr));43switch (ret) {44case OPAL_ASYNC_COMPLETION:45ret = opal_async_wait_response(token, &msg);46if (ret) {47pr_devel("Failed to wait for the async response\n");48ret = -EIO;49goto out;50}51ret = opal_error_code(opal_get_async_rc(msg));52if (!ret) {53ret = sprintf(buf, "%u\n", be32_to_cpu(psr));54if (ret < 0)55ret = -EIO;56}57break;58case OPAL_SUCCESS:59ret = sprintf(buf, "%u\n", be32_to_cpu(psr));60if (ret < 0)61ret = -EIO;62break;63default:64ret = opal_error_code(ret);65}6667out:68mutex_unlock(&psr_mutex);69out_token:70opal_async_release_token(token);71return ret;72}7374static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,75const char *buf, size_t count)76{77struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);78struct opal_msg msg;79int psr, ret, token;8081ret = kstrtoint(buf, 0, &psr);82if (ret)83return ret;8485token = opal_async_get_token_interruptible();86if (token < 0) {87pr_devel("Failed to get token\n");88return token;89}9091ret = mutex_lock_interruptible(&psr_mutex);92if (ret)93goto out_token;9495ret = opal_set_power_shift_ratio(psr_attr->handle, token, psr);96switch (ret) {97case OPAL_ASYNC_COMPLETION:98ret = opal_async_wait_response(token, &msg);99if (ret) {100pr_devel("Failed to wait for the async response\n");101ret = -EIO;102goto out;103}104ret = opal_error_code(opal_get_async_rc(msg));105if (!ret)106ret = count;107break;108case OPAL_SUCCESS:109ret = count;110break;111default:112ret = opal_error_code(ret);113}114115out:116mutex_unlock(&psr_mutex);117out_token:118opal_async_release_token(token);119return ret;120}121122void __init opal_psr_init(void)123{124struct device_node *psr, *node;125int i = 0;126127psr = of_find_compatible_node(NULL, NULL,128"ibm,opal-power-shift-ratio");129if (!psr) {130pr_devel("Power-shift-ratio node not found\n");131return;132}133134psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs),135GFP_KERNEL);136if (!psr_attrs)137goto out_put_psr;138139psr_kobj = kobject_create_and_add("psr", opal_kobj);140if (!psr_kobj) {141pr_warn("Failed to create psr kobject\n");142goto out;143}144145for_each_child_of_node(psr, node) {146if (of_property_read_u32(node, "handle",147&psr_attrs[i].handle))148goto out_kobj;149150sysfs_attr_init(&psr_attrs[i].attr.attr);151if (of_property_read_string(node, "label",152&psr_attrs[i].attr.attr.name))153goto out_kobj;154psr_attrs[i].attr.attr.mode = 0664;155psr_attrs[i].attr.show = psr_show;156psr_attrs[i].attr.store = psr_store;157if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {158pr_devel("Failed to create psr sysfs file %s\n",159psr_attrs[i].attr.attr.name);160goto out_kobj;161}162i++;163}164of_node_put(psr);165166return;167out_kobj:168of_node_put(node);169kobject_put(psr_kobj);170out:171kfree(psr_attrs);172out_put_psr:173of_node_put(psr);174}175176177