162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * KUnit tests
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020, Intel Corporation
662306a36Sopenharmony_ci * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <kunit/test.h>
1062306a36Sopenharmony_ci#include <linux/idr.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "tb.h"
1362306a36Sopenharmony_ci#include "tunnel.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int __ida_init(struct kunit_resource *res, void *context)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	struct ida *ida = context;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	ida_init(ida);
2062306a36Sopenharmony_ci	res->data = ida;
2162306a36Sopenharmony_ci	return 0;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void __ida_destroy(struct kunit_resource *res)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct ida *ida = res->data;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	ida_destroy(ida);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void kunit_ida_init(struct kunit *test, struct ida *ida)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	kunit_alloc_resource(test, __ida_init, __ida_destroy, GFP_KERNEL, ida);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic struct tb_switch *alloc_switch(struct kunit *test, u64 route,
3762306a36Sopenharmony_ci				      u8 upstream_port, u8 max_port_number)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct tb_switch *sw;
4062306a36Sopenharmony_ci	size_t size;
4162306a36Sopenharmony_ci	int i;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	sw = kunit_kzalloc(test, sizeof(*sw), GFP_KERNEL);
4462306a36Sopenharmony_ci	if (!sw)
4562306a36Sopenharmony_ci		return NULL;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	sw->config.upstream_port_number = upstream_port;
4862306a36Sopenharmony_ci	sw->config.depth = tb_route_length(route);
4962306a36Sopenharmony_ci	sw->config.route_hi = upper_32_bits(route);
5062306a36Sopenharmony_ci	sw->config.route_lo = lower_32_bits(route);
5162306a36Sopenharmony_ci	sw->config.enabled = 0;
5262306a36Sopenharmony_ci	sw->config.max_port_number = max_port_number;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	size = (sw->config.max_port_number + 1) * sizeof(*sw->ports);
5562306a36Sopenharmony_ci	sw->ports = kunit_kzalloc(test, size, GFP_KERNEL);
5662306a36Sopenharmony_ci	if (!sw->ports)
5762306a36Sopenharmony_ci		return NULL;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	for (i = 0; i <= sw->config.max_port_number; i++) {
6062306a36Sopenharmony_ci		sw->ports[i].sw = sw;
6162306a36Sopenharmony_ci		sw->ports[i].port = i;
6262306a36Sopenharmony_ci		sw->ports[i].config.port_number = i;
6362306a36Sopenharmony_ci		if (i) {
6462306a36Sopenharmony_ci			kunit_ida_init(test, &sw->ports[i].in_hopids);
6562306a36Sopenharmony_ci			kunit_ida_init(test, &sw->ports[i].out_hopids);
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return sw;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic struct tb_switch *alloc_host(struct kunit *test)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct tb_switch *sw;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	sw = alloc_switch(test, 0, 7, 13);
7762306a36Sopenharmony_ci	if (!sw)
7862306a36Sopenharmony_ci		return NULL;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	sw->config.vendor_id = 0x8086;
8162306a36Sopenharmony_ci	sw->config.device_id = 0x9a1b;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	sw->ports[0].config.type = TB_TYPE_PORT;
8462306a36Sopenharmony_ci	sw->ports[0].config.max_in_hop_id = 7;
8562306a36Sopenharmony_ci	sw->ports[0].config.max_out_hop_id = 7;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	sw->ports[1].config.type = TB_TYPE_PORT;
8862306a36Sopenharmony_ci	sw->ports[1].config.max_in_hop_id = 19;
8962306a36Sopenharmony_ci	sw->ports[1].config.max_out_hop_id = 19;
9062306a36Sopenharmony_ci	sw->ports[1].total_credits = 60;
9162306a36Sopenharmony_ci	sw->ports[1].ctl_credits = 2;
9262306a36Sopenharmony_ci	sw->ports[1].dual_link_port = &sw->ports[2];
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	sw->ports[2].config.type = TB_TYPE_PORT;
9562306a36Sopenharmony_ci	sw->ports[2].config.max_in_hop_id = 19;
9662306a36Sopenharmony_ci	sw->ports[2].config.max_out_hop_id = 19;
9762306a36Sopenharmony_ci	sw->ports[2].total_credits = 60;
9862306a36Sopenharmony_ci	sw->ports[2].ctl_credits = 2;
9962306a36Sopenharmony_ci	sw->ports[2].dual_link_port = &sw->ports[1];
10062306a36Sopenharmony_ci	sw->ports[2].link_nr = 1;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	sw->ports[3].config.type = TB_TYPE_PORT;
10362306a36Sopenharmony_ci	sw->ports[3].config.max_in_hop_id = 19;
10462306a36Sopenharmony_ci	sw->ports[3].config.max_out_hop_id = 19;
10562306a36Sopenharmony_ci	sw->ports[3].total_credits = 60;
10662306a36Sopenharmony_ci	sw->ports[3].ctl_credits = 2;
10762306a36Sopenharmony_ci	sw->ports[3].dual_link_port = &sw->ports[4];
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	sw->ports[4].config.type = TB_TYPE_PORT;
11062306a36Sopenharmony_ci	sw->ports[4].config.max_in_hop_id = 19;
11162306a36Sopenharmony_ci	sw->ports[4].config.max_out_hop_id = 19;
11262306a36Sopenharmony_ci	sw->ports[4].total_credits = 60;
11362306a36Sopenharmony_ci	sw->ports[4].ctl_credits = 2;
11462306a36Sopenharmony_ci	sw->ports[4].dual_link_port = &sw->ports[3];
11562306a36Sopenharmony_ci	sw->ports[4].link_nr = 1;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	sw->ports[5].config.type = TB_TYPE_DP_HDMI_IN;
11862306a36Sopenharmony_ci	sw->ports[5].config.max_in_hop_id = 9;
11962306a36Sopenharmony_ci	sw->ports[5].config.max_out_hop_id = 9;
12062306a36Sopenharmony_ci	sw->ports[5].cap_adap = -1;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	sw->ports[6].config.type = TB_TYPE_DP_HDMI_IN;
12362306a36Sopenharmony_ci	sw->ports[6].config.max_in_hop_id = 9;
12462306a36Sopenharmony_ci	sw->ports[6].config.max_out_hop_id = 9;
12562306a36Sopenharmony_ci	sw->ports[6].cap_adap = -1;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	sw->ports[7].config.type = TB_TYPE_NHI;
12862306a36Sopenharmony_ci	sw->ports[7].config.max_in_hop_id = 11;
12962306a36Sopenharmony_ci	sw->ports[7].config.max_out_hop_id = 11;
13062306a36Sopenharmony_ci	sw->ports[7].config.nfc_credits = 0x41800000;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	sw->ports[8].config.type = TB_TYPE_PCIE_DOWN;
13362306a36Sopenharmony_ci	sw->ports[8].config.max_in_hop_id = 8;
13462306a36Sopenharmony_ci	sw->ports[8].config.max_out_hop_id = 8;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	sw->ports[9].config.type = TB_TYPE_PCIE_DOWN;
13762306a36Sopenharmony_ci	sw->ports[9].config.max_in_hop_id = 8;
13862306a36Sopenharmony_ci	sw->ports[9].config.max_out_hop_id = 8;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	sw->ports[10].disabled = true;
14162306a36Sopenharmony_ci	sw->ports[11].disabled = true;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	sw->ports[12].config.type = TB_TYPE_USB3_DOWN;
14462306a36Sopenharmony_ci	sw->ports[12].config.max_in_hop_id = 8;
14562306a36Sopenharmony_ci	sw->ports[12].config.max_out_hop_id = 8;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	sw->ports[13].config.type = TB_TYPE_USB3_DOWN;
14862306a36Sopenharmony_ci	sw->ports[13].config.max_in_hop_id = 8;
14962306a36Sopenharmony_ci	sw->ports[13].config.max_out_hop_id = 8;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return sw;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic struct tb_switch *alloc_host_usb4(struct kunit *test)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct tb_switch *sw;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	sw = alloc_host(test);
15962306a36Sopenharmony_ci	if (!sw)
16062306a36Sopenharmony_ci		return NULL;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	sw->generation = 4;
16362306a36Sopenharmony_ci	sw->credit_allocation = true;
16462306a36Sopenharmony_ci	sw->max_usb3_credits = 32;
16562306a36Sopenharmony_ci	sw->min_dp_aux_credits = 1;
16662306a36Sopenharmony_ci	sw->min_dp_main_credits = 0;
16762306a36Sopenharmony_ci	sw->max_pcie_credits = 64;
16862306a36Sopenharmony_ci	sw->max_dma_credits = 14;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return sw;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic struct tb_switch *alloc_host_br(struct kunit *test)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct tb_switch *sw;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	sw = alloc_host_usb4(test);
17862306a36Sopenharmony_ci	if (!sw)
17962306a36Sopenharmony_ci		return NULL;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	sw->ports[10].config.type = TB_TYPE_DP_HDMI_IN;
18262306a36Sopenharmony_ci	sw->ports[10].config.max_in_hop_id = 9;
18362306a36Sopenharmony_ci	sw->ports[10].config.max_out_hop_id = 9;
18462306a36Sopenharmony_ci	sw->ports[10].cap_adap = -1;
18562306a36Sopenharmony_ci	sw->ports[10].disabled = false;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return sw;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct tb_switch *alloc_dev_default(struct kunit *test,
19162306a36Sopenharmony_ci					   struct tb_switch *parent,
19262306a36Sopenharmony_ci					   u64 route, bool bonded)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct tb_port *port, *upstream_port;
19562306a36Sopenharmony_ci	struct tb_switch *sw;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	sw = alloc_switch(test, route, 1, 19);
19862306a36Sopenharmony_ci	if (!sw)
19962306a36Sopenharmony_ci		return NULL;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	sw->config.vendor_id = 0x8086;
20262306a36Sopenharmony_ci	sw->config.device_id = 0x15ef;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	sw->ports[0].config.type = TB_TYPE_PORT;
20562306a36Sopenharmony_ci	sw->ports[0].config.max_in_hop_id = 8;
20662306a36Sopenharmony_ci	sw->ports[0].config.max_out_hop_id = 8;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	sw->ports[1].config.type = TB_TYPE_PORT;
20962306a36Sopenharmony_ci	sw->ports[1].config.max_in_hop_id = 19;
21062306a36Sopenharmony_ci	sw->ports[1].config.max_out_hop_id = 19;
21162306a36Sopenharmony_ci	sw->ports[1].total_credits = 60;
21262306a36Sopenharmony_ci	sw->ports[1].ctl_credits = 2;
21362306a36Sopenharmony_ci	sw->ports[1].dual_link_port = &sw->ports[2];
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	sw->ports[2].config.type = TB_TYPE_PORT;
21662306a36Sopenharmony_ci	sw->ports[2].config.max_in_hop_id = 19;
21762306a36Sopenharmony_ci	sw->ports[2].config.max_out_hop_id = 19;
21862306a36Sopenharmony_ci	sw->ports[2].total_credits = 60;
21962306a36Sopenharmony_ci	sw->ports[2].ctl_credits = 2;
22062306a36Sopenharmony_ci	sw->ports[2].dual_link_port = &sw->ports[1];
22162306a36Sopenharmony_ci	sw->ports[2].link_nr = 1;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	sw->ports[3].config.type = TB_TYPE_PORT;
22462306a36Sopenharmony_ci	sw->ports[3].config.max_in_hop_id = 19;
22562306a36Sopenharmony_ci	sw->ports[3].config.max_out_hop_id = 19;
22662306a36Sopenharmony_ci	sw->ports[3].total_credits = 60;
22762306a36Sopenharmony_ci	sw->ports[3].ctl_credits = 2;
22862306a36Sopenharmony_ci	sw->ports[3].dual_link_port = &sw->ports[4];
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	sw->ports[4].config.type = TB_TYPE_PORT;
23162306a36Sopenharmony_ci	sw->ports[4].config.max_in_hop_id = 19;
23262306a36Sopenharmony_ci	sw->ports[4].config.max_out_hop_id = 19;
23362306a36Sopenharmony_ci	sw->ports[4].total_credits = 60;
23462306a36Sopenharmony_ci	sw->ports[4].ctl_credits = 2;
23562306a36Sopenharmony_ci	sw->ports[4].dual_link_port = &sw->ports[3];
23662306a36Sopenharmony_ci	sw->ports[4].link_nr = 1;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	sw->ports[5].config.type = TB_TYPE_PORT;
23962306a36Sopenharmony_ci	sw->ports[5].config.max_in_hop_id = 19;
24062306a36Sopenharmony_ci	sw->ports[5].config.max_out_hop_id = 19;
24162306a36Sopenharmony_ci	sw->ports[5].total_credits = 60;
24262306a36Sopenharmony_ci	sw->ports[5].ctl_credits = 2;
24362306a36Sopenharmony_ci	sw->ports[5].dual_link_port = &sw->ports[6];
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	sw->ports[6].config.type = TB_TYPE_PORT;
24662306a36Sopenharmony_ci	sw->ports[6].config.max_in_hop_id = 19;
24762306a36Sopenharmony_ci	sw->ports[6].config.max_out_hop_id = 19;
24862306a36Sopenharmony_ci	sw->ports[6].total_credits = 60;
24962306a36Sopenharmony_ci	sw->ports[6].ctl_credits = 2;
25062306a36Sopenharmony_ci	sw->ports[6].dual_link_port = &sw->ports[5];
25162306a36Sopenharmony_ci	sw->ports[6].link_nr = 1;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	sw->ports[7].config.type = TB_TYPE_PORT;
25462306a36Sopenharmony_ci	sw->ports[7].config.max_in_hop_id = 19;
25562306a36Sopenharmony_ci	sw->ports[7].config.max_out_hop_id = 19;
25662306a36Sopenharmony_ci	sw->ports[7].total_credits = 60;
25762306a36Sopenharmony_ci	sw->ports[7].ctl_credits = 2;
25862306a36Sopenharmony_ci	sw->ports[7].dual_link_port = &sw->ports[8];
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	sw->ports[8].config.type = TB_TYPE_PORT;
26162306a36Sopenharmony_ci	sw->ports[8].config.max_in_hop_id = 19;
26262306a36Sopenharmony_ci	sw->ports[8].config.max_out_hop_id = 19;
26362306a36Sopenharmony_ci	sw->ports[8].total_credits = 60;
26462306a36Sopenharmony_ci	sw->ports[8].ctl_credits = 2;
26562306a36Sopenharmony_ci	sw->ports[8].dual_link_port = &sw->ports[7];
26662306a36Sopenharmony_ci	sw->ports[8].link_nr = 1;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	sw->ports[9].config.type = TB_TYPE_PCIE_UP;
26962306a36Sopenharmony_ci	sw->ports[9].config.max_in_hop_id = 8;
27062306a36Sopenharmony_ci	sw->ports[9].config.max_out_hop_id = 8;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	sw->ports[10].config.type = TB_TYPE_PCIE_DOWN;
27362306a36Sopenharmony_ci	sw->ports[10].config.max_in_hop_id = 8;
27462306a36Sopenharmony_ci	sw->ports[10].config.max_out_hop_id = 8;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	sw->ports[11].config.type = TB_TYPE_PCIE_DOWN;
27762306a36Sopenharmony_ci	sw->ports[11].config.max_in_hop_id = 8;
27862306a36Sopenharmony_ci	sw->ports[11].config.max_out_hop_id = 8;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	sw->ports[12].config.type = TB_TYPE_PCIE_DOWN;
28162306a36Sopenharmony_ci	sw->ports[12].config.max_in_hop_id = 8;
28262306a36Sopenharmony_ci	sw->ports[12].config.max_out_hop_id = 8;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	sw->ports[13].config.type = TB_TYPE_DP_HDMI_OUT;
28562306a36Sopenharmony_ci	sw->ports[13].config.max_in_hop_id = 9;
28662306a36Sopenharmony_ci	sw->ports[13].config.max_out_hop_id = 9;
28762306a36Sopenharmony_ci	sw->ports[13].cap_adap = -1;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	sw->ports[14].config.type = TB_TYPE_DP_HDMI_OUT;
29062306a36Sopenharmony_ci	sw->ports[14].config.max_in_hop_id = 9;
29162306a36Sopenharmony_ci	sw->ports[14].config.max_out_hop_id = 9;
29262306a36Sopenharmony_ci	sw->ports[14].cap_adap = -1;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	sw->ports[15].disabled = true;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	sw->ports[16].config.type = TB_TYPE_USB3_UP;
29762306a36Sopenharmony_ci	sw->ports[16].config.max_in_hop_id = 8;
29862306a36Sopenharmony_ci	sw->ports[16].config.max_out_hop_id = 8;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	sw->ports[17].config.type = TB_TYPE_USB3_DOWN;
30162306a36Sopenharmony_ci	sw->ports[17].config.max_in_hop_id = 8;
30262306a36Sopenharmony_ci	sw->ports[17].config.max_out_hop_id = 8;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	sw->ports[18].config.type = TB_TYPE_USB3_DOWN;
30562306a36Sopenharmony_ci	sw->ports[18].config.max_in_hop_id = 8;
30662306a36Sopenharmony_ci	sw->ports[18].config.max_out_hop_id = 8;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	sw->ports[19].config.type = TB_TYPE_USB3_DOWN;
30962306a36Sopenharmony_ci	sw->ports[19].config.max_in_hop_id = 8;
31062306a36Sopenharmony_ci	sw->ports[19].config.max_out_hop_id = 8;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (!parent)
31362306a36Sopenharmony_ci		return sw;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Link them */
31662306a36Sopenharmony_ci	upstream_port = tb_upstream_port(sw);
31762306a36Sopenharmony_ci	port = tb_port_at(route, parent);
31862306a36Sopenharmony_ci	port->remote = upstream_port;
31962306a36Sopenharmony_ci	upstream_port->remote = port;
32062306a36Sopenharmony_ci	if (port->dual_link_port && upstream_port->dual_link_port) {
32162306a36Sopenharmony_ci		port->dual_link_port->remote = upstream_port->dual_link_port;
32262306a36Sopenharmony_ci		upstream_port->dual_link_port->remote = port->dual_link_port;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		if (bonded) {
32562306a36Sopenharmony_ci			/* Bonding is used */
32662306a36Sopenharmony_ci			port->bonded = true;
32762306a36Sopenharmony_ci			port->total_credits *= 2;
32862306a36Sopenharmony_ci			port->dual_link_port->bonded = true;
32962306a36Sopenharmony_ci			port->dual_link_port->total_credits = 0;
33062306a36Sopenharmony_ci			upstream_port->bonded = true;
33162306a36Sopenharmony_ci			upstream_port->total_credits *= 2;
33262306a36Sopenharmony_ci			upstream_port->dual_link_port->bonded = true;
33362306a36Sopenharmony_ci			upstream_port->dual_link_port->total_credits = 0;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return sw;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic struct tb_switch *alloc_dev_with_dpin(struct kunit *test,
34162306a36Sopenharmony_ci					     struct tb_switch *parent,
34262306a36Sopenharmony_ci					     u64 route, bool bonded)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct tb_switch *sw;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	sw = alloc_dev_default(test, parent, route, bonded);
34762306a36Sopenharmony_ci	if (!sw)
34862306a36Sopenharmony_ci		return NULL;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	sw->ports[13].config.type = TB_TYPE_DP_HDMI_IN;
35162306a36Sopenharmony_ci	sw->ports[13].config.max_in_hop_id = 9;
35262306a36Sopenharmony_ci	sw->ports[13].config.max_out_hop_id = 9;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	sw->ports[14].config.type = TB_TYPE_DP_HDMI_IN;
35562306a36Sopenharmony_ci	sw->ports[14].config.max_in_hop_id = 9;
35662306a36Sopenharmony_ci	sw->ports[14].config.max_out_hop_id = 9;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return sw;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic struct tb_switch *alloc_dev_without_dp(struct kunit *test,
36262306a36Sopenharmony_ci					      struct tb_switch *parent,
36362306a36Sopenharmony_ci					      u64 route, bool bonded)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct tb_switch *sw;
36662306a36Sopenharmony_ci	int i;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	sw = alloc_dev_default(test, parent, route, bonded);
36962306a36Sopenharmony_ci	if (!sw)
37062306a36Sopenharmony_ci		return NULL;
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * Device with:
37362306a36Sopenharmony_ci	 * 2x USB4 Adapters (adapters 1,2 and 3,4),
37462306a36Sopenharmony_ci	 * 1x PCIe Upstream (adapter 9),
37562306a36Sopenharmony_ci	 * 1x PCIe Downstream (adapter 10),
37662306a36Sopenharmony_ci	 * 1x USB3 Upstream (adapter 16),
37762306a36Sopenharmony_ci	 * 1x USB3 Downstream (adapter 17)
37862306a36Sopenharmony_ci	 */
37962306a36Sopenharmony_ci	for (i = 5; i <= 8; i++)
38062306a36Sopenharmony_ci		sw->ports[i].disabled = true;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	for (i = 11; i <= 14; i++)
38362306a36Sopenharmony_ci		sw->ports[i].disabled = true;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	sw->ports[13].cap_adap = 0;
38662306a36Sopenharmony_ci	sw->ports[14].cap_adap = 0;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	for (i = 18; i <= 19; i++)
38962306a36Sopenharmony_ci		sw->ports[i].disabled = true;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	sw->generation = 4;
39262306a36Sopenharmony_ci	sw->credit_allocation = true;
39362306a36Sopenharmony_ci	sw->max_usb3_credits = 109;
39462306a36Sopenharmony_ci	sw->min_dp_aux_credits = 0;
39562306a36Sopenharmony_ci	sw->min_dp_main_credits = 0;
39662306a36Sopenharmony_ci	sw->max_pcie_credits = 30;
39762306a36Sopenharmony_ci	sw->max_dma_credits = 1;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return sw;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic struct tb_switch *alloc_dev_usb4(struct kunit *test,
40362306a36Sopenharmony_ci					struct tb_switch *parent,
40462306a36Sopenharmony_ci					u64 route, bool bonded)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct tb_switch *sw;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	sw = alloc_dev_default(test, parent, route, bonded);
40962306a36Sopenharmony_ci	if (!sw)
41062306a36Sopenharmony_ci		return NULL;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	sw->generation = 4;
41362306a36Sopenharmony_ci	sw->credit_allocation = true;
41462306a36Sopenharmony_ci	sw->max_usb3_credits = 14;
41562306a36Sopenharmony_ci	sw->min_dp_aux_credits = 1;
41662306a36Sopenharmony_ci	sw->min_dp_main_credits = 18;
41762306a36Sopenharmony_ci	sw->max_pcie_credits = 32;
41862306a36Sopenharmony_ci	sw->max_dma_credits = 14;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return sw;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void tb_test_path_basic(struct kunit *test)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
42662306a36Sopenharmony_ci	struct tb_switch *host;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	host = alloc_host(test);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	src_port = &host->ports[5];
43162306a36Sopenharmony_ci	dst_port = src_port;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	p = tb_next_port_on_path(src_port, dst_port, NULL);
43462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p, dst_port);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	p = tb_next_port_on_path(src_port, dst_port, p);
43762306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !p);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void tb_test_path_not_connected_walk(struct kunit *test)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
44362306a36Sopenharmony_ci	struct tb_switch *host, *dev;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	host = alloc_host(test);
44662306a36Sopenharmony_ci	/* No connection between host and dev */
44762306a36Sopenharmony_ci	dev = alloc_dev_default(test, NULL, 3, true);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	src_port = &host->ports[12];
45062306a36Sopenharmony_ci	dst_port = &dev->ports[16];
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	p = tb_next_port_on_path(src_port, dst_port, NULL);
45362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p, src_port);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	p = tb_next_port_on_path(src_port, dst_port, p);
45662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p, &host->ports[3]);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	p = tb_next_port_on_path(src_port, dst_port, p);
45962306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !p);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* Other direction */
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	p = tb_next_port_on_path(dst_port, src_port, NULL);
46462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p, dst_port);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	p = tb_next_port_on_path(dst_port, src_port, p);
46762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p, &dev->ports[1]);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	p = tb_next_port_on_path(dst_port, src_port, p);
47062306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !p);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistruct port_expectation {
47462306a36Sopenharmony_ci	u64 route;
47562306a36Sopenharmony_ci	u8 port;
47662306a36Sopenharmony_ci	enum tb_port_type type;
47762306a36Sopenharmony_ci};
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic void tb_test_path_single_hop_walk(struct kunit *test)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * Walks from Host PCIe downstream port to Device #1 PCIe
48362306a36Sopenharmony_ci	 * upstream port.
48462306a36Sopenharmony_ci	 *
48562306a36Sopenharmony_ci	 *   [Host]
48662306a36Sopenharmony_ci	 *   1 |
48762306a36Sopenharmony_ci	 *   1 |
48862306a36Sopenharmony_ci	 *  [Device]
48962306a36Sopenharmony_ci	 */
49062306a36Sopenharmony_ci	static const struct port_expectation test_data[] = {
49162306a36Sopenharmony_ci		{ .route = 0x0, .port = 8, .type = TB_TYPE_PCIE_DOWN },
49262306a36Sopenharmony_ci		{ .route = 0x0, .port = 1, .type = TB_TYPE_PORT },
49362306a36Sopenharmony_ci		{ .route = 0x1, .port = 1, .type = TB_TYPE_PORT },
49462306a36Sopenharmony_ci		{ .route = 0x1, .port = 9, .type = TB_TYPE_PCIE_UP },
49562306a36Sopenharmony_ci	};
49662306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
49762306a36Sopenharmony_ci	struct tb_switch *host, *dev;
49862306a36Sopenharmony_ci	int i;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	host = alloc_host(test);
50162306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 1, true);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	src_port = &host->ports[8];
50462306a36Sopenharmony_ci	dst_port = &dev->ports[9];
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Walk both directions */
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	i = 0;
50962306a36Sopenharmony_ci	tb_for_each_port_on_path(src_port, dst_port, p) {
51062306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
51162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
51262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
51362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
51462306a36Sopenharmony_ci				test_data[i].type);
51562306a36Sopenharmony_ci		i++;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	i = ARRAY_SIZE(test_data) - 1;
52162306a36Sopenharmony_ci	tb_for_each_port_on_path(dst_port, src_port, p) {
52262306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
52362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
52462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
52562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
52662306a36Sopenharmony_ci				test_data[i].type);
52762306a36Sopenharmony_ci		i--;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, -1);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void tb_test_path_daisy_chain_walk(struct kunit *test)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	/*
53662306a36Sopenharmony_ci	 * Walks from Host DP IN to Device #2 DP OUT.
53762306a36Sopenharmony_ci	 *
53862306a36Sopenharmony_ci	 *           [Host]
53962306a36Sopenharmony_ci	 *            1 |
54062306a36Sopenharmony_ci	 *            1 |
54162306a36Sopenharmony_ci	 *         [Device #1]
54262306a36Sopenharmony_ci	 *       3 /
54362306a36Sopenharmony_ci	 *      1 /
54462306a36Sopenharmony_ci	 * [Device #2]
54562306a36Sopenharmony_ci	 */
54662306a36Sopenharmony_ci	static const struct port_expectation test_data[] = {
54762306a36Sopenharmony_ci		{ .route = 0x0, .port = 5, .type = TB_TYPE_DP_HDMI_IN },
54862306a36Sopenharmony_ci		{ .route = 0x0, .port = 1, .type = TB_TYPE_PORT },
54962306a36Sopenharmony_ci		{ .route = 0x1, .port = 1, .type = TB_TYPE_PORT },
55062306a36Sopenharmony_ci		{ .route = 0x1, .port = 3, .type = TB_TYPE_PORT },
55162306a36Sopenharmony_ci		{ .route = 0x301, .port = 1, .type = TB_TYPE_PORT },
55262306a36Sopenharmony_ci		{ .route = 0x301, .port = 13, .type = TB_TYPE_DP_HDMI_OUT },
55362306a36Sopenharmony_ci	};
55462306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
55562306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2;
55662306a36Sopenharmony_ci	int i;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	host = alloc_host(test);
55962306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
56062306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x301, true);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	src_port = &host->ports[5];
56362306a36Sopenharmony_ci	dst_port = &dev2->ports[13];
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Walk both directions */
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	i = 0;
56862306a36Sopenharmony_ci	tb_for_each_port_on_path(src_port, dst_port, p) {
56962306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
57062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
57162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
57262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
57362306a36Sopenharmony_ci				test_data[i].type);
57462306a36Sopenharmony_ci		i++;
57562306a36Sopenharmony_ci	}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	i = ARRAY_SIZE(test_data) - 1;
58062306a36Sopenharmony_ci	tb_for_each_port_on_path(dst_port, src_port, p) {
58162306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
58262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
58362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
58462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
58562306a36Sopenharmony_ci				test_data[i].type);
58662306a36Sopenharmony_ci		i--;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, -1);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic void tb_test_path_simple_tree_walk(struct kunit *test)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * Walks from Host DP IN to Device #3 DP OUT.
59662306a36Sopenharmony_ci	 *
59762306a36Sopenharmony_ci	 *           [Host]
59862306a36Sopenharmony_ci	 *            1 |
59962306a36Sopenharmony_ci	 *            1 |
60062306a36Sopenharmony_ci	 *         [Device #1]
60162306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
60262306a36Sopenharmony_ci	 *      1 /    |     \ 1
60362306a36Sopenharmony_ci	 * [Device #2] |    [Device #4]
60462306a36Sopenharmony_ci	 *             | 1
60562306a36Sopenharmony_ci	 *         [Device #3]
60662306a36Sopenharmony_ci	 */
60762306a36Sopenharmony_ci	static const struct port_expectation test_data[] = {
60862306a36Sopenharmony_ci		{ .route = 0x0, .port = 5, .type = TB_TYPE_DP_HDMI_IN },
60962306a36Sopenharmony_ci		{ .route = 0x0, .port = 1, .type = TB_TYPE_PORT },
61062306a36Sopenharmony_ci		{ .route = 0x1, .port = 1, .type = TB_TYPE_PORT },
61162306a36Sopenharmony_ci		{ .route = 0x1, .port = 5, .type = TB_TYPE_PORT },
61262306a36Sopenharmony_ci		{ .route = 0x501, .port = 1, .type = TB_TYPE_PORT },
61362306a36Sopenharmony_ci		{ .route = 0x501, .port = 13, .type = TB_TYPE_DP_HDMI_OUT },
61462306a36Sopenharmony_ci	};
61562306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
61662306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev3;
61762306a36Sopenharmony_ci	int i;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	host = alloc_host(test);
62062306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
62162306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x301, true);
62262306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev1, 0x501, true);
62362306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x701, true);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	src_port = &host->ports[5];
62662306a36Sopenharmony_ci	dst_port = &dev3->ports[13];
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Walk both directions */
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	i = 0;
63162306a36Sopenharmony_ci	tb_for_each_port_on_path(src_port, dst_port, p) {
63262306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
63362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
63462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
63562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
63662306a36Sopenharmony_ci				test_data[i].type);
63762306a36Sopenharmony_ci		i++;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	i = ARRAY_SIZE(test_data) - 1;
64362306a36Sopenharmony_ci	tb_for_each_port_on_path(dst_port, src_port, p) {
64462306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
64562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
64662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
64762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
64862306a36Sopenharmony_ci				test_data[i].type);
64962306a36Sopenharmony_ci		i--;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, -1);
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic void tb_test_path_complex_tree_walk(struct kunit *test)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	/*
65862306a36Sopenharmony_ci	 * Walks from Device #3 DP IN to Device #9 DP OUT.
65962306a36Sopenharmony_ci	 *
66062306a36Sopenharmony_ci	 *           [Host]
66162306a36Sopenharmony_ci	 *            1 |
66262306a36Sopenharmony_ci	 *            1 |
66362306a36Sopenharmony_ci	 *         [Device #1]
66462306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
66562306a36Sopenharmony_ci	 *      1 /    |     \ 1
66662306a36Sopenharmony_ci	 * [Device #2] |    [Device #5]
66762306a36Sopenharmony_ci	 *    5 |      | 1         \ 7
66862306a36Sopenharmony_ci	 *    1 |  [Device #4]      \ 1
66962306a36Sopenharmony_ci	 * [Device #3]             [Device #6]
67062306a36Sopenharmony_ci	 *                       3 /
67162306a36Sopenharmony_ci	 *                      1 /
67262306a36Sopenharmony_ci	 *                    [Device #7]
67362306a36Sopenharmony_ci	 *                  3 /      | 5
67462306a36Sopenharmony_ci	 *                 1 /       |
67562306a36Sopenharmony_ci	 *               [Device #8] | 1
67662306a36Sopenharmony_ci	 *                       [Device #9]
67762306a36Sopenharmony_ci	 */
67862306a36Sopenharmony_ci	static const struct port_expectation test_data[] = {
67962306a36Sopenharmony_ci		{ .route = 0x50301, .port = 13, .type = TB_TYPE_DP_HDMI_IN },
68062306a36Sopenharmony_ci		{ .route = 0x50301, .port = 1, .type = TB_TYPE_PORT },
68162306a36Sopenharmony_ci		{ .route = 0x301, .port = 5, .type = TB_TYPE_PORT },
68262306a36Sopenharmony_ci		{ .route = 0x301, .port = 1, .type = TB_TYPE_PORT },
68362306a36Sopenharmony_ci		{ .route = 0x1, .port = 3, .type = TB_TYPE_PORT },
68462306a36Sopenharmony_ci		{ .route = 0x1, .port = 7, .type = TB_TYPE_PORT },
68562306a36Sopenharmony_ci		{ .route = 0x701, .port = 1, .type = TB_TYPE_PORT },
68662306a36Sopenharmony_ci		{ .route = 0x701, .port = 7, .type = TB_TYPE_PORT },
68762306a36Sopenharmony_ci		{ .route = 0x70701, .port = 1, .type = TB_TYPE_PORT },
68862306a36Sopenharmony_ci		{ .route = 0x70701, .port = 3, .type = TB_TYPE_PORT },
68962306a36Sopenharmony_ci		{ .route = 0x3070701, .port = 1, .type = TB_TYPE_PORT },
69062306a36Sopenharmony_ci		{ .route = 0x3070701, .port = 5, .type = TB_TYPE_PORT },
69162306a36Sopenharmony_ci		{ .route = 0x503070701, .port = 1, .type = TB_TYPE_PORT },
69262306a36Sopenharmony_ci		{ .route = 0x503070701, .port = 14, .type = TB_TYPE_DP_HDMI_OUT },
69362306a36Sopenharmony_ci	};
69462306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev5, *dev6, *dev7, *dev9;
69562306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
69662306a36Sopenharmony_ci	int i;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	host = alloc_host(test);
69962306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
70062306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x301, true);
70162306a36Sopenharmony_ci	dev3 = alloc_dev_with_dpin(test, dev2, 0x50301, true);
70262306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x501, true);
70362306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev1, 0x701, true);
70462306a36Sopenharmony_ci	dev6 = alloc_dev_default(test, dev5, 0x70701, true);
70562306a36Sopenharmony_ci	dev7 = alloc_dev_default(test, dev6, 0x3070701, true);
70662306a36Sopenharmony_ci	alloc_dev_default(test, dev7, 0x303070701, true);
70762306a36Sopenharmony_ci	dev9 = alloc_dev_default(test, dev7, 0x503070701, true);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	src_port = &dev3->ports[13];
71062306a36Sopenharmony_ci	dst_port = &dev9->ports[14];
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/* Walk both directions */
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	i = 0;
71562306a36Sopenharmony_ci	tb_for_each_port_on_path(src_port, dst_port, p) {
71662306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
71762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
71862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
71962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
72062306a36Sopenharmony_ci				test_data[i].type);
72162306a36Sopenharmony_ci		i++;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	i = ARRAY_SIZE(test_data) - 1;
72762306a36Sopenharmony_ci	tb_for_each_port_on_path(dst_port, src_port, p) {
72862306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
72962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
73062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
73162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
73262306a36Sopenharmony_ci				test_data[i].type);
73362306a36Sopenharmony_ci		i--;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, -1);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic void tb_test_path_max_length_walk(struct kunit *test)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5, *dev6;
74262306a36Sopenharmony_ci	struct tb_switch *dev7, *dev8, *dev9, *dev10, *dev11, *dev12;
74362306a36Sopenharmony_ci	struct tb_port *src_port, *dst_port, *p;
74462306a36Sopenharmony_ci	int i;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/*
74762306a36Sopenharmony_ci	 * Walks from Device #6 DP IN to Device #12 DP OUT.
74862306a36Sopenharmony_ci	 *
74962306a36Sopenharmony_ci	 *          [Host]
75062306a36Sopenharmony_ci	 *         1 /  \ 3
75162306a36Sopenharmony_ci	 *        1 /    \ 1
75262306a36Sopenharmony_ci	 * [Device #1]   [Device #7]
75362306a36Sopenharmony_ci	 *     3 |           | 3
75462306a36Sopenharmony_ci	 *     1 |           | 1
75562306a36Sopenharmony_ci	 * [Device #2]   [Device #8]
75662306a36Sopenharmony_ci	 *     3 |           | 3
75762306a36Sopenharmony_ci	 *     1 |           | 1
75862306a36Sopenharmony_ci	 * [Device #3]   [Device #9]
75962306a36Sopenharmony_ci	 *     3 |           | 3
76062306a36Sopenharmony_ci	 *     1 |           | 1
76162306a36Sopenharmony_ci	 * [Device #4]   [Device #10]
76262306a36Sopenharmony_ci	 *     3 |           | 3
76362306a36Sopenharmony_ci	 *     1 |           | 1
76462306a36Sopenharmony_ci	 * [Device #5]   [Device #11]
76562306a36Sopenharmony_ci	 *     3 |           | 3
76662306a36Sopenharmony_ci	 *     1 |           | 1
76762306a36Sopenharmony_ci	 * [Device #6]   [Device #12]
76862306a36Sopenharmony_ci	 */
76962306a36Sopenharmony_ci	static const struct port_expectation test_data[] = {
77062306a36Sopenharmony_ci		{ .route = 0x30303030301, .port = 13, .type = TB_TYPE_DP_HDMI_IN },
77162306a36Sopenharmony_ci		{ .route = 0x30303030301, .port = 1, .type = TB_TYPE_PORT },
77262306a36Sopenharmony_ci		{ .route = 0x303030301, .port = 3, .type = TB_TYPE_PORT },
77362306a36Sopenharmony_ci		{ .route = 0x303030301, .port = 1, .type = TB_TYPE_PORT },
77462306a36Sopenharmony_ci		{ .route = 0x3030301, .port = 3, .type = TB_TYPE_PORT },
77562306a36Sopenharmony_ci		{ .route = 0x3030301, .port = 1, .type = TB_TYPE_PORT },
77662306a36Sopenharmony_ci		{ .route = 0x30301, .port = 3, .type = TB_TYPE_PORT },
77762306a36Sopenharmony_ci		{ .route = 0x30301, .port = 1, .type = TB_TYPE_PORT },
77862306a36Sopenharmony_ci		{ .route = 0x301, .port = 3, .type = TB_TYPE_PORT },
77962306a36Sopenharmony_ci		{ .route = 0x301, .port = 1, .type = TB_TYPE_PORT },
78062306a36Sopenharmony_ci		{ .route = 0x1, .port = 3, .type = TB_TYPE_PORT },
78162306a36Sopenharmony_ci		{ .route = 0x1, .port = 1, .type = TB_TYPE_PORT },
78262306a36Sopenharmony_ci		{ .route = 0x0, .port = 1, .type = TB_TYPE_PORT },
78362306a36Sopenharmony_ci		{ .route = 0x0, .port = 3, .type = TB_TYPE_PORT },
78462306a36Sopenharmony_ci		{ .route = 0x3, .port = 1, .type = TB_TYPE_PORT },
78562306a36Sopenharmony_ci		{ .route = 0x3, .port = 3, .type = TB_TYPE_PORT },
78662306a36Sopenharmony_ci		{ .route = 0x303, .port = 1, .type = TB_TYPE_PORT },
78762306a36Sopenharmony_ci		{ .route = 0x303, .port = 3, .type = TB_TYPE_PORT },
78862306a36Sopenharmony_ci		{ .route = 0x30303, .port = 1, .type = TB_TYPE_PORT },
78962306a36Sopenharmony_ci		{ .route = 0x30303, .port = 3, .type = TB_TYPE_PORT },
79062306a36Sopenharmony_ci		{ .route = 0x3030303, .port = 1, .type = TB_TYPE_PORT },
79162306a36Sopenharmony_ci		{ .route = 0x3030303, .port = 3, .type = TB_TYPE_PORT },
79262306a36Sopenharmony_ci		{ .route = 0x303030303, .port = 1, .type = TB_TYPE_PORT },
79362306a36Sopenharmony_ci		{ .route = 0x303030303, .port = 3, .type = TB_TYPE_PORT },
79462306a36Sopenharmony_ci		{ .route = 0x30303030303, .port = 1, .type = TB_TYPE_PORT },
79562306a36Sopenharmony_ci		{ .route = 0x30303030303, .port = 13, .type = TB_TYPE_DP_HDMI_OUT },
79662306a36Sopenharmony_ci	};
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	host = alloc_host(test);
79962306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
80062306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x301, true);
80162306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev2, 0x30301, true);
80262306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev3, 0x3030301, true);
80362306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev4, 0x303030301, true);
80462306a36Sopenharmony_ci	dev6 = alloc_dev_with_dpin(test, dev5, 0x30303030301, true);
80562306a36Sopenharmony_ci	dev7 = alloc_dev_default(test, host, 0x3, true);
80662306a36Sopenharmony_ci	dev8 = alloc_dev_default(test, dev7, 0x303, true);
80762306a36Sopenharmony_ci	dev9 = alloc_dev_default(test, dev8, 0x30303, true);
80862306a36Sopenharmony_ci	dev10 = alloc_dev_default(test, dev9, 0x3030303, true);
80962306a36Sopenharmony_ci	dev11 = alloc_dev_default(test, dev10, 0x303030303, true);
81062306a36Sopenharmony_ci	dev12 = alloc_dev_default(test, dev11, 0x30303030303, true);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	src_port = &dev6->ports[13];
81362306a36Sopenharmony_ci	dst_port = &dev12->ports[13];
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* Walk both directions */
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	i = 0;
81862306a36Sopenharmony_ci	tb_for_each_port_on_path(src_port, dst_port, p) {
81962306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
82062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
82162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
82262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
82362306a36Sopenharmony_ci				test_data[i].type);
82462306a36Sopenharmony_ci		i++;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	i = ARRAY_SIZE(test_data) - 1;
83062306a36Sopenharmony_ci	tb_for_each_port_on_path(dst_port, src_port, p) {
83162306a36Sopenharmony_ci		KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data));
83262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route);
83362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, p->port, test_data[i].port);
83462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type,
83562306a36Sopenharmony_ci				test_data[i].type);
83662306a36Sopenharmony_ci		i--;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, i, -1);
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic void tb_test_path_not_connected(struct kunit *test)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2;
84562306a36Sopenharmony_ci	struct tb_port *down, *up;
84662306a36Sopenharmony_ci	struct tb_path *path;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	host = alloc_host(test);
84962306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x3, false);
85062306a36Sopenharmony_ci	/* Not connected to anything */
85162306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, NULL, 0x303, false);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	down = &dev1->ports[10];
85462306a36Sopenharmony_ci	up = &dev2->ports[9];
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	path = tb_path_alloc(NULL, down, 8, up, 8, 0, "PCIe Down");
85762306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, path);
85862306a36Sopenharmony_ci	path = tb_path_alloc(NULL, down, 8, up, 8, 1, "PCIe Down");
85962306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, path);
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistruct hop_expectation {
86362306a36Sopenharmony_ci	u64 route;
86462306a36Sopenharmony_ci	u8 in_port;
86562306a36Sopenharmony_ci	enum tb_port_type in_type;
86662306a36Sopenharmony_ci	u8 out_port;
86762306a36Sopenharmony_ci	enum tb_port_type out_type;
86862306a36Sopenharmony_ci};
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic void tb_test_path_not_bonded_lane0(struct kunit *test)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	/*
87362306a36Sopenharmony_ci	 * PCIe path from host to device using lane 0.
87462306a36Sopenharmony_ci	 *
87562306a36Sopenharmony_ci	 *   [Host]
87662306a36Sopenharmony_ci	 *   3 |: 4
87762306a36Sopenharmony_ci	 *   1 |: 2
87862306a36Sopenharmony_ci	 *  [Device]
87962306a36Sopenharmony_ci	 */
88062306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
88162306a36Sopenharmony_ci		{
88262306a36Sopenharmony_ci			.route = 0x0,
88362306a36Sopenharmony_ci			.in_port = 9,
88462306a36Sopenharmony_ci			.in_type = TB_TYPE_PCIE_DOWN,
88562306a36Sopenharmony_ci			.out_port = 3,
88662306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
88762306a36Sopenharmony_ci		},
88862306a36Sopenharmony_ci		{
88962306a36Sopenharmony_ci			.route = 0x3,
89062306a36Sopenharmony_ci			.in_port = 1,
89162306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
89262306a36Sopenharmony_ci			.out_port = 9,
89362306a36Sopenharmony_ci			.out_type = TB_TYPE_PCIE_UP,
89462306a36Sopenharmony_ci		},
89562306a36Sopenharmony_ci	};
89662306a36Sopenharmony_ci	struct tb_switch *host, *dev;
89762306a36Sopenharmony_ci	struct tb_port *down, *up;
89862306a36Sopenharmony_ci	struct tb_path *path;
89962306a36Sopenharmony_ci	int i;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	host = alloc_host(test);
90262306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 0x3, false);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	down = &host->ports[9];
90562306a36Sopenharmony_ci	up = &dev->ports[9];
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	path = tb_path_alloc(NULL, down, 8, up, 8, 0, "PCIe Down");
90862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
90962306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
91062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
91162306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
91462306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
91762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
91862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
91962306a36Sopenharmony_ci				test_data[i].in_type);
92062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
92162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
92262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
92362306a36Sopenharmony_ci				test_data[i].out_type);
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci	tb_path_free(path);
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic void tb_test_path_not_bonded_lane1(struct kunit *test)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	/*
93162306a36Sopenharmony_ci	 * DP Video path from host to device using lane 1. Paths like
93262306a36Sopenharmony_ci	 * these are only used with Thunderbolt 1 devices where lane
93362306a36Sopenharmony_ci	 * bonding is not possible. USB4 specifically does not allow
93462306a36Sopenharmony_ci	 * paths like this (you either use lane 0 where lane 1 is
93562306a36Sopenharmony_ci	 * disabled or both lanes are bonded).
93662306a36Sopenharmony_ci	 *
93762306a36Sopenharmony_ci	 *   [Host]
93862306a36Sopenharmony_ci	 *   1 :| 2
93962306a36Sopenharmony_ci	 *   1 :| 2
94062306a36Sopenharmony_ci	 *  [Device]
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
94362306a36Sopenharmony_ci		{
94462306a36Sopenharmony_ci			.route = 0x0,
94562306a36Sopenharmony_ci			.in_port = 5,
94662306a36Sopenharmony_ci			.in_type = TB_TYPE_DP_HDMI_IN,
94762306a36Sopenharmony_ci			.out_port = 2,
94862306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
94962306a36Sopenharmony_ci		},
95062306a36Sopenharmony_ci		{
95162306a36Sopenharmony_ci			.route = 0x1,
95262306a36Sopenharmony_ci			.in_port = 2,
95362306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
95462306a36Sopenharmony_ci			.out_port = 13,
95562306a36Sopenharmony_ci			.out_type = TB_TYPE_DP_HDMI_OUT,
95662306a36Sopenharmony_ci		},
95762306a36Sopenharmony_ci	};
95862306a36Sopenharmony_ci	struct tb_switch *host, *dev;
95962306a36Sopenharmony_ci	struct tb_port *in, *out;
96062306a36Sopenharmony_ci	struct tb_path *path;
96162306a36Sopenharmony_ci	int i;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	host = alloc_host(test);
96462306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 0x1, false);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	in = &host->ports[5];
96762306a36Sopenharmony_ci	out = &dev->ports[13];
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
97062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
97162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
97262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
97362306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
97662306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
97962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
98062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
98162306a36Sopenharmony_ci				test_data[i].in_type);
98262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
98362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
98462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
98562306a36Sopenharmony_ci				test_data[i].out_type);
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci	tb_path_free(path);
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic void tb_test_path_not_bonded_lane1_chain(struct kunit *test)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	/*
99362306a36Sopenharmony_ci	 * DP Video path from host to device 3 using lane 1.
99462306a36Sopenharmony_ci	 *
99562306a36Sopenharmony_ci	 *    [Host]
99662306a36Sopenharmony_ci	 *    1 :| 2
99762306a36Sopenharmony_ci	 *    1 :| 2
99862306a36Sopenharmony_ci	 *  [Device #1]
99962306a36Sopenharmony_ci	 *    7 :| 8
100062306a36Sopenharmony_ci	 *    1 :| 2
100162306a36Sopenharmony_ci	 *  [Device #2]
100262306a36Sopenharmony_ci	 *    5 :| 6
100362306a36Sopenharmony_ci	 *    1 :| 2
100462306a36Sopenharmony_ci	 *  [Device #3]
100562306a36Sopenharmony_ci	 */
100662306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
100762306a36Sopenharmony_ci		{
100862306a36Sopenharmony_ci			.route = 0x0,
100962306a36Sopenharmony_ci			.in_port = 5,
101062306a36Sopenharmony_ci			.in_type = TB_TYPE_DP_HDMI_IN,
101162306a36Sopenharmony_ci			.out_port = 2,
101262306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
101362306a36Sopenharmony_ci		},
101462306a36Sopenharmony_ci		{
101562306a36Sopenharmony_ci			.route = 0x1,
101662306a36Sopenharmony_ci			.in_port = 2,
101762306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
101862306a36Sopenharmony_ci			.out_port = 8,
101962306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
102062306a36Sopenharmony_ci		},
102162306a36Sopenharmony_ci		{
102262306a36Sopenharmony_ci			.route = 0x701,
102362306a36Sopenharmony_ci			.in_port = 2,
102462306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
102562306a36Sopenharmony_ci			.out_port = 6,
102662306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
102762306a36Sopenharmony_ci		},
102862306a36Sopenharmony_ci		{
102962306a36Sopenharmony_ci			.route = 0x50701,
103062306a36Sopenharmony_ci			.in_port = 2,
103162306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
103262306a36Sopenharmony_ci			.out_port = 13,
103362306a36Sopenharmony_ci			.out_type = TB_TYPE_DP_HDMI_OUT,
103462306a36Sopenharmony_ci		},
103562306a36Sopenharmony_ci	};
103662306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3;
103762306a36Sopenharmony_ci	struct tb_port *in, *out;
103862306a36Sopenharmony_ci	struct tb_path *path;
103962306a36Sopenharmony_ci	int i;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	host = alloc_host(test);
104262306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, false);
104362306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, false);
104462306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev2, 0x50701, false);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	in = &host->ports[5];
104762306a36Sopenharmony_ci	out = &dev3->ports[13];
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
105062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
105162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
105262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
105362306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
105662306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
105962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
106062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
106162306a36Sopenharmony_ci				test_data[i].in_type);
106262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
106362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
106462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
106562306a36Sopenharmony_ci				test_data[i].out_type);
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci	tb_path_free(path);
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic void tb_test_path_not_bonded_lane1_chain_reverse(struct kunit *test)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	/*
107362306a36Sopenharmony_ci	 * DP Video path from device 3 to host using lane 1.
107462306a36Sopenharmony_ci	 *
107562306a36Sopenharmony_ci	 *    [Host]
107662306a36Sopenharmony_ci	 *    1 :| 2
107762306a36Sopenharmony_ci	 *    1 :| 2
107862306a36Sopenharmony_ci	 *  [Device #1]
107962306a36Sopenharmony_ci	 *    7 :| 8
108062306a36Sopenharmony_ci	 *    1 :| 2
108162306a36Sopenharmony_ci	 *  [Device #2]
108262306a36Sopenharmony_ci	 *    5 :| 6
108362306a36Sopenharmony_ci	 *    1 :| 2
108462306a36Sopenharmony_ci	 *  [Device #3]
108562306a36Sopenharmony_ci	 */
108662306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
108762306a36Sopenharmony_ci		{
108862306a36Sopenharmony_ci			.route = 0x50701,
108962306a36Sopenharmony_ci			.in_port = 13,
109062306a36Sopenharmony_ci			.in_type = TB_TYPE_DP_HDMI_IN,
109162306a36Sopenharmony_ci			.out_port = 2,
109262306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
109362306a36Sopenharmony_ci		},
109462306a36Sopenharmony_ci		{
109562306a36Sopenharmony_ci			.route = 0x701,
109662306a36Sopenharmony_ci			.in_port = 6,
109762306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
109862306a36Sopenharmony_ci			.out_port = 2,
109962306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
110062306a36Sopenharmony_ci		},
110162306a36Sopenharmony_ci		{
110262306a36Sopenharmony_ci			.route = 0x1,
110362306a36Sopenharmony_ci			.in_port = 8,
110462306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
110562306a36Sopenharmony_ci			.out_port = 2,
110662306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
110762306a36Sopenharmony_ci		},
110862306a36Sopenharmony_ci		{
110962306a36Sopenharmony_ci			.route = 0x0,
111062306a36Sopenharmony_ci			.in_port = 2,
111162306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
111262306a36Sopenharmony_ci			.out_port = 5,
111362306a36Sopenharmony_ci			.out_type = TB_TYPE_DP_HDMI_IN,
111462306a36Sopenharmony_ci		},
111562306a36Sopenharmony_ci	};
111662306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3;
111762306a36Sopenharmony_ci	struct tb_port *in, *out;
111862306a36Sopenharmony_ci	struct tb_path *path;
111962306a36Sopenharmony_ci	int i;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	host = alloc_host(test);
112262306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, false);
112362306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, false);
112462306a36Sopenharmony_ci	dev3 = alloc_dev_with_dpin(test, dev2, 0x50701, false);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	in = &dev3->ports[13];
112762306a36Sopenharmony_ci	out = &host->ports[5];
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
113062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
113162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
113262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
113362306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
113662306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
113962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
114062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
114162306a36Sopenharmony_ci				test_data[i].in_type);
114262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
114362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
114462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
114562306a36Sopenharmony_ci				test_data[i].out_type);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci	tb_path_free(path);
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic void tb_test_path_mixed_chain(struct kunit *test)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	/*
115362306a36Sopenharmony_ci	 * DP Video path from host to device 4 where first and last link
115462306a36Sopenharmony_ci	 * is bonded.
115562306a36Sopenharmony_ci	 *
115662306a36Sopenharmony_ci	 *    [Host]
115762306a36Sopenharmony_ci	 *    1 |
115862306a36Sopenharmony_ci	 *    1 |
115962306a36Sopenharmony_ci	 *  [Device #1]
116062306a36Sopenharmony_ci	 *    7 :| 8
116162306a36Sopenharmony_ci	 *    1 :| 2
116262306a36Sopenharmony_ci	 *  [Device #2]
116362306a36Sopenharmony_ci	 *    5 :| 6
116462306a36Sopenharmony_ci	 *    1 :| 2
116562306a36Sopenharmony_ci	 *  [Device #3]
116662306a36Sopenharmony_ci	 *    3 |
116762306a36Sopenharmony_ci	 *    1 |
116862306a36Sopenharmony_ci	 *  [Device #4]
116962306a36Sopenharmony_ci	 */
117062306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
117162306a36Sopenharmony_ci		{
117262306a36Sopenharmony_ci			.route = 0x0,
117362306a36Sopenharmony_ci			.in_port = 5,
117462306a36Sopenharmony_ci			.in_type = TB_TYPE_DP_HDMI_IN,
117562306a36Sopenharmony_ci			.out_port = 1,
117662306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
117762306a36Sopenharmony_ci		},
117862306a36Sopenharmony_ci		{
117962306a36Sopenharmony_ci			.route = 0x1,
118062306a36Sopenharmony_ci			.in_port = 1,
118162306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
118262306a36Sopenharmony_ci			.out_port = 8,
118362306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
118462306a36Sopenharmony_ci		},
118562306a36Sopenharmony_ci		{
118662306a36Sopenharmony_ci			.route = 0x701,
118762306a36Sopenharmony_ci			.in_port = 2,
118862306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
118962306a36Sopenharmony_ci			.out_port = 6,
119062306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
119162306a36Sopenharmony_ci		},
119262306a36Sopenharmony_ci		{
119362306a36Sopenharmony_ci			.route = 0x50701,
119462306a36Sopenharmony_ci			.in_port = 2,
119562306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
119662306a36Sopenharmony_ci			.out_port = 3,
119762306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
119862306a36Sopenharmony_ci		},
119962306a36Sopenharmony_ci		{
120062306a36Sopenharmony_ci			.route = 0x3050701,
120162306a36Sopenharmony_ci			.in_port = 1,
120262306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
120362306a36Sopenharmony_ci			.out_port = 13,
120462306a36Sopenharmony_ci			.out_type = TB_TYPE_DP_HDMI_OUT,
120562306a36Sopenharmony_ci		},
120662306a36Sopenharmony_ci	};
120762306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4;
120862306a36Sopenharmony_ci	struct tb_port *in, *out;
120962306a36Sopenharmony_ci	struct tb_path *path;
121062306a36Sopenharmony_ci	int i;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	host = alloc_host(test);
121362306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
121462306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, false);
121562306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev2, 0x50701, false);
121662306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev3, 0x3050701, true);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	in = &host->ports[5];
121962306a36Sopenharmony_ci	out = &dev4->ports[13];
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
122262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
122362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
122462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
122562306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
122862306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
123162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
123262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
123362306a36Sopenharmony_ci				test_data[i].in_type);
123462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
123562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
123662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
123762306a36Sopenharmony_ci				test_data[i].out_type);
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci	tb_path_free(path);
124062306a36Sopenharmony_ci}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic void tb_test_path_mixed_chain_reverse(struct kunit *test)
124362306a36Sopenharmony_ci{
124462306a36Sopenharmony_ci	/*
124562306a36Sopenharmony_ci	 * DP Video path from device 4 to host where first and last link
124662306a36Sopenharmony_ci	 * is bonded.
124762306a36Sopenharmony_ci	 *
124862306a36Sopenharmony_ci	 *    [Host]
124962306a36Sopenharmony_ci	 *    1 |
125062306a36Sopenharmony_ci	 *    1 |
125162306a36Sopenharmony_ci	 *  [Device #1]
125262306a36Sopenharmony_ci	 *    7 :| 8
125362306a36Sopenharmony_ci	 *    1 :| 2
125462306a36Sopenharmony_ci	 *  [Device #2]
125562306a36Sopenharmony_ci	 *    5 :| 6
125662306a36Sopenharmony_ci	 *    1 :| 2
125762306a36Sopenharmony_ci	 *  [Device #3]
125862306a36Sopenharmony_ci	 *    3 |
125962306a36Sopenharmony_ci	 *    1 |
126062306a36Sopenharmony_ci	 *  [Device #4]
126162306a36Sopenharmony_ci	 */
126262306a36Sopenharmony_ci	static const struct hop_expectation test_data[] = {
126362306a36Sopenharmony_ci		{
126462306a36Sopenharmony_ci			.route = 0x3050701,
126562306a36Sopenharmony_ci			.in_port = 13,
126662306a36Sopenharmony_ci			.in_type = TB_TYPE_DP_HDMI_OUT,
126762306a36Sopenharmony_ci			.out_port = 1,
126862306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
126962306a36Sopenharmony_ci		},
127062306a36Sopenharmony_ci		{
127162306a36Sopenharmony_ci			.route = 0x50701,
127262306a36Sopenharmony_ci			.in_port = 3,
127362306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
127462306a36Sopenharmony_ci			.out_port = 2,
127562306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
127662306a36Sopenharmony_ci		},
127762306a36Sopenharmony_ci		{
127862306a36Sopenharmony_ci			.route = 0x701,
127962306a36Sopenharmony_ci			.in_port = 6,
128062306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
128162306a36Sopenharmony_ci			.out_port = 2,
128262306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
128362306a36Sopenharmony_ci		},
128462306a36Sopenharmony_ci		{
128562306a36Sopenharmony_ci			.route = 0x1,
128662306a36Sopenharmony_ci			.in_port = 8,
128762306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
128862306a36Sopenharmony_ci			.out_port = 1,
128962306a36Sopenharmony_ci			.out_type = TB_TYPE_PORT,
129062306a36Sopenharmony_ci		},
129162306a36Sopenharmony_ci		{
129262306a36Sopenharmony_ci			.route = 0x0,
129362306a36Sopenharmony_ci			.in_port = 1,
129462306a36Sopenharmony_ci			.in_type = TB_TYPE_PORT,
129562306a36Sopenharmony_ci			.out_port = 5,
129662306a36Sopenharmony_ci			.out_type = TB_TYPE_DP_HDMI_IN,
129762306a36Sopenharmony_ci		},
129862306a36Sopenharmony_ci	};
129962306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4;
130062306a36Sopenharmony_ci	struct tb_port *in, *out;
130162306a36Sopenharmony_ci	struct tb_path *path;
130262306a36Sopenharmony_ci	int i;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	host = alloc_host(test);
130562306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
130662306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, false);
130762306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev2, 0x50701, false);
130862306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev3, 0x3050701, true);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	in = &dev4->ports[13];
131162306a36Sopenharmony_ci	out = &host->ports[5];
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
131462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, path);
131562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
131662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(test_data); i++) {
131762306a36Sopenharmony_ci		const struct tb_port *in_port, *out_port;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		in_port = path->hops[i].in_port;
132062306a36Sopenharmony_ci		out_port = path->hops[i].out_port;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route);
132362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port);
132462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type,
132562306a36Sopenharmony_ci				test_data[i].in_type);
132662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route);
132762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port);
132862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type,
132962306a36Sopenharmony_ci				test_data[i].out_type);
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci	tb_path_free(path);
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic void tb_test_tunnel_pcie(struct kunit *test)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2;
133762306a36Sopenharmony_ci	struct tb_tunnel *tunnel1, *tunnel2;
133862306a36Sopenharmony_ci	struct tb_port *down, *up;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/*
134162306a36Sopenharmony_ci	 * Create PCIe tunnel between host and two devices.
134262306a36Sopenharmony_ci	 *
134362306a36Sopenharmony_ci	 *   [Host]
134462306a36Sopenharmony_ci	 *    1 |
134562306a36Sopenharmony_ci	 *    1 |
134662306a36Sopenharmony_ci	 *  [Device #1]
134762306a36Sopenharmony_ci	 *    5 |
134862306a36Sopenharmony_ci	 *    1 |
134962306a36Sopenharmony_ci	 *  [Device #2]
135062306a36Sopenharmony_ci	 */
135162306a36Sopenharmony_ci	host = alloc_host(test);
135262306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
135362306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x501, true);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	down = &host->ports[8];
135662306a36Sopenharmony_ci	up = &dev1->ports[9];
135762306a36Sopenharmony_ci	tunnel1 = tb_tunnel_alloc_pci(NULL, up, down);
135862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel1);
135962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel1->type, TB_TUNNEL_PCI);
136062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down);
136162306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up);
136262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->npaths, 2);
136362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2);
136462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down);
136562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up);
136662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->paths[1]->path_length, 2);
136762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[0].in_port, up);
136862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[1].out_port, down);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	down = &dev1->ports[10];
137162306a36Sopenharmony_ci	up = &dev2->ports[9];
137262306a36Sopenharmony_ci	tunnel2 = tb_tunnel_alloc_pci(NULL, up, down);
137362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel2);
137462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel2->type, TB_TUNNEL_PCI);
137562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down);
137662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up);
137762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->npaths, 2);
137862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2);
137962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down);
138062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up);
138162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->paths[1]->path_length, 2);
138262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[0].in_port, up);
138362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[1].out_port, down);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	tb_tunnel_free(tunnel2);
138662306a36Sopenharmony_ci	tb_tunnel_free(tunnel1);
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic void tb_test_tunnel_dp(struct kunit *test)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct tb_switch *host, *dev;
139262306a36Sopenharmony_ci	struct tb_port *in, *out;
139362306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/*
139662306a36Sopenharmony_ci	 * Create DP tunnel between Host and Device
139762306a36Sopenharmony_ci	 *
139862306a36Sopenharmony_ci	 *   [Host]
139962306a36Sopenharmony_ci	 *   1 |
140062306a36Sopenharmony_ci	 *   1 |
140162306a36Sopenharmony_ci	 *  [Device]
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	host = alloc_host(test);
140462306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 0x3, true);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	in = &host->ports[5];
140762306a36Sopenharmony_ci	out = &dev->ports[13];
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
141062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
141162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
141262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
141362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
141462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
141562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 2);
141662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
141762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].out_port, out);
141862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 2);
141962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in);
142062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].out_port, out);
142162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 2);
142262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out);
142362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[1].out_port, in);
142462306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic void tb_test_tunnel_dp_chain(struct kunit *test)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev4;
143062306a36Sopenharmony_ci	struct tb_port *in, *out;
143162306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	/*
143462306a36Sopenharmony_ci	 * Create DP tunnel from Host DP IN to Device #4 DP OUT.
143562306a36Sopenharmony_ci	 *
143662306a36Sopenharmony_ci	 *           [Host]
143762306a36Sopenharmony_ci	 *            1 |
143862306a36Sopenharmony_ci	 *            1 |
143962306a36Sopenharmony_ci	 *         [Device #1]
144062306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
144162306a36Sopenharmony_ci	 *      1 /    |     \ 1
144262306a36Sopenharmony_ci	 * [Device #2] |    [Device #4]
144362306a36Sopenharmony_ci	 *             | 1
144462306a36Sopenharmony_ci	 *         [Device #3]
144562306a36Sopenharmony_ci	 */
144662306a36Sopenharmony_ci	host = alloc_host(test);
144762306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
144862306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x301, true);
144962306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x501, true);
145062306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev1, 0x701, true);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	in = &host->ports[5];
145362306a36Sopenharmony_ci	out = &dev4->ports[14];
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
145662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
145762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
145862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
145962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
146062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
146162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3);
146262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
146362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].out_port, out);
146462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 3);
146562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in);
146662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].out_port, out);
146762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 3);
146862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out);
146962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[2].out_port, in);
147062306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
147162306a36Sopenharmony_ci}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_cistatic void tb_test_tunnel_dp_tree(struct kunit *test)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev5;
147662306a36Sopenharmony_ci	struct tb_port *in, *out;
147762306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	/*
148062306a36Sopenharmony_ci	 * Create DP tunnel from Device #2 DP IN to Device #5 DP OUT.
148162306a36Sopenharmony_ci	 *
148262306a36Sopenharmony_ci	 *          [Host]
148362306a36Sopenharmony_ci	 *           3 |
148462306a36Sopenharmony_ci	 *           1 |
148562306a36Sopenharmony_ci	 *         [Device #1]
148662306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
148762306a36Sopenharmony_ci	 *      1 /    |     \ 1
148862306a36Sopenharmony_ci	 * [Device #2] |    [Device #4]
148962306a36Sopenharmony_ci	 *             | 1
149062306a36Sopenharmony_ci	 *         [Device #3]
149162306a36Sopenharmony_ci	 *             | 5
149262306a36Sopenharmony_ci	 *             | 1
149362306a36Sopenharmony_ci	 *         [Device #5]
149462306a36Sopenharmony_ci	 */
149562306a36Sopenharmony_ci	host = alloc_host(test);
149662306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x3, true);
149762306a36Sopenharmony_ci	dev2 = alloc_dev_with_dpin(test, dev1, 0x303, true);
149862306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev1, 0x503, true);
149962306a36Sopenharmony_ci	alloc_dev_default(test, dev1, 0x703, true);
150062306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev3, 0x50503, true);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	in = &dev2->ports[13];
150362306a36Sopenharmony_ci	out = &dev5->ports[13];
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
150662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
150762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
150862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
150962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
151062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
151162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 4);
151262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
151362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[3].out_port, out);
151462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 4);
151562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in);
151662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[3].out_port, out);
151762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 4);
151862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out);
151962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[3].out_port, in);
152062306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
152162306a36Sopenharmony_ci}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic void tb_test_tunnel_dp_max_length(struct kunit *test)
152462306a36Sopenharmony_ci{
152562306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5, *dev6;
152662306a36Sopenharmony_ci	struct tb_switch *dev7, *dev8, *dev9, *dev10, *dev11, *dev12;
152762306a36Sopenharmony_ci	struct tb_port *in, *out;
152862306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/*
153162306a36Sopenharmony_ci	 * Creates DP tunnel from Device #6 to Device #12.
153262306a36Sopenharmony_ci	 *
153362306a36Sopenharmony_ci	 *          [Host]
153462306a36Sopenharmony_ci	 *         1 /  \ 3
153562306a36Sopenharmony_ci	 *        1 /    \ 1
153662306a36Sopenharmony_ci	 * [Device #1]   [Device #7]
153762306a36Sopenharmony_ci	 *     3 |           | 3
153862306a36Sopenharmony_ci	 *     1 |           | 1
153962306a36Sopenharmony_ci	 * [Device #2]   [Device #8]
154062306a36Sopenharmony_ci	 *     3 |           | 3
154162306a36Sopenharmony_ci	 *     1 |           | 1
154262306a36Sopenharmony_ci	 * [Device #3]   [Device #9]
154362306a36Sopenharmony_ci	 *     3 |           | 3
154462306a36Sopenharmony_ci	 *     1 |           | 1
154562306a36Sopenharmony_ci	 * [Device #4]   [Device #10]
154662306a36Sopenharmony_ci	 *     3 |           | 3
154762306a36Sopenharmony_ci	 *     1 |           | 1
154862306a36Sopenharmony_ci	 * [Device #5]   [Device #11]
154962306a36Sopenharmony_ci	 *     3 |           | 3
155062306a36Sopenharmony_ci	 *     1 |           | 1
155162306a36Sopenharmony_ci	 * [Device #6]   [Device #12]
155262306a36Sopenharmony_ci	 */
155362306a36Sopenharmony_ci	host = alloc_host(test);
155462306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
155562306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x301, true);
155662306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev2, 0x30301, true);
155762306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev3, 0x3030301, true);
155862306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev4, 0x303030301, true);
155962306a36Sopenharmony_ci	dev6 = alloc_dev_with_dpin(test, dev5, 0x30303030301, true);
156062306a36Sopenharmony_ci	dev7 = alloc_dev_default(test, host, 0x3, true);
156162306a36Sopenharmony_ci	dev8 = alloc_dev_default(test, dev7, 0x303, true);
156262306a36Sopenharmony_ci	dev9 = alloc_dev_default(test, dev8, 0x30303, true);
156362306a36Sopenharmony_ci	dev10 = alloc_dev_default(test, dev9, 0x3030303, true);
156462306a36Sopenharmony_ci	dev11 = alloc_dev_default(test, dev10, 0x303030303, true);
156562306a36Sopenharmony_ci	dev12 = alloc_dev_default(test, dev11, 0x30303030303, true);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	in = &dev6->ports[13];
156862306a36Sopenharmony_ci	out = &dev12->ports[13];
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
157162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
157262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
157362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
157462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
157562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
157662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 13);
157762306a36Sopenharmony_ci	/* First hop */
157862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
157962306a36Sopenharmony_ci	/* Middle */
158062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[6].in_port,
158162306a36Sopenharmony_ci			    &host->ports[1]);
158262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[6].out_port,
158362306a36Sopenharmony_ci			    &host->ports[3]);
158462306a36Sopenharmony_ci	/* Last */
158562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[12].out_port, out);
158662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 13);
158762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in);
158862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[6].in_port,
158962306a36Sopenharmony_ci			    &host->ports[1]);
159062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[6].out_port,
159162306a36Sopenharmony_ci			    &host->ports[3]);
159262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[12].out_port, out);
159362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 13);
159462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out);
159562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[6].in_port,
159662306a36Sopenharmony_ci			    &host->ports[3]);
159762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[6].out_port,
159862306a36Sopenharmony_ci			    &host->ports[1]);
159962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[12].out_port, in);
160062306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic void tb_test_tunnel_3dp(struct kunit *test)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5;
160662306a36Sopenharmony_ci	struct tb_port *in1, *in2, *in3, *out1, *out2, *out3;
160762306a36Sopenharmony_ci	struct tb_tunnel *tunnel1, *tunnel2, *tunnel3;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	/*
161062306a36Sopenharmony_ci	 * Create 3 DP tunnels from Host to Devices #2, #5 and #4.
161162306a36Sopenharmony_ci	 *
161262306a36Sopenharmony_ci	 *          [Host]
161362306a36Sopenharmony_ci	 *           3 |
161462306a36Sopenharmony_ci	 *           1 |
161562306a36Sopenharmony_ci	 *         [Device #1]
161662306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
161762306a36Sopenharmony_ci	 *      1 /    |     \ 1
161862306a36Sopenharmony_ci	 * [Device #2] |    [Device #4]
161962306a36Sopenharmony_ci	 *             | 1
162062306a36Sopenharmony_ci	 *         [Device #3]
162162306a36Sopenharmony_ci	 *             | 5
162262306a36Sopenharmony_ci	 *             | 1
162362306a36Sopenharmony_ci	 *         [Device #5]
162462306a36Sopenharmony_ci	 */
162562306a36Sopenharmony_ci	host = alloc_host_br(test);
162662306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x3, true);
162762306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x303, true);
162862306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev1, 0x503, true);
162962306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev1, 0x703, true);
163062306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev3, 0x50503, true);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	in1 = &host->ports[5];
163362306a36Sopenharmony_ci	in2 = &host->ports[6];
163462306a36Sopenharmony_ci	in3 = &host->ports[10];
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	out1 = &dev2->ports[13];
163762306a36Sopenharmony_ci	out2 = &dev5->ports[13];
163862306a36Sopenharmony_ci	out3 = &dev4->ports[14];
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	tunnel1 = tb_tunnel_alloc_dp(NULL, in1, out1, 1, 0, 0);
164162306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tunnel1 != NULL);
164262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel1->type, TB_TUNNEL_DP);
164362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, in1);
164462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, out1);
164562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->npaths, 3);
164662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 3);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	tunnel2 = tb_tunnel_alloc_dp(NULL, in2, out2, 1, 0, 0);
164962306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tunnel2 != NULL);
165062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel2->type, TB_TUNNEL_DP);
165162306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, in2);
165262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, out2);
165362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->npaths, 3);
165462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 4);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	tunnel3 = tb_tunnel_alloc_dp(NULL, in3, out3, 1, 0, 0);
165762306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tunnel3 != NULL);
165862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel3->type, TB_TUNNEL_DP);
165962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel3->src_port, in3);
166062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel3->dst_port, out3);
166162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel3->npaths, 3);
166262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel3->paths[0]->path_length, 3);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	tb_tunnel_free(tunnel2);
166562306a36Sopenharmony_ci	tb_tunnel_free(tunnel1);
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_cistatic void tb_test_tunnel_usb3(struct kunit *test)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2;
167162306a36Sopenharmony_ci	struct tb_tunnel *tunnel1, *tunnel2;
167262306a36Sopenharmony_ci	struct tb_port *down, *up;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	/*
167562306a36Sopenharmony_ci	 * Create USB3 tunnel between host and two devices.
167662306a36Sopenharmony_ci	 *
167762306a36Sopenharmony_ci	 *   [Host]
167862306a36Sopenharmony_ci	 *    1 |
167962306a36Sopenharmony_ci	 *    1 |
168062306a36Sopenharmony_ci	 *  [Device #1]
168162306a36Sopenharmony_ci	 *          \ 7
168262306a36Sopenharmony_ci	 *           \ 1
168362306a36Sopenharmony_ci	 *         [Device #2]
168462306a36Sopenharmony_ci	 */
168562306a36Sopenharmony_ci	host = alloc_host(test);
168662306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
168762306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, true);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	down = &host->ports[12];
169062306a36Sopenharmony_ci	up = &dev1->ports[16];
169162306a36Sopenharmony_ci	tunnel1 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
169262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel1);
169362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel1->type, TB_TUNNEL_USB3);
169462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down);
169562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up);
169662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->npaths, 2);
169762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2);
169862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down);
169962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up);
170062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->paths[1]->path_length, 2);
170162306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[0].in_port, up);
170262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[1].out_port, down);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	down = &dev1->ports[17];
170562306a36Sopenharmony_ci	up = &dev2->ports[16];
170662306a36Sopenharmony_ci	tunnel2 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
170762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel2);
170862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel2->type, TB_TUNNEL_USB3);
170962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down);
171062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up);
171162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->npaths, 2);
171262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2);
171362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down);
171462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up);
171562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->paths[1]->path_length, 2);
171662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[0].in_port, up);
171762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[1].out_port, down);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	tb_tunnel_free(tunnel2);
172062306a36Sopenharmony_ci	tb_tunnel_free(tunnel1);
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic void tb_test_tunnel_port_on_path(struct kunit *test)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5;
172662306a36Sopenharmony_ci	struct tb_port *in, *out, *port;
172762306a36Sopenharmony_ci	struct tb_tunnel *dp_tunnel;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/*
173062306a36Sopenharmony_ci	 *          [Host]
173162306a36Sopenharmony_ci	 *           3 |
173262306a36Sopenharmony_ci	 *           1 |
173362306a36Sopenharmony_ci	 *         [Device #1]
173462306a36Sopenharmony_ci	 *       3 /   | 5  \ 7
173562306a36Sopenharmony_ci	 *      1 /    |     \ 1
173662306a36Sopenharmony_ci	 * [Device #2] |    [Device #4]
173762306a36Sopenharmony_ci	 *             | 1
173862306a36Sopenharmony_ci	 *         [Device #3]
173962306a36Sopenharmony_ci	 *             | 5
174062306a36Sopenharmony_ci	 *             | 1
174162306a36Sopenharmony_ci	 *         [Device #5]
174262306a36Sopenharmony_ci	 */
174362306a36Sopenharmony_ci	host = alloc_host(test);
174462306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x3, true);
174562306a36Sopenharmony_ci	dev2 = alloc_dev_with_dpin(test, dev1, 0x303, true);
174662306a36Sopenharmony_ci	dev3 = alloc_dev_default(test, dev1, 0x503, true);
174762306a36Sopenharmony_ci	dev4 = alloc_dev_default(test, dev1, 0x703, true);
174862306a36Sopenharmony_ci	dev5 = alloc_dev_default(test, dev3, 0x50503, true);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	in = &dev2->ports[13];
175162306a36Sopenharmony_ci	out = &dev5->ports[13];
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
175462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dp_tunnel);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, in));
175762306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, out));
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	port = &host->ports[8];
176062306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port));
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	port = &host->ports[3];
176362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port));
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	port = &dev1->ports[1];
176662306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port));
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	port = &dev1->ports[3];
176962306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port));
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	port = &dev1->ports[5];
177262306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port));
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	port = &dev1->ports[7];
177562306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port));
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	port = &dev3->ports[1];
177862306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port));
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	port = &dev5->ports[1];
178162306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port));
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	port = &dev4->ports[1];
178462306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port));
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	tb_tunnel_free(dp_tunnel);
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic void tb_test_tunnel_dma(struct kunit *test)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct tb_port *nhi, *port;
179262306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
179362306a36Sopenharmony_ci	struct tb_switch *host;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/*
179662306a36Sopenharmony_ci	 * Create DMA tunnel from NHI to port 1 and back.
179762306a36Sopenharmony_ci	 *
179862306a36Sopenharmony_ci	 *   [Host 1]
179962306a36Sopenharmony_ci	 *    1 ^ In HopID 1 -> Out HopID 8
180062306a36Sopenharmony_ci	 *      |
180162306a36Sopenharmony_ci	 *      v In HopID 8 -> Out HopID 1
180262306a36Sopenharmony_ci	 * ............ Domain border
180362306a36Sopenharmony_ci	 *      |
180462306a36Sopenharmony_ci	 *   [Host 2]
180562306a36Sopenharmony_ci	 */
180662306a36Sopenharmony_ci	host = alloc_host(test);
180762306a36Sopenharmony_ci	nhi = &host->ports[7];
180862306a36Sopenharmony_ci	port = &host->ports[1];
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
181162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
181262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
181362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
181462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
181562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 2);
181662306a36Sopenharmony_ci	/* RX path */
181762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
181862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
181962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 8);
182062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, nhi);
182162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 1);
182262306a36Sopenharmony_ci	/* TX path */
182362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 1);
182462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, nhi);
182562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].in_hop_index, 1);
182662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].out_port, port);
182762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].next_hop_index, 8);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_cistatic void tb_test_tunnel_dma_rx(struct kunit *test)
183362306a36Sopenharmony_ci{
183462306a36Sopenharmony_ci	struct tb_port *nhi, *port;
183562306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
183662306a36Sopenharmony_ci	struct tb_switch *host;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/*
183962306a36Sopenharmony_ci	 * Create DMA RX tunnel from port 1 to NHI.
184062306a36Sopenharmony_ci	 *
184162306a36Sopenharmony_ci	 *   [Host 1]
184262306a36Sopenharmony_ci	 *    1 ^
184362306a36Sopenharmony_ci	 *      |
184462306a36Sopenharmony_ci	 *      | In HopID 15 -> Out HopID 2
184562306a36Sopenharmony_ci	 * ............ Domain border
184662306a36Sopenharmony_ci	 *      |
184762306a36Sopenharmony_ci	 *   [Host 2]
184862306a36Sopenharmony_ci	 */
184962306a36Sopenharmony_ci	host = alloc_host(test);
185062306a36Sopenharmony_ci	nhi = &host->ports[7];
185162306a36Sopenharmony_ci	port = &host->ports[1];
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, -1, -1, 15, 2);
185462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
185562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
185662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
185762306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
185862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 1);
185962306a36Sopenharmony_ci	/* RX path */
186062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
186162306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
186262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 15);
186362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, nhi);
186462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 2);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
186762306a36Sopenharmony_ci}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_cistatic void tb_test_tunnel_dma_tx(struct kunit *test)
187062306a36Sopenharmony_ci{
187162306a36Sopenharmony_ci	struct tb_port *nhi, *port;
187262306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
187362306a36Sopenharmony_ci	struct tb_switch *host;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	/*
187662306a36Sopenharmony_ci	 * Create DMA TX tunnel from NHI to port 1.
187762306a36Sopenharmony_ci	 *
187862306a36Sopenharmony_ci	 *   [Host 1]
187962306a36Sopenharmony_ci	 *    1 | In HopID 2 -> Out HopID 15
188062306a36Sopenharmony_ci	 *      |
188162306a36Sopenharmony_ci	 *      v
188262306a36Sopenharmony_ci	 * ............ Domain border
188362306a36Sopenharmony_ci	 *      |
188462306a36Sopenharmony_ci	 *   [Host 2]
188562306a36Sopenharmony_ci	 */
188662306a36Sopenharmony_ci	host = alloc_host(test);
188762306a36Sopenharmony_ci	nhi = &host->ports[7];
188862306a36Sopenharmony_ci	port = &host->ports[1];
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 2, -1, -1);
189162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
189262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
189362306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
189462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
189562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 1);
189662306a36Sopenharmony_ci	/* TX path */
189762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
189862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, nhi);
189962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 2);
190062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port, port);
190162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].next_hop_index, 15);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_cistatic void tb_test_tunnel_dma_chain(struct kunit *test)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	struct tb_switch *host, *dev1, *dev2;
190962306a36Sopenharmony_ci	struct tb_port *nhi, *port;
191062306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	/*
191362306a36Sopenharmony_ci	 * Create DMA tunnel from NHI to Device #2 port 3 and back.
191462306a36Sopenharmony_ci	 *
191562306a36Sopenharmony_ci	 *   [Host 1]
191662306a36Sopenharmony_ci	 *    1 ^ In HopID 1 -> Out HopID x
191762306a36Sopenharmony_ci	 *      |
191862306a36Sopenharmony_ci	 *    1 | In HopID x -> Out HopID 1
191962306a36Sopenharmony_ci	 *  [Device #1]
192062306a36Sopenharmony_ci	 *         7 \
192162306a36Sopenharmony_ci	 *          1 \
192262306a36Sopenharmony_ci	 *         [Device #2]
192362306a36Sopenharmony_ci	 *           3 | In HopID x -> Out HopID 8
192462306a36Sopenharmony_ci	 *             |
192562306a36Sopenharmony_ci	 *             v In HopID 8 -> Out HopID x
192662306a36Sopenharmony_ci	 * ............ Domain border
192762306a36Sopenharmony_ci	 *             |
192862306a36Sopenharmony_ci	 *          [Host 2]
192962306a36Sopenharmony_ci	 */
193062306a36Sopenharmony_ci	host = alloc_host(test);
193162306a36Sopenharmony_ci	dev1 = alloc_dev_default(test, host, 0x1, true);
193262306a36Sopenharmony_ci	dev2 = alloc_dev_default(test, dev1, 0x701, true);
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	nhi = &host->ports[7];
193562306a36Sopenharmony_ci	port = &dev2->ports[3];
193662306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
193762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
193862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
193962306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
194062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
194162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, 2);
194262306a36Sopenharmony_ci	/* RX path */
194362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3);
194462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
194562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[0].in_hop_index, 8);
194662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].out_port,
194762306a36Sopenharmony_ci			    &dev2->ports[1]);
194862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].in_port,
194962306a36Sopenharmony_ci			    &dev1->ports[7]);
195062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].out_port,
195162306a36Sopenharmony_ci			    &dev1->ports[1]);
195262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].in_port,
195362306a36Sopenharmony_ci			    &host->ports[1]);
195462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].out_port, nhi);
195562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[0]->hops[2].next_hop_index, 1);
195662306a36Sopenharmony_ci	/* TX path */
195762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 3);
195862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, nhi);
195962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[0].in_hop_index, 1);
196062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].in_port,
196162306a36Sopenharmony_ci			    &dev1->ports[1]);
196262306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].out_port,
196362306a36Sopenharmony_ci			    &dev1->ports[7]);
196462306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].in_port,
196562306a36Sopenharmony_ci			    &dev2->ports[1]);
196662306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].out_port, port);
196762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, tunnel->paths[1]->hops[2].next_hop_index, 8);
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cistatic void tb_test_tunnel_dma_match(struct kunit *test)
197362306a36Sopenharmony_ci{
197462306a36Sopenharmony_ci	struct tb_port *nhi, *port;
197562306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
197662306a36Sopenharmony_ci	struct tb_switch *host;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	host = alloc_host(test);
197962306a36Sopenharmony_ci	nhi = &host->ports[7];
198062306a36Sopenharmony_ci	port = &host->ports[1];
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 1, 15, 1);
198362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, 15, 1));
198662306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 8, 1, 15, 1));
198762306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1));
198862306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, -1, -1));
198962306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, -1, -1, -1));
199062306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, 1, -1, -1));
199162306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, -1));
199262306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, 1));
199362306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1));
199462306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 8, -1, 8, -1));
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 1, -1, -1);
199962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
200062306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, 1, -1, -1));
200162306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, 15, -1, -1, -1));
200262306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, 1, -1, -1));
200362306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1));
200462306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 1, 15, 1));
200562306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1));
200662306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 11, -1, -1));
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, -1, -1, 15, 11);
201162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
201262306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 11));
201362306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, -1));
201462306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, 11));
201562306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tb_tunnel_match_dma(tunnel, -1, -1, -1, -1));
201662306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 15, 1));
201762306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, -1, -1, 10, 11));
201862306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, tb_tunnel_match_dma(tunnel, 15, 11, -1, -1));
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic void tb_test_credit_alloc_legacy_not_bonded(struct kunit *test)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct tb_switch *host, *dev;
202662306a36Sopenharmony_ci	struct tb_port *up, *down;
202762306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
202862306a36Sopenharmony_ci	struct tb_path *path;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	host = alloc_host(test);
203162306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 0x1, false);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	down = &host->ports[8];
203462306a36Sopenharmony_ci	up = &dev->ports[9];
203562306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_pci(NULL, up, down);
203662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
203762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	path = tunnel->paths[0];
204062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
204162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
204262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
204362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
204462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 16U);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	path = tunnel->paths[1];
204762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
204862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
204962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
205062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
205162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 16U);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic void tb_test_credit_alloc_legacy_bonded(struct kunit *test)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct tb_switch *host, *dev;
205962306a36Sopenharmony_ci	struct tb_port *up, *down;
206062306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
206162306a36Sopenharmony_ci	struct tb_path *path;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	host = alloc_host(test);
206462306a36Sopenharmony_ci	dev = alloc_dev_default(test, host, 0x1, true);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	down = &host->ports[8];
206762306a36Sopenharmony_ci	up = &dev->ports[9];
206862306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_pci(NULL, up, down);
206962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
207062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	path = tunnel->paths[0];
207362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
207462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
207562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
207662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
207762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	path = tunnel->paths[1];
208062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
208162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
208262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
208362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
208462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic void tb_test_credit_alloc_pcie(struct kunit *test)
209062306a36Sopenharmony_ci{
209162306a36Sopenharmony_ci	struct tb_switch *host, *dev;
209262306a36Sopenharmony_ci	struct tb_port *up, *down;
209362306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
209462306a36Sopenharmony_ci	struct tb_path *path;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	host = alloc_host_usb4(test);
209762306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	down = &host->ports[8];
210062306a36Sopenharmony_ci	up = &dev->ports[9];
210162306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_pci(NULL, up, down);
210262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
210362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	path = tunnel->paths[0];
210662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
210762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
210862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
210962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
211062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	path = tunnel->paths[1];
211362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
211462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
211562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
211662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
211762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
212062306a36Sopenharmony_ci}
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_cistatic void tb_test_credit_alloc_without_dp(struct kunit *test)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	struct tb_switch *host, *dev;
212562306a36Sopenharmony_ci	struct tb_port *up, *down;
212662306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
212762306a36Sopenharmony_ci	struct tb_path *path;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	host = alloc_host_usb4(test);
213062306a36Sopenharmony_ci	dev = alloc_dev_without_dp(test, host, 0x1, true);
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	/*
213362306a36Sopenharmony_ci	 * The device has no DP therefore baMinDPmain = baMinDPaux = 0
213462306a36Sopenharmony_ci	 *
213562306a36Sopenharmony_ci	 * Create PCIe path with buffers less than baMaxPCIe.
213662306a36Sopenharmony_ci	 *
213762306a36Sopenharmony_ci	 * For a device with buffers configurations:
213862306a36Sopenharmony_ci	 * baMaxUSB3 = 109
213962306a36Sopenharmony_ci	 * baMinDPaux = 0
214062306a36Sopenharmony_ci	 * baMinDPmain = 0
214162306a36Sopenharmony_ci	 * baMaxPCIe = 30
214262306a36Sopenharmony_ci	 * baMaxHI = 1
214362306a36Sopenharmony_ci	 * Remaining Buffers = Total - (CP + DP) = 120 - (2 + 0) = 118
214462306a36Sopenharmony_ci	 * PCIe Credits = Max(6, Min(baMaxPCIe, Remaining Buffers - baMaxUSB3)
214562306a36Sopenharmony_ci	 *		= Max(6, Min(30, 9) = 9
214662306a36Sopenharmony_ci	 */
214762306a36Sopenharmony_ci	down = &host->ports[8];
214862306a36Sopenharmony_ci	up = &dev->ports[9];
214962306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_pci(NULL, up, down);
215062306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, tunnel != NULL);
215162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	/* PCIe downstream path */
215462306a36Sopenharmony_ci	path = tunnel->paths[0];
215562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
215662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
215762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
215862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
215962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 9U);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	/* PCIe upstream path */
216262306a36Sopenharmony_ci	path = tunnel->paths[1];
216362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
216462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
216562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
216662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
216762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
217062306a36Sopenharmony_ci}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_cistatic void tb_test_credit_alloc_dp(struct kunit *test)
217362306a36Sopenharmony_ci{
217462306a36Sopenharmony_ci	struct tb_switch *host, *dev;
217562306a36Sopenharmony_ci	struct tb_port *in, *out;
217662306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
217762306a36Sopenharmony_ci	struct tb_path *path;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	host = alloc_host_usb4(test);
218062306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	in = &host->ports[5];
218362306a36Sopenharmony_ci	out = &dev->ports[14];
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
218662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
218762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	/* Video (main) path */
219062306a36Sopenharmony_ci	path = tunnel->paths[0];
219162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
219262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
219362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
219462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
219562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	/* AUX TX */
219862306a36Sopenharmony_ci	path = tunnel->paths[1];
219962306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
220062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
220162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
220262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
220362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	/* AUX RX */
220662306a36Sopenharmony_ci	path = tunnel->paths[2];
220762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
220862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
220962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
221062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
221162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
221462306a36Sopenharmony_ci}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_cistatic void tb_test_credit_alloc_usb3(struct kunit *test)
221762306a36Sopenharmony_ci{
221862306a36Sopenharmony_ci	struct tb_switch *host, *dev;
221962306a36Sopenharmony_ci	struct tb_port *up, *down;
222062306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
222162306a36Sopenharmony_ci	struct tb_path *path;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	host = alloc_host_usb4(test);
222462306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	down = &host->ports[12];
222762306a36Sopenharmony_ci	up = &dev->ports[16];
222862306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
222962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
223062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	path = tunnel->paths[0];
223362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
223462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
223562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
223662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
223762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	path = tunnel->paths[1];
224062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
224162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
224262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
224362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
224462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
224762306a36Sopenharmony_ci}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_cistatic void tb_test_credit_alloc_dma(struct kunit *test)
225062306a36Sopenharmony_ci{
225162306a36Sopenharmony_ci	struct tb_switch *host, *dev;
225262306a36Sopenharmony_ci	struct tb_port *nhi, *port;
225362306a36Sopenharmony_ci	struct tb_tunnel *tunnel;
225462306a36Sopenharmony_ci	struct tb_path *path;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	host = alloc_host_usb4(test);
225762306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	nhi = &host->ports[7];
226062306a36Sopenharmony_ci	port = &dev->ports[3];
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
226362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel);
226462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	/* DMA RX */
226762306a36Sopenharmony_ci	path = tunnel->paths[0];
226862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
226962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
227062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
227162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
227262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	/* DMA TX */
227562306a36Sopenharmony_ci	path = tunnel->paths[1];
227662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
227762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
227862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
227962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
228062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	tb_tunnel_free(tunnel);
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_cistatic void tb_test_credit_alloc_dma_multiple(struct kunit *test)
228662306a36Sopenharmony_ci{
228762306a36Sopenharmony_ci	struct tb_tunnel *tunnel1, *tunnel2, *tunnel3;
228862306a36Sopenharmony_ci	struct tb_switch *host, *dev;
228962306a36Sopenharmony_ci	struct tb_port *nhi, *port;
229062306a36Sopenharmony_ci	struct tb_path *path;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	host = alloc_host_usb4(test);
229362306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	nhi = &host->ports[7];
229662306a36Sopenharmony_ci	port = &dev->ports[3];
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	/*
229962306a36Sopenharmony_ci	 * Create three DMA tunnels through the same ports. With the
230062306a36Sopenharmony_ci	 * default buffers we should be able to create two and the last
230162306a36Sopenharmony_ci	 * one fails.
230262306a36Sopenharmony_ci	 *
230362306a36Sopenharmony_ci	 * For default host we have following buffers for DMA:
230462306a36Sopenharmony_ci	 *
230562306a36Sopenharmony_ci	 *   120 - (2 + 2 * (1 + 0) + 32 + 64 + spare) = 20
230662306a36Sopenharmony_ci	 *
230762306a36Sopenharmony_ci	 * For device we have following:
230862306a36Sopenharmony_ci	 *
230962306a36Sopenharmony_ci	 *  120 - (2 + 2 * (1 + 18) + 14 + 32 + spare) = 34
231062306a36Sopenharmony_ci	 *
231162306a36Sopenharmony_ci	 * spare = 14 + 1 = 15
231262306a36Sopenharmony_ci	 *
231362306a36Sopenharmony_ci	 * So on host the first tunnel gets 14 and the second gets the
231462306a36Sopenharmony_ci	 * remaining 1 and then we run out of buffers.
231562306a36Sopenharmony_ci	 */
231662306a36Sopenharmony_ci	tunnel1 = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
231762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel1);
231862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2);
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	path = tunnel1->paths[0];
232162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
232262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
232362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
232462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
232562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	path = tunnel1->paths[1];
232862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
232962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
233062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
233162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
233262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	tunnel2 = tb_tunnel_alloc_dma(NULL, nhi, port, 9, 2, 9, 2);
233562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel2);
233662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	path = tunnel2->paths[0];
233962306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
234062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
234162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
234262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
234362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	path = tunnel2->paths[1];
234662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
234762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
234862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
234962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
235062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	tunnel3 = tb_tunnel_alloc_dma(NULL, nhi, port, 10, 3, 10, 3);
235362306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, tunnel3);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	/*
235662306a36Sopenharmony_ci	 * Release the first DMA tunnel. That should make 14 buffers
235762306a36Sopenharmony_ci	 * available for the next tunnel.
235862306a36Sopenharmony_ci	 */
235962306a36Sopenharmony_ci	tb_tunnel_free(tunnel1);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	tunnel3 = tb_tunnel_alloc_dma(NULL, nhi, port, 10, 3, 10, 3);
236262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, tunnel3);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	path = tunnel3->paths[0];
236562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
236662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
236762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
236862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
236962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	path = tunnel3->paths[1];
237262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
237362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
237462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
237562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
237662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	tb_tunnel_free(tunnel3);
237962306a36Sopenharmony_ci	tb_tunnel_free(tunnel2);
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_PCIE_TUNNEL(struct kunit *test,
238362306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
238462306a36Sopenharmony_ci{
238562306a36Sopenharmony_ci	struct tb_port *up, *down;
238662306a36Sopenharmony_ci	struct tb_tunnel *pcie_tunnel;
238762306a36Sopenharmony_ci	struct tb_path *path;
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	down = &host->ports[8];
239062306a36Sopenharmony_ci	up = &dev->ports[9];
239162306a36Sopenharmony_ci	pcie_tunnel = tb_tunnel_alloc_pci(NULL, up, down);
239262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, pcie_tunnel);
239362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, pcie_tunnel->npaths, (size_t)2);
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	path = pcie_tunnel->paths[0];
239662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
239762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
239862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
239962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
240062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	path = pcie_tunnel->paths[1];
240362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
240462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
240562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
240662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
240762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	return pcie_tunnel;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_DP_TUNNEL1(struct kunit *test,
241362306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
241462306a36Sopenharmony_ci{
241562306a36Sopenharmony_ci	struct tb_port *in, *out;
241662306a36Sopenharmony_ci	struct tb_tunnel *dp_tunnel1;
241762306a36Sopenharmony_ci	struct tb_path *path;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	in = &host->ports[5];
242062306a36Sopenharmony_ci	out = &dev->ports[13];
242162306a36Sopenharmony_ci	dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
242262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dp_tunnel1);
242362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, dp_tunnel1->npaths, (size_t)3);
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	path = dp_tunnel1->paths[0];
242662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
242762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
242862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
242962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
243062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	path = dp_tunnel1->paths[1];
243362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
243462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
243562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
243662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
243762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	path = dp_tunnel1->paths[2];
244062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
244162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
244262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
244362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
244462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	return dp_tunnel1;
244762306a36Sopenharmony_ci}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_DP_TUNNEL2(struct kunit *test,
245062306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
245162306a36Sopenharmony_ci{
245262306a36Sopenharmony_ci	struct tb_port *in, *out;
245362306a36Sopenharmony_ci	struct tb_tunnel *dp_tunnel2;
245462306a36Sopenharmony_ci	struct tb_path *path;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	in = &host->ports[6];
245762306a36Sopenharmony_ci	out = &dev->ports[14];
245862306a36Sopenharmony_ci	dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
245962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dp_tunnel2);
246062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, dp_tunnel2->npaths, (size_t)3);
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	path = dp_tunnel2->paths[0];
246362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
246462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
246562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
246662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
246762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	path = dp_tunnel2->paths[1];
247062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
247162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
247262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
247362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
247462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	path = dp_tunnel2->paths[2];
247762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
247862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
247962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
248062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
248162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	return dp_tunnel2;
248462306a36Sopenharmony_ci}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_USB3_TUNNEL(struct kunit *test,
248762306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
248862306a36Sopenharmony_ci{
248962306a36Sopenharmony_ci	struct tb_port *up, *down;
249062306a36Sopenharmony_ci	struct tb_tunnel *usb3_tunnel;
249162306a36Sopenharmony_ci	struct tb_path *path;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	down = &host->ports[12];
249462306a36Sopenharmony_ci	up = &dev->ports[16];
249562306a36Sopenharmony_ci	usb3_tunnel = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
249662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, usb3_tunnel);
249762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, usb3_tunnel->npaths, (size_t)2);
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	path = usb3_tunnel->paths[0];
250062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
250162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
250262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
250362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
250462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	path = usb3_tunnel->paths[1];
250762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
250862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
250962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
251062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
251162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	return usb3_tunnel;
251462306a36Sopenharmony_ci}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_DMA_TUNNEL1(struct kunit *test,
251762306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
251862306a36Sopenharmony_ci{
251962306a36Sopenharmony_ci	struct tb_port *nhi, *port;
252062306a36Sopenharmony_ci	struct tb_tunnel *dma_tunnel1;
252162306a36Sopenharmony_ci	struct tb_path *path;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	nhi = &host->ports[7];
252462306a36Sopenharmony_ci	port = &dev->ports[3];
252562306a36Sopenharmony_ci	dma_tunnel1 = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
252662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dma_tunnel1);
252762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, dma_tunnel1->npaths, (size_t)2);
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	path = dma_tunnel1->paths[0];
253062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
253162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
253262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
253362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
253462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	path = dma_tunnel1->paths[1];
253762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
253862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
253962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
254062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
254162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	return dma_tunnel1;
254462306a36Sopenharmony_ci}
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_cistatic struct tb_tunnel *TB_TEST_DMA_TUNNEL2(struct kunit *test,
254762306a36Sopenharmony_ci			struct tb_switch *host, struct tb_switch *dev)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	struct tb_port *nhi, *port;
255062306a36Sopenharmony_ci	struct tb_tunnel *dma_tunnel2;
255162306a36Sopenharmony_ci	struct tb_path *path;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	nhi = &host->ports[7];
255462306a36Sopenharmony_ci	port = &dev->ports[3];
255562306a36Sopenharmony_ci	dma_tunnel2 = tb_tunnel_alloc_dma(NULL, nhi, port, 9, 2, 9, 2);
255662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dma_tunnel2);
255762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, dma_tunnel2->npaths, (size_t)2);
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	path = dma_tunnel2->paths[0];
256062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
256162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
256262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
256362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
256462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	path = dma_tunnel2->paths[1];
256762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, path->path_length, 2);
256862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
256962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
257062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
257162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	return dma_tunnel2;
257462306a36Sopenharmony_ci}
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_cistatic void tb_test_credit_alloc_all(struct kunit *test)
257762306a36Sopenharmony_ci{
257862306a36Sopenharmony_ci	struct tb_tunnel *pcie_tunnel, *dp_tunnel1, *dp_tunnel2, *usb3_tunnel;
257962306a36Sopenharmony_ci	struct tb_tunnel *dma_tunnel1, *dma_tunnel2;
258062306a36Sopenharmony_ci	struct tb_switch *host, *dev;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	/*
258362306a36Sopenharmony_ci	 * Create PCIe, 2 x DP, USB 3.x and two DMA tunnels from host to
258462306a36Sopenharmony_ci	 * device. Expectation is that all these can be established with
258562306a36Sopenharmony_ci	 * the default credit allocation found in Intel hardware.
258662306a36Sopenharmony_ci	 */
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	host = alloc_host_usb4(test);
258962306a36Sopenharmony_ci	dev = alloc_dev_usb4(test, host, 0x1, true);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	pcie_tunnel = TB_TEST_PCIE_TUNNEL(test, host, dev);
259262306a36Sopenharmony_ci	dp_tunnel1 = TB_TEST_DP_TUNNEL1(test, host, dev);
259362306a36Sopenharmony_ci	dp_tunnel2 = TB_TEST_DP_TUNNEL2(test, host, dev);
259462306a36Sopenharmony_ci	usb3_tunnel = TB_TEST_USB3_TUNNEL(test, host, dev);
259562306a36Sopenharmony_ci	dma_tunnel1 = TB_TEST_DMA_TUNNEL1(test, host, dev);
259662306a36Sopenharmony_ci	dma_tunnel2 = TB_TEST_DMA_TUNNEL2(test, host, dev);
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci	tb_tunnel_free(dma_tunnel2);
259962306a36Sopenharmony_ci	tb_tunnel_free(dma_tunnel1);
260062306a36Sopenharmony_ci	tb_tunnel_free(usb3_tunnel);
260162306a36Sopenharmony_ci	tb_tunnel_free(dp_tunnel2);
260262306a36Sopenharmony_ci	tb_tunnel_free(dp_tunnel1);
260362306a36Sopenharmony_ci	tb_tunnel_free(pcie_tunnel);
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic const u32 root_directory[] = {
260762306a36Sopenharmony_ci	0x55584401,	/* "UXD" v1 */
260862306a36Sopenharmony_ci	0x00000018,	/* Root directory length */
260962306a36Sopenharmony_ci	0x76656e64,	/* "vend" */
261062306a36Sopenharmony_ci	0x6f726964,	/* "orid" */
261162306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
261262306a36Sopenharmony_ci	0x00000a27,	/* Immediate value, ! Vendor ID */
261362306a36Sopenharmony_ci	0x76656e64,	/* "vend" */
261462306a36Sopenharmony_ci	0x6f726964,	/* "orid" */
261562306a36Sopenharmony_ci	0x74000003,	/* "t" R 3 */
261662306a36Sopenharmony_ci	0x0000001a,	/* Text leaf offset, (“Apple Inc.”) */
261762306a36Sopenharmony_ci	0x64657669,	/* "devi" */
261862306a36Sopenharmony_ci	0x63656964,	/* "ceid" */
261962306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
262062306a36Sopenharmony_ci	0x0000000a,	/* Immediate value, ! Device ID */
262162306a36Sopenharmony_ci	0x64657669,	/* "devi" */
262262306a36Sopenharmony_ci	0x63656964,	/* "ceid" */
262362306a36Sopenharmony_ci	0x74000003,	/* "t" R 3 */
262462306a36Sopenharmony_ci	0x0000001d,	/* Text leaf offset, (“Macintosh”) */
262562306a36Sopenharmony_ci	0x64657669,	/* "devi" */
262662306a36Sopenharmony_ci	0x63657276,	/* "cerv" */
262762306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
262862306a36Sopenharmony_ci	0x80000100,	/* Immediate value, Device Revision */
262962306a36Sopenharmony_ci	0x6e657477,	/* "netw" */
263062306a36Sopenharmony_ci	0x6f726b00,	/* "ork" */
263162306a36Sopenharmony_ci	0x44000014,	/* "D" R 20 */
263262306a36Sopenharmony_ci	0x00000021,	/* Directory data offset, (Network Directory) */
263362306a36Sopenharmony_ci	0x4170706c,	/* "Appl" */
263462306a36Sopenharmony_ci	0x6520496e,	/* "e In" */
263562306a36Sopenharmony_ci	0x632e0000,	/* "c." ! */
263662306a36Sopenharmony_ci	0x4d616369,	/* "Maci" */
263762306a36Sopenharmony_ci	0x6e746f73,	/* "ntos" */
263862306a36Sopenharmony_ci	0x68000000,	/* "h" */
263962306a36Sopenharmony_ci	0x00000000,	/* padding */
264062306a36Sopenharmony_ci	0xca8961c6,	/* Directory UUID, Network Directory */
264162306a36Sopenharmony_ci	0x9541ce1c,	/* Directory UUID, Network Directory */
264262306a36Sopenharmony_ci	0x5949b8bd,	/* Directory UUID, Network Directory */
264362306a36Sopenharmony_ci	0x4f5a5f2e,	/* Directory UUID, Network Directory */
264462306a36Sopenharmony_ci	0x70727463,	/* "prtc" */
264562306a36Sopenharmony_ci	0x69640000,	/* "id" */
264662306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
264762306a36Sopenharmony_ci	0x00000001,	/* Immediate value, Network Protocol ID */
264862306a36Sopenharmony_ci	0x70727463,	/* "prtc" */
264962306a36Sopenharmony_ci	0x76657273,	/* "vers" */
265062306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
265162306a36Sopenharmony_ci	0x00000001,	/* Immediate value, Network Protocol Version */
265262306a36Sopenharmony_ci	0x70727463,	/* "prtc" */
265362306a36Sopenharmony_ci	0x72657673,	/* "revs" */
265462306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
265562306a36Sopenharmony_ci	0x00000001,	/* Immediate value, Network Protocol Revision */
265662306a36Sopenharmony_ci	0x70727463,	/* "prtc" */
265762306a36Sopenharmony_ci	0x73746e73,	/* "stns" */
265862306a36Sopenharmony_ci	0x76000001,	/* "v" R 1 */
265962306a36Sopenharmony_ci	0x00000000,	/* Immediate value, Network Protocol Settings */
266062306a36Sopenharmony_ci};
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_cistatic const uuid_t network_dir_uuid =
266362306a36Sopenharmony_ci	UUID_INIT(0xc66189ca, 0x1cce, 0x4195,
266462306a36Sopenharmony_ci		  0xbd, 0xb8, 0x49, 0x59, 0x2e, 0x5f, 0x5a, 0x4f);
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_cistatic void tb_test_property_parse(struct kunit *test)
266762306a36Sopenharmony_ci{
266862306a36Sopenharmony_ci	struct tb_property_dir *dir, *network_dir;
266962306a36Sopenharmony_ci	struct tb_property *p;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	dir = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory));
267262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dir);
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	p = tb_property_find(dir, "foo", TB_PROPERTY_TYPE_TEXT);
267562306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, p);
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_TEXT);
267862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
267962306a36Sopenharmony_ci	KUNIT_EXPECT_STREQ(test, p->value.text, "Apple Inc.");
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_VALUE);
268262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
268362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0xa27);
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_TEXT);
268662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
268762306a36Sopenharmony_ci	KUNIT_EXPECT_STREQ(test, p->value.text, "Macintosh");
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_VALUE);
269062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
269162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0xa);
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	p = tb_property_find(dir, "missing", TB_PROPERTY_TYPE_DIRECTORY);
269462306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, p);
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	p = tb_property_find(dir, "network", TB_PROPERTY_TYPE_DIRECTORY);
269762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	network_dir = p->value.dir;
270062306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, uuid_equal(network_dir->uuid, &network_dir_uuid));
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	p = tb_property_find(network_dir, "prtcid", TB_PROPERTY_TYPE_VALUE);
270362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
270462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	p = tb_property_find(network_dir, "prtcvers", TB_PROPERTY_TYPE_VALUE);
270762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
270862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	p = tb_property_find(network_dir, "prtcrevs", TB_PROPERTY_TYPE_VALUE);
271162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
271262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	p = tb_property_find(network_dir, "prtcstns", TB_PROPERTY_TYPE_VALUE);
271562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, p);
271662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, p->value.immediate, 0x0);
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	p = tb_property_find(network_dir, "deviceid", TB_PROPERTY_TYPE_VALUE);
271962306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !p);
272062306a36Sopenharmony_ci	p = tb_property_find(network_dir, "deviceid", TB_PROPERTY_TYPE_TEXT);
272162306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !p);
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	tb_property_free_dir(dir);
272462306a36Sopenharmony_ci}
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_cistatic void tb_test_property_format(struct kunit *test)
272762306a36Sopenharmony_ci{
272862306a36Sopenharmony_ci	struct tb_property_dir *dir;
272962306a36Sopenharmony_ci	ssize_t block_len;
273062306a36Sopenharmony_ci	u32 *block;
273162306a36Sopenharmony_ci	int ret, i;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	dir = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory));
273462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dir);
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	ret = tb_property_format_dir(dir, NULL, 0);
273762306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(root_directory));
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	block_len = ret;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	block = kunit_kzalloc(test, block_len * sizeof(u32), GFP_KERNEL);
274262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, block);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	ret = tb_property_format_dir(dir, block, block_len);
274562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, ret, 0);
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(root_directory); i++)
274862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, root_directory[i], block[i]);
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	tb_property_free_dir(dir);
275162306a36Sopenharmony_ci}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_cistatic void compare_dirs(struct kunit *test, struct tb_property_dir *d1,
275462306a36Sopenharmony_ci			 struct tb_property_dir *d2)
275562306a36Sopenharmony_ci{
275662306a36Sopenharmony_ci	struct tb_property *p1, *p2, *tmp;
275762306a36Sopenharmony_ci	int n1, n2, i;
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	if (d1->uuid) {
276062306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_NULL(test, d2->uuid);
276162306a36Sopenharmony_ci		KUNIT_ASSERT_TRUE(test, uuid_equal(d1->uuid, d2->uuid));
276262306a36Sopenharmony_ci	} else {
276362306a36Sopenharmony_ci		KUNIT_ASSERT_NULL(test, d2->uuid);
276462306a36Sopenharmony_ci	}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	n1 = 0;
276762306a36Sopenharmony_ci	tb_property_for_each(d1, tmp)
276862306a36Sopenharmony_ci		n1++;
276962306a36Sopenharmony_ci	KUNIT_ASSERT_NE(test, n1, 0);
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	n2 = 0;
277262306a36Sopenharmony_ci	tb_property_for_each(d2, tmp)
277362306a36Sopenharmony_ci		n2++;
277462306a36Sopenharmony_ci	KUNIT_ASSERT_NE(test, n2, 0);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, n1, n2);
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	p1 = NULL;
277962306a36Sopenharmony_ci	p2 = NULL;
278062306a36Sopenharmony_ci	for (i = 0; i < n1; i++) {
278162306a36Sopenharmony_ci		p1 = tb_property_get_next(d1, p1);
278262306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_NULL(test, p1);
278362306a36Sopenharmony_ci		p2 = tb_property_get_next(d2, p2);
278462306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_NULL(test, p2);
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci		KUNIT_ASSERT_STREQ(test, &p1->key[0], &p2->key[0]);
278762306a36Sopenharmony_ci		KUNIT_ASSERT_EQ(test, p1->type, p2->type);
278862306a36Sopenharmony_ci		KUNIT_ASSERT_EQ(test, p1->length, p2->length);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci		switch (p1->type) {
279162306a36Sopenharmony_ci		case TB_PROPERTY_TYPE_DIRECTORY:
279262306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p1->value.dir);
279362306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p2->value.dir);
279462306a36Sopenharmony_ci			compare_dirs(test, p1->value.dir, p2->value.dir);
279562306a36Sopenharmony_ci			break;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci		case TB_PROPERTY_TYPE_DATA:
279862306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p1->value.data);
279962306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p2->value.data);
280062306a36Sopenharmony_ci			KUNIT_ASSERT_TRUE(test,
280162306a36Sopenharmony_ci				!memcmp(p1->value.data, p2->value.data,
280262306a36Sopenharmony_ci					p1->length * 4)
280362306a36Sopenharmony_ci			);
280462306a36Sopenharmony_ci			break;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		case TB_PROPERTY_TYPE_TEXT:
280762306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p1->value.text);
280862306a36Sopenharmony_ci			KUNIT_ASSERT_NOT_NULL(test, p2->value.text);
280962306a36Sopenharmony_ci			KUNIT_ASSERT_STREQ(test, p1->value.text, p2->value.text);
281062306a36Sopenharmony_ci			break;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci		case TB_PROPERTY_TYPE_VALUE:
281362306a36Sopenharmony_ci			KUNIT_ASSERT_EQ(test, p1->value.immediate,
281462306a36Sopenharmony_ci					p2->value.immediate);
281562306a36Sopenharmony_ci			break;
281662306a36Sopenharmony_ci		default:
281762306a36Sopenharmony_ci			KUNIT_FAIL(test, "unexpected property type");
281862306a36Sopenharmony_ci			break;
281962306a36Sopenharmony_ci		}
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_cistatic void tb_test_property_copy(struct kunit *test)
282462306a36Sopenharmony_ci{
282562306a36Sopenharmony_ci	struct tb_property_dir *src, *dst;
282662306a36Sopenharmony_ci	u32 *block;
282762306a36Sopenharmony_ci	int ret, i;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	src = tb_property_parse_dir(root_directory, ARRAY_SIZE(root_directory));
283062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, src);
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	dst = tb_property_copy_dir(src);
283362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, dst);
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	/* Compare the structures */
283662306a36Sopenharmony_ci	compare_dirs(test, src, dst);
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	/* Compare the resulting property block */
283962306a36Sopenharmony_ci	ret = tb_property_format_dir(dst, NULL, 0);
284062306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(root_directory));
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	block = kunit_kzalloc(test, sizeof(root_directory), GFP_KERNEL);
284362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, block);
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	ret = tb_property_format_dir(dst, block, ARRAY_SIZE(root_directory));
284662306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, !ret);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(root_directory); i++)
284962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, root_directory[i], block[i]);
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	tb_property_free_dir(dst);
285262306a36Sopenharmony_ci	tb_property_free_dir(src);
285362306a36Sopenharmony_ci}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_cistatic struct kunit_case tb_test_cases[] = {
285662306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_basic),
285762306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_connected_walk),
285862306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_single_hop_walk),
285962306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_daisy_chain_walk),
286062306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_simple_tree_walk),
286162306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_complex_tree_walk),
286262306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_max_length_walk),
286362306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_connected),
286462306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_bonded_lane0),
286562306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_bonded_lane1),
286662306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_bonded_lane1_chain),
286762306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_not_bonded_lane1_chain_reverse),
286862306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_mixed_chain),
286962306a36Sopenharmony_ci	KUNIT_CASE(tb_test_path_mixed_chain_reverse),
287062306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_pcie),
287162306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dp),
287262306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dp_chain),
287362306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dp_tree),
287462306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dp_max_length),
287562306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_3dp),
287662306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_port_on_path),
287762306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_usb3),
287862306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dma),
287962306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dma_rx),
288062306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dma_tx),
288162306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dma_chain),
288262306a36Sopenharmony_ci	KUNIT_CASE(tb_test_tunnel_dma_match),
288362306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_legacy_not_bonded),
288462306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_legacy_bonded),
288562306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_pcie),
288662306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_without_dp),
288762306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_dp),
288862306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_usb3),
288962306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_dma),
289062306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_dma_multiple),
289162306a36Sopenharmony_ci	KUNIT_CASE(tb_test_credit_alloc_all),
289262306a36Sopenharmony_ci	KUNIT_CASE(tb_test_property_parse),
289362306a36Sopenharmony_ci	KUNIT_CASE(tb_test_property_format),
289462306a36Sopenharmony_ci	KUNIT_CASE(tb_test_property_copy),
289562306a36Sopenharmony_ci	{ }
289662306a36Sopenharmony_ci};
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_cistatic struct kunit_suite tb_test_suite = {
289962306a36Sopenharmony_ci	.name = "thunderbolt",
290062306a36Sopenharmony_ci	.test_cases = tb_test_cases,
290162306a36Sopenharmony_ci};
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_cikunit_test_suite(tb_test_suite);
2904