19
19
#include <linux/of.h>
20
20
#include <linux/overflow.h>
21
21
22
+ #include "internal.h"
23
+
24
+ #define CREATE_TRACE_POINTS
25
+ #include "trace.h"
26
+
22
27
static DEFINE_IDR (icc_idr );
23
28
static LIST_HEAD (icc_providers );
24
29
static DEFINE_MUTEX (icc_lock );
25
30
static struct dentry * icc_debugfs_dir ;
26
31
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
-
55
32
static void icc_summary_show_one (struct seq_file * s , struct icc_node * n )
56
33
{
57
34
if (!n )
58
35
return ;
59
36
60
- seq_printf (s , "%-30s %12u %12u\n" ,
37
+ seq_printf (s , "%-42s %12u %12u\n" ,
61
38
n -> name , n -> avg_bw , n -> peak_bw );
62
39
}
63
40
64
41
static int icc_summary_show (struct seq_file * s , void * data )
65
42
{
66
43
struct icc_provider * provider ;
67
44
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" );
70
47
71
48
mutex_lock (& icc_lock );
72
49
@@ -81,8 +58,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
81
58
if (!r -> dev )
82
59
continue ;
83
60
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 ,
86
63
r -> peak_bw );
87
64
}
88
65
}
@@ -94,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data)
94
71
}
95
72
DEFINE_SHOW_ATTRIBUTE (icc_summary );
96
73
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
+
97
138
static struct icc_node * node_find (const int id )
98
139
{
99
140
return idr_find (& icc_idr , id );
@@ -244,6 +285,16 @@ static int apply_constraints(struct icc_path *path)
244
285
return ret ;
245
286
}
246
287
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
+
247
298
/* of_icc_xlate_onecell() - Translate function using a single index.
248
299
* @spec: OF phandle args to map into an interconnect node.
249
300
* @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)
382
433
383
434
mutex_lock (& icc_lock );
384
435
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 ));
387
436
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 );
388
447
389
448
return path ;
390
449
}
@@ -436,9 +495,12 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
436
495
size_t i ;
437
496
int ret ;
438
497
439
- if (!path || ! path -> num_nodes )
498
+ if (!path )
440
499
return 0 ;
441
500
501
+ if (WARN_ON (IS_ERR (path ) || !path -> num_nodes ))
502
+ return - EINVAL ;
503
+
442
504
mutex_lock (& icc_lock );
443
505
444
506
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)
453
515
454
516
/* aggregate requests for this node */
455
517
aggregate_requests (node );
518
+
519
+ trace_icc_set_bw (path , node , i , avg_bw , peak_bw );
456
520
}
457
521
458
522
ret = apply_constraints (path );
@@ -471,6 +535,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
471
535
472
536
mutex_unlock (& icc_lock );
473
537
538
+ trace_icc_set_bw_end (path , ret );
539
+
474
540
return ret ;
475
541
}
476
542
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)
507
573
goto out ;
508
574
509
575
path = path_find (dev , src , dst );
510
- if (IS_ERR (path ))
576
+ if (IS_ERR (path )) {
511
577
dev_err (dev , "%s: invalid path=%ld\n" , __func__ , PTR_ERR (path ));
578
+ goto out ;
579
+ }
512
580
581
+ path -> name = kasprintf (GFP_KERNEL , "%s-%s" , src -> name , dst -> name );
513
582
out :
514
583
mutex_unlock (& icc_lock );
515
584
return path ;
@@ -545,6 +614,7 @@ void icc_put(struct icc_path *path)
545
614
}
546
615
mutex_unlock (& icc_lock );
547
616
617
+ kfree_const (path -> name );
548
618
kfree (path );
549
619
}
550
620
EXPORT_SYMBOL_GPL (icc_put );
@@ -742,6 +812,28 @@ void icc_node_del(struct icc_node *node)
742
812
}
743
813
EXPORT_SYMBOL_GPL (icc_node_del );
744
814
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
+
745
837
/**
746
838
* icc_provider_add() - add a new interconnect provider
747
839
* @provider: the interconnect provider that will be added into topology
@@ -802,6 +894,8 @@ static int __init icc_init(void)
802
894
icc_debugfs_dir = debugfs_create_dir ("interconnect" , NULL );
803
895
debugfs_create_file ("interconnect_summary" , 0444 ,
804
896
icc_debugfs_dir , NULL , & icc_summary_fops );
897
+ debugfs_create_file ("interconnect_graph" , 0444 ,
898
+ icc_debugfs_dir , NULL , & icc_graph_fops );
805
899
return 0 ;
806
900
}
807
901
0 commit comments