cpufreq_userspace.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * linux/drivers/cpufreq/cpufreq_userspace.c
  3. *
  4. * Copyright (C) 2001 Russell King
  5. * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/smp.h>
  15. #include <linux/init.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/cpufreq.h>
  19. #include <linux/cpu.h>
  20. #include <linux/types.h>
  21. #include <linux/fs.h>
  22. #include <linux/sysfs.h>
  23. #include <linux/mutex.h>
  24. #include <asm/uaccess.h>
  25. /**
  26. * A few values needed by the userspace governor
  27. */
  28. static unsigned int cpu_max_freq[NR_CPUS];
  29. static unsigned int cpu_min_freq[NR_CPUS];
  30. static unsigned int cpu_cur_freq[NR_CPUS]; /* current CPU freq */
  31. static unsigned int cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */
  32. static unsigned int cpu_is_managed[NR_CPUS];
  33. static DEFINE_MUTEX (userspace_mutex);
  34. static int cpus_using_userspace_governor;
  35. #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
  36. /* keep track of frequency transitions */
  37. static int
  38. userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
  39. void *data)
  40. {
  41. struct cpufreq_freqs *freq = data;
  42. if (!cpu_is_managed[freq->cpu])
  43. return 0;
  44. dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n",
  45. freq->cpu, freq->new);
  46. cpu_cur_freq[freq->cpu] = freq->new;
  47. return 0;
  48. }
  49. static struct notifier_block userspace_cpufreq_notifier_block = {
  50. .notifier_call = userspace_cpufreq_notifier
  51. };
  52. /**
  53. * cpufreq_set - set the CPU frequency
  54. * @freq: target frequency in kHz
  55. * @cpu: CPU for which the frequency is to be set
  56. *
  57. * Sets the CPU frequency to freq.
  58. */
  59. static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
  60. {
  61. int ret = -EINVAL;
  62. dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
  63. mutex_lock(&userspace_mutex);
  64. if (!cpu_is_managed[policy->cpu])
  65. goto err;
  66. cpu_set_freq[policy->cpu] = freq;
  67. if (freq < cpu_min_freq[policy->cpu])
  68. freq = cpu_min_freq[policy->cpu];
  69. if (freq > cpu_max_freq[policy->cpu])
  70. freq = cpu_max_freq[policy->cpu];
  71. /*
  72. * We're safe from concurrent calls to ->target() here
  73. * as we hold the userspace_mutex lock. If we were calling
  74. * cpufreq_driver_target, a deadlock situation might occur:
  75. * A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock)
  76. * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex)
  77. */
  78. ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
  79. err:
  80. mutex_unlock(&userspace_mutex);
  81. return ret;
  82. }
  83. /************************** sysfs interface ************************/
  84. static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
  85. {
  86. return sprintf (buf, "%u\n", cpu_cur_freq[policy->cpu]);
  87. }
  88. static ssize_t
  89. store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
  90. {
  91. unsigned int freq = 0;
  92. unsigned int ret;
  93. ret = sscanf (buf, "%u", &freq);
  94. if (ret != 1)
  95. return -EINVAL;
  96. cpufreq_set(freq, policy);
  97. return count;
  98. }
  99. static struct freq_attr freq_attr_scaling_setspeed =
  100. {
  101. .attr = { .name = "scaling_setspeed", .mode = 0644 },
  102. .show = show_speed,
  103. .store = store_speed,
  104. };
  105. static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
  106. unsigned int event)
  107. {
  108. unsigned int cpu = policy->cpu;
  109. int rc = 0;
  110. switch (event) {
  111. case CPUFREQ_GOV_START:
  112. if (!cpu_online(cpu))
  113. return -EINVAL;
  114. BUG_ON(!policy->cur);
  115. mutex_lock(&userspace_mutex);
  116. rc = sysfs_create_file (&policy->kobj,
  117. &freq_attr_scaling_setspeed.attr);
  118. if (rc)
  119. goto start_out;
  120. if (cpus_using_userspace_governor == 0) {
  121. cpufreq_register_notifier(
  122. &userspace_cpufreq_notifier_block,
  123. CPUFREQ_TRANSITION_NOTIFIER);
  124. }
  125. cpus_using_userspace_governor++;
  126. cpu_is_managed[cpu] = 1;
  127. cpu_min_freq[cpu] = policy->min;
  128. cpu_max_freq[cpu] = policy->max;
  129. cpu_cur_freq[cpu] = policy->cur;
  130. cpu_set_freq[cpu] = policy->cur;
  131. dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]);
  132. start_out:
  133. mutex_unlock(&userspace_mutex);
  134. break;
  135. case CPUFREQ_GOV_STOP:
  136. mutex_lock(&userspace_mutex);
  137. cpus_using_userspace_governor--;
  138. if (cpus_using_userspace_governor == 0) {
  139. cpufreq_unregister_notifier(
  140. &userspace_cpufreq_notifier_block,
  141. CPUFREQ_TRANSITION_NOTIFIER);
  142. }
  143. cpu_is_managed[cpu] = 0;
  144. cpu_min_freq[cpu] = 0;
  145. cpu_max_freq[cpu] = 0;
  146. cpu_set_freq[cpu] = 0;
  147. sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
  148. dprintk("managing cpu %u stopped\n", cpu);
  149. mutex_unlock(&userspace_mutex);
  150. break;
  151. case CPUFREQ_GOV_LIMITS:
  152. mutex_lock(&userspace_mutex);
  153. dprintk("limit event for cpu %u: %u - %u kHz,"
  154. "currently %u kHz, last set to %u kHz\n",
  155. cpu, policy->min, policy->max,
  156. cpu_cur_freq[cpu], cpu_set_freq[cpu]);
  157. if (policy->max < cpu_set_freq[cpu]) {
  158. __cpufreq_driver_target(policy, policy->max,
  159. CPUFREQ_RELATION_H);
  160. }
  161. else if (policy->min > cpu_set_freq[cpu]) {
  162. __cpufreq_driver_target(policy, policy->min,
  163. CPUFREQ_RELATION_L);
  164. }
  165. else {
  166. __cpufreq_driver_target(policy, cpu_set_freq[cpu],
  167. CPUFREQ_RELATION_L);
  168. }
  169. cpu_min_freq[cpu] = policy->min;
  170. cpu_max_freq[cpu] = policy->max;
  171. cpu_cur_freq[cpu] = policy->cur;
  172. mutex_unlock(&userspace_mutex);
  173. break;
  174. }
  175. return rc;
  176. }
  177. struct cpufreq_governor cpufreq_gov_userspace = {
  178. .name = "userspace",
  179. .governor = cpufreq_governor_userspace,
  180. .owner = THIS_MODULE,
  181. };
  182. EXPORT_SYMBOL(cpufreq_gov_userspace);
  183. static int __init cpufreq_gov_userspace_init(void)
  184. {
  185. return cpufreq_register_governor(&cpufreq_gov_userspace);
  186. }
  187. static void __exit cpufreq_gov_userspace_exit(void)
  188. {
  189. cpufreq_unregister_governor(&cpufreq_gov_userspace);
  190. }
  191. MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>");
  192. MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'");
  193. MODULE_LICENSE ("GPL");
  194. fs_initcall(cpufreq_gov_userspace_init);
  195. module_exit(cpufreq_gov_userspace_exit);