cpuidle.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * Copyright 2012 Linaro Ltd.
  3. *
  4. * The code contained herein is licensed under the GNU General Public
  5. * License. You may obtain a copy of the GNU General Public License
  6. * Version 2 or later at the following locations:
  7. *
  8. * http://www.opensource.org/licenses/gpl-license.html
  9. * http://www.gnu.org/copyleft/gpl.html
  10. */
  11. #include <linux/cpuidle.h>
  12. #include <linux/of.h>
  13. #include <linux/of_device.h>
  14. #include <asm/cpuidle.h>
  15. extern struct of_cpuidle_method __cpuidle_method_of_table[];
  16. static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel
  17. __used __section(__cpuidle_method_of_table_end);
  18. static struct cpuidle_ops cpuidle_ops[NR_CPUS];
  19. /**
  20. * arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle()
  21. * @dev: not used
  22. * @drv: not used
  23. * @index: not used
  24. *
  25. * A trivial wrapper to allow the cpu_do_idle function to be assigned as a
  26. * cpuidle callback by matching the function signature.
  27. *
  28. * Returns the index passed as parameter
  29. */
  30. int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
  31. struct cpuidle_driver *drv, int index)
  32. {
  33. cpu_do_idle();
  34. return index;
  35. }
  36. /**
  37. * arm_cpuidle_suspend() - function to enter low power idle states
  38. * @index: an integer used as an identifier for the low level PM callbacks
  39. *
  40. * This function calls the underlying arch specific low level PM code as
  41. * registered at the init time.
  42. *
  43. * Returns -EOPNOTSUPP if no suspend callback is defined, the result of the
  44. * callback otherwise.
  45. */
  46. int arm_cpuidle_suspend(int index)
  47. {
  48. int ret = -EOPNOTSUPP;
  49. int cpu = smp_processor_id();
  50. if (cpuidle_ops[cpu].suspend)
  51. ret = cpuidle_ops[cpu].suspend(cpu, index);
  52. return ret;
  53. }
  54. /**
  55. * arm_cpuidle_get_ops() - find a registered cpuidle_ops by name
  56. * @method: the method name
  57. *
  58. * Search in the __cpuidle_method_of_table array the cpuidle ops matching the
  59. * method name.
  60. *
  61. * Returns a struct cpuidle_ops pointer, NULL if not found.
  62. */
  63. static struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)
  64. {
  65. struct of_cpuidle_method *m = __cpuidle_method_of_table;
  66. for (; m->method; m++)
  67. if (!strcmp(m->method, method))
  68. return m->ops;
  69. return NULL;
  70. }
  71. /**
  72. * arm_cpuidle_read_ops() - Initialize the cpuidle ops with the device tree
  73. * @dn: a pointer to a struct device node corresponding to a cpu node
  74. * @cpu: the cpu identifier
  75. *
  76. * Get the method name defined in the 'enable-method' property, retrieve the
  77. * associated cpuidle_ops and do a struct copy. This copy is needed because all
  78. * cpuidle_ops are tagged __initdata and will be unloaded after the init
  79. * process.
  80. *
  81. * Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if
  82. * no cpuidle_ops is registered for the 'enable-method'.
  83. */
  84. static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)
  85. {
  86. const char *enable_method;
  87. struct cpuidle_ops *ops;
  88. enable_method = of_get_property(dn, "enable-method", NULL);
  89. if (!enable_method)
  90. return -ENOENT;
  91. ops = arm_cpuidle_get_ops(enable_method);
  92. if (!ops) {
  93. pr_warn("%s: unsupported enable-method property: %s\n",
  94. dn->full_name, enable_method);
  95. return -EOPNOTSUPP;
  96. }
  97. cpuidle_ops[cpu] = *ops; /* structure copy */
  98. pr_notice("cpuidle: enable-method property '%s'"
  99. " found operations\n", enable_method);
  100. return 0;
  101. }
  102. /**
  103. * arm_cpuidle_init() - Initialize cpuidle_ops for a specific cpu
  104. * @cpu: the cpu to be initialized
  105. *
  106. * Initialize the cpuidle ops with the device for the cpu and then call
  107. * the cpu's idle initialization callback. This may fail if the underlying HW
  108. * is not operational.
  109. *
  110. * Returns:
  111. * 0 on success,
  112. * -ENODEV if it fails to find the cpu node in the device tree,
  113. * -EOPNOTSUPP if it does not find a registered cpuidle_ops for this cpu,
  114. * -ENOENT if it fails to find an 'enable-method' property,
  115. * -ENXIO if the HW reports a failure or a misconfiguration,
  116. * -ENOMEM if the HW report an memory allocation failure
  117. */
  118. int __init arm_cpuidle_init(int cpu)
  119. {
  120. struct device_node *cpu_node = of_cpu_device_node_get(cpu);
  121. int ret;
  122. if (!cpu_node)
  123. return -ENODEV;
  124. ret = arm_cpuidle_read_ops(cpu_node, cpu);
  125. if (!ret && cpuidle_ops[cpu].init)
  126. ret = cpuidle_ops[cpu].init(cpu_node, cpu);
  127. of_node_put(cpu_node);
  128. return ret;
  129. }