diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/interconnect/core.c | 67 | ||||
-rw-r--r-- | drivers/interconnect/qcom/osm-l3.c | 1 | ||||
-rw-r--r-- | drivers/interconnect/qcom/sc7180.c | 1 | ||||
-rw-r--r-- | drivers/interconnect/qcom/sdm845.c | 1 |
4 files changed, 70 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); diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index eb0158af346f..695f28789e98 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -322,6 +322,7 @@ static struct platform_driver osm_l3_driver = { .driver = { .name = "osm-l3", .of_match_table = osm_l3_of_match, + .sync_state = icc_sync_state, }, }; module_platform_driver(osm_l3_driver); diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index a6f119f363b1..bf11b82ed55c 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -633,6 +633,7 @@ static struct platform_driver qnoc_driver = { .driver = { .name = "qnoc-sc7180", .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, }, }; module_platform_driver(qnoc_driver); diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index 3b81dbb71b0b..d79e3163e2c3 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -559,6 +559,7 @@ static struct platform_driver qnoc_driver = { .driver = { .name = "qnoc-sdm845", .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, }, }; module_platform_driver(qnoc_driver); |