Skip to content

Commit 10d3e38

Browse files
committed
Merge tag 'icc-5.6-rc1' of https://git.linaro.org/people/georgi.djakov/linux into char-misc-next
Georgi writes: interconnect patches for 5.6 Here are the interconnect patches for the 5.6-rc1 merge window. - New core helper functions for some common functionalities in drivers. - Improvements in the information exposed via debugfs. - Basic tracepoints support. - New interconnect driver for msm8916 platforms. - Misc fixes. Signed-off-by: Georgi Djakov <[email protected]> * tag 'icc-5.6-rc1' of https://git.linaro.org/people/georgi.djakov/linux: interconnect: qcom: Add MSM8916 interconnect provider driver dt-bindings: interconnect: Add Qualcomm MSM8916 DT bindings interconnect: Check for valid path in icc_set_bw() interconnect: Print the tag in the debugfs summary interconnect: Add interconnect_graph file to debugfs interconnect: qcom: Use the standard aggregate function interconnect: Add a common standard aggregate function interconnect: Add basic tracepoints interconnect: Add a name to struct icc_path interconnect: Move internal structs into a separate file interconnect: qcom: Use the new common helper for node removal interconnect: Add a common helper for removing all nodes
2 parents 3634a4a + 30c8fa3 commit 10d3e38

File tree

14 files changed

+1057
-100
lines changed

14 files changed

+1057
-100
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Qualcomm MSM8916 Network-On-Chip interconnect
8+
9+
maintainers:
10+
- Georgi Djakov <[email protected]>
11+
12+
description: |
13+
The Qualcomm MSM8916 interconnect providers support adjusting the
14+
bandwidth requirements between the various NoC fabrics.
15+
16+
properties:
17+
compatible:
18+
enum:
19+
- qcom,msm8916-bimc
20+
- qcom,msm8916-pcnoc
21+
- qcom,msm8916-snoc
22+
23+
reg:
24+
maxItems: 1
25+
26+
'#interconnect-cells':
27+
const: 1
28+
29+
clock-names:
30+
items:
31+
- const: bus
32+
- const: bus_a
33+
34+
clocks:
35+
items:
36+
- description: Bus Clock
37+
- description: Bus A Clock
38+
39+
required:
40+
- compatible
41+
- reg
42+
- '#interconnect-cells'
43+
- clock-names
44+
- clocks
45+
46+
additionalProperties: false
47+
48+
examples:
49+
- |
50+
#include <dt-bindings/clock/qcom,rpmcc.h>
51+
52+
bimc: interconnect@400000 {
53+
compatible = "qcom,msm8916-bimc";
54+
reg = <0x00400000 0x62000>;
55+
#interconnect-cells = <1>;
56+
clock-names = "bus", "bus_a";
57+
clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
58+
<&rpmcc RPM_SMD_BIMC_A_CLK>;
59+
};
60+
61+
pcnoc: interconnect@500000 {
62+
compatible = "qcom,msm8916-pcnoc";
63+
reg = <0x00500000 0x11000>;
64+
#interconnect-cells = <1>;
65+
clock-names = "bus", "bus_a";
66+
clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
67+
<&rpmcc RPM_SMD_PCNOC_A_CLK>;
68+
};
69+
70+
snoc: interconnect@580000 {
71+
compatible = "qcom,msm8916-snoc";
72+
reg = <0x00580000 0x14000>;
73+
#interconnect-cells = <1>;
74+
clock-names = "bus", "bus_a";
75+
clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
76+
<&rpmcc RPM_SMD_SNOC_A_CLK>;
77+
};

Documentation/driver-api/interconnect.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,25 @@ Interconnect consumers are the clients which use the interconnect APIs to
9191
get paths between endpoints and set their bandwidth/latency/QoS requirements
9292
for these interconnect paths. These interfaces are not currently
9393
documented.
94+
95+
Interconnect debugfs interfaces
96+
-------------------------------
97+
98+
Like several other subsystems interconnect will create some files for debugging
99+
and introspection. Files in debugfs are not considered ABI so application
100+
software shouldn't rely on format details change between kernel versions.
101+
102+
``/sys/kernel/debug/interconnect/interconnect_summary``:
103+
104+
Show all interconnect nodes in the system with their aggregated bandwidth
105+
request. Indented under each node show bandwidth requests from each device.
106+
107+
``/sys/kernel/debug/interconnect/interconnect_graph``:
108+
109+
Show the interconnect graph in the graphviz dot format. It shows all
110+
interconnect nodes and links in the system and groups together nodes from the
111+
same provider as subgraphs. The format is human-readable and can also be piped
112+
through dot to generate diagrams in many graphical formats::
113+
114+
$ cat /sys/kernel/debug/interconnect/interconnect_graph | \
115+
dot -Tsvg > interconnect_graph.svg

drivers/interconnect/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0
22

3+
CFLAGS_core.o := -I$(src)
34
icc-core-objs := core.o
45

56
obj-$(CONFIG_INTERCONNECT) += icc-core.o

