diff options
author | Georgi Djakov <georgi.djakov@linaro.org> | 2019-10-17 11:41:08 +0300 |
---|---|---|
committer | Georgi Djakov <georgi.djakov@linaro.org> | 2020-02-11 19:52:33 +0200 |
commit | e43cb6a03f8df8a874afae11c2dc11bb1509c1d2 (patch) | |
tree | 1ff02dea8e07fd66cddd3ad2df86d30a3716aa85 | |
parent | d8b41992dca4dc5a2b9396ea5b8b7d1c87a76804 (diff) |
interconnect: Introduce per-provider locks
Currently, there is a single lock, the icc_lock, that used for handling all
icc_set_bw() requests, including those for unrelated paths. This means that
some request are unnecessarily serialized, which may in turn have impact on
performance.
To address this issue, we are introducing a provider specific locks.
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
-rw-r--r-- | drivers/interconnect/core.c | 21 | ||||
-rw-r--r-- | include/linux/interconnect-provider.h | 2 |
2 files changed, 19 insertions, 4 deletions
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index f277e467156f..e18b51012f1b 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -50,6 +50,7 @@ static int icc_summary_show(struct seq_file *s, void *data) list_for_each_entry(provider, &icc_providers, provider_list) { struct icc_node *n; + mutex_lock(&provider->lock); list_for_each_entry(n, &provider->nodes, node_list) { struct icc_req *r; @@ -63,6 +64,7 @@ static int icc_summary_show(struct seq_file *s, void *data) r->peak_bw); } } + mutex_unlock(&provider->lock); } mutex_unlock(&icc_lock); @@ -246,12 +248,15 @@ static int aggregate_requests(struct icc_node *node) node->avg_bw = 0; node->peak_bw = 0; + mutex_lock(&p->lock); + if (p->pre_aggregate) p->pre_aggregate(node); hlist_for_each_entry(r, &node->req_list, req_node) p->aggregate(node, r->tag, r->avg_bw, r->peak_bw, &node->avg_bw, &node->peak_bw); + mutex_unlock(&p->lock); return 0; } @@ -262,6 +267,8 @@ static int apply_constraints(struct icc_path *path) int ret = -EINVAL; int i; + mutex_lock(&icc_lock); + for (i = 0; i < path->num_nodes; i++) { next = path->reqs[i].node; @@ -282,6 +289,8 @@ static int apply_constraints(struct icc_path *path) prev = next; } out: + mutex_unlock(&icc_lock); + return ret; } @@ -501,8 +510,6 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw) if (WARN_ON(IS_ERR(path) || !path->num_nodes)) return -EINVAL; - mutex_lock(&icc_lock); - old_avg = path->reqs[0].avg_bw; old_peak = path->reqs[0].peak_bw; @@ -533,8 +540,6 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw) apply_constraints(path); } - mutex_unlock(&icc_lock); - trace_icc_set_bw_end(path, ret); return ret; @@ -608,9 +613,11 @@ void icc_put(struct icc_path *path) mutex_lock(&icc_lock); for (i = 0; i < path->num_nodes; i++) { node = path->reqs[i].node; + mutex_lock(&node->provider->lock); hlist_del(&path->reqs[i].req_node); if (!WARN_ON(!node->provider->users)) node->provider->users--; + mutex_unlock(&node->provider->lock); } mutex_unlock(&icc_lock); @@ -791,8 +798,10 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider) { mutex_lock(&icc_lock); + mutex_lock(&provider->lock); node->provider = provider; list_add_tail(&node->node_list, &provider->nodes); + mutex_unlock(&provider->lock); mutex_unlock(&icc_lock); } @@ -806,7 +815,9 @@ void icc_node_del(struct icc_node *node) { mutex_lock(&icc_lock); + mutex_lock(&node->provider->lock); list_del(&node->node_list); + mutex_unlock(&node->provider->lock); mutex_unlock(&icc_lock); } @@ -847,6 +858,8 @@ int icc_provider_add(struct icc_provider *provider) if (WARN_ON(!provider->xlate)) return -EINVAL; + mutex_init(&provider->lock); + mutex_lock(&icc_lock); INIT_LIST_HEAD(&provider->nodes); diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h index 5b64e267bfb3..cb2bed5c78f9 100644 --- a/include/linux/interconnect-provider.h +++ b/include/linux/interconnect-provider.h @@ -34,6 +34,7 @@ struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec, * * @provider_list: list of the registered interconnect providers * @nodes: internal list of the interconnect provider nodes + * @lock: interconnect provider specific lock * @set: pointer to device specific set operation function * @aggregate: pointer to device specific aggregate operation function * @pre_aggregate: pointer to device specific function that is called @@ -46,6 +47,7 @@ struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec, struct icc_provider { struct list_head provider_list; struct list_head nodes; + struct mutex lock; int (*set)(struct icc_node *src, struct icc_node *dst); int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw, u32 peak_bw, u32 *agg_avg, u32 *agg_peak); |