1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * SCMI Powercap support. 4 * 5 * Copyright (C) 2022 ARM Ltd. 6 */ 7 8 #include <linux/device.h> 9 #include <linux/math.h> 10 #include <linux/limits.h> 11 #include <linux/list.h> 12 #include <linux/module.h> 13 #include <linux/powercap.h> 14 #include <linux/scmi_protocol.h> 15 16 #define to_scmi_powercap_zone(z) \ 17 container_of(z, struct scmi_powercap_zone, zone) 18 19 static const struct scmi_powercap_proto_ops *powercap_ops; 20 21 struct scmi_powercap_zone { 22 unsigned int height; 23 struct device *dev; 24 struct scmi_protocol_handle *ph; 25 const struct scmi_powercap_info *info; 26 struct scmi_powercap_zone *spzones; 27 struct powercap_zone zone; 28 struct list_head node; 29 }; 30 31 struct scmi_powercap_root { 32 unsigned int num_zones; 33 struct scmi_powercap_zone *spzones; 34 struct list_head *registered_zones; 35 }; 36 37 static struct powercap_control_type *scmi_top_pcntrl; 38 39 static int scmi_powercap_zone_release(struct powercap_zone *pz) 40 { 41 return 0; 42 } 43 44 static int scmi_powercap_get_max_power_range_uw(struct powercap_zone *pz, 45 u64 *max_power_range_uw) 46 { 47 *max_power_range_uw = U32_MAX; 48 return 0; 49 } 50 51 static int scmi_powercap_get_power_uw(struct powercap_zone *pz, 52 u64 *power_uw) 53 { 54 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 55 u32 avg_power, pai; 56 int ret; 57 58 if (!spz->info->powercap_monitoring) 59 return -EINVAL; 60 61 ret = powercap_ops->measurements_get(spz->ph, spz->info->id, &avg_power, 62 &pai); 63 if (ret) 64 return ret; 65 66 *power_uw = avg_power; 67 if (spz->info->powercap_scale_mw) 68 *power_uw *= 1000; 69 70 return 0; 71 } 72 73 static int scmi_powercap_zone_enable_set(struct powercap_zone *pz, bool mode) 74 { 75 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 76 77 return powercap_ops->cap_enable_set(spz->ph, spz->info->id, mode); 78 } 79 80 static int scmi_powercap_zone_enable_get(struct powercap_zone *pz, bool *mode) 81 { 82 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 83 84 return powercap_ops->cap_enable_get(spz->ph, spz->info->id, mode); 85 } 86 87 static const struct powercap_zone_ops zone_ops = { 88 .get_max_power_range_uw = scmi_powercap_get_max_power_range_uw, 89 .get_power_uw = scmi_powercap_get_power_uw, 90 .release = scmi_powercap_zone_release, 91 .set_enable = scmi_powercap_zone_enable_set, 92 .get_enable = scmi_powercap_zone_enable_get, 93 }; 94 95 static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz, 96 u64 power_limit_uw, u32 *norm) 97 { 98 bool scale_mw = spz->info->powercap_scale_mw; 99 u64 val; 100 101 val = scale_mw ? DIV_ROUND_UP_ULL(power_limit_uw, 1000) : power_limit_uw; 102 /* 103 * This cast is lossless since here @req_power is certain to be within 104 * the range [min_power_cap, max_power_cap] whose bounds are assured to 105 * be two unsigned 32bits quantities. 106 */ 107 *norm = clamp_t(u32, val, spz->info->min_power_cap, 108 spz->info->max_power_cap); 109 *norm = rounddown(*norm, spz->info->power_cap_step); 110 111 val = (scale_mw) ? *norm * 1000 : *norm; 112 if (power_limit_uw != val) 113 dev_dbg(spz->dev, 114 "Normalized %s:CAP - requested:%llu - normalized:%llu\n", 115 spz->info->name, power_limit_uw, val); 116 } 117 118 static int scmi_powercap_set_power_limit_uw(struct powercap_zone *pz, int cid, 119 u64 power_uw) 120 { 121 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 122 u32 norm_power; 123 124 if (!spz->info->powercap_cap_config) 125 return -EINVAL; 126 127 scmi_powercap_normalize_cap(spz, power_uw, &norm_power); 128 129 return powercap_ops->cap_set(spz->ph, spz->info->id, norm_power, false); 130 } 131 132 static int scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid, 133 u64 *power_limit_uw) 134 { 135 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 136 u32 power; 137 int ret; 138 139 ret = powercap_ops->cap_get(spz->ph, spz->info->id, &power); 140 if (ret) 141 return ret; 142 143 *power_limit_uw = power; 144 if (spz->info->powercap_scale_mw) 145 *power_limit_uw *= 1000; 146 147 return 0; 148 } 149 150 static void scmi_powercap_normalize_time(const struct scmi_powercap_zone *spz, 151 u64 time_us, u32 *norm) 152 { 153 /* 154 * This cast is lossless since here @time_us is certain to be within the 155 * range [min_pai, max_pai] whose bounds are assured to be two unsigned 156 * 32bits quantities. 157 */ 158 *norm = clamp_t(u32, time_us, spz->info->min_pai, spz->info->max_pai); 159 *norm = rounddown(*norm, spz->info->pai_step); 160 161 if (time_us != *norm) 162 dev_dbg(spz->dev, 163 "Normalized %s:PAI - requested:%llu - normalized:%u\n", 164 spz->info->name, time_us, *norm); 165 } 166 167 static int scmi_powercap_set_time_window_us(struct powercap_zone *pz, int cid, 168 u64 time_window_us) 169 { 170 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 171 u32 norm_pai; 172 173 if (!spz->info->powercap_pai_config) 174 return -EINVAL; 175 176 scmi_powercap_normalize_time(spz, time_window_us, &norm_pai); 177 178 return powercap_ops->pai_set(spz->ph, spz->info->id, norm_pai); 179 } 180 181 static int scmi_powercap_get_time_window_us(struct powercap_zone *pz, int cid, 182 u64 *time_window_us) 183 { 184 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 185 int ret; 186 u32 pai; 187 188 ret = powercap_ops->pai_get(spz->ph, spz->info->id, &pai); 189 if (ret) 190 return ret; 191 192 *time_window_us = pai; 193 194 return 0; 195 } 196 197 static int scmi_powercap_get_max_power_uw(struct powercap_zone *pz, int cid, 198 u64 *max_power_uw) 199 { 200 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 201 202 *max_power_uw = spz->info->max_power_cap; 203 if (spz->info->powercap_scale_mw) 204 *max_power_uw *= 1000; 205 206 return 0; 207 } 208 209 static int scmi_powercap_get_min_power_uw(struct powercap_zone *pz, int cid, 210 u64 *min_power_uw) 211 { 212 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 213 214 *min_power_uw = spz->info->min_power_cap; 215 if (spz->info->powercap_scale_mw) 216 *min_power_uw *= 1000; 217 218 return 0; 219 } 220 221 static int scmi_powercap_get_max_time_window_us(struct powercap_zone *pz, 222 int cid, u64 *time_window_us) 223 { 224 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 225 226 *time_window_us = spz->info->max_pai; 227 228 return 0; 229 } 230 231 static int scmi_powercap_get_min_time_window_us(struct powercap_zone *pz, 232 int cid, u64 *time_window_us) 233 { 234 struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz); 235 236 *time_window_us = (u64)spz->info->min_pai; 237 238 return 0; 239 } 240 241 static const char *scmi_powercap_get_name(struct powercap_zone *pz, int cid) 242 { 243 return "SCMI power-cap"; 244 } 245 246 static const struct powercap_zone_constraint_ops constraint_ops = { 247 .set_power_limit_uw = scmi_powercap_set_power_limit_uw, 248 .get_power_limit_uw = scmi_powercap_get_power_limit_uw, 249 .set_time_window_us = scmi_powercap_set_time_window_us, 250 .get_time_window_us = scmi_powercap_get_time_window_us, 251 .get_max_power_uw = scmi_powercap_get_max_power_uw, 252 .get_min_power_uw = scmi_powercap_get_min_power_uw, 253 .get_max_time_window_us = scmi_powercap_get_max_time_window_us, 254 .get_min_time_window_us = scmi_powercap_get_min_time_window_us, 255 .get_name = scmi_powercap_get_name, 256 }; 257 258 static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr) 259 { 260 int i; 261 262 /* Un-register children zones first starting from the leaves */ 263 for (i = pr->num_zones - 1; i >= 0; i--) { 264 if (!list_empty(&pr->registered_zones[i])) { 265 struct scmi_powercap_zone *spz; 266 267 list_for_each_entry(spz, &pr->registered_zones[i], node) 268 powercap_unregister_zone(scmi_top_pcntrl, 269 &spz->zone); 270 } 271 } 272 } 273 274 static inline bool 275 scmi_powercap_is_zone_registered(struct scmi_powercap_zone *spz) 276 { 277 return !list_empty(&spz->node); 278 } 279 280 static inline unsigned int 281 scmi_powercap_get_zone_height(struct scmi_powercap_zone *spz) 282 { 283 if (spz->info->parent_id == SCMI_POWERCAP_ROOT_ZONE_ID) 284 return 0; 285 286 return spz->spzones[spz->info->parent_id].height + 1; 287 } 288 289 static inline struct scmi_powercap_zone * 290 scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz) 291 { 292 if (spz->info->parent_id == SCMI_POWERCAP_ROOT_ZONE_ID) 293 return NULL; 294 295 return &spz->spzones[spz->info->parent_id]; 296 } 297 298 /** 299 * scmi_powercap_register_zone - Register an SCMI powercap zone recursively 300 * 301 * @pr: A reference to the root powercap zones descriptors 302 * @spz: A reference to the SCMI powercap zone to register 303 * 304 * When registering SCMI powercap zones with the powercap framework we should 305 * take care to always register zones starting from the root ones and to 306 * deregister starting from the leaves. 307 * 308 * Unfortunately we cannot assume that the array of available SCMI powercap 309 * zones provided by the SCMI platform firmware is built to comply with such 310 * requirement. 311 * 312 * This function, given an SCMI powercap zone to register, takes care to walk 313 * the SCMI powercap zones tree up to the root looking recursively for 314 * unregistered parent zones before registering the provided zone; at the same 315 * time each registered zone height in such a tree is accounted for and each 316 * zone, once registered, is stored in the @registered_zones array that is 317 * indexed by zone height: this way will be trivial, at unregister time, to walk 318 * the @registered_zones array backward and unregister all the zones starting 319 * from the leaves, removing children zones before parents. 320 * 321 * While doing this, we prune away any zone marked as invalid (like the ones 322 * sporting an SCMI abstract power scale) as long as they are positioned as 323 * leaves in the SCMI powercap zones hierarchy: any non-leaf invalid zone causes 324 * the entire process to fail since we cannot assume the correctness of an SCMI 325 * powercap zones hierarchy if some of the internal nodes are missing. 326 * 327 * Note that the array of SCMI powercap zones as returned by the SCMI platform 328 * is known to be sane, i.e. zones relationships have been validated at the 329 * protocol layer. 330 * 331 * Return: 0 on Success 332 */ 333 static int scmi_powercap_register_zone(struct scmi_powercap_root *pr, 334 struct scmi_powercap_zone *spz) 335 { 336 int ret = 0; 337 struct scmi_powercap_zone *parent; 338 339 if (!spz->info) 340 return ret; 341 342 parent = scmi_powercap_get_parent_zone(spz); 343 if (parent && !scmi_powercap_is_zone_registered(parent)) { 344 /* 345 * Bail out if a parent domain was marked as unsupported: 346 * only domains participating as leaves can be skipped. 347 */ 348 if (!parent->info) 349 return -ENODEV; 350 351 ret = scmi_powercap_register_zone(pr, parent); 352 if (ret) 353 return ret; 354 } 355 356 if (!scmi_powercap_is_zone_registered(spz)) { 357 struct powercap_zone *z; 358 359 z = powercap_register_zone(&spz->zone, 360 scmi_top_pcntrl, 361 spz->info->name, 362 parent ? &parent->zone : NULL, 363 &zone_ops, 1, &constraint_ops); 364 if (!IS_ERR(z)) { 365 spz->height = scmi_powercap_get_zone_height(spz); 366 list_add(&spz->node, 367 &pr->registered_zones[spz->height]); 368 dev_dbg(spz->dev, 369 "Registered node %s - parent %s - height:%d\n", 370 spz->info->name, 371 parent ? parent->info->name : "ROOT", 372 spz->height); 373 ret = 0; 374 } else { 375 ret = PTR_ERR(z); 376 dev_err(spz->dev, 377 "Error registering node:%s - parent:%s - h:%d - ret:%d\n", 378 spz->info->name, 379 parent ? parent->info->name : "ROOT", 380 spz->height, ret); 381 } 382 } 383 384 return ret; 385 } 386 387 static int scmi_powercap_probe(struct scmi_device *sdev) 388 { 389 int ret, i; 390 struct scmi_powercap_root *pr; 391 struct scmi_powercap_zone *spz; 392 struct scmi_protocol_handle *ph; 393 struct device *dev = &sdev->dev; 394 395 if (!sdev->handle) 396 return -ENODEV; 397 398 powercap_ops = sdev->handle->devm_protocol_get(sdev, 399 SCMI_PROTOCOL_POWERCAP, 400 &ph); 401 if (IS_ERR(powercap_ops)) 402 return PTR_ERR(powercap_ops); 403 404 pr = devm_kzalloc(dev, sizeof(*pr), GFP_KERNEL); 405 if (!pr) 406 return -ENOMEM; 407 408 ret = powercap_ops->num_domains_get(ph); 409 if (ret < 0) { 410 dev_err(dev, "number of powercap domains not found\n"); 411 return ret; 412 } 413 pr->num_zones = ret; 414 415 pr->spzones = devm_kcalloc(dev, pr->num_zones, 416 sizeof(*pr->spzones), GFP_KERNEL); 417 if (!pr->spzones) 418 return -ENOMEM; 419 420 /* Allocate for worst possible scenario of maximum tree height. */ 421 pr->registered_zones = devm_kcalloc(dev, pr->num_zones, 422 sizeof(*pr->registered_zones), 423 GFP_KERNEL); 424 if (!pr->registered_zones) 425 return -ENOMEM; 426 427 for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) { 428 /* 429 * Powercap domains are validate by the protocol layer, i.e. 430 * when only non-NULL domains are returned here, whose 431 * parent_id is assured to point to another valid domain. 432 */ 433 spz->info = powercap_ops->info_get(ph, i); 434 435 spz->dev = dev; 436 spz->ph = ph; 437 spz->spzones = pr->spzones; 438 INIT_LIST_HEAD(&spz->node); 439 INIT_LIST_HEAD(&pr->registered_zones[i]); 440 441 /* 442 * Forcibly skip powercap domains using an abstract scale. 443 * Note that only leaves domains can be skipped, so this could 444 * lead later to a global failure. 445 */ 446 if (!spz->info->powercap_scale_uw && 447 !spz->info->powercap_scale_mw) { 448 dev_warn(dev, 449 "Abstract power scale not supported. Skip %s.\n", 450 spz->info->name); 451 spz->info = NULL; 452 continue; 453 } 454 } 455 456 /* 457 * Scan array of retrieved SCMI powercap domains and register them 458 * recursively starting from the root domains. 459 */ 460 for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) { 461 ret = scmi_powercap_register_zone(pr, spz); 462 if (ret) { 463 dev_err(dev, 464 "Failed to register powercap zone %s - ret:%d\n", 465 spz->info->name, ret); 466 scmi_powercap_unregister_all_zones(pr); 467 return ret; 468 } 469 } 470 471 dev_set_drvdata(dev, pr); 472 473 dev_info(dev, "Registered %d SCMI Powercap domains !\n", pr->num_zones); 474 475 return ret; 476 } 477 478 static void scmi_powercap_remove(struct scmi_device *sdev) 479 { 480 struct device *dev = &sdev->dev; 481 struct scmi_powercap_root *pr = dev_get_drvdata(dev); 482 483 scmi_powercap_unregister_all_zones(pr); 484 } 485 486 static const struct scmi_device_id scmi_id_table[] = { 487 { SCMI_PROTOCOL_POWERCAP, "powercap" }, 488 { }, 489 }; 490 MODULE_DEVICE_TABLE(scmi, scmi_id_table); 491 492 static struct scmi_driver scmi_powercap_driver = { 493 .name = "scmi-powercap", 494 .probe = scmi_powercap_probe, 495 .remove = scmi_powercap_remove, 496 .id_table = scmi_id_table, 497 }; 498 499 static int __init scmi_powercap_init(void) 500 { 501 int ret; 502 503 scmi_top_pcntrl = powercap_register_control_type(NULL, "arm-scmi", NULL); 504 if (IS_ERR(scmi_top_pcntrl)) 505 return PTR_ERR(scmi_top_pcntrl); 506 507 ret = scmi_register(&scmi_powercap_driver); 508 if (ret) 509 powercap_unregister_control_type(scmi_top_pcntrl); 510 511 return ret; 512 } 513 module_init(scmi_powercap_init); 514 515 static void __exit scmi_powercap_exit(void) 516 { 517 scmi_unregister(&scmi_powercap_driver); 518 519 powercap_unregister_control_type(scmi_top_pcntrl); 520 } 521 module_exit(scmi_powercap_exit); 522 523 MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>"); 524 MODULE_DESCRIPTION("ARM SCMI Powercap driver"); 525 MODULE_LICENSE("GPL"); 526