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 if (root == dtpm) 211 root = NULL; 212 213 kfree(dtpm); 214 215 return 0; 216 } 217 218 static int __get_power_limit_uw(struct dtpm *dtpm, int cid, u64 *power_limit) 219 { 220 *power_limit = dtpm->power_limit; 221 return 0; 222 } 223 224 static int get_power_limit_uw(struct powercap_zone *pcz, 225 int cid, u64 *power_limit) 226 { 227 struct dtpm *dtpm = to_dtpm(pcz); 228 int ret; 229 230 mutex_lock(&dtpm_lock); 231 ret = __get_power_limit_uw(dtpm, cid, power_limit); 232 mutex_unlock(&dtpm_lock); 233 234 return ret; 235 } 236 237 /* 238 * Set the power limit on the nodes, the power limit is distributed 239 * given the weight of the children. 240 * 241 * The dtpm node lock must be held when calling this function. 242 */ 243 static int __set_power_limit_uw(struct dtpm *dtpm, int cid, u64 power_limit) 244 { 245 struct dtpm *child; 246 int ret = 0; 247 u64 power; 248 249 /* 250 * A max power limitation means we remove the power limit, 251 * otherwise we set a constraint and flag the dtpm node. 252 */ 253 if (power_limit == dtpm->power_max) { 254 clear_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags); 255 } else { 256 set_bit(DTPM_POWER_LIMIT_FLAG, &dtpm->flags); 257 } 258 259 pr_debug("Setting power limit for '%s': %llu uW\n", 260 dtpm->zone.name, power_limit); 261 262 /* 263 * Only leaves of the dtpm tree has ops to get/set the power 264 */ 265 if (dtpm->ops) { 266 dtpm->power_limit = dtpm->ops->set_power_uw(dtpm, power_limit); 267 } else { 268 dtpm->power_limit = 0; 269 270 list_for_each_entry(child, &dtpm->children, sibling) { 271 272 /* 273 * Integer division rounding will inevitably 274 * lead to a different min or max value when 275 * set several times. In order to restore the 276 * initial value, we force the child's min or 277 * max power every time if the constraint is 278 * at the boundaries. 279 */ 280 if (power_limit == dtpm->power_max) { 281 power = child->power_max; 282 } else if (power_limit == dtpm->power_min) { 283 power = child->power_min; 284 } else { 285 power = DIV_ROUND_CLOSEST_ULL( 286 power_limit * child->weight, 1024); 287 } 288 289 pr_debug("Setting power limit for '%s': %llu uW\n", 290 child->zone.name, power); 291 292 ret = __set_power_limit_uw(child, cid, power); 293 if (!ret) 294 ret = __get_power_limit_uw(child, cid, &power); 295 296 if (ret) 297 break; 298 299 dtpm->power_limit += power; 300 } 301 } 302 303 return ret; 304 } 305 306 static int set_power_limit_uw(struct powercap_zone *pcz, 307 int cid, u64 power_limit) 308 { 309 struct dtpm *dtpm = to_dtpm(pcz); 310 int ret; 311 312 mutex_lock(&dtpm_lock); 313 314 /* 315 * Don't allow values outside of the power range previously 316 * set when initializing the power numbers. 317 */ 318 power_limit = clamp_val(power_limit, dtpm->power_min, dtpm->power_max); 319 320 ret = __set_power_limit_uw(dtpm, cid, power_limit); 321 322 pr_debug("%s: power limit: %llu uW, power max: %llu uW\n", 323 dtpm->zone.name, dtpm->power_limit, dtpm->power_max); 324 325 mutex_unlock(&dtpm_lock); 326 327 return ret; 328 } 329 330 static const char *get_constraint_name(struct powercap_zone *pcz, int cid) 331 { 332 return constraint_name[cid]; 333 } 334 335 static int get_max_power_uw(struct powercap_zone *pcz, int id, u64 *max_power) 336 { 337 struct dtpm *dtpm = to_dtpm(pcz); 338 339 mutex_lock(&dtpm_lock); 340 *max_power = dtpm->power_max; 341 mutex_unlock(&dtpm_lock); 342 343 return 0; 344 } 345 346 static struct powercap_zone_constraint_ops constraint_ops = { 347 .set_power_limit_uw = set_power_limit_uw, 348 .get_power_limit_uw = get_power_limit_uw, 349 .set_time_window_us = set_time_window_us, 350 .get_time_window_us = get_time_window_us, 351 .get_max_power_uw = get_max_power_uw, 352 .get_name = get_constraint_name, 353 }; 354 355 static struct powercap_zone_ops zone_ops = { 356 .get_max_power_range_uw = get_max_power_range_uw, 357 .get_power_uw = get_power_uw, 358 .release = dtpm_release_zone, 359 }; 360 361 /** 362 * dtpm_alloc - Allocate and initialize a dtpm struct 363 * @name: a string specifying the name of the node 364 * 365 * Return: a struct dtpm pointer, NULL in case of error 366 */ 367 struct dtpm *dtpm_alloc(struct dtpm_ops *ops) 368 { 369 struct dtpm *dtpm; 370 371 dtpm = kzalloc(sizeof(*dtpm), GFP_KERNEL); 372 if (dtpm) { 373 INIT_LIST_HEAD(&dtpm->children); 374 INIT_LIST_HEAD(&dtpm->sibling); 375 dtpm->weight = 1024; 376 dtpm->ops = ops; 377 } 378 379 return dtpm; 380 } 381 382 /** 383 * dtpm_unregister - Unregister a dtpm node from the hierarchy tree 384 * @dtpm: a pointer to a dtpm structure corresponding to the node to be removed 385 * 386 * Call the underlying powercap unregister function. That will call 387 * the release callback of the powercap zone. 388 */ 389 void dtpm_unregister(struct dtpm *dtpm) 390 { 391 powercap_unregister_zone(pct, &dtpm->zone); 392 393 pr_info("Unregistered dtpm node '%s'\n", dtpm->zone.name); 394 } 395 396 /** 397 * dtpm_register - Register a dtpm node in the hierarchy tree 398 * @name: a string specifying the name of the node 399 * @dtpm: a pointer to a dtpm structure corresponding to the new node 400 * @parent: a pointer to a dtpm structure corresponding to the parent node 401 * 402 * Create a dtpm node in the tree. If no parent is specified, the node 403 * is the root node of the hierarchy. If the root node already exists, 404 * then the registration will fail. The powercap controller must be 405 * initialized before calling this function. 406 * 407 * The dtpm structure must be initialized with the power numbers 408 * before calling this function. 409 * 410 * Return: zero on success, a negative value in case of error: 411 * -EAGAIN: the function is called before the framework is initialized. 412 * -EBUSY: the root node is already inserted 413 * -EINVAL: * there is no root node yet and @parent is specified 414 * * no all ops are defined 415 * * parent have ops which are reserved for leaves 416 * Other negative values are reported back from the powercap framework 417 */ 418 int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent) 419 { 420 struct powercap_zone *pcz; 421 422 if (!pct) 423 return -EAGAIN; 424 425 if (root && !parent) 426 return -EBUSY; 427 428 if (!root && parent) 429 return -EINVAL; 430 431 if (parent && parent->ops) 432 return -EINVAL; 433 434 if (!dtpm) 435 return -EINVAL; 436 437 if (dtpm->ops && !(dtpm->ops->set_power_uw && 438 dtpm->ops->get_power_uw && 439 dtpm->ops->release)) 440 return -EINVAL; 441 442 pcz = powercap_register_zone(&dtpm->zone, pct, name, 443 parent ? &parent->zone : NULL, 444 &zone_ops, MAX_DTPM_CONSTRAINTS, 445 &constraint_ops); 446 if (IS_ERR(pcz)) 447 return PTR_ERR(pcz); 448 449 mutex_lock(&dtpm_lock); 450 451 if (parent) { 452 list_add_tail(&dtpm->sibling, &parent->children); 453 dtpm->parent = parent; 454 } else { 455 root = dtpm; 456 } 457 458 __dtpm_add_power(dtpm); 459 460 pr_info("Registered dtpm node '%s' / %llu-%llu uW, \n", 461 dtpm->zone.name, dtpm->power_min, dtpm->power_max); 462 463 mutex_unlock(&dtpm_lock); 464 465 return 0; 466 } 467 468 static int __init dtpm_init(void) 469 { 470 struct dtpm_descr **dtpm_descr; 471 472 pct = powercap_register_control_type(NULL, "dtpm", NULL); 473 if (IS_ERR(pct)) { 474 pr_err("Failed to register control type\n"); 475 return PTR_ERR(pct); 476 } 477 478 for_each_dtpm_table(dtpm_descr) 479 (*dtpm_descr)->init(*dtpm_descr); 480 481 return 0; 482 } 483 late_initcall(dtpm_init); 484