cpufreq_cooling.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/drivers/thermal/cpufreq_cooling.c
  4. *
  5. * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
  6. *
  7. * Copyright (C) 2012-2018 Linaro Limited.
  8. *
  9. * Authors: Amit Daniel <[email protected]>
  10. * Viresh Kumar <[email protected]>
  11. *
  12. */
  13. #include <linux/cpu.h>
  14. #include <linux/cpufreq.h>
  15. #include <linux/cpu_cooling.h>
  16. #include <linux/device.h>
  17. #include <linux/energy_model.h>
  18. #include <linux/err.h>
  19. #include <linux/export.h>
  20. #include <linux/pm_opp.h>
  21. #include <linux/pm_qos.h>
  22. #include <linux/slab.h>
  23. #include <linux/thermal.h>
  24. #include <linux/units.h>
  25. #include <trace/events/thermal.h>
  26. #include <trace/hooks/thermal.h>
  27. /*
  28. * Cooling state <-> CPUFreq frequency
  29. *
  30. * Cooling states are translated to frequencies throughout this driver and this
  31. * is the relation between them.
  32. *
  33. * Highest cooling state corresponds to lowest possible frequency.
  34. *
  35. * i.e.
  36. * level 0 --> 1st Max Freq
  37. * level 1 --> 2nd Max Freq
  38. * ...
  39. */
  40. /**
  41. * struct time_in_idle - Idle time stats
  42. * @time: previous reading of the absolute time that this cpu was idle
  43. * @timestamp: wall time of the last invocation of get_cpu_idle_time_us()
  44. */
  45. struct time_in_idle {
  46. u64 time;
  47. u64 timestamp;
  48. };
  49. /**
  50. * struct cpufreq_cooling_device - data for cooling device with cpufreq
  51. * @last_load: load measured by the latest call to cpufreq_get_requested_power()
  52. * @cpufreq_state: integer value representing the current state of cpufreq
  53. * cooling devices.
  54. * @max_level: maximum cooling level. One less than total number of valid
  55. * cpufreq frequencies.
  56. * @em: Reference on the Energy Model of the device
  57. * @cdev: thermal_cooling_device pointer to keep track of the
  58. * registered cooling device.
  59. * @policy: cpufreq policy.
  60. * @cooling_ops: cpufreq callbacks to thermal cooling device ops
  61. * @idle_time: idle time stats
  62. * @qos_req: PM QoS contraint to apply
  63. *
  64. * This structure is required for keeping information of each registered
  65. * cpufreq_cooling_device.
  66. */
  67. struct cpufreq_cooling_device {
  68. u32 last_load;
  69. unsigned int cpufreq_state;
  70. unsigned int max_level;
  71. struct em_perf_domain *em;
  72. struct cpufreq_policy *policy;
  73. struct thermal_cooling_device_ops cooling_ops;
  74. #ifndef CONFIG_SMP
  75. struct time_in_idle *idle_time;
  76. #endif
  77. struct freq_qos_request qos_req;
  78. };
  79. #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
  80. /**
  81. * get_level: Find the level for a particular frequency
  82. * @cpufreq_cdev: cpufreq_cdev for which the property is required
  83. * @freq: Frequency
  84. *
  85. * Return: level corresponding to the frequency.
  86. */
  87. static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
  88. unsigned int freq)
  89. {
  90. int i;
  91. for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
  92. if (freq > cpufreq_cdev->em->table[i].frequency)
  93. break;
  94. }
  95. return cpufreq_cdev->max_level - i - 1;
  96. }
  97. static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
  98. u32 freq)
  99. {
  100. unsigned long power_mw;
  101. int i;
  102. for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
  103. if (freq > cpufreq_cdev->em->table[i].frequency)
  104. break;
  105. }
  106. power_mw = cpufreq_cdev->em->table[i + 1].power;
  107. power_mw /= MICROWATT_PER_MILLIWATT;
  108. return power_mw;
  109. }
  110. static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
  111. u32 power)
  112. {
  113. unsigned long em_power_mw;
  114. int i;
  115. for (i = cpufreq_cdev->max_level; i > 0; i--) {
  116. /* Convert EM power to milli-Watts to make safe comparison */
  117. em_power_mw = cpufreq_cdev->em->table[i].power;
  118. em_power_mw /= MICROWATT_PER_MILLIWATT;
  119. if (power >= em_power_mw)
  120. break;
  121. }
  122. return cpufreq_cdev->em->table[i].frequency;
  123. }
  124. /**
  125. * get_load() - get load for a cpu
  126. * @cpufreq_cdev: struct cpufreq_cooling_device for the cpu
  127. * @cpu: cpu number
  128. * @cpu_idx: index of the cpu in time_in_idle array
  129. *
  130. * Return: The average load of cpu @cpu in percentage since this
  131. * function was last called.
  132. */
  133. #ifdef CONFIG_SMP
  134. static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
  135. int cpu_idx)
  136. {
  137. unsigned long util = sched_cpu_util(cpu);
  138. return (util * 100) / arch_scale_cpu_capacity(cpu);
  139. }
  140. #else /* !CONFIG_SMP */
  141. static u32 get_load(struct cpufreq_cooling_device *cpufreq_cdev, int cpu,
  142. int cpu_idx)
  143. {
  144. u32 load;
  145. u64 now, now_idle, delta_time, delta_idle;
  146. struct time_in_idle *idle_time = &cpufreq_cdev->idle_time[cpu_idx];
  147. now_idle = get_cpu_idle_time(cpu, &now, 0);
  148. delta_idle = now_idle - idle_time->time;
  149. delta_time = now - idle_time->timestamp;
  150. if (delta_time <= delta_idle)
  151. load = 0;
  152. else
  153. load = div64_u64(100 * (delta_time - delta_idle), delta_time);
  154. idle_time->time = now_idle;
  155. idle_time->timestamp = now;
  156. return load;
  157. }
  158. #endif /* CONFIG_SMP */
  159. /**
  160. * get_dynamic_power() - calculate the dynamic power
  161. * @cpufreq_cdev: &cpufreq_cooling_device for this cdev
  162. * @freq: current frequency
  163. *
  164. * Return: the dynamic power consumed by the cpus described by
  165. * @cpufreq_cdev.
  166. */
  167. static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_cdev,
  168. unsigned long freq)
  169. {
  170. u32 raw_cpu_power;
  171. raw_cpu_power = cpu_freq_to_power(cpufreq_cdev, freq);
  172. return (raw_cpu_power * cpufreq_cdev->last_load) / 100;
  173. }
  174. /**
  175. * cpufreq_get_requested_power() - get the current power
  176. * @cdev: &thermal_cooling_device pointer
  177. * @power: pointer in which to store the resulting power
  178. *
  179. * Calculate the current power consumption of the cpus in milliwatts
  180. * and store it in @power. This function should actually calculate
  181. * the requested power, but it's hard to get the frequency that
  182. * cpufreq would have assigned if there were no thermal limits.
  183. * Instead, we calculate the current power on the assumption that the
  184. * immediate future will look like the immediate past.
  185. *
  186. * We use the current frequency and the average load since this
  187. * function was last called. In reality, there could have been
  188. * multiple opps since this function was last called and that affects
  189. * the load calculation. While it's not perfectly accurate, this
  190. * simplification is good enough and works. REVISIT this, as more
  191. * complex code may be needed if experiments show that it's not
  192. * accurate enough.
  193. *
  194. * Return: 0 on success, this function doesn't fail.
  195. */
  196. static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
  197. u32 *power)
  198. {
  199. unsigned long freq;
  200. int i = 0, cpu;
  201. u32 total_load = 0;
  202. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  203. struct cpufreq_policy *policy = cpufreq_cdev->policy;
  204. freq = cpufreq_quick_get(policy->cpu);
  205. trace_android_vh_modify_thermal_request_freq(policy, &freq);
  206. for_each_cpu(cpu, policy->related_cpus) {
  207. u32 load;
  208. if (cpu_online(cpu))
  209. load = get_load(cpufreq_cdev, cpu, i);
  210. else
  211. load = 0;
  212. total_load += load;
  213. }
  214. cpufreq_cdev->last_load = total_load;
  215. *power = get_dynamic_power(cpufreq_cdev, freq);
  216. trace_thermal_power_cpu_get_power_simple(policy->cpu, *power);
  217. return 0;
  218. }
  219. /**
  220. * cpufreq_state2power() - convert a cpu cdev state to power consumed
  221. * @cdev: &thermal_cooling_device pointer
  222. * @state: cooling device state to be converted
  223. * @power: pointer in which to store the resulting power
  224. *
  225. * Convert cooling device state @state into power consumption in
  226. * milliwatts assuming 100% load. Store the calculated power in
  227. * @power.
  228. *
  229. * Return: 0 on success, -EINVAL if the cooling device state is bigger
  230. * than maximum allowed.
  231. */
  232. static int cpufreq_state2power(struct thermal_cooling_device *cdev,
  233. unsigned long state, u32 *power)
  234. {
  235. unsigned int freq, num_cpus, idx;
  236. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  237. /* Request state should be less than max_level */
  238. if (state > cpufreq_cdev->max_level)
  239. return -EINVAL;
  240. num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
  241. idx = cpufreq_cdev->max_level - state;
  242. freq = cpufreq_cdev->em->table[idx].frequency;
  243. *power = cpu_freq_to_power(cpufreq_cdev, freq) * num_cpus;
  244. return 0;
  245. }
  246. /**
  247. * cpufreq_power2state() - convert power to a cooling device state
  248. * @cdev: &thermal_cooling_device pointer
  249. * @power: power in milliwatts to be converted
  250. * @state: pointer in which to store the resulting state
  251. *
  252. * Calculate a cooling device state for the cpus described by @cdev
  253. * that would allow them to consume at most @power mW and store it in
  254. * @state. Note that this calculation depends on external factors
  255. * such as the CPUs load. Calling this function with the same power
  256. * as input can yield different cooling device states depending on those
  257. * external factors.
  258. *
  259. * Return: 0 on success, this function doesn't fail.
  260. */
  261. static int cpufreq_power2state(struct thermal_cooling_device *cdev,
  262. u32 power, unsigned long *state)
  263. {
  264. unsigned int target_freq;
  265. u32 last_load, normalised_power;
  266. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  267. struct cpufreq_policy *policy = cpufreq_cdev->policy;
  268. last_load = cpufreq_cdev->last_load ?: 1;
  269. normalised_power = (power * 100) / last_load;
  270. target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
  271. trace_android_vh_modify_thermal_target_freq(policy, &target_freq);
  272. *state = get_level(cpufreq_cdev, target_freq);
  273. trace_thermal_power_cpu_limit(policy->related_cpus, target_freq, *state,
  274. power);
  275. return 0;
  276. }
  277. static inline bool em_is_sane(struct cpufreq_cooling_device *cpufreq_cdev,
  278. struct em_perf_domain *em) {
  279. struct cpufreq_policy *policy;
  280. unsigned int nr_levels;
  281. if (!em || em_is_artificial(em))
  282. return false;
  283. policy = cpufreq_cdev->policy;
  284. if (!cpumask_equal(policy->related_cpus, em_span_cpus(em))) {
  285. pr_err("The span of pd %*pbl is misaligned with cpufreq policy %*pbl\n",
  286. cpumask_pr_args(em_span_cpus(em)),
  287. cpumask_pr_args(policy->related_cpus));
  288. return false;
  289. }
  290. nr_levels = cpufreq_cdev->max_level + 1;
  291. if (em_pd_nr_perf_states(em) != nr_levels) {
  292. pr_err("The number of performance states in pd %*pbl (%u) doesn't match the number of cooling levels (%u)\n",
  293. cpumask_pr_args(em_span_cpus(em)),
  294. em_pd_nr_perf_states(em), nr_levels);
  295. return false;
  296. }
  297. return true;
  298. }
  299. #endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
  300. #ifdef CONFIG_SMP
  301. static inline int allocate_idle_time(struct cpufreq_cooling_device *cpufreq_cdev)
  302. {
  303. return 0;
  304. }
  305. static inline void free_idle_time(struct cpufreq_cooling_device *cpufreq_cdev)
  306. {
  307. }
  308. #else
  309. static int allocate_idle_time(struct cpufreq_cooling_device *cpufreq_cdev)
  310. {
  311. unsigned int num_cpus = cpumask_weight(cpufreq_cdev->policy->related_cpus);
  312. cpufreq_cdev->idle_time = kcalloc(num_cpus,
  313. sizeof(*cpufreq_cdev->idle_time),
  314. GFP_KERNEL);
  315. if (!cpufreq_cdev->idle_time)
  316. return -ENOMEM;
  317. return 0;
  318. }
  319. static void free_idle_time(struct cpufreq_cooling_device *cpufreq_cdev)
  320. {
  321. kfree(cpufreq_cdev->idle_time);
  322. cpufreq_cdev->idle_time = NULL;
  323. }
  324. #endif /* CONFIG_SMP */
  325. static unsigned int get_state_freq(struct cpufreq_cooling_device *cpufreq_cdev,
  326. unsigned long state)
  327. {
  328. struct cpufreq_policy *policy;
  329. unsigned long idx;
  330. #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
  331. /* Use the Energy Model table if available */
  332. if (cpufreq_cdev->em) {
  333. idx = cpufreq_cdev->max_level - state;
  334. return cpufreq_cdev->em->table[idx].frequency;
  335. }
  336. #endif
  337. /* Otherwise, fallback on the CPUFreq table */
  338. policy = cpufreq_cdev->policy;
  339. if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
  340. idx = cpufreq_cdev->max_level - state;
  341. else
  342. idx = state;
  343. return policy->freq_table[idx].frequency;
  344. }
  345. /* cpufreq cooling device callback functions are defined below */
  346. /**
  347. * cpufreq_get_max_state - callback function to get the max cooling state.
  348. * @cdev: thermal cooling device pointer.
  349. * @state: fill this variable with the max cooling state.
  350. *
  351. * Callback for the thermal cooling device to return the cpufreq
  352. * max cooling state.
  353. *
  354. * Return: 0 on success, this function doesn't fail.
  355. */
  356. static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
  357. unsigned long *state)
  358. {
  359. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  360. *state = cpufreq_cdev->max_level;
  361. return 0;
  362. }
  363. /**
  364. * cpufreq_get_cur_state - callback function to get the current cooling state.
  365. * @cdev: thermal cooling device pointer.
  366. * @state: fill this variable with the current cooling state.
  367. *
  368. * Callback for the thermal cooling device to return the cpufreq
  369. * current cooling state.
  370. *
  371. * Return: 0 on success, this function doesn't fail.
  372. */
  373. static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
  374. unsigned long *state)
  375. {
  376. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  377. *state = cpufreq_cdev->cpufreq_state;
  378. return 0;
  379. }
  380. /**
  381. * cpufreq_set_cur_state - callback function to set the current cooling state.
  382. * @cdev: thermal cooling device pointer.
  383. * @state: set this variable to the current cooling state.
  384. *
  385. * Callback for the thermal cooling device to change the cpufreq
  386. * current cooling state.
  387. *
  388. * Return: 0 on success, an error code otherwise.
  389. */
  390. static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
  391. unsigned long state)
  392. {
  393. struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
  394. struct cpumask *cpus;
  395. unsigned int frequency;
  396. int ret;
  397. /* Request state should be less than max_level */
  398. if (state > cpufreq_cdev->max_level)
  399. return -EINVAL;
  400. /* Check if the old cooling action is same as new cooling action */
  401. if (cpufreq_cdev->cpufreq_state == state)
  402. return 0;
  403. frequency = get_state_freq(cpufreq_cdev, state);
  404. ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
  405. if (ret >= 0) {
  406. cpufreq_cdev->cpufreq_state = state;
  407. cpus = cpufreq_cdev->policy->related_cpus;
  408. arch_update_thermal_pressure(cpus, frequency);
  409. ret = 0;
  410. }
  411. return ret;
  412. }
  413. /**
  414. * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  415. * @np: a valid struct device_node to the cooling device tree node
  416. * @policy: cpufreq policy
  417. * Normally this should be same as cpufreq policy->related_cpus.
  418. * @em: Energy Model of the cpufreq policy
  419. *
  420. * This interface function registers the cpufreq cooling device with the name
  421. * "cpufreq-%s". This API can support multiple instances of cpufreq
  422. * cooling devices. It also gives the opportunity to link the cooling device
  423. * with a device tree node, in order to bind it via the thermal DT code.
  424. *
  425. * Return: a valid struct thermal_cooling_device pointer on success,
  426. * on failure, it returns a corresponding ERR_PTR().
  427. */
  428. static struct thermal_cooling_device *
  429. __cpufreq_cooling_register(struct device_node *np,
  430. struct cpufreq_policy *policy,
  431. struct em_perf_domain *em)
  432. {
  433. struct thermal_cooling_device *cdev;
  434. struct cpufreq_cooling_device *cpufreq_cdev;
  435. unsigned int i;
  436. struct device *dev;
  437. int ret;
  438. struct thermal_cooling_device_ops *cooling_ops;
  439. char *name;
  440. if (IS_ERR_OR_NULL(policy)) {
  441. pr_err("%s: cpufreq policy isn't valid: %p\n", __func__, policy);
  442. return ERR_PTR(-EINVAL);
  443. }
  444. dev = get_cpu_device(policy->cpu);
  445. if (unlikely(!dev)) {
  446. pr_warn("No cpu device for cpu %d\n", policy->cpu);
  447. return ERR_PTR(-ENODEV);
  448. }
  449. i = cpufreq_table_count_valid_entries(policy);
  450. if (!i) {
  451. pr_debug("%s: CPUFreq table not found or has no valid entries\n",
  452. __func__);
  453. return ERR_PTR(-ENODEV);
  454. }
  455. cpufreq_cdev = kzalloc(sizeof(*cpufreq_cdev), GFP_KERNEL);
  456. if (!cpufreq_cdev)
  457. return ERR_PTR(-ENOMEM);
  458. cpufreq_cdev->policy = policy;
  459. ret = allocate_idle_time(cpufreq_cdev);
  460. if (ret) {
  461. cdev = ERR_PTR(ret);
  462. goto free_cdev;
  463. }
  464. /* max_level is an index, not a counter */
  465. cpufreq_cdev->max_level = i - 1;
  466. cooling_ops = &cpufreq_cdev->cooling_ops;
  467. cooling_ops->get_max_state = cpufreq_get_max_state;
  468. cooling_ops->get_cur_state = cpufreq_get_cur_state;
  469. cooling_ops->set_cur_state = cpufreq_set_cur_state;
  470. #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
  471. if (em_is_sane(cpufreq_cdev, em)) {
  472. cpufreq_cdev->em = em;
  473. cooling_ops->get_requested_power = cpufreq_get_requested_power;
  474. cooling_ops->state2power = cpufreq_state2power;
  475. cooling_ops->power2state = cpufreq_power2state;
  476. } else
  477. #endif
  478. if (policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED) {
  479. pr_err("%s: unsorted frequency tables are not supported\n",
  480. __func__);
  481. cdev = ERR_PTR(-EINVAL);
  482. goto free_idle_time;
  483. }
  484. ret = freq_qos_add_request(&policy->constraints,
  485. &cpufreq_cdev->qos_req, FREQ_QOS_MAX,
  486. get_state_freq(cpufreq_cdev, 0));
  487. if (ret < 0) {
  488. pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
  489. ret);
  490. cdev = ERR_PTR(ret);
  491. goto free_idle_time;
  492. }
  493. cdev = ERR_PTR(-ENOMEM);
  494. name = kasprintf(GFP_KERNEL, "cpufreq-%s", dev_name(dev));
  495. if (!name)
  496. goto remove_qos_req;
  497. cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev,
  498. cooling_ops);
  499. kfree(name);
  500. if (IS_ERR(cdev))
  501. goto remove_qos_req;
  502. return cdev;
  503. remove_qos_req:
  504. freq_qos_remove_request(&cpufreq_cdev->qos_req);
  505. free_idle_time:
  506. free_idle_time(cpufreq_cdev);
  507. free_cdev:
  508. kfree(cpufreq_cdev);
  509. return cdev;
  510. }
  511. /**
  512. * cpufreq_cooling_register - function to create cpufreq cooling device.
  513. * @policy: cpufreq policy
  514. *
  515. * This interface function registers the cpufreq cooling device with the name
  516. * "cpufreq-%s". This API can support multiple instances of cpufreq cooling
  517. * devices.
  518. *
  519. * Return: a valid struct thermal_cooling_device pointer on success,
  520. * on failure, it returns a corresponding ERR_PTR().
  521. */
  522. struct thermal_cooling_device *
  523. cpufreq_cooling_register(struct cpufreq_policy *policy)
  524. {
  525. return __cpufreq_cooling_register(NULL, policy, NULL);
  526. }
  527. EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
  528. /**
  529. * of_cpufreq_cooling_register - function to create cpufreq cooling device.
  530. * @policy: cpufreq policy
  531. *
  532. * This interface function registers the cpufreq cooling device with the name
  533. * "cpufreq-%s". This API can support multiple instances of cpufreq cooling
  534. * devices. Using this API, the cpufreq cooling device will be linked to the
  535. * device tree node provided.
  536. *
  537. * Using this function, the cooling device will implement the power
  538. * extensions by using the Energy Model (if present). The cpus must have
  539. * registered their OPPs using the OPP library.
  540. *
  541. * Return: a valid struct thermal_cooling_device pointer on success,
  542. * and NULL on failure.
  543. */
  544. struct thermal_cooling_device *
  545. of_cpufreq_cooling_register(struct cpufreq_policy *policy)
  546. {
  547. struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
  548. struct thermal_cooling_device *cdev = NULL;
  549. if (!np) {
  550. pr_err("cpufreq_cooling: OF node not available for cpu%d\n",
  551. policy->cpu);
  552. return NULL;
  553. }
  554. if (of_find_property(np, "#cooling-cells", NULL)) {
  555. struct em_perf_domain *em = em_cpu_get(policy->cpu);
  556. cdev = __cpufreq_cooling_register(np, policy, em);
  557. if (IS_ERR(cdev)) {
  558. pr_err("cpufreq_cooling: cpu%d failed to register as cooling device: %ld\n",
  559. policy->cpu, PTR_ERR(cdev));
  560. cdev = NULL;
  561. }
  562. }
  563. of_node_put(np);
  564. return cdev;
  565. }
  566. EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
  567. /**
  568. * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
  569. * @cdev: thermal cooling device pointer.
  570. *
  571. * This interface function unregisters the "cpufreq-%x" cooling device.
  572. */
  573. void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
  574. {
  575. struct cpufreq_cooling_device *cpufreq_cdev;
  576. if (!cdev)
  577. return;
  578. cpufreq_cdev = cdev->devdata;
  579. thermal_cooling_device_unregister(cdev);
  580. freq_qos_remove_request(&cpufreq_cdev->qos_req);
  581. free_idle_time(cpufreq_cdev);
  582. kfree(cpufreq_cdev);
  583. }
  584. EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);