drivers/interconnect/core.c

Lines changed: 131 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,54 +19,31 @@
1919
#include <linux/of.h>
2020
#include <linux/overflow.h>
2121

22+
#include "internal.h"
23+
24+
#define CREATE_TRACE_POINTS
25+
#include "trace.h"
26+
2227
static DEFINE_IDR(icc_idr);
2328
static LIST_HEAD(icc_providers);
2429
static DEFINE_MUTEX(icc_lock);
2530
static struct dentry *icc_debugfs_dir;
2631

27-
/**
28-
* struct icc_req - constraints that are attached to each node
29-
* @req_node: entry in list of requests for the particular @node
30-
* @node: the interconnect node to which this constraint applies
31-
* @dev: reference to the device that sets the constraints
32-
* @tag: path tag (optional)
33-
* @avg_bw: an integer describing the average bandwidth in kBps
34-
* @peak_bw: an integer describing the peak bandwidth in kBps
35-
*/
36-
struct icc_req {
37-
struct hlist_node req_node;
38-
struct icc_node *node;
39-
struct device *dev;
40-
u32 tag;
41-
u32 avg_bw;
42-
u32 peak_bw;
43-
};
44-
45-
/**
46-
* struct icc_path - interconnect path structure
47-
* @num_nodes: number of hops (nodes)
48-
* @reqs: array of the requests applicable to this path of nodes
49-
*/
50-
struct icc_path {
51-
size_t num_nodes;
52-
struct icc_req reqs[];
53-
};
54-
5532
static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
5633
{
5734
if (!n)
5835
return;
5936

60-
seq_printf(s, "%-30s %12u %12u\n",
37+
seq_printf(s, "%-42s %12u %12u\n",
6138
n->name, n->avg_bw, n->peak_bw);
6239
}
6340

6441
static int icc_summary_show(struct seq_file *s, void *data)
6542
{
6643
struct icc_provider *provider;
6744

68-
seq_puts(s, " node avg peak\n");
69-
seq_puts(s, "--------------------------------------------------------\n");
45+
seq_puts(s, " node tag avg peak\n");
46+
seq_puts(s, "--------------------------------------------------------------------\n");
7047

7148
mutex_lock(&icc_lock);
7249

@@ -81,8 +58,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
8158
if (!r->dev)
8259
continue;
8360

84-
seq_printf(s, " %-26s %12u %12u\n",
85-
dev_name(r->dev), r->avg_bw,
61+
seq_printf(s, " %-27s %12u %12u %12u\n",
62+
dev_name(r->dev), r->tag, r->avg_bw,
8663
r->peak_bw);
8764
}
8865
}
@@ -94,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data)
9471
}
9572
DEFINE_SHOW_ATTRIBUTE(icc_summary);
9673

74+
static void icc_graph_show_link(struct seq_file *s, int level,
75+
struct icc_node *n, struct icc_node *m)
76+
{
77+
seq_printf(s, "%s\"%d:%s\" -> \"%d:%s\"\n",
78+
level == 2 ? "\t\t" : "\t",
79+
n->id, n->name, m->id, m->name);
80+
}
81+
82+
static void icc_graph_show_node(struct seq_file *s, struct icc_node *n)
83+
{
84+
seq_printf(s, "\t\t\"%d:%s\" [label=\"%d:%s",
85+
n->id, n->name, n->id, n->name);
86+
seq_printf(s, "\n\t\t\t|avg_bw=%ukBps", n->avg_bw);
87+
seq_printf(s, "\n\t\t\t|peak_bw=%ukBps", n->peak_bw);
88+
seq_puts(s, "\"]\n");
89+
}
90+
91+
static int icc_graph_show(struct seq_file *s, void *data)
92+
{
93+
struct icc_provider *provider;
94+
struct icc_node *n;
95+
int cluster_index = 0;
96+
int i;
97+
98+
seq_puts(s, "digraph {\n\trankdir = LR\n\tnode [shape = record]\n");
99+
mutex_lock(&icc_lock);
100+
101+
/* draw providers as cluster subgraphs */
102+
cluster_index = 0;
103+
list_for_each_entry(provider, &icc_providers, provider_list) {
104+
seq_printf(s, "\tsubgraph cluster_%d {\n", ++cluster_index);
105+
if (provider->dev)
106+
seq_printf(s, "\t\tlabel = \"%s\"\n",
107+
dev_name(provider->dev));
108+
109+
/* draw nodes */
110+
list_for_each_entry(n, &provider->nodes, node_list)
111+
icc_graph_show_node(s, n);
112+
113+
/* draw internal links */
114+
list_for_each_entry(n, &provider->nodes, node_list)
115+
for (i = 0; i < n->num_links; ++i)
116+
if (n->provider == n->links[i]->provider)
117+
icc_graph_show_link(s, 2, n,
118+
n->links[i]);
119+
120+
seq_puts(s, "\t}\n");
121+
}
122+
123+
/* draw external links */
124+
list_for_each_entry(provider, &icc_providers, provider_list)
125+
list_for_each_entry(n, &provider->nodes, node_list)
126+
for (i = 0; i < n->num_links; ++i)
127+
if (n->provider != n->links[i]->provider)
128+
icc_graph_show_link(s, 1, n,
129+
n->links[i]);
130+
131+
mutex_unlock(&icc_lock);
132+
seq_puts(s, "}");
133+
134+
return 0;
135+
}
136+
DEFINE_SHOW_ATTRIBUTE(icc_graph);
137+
97138
static struct icc_node *node_find(const int id)
98139
{
99140
return idr_find(&icc_idr, id);
@@ -244,6 +285,16 @@ static int apply_constraints(struct icc_path *path)
244285
return ret;
245286
}
246287

