Skip to content

Commit 96657eb

Browse files
committed
Merge tag 'icc-6.20-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/djakov/icc into char-misc-next
Georgi writes: interconnect changes for 6.20 This pull request contains the interconnect changes for the 6.20-rc1 merge window. The core and driver changes are listed below. Core changes: - Add KUnit tests for core functionality Driver changes: - New driver for MediaTek MT8196 EMI - MediaTek driver fixes - Support for Glymur BWMONs - QCS8300 driver topology fix - Misc cleanups Signed-off-by: Georgi Djakov <djakov@kernel.org> * tag 'icc-6.20-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/djakov/icc: interconnect: qcom: msm8974: drop duplicated RPM_BUS_{MASTER,SLAVE}_REQ defines interconnect: qcom: smd-rpm: drop duplicated QCOM_RPM_SMD_KEY_RATE define dt-bindings: interconnect: qcom-bwmon: Document Glymur BWMONs interconnect: qcom: qcs8300: fix the num_links for nsp icc node interconnect: Add kunit tests for core functionality dt-bindings: interconnect: qcom,qcs615-rpmh: Drop IPA interconnects interconnect: mediatek: Aggregate bandwidth with saturating add interconnect: mediatek: Don't hijack parent device interconnect: mediatek: Add support for MediaTek MT8196 EMI ICC dt-bindings: interconnect: mt8183-emi: Add support for MT8196 EMI
2 parents 370fdb9 + 0e841d1 commit 96657eb

14 files changed

Lines changed: 788 additions & 10 deletions

File tree

Documentation/devicetree/bindings/interconnect/mediatek,mt8183-emi.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ properties:
4040
enum:
4141
- mediatek,mt8183-emi
4242
- mediatek,mt8195-emi
43+
- mediatek,mt8196-emi
4344

4445
'#interconnect-cells':
4546
const: 1

Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ properties:
2525
- const: qcom,msm8998-bwmon # BWMON v4
2626
- items:
2727
- enum:
28+
- qcom,glymur-cpu-bwmon
2829
- qcom,kaanapali-cpu-bwmon
2930
- qcom,qcm2290-cpu-bwmon
3031
- qcom,qcs615-cpu-bwmon

Documentation/devicetree/bindings/interconnect/qcom,qcs615-rpmh.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ properties:
2727
- qcom,qcs615-config-noc
2828
- qcom,qcs615-dc-noc
2929
- qcom,qcs615-gem-noc
30-
- qcom,qcs615-ipa-virt
3130
- qcom,qcs615-mc-virt
3231
- qcom,qcs615-mmss-noc
3332
- qcom,qcs615-system-noc
@@ -46,7 +45,6 @@ allOf:
4645
contains:
4746
enum:
4847
- qcom,qcs615-camnoc-virt
49-
- qcom,qcs615-ipa-virt
5048
- qcom,qcs615-mc-virt
5149
then:
5250
properties:

drivers/interconnect/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,18 @@ config INTERCONNECT_CLK
2222
help
2323
Support for wrapping clocks into the interconnect nodes.
2424

25+
config INTERCONNECT_KUNIT_TEST
26+
tristate "KUnit tests for Interconnect framework"
27+
depends on KUNIT
28+
default KUNIT_ALL_TESTS
29+
help
30+
This builds the KUnit test suite for the generic system interconnect
31+
framework.
32+
33+
The tests cover the core functionality of the interconnect subsystem,
34+
including provider/consumer APIs, topology management, and bandwidth
35+
aggregation logic.
36+
37+
If unsure, say N.
38+
2539
endif

drivers/interconnect/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/
1010
obj-$(CONFIG_INTERCONNECT_SAMSUNG) += samsung/
1111

1212
obj-$(CONFIG_INTERCONNECT_CLK) += icc-clk.o
13+
14+
obj-$(CONFIG_INTERCONNECT_KUNIT_TEST) += icc-kunit.o

