qcom-lpm-sysfs.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/cpu.h>
  7. #include <linux/cpuidle.h>
  8. #include <linux/module.h>
  9. #include <linux/moduleparam.h>
  10. #include <linux/pm_domain.h>
  11. #include <linux/slab.h>
  12. #include <linux/string.h>
  13. #include "qcom-lpm.h"
  14. static struct kobject *qcom_lpm_kobj;
  15. static ssize_t cluster_idle_set(struct kobject *kobj,
  16. struct kobj_attribute *attr,
  17. const char *buf, size_t len)
  18. {
  19. struct qcom_cluster_node *d = container_of(attr, struct qcom_cluster_node, disable_attr);
  20. bool disable;
  21. int ret;
  22. ret = strtobool(buf, &disable);
  23. if (ret)
  24. return -EINVAL;
  25. d->cluster->state_allowed[d->state_idx] = !disable;
  26. return len;
  27. }
  28. static ssize_t cluster_idle_get(struct kobject *kobj,
  29. struct kobj_attribute *attr,
  30. char *buf)
  31. {
  32. struct qcom_cluster_node *d = container_of(attr, struct qcom_cluster_node, disable_attr);
  33. return scnprintf(buf, PAGE_SIZE, "%d\n", !d->cluster->state_allowed[d->state_idx]);
  34. }
  35. static int create_cluster_state_node(struct device *dev, struct qcom_cluster_node *d)
  36. {
  37. struct kobj_attribute *attr = &d->disable_attr;
  38. int ret;
  39. d->attr_group = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);
  40. if (!d->attr_group)
  41. return -ENOMEM;
  42. d->attrs = devm_kcalloc(dev, 2, sizeof(struct attribute *), GFP_KERNEL);
  43. if (!d->attrs)
  44. return -ENOMEM;
  45. sysfs_attr_init(&attr->attr);
  46. attr->attr.name = "disable";
  47. attr->attr.mode = 0644;
  48. attr->show = cluster_idle_get;
  49. attr->store = cluster_idle_set;
  50. d->attrs[0] = &attr->attr;
  51. d->attrs[1] = NULL;
  52. d->attr_group->attrs = d->attrs;
  53. ret = sysfs_create_group(d->kobj, d->attr_group);
  54. if (ret)
  55. return -ENOMEM;
  56. return ret;
  57. }
  58. void remove_cluster_sysfs_nodes(struct lpm_cluster *cluster)
  59. {
  60. struct generic_pm_domain *genpd = cluster->genpd;
  61. struct kobject *kobj = cluster->dev_kobj;
  62. int i;
  63. if (!qcom_lpm_kobj)
  64. return;
  65. for (i = 0; i < genpd->state_count; i++) {
  66. struct qcom_cluster_node *d = cluster->dev_node[i];
  67. kobject_put(d->kobj);
  68. }
  69. kobject_put(kobj);
  70. }
  71. int create_cluster_sysfs_nodes(struct lpm_cluster *cluster)
  72. {
  73. char name[10];
  74. int i, ret;
  75. struct generic_pm_domain *genpd = cluster->genpd;
  76. if (!qcom_lpm_kobj)
  77. return -EPROBE_DEFER;
  78. cluster->dev_kobj = kobject_create_and_add(genpd->name, qcom_lpm_kobj);
  79. if (!cluster->dev_kobj)
  80. return -ENOMEM;
  81. for (i = 0; i < genpd->state_count; i++) {
  82. struct qcom_cluster_node *d;
  83. d = devm_kzalloc(cluster->dev, sizeof(*d), GFP_KERNEL);
  84. if (!d) {
  85. kobject_put(cluster->dev_kobj);
  86. return -ENOMEM;
  87. }
  88. d->state_idx = i;
  89. d->cluster = cluster;
  90. scnprintf(name, PAGE_SIZE, "D%u", i);
  91. d->kobj = kobject_create_and_add(name, cluster->dev_kobj);
  92. if (!d->kobj) {
  93. kobject_put(cluster->dev_kobj);
  94. return -ENOMEM;
  95. }
  96. ret = create_cluster_state_node(cluster->dev, d);
  97. if (ret) {
  98. kobject_put(d->kobj);
  99. kobject_put(cluster->dev_kobj);
  100. return ret;
  101. }
  102. cluster->dev_node[i] = d;
  103. }
  104. return 0;
  105. }
  106. static ssize_t sleep_disabled_show(struct kobject *kobj,
  107. struct kobj_attribute *attr,
  108. char *buf)
  109. {
  110. return scnprintf(buf, PAGE_SIZE, "%u\n", sleep_disabled);
  111. }
  112. static ssize_t sleep_disabled_store(struct kobject *kobj,
  113. struct kobj_attribute *attr,
  114. const char *buf, size_t count)
  115. {
  116. bool val;
  117. int ret;
  118. ret = kstrtobool(buf, &val);
  119. if (ret) {
  120. pr_err("Invalid argument passed\n");
  121. return ret;
  122. }
  123. sleep_disabled = val;
  124. return count;
  125. }
  126. static ssize_t prediction_disabled_show(struct kobject *kobj,
  127. struct kobj_attribute *attr,
  128. char *buf)
  129. {
  130. return scnprintf(buf, PAGE_SIZE, "%u\n", prediction_disabled);
  131. }
  132. static ssize_t prediction_disabled_store(struct kobject *kobj,
  133. struct kobj_attribute *attr,
  134. const char *buf, size_t count)
  135. {
  136. bool val;
  137. int ret;
  138. ret = kstrtobool(buf, &val);
  139. if (ret) {
  140. pr_err("Invalid argument passed\n");
  141. return ret;
  142. }
  143. prediction_disabled = val;
  144. return count;
  145. }
  146. static struct kobj_attribute attr_sleep_disabled = __ATTR_RW(sleep_disabled);
  147. static struct kobj_attribute attr_prediction_disabled = __ATTR_RW(prediction_disabled);
  148. static struct attribute *lpm_gov_attrs[] = {
  149. &attr_sleep_disabled.attr,
  150. &attr_prediction_disabled.attr,
  151. NULL
  152. };
  153. static struct attribute_group lpm_gov_attr_group = {
  154. .attrs = lpm_gov_attrs,
  155. .name = "parameters",
  156. };
  157. void remove_global_sysfs_nodes(void)
  158. {
  159. kobject_put(qcom_lpm_kobj);
  160. }
  161. int create_global_sysfs_nodes(void)
  162. {
  163. struct kobject *cpuidle_kobj = &cpu_subsys.dev_root->kobj;
  164. qcom_lpm_kobj = kobject_create_and_add(KBUILD_MODNAME, cpuidle_kobj);
  165. if (!qcom_lpm_kobj)
  166. return -ENOMEM;
  167. return sysfs_create_group(qcom_lpm_kobj, &lpm_gov_attr_group);
  168. }