1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2020 Linaro Limited 4 * 5 * Author: Daniel Lezcano <daniel.lezcano@linaro.org> 6 * 7 * The powercap based Dynamic Thermal Power Management framework 8 * provides to the userspace a consistent API to set the power limit 9 * on some devices. 10 * 11 * DTPM defines the functions to create a tree of constraints. Each 12 * parent node is a virtual description of the aggregation of the 13 * children. It propagates the constraints set at its level to its 14 * children and collect the children power information. The leaves of 15 * the tree are the real devices which have the ability to get their 16 * current power consumption and set their power limit. 17 */ 18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 20 #include <linux/dtpm.h> 21 #include <linux/init.h> 22 #include <linux/kernel.h> 23 #include <linux/powercap.h> 24 #include <linux/slab.h> 25 #include <linux/mutex.h> 26 27 #define DTPM_POWER_LIMIT_FLAG 0 28 29 static const char *constraint_name[] = { 30 "Instantaneous", 31 }; 32 33 static DEFINE_MUTEX(dtpm_lock); 34 static struct powercap_control_type *pct; 35 static struct dtpm *root; 36 37 static int get_time_window_us(struct powercap_zone *pcz, int cid, u64 *window) 38 { 39 return -ENOSYS; 40 } 41 42 static int set_time_window_us(struct powercap_zone *pcz, int cid, u64 window) 43 { 44 return -ENOSYS; 45 } 46 47 static int get_max_power_range_uw(struct powercap_zone *pcz, u64 *max_power_uw) 48 { 49 struct dtpm *dtpm = to_dtpm(pcz); 50 51 mutex_lock(&dtpm_lock); 52 *max_power_uw = dtpm->power_max - dtpm->power_min; 53 mutex_unlock(&dtpm_lock); 54 55 return 0; 56 } 57 58 static int __get_power_uw(struct dtpm *dtpm, u64 *power_uw) 59 { 60 struct dtpm *child; 61 u64 power; 62 int ret = 0; 63 64 if (dtpm->ops) { 65 *power_uw = dtpm->ops->get_power_uw(dtpm); 66 return 0; 67 } 68 69 *power_uw = 0; 70 71 list_for_each_entry(child, &dtpm->children, sibling) { 72 ret = __get_power_uw(child, &power); 73 if (ret) 74 break; 75 *power_uw += power; 76 } 77 78 return ret; 79 } 80 81 static int get_power_uw(struct powercap_zone *pcz, u64 *power_uw) 82 { 83 struct dtpm *dtpm = to_dtpm(pcz); 84 int ret; 85 86 mutex_lock(&dtpm_lock); 87 ret = __get_power_uw(dtpm, power_uw); 88 mutex_unlock(&dtpm_lock); 89 90 return ret; 91 } 92 93 static void __dtpm_rebalance_weight(struct dtpm *dtpm) 94 { 95 struct dtpm *child; 96 97 list_for_each_entry(child, &dtpm->children, sibling) { 98 99 pr_debug("Setting weight '%d' for '%s'\n", 100 child->weight, child->zone.name); 101 102 child->weight = DIV64_U64_ROUND_CLOSEST( 103 child->power_max * 1024, dtpm->power_max); 104 105 __dtpm_rebalance_weight(child); 106 } 107 } 108 109 static void __dtpm_sub_power(struct dtpm *dtpm) 110 { 111 struct dtpm *parent = dtpm->parent; 112 113 while (parent) { 114 parent->power_min -= dtpm->power_min; 115 parent->power_max -= dtpm->power_max; 116 parent->power_limit -= dtpm->power_limit; 117 parent = parent->parent; 118 } 119 120 __dtpm_rebalance_weight(root); 121 } 122 123 static void __dtpm_add_power(struct dtpm *dtpm) 124 { 125 struct dtpm *parent = dtpm->parent; 126 127 while (parent) { 128 parent->power_min += dtpm->power_min; 129 parent->power_max += dtpm->power_max; 130 parent->power_limit += dtpm->power_limit; 131 parent = parent->parent; 132 } 133 134 __dtpm_rebalance_weight(root); 135 } 136 137 /** 138 * dtpm_update_power - Update the power on the dtpm 139 * @dtpm: a pointer to a dtpm structure to update 140 * @power_min: a u64 representing the new power_min value 141 * @power_max: a u64 representing the new power_max value 142 * 143 * Function to update the power values of the dtpm node specified in 144 * parameter. These new values will be propagated to the tree. 145 * 146 * Return: zero on success, -EINVAL if the values are inconsistent 147 */ 148 int dtpm_update_power(struct dtpm *dtpm, u64 power_min, u64 power_max) 149 { 150 int ret = 0; 151 152 mutex_lock(&dtpm_lock); 153 154 if (power_min == dtpm->power_min && power_max == dtpm->power_max) 155 goto unlock; 156 157 if (power_max < power_min) { 158 ret = -EINVAL; 159 goto unlock; 160 } 161 162 __dtpm_sub_power(dtpm); 163 164 dtpm->power_min = power_min; 165 dtpm->power_max = power_max; 166 if (!test_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags)) 167 dtpm->power_limit = power_max; 168 169 __dtpm_add_power(dtpm); 170 171 unlock: 172 mutex_unlock(&dtpm_lock); 173 174 return ret; 175 } 176 177 /** 178 * dtpm_release_zone - Cleanup when the node is released 179 * @pcz: a pointer to a powercap_zone structure 180 * 181 * Do some housecleaning and update the weight on the tree. The 182 * release will be denied if the node has children. This function must 183 * be called by the specific release callback of the different 184 * backends. 185 * 186 * Return: 0 on success, -EBUSY if there are children 187 */ 188 int dtpm_release_zone(struct powercap_zone *pcz) 189 { 190 struct dtpm *dtpm = to_dtpm(pcz); 191 struct dtpm *parent = dtpm->parent; 192 193 mutex_lock(&dtpm_lock); 194 195 if (!list_empty(&dtpm->children)) { 196 mutex_unlock(&dtpm_lock); 197 return -EBUSY; 198 } 199 200 if (parent) 201 list_del(&dtpm->sibling); 202 203 __dtpm_sub_power(dtpm); 204 205 mutex_unlock(&dtpm_lock); 206 207 if (dtpm->ops) 208 dtpm->ops->release(dtpm); 209 210 kfree(dtpm); 211 212 return 0; 213 } 214 215 static int __get_power_limit_uw(struct dtpm *dtpm, int cid, u64 *power_limit) 216 { 217 *power_limit = dtpm->power_limit; 218 return 0; 219 } 220 221 static int get_power_limit_uw(struct powercap_zone *pcz, 222 int cid, u64 *power_limit) 223 { 224 struct dtpm *dtpm = to_dtpm(pcz); 225 int ret; 226 227 mutex_lock(&dtpm_lock); 228 ret = __get_power_limit_uw(dtpm, cid, power_limit); 229 mutex_unlock(&dtpm_lock); 230 231 return ret; 232 } 233 234 /* 235 * Set the power limit on the nodes, the power limit is distributed 236 * given the weight of the children. 237 * 238 * The dtpm node lock must be held when calling this function. 239 */ 240 static int __set_power_limit_uw(struct dtpm *dtpm, int cid, u64 power_limit) 241 { 242 struct dtpm *child; 243 int ret = 0; 244 u64 power; 245 246 /* 247 * A max power limitation means we remove the power limit, 248 * otherwise we set a constraint and flag the dtpm node. 249 */ 250 if (power_limit == dtpm->power_max) { 251 clear_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags); 252 } else { 253 set_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags); 254 } 255 256 pr_debug("Setting power limit for '%s': %llu uW\n", 257 dtpm->zone.name, power_limit); 258 259 /* 260 * Only leaves of the dtpm tree has ops to get/set the power 261 */ 262 if (dtpm->ops) { 263 dtpm->power_limit = dtpm->ops->set_power_uw(dtpm, power_limit); 264 } else { 265 dtpm->power_limit = 0; 266 267 list_for_each_entry(child, &dtpm->children, sibling) { 268 269 /* 270 * Integer division rounding will inevitably 271 * lead to a different min or max value when 272 * set several times. In order to restore the 273 * initial value, we force the child's min or 274 * max power every time if the constraint is 275 * at the boundaries. 276 */ 277 if (power_limit == dtpm->power_max) { 278 power = child->power_max; 279 } else if (power_limit == dtpm->power_min) { 280 power = child->power_min; 281 } else { 282 power = DIV_ROUND_CLOSEST_ULL( 283 power_limit * child->weight, 1024); 284 } 285 286 pr_debug("Setting power limit for '%s': %llu uW\n", 287 child->zone.name, power); 288 289 ret = __set_power_limit_uw(child, cid, power); 290 if (!ret) 291 ret = __get_power_limit_uw(child, cid, &power); 292 293 if (ret) 294 break; 295 296 dtpm->power_limit += power; 297 } 298 } 299 300 return ret; 301 } 302 303 static int set_power_limit_uw(struct powercap_zone *pcz, 304 int cid, u64 power_limit) 305 { 306 struct dtpm *dtpm = to_dtpm(pcz); 307 int ret; 308 309 mutex_lock(&dtpm_lock); 310 311 /* 312 * Don't allow values outside of the power range previously 313 * set when initializing the power numbers. 314 */ 315 power_limit = clamp_val(power_limit, dtpm->power_min, dtpm->power_max); 316 317 ret = __set_power_limit_uw(dtpm, cid, power_limit); 318 319 pr_debug("%s: power limit: %llu uW, power max: %llu uW\n", 320 dtpm->zone.name, dtpm->power_limit, dtpm->power_max); 321 322 mutex_unlock(&dtpm_lock); 323 324 return ret; 325 } 326 327 static const char *get_constraint_name(struct powercap_zone *pcz, int cid) 328 { 329 return constraint_name[cid]; 330 } 331 332 static int get_max_power_uw(struct powercap_zone *pcz, int id, u64 *max_power) 333 { 334 struct dtpm *dtpm = to_dtpm(pcz); 335 336 mutex_lock(&dtpm_lock); 337 *max_power = dtpm->power_max; 338 mutex_unlock(&dtpm_lock); 339 340 return 0; 341 } 342 343 static struct powercap_zone_constraint_ops constraint_ops = { 344 .set_power_limit_uw = set_power_limit_uw, 345 .get_power_limit_uw = get_power_limit_uw, 346 .set_time_window_us = set_time_window_us, 347 .get_time_window_us = get_time_window_us, 348 .get_max_power_uw = get_max_power_uw, 349 .get_name = get_constraint_name, 350 }; 351 352 static struct powercap_zone_ops zone_ops = { 353 .get_max_power_range_uw = get_max_power_range_uw, 354 .get_power_uw = get_power_uw, 355 .release = dtpm_release_zone, 356 }; 357 358 /** 359 * dtpm_alloc - Allocate and initialize a dtpm struct 360 * @name: a string specifying the name of the node 361 * 362 * Return: a struct dtpm pointer, NULL in case of error 363 */ 364 struct dtpm *dtpm_alloc(struct dtpm_ops *ops) 365 { 366 struct dtpm *dtpm; 367 368 dtpm = kzalloc(sizeof(*dtpm), GFP_KERNEL); 369 if (dtpm) { 370 INIT_LIST_HEAD(&dtpm->children); 371 INIT_LIST_HEAD(&dtpm->sibling); 372 dtpm->weight = 1024; 373 dtpm->ops = ops; 374 } 375 376 return dtpm; 377 } 378 379 /** 380 * dtpm_unregister - Unregister a dtpm node from the hierarchy tree 381 * @dtpm: a pointer to a dtpm structure corresponding to the node to be removed 382 * 383 * Call the underlying powercap unregister function. That will call 384 * the release callback of the powercap zone. 385 */ 386 void dtpm_unregister(struct dtpm *dtpm) 387 { 388 powercap_unregister_zone(pct, &dtpm->zone); 389 390 pr_info("Unregistered dtpm node '%s'\n", dtpm->zone.name); 391 } 392 393 /** 394 * dtpm_register - Register a dtpm node in the hierarchy tree 395 * @name: a string specifying the name of the node 396 * @dtpm: a pointer to a dtpm structure corresponding to the new node 397 * @parent: a pointer to a dtpm structure corresponding to the parent node 398 * 399 * Create a dtpm node in the tree. If no parent is specified, the node 400 * is the root node of the hierarchy. If the root node already exists, 401 * then the registration will fail. The powercap controller must be 402 * initialized before calling this function. 403 * 404 * The dtpm structure must be initialized with the power numbers 405 * before calling this function. 406 * 407 * Return: zero on success, a negative value in case of error: 408 * -EAGAIN: the function is called before the framework is initialized. 409 * -EBUSY: the root node is already inserted 410 * -EINVAL: * there is no root node yet and @parent is specified 411 * * no all ops are defined 412 * * parent have ops which are reserved for leaves 413 * Other negative values are reported back from the powercap framework 414 */ 415 int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) 416 { 417 struct powercap_zone *pcz; 418 419 if (!pct) 420 return -EAGAIN; 421 422 if (root && !parent) 423 return -EBUSY; 424 425 if (!root && parent) 426 return -EINVAL; 427 428 if (parent && parent->ops) 429 return -EINVAL; 430 431 if (!dtpm) 432 return -EINVAL; 433 434 if (dtpm->ops && !(dtpm->ops->set_power_uw && 435 dtpm->ops->get_power_uw && 436 dtpm->ops->release)) 437 return -EINVAL; 438 439 pcz = powercap_register_zone(&dtpm->zone, pct, name, 440 parent ? &parent->zone : NULL, 441 &zone_ops, MAX_DTPM_CONSTRAINTS, 442 &constraint_ops); 443 if (IS_ERR(pcz)) 444 return PTR_ERR(pcz); 445 446 mutex_lock(&dtpm_lock); 447 448 if (parent) { 449 list_add_tail(&dtpm->sibling, &parent->children); 450 dtpm->parent = parent; 451 } else { 452 root = dtpm; 453 } 454 455 __dtpm_add_power(dtpm); 456 457 pr_info("Registered dtpm node '%s' / %llu-%llu uW, \n", 458 dtpm->zone.name, dtpm->power_min, dtpm->power_max); 459 460 mutex_unlock(&dtpm_lock); 461 462 return 0; 463 } 464 465 static int __init dtpm_init(void) 466 { 467 struct dtpm_descr **dtpm_descr; 468 469 pct = powercap_register_control_type(NULL, "dtpm", NULL); 470 if (!pct) { 471 pr_err("Failed to register control type\n"); 472 return -EINVAL; 473 } 474 475 for_each_dtpm_table(dtpm_descr) 476 (*dtpm_descr)->init(*dtpm_descr); 477 478 return 0; 479 } 480 late_initcall(dtpm_init); 481