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