Lines Matching +full:data +full:- +full:path

1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (c) 2017-2019, Linaro Ltd.
14 #include <linux/interconnect-provider.h>
39 seq_printf(s, "%-42s %12u %12u\n", in icc_summary_show_one()
40 n->name, n->avg_bw, n->peak_bw); in icc_summary_show_one()
43 static int icc_summary_show(struct seq_file *s, void *data) in icc_summary_show() argument
48 seq_puts(s, "--------------------------------------------------------------------\n"); in icc_summary_show()
55 list_for_each_entry(n, &provider->nodes, node_list) { in icc_summary_show()
59 hlist_for_each_entry(r, &n->req_list, req_node) { in icc_summary_show()
62 if (!r->dev) in icc_summary_show()
65 if (r->enabled) { in icc_summary_show()
66 avg_bw = r->avg_bw; in icc_summary_show()
67 peak_bw = r->peak_bw; in icc_summary_show()
70 seq_printf(s, " %-27s %12u %12u %12u\n", in icc_summary_show()
71 dev_name(r->dev), r->tag, avg_bw, peak_bw); in icc_summary_show()
85 seq_printf(s, "%s\"%d:%s\" -> \"%d:%s\"\n", in icc_graph_show_link()
87 n->id, n->name, m->id, m->name); in icc_graph_show_link()
93 n->id, n->name, n->id, n->name); in icc_graph_show_node()
94 seq_printf(s, "\n\t\t\t|avg_bw=%ukBps", n->avg_bw); in icc_graph_show_node()
95 seq_printf(s, "\n\t\t\t|peak_bw=%ukBps", n->peak_bw); in icc_graph_show_node()
99 static int icc_graph_show(struct seq_file *s, void *data) in icc_graph_show() argument
113 if (provider->dev) in icc_graph_show()
115 dev_name(provider->dev)); in icc_graph_show()
118 list_for_each_entry(n, &provider->nodes, node_list) in icc_graph_show()
122 list_for_each_entry(n, &provider->nodes, node_list) in icc_graph_show()
123 for (i = 0; i < n->num_links; ++i) in icc_graph_show()
124 if (n->provider == n->links[i]->provider) in icc_graph_show()
126 n->links[i]); in icc_graph_show()
133 list_for_each_entry(n, &provider->nodes, node_list) in icc_graph_show()
134 for (i = 0; i < n->num_links; ++i) in icc_graph_show()
135 if (n->provider != n->links[i]->provider) in icc_graph_show()
137 n->links[i]); in icc_graph_show()
157 list_for_each_entry(n, &provider->nodes, node_list) { in node_find_by_name()
158 if (!strcmp(n->name, name)) in node_find_by_name()
170 struct icc_path *path; in path_init() local
173 path = kzalloc(struct_size(path, reqs, num_nodes), GFP_KERNEL); in path_init()
174 if (!path) in path_init()
175 return ERR_PTR(-ENOMEM); in path_init()
177 path->num_nodes = num_nodes; in path_init()
181 for (i = num_nodes - 1; i >= 0; i--) { in path_init()
182 node->provider->users++; in path_init()
183 hlist_add_head(&path->reqs[i].req_node, &node->req_list); in path_init()
184 path->reqs[i].node = node; in path_init()
185 path->reqs[i].dev = dev; in path_init()
186 path->reqs[i].enabled = true; in path_init()
187 /* reference to previous node was saved during path traversal */ in path_init()
188 node = node->reverse; in path_init()
193 return path; in path_init()
199 struct icc_path *path = ERR_PTR(-EPROBE_DEFER); in path_find() local
211 list_add(&src->search_list, &traverse_list); in path_find()
212 src->reverse = NULL; in path_find()
222 for (i = 0; i < node->num_links; i++) { in path_find()
223 struct icc_node *tmp = node->links[i]; in path_find()
226 path = ERR_PTR(-ENOENT); in path_find()
230 if (tmp->is_traversed) in path_find()
233 tmp->is_traversed = true; in path_find()
234 tmp->reverse = node; in path_find()
235 list_add_tail(&tmp->search_list, &edge_list); in path_find()
254 n->is_traversed = false; in path_find()
257 path = path_init(dev, dst, depth); in path_find()
259 return path; in path_find()
263 * We want the path to honor all bandwidth requests, so the average and peak
271 struct icc_provider *p = node->provider; in aggregate_requests()
275 node->avg_bw = 0; in aggregate_requests()
276 node->peak_bw = 0; in aggregate_requests()
278 if (p->pre_aggregate) in aggregate_requests()
279 p->pre_aggregate(node); in aggregate_requests()
281 hlist_for_each_entry(r, &node->req_list, req_node) { in aggregate_requests()
282 if (r->enabled) { in aggregate_requests()
283 avg_bw = r->avg_bw; in aggregate_requests()
284 peak_bw = r->peak_bw; in aggregate_requests()
289 p->aggregate(node, r->tag, avg_bw, peak_bw, in aggregate_requests()
290 &node->avg_bw, &node->peak_bw); in aggregate_requests()
294 node->avg_bw = max(node->avg_bw, node->init_avg); in aggregate_requests()
295 node->peak_bw = max(node->peak_bw, node->init_peak); in aggregate_requests()
302 static int apply_constraints(struct icc_path *path) in apply_constraints() argument
306 int ret = -EINVAL; in apply_constraints()
309 for (i = 0; i < path->num_nodes; i++) { in apply_constraints()
310 next = path->reqs[i].node; in apply_constraints()
311 p = next->provider; in apply_constraints()
313 /* both endpoints should be valid master-slave pairs */ in apply_constraints()
314 if (!prev || (p != prev->provider && !p->inter_set)) { in apply_constraints()
320 ret = p->set(prev, next); in apply_constraints()
340 /* of_icc_xlate_onecell() - Translate function using a single index.
342 * @data: private data (pointer to struct icc_onecell_data)
351 void *data) in of_icc_xlate_onecell() argument
353 struct icc_onecell_data *icc_data = data; in of_icc_xlate_onecell()
354 unsigned int idx = spec->args[0]; in of_icc_xlate_onecell()
356 if (idx >= icc_data->num_nodes) { in of_icc_xlate_onecell()
358 return ERR_PTR(-EINVAL); in of_icc_xlate_onecell()
361 return icc_data->nodes[idx]; in of_icc_xlate_onecell()
366 * of_icc_get_from_provider() - Look-up interconnect node
367 * @spec: OF phandle args to use for look-up
377 struct icc_node *node = ERR_PTR(-EPROBE_DEFER); in of_icc_get_from_provider()
378 struct icc_node_data *data = NULL; in of_icc_get_from_provider() local
382 return ERR_PTR(-EINVAL); in of_icc_get_from_provider()
386 if (provider->dev->of_node == spec->np) { in of_icc_get_from_provider()
387 if (provider->xlate_extended) { in of_icc_get_from_provider()
388 data = provider->xlate_extended(spec, provider->data); in of_icc_get_from_provider()
389 if (!IS_ERR(data)) { in of_icc_get_from_provider()
390 node = data->node; in of_icc_get_from_provider()
394 node = provider->xlate(spec, provider->data); in of_icc_get_from_provider()
403 return ERR_PTR(-EINVAL); in of_icc_get_from_provider()
408 if (!data) { in of_icc_get_from_provider()
409 data = kzalloc(sizeof(*data), GFP_KERNEL); in of_icc_get_from_provider()
410 if (!data) in of_icc_get_from_provider()
411 return ERR_PTR(-ENOMEM); in of_icc_get_from_provider()
412 data->node = node; in of_icc_get_from_provider()
415 return data; in of_icc_get_from_provider()
426 struct icc_path **ptr, *path; in devm_of_icc_get() local
430 return ERR_PTR(-ENOMEM); in devm_of_icc_get()
432 path = of_icc_get(dev, name); in devm_of_icc_get()
433 if (!IS_ERR(path)) { in devm_of_icc_get()
434 *ptr = path; in devm_of_icc_get()
440 return path; in devm_of_icc_get()
445 * of_icc_get_by_index() - get a path handle from a DT node based on index
447 * @idx: interconnect path index
449 * This function will search for a path between two endpoints and return an
461 struct icc_path *path; in of_icc_get_by_index() local
467 if (!dev || !dev->of_node) in of_icc_get_by_index()
468 return ERR_PTR(-ENODEV); in of_icc_get_by_index()
470 np = dev->of_node; in of_icc_get_by_index()
474 * return a NULL path to skip setting constraints. in of_icc_get_by_index()
485 "#interconnect-cells", idx * 2, in of_icc_get_by_index()
493 "#interconnect-cells", idx * 2 + 1, in of_icc_get_by_index()
516 path = path_find(dev, src_data->node, dst_data->node); in of_icc_get_by_index()
518 if (IS_ERR(path)) { in of_icc_get_by_index()
519 dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path)); in of_icc_get_by_index()
523 if (src_data->tag && src_data->tag == dst_data->tag) in of_icc_get_by_index()
524 icc_set_tag(path, src_data->tag); in of_icc_get_by_index()
526 path->name = kasprintf(GFP_KERNEL, "%s-%s", in of_icc_get_by_index()
527 src_data->node->name, dst_data->node->name); in of_icc_get_by_index()
528 if (!path->name) { in of_icc_get_by_index()
529 kfree(path); in of_icc_get_by_index()
530 path = ERR_PTR(-ENOMEM); in of_icc_get_by_index()
536 return path; in of_icc_get_by_index()
541 * of_icc_get() - get a path handle from a DT node based on name
543 * @name: interconnect path name
545 * This function will search for a path between two endpoints and return an
560 if (!dev || !dev->of_node) in of_icc_get()
561 return ERR_PTR(-ENODEV); in of_icc_get()
563 np = dev->of_node; in of_icc_get()
567 * return a NULL path to skip setting constraints. in of_icc_get()
578 idx = of_property_match_string(np, "interconnect-names", name); in of_icc_get()
588 * icc_get() - get a path handle between two endpoints
593 * This function will search for a path between two endpoints and return an
603 struct icc_path *path = ERR_PTR(-EPROBE_DEFER); in icc_get() local
619 path = path_find(dev, src_node, dst_node); in icc_get()
620 if (IS_ERR(path)) { in icc_get()
621 dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path)); in icc_get()
625 path->name = kasprintf(GFP_KERNEL, "%s-%s", src_node->name, dst_node->name); in icc_get()
626 if (!path->name) { in icc_get()
627 kfree(path); in icc_get()
628 path = ERR_PTR(-ENOMEM); in icc_get()
632 return path; in icc_get()
636 * icc_set_tag() - set an optional tag on a path
637 * @path: the path we want to tag
641 * with a path, so that a different aggregation could be done based on this tag.
643 void icc_set_tag(struct icc_path *path, u32 tag) in icc_set_tag() argument
647 if (!path) in icc_set_tag()
652 for (i = 0; i < path->num_nodes; i++) in icc_set_tag()
653 path->reqs[i].tag = tag; in icc_set_tag()
660 * icc_get_name() - Get name of the icc path
661 * @path: interconnect path
664 * path.
668 const char *icc_get_name(struct icc_path *path) in icc_get_name() argument
670 if (!path) in icc_get_name()
673 return path->name; in icc_get_name()
678 * icc_set_bw() - set bandwidth constraints on an interconnect path
679 * @path: interconnect path
684 * in terms of bandwidth for a previously requested path between two endpoints.
686 * path is locked by a mutex to ensure that the set() is completed.
687 * The @path can be NULL when the "interconnects" DT properties is missing,
692 int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw) in icc_set_bw() argument
699 if (!path) in icc_set_bw()
702 if (WARN_ON(IS_ERR(path) || !path->num_nodes)) in icc_set_bw()
703 return -EINVAL; in icc_set_bw()
707 old_avg = path->reqs[0].avg_bw; in icc_set_bw()
708 old_peak = path->reqs[0].peak_bw; in icc_set_bw()
710 for (i = 0; i < path->num_nodes; i++) { in icc_set_bw()
711 node = path->reqs[i].node; in icc_set_bw()
713 /* update the consumer request for this path */ in icc_set_bw()
714 path->reqs[i].avg_bw = avg_bw; in icc_set_bw()
715 path->reqs[i].peak_bw = peak_bw; in icc_set_bw()
720 trace_icc_set_bw(path, node, i, avg_bw, peak_bw); in icc_set_bw()
723 ret = apply_constraints(path); in icc_set_bw()
728 for (i = 0; i < path->num_nodes; i++) { in icc_set_bw()
729 node = path->reqs[i].node; in icc_set_bw()
730 path->reqs[i].avg_bw = old_avg; in icc_set_bw()
731 path->reqs[i].peak_bw = old_peak; in icc_set_bw()
734 apply_constraints(path); in icc_set_bw()
739 trace_icc_set_bw_end(path, ret); in icc_set_bw()
745 static int __icc_enable(struct icc_path *path, bool enable) in __icc_enable() argument
749 if (!path) in __icc_enable()
752 if (WARN_ON(IS_ERR(path) || !path->num_nodes)) in __icc_enable()
753 return -EINVAL; in __icc_enable()
757 for (i = 0; i < path->num_nodes; i++) in __icc_enable()
758 path->reqs[i].enabled = enable; in __icc_enable()
762 return icc_set_bw(path, path->reqs[0].avg_bw, in __icc_enable()
763 path->reqs[0].peak_bw); in __icc_enable()
766 int icc_enable(struct icc_path *path) in icc_enable() argument
768 return __icc_enable(path, true); in icc_enable()
772 int icc_disable(struct icc_path *path) in icc_disable() argument
774 return __icc_enable(path, false); in icc_disable()
779 * icc_put() - release the reference to the icc_path
780 * @path: interconnect path
782 * Use this function to release the constraints on a path when the path is
783 * no longer needed. The constraints will be re-aggregated.
785 void icc_put(struct icc_path *path) in icc_put() argument
791 if (!path || WARN_ON(IS_ERR(path))) in icc_put()
794 ret = icc_set_bw(path, 0, 0); in icc_put()
801 for (i = 0; i < path->num_nodes; i++) { in icc_put()
802 node = path->reqs[i].node; in icc_put()
803 hlist_del(&path->reqs[i].req_node); in icc_put()
804 if (!WARN_ON(!node->provider->users)) in icc_put()
805 node->provider->users--; in icc_put()
811 kfree(path->name); in icc_put()
812 kfree(path); in icc_put()
827 return ERR_PTR(-ENOMEM); in icc_node_create_nolock()
836 node->id = id; in icc_node_create_nolock()
842 * icc_node_create() - create a node
862 * icc_node_destroy() - destroy a node
873 idr_remove(&icc_idr, node->id); in icc_node_destroy()
874 WARN_ON(!hlist_empty(&node->req_list)); in icc_node_destroy()
882 kfree(node->links); in icc_node_destroy()
888 * icc_link_create() - create a link between two nodes
896 * data is filled.
906 if (!node->provider) in icc_link_create()
907 return -EINVAL; in icc_link_create()
921 new = krealloc(node->links, in icc_link_create()
922 (node->num_links + 1) * sizeof(*node->links), in icc_link_create()
925 ret = -ENOMEM; in icc_link_create()
929 node->links = new; in icc_link_create()
930 node->links[node->num_links++] = dst; in icc_link_create()
940 * icc_node_add() - add interconnect node to interconnect provider
946 if (WARN_ON(node->provider)) in icc_node_add()
952 node->provider = provider; in icc_node_add()
953 list_add_tail(&node->node_list, &provider->nodes); in icc_node_add()
956 if (provider->get_bw) { in icc_node_add()
957 provider->get_bw(node, &node->init_avg, &node->init_peak); in icc_node_add()
959 node->init_avg = INT_MAX; in icc_node_add()
960 node->init_peak = INT_MAX; in icc_node_add()
962 node->avg_bw = node->init_avg; in icc_node_add()
963 node->peak_bw = node->init_peak; in icc_node_add()
965 if (node->avg_bw || node->peak_bw) { in icc_node_add()
966 if (provider->pre_aggregate) in icc_node_add()
967 provider->pre_aggregate(node); in icc_node_add()
969 if (provider->aggregate) in icc_node_add()
970 provider->aggregate(node, 0, node->init_avg, node->init_peak, in icc_node_add()
971 &node->avg_bw, &node->peak_bw); in icc_node_add()
972 if (provider->set) in icc_node_add()
973 provider->set(node, node); in icc_node_add()
976 node->avg_bw = 0; in icc_node_add()
977 node->peak_bw = 0; in icc_node_add()
985 * icc_node_del() - delete interconnect node from interconnect provider
992 list_del(&node->node_list); in icc_node_del()
999 * icc_nodes_remove() - remove all previously added nodes from provider
1009 return -EINVAL; in icc_nodes_remove()
1011 list_for_each_entry_safe_reverse(n, tmp, &provider->nodes, node_list) { in icc_nodes_remove()
1013 icc_node_destroy(n->id); in icc_nodes_remove()
1021 * icc_provider_init() - initialize a new interconnect provider
1028 WARN_ON(!provider->set); in icc_provider_init()
1030 INIT_LIST_HEAD(&provider->nodes); in icc_provider_init()
1035 * icc_provider_register() - register a new interconnect provider
1042 if (WARN_ON(!provider->xlate && !provider->xlate_extended)) in icc_provider_register()
1043 return -EINVAL; in icc_provider_register()
1046 list_add_tail(&provider->provider_list, &icc_providers); in icc_provider_register()
1049 dev_dbg(provider->dev, "interconnect provider registered\n"); in icc_provider_register()
1056 * icc_provider_deregister() - deregister an interconnect provider
1062 WARN_ON(provider->users); in icc_provider_deregister()
1064 list_del(&provider->provider_list); in icc_provider_deregister()
1070 { .compatible = "qcom,sc7180-ipa-virt" },
1071 { .compatible = "qcom,sc8180x-ipa-virt" },
1072 { .compatible = "qcom,sdx55-ipa-virt" },
1073 { .compatible = "qcom,sm8150-ipa-virt" },
1074 { .compatible = "qcom,sm8250-ipa-virt" },
1084 if (of_property_present(child, "#interconnect-cells") && in of_count_icc_providers()
1108 dev_dbg(p->dev, "interconnect provider is in synced state\n"); in icc_sync_state()
1109 list_for_each_entry(n, &p->nodes, node_list) { in icc_sync_state()
1110 if (n->init_avg || n->init_peak) { in icc_sync_state()
1111 n->init_avg = 0; in icc_sync_state()
1112 n->init_peak = 0; in icc_sync_state()
1114 p->set(n, n); in icc_sync_state()