Skip to content

Commit b1d681d

Browse files
author
Georgi Djakov
committed
interconnect: Add sync state support
The bootloaders often do some initial configuration of the interconnects in the system and we want to keep this configuration until all consumers have probed and expressed their bandwidth needs. This is because we don't want to change the configuration by starting to disable unused paths until every user had a chance to request the amount of bandwidth it needs. To accomplish this we will implement an interconnect specific sync_state callback which will synchronize (aggregate and set) the current bandwidth settings when all consumers have been probed. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Saravana Kannan <[email protected]> Signed-off-by: Georgi Djakov <[email protected]>
1 parent cc80d10 commit b1d681d

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

drivers/interconnect/core.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
static DEFINE_IDR(icc_idr);
2828
static LIST_HEAD(icc_providers);
29+
static int providers_count;
30+
static bool synced_state;
2931
static DEFINE_MUTEX(icc_lock);
3032
static struct dentry *icc_debugfs_dir;
3133

@@ -267,6 +269,12 @@ static int aggregate_requests(struct icc_node *node)
267269
}
268270
p->aggregate(node, r->tag, avg_bw, peak_bw,
269271
&node->avg_bw, &node->peak_bw);
272+
273+
/* during boot use the initial bandwidth as a floor value */
274+
if (!synced_state) {
275+
node->avg_bw = max(node->avg_bw, node->init_avg);
276+
node->peak_bw = max(node->peak_bw, node->init_peak);
277+
}
270278
}
271279

272280
return 0;
@@ -931,6 +939,19 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider)
931939
node->provider = provider;
932940
list_add_tail(&node->node_list, &provider->nodes);
933941

942+
/* get the initial bandwidth values and sync them with hardware */
943+
if (provider->get_bw) {
944+
provider->get_bw(node, &node->init_avg, &node->init_peak);
945+
} else {
946+
node->init_avg = INT_MAX;
947+
node->init_peak = INT_MAX;
948+
}
949+
node->avg_bw = node->init_avg;
950+
node->peak_bw = node->init_peak;
951+
provider->set(node, node);
952+
node->avg_bw = 0;
953+
node->peak_bw = 0;
954+
934955
mutex_unlock(&icc_lock);
935956
}
936957
EXPORT_SYMBOL_GPL(icc_node_add);
@@ -1026,8 +1047,54 @@ int icc_provider_del(struct icc_provider *provider)
10261047
}
10271048
EXPORT_SYMBOL_GPL(icc_provider_del);
10281049

1050+
static int of_count_icc_providers(struct device_node *np)
1051+
{
1052+
struct device_node *child;
1053+
int count = 0;
1054+
1055+
for_each_available_child_of_node(np, child) {
1056+
if (of_property_read_bool(child, "#interconnect-cells"))
1057+
count++;
1058+
count += of_count_icc_providers(child);
1059+
}
1060+
of_node_put(np);
1061+
1062+
return count;
1063+
}
1064+
1065+
void icc_sync_state(struct device *dev)
1066+
{
1067+
struct icc_provider *p;
1068+
struct icc_node *n;
1069+
static int count;
1070+
1071+
count++;
1072+
1073+
if (count < providers_count)
1074+
return;
1075+
1076+
mutex_lock(&icc_lock);
1077+
synced_state = true;
1078+
list_for_each_entry(p, &icc_providers, provider_list) {
1079+
dev_dbg(p->dev, "interconnect provider is in synced state\n");
1080+
list_for_each_entry(n, &p->nodes, node_list) {
1081+
if (n->init_avg || n->init_peak) {
1082+
aggregate_requests(n);
1083+
p->set(n, n);
1084+
}
1085+
}
1086+
}
1087+
mutex_unlock(&icc_lock);
1088+
}
1089+
EXPORT_SYMBOL_GPL(icc_sync_state);
1090+
10291091
static int __init icc_init(void)
10301092
{
1093+
struct device_node *root = of_find_node_by_path("/");
1094+
1095+
providers_count = of_count_icc_providers(root);
1096+
of_node_put(root);
1097+
10311098
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
10321099
debugfs_create_file("interconnect_summary", 0444,
10331100
icc_debugfs_dir, NULL, &icc_summary_fops);

include/linux/interconnect-provider.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ struct icc_provider {
7575
* @req_list: a list of QoS constraint requests associated with this node
7676
* @avg_bw: aggregated value of average bandwidth requests from all consumers
7777
* @peak_bw: aggregated value of peak bandwidth requests from all consumers
78+
* @init_avg: average bandwidth value that is read from the hardware during init
79+
* @init_peak: peak bandwidth value that is read from the hardware during init
7880
* @data: pointer to private data
7981
*/
8082
struct icc_node {
@@ -91,6 +93,8 @@ struct icc_node {
9193
struct hlist_head req_list;
9294
u32 avg_bw;
9395
u32 peak_bw;
96+
u32 init_avg;
97+
u32 init_peak;
9498
void *data;
9599
};
96100

@@ -108,6 +112,7 @@ int icc_nodes_remove(struct icc_provider *provider);
108112
int icc_provider_add(struct icc_provider *provider);
109113
int icc_provider_del(struct icc_provider *provider);
110114
struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec);
115+
void icc_sync_state(struct device *dev);
111116

112117
#else
113118

0 commit comments

Comments
 (0)