windfarm_cpufreq_clamp.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/types.h>
  3. #include <linux/errno.h>
  4. #include <linux/kernel.h>
  5. #include <linux/delay.h>
  6. #include <linux/pm_qos.h>
  7. #include <linux/slab.h>
  8. #include <linux/init.h>
  9. #include <linux/wait.h>
  10. #include <linux/cpu.h>
  11. #include <linux/cpufreq.h>
  12. #include "windfarm.h"
  13. #define VERSION "0.3"
  14. static int clamped;
  15. static struct wf_control *clamp_control;
  16. static struct freq_qos_request qos_req;
  17. static unsigned int min_freq, max_freq;
  18. static int clamp_set(struct wf_control *ct, s32 value)
  19. {
  20. unsigned int freq;
  21. if (value) {
  22. freq = min_freq;
  23. printk(KERN_INFO "windfarm: Clamping CPU frequency to "
  24. "minimum !\n");
  25. } else {
  26. freq = max_freq;
  27. printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
  28. }
  29. clamped = value;
  30. return freq_qos_update_request(&qos_req, freq);
  31. }
  32. static int clamp_get(struct wf_control *ct, s32 *value)
  33. {
  34. *value = clamped;
  35. return 0;
  36. }
  37. static s32 clamp_min(struct wf_control *ct)
  38. {
  39. return 0;
  40. }
  41. static s32 clamp_max(struct wf_control *ct)
  42. {
  43. return 1;
  44. }
  45. static const struct wf_control_ops clamp_ops = {
  46. .set_value = clamp_set,
  47. .get_value = clamp_get,
  48. .get_min = clamp_min,
  49. .get_max = clamp_max,
  50. .owner = THIS_MODULE,
  51. };
  52. static int __init wf_cpufreq_clamp_init(void)
  53. {
  54. struct cpufreq_policy *policy;
  55. struct wf_control *clamp;
  56. struct device *dev;
  57. int ret;
  58. policy = cpufreq_cpu_get(0);
  59. if (!policy) {
  60. pr_warn("%s: cpufreq policy not found cpu0\n", __func__);
  61. return -EPROBE_DEFER;
  62. }
  63. min_freq = policy->cpuinfo.min_freq;
  64. max_freq = policy->cpuinfo.max_freq;
  65. ret = freq_qos_add_request(&policy->constraints, &qos_req, FREQ_QOS_MAX,
  66. max_freq);
  67. cpufreq_cpu_put(policy);
  68. if (ret < 0) {
  69. pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
  70. ret);
  71. return ret;
  72. }
  73. dev = get_cpu_device(0);
  74. if (unlikely(!dev)) {
  75. pr_warn("%s: No cpu device for cpu0\n", __func__);
  76. ret = -ENODEV;
  77. goto fail;
  78. }
  79. clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
  80. if (clamp == NULL) {
  81. ret = -ENOMEM;
  82. goto fail;
  83. }
  84. clamp->ops = &clamp_ops;
  85. clamp->name = "cpufreq-clamp";
  86. ret = wf_register_control(clamp);
  87. if (ret)
  88. goto free;
  89. clamp_control = clamp;
  90. return 0;
  91. free:
  92. kfree(clamp);
  93. fail:
  94. freq_qos_remove_request(&qos_req);
  95. return ret;
  96. }
  97. static void __exit wf_cpufreq_clamp_exit(void)
  98. {
  99. if (clamp_control) {
  100. wf_unregister_control(clamp_control);
  101. freq_qos_remove_request(&qos_req);
  102. }
  103. }
  104. module_init(wf_cpufreq_clamp_init);
  105. module_exit(wf_cpufreq_clamp_exit);
  106. MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
  107. MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control");
  108. MODULE_LICENSE("GPL");