drivers/interconnect/icc-kunit.c

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* KUnit tests for the Interconnect framework.
4+
*
5+
* Copyright (c) 2025 Kuan-Wei Chiu <visitorckw@gmail.com>
6+
*
7+
* This suite verifies the behavior of the interconnect core, including
8+
* topology construction, bandwidth aggregation, and path lifecycle.
9+
*/
10+
11+
#include <kunit/platform_device.h>
12+
#include <kunit/test.h>
13+
#include <linux/interconnect-provider.h>
14+
#include <linux/interconnect.h>
15+
#include <linux/list.h>
16+
#include <linux/module.h>
17+
#include <linux/overflow.h>
18+
#include <linux/platform_device.h>
19+
#include <linux/slab.h>
20+
21+
#include "internal.h"
22+
23+
enum {
24+
NODE_CPU,
25+
NODE_GPU,
26+
NODE_BUS,
27+
NODE_DDR,
28+
NODE_MAX
29+
};
30+
31+
struct test_node_data {
32+
int id;
33+
const char *name;
34+
int num_links;
35+
int links[2];
36+
};
37+
38+
/*
39+
* Static Topology:
40+
* CPU -\
41+
* -> BUS -> DDR
42+
* GPU -/
43+
*/
44+
static const struct test_node_data test_topology[] = {
45+
{ NODE_CPU, "cpu", 1, { NODE_BUS } },
46+
{ NODE_GPU, "gpu", 1, { NODE_BUS } },
47+
{ NODE_BUS, "bus", 1, { NODE_DDR } },
48+
{ NODE_DDR, "ddr", 0, { } },
49+
};
50+
51+
struct icc_test_priv {
52+
struct icc_provider provider;
53+
struct platform_device *pdev;
54+
struct icc_node *nodes[NODE_MAX];
55+
};
56+
57+
static struct icc_node *get_node(struct icc_test_priv *priv, int id)
58+
{
59+
int idx = id - NODE_CPU;
60+
61+
if (idx < 0 || idx >= ARRAY_SIZE(test_topology))
62+
return NULL;
63+
return priv->nodes[idx];
64+
}
65+
66+
static int icc_test_set(struct icc_node *src, struct icc_node *dst)
67+
{
68+
return 0;
69+
}
70+
71+
static int icc_test_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
72+
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
73+
{
74+
return icc_std_aggregate(node, tag, avg_bw, peak_bw, agg_avg, agg_peak);
75+
}
76+
77+
static struct icc_node *icc_test_xlate(const struct of_phandle_args *spec, void *data)
78+
{
79+
return NULL;
80+
}
81+
82+
static int icc_test_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
83+
{
84+
*avg = 0;
85+
*peak = 0;
86+
87+
return 0;
88+
}
89+
90+
static int icc_test_init(struct kunit *test)
91+
{
92+
struct icc_test_priv *priv;
93+
struct icc_node *node;
94+
int i, j, ret;
95+
96+
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
97+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
98+
test->priv = priv;
99+
100+
priv->pdev = kunit_platform_device_alloc(test, "icc-test-dev", -1);
101+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->pdev);
102+
KUNIT_ASSERT_EQ(test, kunit_platform_device_add(test, priv->pdev), 0);
103+
104+
priv->provider.set = icc_test_set;
105+
priv->provider.aggregate = icc_test_aggregate;
106+
priv->provider.xlate = icc_test_xlate;
107+
priv->provider.get_bw = icc_test_get_bw;
108+
priv->provider.dev = &priv->pdev->dev;
109+
priv->provider.data = priv;
110+
INIT_LIST_HEAD(&priv->provider.nodes);
111+
112+
ret = icc_provider_register(&priv->provider);
113+
KUNIT_ASSERT_EQ(test, ret, 0);
114+
115+
for (i = 0; i < ARRAY_SIZE(test_topology); i++) {
116+
const struct test_node_data *data = &test_topology[i];
117+
118+
node = icc_node_create(data->id);
119+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
120+
121+
node->name = data->name;
122+
icc_node_add(node, &priv->provider);
123+
priv->nodes[i] = node;
124+
}
125+
126+
for (i = 0; i < ARRAY_SIZE(test_topology); i++) {
127+
const struct test_node_data *data = &test_topology[i];
128+
struct icc_node *src = get_node(priv, data->id);
129+
130+
for (j = 0; j < data->num_links; j++) {
131+
ret = icc_link_create(src, data->links[j]);
132+
KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Failed to link %s->%d",
133+
src->name, data->links[j]);
134+
}
135+
}
136+
137+
icc_sync_state(&priv->pdev->dev);
138+
139+
return 0;
140+
}
141+
142+
static void icc_test_exit(struct kunit *test)
143+
{
144+
struct icc_test_priv *priv = test->priv;
145+
146+
icc_nodes_remove(&priv->provider);
147+
icc_provider_deregister(&priv->provider);
148+
}
149+
150+
/*
151+
* Helper to construct a mock path.
152+
*
153+
* Because we are bypassing icc_get(), we must manually link the requests
154+
* to the nodes' req_list so that icc_std_aggregate() can discover them.
155+
*/
156+
static struct icc_path *icc_test_create_path(struct kunit *test,
157+
struct icc_node **nodes, int num)
158+
{
159+
struct icc_path *path;
160+
int i;
161+
162+
path = kunit_kzalloc(test, struct_size(path, reqs, num), GFP_KERNEL);
163+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, path);
164+
165+
path->num_nodes = num;
166+
for (i = 0; i < num; i++) {
167+
path->reqs[i].node = nodes[i];
168+
hlist_add_head(&path->reqs[i].req_node, &nodes[i]->req_list);
169+
}
170+
path->name = "mock-path";
171+
172+
return path;
173+
}
174+
175+
static void icc_test_destroy_path(struct kunit *test, struct icc_path *path)
176+
{
177+
int i;
178+
179+
for (i = 0; i < path->num_nodes; i++)
180+
hlist_del(&path->reqs[i].req_node);
181+
182+
kunit_kfree(test, path);
183+
}
184+
185+
static void icc_test_topology_integrity(struct kunit *test)
186+
{
187+
struct icc_test_priv *priv = test->priv;
188+
struct icc_node *cpu = get_node(priv, NODE_CPU);
189+
struct icc_node *bus = get_node(priv, NODE_BUS);
190+
191+
KUNIT_EXPECT_EQ(test, cpu->num_links, 1);
192+
KUNIT_EXPECT_PTR_EQ(test, cpu->links[0], bus);
193+
KUNIT_EXPECT_PTR_EQ(test, cpu->provider, &priv->provider);
194+
}
195+
196+
static void icc_test_set_bw(struct kunit *test)
197+
{
198+
struct icc_test_priv *priv = test->priv;
199+
struct icc_path *path;
200+
struct icc_node *path_nodes[3];
201+
int ret;
202+
203+
/* Path: CPU -> BUS -> DDR */
204+
path_nodes[0] = get_node(priv, NODE_CPU);
205+
path_nodes[1] = get_node(priv, NODE_BUS);
206+
path_nodes[2] = get_node(priv, NODE_DDR);
207+
208+
path = icc_test_create_path(test, path_nodes, 3);
209+
210+
ret = icc_enable(path);
211+
KUNIT_ASSERT_EQ(test, ret, 0);
212+
213+
ret = icc_set_bw(path, 1000, 2000);
214+
KUNIT_EXPECT_EQ(test, ret, 0);
215+
216+
KUNIT_EXPECT_EQ(test, path_nodes[0]->avg_bw, 1000);
217+
KUNIT_EXPECT_EQ(test, path_nodes[0]->peak_bw, 2000);
218+
KUNIT_EXPECT_EQ(test, path_nodes[1]->avg_bw, 1000);
219+
KUNIT_EXPECT_EQ(test, path_nodes[1]->peak_bw, 2000);
220+
221+
icc_set_tag(path, 0xABC);
222+
KUNIT_EXPECT_EQ(test, path->reqs[0].tag, 0xABC);
223+
224+
icc_disable(path);
225+
KUNIT_EXPECT_EQ(test, path_nodes[0]->avg_bw, 0);
226+
227+
icc_test_destroy_path(test, path);
228+
}
229+
230+
static void icc_test_aggregation(struct kunit *test)
231+
{
232+
struct icc_test_priv *priv = test->priv;
233+
struct icc_path *path_cpu, *path_gpu;
234+
struct icc_node *nodes_cpu[3], *nodes_gpu[2];
235+
struct icc_node *bus = get_node(priv, NODE_BUS);
236+
int ret;
237+
238+
nodes_cpu[0] = get_node(priv, NODE_CPU);
239+
nodes_cpu[1] = bus;
240+
nodes_cpu[2] = get_node(priv, NODE_DDR);
241+
path_cpu = icc_test_create_path(test, nodes_cpu, 3);
242+
243+
nodes_gpu[0] = get_node(priv, NODE_GPU);
244+
nodes_gpu[1] = bus;
245+
path_gpu = icc_test_create_path(test, nodes_gpu, 2);
246+
247+
icc_enable(path_cpu);
248+
icc_enable(path_gpu);
249+
250+
ret = icc_set_bw(path_cpu, 1000, 1000);
251+
KUNIT_EXPECT_EQ(test, ret, 0);
252+
KUNIT_EXPECT_EQ(test, bus->avg_bw, 1000);
253+
254+
ret = icc_set_bw(path_gpu, 2000, 2000);
255+
KUNIT_EXPECT_EQ(test, ret, 0);
256+
257+
/* Bus aggregates: CPU(1000) + GPU(2000) */
258+
KUNIT_EXPECT_EQ(test, bus->avg_bw, 3000);
259+
/* Peak aggregates: max(CPU, GPU) */
260+
KUNIT_EXPECT_EQ(test, bus->peak_bw, 2000);
261+
262+
icc_test_destroy_path(test, path_cpu);
263+
icc_test_destroy_path(test, path_gpu);
264+
}
265+
266+
static void icc_test_bulk_ops(struct kunit *test)
267+
{
268+
struct icc_test_priv *priv = test->priv;
269+
struct icc_node *nodes_cpu[3], *nodes_gpu[2];
270+
struct icc_bulk_data bulk[2];
271+
int ret;
272+
273+
nodes_cpu[0] = get_node(priv, NODE_CPU);
274+
nodes_cpu[1] = get_node(priv, NODE_BUS);
275+
nodes_cpu[2] = get_node(priv, NODE_DDR);
276+
277+
nodes_gpu[0] = get_node(priv, NODE_GPU);
278+
nodes_gpu[1] = get_node(priv, NODE_BUS);
279+
280+
bulk[0].path = icc_test_create_path(test, nodes_cpu, 3);
281+
bulk[0].avg_bw = 500;
282+
bulk[0].peak_bw = 500;
283+
284+
bulk[1].path = icc_test_create_path(test, nodes_gpu, 2);
285+
bulk[1].avg_bw = 600;
286+
bulk[1].peak_bw = 600;
287+
288+
ret = icc_bulk_set_bw(2, bulk);
289+
KUNIT_EXPECT_EQ(test, ret, 0);
290+
/* Paths disabled, bandwidth should be 0 */
291+
KUNIT_EXPECT_EQ(test, get_node(priv, NODE_BUS)->avg_bw, 0);
292+
293+
ret = icc_bulk_enable(2, bulk);
294+
KUNIT_EXPECT_EQ(test, ret, 0);
295+
/* Paths enabled, aggregation applies */
296+
KUNIT_EXPECT_EQ(test, get_node(priv, NODE_BUS)->avg_bw, 1100);
297+
298+
icc_bulk_disable(2, bulk);
299+
KUNIT_EXPECT_EQ(test, get_node(priv, NODE_BUS)->avg_bw, 0);
300+
301+
icc_test_destroy_path(test, bulk[0].path);
302+
icc_test_destroy_path(test, bulk[1].path);
303+
}
304+
305+
static struct kunit_case icc_test_cases[] = {
306+
KUNIT_CASE(icc_test_topology_integrity),
307+
KUNIT_CASE(icc_test_set_bw),
308+
KUNIT_CASE(icc_test_aggregation),
309+
KUNIT_CASE(icc_test_bulk_ops),
310+
{}
311+
};
312+
313+
static struct kunit_suite icc_test_suite = {
314+
.name = "interconnect",
315+
.init = icc_test_init,
316+
.exit = icc_test_exit,
317+
.test_cases = icc_test_cases,
318+
};
319+
320+
kunit_test_suite(icc_test_suite);
321+
322+
MODULE_AUTHOR("Kuan-Wei Chiu <visitorckw@gmail.com>");
323+
MODULE_DESCRIPTION("KUnit tests for the Interconnect framework");
324+
MODULE_LICENSE("GPL");

drivers/interconnect/mediatek/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,10 @@ config INTERCONNECT_MTK_MT8195
2727
help
2828
This is a driver for the MediaTek bus interconnect on MT8195-based
2929
platforms.
30+
31+
config INTERCONNECT_MTK_MT8196
32+
tristate "MediaTek MT8196 interconnect driver"
33+
depends on INTERCONNECT_MTK_DVFSRC_EMI
34+
help
35+
This is a driver for the MediaTek bus interconnect on MT8196-based
36+
platforms.

drivers/interconnect/mediatek/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
obj-$(CONFIG_INTERCONNECT_MTK_DVFSRC_EMI) += icc-emi.o
44
obj-$(CONFIG_INTERCONNECT_MTK_MT8183) += mt8183.o
55
obj-$(CONFIG_INTERCONNECT_MTK_MT8195) += mt8195.o
6+
obj-$(CONFIG_INTERCONNECT_MTK_MT8195) += mt8196.o

0 commit comments

Comments
 (0)