summaryrefslogtreecommitdiff
path: root/drivers/interconnect/core.c
diff options
context:
space:
mode:
authorGeorgi Djakov <georgi.djakov@linaro.org>2020-09-18 09:12:40 +0300
committerGeorgi Djakov <georgi.djakov@linaro.org>2020-09-18 09:13:40 +0300
commit628fdbcf9d665ab68f5493936ca23383a5844ff7 (patch)
tree89432b0ad4511d2f478dc18a465992b67249aa6c /drivers/interconnect/core.c
parentb1a367bb1cbba607d6c5d7dcf828b049241ee9a6 (diff)
parent7d3b0b0d8184ce4a20fd9f48cd12484139bec939 (diff)
Merge branch 'icc-syncstate' into icc-next
* icc-syncstate: interconnect: Add get_bw() callback interconnect: Add sync state support interconnect: qcom: Use icc_sync_state Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
Diffstat (limited to 'drivers/interconnect/core.c')
-rw-r--r--drivers/interconnect/core.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index 7642f3601dbf..998ede7e87ef 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -26,6 +26,8 @@
static DEFINE_IDR(icc_idr);
static LIST_HEAD(icc_providers);
+static int providers_count;
+static bool synced_state;
static DEFINE_MUTEX(icc_lock);
static struct dentry *icc_debugfs_dir;
@@ -267,6 +269,12 @@ static int aggregate_requests(struct icc_node *node)
}
p->aggregate(node, r->tag, avg_bw, peak_bw,
&node->avg_bw, &node->peak_bw);
+
+ /* during boot use the initial bandwidth as a floor value */
+ if (!synced_state) {
+ node->avg_bw = max(node->avg_bw, node->init_avg);
+ node->peak_bw = max(node->peak_bw, node->init_peak);
+ }
}
return 0;
@@ -958,6 +966,19 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider)
node->provider = provider;
list_add_tail(&node->node_list, &provider->nodes);
+ /* get the initial bandwidth values and sync them with hardware */
+ if (provider->get_bw) {
+ provider->get_bw(node, &node->init_avg, &node->init_peak);
+ } else {
+ node->init_avg = INT_MAX;
+ node->init_peak = INT_MAX;
+ }
+ node->avg_bw = node->init_avg;
+ node->peak_bw = node->init_peak;
+ provider->set(node, node);
+ node->avg_bw = 0;
+ node->peak_bw = 0;
+
mutex_unlock(&icc_lock);
}
EXPORT_SYMBOL_GPL(icc_node_add);
@@ -1053,8 +1074,54 @@ int icc_provider_del(struct icc_provider *provider)
}
EXPORT_SYMBOL_GPL(icc_provider_del);
+static int of_count_icc_providers(struct device_node *np)
+{
+ struct device_node *child;
+ int count = 0;
+
+ for_each_available_child_of_node(np, child) {
+ if (of_property_read_bool(child, "#interconnect-cells"))
+ count++;
+ count += of_count_icc_providers(child);
+ }
+ of_node_put(np);
+
+ return count;
+}
+
+void icc_sync_state(struct device *dev)
+{
+ struct icc_provider *p;
+ struct icc_node *n;
+ static int count;
+
+ count++;
+
+ if (count < providers_count)
+ return;
+
+ mutex_lock(&icc_lock);
+ synced_state = true;
+ list_for_each_entry(p, &icc_providers, provider_list) {
+ dev_dbg(p->dev, "interconnect provider is in synced state\n");
+ list_for_each_entry(n, &p->nodes, node_list) {
+ if (n->init_avg || n->init_peak) {
+ aggregate_requests(n);
+ p->set(n, n);
+ }
+ }
+ }
+ mutex_unlock(&icc_lock);
+}
+EXPORT_SYMBOL_GPL(icc_sync_state);
+
static int __init icc_init(void)
{
+ struct device_node *root = of_find_node_by_path("/");
+
+ providers_count = of_count_icc_providers(root);
+ of_node_put(root);
+
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
debugfs_create_file("interconnect_summary", 0444,
icc_debugfs_dir, NULL, &icc_summary_fops);