xref: /linux/drivers/gpu/drm/xe/tests/xe_guc_g2g_test.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*456b32c9SJohn Harrison // SPDX-License-Identifier: GPL-2.0 AND MIT
2*456b32c9SJohn Harrison /*
3*456b32c9SJohn Harrison  * Copyright © 2025 Intel Corporation
4*456b32c9SJohn Harrison  */
5*456b32c9SJohn Harrison 
6*456b32c9SJohn Harrison #include <linux/delay.h>
7*456b32c9SJohn Harrison 
8*456b32c9SJohn Harrison #include <kunit/test.h>
9*456b32c9SJohn Harrison #include <kunit/visibility.h>
10*456b32c9SJohn Harrison 
11*456b32c9SJohn Harrison #include "tests/xe_kunit_helpers.h"
12*456b32c9SJohn Harrison #include "tests/xe_pci_test.h"
13*456b32c9SJohn Harrison #include "tests/xe_test.h"
14*456b32c9SJohn Harrison 
15*456b32c9SJohn Harrison #include "xe_bo.h"
16*456b32c9SJohn Harrison #include "xe_device.h"
17*456b32c9SJohn Harrison #include "xe_pm.h"
18*456b32c9SJohn Harrison 
19*456b32c9SJohn Harrison /*
20*456b32c9SJohn Harrison  * There are different ways to allocate the G2G buffers. The plan for this test
21*456b32c9SJohn Harrison  * is to make sure that all the possible options work. The particular option
22*456b32c9SJohn Harrison  * chosen by the driver may vary from one platform to another, it may also change
23*456b32c9SJohn Harrison  * with time. So to ensure consistency of testing, the relevant driver code is
24*456b32c9SJohn Harrison  * replicated here to guarantee it won't change without the test being updated
25*456b32c9SJohn Harrison  * to keep testing the other options.
26*456b32c9SJohn Harrison  *
27*456b32c9SJohn Harrison  * In order to test the actual code being used by the driver, there is also the
28*456b32c9SJohn Harrison  * 'default' scheme. That will use the official driver routines to test whatever
29*456b32c9SJohn Harrison  * method the driver is using on the current platform at the current time.
30*456b32c9SJohn Harrison  */
31*456b32c9SJohn Harrison enum {
32*456b32c9SJohn Harrison 	/* Driver defined allocation scheme */
33*456b32c9SJohn Harrison 	G2G_CTB_TYPE_DEFAULT,
34*456b32c9SJohn Harrison 	/* Single buffer in host memory */
35*456b32c9SJohn Harrison 	G2G_CTB_TYPE_HOST,
36*456b32c9SJohn Harrison 	/* Single buffer in a specific tile, loops across all tiles */
37*456b32c9SJohn Harrison 	G2G_CTB_TYPE_TILE,
38*456b32c9SJohn Harrison };
39*456b32c9SJohn Harrison 
40*456b32c9SJohn Harrison /*
41*456b32c9SJohn Harrison  * Payload is opaque to GuC. So KMD can define any structure or size it wants.
42*456b32c9SJohn Harrison  */
43*456b32c9SJohn Harrison struct g2g_test_payload  {
44*456b32c9SJohn Harrison 	u32 tx_dev;
45*456b32c9SJohn Harrison 	u32 tx_tile;
46*456b32c9SJohn Harrison 	u32 rx_dev;
47*456b32c9SJohn Harrison 	u32 rx_tile;
48*456b32c9SJohn Harrison 	u32 seqno;
49*456b32c9SJohn Harrison };
50*456b32c9SJohn Harrison 
51*456b32c9SJohn Harrison static void g2g_test_send(struct kunit *test, struct xe_guc *guc,
52*456b32c9SJohn Harrison 			  u32 far_tile, u32 far_dev,
53*456b32c9SJohn Harrison 			  struct g2g_test_payload *payload)
54*456b32c9SJohn Harrison {
55*456b32c9SJohn Harrison 	struct xe_device *xe = guc_to_xe(guc);
56*456b32c9SJohn Harrison 	struct xe_gt *gt = guc_to_gt(guc);
57*456b32c9SJohn Harrison 	u32 *action, total;
58*456b32c9SJohn Harrison 	size_t payload_len;
59*456b32c9SJohn Harrison 	int ret;
60*456b32c9SJohn Harrison 
61*456b32c9SJohn Harrison 	static_assert(IS_ALIGNED(sizeof(*payload), sizeof(u32)));
62*456b32c9SJohn Harrison 	payload_len = sizeof(*payload) / sizeof(u32);
63*456b32c9SJohn Harrison 
64*456b32c9SJohn Harrison 	total = 4 + payload_len;
65*456b32c9SJohn Harrison 	action = kunit_kmalloc_array(test, total, sizeof(*action), GFP_KERNEL);
66*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, action);
67*456b32c9SJohn Harrison 
68*456b32c9SJohn Harrison 	action[0] = XE_GUC_ACTION_TEST_G2G_SEND;
69*456b32c9SJohn Harrison 	action[1] = far_tile;
70*456b32c9SJohn Harrison 	action[2] = far_dev;
71*456b32c9SJohn Harrison 	action[3] = payload_len;
72*456b32c9SJohn Harrison 	memcpy(action + 4, payload, payload_len * sizeof(u32));
73*456b32c9SJohn Harrison 
74*456b32c9SJohn Harrison 	atomic_inc(&xe->g2g_test_count);
75*456b32c9SJohn Harrison 
76*456b32c9SJohn Harrison 	/*
77*456b32c9SJohn Harrison 	 * Should specify the expected response notification here. Problem is that
78*456b32c9SJohn Harrison 	 * the response will be coming from a different GuC. By the end, it should
79*456b32c9SJohn Harrison 	 * all add up as long as an equal number of messages are sent from each GuC
80*456b32c9SJohn Harrison 	 * and to each GuC. However, in the middle negative reservation space errors
81*456b32c9SJohn Harrison 	 * and such like can occur. Rather than add intrusive changes to the CT layer
82*456b32c9SJohn Harrison 	 * it is simpler to just not bother counting it at all. The system should be
83*456b32c9SJohn Harrison 	 * idle when running the selftest, and the selftest's notification total size
84*456b32c9SJohn Harrison 	 * is well within the G2H allocation size. So there should be no issues with
85*456b32c9SJohn Harrison 	 * needing to block for space, which is all the tracking code is really for.
86*456b32c9SJohn Harrison 	 */
87*456b32c9SJohn Harrison 	ret = xe_guc_ct_send(&guc->ct, action, total, 0, 0);
88*456b32c9SJohn Harrison 	kunit_kfree(test, action);
89*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G send failed: %d [%d:%d -> %d:%d]\n", ret,
90*456b32c9SJohn Harrison 			    gt_to_tile(gt)->id, G2G_DEV(gt), far_tile, far_dev);
91*456b32c9SJohn Harrison }
92*456b32c9SJohn Harrison 
93*456b32c9SJohn Harrison /*
94*456b32c9SJohn Harrison  * NB: Can't use KUNIT_ASSERT and friends in here as this is called asynchronously
95*456b32c9SJohn Harrison  * from the G2H notification handler. Need that to actually complete rather than
96*456b32c9SJohn Harrison  * thread-abort in order to keep the rest of the driver alive!
97*456b32c9SJohn Harrison  */
98*456b32c9SJohn Harrison int xe_guc_g2g_test_notification(struct xe_guc *guc, u32 *msg, u32 len)
99*456b32c9SJohn Harrison {
100*456b32c9SJohn Harrison 	struct xe_device *xe = guc_to_xe(guc);
101*456b32c9SJohn Harrison 	struct xe_gt *rx_gt = guc_to_gt(guc), *test_gt, *tx_gt = NULL;
102*456b32c9SJohn Harrison 	u32 tx_tile, tx_dev, rx_tile, rx_dev, idx, got_len;
103*456b32c9SJohn Harrison 	struct g2g_test_payload *payload;
104*456b32c9SJohn Harrison 	size_t payload_len;
105*456b32c9SJohn Harrison 	int ret = 0, i;
106*456b32c9SJohn Harrison 
107*456b32c9SJohn Harrison 	payload_len = sizeof(*payload) / sizeof(u32);
108*456b32c9SJohn Harrison 
109*456b32c9SJohn Harrison 	if (unlikely(len != (G2H_LEN_DW_G2G_NOTIFY_MIN + payload_len))) {
110*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G test notification invalid length %u", len);
111*456b32c9SJohn Harrison 		ret = -EPROTO;
112*456b32c9SJohn Harrison 		goto done;
113*456b32c9SJohn Harrison 	}
114*456b32c9SJohn Harrison 
115*456b32c9SJohn Harrison 	tx_tile = msg[0];
116*456b32c9SJohn Harrison 	tx_dev = msg[1];
117*456b32c9SJohn Harrison 	got_len = msg[2];
118*456b32c9SJohn Harrison 	payload = (struct g2g_test_payload *)(msg + 3);
119*456b32c9SJohn Harrison 
120*456b32c9SJohn Harrison 	rx_tile = gt_to_tile(rx_gt)->id;
121*456b32c9SJohn Harrison 	rx_dev = G2G_DEV(rx_gt);
122*456b32c9SJohn Harrison 
123*456b32c9SJohn Harrison 	if (got_len != payload_len) {
124*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G: Invalid payload length: %u vs %zu\n", got_len, payload_len);
125*456b32c9SJohn Harrison 		ret = -EPROTO;
126*456b32c9SJohn Harrison 		goto done;
127*456b32c9SJohn Harrison 	}
128*456b32c9SJohn Harrison 
129*456b32c9SJohn Harrison 	if (payload->tx_dev != tx_dev || payload->tx_tile != tx_tile ||
130*456b32c9SJohn Harrison 	    payload->rx_dev != rx_dev || payload->rx_tile != rx_tile) {
131*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G: Invalid payload: %d:%d -> %d:%d vs %d:%d -> %d:%d! [%d]\n",
132*456b32c9SJohn Harrison 			  payload->tx_tile, payload->tx_dev, payload->rx_tile, payload->rx_dev,
133*456b32c9SJohn Harrison 			  tx_tile, tx_dev, rx_tile, rx_dev, payload->seqno);
134*456b32c9SJohn Harrison 		ret = -EPROTO;
135*456b32c9SJohn Harrison 		goto done;
136*456b32c9SJohn Harrison 	}
137*456b32c9SJohn Harrison 
138*456b32c9SJohn Harrison 	if (!xe->g2g_test_array) {
139*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G: Missing test array!\n");
140*456b32c9SJohn Harrison 		ret = -ENOMEM;
141*456b32c9SJohn Harrison 		goto done;
142*456b32c9SJohn Harrison 	}
143*456b32c9SJohn Harrison 
144*456b32c9SJohn Harrison 	for_each_gt(test_gt, xe, i) {
145*456b32c9SJohn Harrison 		if (gt_to_tile(test_gt)->id != tx_tile)
146*456b32c9SJohn Harrison 			continue;
147*456b32c9SJohn Harrison 
148*456b32c9SJohn Harrison 		if (G2G_DEV(test_gt) != tx_dev)
149*456b32c9SJohn Harrison 			continue;
150*456b32c9SJohn Harrison 
151*456b32c9SJohn Harrison 		if (tx_gt) {
152*456b32c9SJohn Harrison 			xe_gt_err(rx_gt, "G2G: Got duplicate TX GTs: %d vs %d for %d:%d!\n",
153*456b32c9SJohn Harrison 				  tx_gt->info.id, test_gt->info.id, tx_tile, tx_dev);
154*456b32c9SJohn Harrison 			ret = -EINVAL;
155*456b32c9SJohn Harrison 			goto done;
156*456b32c9SJohn Harrison 		}
157*456b32c9SJohn Harrison 
158*456b32c9SJohn Harrison 		tx_gt = test_gt;
159*456b32c9SJohn Harrison 	}
160*456b32c9SJohn Harrison 	if (!tx_gt) {
161*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G: Failed to find a TX GT for %d:%d!\n", tx_tile, tx_dev);
162*456b32c9SJohn Harrison 		ret = -EINVAL;
163*456b32c9SJohn Harrison 		goto done;
164*456b32c9SJohn Harrison 	}
165*456b32c9SJohn Harrison 
166*456b32c9SJohn Harrison 	idx = (tx_gt->info.id * xe->info.gt_count) + rx_gt->info.id;
167*456b32c9SJohn Harrison 
168*456b32c9SJohn Harrison 	if (xe->g2g_test_array[idx] != payload->seqno - 1) {
169*456b32c9SJohn Harrison 		xe_gt_err(rx_gt, "G2G: Seqno mismatch %d vs %d for %d:%d -> %d:%d!\n",
170*456b32c9SJohn Harrison 			  xe->g2g_test_array[idx], payload->seqno - 1,
171*456b32c9SJohn Harrison 			  tx_tile, tx_dev, rx_tile, rx_dev);
172*456b32c9SJohn Harrison 		ret = -EINVAL;
173*456b32c9SJohn Harrison 		goto done;
174*456b32c9SJohn Harrison 	}
175*456b32c9SJohn Harrison 
176*456b32c9SJohn Harrison 	xe->g2g_test_array[idx] = payload->seqno;
177*456b32c9SJohn Harrison 
178*456b32c9SJohn Harrison done:
179*456b32c9SJohn Harrison 	atomic_dec(&xe->g2g_test_count);
180*456b32c9SJohn Harrison 	return ret;
181*456b32c9SJohn Harrison }
182*456b32c9SJohn Harrison 
183*456b32c9SJohn Harrison /*
184*456b32c9SJohn Harrison  * Send the given seqno from all GuCs to all other GuCs in tile/GT order
185*456b32c9SJohn Harrison  */
186*456b32c9SJohn Harrison static void g2g_test_in_order(struct kunit *test, struct xe_device *xe, u32 seqno)
187*456b32c9SJohn Harrison {
188*456b32c9SJohn Harrison 	struct xe_gt *near_gt, *far_gt;
189*456b32c9SJohn Harrison 	int i, j;
190*456b32c9SJohn Harrison 
191*456b32c9SJohn Harrison 	for_each_gt(near_gt, xe, i) {
192*456b32c9SJohn Harrison 		u32 near_tile = gt_to_tile(near_gt)->id;
193*456b32c9SJohn Harrison 		u32 near_dev = G2G_DEV(near_gt);
194*456b32c9SJohn Harrison 
195*456b32c9SJohn Harrison 		for_each_gt(far_gt, xe, j) {
196*456b32c9SJohn Harrison 			u32 far_tile = gt_to_tile(far_gt)->id;
197*456b32c9SJohn Harrison 			u32 far_dev = G2G_DEV(far_gt);
198*456b32c9SJohn Harrison 			struct g2g_test_payload payload;
199*456b32c9SJohn Harrison 
200*456b32c9SJohn Harrison 			if (far_gt->info.id == near_gt->info.id)
201*456b32c9SJohn Harrison 				continue;
202*456b32c9SJohn Harrison 
203*456b32c9SJohn Harrison 			payload.tx_dev = near_dev;
204*456b32c9SJohn Harrison 			payload.tx_tile = near_tile;
205*456b32c9SJohn Harrison 			payload.rx_dev = far_dev;
206*456b32c9SJohn Harrison 			payload.rx_tile = far_tile;
207*456b32c9SJohn Harrison 			payload.seqno = seqno;
208*456b32c9SJohn Harrison 			g2g_test_send(test, &near_gt->uc.guc, far_tile, far_dev, &payload);
209*456b32c9SJohn Harrison 		}
210*456b32c9SJohn Harrison 	}
211*456b32c9SJohn Harrison }
212*456b32c9SJohn Harrison 
213*456b32c9SJohn Harrison #define WAIT_TIME_MS	100
214*456b32c9SJohn Harrison #define WAIT_COUNT	(1000 / WAIT_TIME_MS)
215*456b32c9SJohn Harrison 
216*456b32c9SJohn Harrison static void g2g_wait_for_complete(void *_xe)
217*456b32c9SJohn Harrison {
218*456b32c9SJohn Harrison 	struct xe_device *xe = (struct xe_device *)_xe;
219*456b32c9SJohn Harrison 	struct kunit *test = kunit_get_current_test();
220*456b32c9SJohn Harrison 	int wait = 0;
221*456b32c9SJohn Harrison 
222*456b32c9SJohn Harrison 	/* Wait for all G2H messages to be received */
223*456b32c9SJohn Harrison 	while (atomic_read(&xe->g2g_test_count)) {
224*456b32c9SJohn Harrison 		if (++wait > WAIT_COUNT)
225*456b32c9SJohn Harrison 			break;
226*456b32c9SJohn Harrison 
227*456b32c9SJohn Harrison 		msleep(WAIT_TIME_MS);
228*456b32c9SJohn Harrison 	}
229*456b32c9SJohn Harrison 
230*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, atomic_read(&xe->g2g_test_count),
231*456b32c9SJohn Harrison 			    "Timed out waiting for notifications\n");
232*456b32c9SJohn Harrison 	kunit_info(test, "Got all notifications back\n");
233*456b32c9SJohn Harrison }
234*456b32c9SJohn Harrison 
235*456b32c9SJohn Harrison #undef WAIT_TIME_MS
236*456b32c9SJohn Harrison #undef WAIT_COUNT
237*456b32c9SJohn Harrison 
238*456b32c9SJohn Harrison static void g2g_clean_array(void *_xe)
239*456b32c9SJohn Harrison {
240*456b32c9SJohn Harrison 	struct xe_device *xe = (struct xe_device *)_xe;
241*456b32c9SJohn Harrison 
242*456b32c9SJohn Harrison 	xe->g2g_test_array = NULL;
243*456b32c9SJohn Harrison }
244*456b32c9SJohn Harrison 
245*456b32c9SJohn Harrison #define NUM_LOOPS	16
246*456b32c9SJohn Harrison 
247*456b32c9SJohn Harrison static void g2g_run_test(struct kunit *test, struct xe_device *xe)
248*456b32c9SJohn Harrison {
249*456b32c9SJohn Harrison 	u32 seqno, max_array;
250*456b32c9SJohn Harrison 	int ret, i, j;
251*456b32c9SJohn Harrison 
252*456b32c9SJohn Harrison 	max_array = xe->info.gt_count * xe->info.gt_count;
253*456b32c9SJohn Harrison 	xe->g2g_test_array = kunit_kcalloc(test, max_array, sizeof(u32), GFP_KERNEL);
254*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe->g2g_test_array);
255*456b32c9SJohn Harrison 
256*456b32c9SJohn Harrison 	ret = kunit_add_action_or_reset(test, g2g_clean_array, xe);
257*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n");
258*456b32c9SJohn Harrison 
259*456b32c9SJohn Harrison 	/*
260*456b32c9SJohn Harrison 	 * Send incrementing seqnos from all GuCs to all other GuCs in tile/GT order.
261*456b32c9SJohn Harrison 	 * Tile/GT order doesn't really mean anything to the hardware but it is going
262*456b32c9SJohn Harrison 	 * to be a fixed sequence every time.
263*456b32c9SJohn Harrison 	 *
264*456b32c9SJohn Harrison 	 * Verify that each one comes back having taken the correct route.
265*456b32c9SJohn Harrison 	 */
266*456b32c9SJohn Harrison 	ret = kunit_add_action(test, g2g_wait_for_complete, xe);
267*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n");
268*456b32c9SJohn Harrison 	for (seqno = 1; seqno < NUM_LOOPS; seqno++)
269*456b32c9SJohn Harrison 		g2g_test_in_order(test, xe, seqno);
270*456b32c9SJohn Harrison 	seqno--;
271*456b32c9SJohn Harrison 
272*456b32c9SJohn Harrison 	kunit_release_action(test, &g2g_wait_for_complete, xe);
273*456b32c9SJohn Harrison 
274*456b32c9SJohn Harrison 	/* Check for the final seqno in each slot */
275*456b32c9SJohn Harrison 	for (i = 0; i < xe->info.gt_count; i++) {
276*456b32c9SJohn Harrison 		for (j = 0; j < xe->info.gt_count; j++) {
277*456b32c9SJohn Harrison 			u32 idx = (j * xe->info.gt_count) + i;
278*456b32c9SJohn Harrison 
279*456b32c9SJohn Harrison 			if (i == j)
280*456b32c9SJohn Harrison 				KUNIT_ASSERT_EQ_MSG(test, 0, xe->g2g_test_array[idx],
281*456b32c9SJohn Harrison 						    "identity seqno modified: %d for %dx%d!\n",
282*456b32c9SJohn Harrison 						    xe->g2g_test_array[idx], i, j);
283*456b32c9SJohn Harrison 			else
284*456b32c9SJohn Harrison 				KUNIT_ASSERT_EQ_MSG(test, seqno, xe->g2g_test_array[idx],
285*456b32c9SJohn Harrison 						    "invalid seqno: %d vs %d for %dx%d!\n",
286*456b32c9SJohn Harrison 						    xe->g2g_test_array[idx], seqno, i, j);
287*456b32c9SJohn Harrison 		}
288*456b32c9SJohn Harrison 	}
289*456b32c9SJohn Harrison 
290*456b32c9SJohn Harrison 	kunit_kfree(test, xe->g2g_test_array);
291*456b32c9SJohn Harrison 	kunit_release_action(test, &g2g_clean_array, xe);
292*456b32c9SJohn Harrison 
293*456b32c9SJohn Harrison 	kunit_info(test, "Test passed\n");
294*456b32c9SJohn Harrison }
295*456b32c9SJohn Harrison 
296*456b32c9SJohn Harrison #undef NUM_LOOPS
297*456b32c9SJohn Harrison 
298*456b32c9SJohn Harrison static void g2g_ct_stop(struct xe_guc *guc)
299*456b32c9SJohn Harrison {
300*456b32c9SJohn Harrison 	struct xe_gt *remote_gt, *gt = guc_to_gt(guc);
301*456b32c9SJohn Harrison 	struct xe_device *xe = gt_to_xe(gt);
302*456b32c9SJohn Harrison 	int i, t;
303*456b32c9SJohn Harrison 
304*456b32c9SJohn Harrison 	for_each_gt(remote_gt, xe, i) {
305*456b32c9SJohn Harrison 		u32 tile, dev;
306*456b32c9SJohn Harrison 
307*456b32c9SJohn Harrison 		if (remote_gt->info.id == gt->info.id)
308*456b32c9SJohn Harrison 			continue;
309*456b32c9SJohn Harrison 
310*456b32c9SJohn Harrison 		tile = gt_to_tile(remote_gt)->id;
311*456b32c9SJohn Harrison 		dev = G2G_DEV(remote_gt);
312*456b32c9SJohn Harrison 
313*456b32c9SJohn Harrison 		for (t = 0; t < XE_G2G_TYPE_LIMIT; t++)
314*456b32c9SJohn Harrison 			guc_g2g_deregister(guc, tile, dev, t);
315*456b32c9SJohn Harrison 	}
316*456b32c9SJohn Harrison }
317*456b32c9SJohn Harrison 
318*456b32c9SJohn Harrison /* Size of a single allocation that contains all G2G CTBs across all GTs */
319*456b32c9SJohn Harrison static u32 g2g_ctb_size(struct kunit *test, struct xe_device *xe)
320*456b32c9SJohn Harrison {
321*456b32c9SJohn Harrison 	unsigned int count = xe->info.gt_count;
322*456b32c9SJohn Harrison 	u32 num_channels = (count * (count - 1)) / 2;
323*456b32c9SJohn Harrison 
324*456b32c9SJohn Harrison 	kunit_info(test, "Size: (%d * %d / 2) * %d * 0x%08X + 0x%08X => 0x%08X [%d]\n",
325*456b32c9SJohn Harrison 		   count, count - 1, XE_G2G_TYPE_LIMIT, G2G_BUFFER_SIZE, G2G_DESC_AREA_SIZE,
326*456b32c9SJohn Harrison 		   num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE,
327*456b32c9SJohn Harrison 		   num_channels * XE_G2G_TYPE_LIMIT);
328*456b32c9SJohn Harrison 
329*456b32c9SJohn Harrison 	return num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE;
330*456b32c9SJohn Harrison }
331*456b32c9SJohn Harrison 
332*456b32c9SJohn Harrison /*
333*456b32c9SJohn Harrison  * Use the driver's regular CTB allocation scheme.
334*456b32c9SJohn Harrison  */
335*456b32c9SJohn Harrison static void g2g_alloc_default(struct kunit *test, struct xe_device *xe)
336*456b32c9SJohn Harrison {
337*456b32c9SJohn Harrison 	struct xe_gt *gt;
338*456b32c9SJohn Harrison 	int i;
339*456b32c9SJohn Harrison 
340*456b32c9SJohn Harrison 	kunit_info(test, "Default [tiles = %d, GTs = %d]\n",
341*456b32c9SJohn Harrison 		   xe->info.tile_count, xe->info.gt_count);
342*456b32c9SJohn Harrison 
343*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
344*456b32c9SJohn Harrison 		struct xe_guc *guc = &gt->uc.guc;
345*456b32c9SJohn Harrison 		int ret;
346*456b32c9SJohn Harrison 
347*456b32c9SJohn Harrison 		ret = guc_g2g_alloc(guc);
348*456b32c9SJohn Harrison 		KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G alloc failed: %pe", ERR_PTR(ret));
349*456b32c9SJohn Harrison 		continue;
350*456b32c9SJohn Harrison 	}
351*456b32c9SJohn Harrison }
352*456b32c9SJohn Harrison 
353*456b32c9SJohn Harrison static void g2g_distribute(struct kunit *test, struct xe_device *xe, struct xe_bo *bo)
354*456b32c9SJohn Harrison {
355*456b32c9SJohn Harrison 	struct xe_gt *root_gt, *gt;
356*456b32c9SJohn Harrison 	int i;
357*456b32c9SJohn Harrison 
358*456b32c9SJohn Harrison 	root_gt = xe_device_get_gt(xe, 0);
359*456b32c9SJohn Harrison 	root_gt->uc.guc.g2g.bo = bo;
360*456b32c9SJohn Harrison 	root_gt->uc.guc.g2g.owned = true;
361*456b32c9SJohn Harrison 	kunit_info(test, "[%d.%d] Assigned 0x%p\n", gt_to_tile(root_gt)->id, root_gt->info.id, bo);
362*456b32c9SJohn Harrison 
363*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
364*456b32c9SJohn Harrison 		if (gt->info.id != 0) {
365*456b32c9SJohn Harrison 			gt->uc.guc.g2g.owned = false;
366*456b32c9SJohn Harrison 			gt->uc.guc.g2g.bo = xe_bo_get(bo);
367*456b32c9SJohn Harrison 			kunit_info(test, "[%d.%d] Pinned 0x%p\n",
368*456b32c9SJohn Harrison 				   gt_to_tile(gt)->id, gt->info.id, gt->uc.guc.g2g.bo);
369*456b32c9SJohn Harrison 		}
370*456b32c9SJohn Harrison 
371*456b32c9SJohn Harrison 		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gt->uc.guc.g2g.bo);
372*456b32c9SJohn Harrison 	}
373*456b32c9SJohn Harrison }
374*456b32c9SJohn Harrison 
375*456b32c9SJohn Harrison /*
376*456b32c9SJohn Harrison  * Allocate a single blob on the host and split between all G2G CTBs.
377*456b32c9SJohn Harrison  */
378*456b32c9SJohn Harrison static void g2g_alloc_host(struct kunit *test, struct xe_device *xe)
379*456b32c9SJohn Harrison {
380*456b32c9SJohn Harrison 	struct xe_bo *bo;
381*456b32c9SJohn Harrison 	u32 g2g_size;
382*456b32c9SJohn Harrison 
383*456b32c9SJohn Harrison 	kunit_info(test, "Host [tiles = %d, GTs = %d]\n", xe->info.tile_count, xe->info.gt_count);
384*456b32c9SJohn Harrison 
385*456b32c9SJohn Harrison 	g2g_size = g2g_ctb_size(test, xe);
386*456b32c9SJohn Harrison 	bo = xe_managed_bo_create_pin_map(xe, xe_device_get_root_tile(xe), g2g_size,
387*456b32c9SJohn Harrison 					  XE_BO_FLAG_SYSTEM |
388*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT |
389*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT_ALL |
390*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT_INVALIDATE);
391*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
392*456b32c9SJohn Harrison 	kunit_info(test, "[HST] G2G buffer create: 0x%p\n", bo);
393*456b32c9SJohn Harrison 
394*456b32c9SJohn Harrison 	xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size);
395*456b32c9SJohn Harrison 
396*456b32c9SJohn Harrison 	g2g_distribute(test, xe, bo);
397*456b32c9SJohn Harrison }
398*456b32c9SJohn Harrison 
399*456b32c9SJohn Harrison /*
400*456b32c9SJohn Harrison  * Allocate a single blob on the given tile and split between all G2G CTBs.
401*456b32c9SJohn Harrison  */
402*456b32c9SJohn Harrison static void g2g_alloc_tile(struct kunit *test, struct xe_device *xe, struct xe_tile *tile)
403*456b32c9SJohn Harrison {
404*456b32c9SJohn Harrison 	struct xe_bo *bo;
405*456b32c9SJohn Harrison 	u32 g2g_size;
406*456b32c9SJohn Harrison 
407*456b32c9SJohn Harrison 	KUNIT_ASSERT_TRUE(test, IS_DGFX(xe));
408*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tile);
409*456b32c9SJohn Harrison 
410*456b32c9SJohn Harrison 	kunit_info(test, "Tile %d [tiles = %d, GTs = %d]\n",
411*456b32c9SJohn Harrison 		   tile->id, xe->info.tile_count, xe->info.gt_count);
412*456b32c9SJohn Harrison 
413*456b32c9SJohn Harrison 	g2g_size = g2g_ctb_size(test, xe);
414*456b32c9SJohn Harrison 	bo = xe_managed_bo_create_pin_map(xe, tile, g2g_size,
415*456b32c9SJohn Harrison 					  XE_BO_FLAG_VRAM_IF_DGFX(tile) |
416*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT |
417*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT_ALL |
418*456b32c9SJohn Harrison 					  XE_BO_FLAG_GGTT_INVALIDATE);
419*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
420*456b32c9SJohn Harrison 	kunit_info(test, "[%d.*] G2G buffer create: 0x%p\n", tile->id, bo);
421*456b32c9SJohn Harrison 
422*456b32c9SJohn Harrison 	xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size);
423*456b32c9SJohn Harrison 
424*456b32c9SJohn Harrison 	g2g_distribute(test, xe, bo);
425*456b32c9SJohn Harrison }
426*456b32c9SJohn Harrison 
427*456b32c9SJohn Harrison static void g2g_free(struct kunit *test, struct xe_device *xe)
428*456b32c9SJohn Harrison {
429*456b32c9SJohn Harrison 	struct xe_gt *gt;
430*456b32c9SJohn Harrison 	struct xe_bo *bo;
431*456b32c9SJohn Harrison 	int i;
432*456b32c9SJohn Harrison 
433*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
434*456b32c9SJohn Harrison 		bo = gt->uc.guc.g2g.bo;
435*456b32c9SJohn Harrison 		if (!bo)
436*456b32c9SJohn Harrison 			continue;
437*456b32c9SJohn Harrison 
438*456b32c9SJohn Harrison 		if (gt->uc.guc.g2g.owned) {
439*456b32c9SJohn Harrison 			xe_managed_bo_unpin_map_no_vm(bo);
440*456b32c9SJohn Harrison 			kunit_info(test, "[%d.%d] Unmapped 0x%p\n",
441*456b32c9SJohn Harrison 				   gt_to_tile(gt)->id, gt->info.id, bo);
442*456b32c9SJohn Harrison 		} else {
443*456b32c9SJohn Harrison 			xe_bo_put(bo);
444*456b32c9SJohn Harrison 			kunit_info(test, "[%d.%d] Unpinned 0x%p\n",
445*456b32c9SJohn Harrison 				   gt_to_tile(gt)->id, gt->info.id, bo);
446*456b32c9SJohn Harrison 		}
447*456b32c9SJohn Harrison 
448*456b32c9SJohn Harrison 		gt->uc.guc.g2g.bo = NULL;
449*456b32c9SJohn Harrison 	}
450*456b32c9SJohn Harrison }
451*456b32c9SJohn Harrison 
452*456b32c9SJohn Harrison static void g2g_stop(struct kunit *test, struct xe_device *xe)
453*456b32c9SJohn Harrison {
454*456b32c9SJohn Harrison 	struct xe_gt *gt;
455*456b32c9SJohn Harrison 	int i;
456*456b32c9SJohn Harrison 
457*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
458*456b32c9SJohn Harrison 		struct xe_guc *guc = &gt->uc.guc;
459*456b32c9SJohn Harrison 
460*456b32c9SJohn Harrison 		if (!guc->g2g.bo)
461*456b32c9SJohn Harrison 			continue;
462*456b32c9SJohn Harrison 
463*456b32c9SJohn Harrison 		g2g_ct_stop(guc);
464*456b32c9SJohn Harrison 	}
465*456b32c9SJohn Harrison 
466*456b32c9SJohn Harrison 	g2g_free(test, xe);
467*456b32c9SJohn Harrison }
468*456b32c9SJohn Harrison 
469*456b32c9SJohn Harrison /*
470*456b32c9SJohn Harrison  * Generate a unique id for each bi-directional CTB for each pair of
471*456b32c9SJohn Harrison  * near and far tiles/devices. The id can then be used as an index into
472*456b32c9SJohn Harrison  * a single allocation that is sub-divided into multiple CTBs.
473*456b32c9SJohn Harrison  *
474*456b32c9SJohn Harrison  * For example, with two devices per tile and two tiles, the table should
475*456b32c9SJohn Harrison  * look like:
476*456b32c9SJohn Harrison  *           Far <tile>.<dev>
477*456b32c9SJohn Harrison  *         0.0   0.1   1.0   1.1
478*456b32c9SJohn Harrison  * N 0.0  --/-- 00/01 02/03 04/05
479*456b32c9SJohn Harrison  * e 0.1  01/00 --/-- 06/07 08/09
480*456b32c9SJohn Harrison  * a 1.0  03/02 07/06 --/-- 10/11
481*456b32c9SJohn Harrison  * r 1.1  05/04 09/08 11/10 --/--
482*456b32c9SJohn Harrison  *
483*456b32c9SJohn Harrison  * Where each entry is Rx/Tx channel id.
484*456b32c9SJohn Harrison  *
485*456b32c9SJohn Harrison  * So GuC #3 (tile 1, dev 1) talking to GuC #2 (tile 1, dev 0) would
486*456b32c9SJohn Harrison  * be reading from channel #11 and writing to channel #10. Whereas,
487*456b32c9SJohn Harrison  * GuC #2 talking to GuC #3 would be read on #10 and write to #11.
488*456b32c9SJohn Harrison  */
489*456b32c9SJohn Harrison static int g2g_slot_flat(u32 near_tile, u32 near_dev, u32 far_tile, u32 far_dev,
490*456b32c9SJohn Harrison 			 u32 type, u32 max_inst, bool have_dev)
491*456b32c9SJohn Harrison {
492*456b32c9SJohn Harrison 	u32 near = near_tile, far = far_tile;
493*456b32c9SJohn Harrison 	u32 idx = 0, x, y, direction;
494*456b32c9SJohn Harrison 	int i;
495*456b32c9SJohn Harrison 
496*456b32c9SJohn Harrison 	if (have_dev) {
497*456b32c9SJohn Harrison 		near = (near << 1) | near_dev;
498*456b32c9SJohn Harrison 		far = (far << 1) | far_dev;
499*456b32c9SJohn Harrison 	}
500*456b32c9SJohn Harrison 
501*456b32c9SJohn Harrison 	/* No need to send to one's self */
502*456b32c9SJohn Harrison 	if (far == near)
503*456b32c9SJohn Harrison 		return -1;
504*456b32c9SJohn Harrison 
505*456b32c9SJohn Harrison 	if (far > near) {
506*456b32c9SJohn Harrison 		/* Top right table half */
507*456b32c9SJohn Harrison 		x = far;
508*456b32c9SJohn Harrison 		y = near;
509*456b32c9SJohn Harrison 
510*456b32c9SJohn Harrison 		/* T/R is 'forwards' direction */
511*456b32c9SJohn Harrison 		direction = type;
512*456b32c9SJohn Harrison 	} else {
513*456b32c9SJohn Harrison 		/* Bottom left table half */
514*456b32c9SJohn Harrison 		x = near;
515*456b32c9SJohn Harrison 		y = far;
516*456b32c9SJohn Harrison 
517*456b32c9SJohn Harrison 		/* B/L is 'backwards' direction */
518*456b32c9SJohn Harrison 		direction = (1 - type);
519*456b32c9SJohn Harrison 	}
520*456b32c9SJohn Harrison 
521*456b32c9SJohn Harrison 	/* Count the rows prior to the target */
522*456b32c9SJohn Harrison 	for (i = y; i > 0; i--)
523*456b32c9SJohn Harrison 		idx += max_inst - i;
524*456b32c9SJohn Harrison 
525*456b32c9SJohn Harrison 	/* Count this row up to the target */
526*456b32c9SJohn Harrison 	idx += (x - 1 - y);
527*456b32c9SJohn Harrison 
528*456b32c9SJohn Harrison 	/* Slots are in Rx/Tx pairs */
529*456b32c9SJohn Harrison 	idx *= 2;
530*456b32c9SJohn Harrison 
531*456b32c9SJohn Harrison 	/* Pick Rx/Tx direction */
532*456b32c9SJohn Harrison 	idx += direction;
533*456b32c9SJohn Harrison 
534*456b32c9SJohn Harrison 	return idx;
535*456b32c9SJohn Harrison }
536*456b32c9SJohn Harrison 
537*456b32c9SJohn Harrison static int g2g_register_flat(struct xe_guc *guc, u32 far_tile, u32 far_dev, u32 type, bool have_dev)
538*456b32c9SJohn Harrison {
539*456b32c9SJohn Harrison 	struct xe_gt *gt = guc_to_gt(guc);
540*456b32c9SJohn Harrison 	struct xe_device *xe = gt_to_xe(gt);
541*456b32c9SJohn Harrison 	u32 near_tile = gt_to_tile(gt)->id;
542*456b32c9SJohn Harrison 	u32 near_dev = G2G_DEV(gt);
543*456b32c9SJohn Harrison 	u32 max = xe->info.gt_count;
544*456b32c9SJohn Harrison 	int idx;
545*456b32c9SJohn Harrison 	u32 base, desc, buf;
546*456b32c9SJohn Harrison 
547*456b32c9SJohn Harrison 	if (!guc->g2g.bo)
548*456b32c9SJohn Harrison 		return -ENODEV;
549*456b32c9SJohn Harrison 
550*456b32c9SJohn Harrison 	idx = g2g_slot_flat(near_tile, near_dev, far_tile, far_dev, type, max, have_dev);
551*456b32c9SJohn Harrison 	xe_assert(xe, idx >= 0);
552*456b32c9SJohn Harrison 
553*456b32c9SJohn Harrison 	base = guc_bo_ggtt_addr(guc, guc->g2g.bo);
554*456b32c9SJohn Harrison 	desc = base + idx * G2G_DESC_SIZE;
555*456b32c9SJohn Harrison 	buf = base + idx * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE;
556*456b32c9SJohn Harrison 
557*456b32c9SJohn Harrison 	xe_assert(xe, (desc - base + G2G_DESC_SIZE) <= G2G_DESC_AREA_SIZE);
558*456b32c9SJohn Harrison 	xe_assert(xe, (buf - base + G2G_BUFFER_SIZE) <= xe_bo_size(guc->g2g.bo));
559*456b32c9SJohn Harrison 
560*456b32c9SJohn Harrison 	return guc_action_register_g2g_buffer(guc, type, far_tile, far_dev,
561*456b32c9SJohn Harrison 					      desc, buf, G2G_BUFFER_SIZE);
562*456b32c9SJohn Harrison }
563*456b32c9SJohn Harrison 
564*456b32c9SJohn Harrison static void g2g_start(struct kunit *test, struct xe_guc *guc)
565*456b32c9SJohn Harrison {
566*456b32c9SJohn Harrison 	struct xe_gt *remote_gt, *gt = guc_to_gt(guc);
567*456b32c9SJohn Harrison 	struct xe_device *xe = gt_to_xe(gt);
568*456b32c9SJohn Harrison 	unsigned int i;
569*456b32c9SJohn Harrison 	int t, ret;
570*456b32c9SJohn Harrison 	bool have_dev;
571*456b32c9SJohn Harrison 
572*456b32c9SJohn Harrison 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, guc->g2g.bo);
573*456b32c9SJohn Harrison 
574*456b32c9SJohn Harrison 	/* GuC interface will need extending if more GT device types are ever created. */
575*456b32c9SJohn Harrison 	KUNIT_ASSERT_TRUE(test,
576*456b32c9SJohn Harrison 			  (gt->info.type == XE_GT_TYPE_MAIN) ||
577*456b32c9SJohn Harrison 			  (gt->info.type == XE_GT_TYPE_MEDIA));
578*456b32c9SJohn Harrison 
579*456b32c9SJohn Harrison 	/* Channel numbering depends on whether there are multiple GTs per tile */
580*456b32c9SJohn Harrison 	have_dev = xe->info.gt_count > xe->info.tile_count;
581*456b32c9SJohn Harrison 
582*456b32c9SJohn Harrison 	for_each_gt(remote_gt, xe, i) {
583*456b32c9SJohn Harrison 		u32 tile, dev;
584*456b32c9SJohn Harrison 
585*456b32c9SJohn Harrison 		if (remote_gt->info.id == gt->info.id)
586*456b32c9SJohn Harrison 			continue;
587*456b32c9SJohn Harrison 
588*456b32c9SJohn Harrison 		tile = gt_to_tile(remote_gt)->id;
589*456b32c9SJohn Harrison 		dev = G2G_DEV(remote_gt);
590*456b32c9SJohn Harrison 
591*456b32c9SJohn Harrison 		for (t = 0; t < XE_G2G_TYPE_LIMIT; t++) {
592*456b32c9SJohn Harrison 			ret = g2g_register_flat(guc, tile, dev, t, have_dev);
593*456b32c9SJohn Harrison 			KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G register failed: %pe", ERR_PTR(ret));
594*456b32c9SJohn Harrison 		}
595*456b32c9SJohn Harrison 	}
596*456b32c9SJohn Harrison }
597*456b32c9SJohn Harrison 
598*456b32c9SJohn Harrison static void g2g_reinit(struct kunit *test, struct xe_device *xe, int ctb_type, struct xe_tile *tile)
599*456b32c9SJohn Harrison {
600*456b32c9SJohn Harrison 	struct xe_gt *gt;
601*456b32c9SJohn Harrison 	int i, found = 0;
602*456b32c9SJohn Harrison 
603*456b32c9SJohn Harrison 	g2g_stop(test, xe);
604*456b32c9SJohn Harrison 
605*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
606*456b32c9SJohn Harrison 		struct xe_guc *guc = &gt->uc.guc;
607*456b32c9SJohn Harrison 
608*456b32c9SJohn Harrison 		KUNIT_ASSERT_NULL(test, guc->g2g.bo);
609*456b32c9SJohn Harrison 	}
610*456b32c9SJohn Harrison 
611*456b32c9SJohn Harrison 	switch (ctb_type) {
612*456b32c9SJohn Harrison 	case G2G_CTB_TYPE_DEFAULT:
613*456b32c9SJohn Harrison 		g2g_alloc_default(test, xe);
614*456b32c9SJohn Harrison 		break;
615*456b32c9SJohn Harrison 
616*456b32c9SJohn Harrison 	case G2G_CTB_TYPE_HOST:
617*456b32c9SJohn Harrison 		g2g_alloc_host(test, xe);
618*456b32c9SJohn Harrison 		break;
619*456b32c9SJohn Harrison 
620*456b32c9SJohn Harrison 	case G2G_CTB_TYPE_TILE:
621*456b32c9SJohn Harrison 		g2g_alloc_tile(test, xe, tile);
622*456b32c9SJohn Harrison 		break;
623*456b32c9SJohn Harrison 
624*456b32c9SJohn Harrison 	default:
625*456b32c9SJohn Harrison 		KUNIT_ASSERT_TRUE(test, false);
626*456b32c9SJohn Harrison 	}
627*456b32c9SJohn Harrison 
628*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
629*456b32c9SJohn Harrison 		struct xe_guc *guc = &gt->uc.guc;
630*456b32c9SJohn Harrison 
631*456b32c9SJohn Harrison 		if (!guc->g2g.bo)
632*456b32c9SJohn Harrison 			continue;
633*456b32c9SJohn Harrison 
634*456b32c9SJohn Harrison 		if (ctb_type == G2G_CTB_TYPE_DEFAULT)
635*456b32c9SJohn Harrison 			guc_g2g_start(guc);
636*456b32c9SJohn Harrison 		else
637*456b32c9SJohn Harrison 			g2g_start(test, guc);
638*456b32c9SJohn Harrison 		found++;
639*456b32c9SJohn Harrison 	}
640*456b32c9SJohn Harrison 
641*456b32c9SJohn Harrison 	KUNIT_ASSERT_GT_MSG(test, found, 1, "insufficient G2G channels running: %d", found);
642*456b32c9SJohn Harrison 
643*456b32c9SJohn Harrison 	kunit_info(test, "Testing across %d GTs\n", found);
644*456b32c9SJohn Harrison }
645*456b32c9SJohn Harrison 
646*456b32c9SJohn Harrison static void g2g_recreate_ctb(void *_xe)
647*456b32c9SJohn Harrison {
648*456b32c9SJohn Harrison 	struct xe_device *xe = (struct xe_device *)_xe;
649*456b32c9SJohn Harrison 	struct kunit *test = kunit_get_current_test();
650*456b32c9SJohn Harrison 
651*456b32c9SJohn Harrison 	g2g_stop(test, xe);
652*456b32c9SJohn Harrison 
653*456b32c9SJohn Harrison 	if (xe_guc_g2g_wanted(xe))
654*456b32c9SJohn Harrison 		g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL);
655*456b32c9SJohn Harrison }
656*456b32c9SJohn Harrison 
657*456b32c9SJohn Harrison static void g2g_pm_runtime_put(void *_xe)
658*456b32c9SJohn Harrison {
659*456b32c9SJohn Harrison 	struct xe_device *xe = (struct xe_device *)_xe;
660*456b32c9SJohn Harrison 
661*456b32c9SJohn Harrison 	xe_pm_runtime_put(xe);
662*456b32c9SJohn Harrison }
663*456b32c9SJohn Harrison 
664*456b32c9SJohn Harrison static void g2g_pm_runtime_get(struct kunit *test)
665*456b32c9SJohn Harrison {
666*456b32c9SJohn Harrison 	struct xe_device *xe = test->priv;
667*456b32c9SJohn Harrison 	int ret;
668*456b32c9SJohn Harrison 
669*456b32c9SJohn Harrison 	xe_pm_runtime_get(xe);
670*456b32c9SJohn Harrison 	ret = kunit_add_action_or_reset(test, g2g_pm_runtime_put, xe);
671*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register runtime PM action\n");
672*456b32c9SJohn Harrison }
673*456b32c9SJohn Harrison 
674*456b32c9SJohn Harrison static void g2g_check_skip(struct kunit *test)
675*456b32c9SJohn Harrison {
676*456b32c9SJohn Harrison 	struct xe_device *xe = test->priv;
677*456b32c9SJohn Harrison 	struct xe_gt *gt;
678*456b32c9SJohn Harrison 	int i;
679*456b32c9SJohn Harrison 
680*456b32c9SJohn Harrison 	if (IS_SRIOV_VF(xe))
681*456b32c9SJohn Harrison 		kunit_skip(test, "not supported from a VF");
682*456b32c9SJohn Harrison 
683*456b32c9SJohn Harrison 	if (xe->info.gt_count <= 1)
684*456b32c9SJohn Harrison 		kunit_skip(test, "not enough GTs");
685*456b32c9SJohn Harrison 
686*456b32c9SJohn Harrison 	for_each_gt(gt, xe, i) {
687*456b32c9SJohn Harrison 		struct xe_guc *guc = &gt->uc.guc;
688*456b32c9SJohn Harrison 
689*456b32c9SJohn Harrison 		if (guc->fw.build_type == CSS_UKERNEL_INFO_BUILDTYPE_PROD)
690*456b32c9SJohn Harrison 			kunit_skip(test,
691*456b32c9SJohn Harrison 				   "G2G test interface not available in production firmware builds\n");
692*456b32c9SJohn Harrison 	}
693*456b32c9SJohn Harrison }
694*456b32c9SJohn Harrison 
695*456b32c9SJohn Harrison /*
696*456b32c9SJohn Harrison  * Simple test that does not try to recreate the CTBs.
697*456b32c9SJohn Harrison  * Requires that the platform already enables G2G comms
698*456b32c9SJohn Harrison  * but has no risk of leaving the system in a broken state
699*456b32c9SJohn Harrison  * afterwards.
700*456b32c9SJohn Harrison  */
701*456b32c9SJohn Harrison static void xe_live_guc_g2g_kunit_default(struct kunit *test)
702*456b32c9SJohn Harrison {
703*456b32c9SJohn Harrison 	struct xe_device *xe = test->priv;
704*456b32c9SJohn Harrison 
705*456b32c9SJohn Harrison 	if (!xe_guc_g2g_wanted(xe))
706*456b32c9SJohn Harrison 		kunit_skip(test, "G2G not enabled");
707*456b32c9SJohn Harrison 
708*456b32c9SJohn Harrison 	g2g_check_skip(test);
709*456b32c9SJohn Harrison 
710*456b32c9SJohn Harrison 	g2g_pm_runtime_get(test);
711*456b32c9SJohn Harrison 
712*456b32c9SJohn Harrison 	kunit_info(test, "Testing default CTBs\n");
713*456b32c9SJohn Harrison 	g2g_run_test(test, xe);
714*456b32c9SJohn Harrison 
715*456b32c9SJohn Harrison 	kunit_release_action(test, &g2g_pm_runtime_put, xe);
716*456b32c9SJohn Harrison }
717*456b32c9SJohn Harrison 
718*456b32c9SJohn Harrison /*
719*456b32c9SJohn Harrison  * More complex test that re-creates the CTBs in various location to
720*456b32c9SJohn Harrison  * test access to each location from each GuC. Can be run even on
721*456b32c9SJohn Harrison  * systems that do not enable G2G by default. On the other hand,
722*456b32c9SJohn Harrison  * because it recreates the CTBs, if something goes wrong it could
723*456b32c9SJohn Harrison  * leave the system with broken G2G comms.
724*456b32c9SJohn Harrison  */
725*456b32c9SJohn Harrison static void xe_live_guc_g2g_kunit_allmem(struct kunit *test)
726*456b32c9SJohn Harrison {
727*456b32c9SJohn Harrison 	struct xe_device *xe = test->priv;
728*456b32c9SJohn Harrison 	int ret;
729*456b32c9SJohn Harrison 
730*456b32c9SJohn Harrison 	g2g_check_skip(test);
731*456b32c9SJohn Harrison 
732*456b32c9SJohn Harrison 	g2g_pm_runtime_get(test);
733*456b32c9SJohn Harrison 
734*456b32c9SJohn Harrison 	/* Make sure to leave the system as we found it */
735*456b32c9SJohn Harrison 	ret = kunit_add_action_or_reset(test, g2g_recreate_ctb, xe);
736*456b32c9SJohn Harrison 	KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register CTB re-creation action\n");
737*456b32c9SJohn Harrison 
738*456b32c9SJohn Harrison 	kunit_info(test, "Testing CTB type 'default'...\n");
739*456b32c9SJohn Harrison 	g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL);
740*456b32c9SJohn Harrison 	g2g_run_test(test, xe);
741*456b32c9SJohn Harrison 
742*456b32c9SJohn Harrison 	kunit_info(test, "Testing CTB type 'host'...\n");
743*456b32c9SJohn Harrison 	g2g_reinit(test, xe, G2G_CTB_TYPE_HOST, NULL);
744*456b32c9SJohn Harrison 	g2g_run_test(test, xe);
745*456b32c9SJohn Harrison 
746*456b32c9SJohn Harrison 	if (IS_DGFX(xe)) {
747*456b32c9SJohn Harrison 		struct xe_tile *tile;
748*456b32c9SJohn Harrison 		int id;
749*456b32c9SJohn Harrison 
750*456b32c9SJohn Harrison 		for_each_tile(tile, xe, id) {
751*456b32c9SJohn Harrison 			kunit_info(test, "Testing CTB type 'tile: #%d'...\n", id);
752*456b32c9SJohn Harrison 
753*456b32c9SJohn Harrison 			g2g_reinit(test, xe, G2G_CTB_TYPE_TILE, tile);
754*456b32c9SJohn Harrison 			g2g_run_test(test, xe);
755*456b32c9SJohn Harrison 		}
756*456b32c9SJohn Harrison 	} else {
757*456b32c9SJohn Harrison 		kunit_info(test, "Skipping local memory on integrated platform\n");
758*456b32c9SJohn Harrison 	}
759*456b32c9SJohn Harrison 
760*456b32c9SJohn Harrison 	kunit_release_action(test, g2g_recreate_ctb, xe);
761*456b32c9SJohn Harrison 	kunit_release_action(test, g2g_pm_runtime_put, xe);
762*456b32c9SJohn Harrison }
763*456b32c9SJohn Harrison 
764*456b32c9SJohn Harrison static struct kunit_case xe_guc_g2g_tests[] = {
765*456b32c9SJohn Harrison 	KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_default, xe_pci_live_device_gen_param),
766*456b32c9SJohn Harrison 	KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_allmem, xe_pci_live_device_gen_param),
767*456b32c9SJohn Harrison 	{}
768*456b32c9SJohn Harrison };
769*456b32c9SJohn Harrison 
770*456b32c9SJohn Harrison VISIBLE_IF_KUNIT
771*456b32c9SJohn Harrison struct kunit_suite xe_guc_g2g_test_suite = {
772*456b32c9SJohn Harrison 	.name = "xe_guc_g2g",
773*456b32c9SJohn Harrison 	.test_cases = xe_guc_g2g_tests,
774*456b32c9SJohn Harrison 	.init = xe_kunit_helper_xe_device_live_test_init,
775*456b32c9SJohn Harrison };
776*456b32c9SJohn Harrison EXPORT_SYMBOL_IF_KUNIT(xe_guc_g2g_test_suite);
777