cpufreq_spudemand.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * spu aware cpufreq governor for the cell processor
  4. *
  5. * © Copyright IBM Corporation 2006-2008
  6. *
  7. * Author: Christian Krafft <krafft@de.ibm.com>
  8. */
  9. #include <linux/cpufreq.h>
  10. #include <linux/sched.h>
  11. #include <linux/sched/loadavg.h>
  12. #include <linux/module.h>
  13. #include <linux/timer.h>
  14. #include <linux/workqueue.h>
  15. #include <linux/atomic.h>
  16. #include <asm/machdep.h>
  17. #include <asm/spu.h>
  18. #define POLL_TIME 100000 /* in µs */
  19. #define EXP 753 /* exp(-1) in fixed-point */
  20. struct spu_gov_info_struct {
  21. unsigned long busy_spus; /* fixed-point */
  22. struct cpufreq_policy *policy;
  23. struct delayed_work work;
  24. unsigned int poll_int; /* µs */
  25. };
  26. static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info);
  27. static int calc_freq(struct spu_gov_info_struct *info)
  28. {
  29. int cpu;
  30. int busy_spus;
  31. cpu = info->policy->cpu;
  32. busy_spus = atomic_read(&cbe_spu_info[cpu_to_node(cpu)].busy_spus);
  33. info->busy_spus = calc_load(info->busy_spus, EXP, busy_spus * FIXED_1);
  34. pr_debug("cpu %d: busy_spus=%d, info->busy_spus=%ld\n",
  35. cpu, busy_spus, info->busy_spus);
  36. return info->policy->max * info->busy_spus / FIXED_1;
  37. }
  38. static void spu_gov_work(struct work_struct *work)
  39. {
  40. struct spu_gov_info_struct *info;
  41. int delay;
  42. unsigned long target_freq;
  43. info = container_of(work, struct spu_gov_info_struct, work.work);
  44. /* after cancel_delayed_work_sync we unset info->policy */
  45. BUG_ON(info->policy == NULL);
  46. target_freq = calc_freq(info);
  47. __cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H);
  48. delay = usecs_to_jiffies(info->poll_int);
  49. schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
  50. }
  51. static void spu_gov_init_work(struct spu_gov_info_struct *info)
  52. {
  53. int delay = usecs_to_jiffies(info->poll_int);
  54. INIT_DEFERRABLE_WORK(&info->work, spu_gov_work);
  55. schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
  56. }
  57. static void spu_gov_cancel_work(struct spu_gov_info_struct *info)
  58. {
  59. cancel_delayed_work_sync(&info->work);
  60. }
  61. static int spu_gov_start(struct cpufreq_policy *policy)
  62. {
  63. unsigned int cpu = policy->cpu;
  64. struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
  65. struct spu_gov_info_struct *affected_info;
  66. int i;
  67. if (!cpu_online(cpu)) {
  68. printk(KERN_ERR "cpu %d is not online\n", cpu);
  69. return -EINVAL;
  70. }
  71. if (!policy->cur) {
  72. printk(KERN_ERR "no cpu specified in policy\n");
  73. return -EINVAL;
  74. }
  75. /* initialize spu_gov_info for all affected cpus */
  76. for_each_cpu(i, policy->cpus) {
  77. affected_info = &per_cpu(spu_gov_info, i);
  78. affected_info->policy = policy;
  79. }
  80. info->poll_int = POLL_TIME;
  81. /* setup timer */
  82. spu_gov_init_work(info);
  83. return 0;
  84. }
  85. static void spu_gov_stop(struct cpufreq_policy *policy)
  86. {
  87. unsigned int cpu = policy->cpu;
  88. struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
  89. int i;
  90. /* cancel timer */
  91. spu_gov_cancel_work(info);
  92. /* clean spu_gov_info for all affected cpus */
  93. for_each_cpu (i, policy->cpus) {
  94. info = &per_cpu(spu_gov_info, i);
  95. info->policy = NULL;
  96. }
  97. }
  98. static struct cpufreq_governor spu_governor = {
  99. .name = "spudemand",
  100. .start = spu_gov_start,
  101. .stop = spu_gov_stop,
  102. .owner = THIS_MODULE,
  103. };
  104. cpufreq_governor_init(spu_governor);
  105. cpufreq_governor_exit(spu_governor);
  106. MODULE_DESCRIPTION("SPU-aware cpufreq governor for the cell processor");
  107. MODULE_LICENSE("GPL");
  108. MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");