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