cpufreq_limit.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * drivers/cpufreq/cpufreq_limit.c
  3. *
  4. * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  5. * Minsung Kim <ms925.kim@samsung.com>
  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. #include <linux/module.h>
  12. #include <linux/sysfs.h>
  13. #include <linux/cpufreq.h>
  14. #include <linux/cpufreq_limit.h>
  15. #include <linux/notifier.h>
  16. #include <linux/slab.h>
  17. #include <linux/err.h>
  18. #include <linux/suspend.h>
  19. struct cpufreq_limit_handle {
  20. struct list_head node;
  21. unsigned long min;
  22. unsigned long max;
  23. char label[20];
  24. };
  25. static DEFINE_MUTEX(cpufreq_limit_lock);
  26. static LIST_HEAD(cpufreq_limit_requests);
  27. #if defined(CONFIG_ARCH_MSM8974PRO)
  28. static int suspend_boost = 1190400;
  29. module_param(suspend_boost, uint, 0644);
  30. #endif
  31. /**
  32. * cpufreq_limit_get - limit min_freq or max_freq, return cpufreq_limit_handle
  33. * @min_freq limit minimum frequency (0: none)
  34. * @max_freq limit maximum frequency (0: none)
  35. * @label a literal description string of this request
  36. */
  37. struct cpufreq_limit_handle *cpufreq_limit_get(unsigned long min_freq,
  38. unsigned long max_freq, char *label)
  39. {
  40. struct cpufreq_limit_handle *handle;
  41. int i;
  42. if (max_freq && max_freq < min_freq)
  43. return ERR_PTR(-EINVAL);
  44. handle = kzalloc(sizeof(*handle), GFP_KERNEL);
  45. if (!handle)
  46. return ERR_PTR(-ENOMEM);
  47. pr_debug("%s: %s,%lu,%lu\n", __func__, handle->label, handle->min,
  48. handle->max);
  49. handle->min = min_freq;
  50. handle->max = max_freq;
  51. if (strlen(label) < sizeof(handle->label))
  52. strcpy(handle->label, label);
  53. else
  54. strncpy(handle->label, label, sizeof(handle->label) - 1);
  55. mutex_lock(&cpufreq_limit_lock);
  56. list_add_tail(&handle->node, &cpufreq_limit_requests);
  57. mutex_unlock(&cpufreq_limit_lock);
  58. for_each_online_cpu(i)
  59. cpufreq_update_policy(i);
  60. return handle;
  61. }
  62. /**
  63. * cpufreq_limit_put - release of a limit of min_freq or max_freq, free
  64. * a cpufreq_limit_handle
  65. * @handle a cpufreq_limit_handle that has been requested
  66. */
  67. int cpufreq_limit_put(struct cpufreq_limit_handle *handle)
  68. {
  69. int i;
  70. if (handle == NULL || IS_ERR(handle))
  71. return -EINVAL;
  72. pr_debug("%s: %s,%lu,%lu\n", __func__, handle->label, handle->min,
  73. handle->max);
  74. mutex_lock(&cpufreq_limit_lock);
  75. list_del(&handle->node);
  76. mutex_unlock(&cpufreq_limit_lock);
  77. for_each_online_cpu(i)
  78. cpufreq_update_policy(i);
  79. kfree(handle);
  80. return 0;
  81. }
  82. static int cpufreq_limit_notifier_policy(struct notifier_block *nb,
  83. unsigned long val, void *data)
  84. {
  85. struct cpufreq_policy *policy = data;
  86. struct cpufreq_limit_handle *handle;
  87. unsigned long min = 0, max = ULONG_MAX;
  88. if (val != CPUFREQ_ADJUST)
  89. goto done;
  90. mutex_lock(&cpufreq_limit_lock);
  91. list_for_each_entry(handle, &cpufreq_limit_requests, node) {
  92. if (handle->min > min)
  93. min = handle->min;
  94. if (handle->max && handle->max < max)
  95. max = handle->max;
  96. }
  97. #ifdef CONFIG_SEC_PM
  98. pr_debug("CPUFREQ(%d): %s: umin=%d,umax=%d\n",
  99. policy->cpu, __func__, policy->user_policy.min, policy->user_policy.max);
  100. if (policy->user_policy.min > min)
  101. min = policy->user_policy.min;
  102. if (policy->user_policy.max && policy->user_policy.max < max)
  103. max = policy->user_policy.max;
  104. #endif
  105. mutex_unlock(&cpufreq_limit_lock);
  106. if (!min && max == ULONG_MAX)
  107. goto done;
  108. if (!min)
  109. min = policy->cpuinfo.min_freq;
  110. if (max == ULONG_MAX)
  111. max = policy->cpuinfo.max_freq;
  112. pr_debug("%s: limiting cpu%d cpufreq to %lu,%lu", __func__,
  113. policy->cpu, min, max);
  114. cpufreq_verify_within_limits(policy, min, max);
  115. done:
  116. return 0;
  117. }
  118. static struct notifier_block notifier_policy_block = {
  119. .notifier_call = cpufreq_limit_notifier_policy
  120. };
  121. static ssize_t show_cpufreq_limit_requests(struct kobject *kobj,
  122. struct attribute *attr, char *buf)
  123. {
  124. struct cpufreq_limit_handle *handle;
  125. ssize_t len = 0;
  126. mutex_lock(&cpufreq_limit_lock);
  127. list_for_each_entry(handle, &cpufreq_limit_requests, node) {
  128. len += sprintf(buf + len, "%s\t%lu\t%lu\n", handle->label,
  129. handle->min, handle->max);
  130. }
  131. mutex_unlock(&cpufreq_limit_lock);
  132. return len;
  133. }
  134. static struct global_attr cpufreq_limit_requests_attr =
  135. __ATTR(cpufreq_limit_requests, 0444, show_cpufreq_limit_requests, NULL);
  136. static struct attribute *limit_attributes[] = {
  137. &cpufreq_limit_requests_attr.attr,
  138. NULL,
  139. };
  140. static struct attribute_group limit_attr_group = {
  141. .attrs = limit_attributes,
  142. .name = "cpufreq_limit",
  143. };
  144. #if defined(CONFIG_ARCH_MSM8974PRO)
  145. static int cpufreq_limit_suspend_handler(struct notifier_block *nb,
  146. unsigned long val, void *data)
  147. {
  148. static struct cpufreq_limit_handle *cpufreq_suspend;
  149. switch (val) {
  150. case PM_SUSPEND_PREPARE:
  151. pr_info("%s: limit suspend_boost %d\n", __func__, suspend_boost);
  152. cpufreq_suspend = cpufreq_limit_min_freq(suspend_boost, "cpufreq_suspend");
  153. if (IS_ERR(cpufreq_suspend)) {
  154. pr_err("%s: fail to get the handle\n", __func__);
  155. goto out;
  156. }
  157. break;
  158. case PM_POST_SUSPEND:
  159. pr_info("%s: release suspend_boost\n", __func__);
  160. cpufreq_limit_put(cpufreq_suspend);
  161. break;
  162. default:
  163. return NOTIFY_DONE;
  164. }
  165. out:
  166. return NOTIFY_OK;
  167. }
  168. #endif
  169. static int __init cpufreq_limit_init(void)
  170. {
  171. int ret;
  172. ret = cpufreq_register_notifier(&notifier_policy_block,
  173. CPUFREQ_POLICY_NOTIFIER);
  174. if (ret)
  175. return ret;
  176. ret = sysfs_create_group(cpufreq_global_kobject,
  177. &limit_attr_group);
  178. if (ret)
  179. return ret;
  180. #if defined(CONFIG_ARCH_MSM8974PRO)
  181. pm_notifier(cpufreq_limit_suspend_handler, 0);
  182. #endif
  183. return 0;
  184. }
  185. static void __exit cpufreq_limit_exit(void)
  186. {
  187. cpufreq_unregister_notifier(&notifier_policy_block,
  188. CPUFREQ_POLICY_NOTIFIER);
  189. sysfs_remove_group(cpufreq_global_kobject, &limit_attr_group);
  190. }
  191. MODULE_AUTHOR("Minsung Kim <ms925.kim@samsung.com>");
  192. MODULE_DESCRIPTION("'cpufreq_limit' - A driver to limit cpu frequency");
  193. MODULE_LICENSE("GPL");
  194. module_init(cpufreq_limit_init);
  195. module_exit(cpufreq_limit_exit);