arm_scmi_powercap.c 15 KB

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