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