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 16 static DEFINE_MUTEX(psr_mutex); 17 18 static struct kobject *psr_kobj; 19 20 static struct psr_attr { 21 u32 handle; 22 struct kobj_attribute attr; 23 } *psr_attrs; 24 25 static 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 68 out: 69 mutex_unlock(&psr_mutex); 70 out_token: 71 opal_async_release_token(token); 72 return ret; 73 } 74 75 static 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 116 out: 117 mutex_unlock(&psr_mutex); 118 out_token: 119 opal_async_release_token(token); 120 return ret; 121 } 122 123 void __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 goto out_put_psr; 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 of_node_put(psr); 166 167 return; 168 out_kobj: 169 of_node_put(node); 170 kobject_put(psr_kobj); 171 out: 172 kfree(psr_attrs); 173 out_put_psr: 174 of_node_put(psr); 175 } 176
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.