icc-rpmh.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/interconnect.h>
  6. #include <linux/interconnect-provider.h>
  7. #include <linux/module.h>
  8. #include <linux/of.h>
  9. #include <linux/slab.h>
  10. #include "bcm-voter.h"
  11. #include "icc-rpmh.h"
  12. /**
  13. * qcom_icc_pre_aggregate - cleans up stale values from prior icc_set
  14. * @node: icc node to operate on
  15. */
  16. void qcom_icc_pre_aggregate(struct icc_node *node)
  17. {
  18. size_t i;
  19. struct qcom_icc_node *qn;
  20. qn = node->data;
  21. for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
  22. qn->sum_avg[i] = 0;
  23. qn->max_peak[i] = 0;
  24. }
  25. }
  26. EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
  27. /**
  28. * qcom_icc_aggregate - aggregate bw for buckets indicated by tag
  29. * @node: node to aggregate
  30. * @tag: tag to indicate which buckets to aggregate
  31. * @avg_bw: new bw to sum aggregate
  32. * @peak_bw: new bw to max aggregate
  33. * @agg_avg: existing aggregate avg bw val
  34. * @agg_peak: existing aggregate peak bw val
  35. */
  36. int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
  37. u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
  38. {
  39. size_t i;
  40. struct qcom_icc_node *qn;
  41. struct qcom_icc_provider *qp;
  42. qn = node->data;
  43. qp = to_qcom_provider(node->provider);
  44. if (!tag)
  45. tag = QCOM_ICC_TAG_ALWAYS;
  46. for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
  47. if (tag & BIT(i)) {
  48. qn->sum_avg[i] += avg_bw;
  49. qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
  50. }
  51. if (node->init_avg || node->init_peak) {
  52. qn->sum_avg[i] = max_t(u64, qn->sum_avg[i], node->init_avg);
  53. qn->max_peak[i] = max_t(u64, qn->max_peak[i], node->init_peak);
  54. }
  55. }
  56. *agg_avg += avg_bw;
  57. *agg_peak = max_t(u32, *agg_peak, peak_bw);
  58. for (i = 0; i < qn->num_bcms; i++)
  59. qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
  60. return 0;
  61. }
  62. EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
  63. /**
  64. * qcom_icc_set - set the constraints based on path
  65. * @src: source node for the path to set constraints on
  66. * @dst: destination node for the path to set constraints on
  67. *
  68. * Return: 0 on success, or an error code otherwise
  69. */
  70. int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
  71. {
  72. struct qcom_icc_provider *qp;
  73. struct icc_node *node;
  74. if (!src)
  75. node = dst;
  76. else
  77. node = src;
  78. qp = to_qcom_provider(node->provider);
  79. qcom_icc_bcm_voter_commit(qp->voter);
  80. return 0;
  81. }
  82. EXPORT_SYMBOL_GPL(qcom_icc_set);
  83. struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data)
  84. {
  85. struct icc_node_data *ndata;
  86. struct icc_node *node;
  87. node = of_icc_xlate_onecell(spec, data);
  88. if (IS_ERR(node))
  89. return ERR_CAST(node);
  90. ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
  91. if (!ndata)
  92. return ERR_PTR(-ENOMEM);
  93. ndata->node = node;
  94. if (spec->args_count == 2)
  95. ndata->tag = spec->args[1];
  96. if (spec->args_count > 2)
  97. pr_warn("%pOF: Too many arguments, path tag is not parsed\n", spec->np);
  98. return ndata;
  99. }
  100. EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended);
  101. /**
  102. * qcom_icc_bcm_init - populates bcm aux data and connect qnodes
  103. * @bcm: bcm to be initialized
  104. * @dev: associated provider device
  105. *
  106. * Return: 0 on success, or an error code otherwise
  107. */
  108. int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
  109. {
  110. struct qcom_icc_node *qn;
  111. const struct bcm_db *data;
  112. size_t data_count;
  113. int i;
  114. /* BCM is already initialised*/
  115. if (bcm->addr)
  116. return 0;
  117. bcm->addr = cmd_db_read_addr(bcm->name);
  118. if (!bcm->addr) {
  119. dev_err(dev, "%s could not find RPMh address\n",
  120. bcm->name);
  121. return -EINVAL;
  122. }
  123. data = cmd_db_read_aux_data(bcm->name, &data_count);
  124. if (IS_ERR(data)) {
  125. dev_err(dev, "%s command db read error (%ld)\n",
  126. bcm->name, PTR_ERR(data));
  127. return PTR_ERR(data);
  128. }
  129. if (!data_count) {
  130. dev_err(dev, "%s command db missing or partial aux data\n",
  131. bcm->name);
  132. return -EINVAL;
  133. }
  134. bcm->aux_data.unit = le32_to_cpu(data->unit);
  135. bcm->aux_data.width = le16_to_cpu(data->width);
  136. bcm->aux_data.vcd = data->vcd;
  137. bcm->aux_data.reserved = data->reserved;
  138. INIT_LIST_HEAD(&bcm->list);
  139. INIT_LIST_HEAD(&bcm->ws_list);
  140. if (!bcm->vote_scale)
  141. bcm->vote_scale = 1000;
  142. /* Link Qnodes to their respective BCMs */
  143. for (i = 0; i < bcm->num_nodes; i++) {
  144. qn = bcm->nodes[i];
  145. qn->bcms[qn->num_bcms] = bcm;
  146. qn->num_bcms++;
  147. }
  148. return 0;
  149. }
  150. EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
  151. MODULE_LICENSE("GPL v2");