cpuidle-big_little.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright (c) 2013 ARM/Linaro
  3. *
  4. * Authors: Daniel Lezcano <daniel.lezcano@linaro.org>
  5. * Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  6. * Nicolas Pitre <nicolas.pitre@linaro.org>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. *
  12. * Maintainer: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  13. * Maintainer: Daniel Lezcano <daniel.lezcano@linaro.org>
  14. */
  15. #include <linux/cpuidle.h>
  16. #include <linux/cpu_pm.h>
  17. #include <linux/slab.h>
  18. #include <linux/of.h>
  19. #include <asm/cpu.h>
  20. #include <asm/cputype.h>
  21. #include <asm/cpuidle.h>
  22. #include <asm/mcpm.h>
  23. #include <asm/smp_plat.h>
  24. #include <asm/suspend.h>
  25. static int bl_enter_powerdown(struct cpuidle_device *dev,
  26. struct cpuidle_driver *drv, int idx);
  27. /*
  28. * NB: Owing to current menu governor behaviour big and LITTLE
  29. * index 1 states have to define exit_latency and target_residency for
  30. * cluster state since, when all CPUs in a cluster hit it, the cluster
  31. * can be shutdown. This means that when a single CPU enters this state
  32. * the exit_latency and target_residency values are somewhat overkill.
  33. * There is no notion of cluster states in the menu governor, so CPUs
  34. * have to define CPU states where possibly the cluster will be shutdown
  35. * depending on the state of other CPUs. idle states entry and exit happen
  36. * at random times; however the cluster state provides target_residency
  37. * values as if all CPUs in a cluster enter the state at once; this is
  38. * somewhat optimistic and behaviour should be fixed either in the governor
  39. * or in the MCPM back-ends.
  40. * To make this driver 100% generic the number of states and the exit_latency
  41. * target_residency values must be obtained from device tree bindings.
  42. *
  43. * exit_latency: refers to the TC2 vexpress test chip and depends on the
  44. * current cluster operating point. It is the time it takes to get the CPU
  45. * up and running when the CPU is powered up on cluster wake-up from shutdown.
  46. * Current values for big and LITTLE clusters are provided for clusters
  47. * running at default operating points.
  48. *
  49. * target_residency: it is the minimum amount of time the cluster has
  50. * to be down to break even in terms of power consumption. cluster
  51. * shutdown has inherent dynamic power costs (L2 writebacks to DRAM
  52. * being the main factor) that depend on the current operating points.
  53. * The current values for both clusters are provided for a CPU whose half
  54. * of L2 lines are dirty and require cleaning to DRAM, and takes into
  55. * account leakage static power values related to the vexpress TC2 testchip.
  56. */
  57. static struct cpuidle_driver bl_idle_little_driver = {
  58. .name = "little_idle",
  59. .owner = THIS_MODULE,
  60. .states[0] = ARM_CPUIDLE_WFI_STATE,
  61. .states[1] = {
  62. .enter = bl_enter_powerdown,
  63. .exit_latency = 700,
  64. .target_residency = 2500,
  65. .flags = CPUIDLE_FLAG_TIME_VALID |
  66. CPUIDLE_FLAG_TIMER_STOP,
  67. .name = "C1",
  68. .desc = "ARM little-cluster power down",
  69. },
  70. .state_count = 2,
  71. };
  72. static struct cpuidle_driver bl_idle_big_driver = {
  73. .name = "big_idle",
  74. .owner = THIS_MODULE,
  75. .states[0] = ARM_CPUIDLE_WFI_STATE,
  76. .states[1] = {
  77. .enter = bl_enter_powerdown,
  78. .exit_latency = 500,
  79. .target_residency = 2000,
  80. .flags = CPUIDLE_FLAG_TIME_VALID |
  81. CPUIDLE_FLAG_TIMER_STOP,
  82. .name = "C1",
  83. .desc = "ARM big-cluster power down",
  84. },
  85. .state_count = 2,
  86. };
  87. /*
  88. * notrace prevents trace shims from getting inserted where they
  89. * should not. Global jumps and ldrex/strex must not be inserted
  90. * in power down sequences where caches and MMU may be turned off.
  91. */
  92. static int notrace bl_powerdown_finisher(unsigned long arg)
  93. {
  94. /* MCPM works with HW CPU identifiers */
  95. unsigned int mpidr = read_cpuid_mpidr();
  96. unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
  97. unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
  98. mcpm_set_entry_vector(cpu, cluster, cpu_resume);
  99. /*
  100. * Residency value passed to mcpm_cpu_suspend back-end
  101. * has to be given clear semantics. Set to 0 as a
  102. * temporary value.
  103. */
  104. mcpm_cpu_suspend(0);
  105. /* return value != 0 means failure */
  106. return 1;
  107. }
  108. /**
  109. * bl_enter_powerdown - Programs CPU to enter the specified state
  110. * @dev: cpuidle device
  111. * @drv: The target state to be programmed
  112. * @idx: state index
  113. *
  114. * Called from the CPUidle framework to program the device to the
  115. * specified target state selected by the governor.
  116. */
  117. static int bl_enter_powerdown(struct cpuidle_device *dev,
  118. struct cpuidle_driver *drv, int idx)
  119. {
  120. cpu_pm_enter();
  121. cpu_suspend(0, bl_powerdown_finisher);
  122. /* signals the MCPM core that CPU is out of low power state */
  123. mcpm_cpu_powered_up();
  124. cpu_pm_exit();
  125. return idx;
  126. }
  127. static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int cpu_id)
  128. {
  129. struct cpuinfo_arm *cpu_info;
  130. struct cpumask *cpumask;
  131. unsigned long cpuid;
  132. int cpu;
  133. cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
  134. if (!cpumask)
  135. return -ENOMEM;
  136. for_each_possible_cpu(cpu) {
  137. cpu_info = &per_cpu(cpu_data, cpu);
  138. cpuid = is_smp() ? cpu_info->cpuid : read_cpuid_id();
  139. /* read cpu id part number */
  140. if ((cpuid & 0xFFF0) == cpu_id)
  141. cpumask_set_cpu(cpu, cpumask);
  142. }
  143. drv->cpumask = cpumask;
  144. return 0;
  145. }
  146. static int __init bl_idle_init(void)
  147. {
  148. int ret;
  149. /*
  150. * Initialize the driver just for a compliant set of machines
  151. */
  152. if (!of_machine_is_compatible("arm,vexpress,v2p-ca15_a7"))
  153. return -ENODEV;
  154. /*
  155. * For now the differentiation between little and big cores
  156. * is based on the part number. A7 cores are considered little
  157. * cores, A15 are considered big cores. This distinction may
  158. * evolve in the future with a more generic matching approach.
  159. */
  160. ret = bl_idle_driver_init(&bl_idle_little_driver,
  161. ARM_CPU_PART_CORTEX_A7);
  162. if (ret)
  163. return ret;
  164. ret = bl_idle_driver_init(&bl_idle_big_driver, ARM_CPU_PART_CORTEX_A15);
  165. if (ret)
  166. goto out_uninit_little;
  167. ret = cpuidle_register(&bl_idle_little_driver, NULL);
  168. if (ret)
  169. goto out_uninit_big;
  170. ret = cpuidle_register(&bl_idle_big_driver, NULL);
  171. if (ret)
  172. goto out_unregister_little;
  173. return 0;
  174. out_unregister_little:
  175. cpuidle_unregister(&bl_idle_little_driver);
  176. out_uninit_big:
  177. kfree(bl_idle_big_driver.cpumask);
  178. out_uninit_little:
  179. kfree(bl_idle_little_driver.cpumask);
  180. return ret;
  181. }
  182. device_initcall(bl_idle_init);