288+
int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
289+
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
290+
{
291+
*agg_avg += avg_bw;
292+
*agg_peak = max(*agg_peak, peak_bw);
293+
294+
return 0;
295+
}
296+
EXPORT_SYMBOL_GPL(icc_std_aggregate);
297+
247298
/* of_icc_xlate_onecell() - Translate function using a single index.
248299
* @spec: OF phandle args to map into an interconnect node.
249300
* @data: private data (pointer to struct icc_onecell_data)
@@ -382,9 +433,17 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
382433

383434
mutex_lock(&icc_lock);
384435
path = path_find(dev, src_node, dst_node);
385-
if (IS_ERR(path))
386-
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
387436
mutex_unlock(&icc_lock);
437+
if (IS_ERR(path)) {
438+
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
439+
return path;
440+
}
441+
442+
if (name)
443+
path->name = kstrdup_const(name, GFP_KERNEL);
444+
else
445+
path->name = kasprintf(GFP_KERNEL, "%s-%s",
446+
src_node->name, dst_node->name);
388447

389448
return path;
390449
}
@@ -436,9 +495,12 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
436495
size_t i;
437496
int ret;
438497

439-
if (!path || !path->num_nodes)
498+
if (!path)
440499
return 0;
441500

501+
if (WARN_ON(IS_ERR(path) || !path->num_nodes))
502+
return -EINVAL;
503+
442504
mutex_lock(&icc_lock);
443505

444506
old_avg = path->reqs[0].avg_bw;
@@ -453,6 +515,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
453515

454516
/* aggregate requests for this node */
455517
aggregate_requests(node);
518+
519+
trace_icc_set_bw(path, node, i, avg_bw, peak_bw);
456520
}
457521

458522
ret = apply_constraints(path);
@@ -471,6 +535,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
471535

472536
mutex_unlock(&icc_lock);
473537

538+
trace_icc_set_bw_end(path, ret);
539+
474540
return ret;
475541
}
476542
EXPORT_SYMBOL_GPL(icc_set_bw);
@@ -507,9 +573,12 @@ struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
507573
goto out;
508574

509575
path = path_find(dev, src, dst);
510-
if (IS_ERR(path))
576+
if (IS_ERR(path)) {
511577
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
578+
goto out;
579+
}
512580

581+
path->name = kasprintf(GFP_KERNEL, "%s-%s", src->name, dst->name);
513582
out:
514583
mutex_unlock(&icc_lock);
515584
return path;
@@ -545,6 +614,7 @@ void icc_put(struct icc_path *path)
545614
}
546615
mutex_unlock(&icc_lock);
547616

617+
kfree_const(path->name);
548618
kfree(path);
549619
}
550620
EXPORT_SYMBOL_GPL(icc_put);
@@ -742,6 +812,28 @@ void icc_node_del(struct icc_node *node)
742812
}
743813
EXPORT_SYMBOL_GPL(icc_node_del);
744814

815+
/**
816+
* icc_nodes_remove() - remove all previously added nodes from provider
817+
* @provider: the interconnect provider we are removing nodes from
818+
*
819+
* Return: 0 on success, or an error code otherwise
820+
*/
821+
int icc_nodes_remove(struct icc_provider *provider)
822+
{
823+
struct icc_node *n, *tmp;
824+
825+
if (WARN_ON(IS_ERR_OR_NULL(provider)))
826+
return -EINVAL;
827+
828+
list_for_each_entry_safe_reverse(n, tmp, &provider->nodes, node_list) {
829+
icc_node_del(n);
830+
icc_node_destroy(n->id);
831+
}
832+
833+
return 0;
834+
}
835+
EXPORT_SYMBOL_GPL(icc_nodes_remove);
836+
745837
/**
746838
* icc_provider_add() - add a new interconnect provider
747839
* @provider: the interconnect provider that will be added into topology
@@ -802,6 +894,8 @@ static int __init icc_init(void)
802894
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
803895
debugfs_create_file("interconnect_summary", 0444,
804896
icc_debugfs_dir, NULL, &icc_summary_fops);
897+
debugfs_create_file("interconnect_graph", 0444,
898+
icc_debugfs_dir, NULL, &icc_graph_fops);
805899
return 0;
806900
}
807901

0 commit comments

Comments
 (0)