1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2 /*
3 * KUnit tests for amdgpu_dm_irq.c
4 *
5 * Copyright 2026 Advanced Micro Devices, Inc.
6 */
7
8 #include <kunit/test.h>
9 #include <drm/drm_kunit_helpers.h>
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_probe_helper.h>
12
13 #include "dc.h"
14 #include "inc/core_types.h"
15 #include "irq/irq_service.h"
16 #include "amdgpu.h"
17 #include "amdgpu_mode.h"
18 #include "amdgpu_dm.h"
19 #include "amdgpu_dm_irq.h"
20 #include "amdgpu_dm_kunit_test_helpers.h"
21 #include "dc_dmub_srv.h"
22 #include "ivsrcid/ivsrcid_vislands30.h"
23 #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
24 #include "link_service.h"
25 #include "dmub/dmub_srv.h"
26 #include "dal_asic_id.h"
27 #include "../../amdgpu/amdgpu_reset.h"
28
dm_test_irq_handler(void * arg)29 static void dm_test_irq_handler(void *arg)
30 {
31 }
32
dm_test_irq_handler_alt(void * arg)33 static void dm_test_irq_handler_alt(void *arg)
34 {
35 }
36
dm_test_irq_handler_count(void * arg)37 static void dm_test_irq_handler_count(void *arg)
38 {
39 int *count = arg;
40
41 if (count)
42 (*count)++;
43 }
44
dm_test_detect_connection_none(struct dc_link * link,enum dc_connection_type * type)45 static bool dm_test_detect_connection_none(struct dc_link *link,
46 enum dc_connection_type *type)
47 {
48 *type = dc_connection_none;
49
50 return true;
51 }
52
dm_test_detect_link_false(struct dc_link * link,enum dc_detect_reason reason)53 static bool dm_test_detect_link_false(struct dc_link *link,
54 enum dc_detect_reason reason)
55 {
56 return false;
57 }
58
dm_test_detect_connection_single(struct dc_link * link,enum dc_connection_type * type)59 static bool dm_test_detect_connection_single(struct dc_link *link,
60 enum dc_connection_type *type)
61 {
62 *type = dc_connection_single;
63
64 return true;
65 }
66
67 /* Recording stubs for the dm_handle_hpd_rx_offload_work() DP-IRQ branches. */
68 static int dm_test_automated_test_count;
69 static int dm_test_handle_link_loss_count;
70
dm_test_dp_handle_automated_test(struct dc_link * link)71 static void dm_test_dp_handle_automated_test(struct dc_link *link)
72 {
73 dm_test_automated_test_count++;
74 }
75
dm_test_dp_handle_link_loss(struct dc_link * link)76 static void dm_test_dp_handle_link_loss(struct dc_link *link)
77 {
78 dm_test_handle_link_loss_count++;
79 }
80
dm_test_dp_parse_link_loss_true(struct dc_link * link,union hpd_irq_data * hpd_irq_dpcd_data)81 static bool dm_test_dp_parse_link_loss_true(struct dc_link *link,
82 union hpd_irq_data *hpd_irq_dpcd_data)
83 {
84 return true;
85 }
86
dm_test_dp_should_allow_hpd_rx_irq_true(const struct dc_link * link)87 static bool dm_test_dp_should_allow_hpd_rx_irq_true(const struct dc_link *link)
88 {
89 return true;
90 }
91
dm_test_dp_read_hpd_rx_irq_data_ok(struct dc_link * link,union hpd_irq_data * irq_data)92 static enum dc_status dm_test_dp_read_hpd_rx_irq_data_ok(struct dc_link *link,
93 union hpd_irq_data *irq_data)
94 {
95 return DC_OK;
96 }
97
98 /*
99 * Allocate a refcounted dc_sink for tests without pulling in the DC-core
100 * dc_sink_create()/dc_sink_release() symbols. Production code under test still
101 * uses dc_sink_retain()/dc_sink_release() (resolved inside the amdgpu module).
102 * Use kzalloc (not kunit_kzalloc) so the final kref_put frees it exactly once.
103 */
dm_test_sink_create(struct dc_link * link)104 static struct dc_sink *dm_test_sink_create(struct dc_link *link)
105 {
106 struct dc_sink *sink = kzalloc_obj(*sink);
107
108 if (!sink)
109 return NULL;
110
111 sink->link = link;
112 sink->ctx = link->ctx;
113 kref_init(&sink->refcount);
114
115 return sink;
116 }
117
dm_test_sink_free(struct kref * kref)118 static void dm_test_sink_free(struct kref *kref)
119 {
120 struct dc_sink *sink = container_of(kref, struct dc_sink, refcount);
121
122 kfree(sink->dc_container_id);
123 kfree(sink);
124 }
125
dm_test_sink_release(struct dc_sink * sink)126 static void dm_test_sink_release(struct dc_sink *sink)
127 {
128 kref_put(&sink->refcount, dm_test_sink_free);
129 }
130
dm_test_handle_hpd_rx_no_work(struct dc_link * link,union hpd_irq_data * hpd_irq_data,bool * link_loss,bool defer_handling,bool * has_left_work)131 static bool dm_test_handle_hpd_rx_no_work(struct dc_link *link,
132 union hpd_irq_data *hpd_irq_data,
133 bool *link_loss,
134 bool defer_handling,
135 bool *has_left_work)
136 {
137 *link_loss = false;
138 *has_left_work = false;
139
140 return false;
141 }
142
dm_test_handle_hpd_rx_automated(struct dc_link * link,union hpd_irq_data * hpd_irq_data,bool * link_loss,bool defer_handling,bool * has_left_work)143 static bool dm_test_handle_hpd_rx_automated(struct dc_link *link,
144 union hpd_irq_data *hpd_irq_data,
145 bool *link_loss,
146 bool defer_handling,
147 bool *has_left_work)
148 {
149 *link_loss = false;
150 *has_left_work = true;
151 hpd_irq_data->bytes.device_service_irq.bits.AUTOMATED_TEST = 1;
152
153 return false;
154 }
155
dm_test_handle_hpd_rx_msg_rdy(struct dc_link * link,union hpd_irq_data * hpd_irq_data,bool * link_loss,bool defer_handling,bool * has_left_work)156 static bool dm_test_handle_hpd_rx_msg_rdy(struct dc_link *link,
157 union hpd_irq_data *hpd_irq_data,
158 bool *link_loss,
159 bool defer_handling,
160 bool *has_left_work)
161 {
162 *link_loss = false;
163 *has_left_work = true;
164 hpd_irq_data->bytes.device_service_irq.bits.UP_REQ_MSG_RDY = 1;
165
166 return false;
167 }
168
dm_test_handle_hpd_rx_link_loss(struct dc_link * link,union hpd_irq_data * hpd_irq_data,bool * link_loss,bool defer_handling,bool * has_left_work)169 static bool dm_test_handle_hpd_rx_link_loss(struct dc_link *link,
170 union hpd_irq_data *hpd_irq_data,
171 bool *link_loss,
172 bool defer_handling,
173 bool *has_left_work)
174 {
175 *link_loss = true;
176 *has_left_work = true;
177
178 return false;
179 }
180
dm_test_allow_hpd_rx_irq_true(const struct dc_link * link)181 static bool dm_test_allow_hpd_rx_irq_true(const struct dc_link *link)
182 {
183 return true;
184 }
185
186
dm_test_dmub_get_outbox0_wptr(struct dmub_srv * dmub)187 static uint32_t dm_test_dmub_get_outbox0_wptr(struct dmub_srv *dmub)
188 {
189 return 0;
190 }
191
dm_test_dmub_get_outbox1_wptr(struct dmub_srv * dmub)192 static uint32_t dm_test_dmub_get_outbox1_wptr(struct dmub_srv *dmub)
193 {
194 return 0;
195 }
196
197 static int dm_test_dmub_notify_count;
198
dm_test_dmub_notify_callback(struct amdgpu_device * adev,struct dmub_notification * notify)199 static void dm_test_dmub_notify_callback(struct amdgpu_device *adev,
200 struct dmub_notification *notify)
201 {
202 dm_test_dmub_notify_count++;
203 }
204
dm_test_to_dal_irq_source_dce110(struct irq_service * irq_service,uint32_t src_id,uint32_t ext_id)205 static enum dc_irq_source dm_test_to_dal_irq_source_dce110(
206 struct irq_service *irq_service,
207 uint32_t src_id,
208 uint32_t ext_id)
209 {
210 switch (src_id) {
211 case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0:
212 return DC_IRQ_SOURCE_VBLANK1;
213 case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT:
214 return DC_IRQ_SOURCE_VUPDATE1;
215 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP:
216 return DC_IRQ_SOURCE_PFLIP1;
217 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP + 2:
218 return DC_IRQ_SOURCE_PFLIP2;
219 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP + 4:
220 return DC_IRQ_SOURCE_PFLIP3;
221 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP + 6:
222 return DC_IRQ_SOURCE_PFLIP4;
223 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP + 8:
224 return DC_IRQ_SOURCE_PFLIP5;
225 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP + 10:
226 return DC_IRQ_SOURCE_PFLIP6;
227 default:
228 return DC_IRQ_SOURCE_INVALID;
229 }
230 }
231
232 static const struct irq_service_funcs dm_test_irq_service_funcs_dce110 = {
233 .to_dal_irq_source = dm_test_to_dal_irq_source_dce110
234 };
235
dm_test_to_dal_irq_source_dcn10(struct irq_service * irq_service,uint32_t src_id,uint32_t ext_id)236 static enum dc_irq_source dm_test_to_dal_irq_source_dcn10(
237 struct irq_service *irq_service,
238 uint32_t src_id,
239 uint32_t ext_id)
240 {
241 switch (src_id) {
242 case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
243 return DC_IRQ_SOURCE_VBLANK1;
244 case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
245 return DC_IRQ_SOURCE_VUPDATE1;
246 case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
247 return DC_IRQ_SOURCE_PFLIP1;
248 case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
249 return DC_IRQ_SOURCE_DMCUB_OUTBOX;
250 default:
251 return DC_IRQ_SOURCE_INVALID;
252 }
253 }
254
255 static const struct irq_service_funcs dm_test_irq_service_funcs_dcn10 = {
256 .to_dal_irq_source = dm_test_to_dal_irq_source_dcn10
257 };
258
dm_test_irq_src_set(struct irq_service * irq_service,const struct irq_source_info * info,bool enable)259 static bool dm_test_irq_src_set(struct irq_service *irq_service,
260 const struct irq_source_info *info, bool enable)
261 {
262 return true;
263 }
264
dm_test_irq_src_ack(struct irq_service * irq_service,const struct irq_source_info * info)265 static bool dm_test_irq_src_ack(struct irq_service *irq_service,
266 const struct irq_source_info *info)
267 {
268 return true;
269 }
270
271 /* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
272 static struct irq_source_info_funcs dm_test_irq_src_funcs = {
273 .set = dm_test_irq_src_set,
274 .ack = dm_test_irq_src_ack,
275 };
276
dm_test_alloc_dc_with_irq_service(struct kunit * test,const struct irq_service_funcs * funcs)277 static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
278 const struct irq_service_funcs *funcs)
279 {
280 struct irq_source_info *info;
281 struct resource_pool *res_pool;
282 struct irq_service *irqs;
283 struct dc *dc;
284 int i;
285
286 dc = dm_kunit_alloc_dc_with_ctx(test);
287 res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
288 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool);
289 irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
290 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
291
292 /*
293 * Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
294 * succeed without touching hardware registers.
295 */
296 info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
297 GFP_KERNEL);
298 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
299 for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++)
300 info[i].funcs = &dm_test_irq_src_funcs;
301
302 irqs->funcs = funcs;
303 irqs->info = info;
304 res_pool->irqs = irqs;
305 dc->res_pool = res_pool;
306
307 return dc;
308 }
309
dm_test_free_irq_sources(void * data)310 static void dm_test_free_irq_sources(void *data)
311 {
312 struct amdgpu_device *adev = data;
313 int i;
314
315 for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; i++) {
316 kfree(adev->irq.client[i].sources);
317 adev->irq.client[i].sources = NULL;
318 }
319
320 kfree(adev->crtc_irq.enabled_types);
321 adev->crtc_irq.enabled_types = NULL;
322 kfree(adev->vline0_irq.enabled_types);
323 adev->vline0_irq.enabled_types = NULL;
324 kfree(adev->vupdate_irq.enabled_types);
325 adev->vupdate_irq.enabled_types = NULL;
326 kfree(adev->pageflip_irq.enabled_types);
327 adev->pageflip_irq.enabled_types = NULL;
328 kfree(adev->dmub_outbox_irq.enabled_types);
329 adev->dmub_outbox_irq.enabled_types = NULL;
330 kfree(adev->dmub_trace_irq.enabled_types);
331 adev->dmub_trace_irq.enabled_types = NULL;
332 kfree(adev->hpd_irq.enabled_types);
333 adev->hpd_irq.enabled_types = NULL;
334 }
335
dm_test_crtc_list_del(void * data)336 static void dm_test_crtc_list_del(void *data)
337 {
338 struct amdgpu_crtc *acrtc = data;
339
340 list_del_init(&acrtc->base.head);
341 }
342
343 struct dm_test_hpd_rx_wq_ctx {
344 struct hpd_rx_irq_offload_work_queue *wq;
345 int count;
346 };
347
dm_test_destroy_hpd_rx_wq(void * data)348 static void dm_test_destroy_hpd_rx_wq(void *data)
349 {
350 struct dm_test_hpd_rx_wq_ctx *ctx = data;
351 int i;
352
353 for (i = 0; i < ctx->count; i++)
354 if (ctx->wq[i].wq)
355 destroy_workqueue(ctx->wq[i].wq);
356 kfree(ctx->wq);
357 }
358
359 static const struct drm_connector_funcs dm_test_connector_funcs = {
360 .reset = drm_atomic_helper_connector_reset,
361 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
362 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
363 .fill_modes = drm_helper_probe_single_connector_modes,
364 .destroy = drm_connector_cleanup,
365 };
366
dm_test_connector_cleanup(void * data)367 static void dm_test_connector_cleanup(void *data)
368 {
369 drm_connector_cleanup(data);
370 }
371
372 /* Tests for amdgpu_dm_hpd_to_dal_irq_source() */
373
374 /**
375 * dm_test_hpd_to_dal_irq_source_hpd1 - Test Hpd to dal irq source hpd1
376 * @test: The KUnit test context
377 */
dm_test_hpd_to_dal_irq_source_hpd1(struct kunit * test)378 static void dm_test_hpd_to_dal_irq_source_hpd1(struct kunit *test)
379 {
380 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_1),
381 (int)DC_IRQ_SOURCE_HPD1);
382 }
383
384 /**
385 * dm_test_hpd_to_dal_irq_source_hpd2 - Test Hpd to dal irq source hpd2
386 * @test: The KUnit test context
387 */
dm_test_hpd_to_dal_irq_source_hpd2(struct kunit * test)388 static void dm_test_hpd_to_dal_irq_source_hpd2(struct kunit *test)
389 {
390 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_2),
391 (int)DC_IRQ_SOURCE_HPD2);
392 }
393
394 /**
395 * dm_test_hpd_to_dal_irq_source_hpd3 - Test Hpd to dal irq source hpd3
396 * @test: The KUnit test context
397 */
dm_test_hpd_to_dal_irq_source_hpd3(struct kunit * test)398 static void dm_test_hpd_to_dal_irq_source_hpd3(struct kunit *test)
399 {
400 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_3),
401 (int)DC_IRQ_SOURCE_HPD3);
402 }
403
404 /**
405 * dm_test_hpd_to_dal_irq_source_hpd4 - Test Hpd to dal irq source hpd4
406 * @test: The KUnit test context
407 */
dm_test_hpd_to_dal_irq_source_hpd4(struct kunit * test)408 static void dm_test_hpd_to_dal_irq_source_hpd4(struct kunit *test)
409 {
410 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_4),
411 (int)DC_IRQ_SOURCE_HPD4);
412 }
413
414 /**
415 * dm_test_hpd_to_dal_irq_source_hpd5 - Test Hpd to dal irq source hpd5
416 * @test: The KUnit test context
417 */
dm_test_hpd_to_dal_irq_source_hpd5(struct kunit * test)418 static void dm_test_hpd_to_dal_irq_source_hpd5(struct kunit *test)
419 {
420 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_5),
421 (int)DC_IRQ_SOURCE_HPD5);
422 }
423
424 /**
425 * dm_test_hpd_to_dal_irq_source_hpd6 - Test Hpd to dal irq source hpd6
426 * @test: The KUnit test context
427 */
dm_test_hpd_to_dal_irq_source_hpd6(struct kunit * test)428 static void dm_test_hpd_to_dal_irq_source_hpd6(struct kunit *test)
429 {
430 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_6),
431 (int)DC_IRQ_SOURCE_HPD6);
432 }
433
434 /**
435 * dm_test_hpd_to_dal_irq_source_invalid - Test Hpd to dal irq source invalid
436 * @test: The KUnit test context
437 */
dm_test_hpd_to_dal_irq_source_invalid(struct kunit * test)438 static void dm_test_hpd_to_dal_irq_source_invalid(struct kunit *test)
439 {
440 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_NONE),
441 (int)DC_IRQ_SOURCE_INVALID);
442 }
443
444 /**
445 * dm_test_hpd_to_dal_irq_source_out_of_range - Test Hpd to dal irq source out of range
446 * @test: The KUnit test context
447 */
dm_test_hpd_to_dal_irq_source_out_of_range(struct kunit * test)448 static void dm_test_hpd_to_dal_irq_source_out_of_range(struct kunit *test)
449 {
450 KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(99),
451 (int)DC_IRQ_SOURCE_INVALID);
452 }
453
454 /* Tests for are_sinks_equal() */
455
456 /**
457 * dm_test_are_sinks_equal_both_null - Test Are sinks equal both null
458 * @test: The KUnit test context
459 */
dm_test_are_sinks_equal_both_null(struct kunit * test)460 static void dm_test_are_sinks_equal_both_null(struct kunit *test)
461 {
462 KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, NULL));
463 }
464
465 /**
466 * dm_test_are_sinks_equal_first_null - Test Are sinks equal first null
467 * @test: The KUnit test context
468 */
dm_test_are_sinks_equal_first_null(struct kunit * test)469 static void dm_test_are_sinks_equal_first_null(struct kunit *test)
470 {
471 struct dc_sink *sink2;
472
473 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
474 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
475
476 KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, sink2));
477 }
478
479 /**
480 * dm_test_are_sinks_equal_second_null - Test Are sinks equal second null
481 * @test: The KUnit test context
482 */
dm_test_are_sinks_equal_second_null(struct kunit * test)483 static void dm_test_are_sinks_equal_second_null(struct kunit *test)
484 {
485 struct dc_sink *sink1;
486
487 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
488 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
489
490 KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, NULL));
491 }
492
493 /**
494 * dm_test_are_sinks_equal_different_signal - Test Are sinks equal different signal
495 * @test: The KUnit test context
496 */
dm_test_are_sinks_equal_different_signal(struct kunit * test)497 static void dm_test_are_sinks_equal_different_signal(struct kunit *test)
498 {
499 struct dc_sink *sink1, *sink2;
500
501 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
502 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
503 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
504 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
505
506 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
507 sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
508
509 KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2));
510 }
511
512 /**
513 * dm_test_are_sinks_equal_different_edid_length - Test Are sinks equal different edid length
514 * @test: The KUnit test context
515 */
dm_test_are_sinks_equal_different_edid_length(struct kunit * test)516 static void dm_test_are_sinks_equal_different_edid_length(struct kunit *test)
517 {
518 struct dc_sink *sink1, *sink2;
519
520 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
521 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
522 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
523 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
524
525 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
526 sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
527 sink1->dc_edid.length = 128;
528 sink2->dc_edid.length = 256;
529
530 KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2));
531 }
532
533 /**
534 * dm_test_are_sinks_equal_different_edid_data - Test Are sinks equal different edid data
535 * @test: The KUnit test context
536 */
dm_test_are_sinks_equal_different_edid_data(struct kunit * test)537 static void dm_test_are_sinks_equal_different_edid_data(struct kunit *test)
538 {
539 struct dc_sink *sink1, *sink2;
540
541 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
542 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
543 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
544 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
545
546 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
547 sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
548 sink1->dc_edid.length = 4;
549 sink2->dc_edid.length = 4;
550 memset(sink1->dc_edid.raw_edid, 0xAA, 4);
551 memset(sink2->dc_edid.raw_edid, 0xBB, 4);
552
553 KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2));
554 }
555
556 /**
557 * dm_test_are_sinks_equal_identical - Test Are sinks equal identical
558 * @test: The KUnit test context
559 */
dm_test_are_sinks_equal_identical(struct kunit * test)560 static void dm_test_are_sinks_equal_identical(struct kunit *test)
561 {
562 struct dc_sink *sink1, *sink2;
563
564 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
565 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
566 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
567 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
568
569 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
570 sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
571 sink1->dc_edid.length = 4;
572 sink2->dc_edid.length = 4;
573 memset(sink1->dc_edid.raw_edid, 0xAA, 4);
574 memset(sink2->dc_edid.raw_edid, 0xAA, 4);
575
576 KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2));
577 }
578
579 /**
580 * dm_test_are_sinks_equal_zero_length - Test Are sinks equal zero length
581 * @test: The KUnit test context
582 */
dm_test_are_sinks_equal_zero_length(struct kunit * test)583 static void dm_test_are_sinks_equal_zero_length(struct kunit *test)
584 {
585 struct dc_sink *sink1, *sink2;
586
587 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
588 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
589 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
590 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
591
592 sink1->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
593 sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
594 sink1->dc_edid.length = 0;
595 sink2->dc_edid.length = 0;
596
597 KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2));
598 }
599
600 /**
601 * dm_test_are_sinks_equal_full_edid_identical - Test Are sinks equal full edid identical
602 * @test: The KUnit test context
603 */
dm_test_are_sinks_equal_full_edid_identical(struct kunit * test)604 static void dm_test_are_sinks_equal_full_edid_identical(struct kunit *test)
605 {
606 struct dc_sink *sink1, *sink2;
607
608 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
609 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
610 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
611 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
612
613 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
614 sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
615 sink1->dc_edid.length = 128;
616 sink2->dc_edid.length = 128;
617 memset(sink1->dc_edid.raw_edid, 0x5A, 128);
618 memset(sink2->dc_edid.raw_edid, 0x5A, 128);
619
620 KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2));
621 }
622
623 /**
624 * dm_test_are_sinks_equal_full_edid_last_byte_differs - Test Are sinks equal last byte differs
625 * @test: The KUnit test context
626 */
dm_test_are_sinks_equal_full_edid_last_byte_differs(struct kunit * test)627 static void dm_test_are_sinks_equal_full_edid_last_byte_differs(struct kunit *test)
628 {
629 struct dc_sink *sink1, *sink2;
630
631 sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL);
632 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1);
633 sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL);
634 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2);
635
636 sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
637 sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
638 sink1->dc_edid.length = 128;
639 sink2->dc_edid.length = 128;
640 memset(sink1->dc_edid.raw_edid, 0x5A, 128);
641 memset(sink2->dc_edid.raw_edid, 0x5A, 128);
642 sink2->dc_edid.raw_edid[127] = 0x5B;
643
644 KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2));
645 }
646
647 /* Tests for dmub_notification_type_str() */
648
649 /**
650 * dm_test_notification_str_no_data - Test Notification str no data
651 * @test: The KUnit test context
652 */
dm_test_notification_str_no_data(struct kunit * test)653 static void dm_test_notification_str_no_data(struct kunit *test)
654 {
655 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_NO_DATA), "NO_DATA");
656 }
657
658 /**
659 * dm_test_notification_str_aux_reply - Test Notification str aux reply
660 * @test: The KUnit test context
661 */
dm_test_notification_str_aux_reply(struct kunit * test)662 static void dm_test_notification_str_aux_reply(struct kunit *test)
663 {
664 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_AUX_REPLY), "AUX_REPLY");
665 }
666
667 /**
668 * dm_test_notification_str_hpd - Test Notification str hpd
669 * @test: The KUnit test context
670 */
dm_test_notification_str_hpd(struct kunit * test)671 static void dm_test_notification_str_hpd(struct kunit *test)
672 {
673 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD), "HPD");
674 }
675
676 /**
677 * dm_test_notification_str_hpd_irq - Test Notification str hpd irq
678 * @test: The KUnit test context
679 */
dm_test_notification_str_hpd_irq(struct kunit * test)680 static void dm_test_notification_str_hpd_irq(struct kunit *test)
681 {
682 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD_IRQ), "HPD_IRQ");
683 }
684
685 /**
686 * dm_test_notification_str_set_config - Test Notification str set config
687 * @test: The KUnit test context
688 */
dm_test_notification_str_set_config(struct kunit * test)689 static void dm_test_notification_str_set_config(struct kunit *test)
690 {
691 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_SET_CONFIG_REPLY),
692 "SET_CONFIG_REPLY");
693 }
694
695 /**
696 * dm_test_notification_str_dpia - Test Notification str dpia
697 * @test: The KUnit test context
698 */
dm_test_notification_str_dpia(struct kunit * test)699 static void dm_test_notification_str_dpia(struct kunit *test)
700 {
701 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_DPIA_NOTIFICATION),
702 "DPIA_NOTIFICATION");
703 }
704
705 /**
706 * dm_test_notification_str_hpd_sense - Test Notification str hpd sense
707 * @test: The KUnit test context
708 */
dm_test_notification_str_hpd_sense(struct kunit * test)709 static void dm_test_notification_str_hpd_sense(struct kunit *test)
710 {
711 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD_SENSE_NOTIFY),
712 "HPD_SENSE_NOTIFY");
713 }
714
715 /**
716 * dm_test_notification_str_fused_io - Test Notification str fused io
717 * @test: The KUnit test context
718 */
dm_test_notification_str_fused_io(struct kunit * test)719 static void dm_test_notification_str_fused_io(struct kunit *test)
720 {
721 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_FUSED_IO),
722 "FUSED_IO");
723 }
724
725 /**
726 * dm_test_notification_str_unknown - Test Notification str unknown
727 * @test: The KUnit test context
728 */
dm_test_notification_str_unknown(struct kunit * test)729 static void dm_test_notification_str_unknown(struct kunit *test)
730 {
731 KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_MAX), "<unknown>");
732 }
733
734 /* Tests for amdgpu_dm_irq_init() */
735
736 /**
737 * dm_test_irq_init_initializes_lists - Test irq init initializes list heads
738 * @test: The KUnit test context
739 */
dm_test_irq_init_initializes_lists(struct kunit * test)740 static void dm_test_irq_init_initializes_lists(struct kunit *test)
741 {
742 struct amdgpu_device *adev;
743 int src;
744
745 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
746 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
747
748 KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_init(adev), 0);
749
750 for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) {
751 KUNIT_EXPECT_TRUE(test,
752 list_empty(&adev->dm.irq_handler_list_low_tab[src]));
753 KUNIT_EXPECT_TRUE(test,
754 list_empty(&adev->dm.irq_handler_list_high_tab[src]));
755 }
756 }
757
758 /* Tests for amdgpu_dm_irq_register_interrupt() */
759
760 /**
761 * dm_test_irq_register_rejects_null_params - Test register rejects null params
762 * @test: The KUnit test context
763 */
dm_test_irq_register_rejects_null_params(struct kunit * test)764 static void dm_test_irq_register_rejects_null_params(struct kunit *test)
765 {
766 struct amdgpu_device *adev;
767 struct dc_interrupt_params int_params = { 0 };
768
769 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
770 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
771
772 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
773 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
774
775 KUNIT_EXPECT_NULL(test,
776 amdgpu_dm_irq_register_interrupt(adev, NULL,
777 dm_test_irq_handler, NULL));
778 KUNIT_EXPECT_NULL(test,
779 amdgpu_dm_irq_register_interrupt(adev, &int_params, NULL, NULL));
780 }
781
782 /**
783 * dm_test_irq_register_rejects_invalid_context - Test register rejects context
784 * @test: The KUnit test context
785 */
dm_test_irq_register_rejects_invalid_context(struct kunit * test)786 static void dm_test_irq_register_rejects_invalid_context(struct kunit *test)
787 {
788 struct amdgpu_device *adev;
789 struct dc_interrupt_params int_params = { 0 };
790
791 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
792 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
793
794 int_params.int_context = INTERRUPT_CONTEXT_NUMBER;
795 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
796
797 KUNIT_EXPECT_NULL(test,
798 amdgpu_dm_irq_register_interrupt(adev, &int_params,
799 dm_test_irq_handler, NULL));
800 }
801
802 /**
803 * dm_test_irq_register_rejects_invalid_source - Test register rejects source
804 * @test: The KUnit test context
805 */
dm_test_irq_register_rejects_invalid_source(struct kunit * test)806 static void dm_test_irq_register_rejects_invalid_source(struct kunit *test)
807 {
808 struct amdgpu_device *adev;
809 struct dc_interrupt_params int_params = { 0 };
810
811 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
812 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
813
814 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
815 int_params.irq_source = DC_IRQ_SOURCE_INVALID;
816
817 KUNIT_EXPECT_NULL(test,
818 amdgpu_dm_irq_register_interrupt(adev, &int_params,
819 dm_test_irq_handler, NULL));
820 }
821
822 /**
823 * dm_test_irq_register_adds_low_context_handler - Test register adds low handler
824 * @test: The KUnit test context
825 */
dm_test_irq_register_adds_low_context_handler(struct kunit * test)826 static void dm_test_irq_register_adds_low_context_handler(struct kunit *test)
827 {
828 struct amdgpu_device *adev;
829 struct dc_interrupt_params int_params = { 0 };
830 void *handler;
831
832 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
833 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
834 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
835
836 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
837 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
838
839 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
840 dm_test_irq_handler, adev);
841
842 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
843 KUNIT_EXPECT_FALSE(test,
844 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
845 KUNIT_EXPECT_TRUE(test,
846 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1]));
847
848 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
849 dm_test_irq_handler);
850 KUNIT_EXPECT_TRUE(test,
851 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
852 }
853
854 /**
855 * dm_test_irq_register_adds_high_context_handler - Test register adds high handler
856 * @test: The KUnit test context
857 */
dm_test_irq_register_adds_high_context_handler(struct kunit * test)858 static void dm_test_irq_register_adds_high_context_handler(struct kunit *test)
859 {
860 struct amdgpu_device *adev;
861 struct dc_interrupt_params int_params = { 0 };
862 void *handler;
863
864 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
865 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
866 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
867
868 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
869 int_params.irq_source = DC_IRQ_SOURCE_HPD2;
870
871 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
872 dm_test_irq_handler, adev);
873
874 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
875 KUNIT_EXPECT_FALSE(test,
876 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2]));
877 KUNIT_EXPECT_TRUE(test,
878 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD2]));
879
880 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD2,
881 dm_test_irq_handler);
882 KUNIT_EXPECT_TRUE(test,
883 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2]));
884 }
885
886 /**
887 * dm_test_irq_register_multiple_handlers - Test register keeps multiple handlers
888 * @test: The KUnit test context
889 */
dm_test_irq_register_multiple_handlers(struct kunit * test)890 static void dm_test_irq_register_multiple_handlers(struct kunit *test)
891 {
892 struct amdgpu_device *adev;
893 struct dc_interrupt_params int_params = { 0 };
894 struct list_head *hnd_list;
895 void *handler1, *handler2;
896
897 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
898 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
899 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
900
901 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
902 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
903
904 handler1 = amdgpu_dm_irq_register_interrupt(adev, &int_params,
905 dm_test_irq_handler, adev);
906 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler1);
907 handler2 = amdgpu_dm_irq_register_interrupt(adev, &int_params,
908 dm_test_irq_handler_alt, adev);
909 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler2);
910
911 hnd_list = &adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1];
912 KUNIT_EXPECT_EQ(test, list_count_nodes(hnd_list), 2);
913
914 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
915 dm_test_irq_handler);
916 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
917 dm_test_irq_handler_alt);
918 KUNIT_EXPECT_TRUE(test, list_empty(hnd_list));
919 }
920
921 /**
922 * dm_test_irq_register_separate_contexts - Test register same source in two contexts
923 * @test: The KUnit test context
924 */
dm_test_irq_register_separate_contexts(struct kunit * test)925 static void dm_test_irq_register_separate_contexts(struct kunit *test)
926 {
927 struct amdgpu_device *adev;
928 struct dc_interrupt_params int_params = { 0 };
929 void *handler;
930
931 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
932 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
933 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
934
935 int_params.irq_source = DC_IRQ_SOURCE_HPD5;
936
937 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
938 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
939 dm_test_irq_handler, adev);
940 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
941
942 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
943 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
944 dm_test_irq_handler, adev);
945 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
946
947 KUNIT_EXPECT_FALSE(test,
948 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD5]));
949 KUNIT_EXPECT_FALSE(test,
950 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5]));
951
952 /*
953 * A single unregister call stops at the first context where the handler
954 * is found (low context), leaving the high context handler in place.
955 */
956 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD5,
957 dm_test_irq_handler);
958
959 KUNIT_EXPECT_TRUE(test,
960 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD5]));
961 KUNIT_EXPECT_FALSE(test,
962 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5]));
963
964 /* A second call removes the remaining high context handler. */
965 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD5,
966 dm_test_irq_handler);
967
968 KUNIT_EXPECT_TRUE(test,
969 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5]));
970 }
971
972 /* Tests for amdgpu_dm_irq_unregister_interrupt() */
973
974 /**
975 * dm_test_irq_unregister_rejects_invalid_source - Test unregister rejects source
976 * @test: The KUnit test context
977 */
dm_test_irq_unregister_rejects_invalid_source(struct kunit * test)978 static void dm_test_irq_unregister_rejects_invalid_source(struct kunit *test)
979 {
980 struct amdgpu_device *adev;
981
982 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
983 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
984 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
985
986 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_INVALID,
987 dm_test_irq_handler);
988
989 KUNIT_EXPECT_TRUE(test,
990 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
991 KUNIT_EXPECT_TRUE(test,
992 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1]));
993 }
994
995 /**
996 * dm_test_irq_unregister_rejects_null_handler - Test unregister rejects handler
997 * @test: The KUnit test context
998 */
dm_test_irq_unregister_rejects_null_handler(struct kunit * test)999 static void dm_test_irq_unregister_rejects_null_handler(struct kunit *test)
1000 {
1001 struct amdgpu_device *adev;
1002
1003 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1004 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1005 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1006
1007 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
1008 DAL_INVALID_IRQ_HANDLER_IDX);
1009
1010 KUNIT_EXPECT_TRUE(test,
1011 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
1012 KUNIT_EXPECT_TRUE(test,
1013 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1]));
1014 }
1015
1016 /**
1017 * dm_test_irq_unregister_handler_not_found - Test unregister keeps unmatched handler
1018 * @test: The KUnit test context
1019 */
dm_test_irq_unregister_handler_not_found(struct kunit * test)1020 static void dm_test_irq_unregister_handler_not_found(struct kunit *test)
1021 {
1022 struct amdgpu_device *adev;
1023 struct dc_interrupt_params int_params = { 0 };
1024 void *handler;
1025
1026 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1027 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1028 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1029
1030 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1031 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1032 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1033 dm_test_irq_handler, adev);
1034 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1035
1036 /* Unregister a handler that was never registered for this source. */
1037 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
1038 dm_test_irq_handler_alt);
1039
1040 /* The originally registered handler must still be present. */
1041 KUNIT_EXPECT_FALSE(test,
1042 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
1043
1044 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
1045 dm_test_irq_handler);
1046 KUNIT_EXPECT_TRUE(test,
1047 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
1048 }
1049
1050 /* Tests for amdgpu_dm_irq_fini() */
1051
1052 /**
1053 * dm_test_irq_fini_removes_registered_handlers - Test fini removes handlers
1054 * @test: The KUnit test context
1055 */
dm_test_irq_fini_removes_registered_handlers(struct kunit * test)1056 static void dm_test_irq_fini_removes_registered_handlers(struct kunit *test)
1057 {
1058 struct amdgpu_device *adev;
1059 struct dc_interrupt_params int_params = { 0 };
1060 void *handler;
1061
1062 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1063 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1064 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1065
1066 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1067 int_params.irq_source = DC_IRQ_SOURCE_HPD3;
1068 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1069 dm_test_irq_handler, adev);
1070 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1071
1072 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1073 int_params.irq_source = DC_IRQ_SOURCE_HPD4;
1074 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1075 dm_test_irq_handler, adev);
1076 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1077
1078 amdgpu_dm_irq_fini(adev);
1079
1080 KUNIT_EXPECT_TRUE(test,
1081 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD3]));
1082 KUNIT_EXPECT_TRUE(test,
1083 list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD4]));
1084 }
1085
1086 /**
1087 * dm_test_irq_fini_on_empty_tables - Test fini on tables with no handlers
1088 * @test: The KUnit test context
1089 */
dm_test_irq_fini_on_empty_tables(struct kunit * test)1090 static void dm_test_irq_fini_on_empty_tables(struct kunit *test)
1091 {
1092 struct amdgpu_device *adev;
1093 int src;
1094
1095 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1096 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1097 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1098
1099 amdgpu_dm_irq_fini(adev);
1100
1101 for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) {
1102 KUNIT_EXPECT_TRUE(test,
1103 list_empty(&adev->dm.irq_handler_list_low_tab[src]));
1104 KUNIT_EXPECT_TRUE(test,
1105 list_empty(&adev->dm.irq_handler_list_high_tab[src]));
1106 }
1107 }
1108
1109 /* Tests for amdgpu_dm_get_crtc_by_otg_inst() */
1110
1111 /**
1112 * dm_test_get_crtc_by_otg_inst_returns_match - Test CRTC lookup by OTG instance
1113 * @test: The KUnit test context
1114 */
dm_test_get_crtc_by_otg_inst_returns_match(struct kunit * test)1115 static void dm_test_get_crtc_by_otg_inst_returns_match(struct kunit *test)
1116 {
1117 struct amdgpu_crtc *acrtc_a, *acrtc_b;
1118 struct amdgpu_device *adev;
1119 struct drm_device *drm;
1120
1121 adev = dm_kunit_alloc_adev(test);
1122 drm = &adev->ddev;
1123
1124 acrtc_a = kunit_kzalloc(test, sizeof(*acrtc_a), GFP_KERNEL);
1125 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_a);
1126 acrtc_b = kunit_kzalloc(test, sizeof(*acrtc_b), GFP_KERNEL);
1127 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_b);
1128
1129 INIT_LIST_HEAD(&acrtc_a->base.head);
1130 INIT_LIST_HEAD(&acrtc_b->base.head);
1131 acrtc_a->otg_inst = 1;
1132 acrtc_b->otg_inst = 3;
1133
1134 list_add_tail(&acrtc_a->base.head, &drm->mode_config.crtc_list);
1135 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, acrtc_a), 0);
1136 list_add_tail(&acrtc_b->base.head, &drm->mode_config.crtc_list);
1137 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, acrtc_b), 0);
1138
1139 KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 3), acrtc_b);
1140 }
1141
1142 /**
1143 * dm_test_get_crtc_by_otg_inst_returns_null - Test CRTC lookup misses unknown OTG
1144 * @test: The KUnit test context
1145 */
dm_test_get_crtc_by_otg_inst_returns_null(struct kunit * test)1146 static void dm_test_get_crtc_by_otg_inst_returns_null(struct kunit *test)
1147 {
1148 struct amdgpu_crtc *acrtc;
1149 struct amdgpu_device *adev;
1150 struct drm_device *drm;
1151
1152 adev = dm_kunit_alloc_adev(test);
1153 drm = &adev->ddev;
1154
1155 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1156 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1157
1158 INIT_LIST_HEAD(&acrtc->base.head);
1159 acrtc->otg_inst = 2;
1160
1161 list_add_tail(&acrtc->base.head, &drm->mode_config.crtc_list);
1162 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, acrtc), 0);
1163
1164 KUNIT_EXPECT_NULL(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 5));
1165 }
1166
1167 /**
1168 * dm_test_get_crtc_by_otg_inst_empty_list - Test CRTC lookup on empty CRTC list
1169 * @test: The KUnit test context
1170 */
dm_test_get_crtc_by_otg_inst_empty_list(struct kunit * test)1171 static void dm_test_get_crtc_by_otg_inst_empty_list(struct kunit *test)
1172 {
1173 struct amdgpu_device *adev;
1174
1175 adev = dm_kunit_alloc_adev(test);
1176
1177 KUNIT_EXPECT_NULL(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 0));
1178 }
1179
1180 /* Tests for amdgpu_dm_set_irq_funcs() */
1181
1182 /**
1183 * dm_test_set_irq_funcs - Test irq src funcs and counts are populated
1184 * @test: The KUnit test context
1185 */
dm_test_set_irq_funcs(struct kunit * test)1186 static void dm_test_set_irq_funcs(struct kunit *test)
1187 {
1188 struct amdgpu_device *adev;
1189
1190 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1191 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1192
1193 adev->mode_info.num_crtc = 6;
1194 adev->mode_info.num_hpd = 4;
1195
1196 amdgpu_dm_set_irq_funcs(adev);
1197
1198 KUNIT_EXPECT_EQ(test, adev->crtc_irq.num_types, 6);
1199 KUNIT_EXPECT_EQ(test, adev->vline0_irq.num_types, 6);
1200 KUNIT_EXPECT_EQ(test, adev->vupdate_irq.num_types, 6);
1201 KUNIT_EXPECT_EQ(test, adev->pageflip_irq.num_types, 6);
1202 KUNIT_EXPECT_EQ(test, adev->dmub_outbox_irq.num_types, 1);
1203 KUNIT_EXPECT_EQ(test, adev->dmub_trace_irq.num_types, 1);
1204 KUNIT_EXPECT_EQ(test, adev->hpd_irq.num_types, 4);
1205
1206 KUNIT_EXPECT_TRUE(test, adev->crtc_irq.funcs != NULL);
1207 KUNIT_EXPECT_TRUE(test, adev->vline0_irq.funcs != NULL);
1208 KUNIT_EXPECT_TRUE(test, adev->dmub_outbox_irq.funcs != NULL);
1209 KUNIT_EXPECT_TRUE(test, adev->vupdate_irq.funcs != NULL);
1210 KUNIT_EXPECT_TRUE(test, adev->dmub_trace_irq.funcs != NULL);
1211 KUNIT_EXPECT_TRUE(test, adev->pageflip_irq.funcs != NULL);
1212 KUNIT_EXPECT_TRUE(test, adev->hpd_irq.funcs != NULL);
1213 }
1214
1215 /* Tests for amdgpu_dm_irq_suspend()/resume_early()/resume_late() */
1216
1217 /**
1218 * dm_test_irq_suspend_empty - Test suspend walks empty handler tables safely
1219 * @test: The KUnit test context
1220 */
dm_test_irq_suspend_empty(struct kunit * test)1221 static void dm_test_irq_suspend_empty(struct kunit *test)
1222 {
1223 struct amdgpu_device *adev;
1224 int src;
1225
1226 adev = dm_kunit_alloc_adev(test);
1227 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1228
1229 /*
1230 * With no registered handlers the amdgpu_dm_irq_set() calls are
1231 * skipped, so suspend must complete without touching the (absent) DC.
1232 */
1233 amdgpu_dm_irq_suspend(adev);
1234
1235 for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) {
1236 KUNIT_EXPECT_TRUE(test, list_empty(&adev->dm.irq_handler_list_low_tab[src]));
1237 KUNIT_EXPECT_TRUE(test, list_empty(&adev->dm.irq_handler_list_high_tab[src]));
1238 }
1239 }
1240
1241 /**
1242 * dm_test_irq_resume_early_empty - Test early resume walks empty tables safely
1243 * @test: The KUnit test context
1244 */
dm_test_irq_resume_early_empty(struct kunit * test)1245 static void dm_test_irq_resume_early_empty(struct kunit *test)
1246 {
1247 struct amdgpu_device *adev;
1248 int src;
1249
1250 adev = dm_kunit_alloc_adev(test);
1251 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1252
1253 amdgpu_dm_irq_resume_early(adev);
1254
1255 for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++)
1256 KUNIT_EXPECT_TRUE(test, list_empty(&adev->dm.irq_handler_list_high_tab[src]));
1257 }
1258
1259 /**
1260 * dm_test_irq_resume_late_empty - Test late resume walks empty tables safely
1261 * @test: The KUnit test context
1262 */
dm_test_irq_resume_late_empty(struct kunit * test)1263 static void dm_test_irq_resume_late_empty(struct kunit *test)
1264 {
1265 struct amdgpu_device *adev;
1266 int src;
1267
1268 adev = dm_kunit_alloc_adev(test);
1269 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1270
1271 amdgpu_dm_irq_resume_late(adev);
1272
1273 for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++)
1274 KUNIT_EXPECT_TRUE(test, list_empty(&adev->dm.irq_handler_list_low_tab[src]));
1275 }
1276
1277 /**
1278 * dm_test_irq_suspend_registered - Test suspend reaches the irq set path
1279 * @test: The KUnit test context
1280 *
1281 * Registers a low-context HPD handler so the handler list is non-empty,
1282 * forcing amdgpu_dm_irq_suspend() to call amdgpu_dm_irq_set() (NULL-safe with
1283 * no DC) and flush_work() on the registered handler.
1284 */
dm_test_irq_suspend_registered(struct kunit * test)1285 static void dm_test_irq_suspend_registered(struct kunit *test)
1286 {
1287 struct dc_interrupt_params int_params = { 0 };
1288 struct amdgpu_device *adev;
1289 void *handler;
1290
1291 adev = dm_kunit_alloc_adev(test);
1292 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1293
1294 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1295 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1296 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1297 dm_test_irq_handler, adev);
1298 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1299
1300 amdgpu_dm_irq_suspend(adev);
1301
1302 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
1303 dm_test_irq_handler);
1304 }
1305
1306 /**
1307 * dm_test_irq_suspend_disables_polling - Test suspend disables KMS polling
1308 * @test: The KUnit test context
1309 *
1310 * With KMS polling active, suspend must take the poll-disable branch.
1311 * drm_kms_helper_poll_disable() only cancels the poll work; it leaves the
1312 * poll_enabled flag set (cleared later by drm_kms_helper_poll_fini()).
1313 */
dm_test_irq_suspend_disables_polling(struct kunit * test)1314 static void dm_test_irq_suspend_disables_polling(struct kunit *test)
1315 {
1316 struct amdgpu_device *adev;
1317
1318 adev = dm_kunit_alloc_adev(test);
1319 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1320
1321 /* Enable KMS polling so suspend takes the poll-disable branch. */
1322 drm_kms_helper_poll_init(&adev->ddev);
1323 KUNIT_ASSERT_TRUE(test, adev->ddev.mode_config.poll_enabled);
1324
1325 amdgpu_dm_irq_suspend(adev);
1326
1327 KUNIT_EXPECT_TRUE(test, adev->ddev.mode_config.poll_enabled);
1328
1329 drm_kms_helper_poll_fini(&adev->ddev);
1330 }
1331
1332 /**
1333 * dm_test_irq_resume_early_registered - Test early resume reaches irq set
1334 * @test: The KUnit test context
1335 *
1336 * Registers a low-context HPD RX handler so early resume calls
1337 * amdgpu_dm_irq_set() for the short-pulse interrupt source.
1338 */
dm_test_irq_resume_early_registered(struct kunit * test)1339 static void dm_test_irq_resume_early_registered(struct kunit *test)
1340 {
1341 struct dc_interrupt_params int_params = { 0 };
1342 struct amdgpu_device *adev;
1343 void *handler;
1344
1345 adev = dm_kunit_alloc_adev(test);
1346 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1347
1348 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1349 int_params.irq_source = DC_IRQ_SOURCE_HPD1RX;
1350 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1351 dm_test_irq_handler, adev);
1352 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1353
1354 amdgpu_dm_irq_resume_early(adev);
1355
1356 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1RX,
1357 dm_test_irq_handler);
1358 }
1359
1360 /**
1361 * dm_test_irq_resume_late_registered - Test late resume reaches irq set
1362 * @test: The KUnit test context
1363 *
1364 * Registers a low-context HPD handler so late resume calls amdgpu_dm_irq_set()
1365 * for the HPD interrupt source.
1366 */
dm_test_irq_resume_late_registered(struct kunit * test)1367 static void dm_test_irq_resume_late_registered(struct kunit *test)
1368 {
1369 struct dc_interrupt_params int_params = { 0 };
1370 struct amdgpu_device *adev;
1371 void *handler;
1372
1373 adev = dm_kunit_alloc_adev(test);
1374 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1375
1376 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1377 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1378 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1379 dm_test_irq_handler, adev);
1380 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1381
1382 amdgpu_dm_irq_resume_late(adev);
1383
1384 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1,
1385 dm_test_irq_handler);
1386 }
1387
1388 /**
1389 * dm_test_irq_resume_late_enables_polling - Test late resume re-enables polling
1390 * @test: The KUnit test context
1391 *
1392 * With KMS polling active, late resume must take the poll-enable branch and
1393 * leave polling enabled.
1394 */
dm_test_irq_resume_late_enables_polling(struct kunit * test)1395 static void dm_test_irq_resume_late_enables_polling(struct kunit *test)
1396 {
1397 struct amdgpu_device *adev;
1398
1399 adev = dm_kunit_alloc_adev(test);
1400 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1401
1402 /* Enable KMS polling so resume_late takes the poll-enable branch. */
1403 drm_kms_helper_poll_init(&adev->ddev);
1404 KUNIT_ASSERT_TRUE(test, adev->ddev.mode_config.poll_enabled);
1405
1406 amdgpu_dm_irq_resume_late(adev);
1407
1408 KUNIT_EXPECT_TRUE(test, adev->ddev.mode_config.poll_enabled);
1409
1410 drm_kms_helper_poll_fini(&adev->ddev);
1411 }
1412
1413 /* Tests for amdgpu_dm_hpd_rx_irq_create_workqueue() */
1414
1415 /**
1416 * dm_test_hpd_rx_irq_create_workqueue - Test workqueue array creation
1417 * @test: The KUnit test context
1418 */
dm_test_hpd_rx_irq_create_workqueue(struct kunit * test)1419 static void dm_test_hpd_rx_irq_create_workqueue(struct kunit *test)
1420 {
1421 struct dm_test_hpd_rx_wq_ctx *ctx;
1422 struct amdgpu_device *adev;
1423 struct dc *dc;
1424 int i;
1425
1426 adev = dm_kunit_alloc_adev(test);
1427
1428 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
1429 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
1430 dc->caps.max_links = 4;
1431 adev->dm.dc = dc;
1432
1433 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
1434 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
1435
1436 ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
1437 KUNIT_ASSERT_NOT_NULL(test, ctx->wq);
1438 ctx->count = dc->caps.max_links;
1439 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_destroy_hpd_rx_wq, ctx), 0);
1440
1441 for (i = 0; i < dc->caps.max_links; i++)
1442 KUNIT_EXPECT_TRUE(test, ctx->wq[i].wq != NULL);
1443 }
1444
1445 /* Tests for amdgpu_dm_hpd_rx_irq_work_suspend() */
1446
1447 /**
1448 * dm_test_hpd_rx_irq_work_suspend_null - Test suspend with no work queue
1449 * @test: The KUnit test context
1450 */
dm_test_hpd_rx_irq_work_suspend_null(struct kunit * test)1451 static void dm_test_hpd_rx_irq_work_suspend_null(struct kunit *test)
1452 {
1453 struct amdgpu_display_manager *dm;
1454
1455 dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
1456 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm);
1457
1458 /* A NULL hpd_rx_offload_wq must be a safe no-op (DC untouched). */
1459 amdgpu_dm_hpd_rx_irq_work_suspend(dm);
1460 }
1461
1462 /**
1463 * dm_test_hpd_rx_irq_work_suspend_flushes - Test suspend flushes queues
1464 * @test: The KUnit test context
1465 */
dm_test_hpd_rx_irq_work_suspend_flushes(struct kunit * test)1466 static void dm_test_hpd_rx_irq_work_suspend_flushes(struct kunit *test)
1467 {
1468 struct dm_test_hpd_rx_wq_ctx *ctx;
1469 struct amdgpu_device *adev;
1470 struct dc *dc;
1471
1472 adev = dm_kunit_alloc_adev(test);
1473
1474 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
1475 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
1476 dc->caps.max_links = 2;
1477 adev->dm.dc = dc;
1478
1479 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
1480 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
1481
1482 ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
1483 KUNIT_ASSERT_NOT_NULL(test, ctx->wq);
1484 ctx->count = dc->caps.max_links;
1485 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_destroy_hpd_rx_wq, ctx), 0);
1486
1487 adev->dm.hpd_rx_offload_wq = ctx->wq;
1488
1489 amdgpu_dm_hpd_rx_irq_work_suspend(&adev->dm);
1490 }
1491
1492 /* Tests for CRTC-based irq state callbacks (no-CRTC early return) */
1493
1494 /**
1495 * dm_test_set_crtc_irq_state_no_crtc - Test crtc irq state with missing CRTC
1496 * @test: The KUnit test context
1497 */
dm_test_set_crtc_irq_state_no_crtc(struct kunit * test)1498 static void dm_test_set_crtc_irq_state_no_crtc(struct kunit *test)
1499 {
1500 struct amdgpu_device *adev;
1501
1502 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1503 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1504
1505 /* mode_info.crtcs[0] is NULL -> returns 0 without dereferencing DC. */
1506 KUNIT_EXPECT_EQ(test,
1507 amdgpu_dm_set_crtc_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1508 }
1509
1510 /**
1511 * dm_test_set_pflip_irq_state_no_crtc - Test pflip irq state with missing CRTC
1512 * @test: The KUnit test context
1513 */
dm_test_set_pflip_irq_state_no_crtc(struct kunit * test)1514 static void dm_test_set_pflip_irq_state_no_crtc(struct kunit *test)
1515 {
1516 struct amdgpu_device *adev;
1517
1518 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1519 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1520
1521 KUNIT_EXPECT_EQ(test,
1522 amdgpu_dm_set_pflip_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_DISABLE), 0);
1523 }
1524
1525 /**
1526 * dm_test_set_vline0_irq_state_no_crtc - Test vline0 irq state with missing CRTC
1527 * @test: The KUnit test context
1528 */
dm_test_set_vline0_irq_state_no_crtc(struct kunit * test)1529 static void dm_test_set_vline0_irq_state_no_crtc(struct kunit *test)
1530 {
1531 struct amdgpu_device *adev;
1532
1533 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1534 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1535
1536 KUNIT_EXPECT_EQ(test,
1537 amdgpu_dm_set_vline0_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1538 }
1539
1540 /**
1541 * dm_test_set_vupdate_irq_state_no_crtc - Test vupdate irq state with missing CRTC
1542 * @test: The KUnit test context
1543 */
dm_test_set_vupdate_irq_state_no_crtc(struct kunit * test)1544 static void dm_test_set_vupdate_irq_state_no_crtc(struct kunit *test)
1545 {
1546 struct amdgpu_device *adev;
1547
1548 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1549 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1550
1551 KUNIT_EXPECT_EQ(test,
1552 amdgpu_dm_set_vupdate_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1553 }
1554
1555 /* Tests for CRTC-based irq state callbacks (dm_irq_state happy path) */
1556
1557 /**
1558 * dm_test_set_crtc_irq_state_otg_disabled - Test crtc irq state with disabled OTG
1559 * @test: The KUnit test context
1560 */
dm_test_set_crtc_irq_state_otg_disabled(struct kunit * test)1561 static void dm_test_set_crtc_irq_state_otg_disabled(struct kunit *test)
1562 {
1563 struct amdgpu_device *adev;
1564 struct amdgpu_crtc *acrtc;
1565
1566 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1567 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1568 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1569 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1570
1571 /* otg_inst == -1 short-circuits before computing the irq source. */
1572 acrtc->otg_inst = -1;
1573 adev->mode_info.crtcs[0] = acrtc;
1574
1575 KUNIT_EXPECT_EQ(test,
1576 amdgpu_dm_set_crtc_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1577 }
1578
1579 /**
1580 * dm_test_set_crtc_irq_state_enable - Test crtc irq state reaches DC (enable)
1581 * @test: The KUnit test context
1582 */
dm_test_set_crtc_irq_state_enable(struct kunit * test)1583 static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
1584 {
1585 struct amdgpu_device *adev;
1586 struct amdgpu_crtc *acrtc;
1587
1588 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1589 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1590 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1591 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1592
1593 /*
1594 * otg_inst >= 0 computes the irq source and reaches the NULL-safe
1595 * amdgpu_dm_irq_set(); the ips_support branch is skipped (dc == NULL).
1596 */
1597 acrtc->otg_inst = 3;
1598 adev->mode_info.crtcs[0] = acrtc;
1599
1600 KUNIT_EXPECT_EQ(test,
1601 amdgpu_dm_set_crtc_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1602 }
1603
1604 /**
1605 * dm_test_set_pflip_irq_state_disable - Test pflip irq state reaches DC (disable)
1606 * @test: The KUnit test context
1607 */
dm_test_set_pflip_irq_state_disable(struct kunit * test)1608 static void dm_test_set_pflip_irq_state_disable(struct kunit *test)
1609 {
1610 struct amdgpu_device *adev;
1611 struct amdgpu_crtc *acrtc;
1612
1613 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1614 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1615 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1616 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1617
1618 /* The disable state exercises the st == false path. */
1619 acrtc->otg_inst = 1;
1620 adev->mode_info.crtcs[0] = acrtc;
1621
1622 KUNIT_EXPECT_EQ(test,
1623 amdgpu_dm_set_pflip_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_DISABLE), 0);
1624 }
1625
1626 /**
1627 * dm_test_set_vline0_irq_state_enable - Test vline0 irq state reaches DC (enable)
1628 * @test: The KUnit test context
1629 */
dm_test_set_vline0_irq_state_enable(struct kunit * test)1630 static void dm_test_set_vline0_irq_state_enable(struct kunit *test)
1631 {
1632 struct amdgpu_device *adev;
1633 struct amdgpu_crtc *acrtc;
1634
1635 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1636 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1637 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1638 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1639
1640 acrtc->otg_inst = 0;
1641 adev->mode_info.crtcs[0] = acrtc;
1642
1643 KUNIT_EXPECT_EQ(test,
1644 amdgpu_dm_set_vline0_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1645 }
1646
1647 /**
1648 * dm_test_set_vupdate_irq_state_enable - Test vupdate irq state reaches DC (enable)
1649 * @test: The KUnit test context
1650 */
dm_test_set_vupdate_irq_state_enable(struct kunit * test)1651 static void dm_test_set_vupdate_irq_state_enable(struct kunit *test)
1652 {
1653 struct amdgpu_device *adev;
1654 struct amdgpu_crtc *acrtc;
1655
1656 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1657 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1658 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1659 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1660
1661 acrtc->otg_inst = 2;
1662 adev->mode_info.crtcs[0] = acrtc;
1663
1664 KUNIT_EXPECT_EQ(test,
1665 amdgpu_dm_set_vupdate_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1666 }
1667
1668 /**
1669 * dm_test_set_crtc_irq_state_allows_idle - Test the idle-optimization branch
1670 * @test: The KUnit test context
1671 *
1672 * With a non-NULL DC that advertises IPS support and currently allows idle
1673 * optimizations, dm_irq_state() must call dc_allow_idle_optimizations() before
1674 * amdgpu_dm_irq_set(). disable_idle_power_optimizations makes that call a safe
1675 * early return, and per-source stub funcs let amdgpu_dm_irq_set() succeed.
1676 */
dm_test_set_crtc_irq_state_allows_idle(struct kunit * test)1677 static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
1678 {
1679 struct amdgpu_device *adev;
1680 struct amdgpu_crtc *acrtc;
1681 struct dal_logger *logger;
1682 struct dc *dc;
1683
1684 adev = dm_kunit_alloc_adev(test);
1685 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
1686 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
1687
1688 dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
1689
1690 /* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */
1691 logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
1692 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
1693 logger->dev = &adev->ddev;
1694 dc->ctx->logger = logger;
1695
1696 dc->caps.ips_support = true;
1697 dc->idle_optimizations_allowed = true;
1698 /* Keep dc_allow_idle_optimizations() a safe early return. */
1699 dc->debug.disable_idle_power_optimizations = true;
1700 adev->dm.dc = dc;
1701
1702 acrtc->otg_inst = 0;
1703 adev->mode_info.crtcs[0] = acrtc;
1704
1705 KUNIT_EXPECT_EQ(test,
1706 amdgpu_dm_set_crtc_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0);
1707 }
1708
1709 /* Tests for amdgpu_dm_irq_immediate_work() */
1710
1711 /**
1712 * dm_test_irq_immediate_work_empty - Test immediate work on empty high table
1713 * @test: The KUnit test context
1714 */
dm_test_irq_immediate_work_empty(struct kunit * test)1715 static void dm_test_irq_immediate_work_empty(struct kunit *test)
1716 {
1717 struct amdgpu_device *adev;
1718
1719 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1720 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1721 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1722
1723 /* No registered high-context handlers: must be a safe no-op. */
1724 amdgpu_dm_irq_immediate_work(adev, DC_IRQ_SOURCE_HPD1);
1725 }
1726
1727 /**
1728 * dm_test_irq_immediate_work_invokes_handler - Test immediate work calls handler
1729 * @test: The KUnit test context
1730 */
dm_test_irq_immediate_work_invokes_handler(struct kunit * test)1731 static void dm_test_irq_immediate_work_invokes_handler(struct kunit *test)
1732 {
1733 struct amdgpu_device *adev;
1734 struct dc_interrupt_params int_params = { 0 };
1735 int count = 0;
1736 void *handler;
1737
1738 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1739 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1740 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1741
1742 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1743 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1744 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1745 dm_test_irq_handler_count, &count);
1746 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1747
1748 /* High-context handlers are invoked synchronously, in-place. */
1749 amdgpu_dm_irq_immediate_work(adev, DC_IRQ_SOURCE_HPD1);
1750 KUNIT_EXPECT_EQ(test, count, 1);
1751
1752 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, dm_test_irq_handler_count);
1753 }
1754
1755 /**
1756 * dm_test_irq_immediate_work_invokes_all - Test immediate work calls all handlers
1757 * @test: The KUnit test context
1758 */
dm_test_irq_immediate_work_invokes_all(struct kunit * test)1759 static void dm_test_irq_immediate_work_invokes_all(struct kunit *test)
1760 {
1761 struct amdgpu_device *adev;
1762 struct dc_interrupt_params int_params = { 0 };
1763 int count = 0;
1764 void *handler;
1765
1766 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1767 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1768 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1769
1770 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1771 int_params.irq_source = DC_IRQ_SOURCE_HPD2;
1772 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1773 dm_test_irq_handler_count, &count);
1774 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1775 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1776 dm_test_irq_handler_count, &count);
1777 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1778
1779 /* Both registered high-context handlers must run. */
1780 amdgpu_dm_irq_immediate_work(adev, DC_IRQ_SOURCE_HPD2);
1781 KUNIT_EXPECT_EQ(test, count, 2);
1782
1783 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD2, dm_test_irq_handler_count);
1784 amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD2, dm_test_irq_handler_count);
1785 }
1786
1787 /* Tests for amdgpu_dm_irq_schedule_work() */
1788
1789 /**
1790 * dm_test_irq_schedule_work_empty - Test schedule work on empty low table
1791 * @test: The KUnit test context
1792 */
dm_test_irq_schedule_work_empty(struct kunit * test)1793 static void dm_test_irq_schedule_work_empty(struct kunit *test)
1794 {
1795 struct amdgpu_device *adev;
1796
1797 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1798 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1799 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1800
1801 /* Empty handler list: schedule_work returns immediately. */
1802 amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
1803 }
1804
1805 /**
1806 * dm_test_irq_schedule_work_queues_handler - Test schedule work runs handler
1807 * @test: The KUnit test context
1808 */
dm_test_irq_schedule_work_queues_handler(struct kunit * test)1809 static void dm_test_irq_schedule_work_queues_handler(struct kunit *test)
1810 {
1811 struct amdgpu_device *adev;
1812 struct dc_interrupt_params int_params = { 0 };
1813 int count = 0;
1814 void *handler;
1815
1816 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1817 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1818 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1819
1820 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1821 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1822 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1823 dm_test_irq_handler_count, &count);
1824 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1825
1826 amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
1827
1828 /*
1829 * Low-context work runs asynchronously on the DM IRQ workqueue.
1830 * Flush it so the handler completes before we check the count;
1831 * amdgpu_dm_irq_fini() cancels (rather than runs) any work that is
1832 * still pending, so the flush must happen first.
1833 */
1834 flush_workqueue(adev->dm.irq_wq);
1835 KUNIT_EXPECT_EQ(test, count, 1);
1836
1837 amdgpu_dm_irq_fini(adev);
1838 }
1839
1840 /**
1841 * dm_test_irq_schedule_work_requeue_fallback - Test the re-queue fallback path
1842 * @test: The KUnit test context
1843 *
1844 * The first schedule queues the handler's work item. Issuing a second
1845 * schedule before the work has run makes queue_work() fail for the
1846 * still-pending item, forcing amdgpu_dm_irq_schedule_work() into the fallback
1847 * that allocates and queues a fresh handler copy. Both work items run when
1848 * the DM IRQ workqueue is flushed, so the handler fires twice.
1849 */
dm_test_irq_schedule_work_requeue_fallback(struct kunit * test)1850 static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test)
1851 {
1852 struct dc_interrupt_params int_params = { 0 };
1853 struct amdgpu_device *adev;
1854 int count = 0;
1855 void *handler;
1856
1857 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1858 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1859 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
1860
1861 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1862 int_params.irq_source = DC_IRQ_SOURCE_HPD1;
1863 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
1864 dm_test_irq_handler_count, &count);
1865 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
1866
1867 amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
1868 amdgpu_dm_irq_schedule_work(adev, DC_IRQ_SOURCE_HPD1);
1869
1870 /*
1871 * Flush the DM IRQ workqueue so both work items run before we check
1872 * the count; amdgpu_dm_irq_fini() would cancel any still-pending work
1873 * instead of running it.
1874 */
1875 flush_workqueue(adev->dm.irq_wq);
1876 KUNIT_EXPECT_EQ(test, count, 2);
1877
1878 amdgpu_dm_irq_fini(adev);
1879 }
1880
1881 /* Tests for amdgpu_dm_set_hpd_irq_state() */
1882
1883 /**
1884 * dm_test_set_hpd_irq_state_null_dc - Test HPD irq state with no DC
1885 * @test: The KUnit test context
1886 */
dm_test_set_hpd_irq_state_null_dc(struct kunit * test)1887 static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
1888 {
1889 struct amdgpu_device *adev;
1890
1891 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1892 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1893
1894 /* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
1895 * return 0 without dereferencing the (absent) DC.
1896 */
1897 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
1898 AMDGPU_IRQ_STATE_ENABLE), 0);
1899 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
1900 AMDGPU_IRQ_STATE_DISABLE), 0);
1901 }
1902
1903 /* Tests for amdgpu_dm_set_dmub_outbox_irq_state() */
1904
1905 /**
1906 * dm_test_set_dmub_outbox_irq_state_null_dc - Test outbox irq state with no DC
1907 * @test: The KUnit test context
1908 */
dm_test_set_dmub_outbox_irq_state_null_dc(struct kunit * test)1909 static void dm_test_set_dmub_outbox_irq_state_null_dc(struct kunit *test)
1910 {
1911 struct amdgpu_device *adev;
1912
1913 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1914 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1915
1916 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_outbox_irq_state(adev, NULL, 0,
1917 AMDGPU_IRQ_STATE_ENABLE), 0);
1918 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_outbox_irq_state(adev, NULL, 0,
1919 AMDGPU_IRQ_STATE_DISABLE), 0);
1920 }
1921
1922 /* Tests for amdgpu_dm_set_dmub_trace_irq_state() */
1923
1924 /**
1925 * dm_test_set_dmub_trace_irq_state_null_dc - Test trace irq state with no DC
1926 * @test: The KUnit test context
1927 */
dm_test_set_dmub_trace_irq_state_null_dc(struct kunit * test)1928 static void dm_test_set_dmub_trace_irq_state_null_dc(struct kunit *test)
1929 {
1930 struct amdgpu_device *adev;
1931
1932 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1933 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1934
1935 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_trace_irq_state(adev, NULL, 0,
1936 AMDGPU_IRQ_STATE_ENABLE), 0);
1937 KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_trace_irq_state(adev, NULL, 0,
1938 AMDGPU_IRQ_STATE_DISABLE), 0);
1939 }
1940
1941 /* Tests for amdgpu_dm_outbox_init() */
1942
1943 /**
1944 * dm_test_outbox_init_null_dc - Test outbox init is a safe no-op with no DC
1945 * @test: The KUnit test context
1946 */
dm_test_outbox_init_null_dc(struct kunit * test)1947 static void dm_test_outbox_init_null_dc(struct kunit *test)
1948 {
1949 struct amdgpu_device *adev;
1950
1951 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
1952 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
1953
1954 /* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
1955 amdgpu_dm_outbox_init(adev);
1956 }
1957
1958 /* Tests for amdgpu_dm_hpd_init()/amdgpu_dm_hpd_fini() */
1959
1960 /**
1961 * dm_test_hpd_init_empty_connectors - Test HPD init with no connectors
1962 * @test: The KUnit test context
1963 */
dm_test_hpd_init_empty_connectors(struct kunit * test)1964 static void dm_test_hpd_init_empty_connectors(struct kunit *test)
1965 {
1966 struct amdgpu_device *adev;
1967
1968 adev = dm_kunit_alloc_adev(test);
1969
1970 /*
1971 * With an empty connector list the per-connector loop is skipped and
1972 * the initial clear loop relies on amdgpu_dm_irq_set() being a no-op
1973 * for a NULL dc, so init must complete without touching the DC.
1974 */
1975 amdgpu_dm_hpd_init(adev);
1976 }
1977
1978 /**
1979 * dm_test_hpd_fini_empty_connectors - Test HPD fini with no connectors
1980 * @test: The KUnit test context
1981 */
dm_test_hpd_fini_empty_connectors(struct kunit * test)1982 static void dm_test_hpd_fini_empty_connectors(struct kunit *test)
1983 {
1984 struct amdgpu_device *adev;
1985
1986 adev = dm_kunit_alloc_adev(test);
1987
1988 /* Empty connector list and disabled polling: fini is a safe no-op. */
1989 amdgpu_dm_hpd_fini(adev);
1990 }
1991
1992 /**
1993 * dm_test_hpd_init_fini_with_connectors - Test HPD init/fini walk connectors
1994 * @test: The KUnit test context
1995 */
dm_test_hpd_init_fini_with_connectors(struct kunit * test)1996 static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
1997 {
1998 struct amdgpu_dm_connector *aconn;
1999 struct drm_connector *wbconn;
2000 struct amdgpu_device *adev;
2001 struct dc_link *link;
2002
2003 adev = dm_kunit_alloc_adev(test);
2004
2005 /*
2006 * num_hpd = 0 forces irq_type >= num_hpd so the loop takes the HW
2007 * fallback (amdgpu_dm_irq_set()) instead of amdgpu_irq_get(); with a
2008 * NULL dc that fallback is a safe no-op.
2009 */
2010 adev->mode_info.num_hpd = 0;
2011
2012 /* A writeback connector must be skipped by the per-connector loop. */
2013 wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL);
2014 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn);
2015 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs,
2016 DRM_MODE_CONNECTOR_WRITEBACK), 0);
2017 KUNIT_ASSERT_EQ(test,
2018 kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0);
2019
2020 /* A DisplayPort connector with a dc_link exercises the loop body. */
2021 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
2022 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
2023 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
2024 &dm_test_connector_funcs,
2025 DRM_MODE_CONNECTOR_DisplayPort), 0);
2026 KUNIT_ASSERT_EQ(test,
2027 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
2028
2029 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2030 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2031 link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
2032 link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
2033 aconn->dc_link = link;
2034
2035 /* DC is absent (NULL), so the HW writes are NULL-safe no-ops. */
2036 amdgpu_dm_hpd_init(adev);
2037 amdgpu_dm_hpd_fini(adev);
2038 }
2039
2040 /**
2041 * dm_test_hpd_init_fini_analog_connector - Test HPD init/fini analog polling path
2042 * @test: The KUnit test context
2043 */
dm_test_hpd_init_fini_analog_connector(struct kunit * test)2044 static void dm_test_hpd_init_fini_analog_connector(struct kunit *test)
2045 {
2046 struct amdgpu_dm_connector *aconn;
2047 struct amdgpu_device *adev;
2048 struct dc_link *link;
2049
2050 adev = dm_kunit_alloc_adev(test);
2051 adev->mode_info.num_hpd = 0;
2052
2053 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
2054 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
2055 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
2056 &dm_test_connector_funcs,
2057 DRM_MODE_CONNECTOR_VGA), 0);
2058 KUNIT_ASSERT_EQ(test,
2059 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
2060
2061 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2062 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2063 link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
2064 link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
2065 /* An analog connector id makes the loop request polling. */
2066 link->link_id.id = CONNECTOR_ID_VGA;
2067 aconn->dc_link = link;
2068
2069 /* use_polling becomes true, so init must enable KMS polling. */
2070 amdgpu_dm_hpd_init(adev);
2071 KUNIT_EXPECT_TRUE(test, adev->ddev.mode_config.poll_enabled);
2072
2073 /* fini must tear the polling back down. */
2074 amdgpu_dm_hpd_fini(adev);
2075 KUNIT_EXPECT_FALSE(test, adev->ddev.mode_config.poll_enabled);
2076 }
2077
2078 /**
2079 * dm_test_hpd_init_fini_irq_ref - Test HPD init/fini base-driver irq ref path
2080 * @test: The KUnit test context
2081 */
dm_test_hpd_init_fini_irq_ref(struct kunit * test)2082 static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
2083 {
2084 struct amdgpu_dm_connector *aconn;
2085 struct amdgpu_device *adev;
2086 struct dc_link *link;
2087
2088 adev = dm_kunit_alloc_adev(test);
2089
2090 /*
2091 * num_hpd >= 1 makes irq_type (0) < num_hpd, so the loop takes the
2092 * amdgpu_irq_get()/amdgpu_irq_put() branch instead of the
2093 * amdgpu_dm_irq_set() fallback. The mock device has irq.installed ==
2094 * false, so both calls fail early with -ENOENT (logging an error)
2095 * without touching the base-driver irq state.
2096 */
2097 adev->mode_info.num_hpd = 1;
2098
2099 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
2100 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
2101 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
2102 &dm_test_connector_funcs,
2103 DRM_MODE_CONNECTOR_DisplayPort), 0);
2104 KUNIT_ASSERT_EQ(test,
2105 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
2106
2107 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2108 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2109 link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
2110 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
2111 aconn->dc_link = link;
2112
2113 amdgpu_dm_hpd_init(adev);
2114 amdgpu_dm_hpd_fini(adev);
2115 }
2116
2117 /* Tests for dm_handle_hpd_rx_offload_work() */
2118
2119 /**
2120 * dm_test_hpd_rx_offload_work_no_connector - Test missing connector early exit
2121 * @test: The KUnit test context
2122 */
dm_test_hpd_rx_offload_work_no_connector(struct kunit * test)2123 static void dm_test_hpd_rx_offload_work_no_connector(struct kunit *test)
2124 {
2125 struct hpd_rx_irq_offload_work_queue *offload_wq;
2126 struct hpd_rx_irq_offload_work *offload_work;
2127 struct amdgpu_device *adev;
2128
2129 adev = dm_kunit_alloc_adev(test);
2130
2131 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2132 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2133
2134 offload_work = kzalloc_obj(*offload_work);
2135 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
2136 offload_work->offload_wq = offload_wq;
2137 offload_work->adev = adev;
2138 INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
2139
2140 dm_handle_hpd_rx_offload_work(&offload_work->work);
2141 }
2142
2143 /**
2144 * dm_test_hpd_rx_offload_work_no_connection - Test no connection early exit
2145 * @test: The KUnit test context
2146 */
dm_test_hpd_rx_offload_work_no_connection(struct kunit * test)2147 static void dm_test_hpd_rx_offload_work_no_connection(struct kunit *test)
2148 {
2149 struct hpd_rx_irq_offload_work_queue *offload_wq;
2150 struct hpd_rx_irq_offload_work *offload_work;
2151 struct amdgpu_dm_connector *aconn;
2152 struct link_service *link_srv;
2153 struct amdgpu_device *adev;
2154 struct dc_link *link;
2155 struct dc *dc;
2156
2157 adev = dm_kunit_alloc_adev(test);
2158 mutex_init(&adev->dm.dc_lock);
2159
2160 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2161 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2162
2163 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2164 mutex_init(&aconn->hpd_lock);
2165 offload_wq->aconnector = aconn;
2166
2167 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2168 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2169
2170 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2171 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2172 link_srv->detect_connection_type = dm_test_detect_connection_none;
2173 dc->link_srv = link_srv;
2174
2175 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2176 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2177 link->dc = dc;
2178 aconn->dc_link = link;
2179
2180 offload_work = kzalloc_obj(*offload_work);
2181 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
2182 offload_work->offload_wq = offload_wq;
2183 offload_work->adev = adev;
2184 INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
2185
2186 dm_handle_hpd_rx_offload_work(&offload_work->work);
2187 }
2188
2189 /**
2190 * dm_test_hpd_rx_offload_work_automated_test - Test AUTOMATED_TEST branch
2191 * @test: The KUnit test context
2192 *
2193 * With a present connection and the AUTOMATED_TEST service-IRQ bit set, the
2194 * worker runs dc_link_dp_handle_automated_test() (stubbed via link_srv) and
2195 * writes the test response with core_link_write_dpcd(). timing_changed is left
2196 * false so force_connector_state() (which needs a registered DRM device) is
2197 * skipped, and aux_access_disabled makes the DPCD write a safe no-op.
2198 */
dm_test_hpd_rx_offload_work_automated_test(struct kunit * test)2199 static void dm_test_hpd_rx_offload_work_automated_test(struct kunit *test)
2200 {
2201 struct hpd_rx_irq_offload_work_queue *offload_wq;
2202 struct hpd_rx_irq_offload_work *offload_work;
2203 struct amdgpu_dm_connector *aconn;
2204 struct link_service *link_srv;
2205 struct amdgpu_device *adev;
2206 struct dc_context *ctx;
2207 struct dc_link *link;
2208 struct dc *dc;
2209
2210 dm_test_automated_test_count = 0;
2211
2212 adev = dm_kunit_alloc_adev(test);
2213 mutex_init(&adev->dm.dc_lock);
2214 adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain),
2215 GFP_KERNEL);
2216 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain);
2217
2218 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2219 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2220 spin_lock_init(&offload_wq->offload_lock);
2221
2222 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2223 mutex_init(&aconn->hpd_lock);
2224 aconn->timing_changed = false;
2225 offload_wq->aconnector = aconn;
2226
2227 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2228 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2229 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2230 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2231 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2232 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2233 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2234 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2235
2236 link_srv->detect_connection_type = dm_test_detect_connection_single;
2237 link_srv->dp_handle_automated_test = dm_test_dp_handle_automated_test;
2238 dc->link_srv = link_srv;
2239 dc->ctx = ctx;
2240 ctx->dc = dc;
2241 link->dc = dc;
2242 link->ctx = ctx;
2243 link->aux_access_disabled = true;
2244 link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
2245 aconn->dc_link = link;
2246
2247 offload_work = kzalloc_obj(*offload_work);
2248 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
2249 offload_work->offload_wq = offload_wq;
2250 offload_work->adev = adev;
2251 offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST = 1;
2252 INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
2253
2254 dm_handle_hpd_rx_offload_work(&offload_work->work);
2255
2256 KUNIT_EXPECT_EQ(test, dm_test_automated_test_count, 1);
2257 }
2258
2259 /**
2260 * dm_test_hpd_rx_offload_work_link_loss - Test link-loss branch
2261 * @test: The KUnit test context
2262 *
2263 * With a present non-eDP connection and no service-IRQ bits set, the worker
2264 * takes the else-if link-loss path: dc_link_check_link_loss_status() and
2265 * dc_link_dp_allow_hpd_rx_irq() gate entry, then dc_link_dp_read_hpd_rx_irq_data()
2266 * returns DC_OK and a second link-loss check triggers dc_link_dp_handle_link_loss().
2267 * All four are stubbed via link_srv.
2268 */
dm_test_hpd_rx_offload_work_link_loss(struct kunit * test)2269 static void dm_test_hpd_rx_offload_work_link_loss(struct kunit *test)
2270 {
2271 struct hpd_rx_irq_offload_work_queue *offload_wq;
2272 struct hpd_rx_irq_offload_work *offload_work;
2273 struct amdgpu_dm_connector *aconn;
2274 struct link_service *link_srv;
2275 struct amdgpu_device *adev;
2276 struct dc_context *ctx;
2277 struct dc_link *link;
2278 struct dc *dc;
2279
2280 dm_test_handle_link_loss_count = 0;
2281
2282 adev = dm_kunit_alloc_adev(test);
2283 mutex_init(&adev->dm.dc_lock);
2284 adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain),
2285 GFP_KERNEL);
2286 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain);
2287
2288 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2289 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2290 spin_lock_init(&offload_wq->offload_lock);
2291
2292 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2293 mutex_init(&aconn->hpd_lock);
2294 offload_wq->aconnector = aconn;
2295
2296 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2297 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2298 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2299 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2300 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2301 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2302 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2303 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2304
2305 link_srv->detect_connection_type = dm_test_detect_connection_single;
2306 link_srv->dp_parse_link_loss_status = dm_test_dp_parse_link_loss_true;
2307 link_srv->dp_should_allow_hpd_rx_irq = dm_test_dp_should_allow_hpd_rx_irq_true;
2308 link_srv->dp_read_hpd_rx_irq_data = dm_test_dp_read_hpd_rx_irq_data_ok;
2309 link_srv->dp_handle_link_loss = dm_test_dp_handle_link_loss;
2310 dc->link_srv = link_srv;
2311 dc->ctx = ctx;
2312 ctx->dc = dc;
2313 link->dc = dc;
2314 link->ctx = ctx;
2315 link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
2316 aconn->dc_link = link;
2317
2318 offload_work = kzalloc_obj(*offload_work);
2319 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work);
2320 offload_work->offload_wq = offload_wq;
2321 offload_work->adev = adev;
2322 INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
2323
2324 dm_handle_hpd_rx_offload_work(&offload_work->work);
2325
2326 KUNIT_EXPECT_EQ(test, dm_test_handle_link_loss_count, 1);
2327 }
2328
2329 /* Tests for amdgpu_dm_hdmi_hpd_debounce_work() */
2330
2331 /**
2332 * dm_test_hdmi_hpd_debounce_detect_false - Test debounce false detect path
2333 * @test: The KUnit test context
2334 */
dm_test_hdmi_hpd_debounce_detect_false(struct kunit * test)2335 static void dm_test_hdmi_hpd_debounce_detect_false(struct kunit *test)
2336 {
2337 struct amdgpu_dm_connector *aconn;
2338 struct link_service *link_srv;
2339 struct amdgpu_device *adev;
2340 struct dc_context *ctx;
2341 struct dc_link *link;
2342 struct dc *dc;
2343
2344 adev = dm_kunit_alloc_adev(test);
2345 mutex_init(&adev->dm.dc_lock);
2346
2347 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2348 mutex_init(&aconn->hpd_lock);
2349 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
2350 amdgpu_dm_hdmi_hpd_debounce_work);
2351
2352 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2353 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2354 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2355 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2356 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2357 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2358 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2359 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2360
2361 link_srv->detect_link = dm_test_detect_link_false;
2362 dc->ctx = ctx;
2363 dc->link_srv = link_srv;
2364 ctx->dc = dc;
2365 link->dc = dc;
2366 link->ctx = ctx;
2367 aconn->dc_link = link;
2368
2369 amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work);
2370 KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink);
2371 }
2372
2373 /**
2374 * dm_test_hdmi_hpd_debounce_reallow_idle - Test debounce idle/sink-release tail
2375 * @test: The KUnit test context
2376 *
2377 * With detection stubbed to return false, the if (ret) block is skipped, but
2378 * the function tail is still exercised: IPS support plus an idle-allowed dmub
2379 * makes reallow_idle true so dc_allow_idle_optimizations() runs on both entry
2380 * and exit (disable_idle_power_optimizations keeps those safe early returns),
2381 * and a cached hdmi_prev_sink is released and cleared.
2382 */
dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit * test)2383 static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test)
2384 {
2385 struct amdgpu_dm_connector *aconn;
2386 struct link_service *link_srv;
2387 struct dc_dmub_srv *dmub_srv;
2388 struct amdgpu_device *adev;
2389 struct dal_logger *logger;
2390 struct dc_context *ctx;
2391 struct dc_link *link;
2392 struct dc *dc;
2393
2394 adev = dm_kunit_alloc_adev(test);
2395 mutex_init(&adev->dm.dc_lock);
2396
2397 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2398 mutex_init(&aconn->hpd_lock);
2399 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
2400 amdgpu_dm_hdmi_hpd_debounce_work);
2401
2402 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2403 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2404 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2405 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2406 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2407 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2408 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2409 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2410 logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL);
2411 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger);
2412 dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL);
2413 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv);
2414
2415 link_srv->detect_link = dm_test_detect_link_false;
2416 dc->ctx = ctx;
2417 dc->link_srv = link_srv;
2418 ctx->dc = dc;
2419 link->dc = dc;
2420 link->ctx = ctx;
2421 aconn->dc_link = link;
2422
2423 /* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */
2424 logger->dev = &adev->ddev;
2425 dc->ctx->logger = logger;
2426
2427 /* Make reallow_idle true and keep dc_allow_idle*() a safe early return. */
2428 dmub_srv->idle_allowed = true;
2429 dc->ctx->dmub_srv = dmub_srv;
2430 dc->caps.ips_support = true;
2431 dc->debug.disable_idle_power_optimizations = true;
2432
2433 /* A cached previous sink must be released and cleared. */
2434 aconn->hdmi_prev_sink = dm_test_sink_create(link);
2435 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink);
2436
2437 amdgpu_dm_hdmi_hpd_debounce_work(&aconn->hdmi_hpd_debounce_work.work);
2438 KUNIT_EXPECT_NULL(test, aconn->hdmi_prev_sink);
2439 }
2440
2441 /* Tests for handle_hpd_irq()/handle_hpd_irq_helper() */
2442
2443 /**
2444 * dm_test_handle_hpd_irq_disabled - Test HPD helper returns when disabled
2445 * @test: The KUnit test context
2446 */
dm_test_handle_hpd_irq_disabled(struct kunit * test)2447 static void dm_test_handle_hpd_irq_disabled(struct kunit *test)
2448 {
2449 struct amdgpu_dm_connector *aconn;
2450 struct dm_connector_state *state;
2451 struct amdgpu_device *adev;
2452 struct dc_context *ctx;
2453 struct dc_link *link;
2454 struct dc *dc;
2455
2456 adev = dm_kunit_alloc_adev(test);
2457 adev->dm.disable_hpd_irq = true;
2458
2459 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2460 state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
2461 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2462 aconn->base.state = &state->base;
2463
2464 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2465 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2466 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2467 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2468 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2469 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2470
2471 dc->ctx = ctx;
2472 ctx->dc = dc;
2473 link->ctx = ctx;
2474 aconn->dc_link = link;
2475 aconn->fake_enable = true;
2476
2477 handle_hpd_irq_helper(aconn, DETECT_REASON_HPD);
2478 KUNIT_EXPECT_TRUE(test, aconn->fake_enable);
2479
2480 handle_hpd_irq(aconn);
2481 KUNIT_EXPECT_TRUE(test, aconn->fake_enable);
2482 }
2483
2484 /**
2485 * dm_test_handle_hpd_irq_helper_debounce_schedule - Test HDMI debounce branch
2486 * @test: The KUnit test context
2487 *
2488 * An HDMI link reporting a disconnect (connection type none) with a non-zero
2489 * debounce delay and a cached local_sink must take the debounce branch: it
2490 * caches local_sink in hdmi_prev_sink and schedules the delayed debounce work
2491 * instead of detecting immediately.
2492 */
dm_test_handle_hpd_irq_helper_debounce_schedule(struct kunit * test)2493 static void dm_test_handle_hpd_irq_helper_debounce_schedule(struct kunit *test)
2494 {
2495 struct amdgpu_dm_connector *aconn;
2496 struct dm_connector_state *state;
2497 struct link_service *link_srv;
2498 struct amdgpu_device *adev;
2499 struct dc_context *ctx;
2500 struct dc_link *link;
2501 struct dc *dc;
2502
2503 adev = dm_kunit_alloc_adev(test);
2504
2505 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2506 mutex_init(&aconn->hpd_lock);
2507 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
2508 amdgpu_dm_hdmi_hpd_debounce_work);
2509
2510 state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
2511 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2512 aconn->base.state = &state->base;
2513
2514 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2515 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2516 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2517 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2518 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2519 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2520 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2521 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2522
2523 link_srv->detect_connection_type = dm_test_detect_connection_none;
2524 dc->ctx = ctx;
2525 dc->link_srv = link_srv;
2526 ctx->dc = dc;
2527 link->dc = dc;
2528 link->ctx = ctx;
2529 aconn->dc_link = link;
2530
2531 /* HDMI signal + debounce delay + cached sink -> debounce branch. */
2532 aconn->hdmi_hpd_debounce_delay_ms = 100;
2533 link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
2534 link->local_sink = dm_test_sink_create(link);
2535 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link->local_sink);
2536
2537 handle_hpd_irq_helper(aconn, DETECT_REASON_HPD);
2538
2539 /* local_sink is cached for later comparison by the debounce work. */
2540 KUNIT_EXPECT_PTR_EQ(test, aconn->hdmi_prev_sink, link->local_sink);
2541
2542 cancel_delayed_work_sync(&aconn->hdmi_hpd_debounce_work);
2543 dm_test_sink_release(aconn->hdmi_prev_sink);
2544 dm_test_sink_release(link->local_sink);
2545 }
2546
2547 /**
2548 * dm_test_handle_hpd_irq_helper_debounce_release_prev - Test stale prev_sink
2549 * @test: The KUnit test context
2550 *
2551 * When the debounce branch is taken and a stale hdmi_prev_sink is already
2552 * cached from a previous HPD, it must be released before caching the current
2553 * local_sink. This exercises the dc_sink_release() of the previous sink.
2554 */
dm_test_handle_hpd_irq_helper_debounce_release_prev(struct kunit * test)2555 static void dm_test_handle_hpd_irq_helper_debounce_release_prev(struct kunit *test)
2556 {
2557 struct amdgpu_dm_connector *aconn;
2558 struct dm_connector_state *state;
2559 struct link_service *link_srv;
2560 struct amdgpu_device *adev;
2561 struct dc_context *ctx;
2562 struct dc_link *link;
2563 struct dc *dc;
2564
2565 adev = dm_kunit_alloc_adev(test);
2566
2567 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2568 mutex_init(&aconn->hpd_lock);
2569 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
2570 amdgpu_dm_hdmi_hpd_debounce_work);
2571
2572 state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
2573 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2574 aconn->base.state = &state->base;
2575
2576 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2577 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2578 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2579 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2580 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2581 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2582 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2583 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2584
2585 link_srv->detect_connection_type = dm_test_detect_connection_none;
2586 dc->ctx = ctx;
2587 dc->link_srv = link_srv;
2588 ctx->dc = dc;
2589 link->dc = dc;
2590 link->ctx = ctx;
2591 aconn->dc_link = link;
2592
2593 /* HDMI signal + debounce delay + cached sink -> debounce branch. */
2594 aconn->hdmi_hpd_debounce_delay_ms = 100;
2595 link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
2596 link->local_sink = dm_test_sink_create(link);
2597 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link->local_sink);
2598
2599 /* Stale sink from a previous HPD must be released by the helper. */
2600 aconn->hdmi_prev_sink = dm_test_sink_create(link);
2601 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn->hdmi_prev_sink);
2602 KUNIT_ASSERT_PTR_NE(test, aconn->hdmi_prev_sink, link->local_sink);
2603
2604 handle_hpd_irq_helper(aconn, DETECT_REASON_HPD);
2605
2606 /* Stale sink replaced by the current local_sink. */
2607 KUNIT_EXPECT_PTR_EQ(test, aconn->hdmi_prev_sink, link->local_sink);
2608
2609 cancel_delayed_work_sync(&aconn->hdmi_hpd_debounce_work);
2610 dm_test_sink_release(aconn->hdmi_prev_sink);
2611 dm_test_sink_release(link->local_sink);
2612 }
2613
2614 /**
2615 * dm_test_handle_hpd_irq_helper_detect_false - Test immediate detect branch
2616 * @test: The KUnit test context
2617 *
2618 * With no force, no debounce, and detection stubbed to report no connection,
2619 * the helper takes the else branch: dc_exit_ips_for_hw_access() is a safe
2620 * no-op (no IPS support) and dc_link_detect() returns false, so the connected
2621 * if (ret) block is skipped. fake_enable must still be cleared.
2622 */
dm_test_handle_hpd_irq_helper_detect_false(struct kunit * test)2623 static void dm_test_handle_hpd_irq_helper_detect_false(struct kunit *test)
2624 {
2625 struct amdgpu_dm_connector *aconn;
2626 struct dm_connector_state *state;
2627 struct link_service *link_srv;
2628 struct amdgpu_device *adev;
2629 struct dc_context *ctx;
2630 struct dc_link *link;
2631 struct dc *dc;
2632
2633 adev = dm_kunit_alloc_adev(test);
2634 mutex_init(&adev->dm.dc_lock);
2635
2636 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2637 mutex_init(&aconn->hpd_lock);
2638 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
2639 amdgpu_dm_hdmi_hpd_debounce_work);
2640
2641 state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
2642 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2643 aconn->base.state = &state->base;
2644
2645 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2646 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2647 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2648 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2649 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2650 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2651 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2652 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2653
2654 link_srv->detect_connection_type = dm_test_detect_connection_none;
2655 link_srv->detect_link = dm_test_detect_link_false;
2656 dc->ctx = ctx;
2657 dc->link_srv = link_srv;
2658 ctx->dc = dc;
2659 link->dc = dc;
2660 link->ctx = ctx;
2661 aconn->dc_link = link;
2662 aconn->fake_enable = true;
2663
2664 /* No debounce delay and no force -> immediate-detect else branch. */
2665 handle_hpd_irq_helper(aconn, DETECT_REASON_HPD);
2666
2667 KUNIT_EXPECT_FALSE(test, aconn->fake_enable);
2668 }
2669
2670 /* Tests for handle_hpd_rx_irq()/schedule_hpd_rx_offload_work() */
2671
2672 /**
2673 * dm_test_handle_hpd_rx_irq_disabled - Test HPDRX handler returns when disabled
2674 * @test: The KUnit test context
2675 */
dm_test_handle_hpd_rx_irq_disabled(struct kunit * test)2676 static void dm_test_handle_hpd_rx_irq_disabled(struct kunit *test)
2677 {
2678 struct hpd_rx_irq_offload_work_queue *offload_wq;
2679 struct amdgpu_dm_connector *aconn;
2680 struct link_service *link_srv;
2681 struct amdgpu_device *adev;
2682 struct dc_context *ctx;
2683 struct dc_link *link;
2684 struct dc *dc;
2685
2686 adev = dm_kunit_alloc_adev(test);
2687 adev->dm.disable_hpd_irq = true;
2688
2689 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2690 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2691 adev->dm.hpd_rx_offload_wq = offload_wq;
2692
2693 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2694
2695 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2696 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2697 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2698 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2699 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2700 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2701 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2702 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2703
2704 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work;
2705 dc->ctx = ctx;
2706 dc->link_srv = link_srv;
2707 ctx->dc = dc;
2708 link->dc = dc;
2709 link->ctx = ctx;
2710 link->link_index = 0;
2711 aconn->dc_link = link;
2712
2713 handle_hpd_rx_irq(aconn);
2714 }
2715
2716 /**
2717 * dm_test_schedule_hpd_rx_offload_work - Test offload work is queued
2718 * @test: The KUnit test context
2719 */
dm_test_schedule_hpd_rx_offload_work(struct kunit * test)2720 static void dm_test_schedule_hpd_rx_offload_work(struct kunit *test)
2721 {
2722 struct hpd_rx_irq_offload_work_queue *offload_wq;
2723 struct amdgpu_device *adev;
2724 union hpd_irq_data data = { 0 };
2725
2726 adev = dm_kunit_alloc_adev(test);
2727
2728 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2729 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2730 offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx");
2731 KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq);
2732
2733 schedule_hpd_rx_offload_work(adev, offload_wq, data);
2734 flush_workqueue(offload_wq->wq);
2735 destroy_workqueue(offload_wq->wq);
2736 }
2737
dm_test_destroy_offload_wq(void * data)2738 static void dm_test_destroy_offload_wq(void *data)
2739 {
2740 struct workqueue_struct *wq = data;
2741
2742 flush_workqueue(wq);
2743 destroy_workqueue(wq);
2744 }
2745
2746 /*
2747 * Build an aconnector wired for handle_hpd_rx_irq(): HPD enabled, an MST-root
2748 * connector on an MST-branch link so the post-detect block and drm_dp_cec_irq
2749 * are skipped, and a flushed offload work queue. Caller sets the link_srv
2750 * stubs (dp_handle_hpd_rx_irq and, if needed, dp_should_allow_hpd_rx_irq).
2751 */
dm_test_setup_hpd_rx_irq(struct kunit * test,struct link_service ** link_srv_out)2752 static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *test,
2753 struct link_service **link_srv_out)
2754 {
2755 struct hpd_rx_irq_offload_work_queue *offload_wq;
2756 struct amdgpu_dm_connector *aconn;
2757 struct link_service *link_srv;
2758 struct amdgpu_device *adev;
2759 struct dc_context *ctx;
2760 struct dc_link *link;
2761 struct dc *dc;
2762
2763 adev = dm_kunit_alloc_adev(test);
2764 mutex_init(&adev->dm.dc_lock);
2765
2766 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
2767 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
2768 spin_lock_init(&offload_wq->offload_lock);
2769 offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx");
2770 KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq);
2771 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_destroy_offload_wq,
2772 offload_wq->wq), 0);
2773 adev->dm.hpd_rx_offload_wq = offload_wq;
2774
2775 aconn = dm_kunit_alloc_connector(test, adev, NULL);
2776 mutex_init(&aconn->hpd_lock);
2777 aconn->mst_mgr.mst_state = true;
2778
2779 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2780 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2781 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
2782 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
2783 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
2784 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
2785 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2786 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2787
2788 dc->ctx = ctx;
2789 dc->link_srv = link_srv;
2790 ctx->dc = dc;
2791 link->dc = dc;
2792 link->ctx = ctx;
2793 link->link_index = 0;
2794 link->type = dc_connection_mst_branch;
2795 aconn->dc_link = link;
2796
2797 *link_srv_out = link_srv;
2798
2799 return aconn;
2800 }
2801
2802 /**
2803 * dm_test_handle_hpd_rx_irq_no_left_work - Test HPDRX early out (no left work)
2804 * @test: The KUnit test context
2805 *
2806 * When dc_link_handle_hpd_rx_irq() reports no left-over work, the handler
2807 * jumps to out and returns without scheduling any offload work.
2808 */
dm_test_handle_hpd_rx_irq_no_left_work(struct kunit * test)2809 static void dm_test_handle_hpd_rx_irq_no_left_work(struct kunit *test)
2810 {
2811 struct amdgpu_dm_connector *aconn;
2812 struct link_service *link_srv;
2813
2814 aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
2815 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work;
2816
2817 handle_hpd_rx_irq(aconn);
2818 }
2819
2820 /**
2821 * dm_test_handle_hpd_rx_irq_automated_test - Test HPDRX automated-test path
2822 * @test: The KUnit test context
2823 *
2824 * The AUTOMATED_TEST device-service bit must schedule offload work and jump to
2825 * out before the allow-hpd-rx-irq checks.
2826 */
dm_test_handle_hpd_rx_irq_automated_test(struct kunit * test)2827 static void dm_test_handle_hpd_rx_irq_automated_test(struct kunit *test)
2828 {
2829 struct amdgpu_dm_connector *aconn;
2830 struct link_service *link_srv;
2831
2832 aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
2833 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_automated;
2834
2835 handle_hpd_rx_irq(aconn);
2836 }
2837
2838 /**
2839 * dm_test_handle_hpd_rx_irq_msg_rdy - Test HPDRX MST message-ready path
2840 * @test: The KUnit test context
2841 *
2842 * With HPD RX IRQs allowed and an UP_REQ_MSG_RDY bit set, the handler must take
2843 * the MST message-ready branch, mark is_handling_mst_msg_rdy_event and schedule
2844 * offload work.
2845 */
dm_test_handle_hpd_rx_irq_msg_rdy(struct kunit * test)2846 static void dm_test_handle_hpd_rx_irq_msg_rdy(struct kunit *test)
2847 {
2848 struct amdgpu_dm_connector *aconn;
2849 struct link_service *link_srv;
2850
2851 aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
2852 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_msg_rdy;
2853 link_srv->dp_should_allow_hpd_rx_irq = dm_test_allow_hpd_rx_irq_true;
2854
2855 handle_hpd_rx_irq(aconn);
2856
2857 KUNIT_EXPECT_TRUE(test, drm_to_adev(aconn->base.dev)
2858 ->dm.hpd_rx_offload_wq->is_handling_mst_msg_rdy_event);
2859 }
2860
2861 /**
2862 * dm_test_handle_hpd_rx_irq_link_loss - Test HPDRX link-loss path
2863 * @test: The KUnit test context
2864 *
2865 * With HPD RX IRQs allowed and a reported link loss (no message-ready bits),
2866 * the handler must take the link-loss branch, mark is_handling_link_loss and
2867 * schedule offload work.
2868 */
dm_test_handle_hpd_rx_irq_link_loss(struct kunit * test)2869 static void dm_test_handle_hpd_rx_irq_link_loss(struct kunit *test)
2870 {
2871 struct amdgpu_dm_connector *aconn;
2872 struct link_service *link_srv;
2873
2874 aconn = dm_test_setup_hpd_rx_irq(test, &link_srv);
2875 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_link_loss;
2876 link_srv->dp_should_allow_hpd_rx_irq = dm_test_allow_hpd_rx_irq_true;
2877
2878 handle_hpd_rx_irq(aconn);
2879
2880 KUNIT_EXPECT_TRUE(test, drm_to_adev(aconn->base.dev)
2881 ->dm.hpd_rx_offload_wq->is_handling_link_loss);
2882 }
2883
2884 /* Tests for dmub_hpd_callback()/dmub_hpd_sense_callback() */
2885
2886 /**
2887 * dm_test_dmub_hpd_callback_null_inputs - Test DMUB callback null inputs
2888 * @test: The KUnit test context
2889 */
dm_test_dmub_hpd_callback_null_inputs(struct kunit * test)2890 static void dm_test_dmub_hpd_callback_null_inputs(struct kunit *test)
2891 {
2892 struct amdgpu_device *adev;
2893
2894 adev = dm_kunit_alloc_adev(test);
2895
2896 dmub_hpd_callback(NULL, NULL);
2897 dmub_hpd_callback(adev, NULL);
2898 }
2899
2900 /**
2901 * dm_test_dmub_hpd_callback_invalid_index - Test DMUB callback index check
2902 * @test: The KUnit test context
2903 */
dm_test_dmub_hpd_callback_invalid_index(struct kunit * test)2904 static void dm_test_dmub_hpd_callback_invalid_index(struct kunit *test)
2905 {
2906 struct dmub_notification notify = { 0 };
2907 struct amdgpu_device *adev;
2908 struct dc *dc;
2909
2910 adev = dm_kunit_alloc_adev(test);
2911 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2912 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2913 adev->dm.dc = dc;
2914 notify.link_index = 1;
2915
2916 dmub_hpd_callback(adev, ¬ify);
2917 }
2918
2919 /**
2920 * dm_test_dmub_hpd_callback_empty_connectors - Test DMUB callback without match
2921 * @test: The KUnit test context
2922 */
dm_test_dmub_hpd_callback_empty_connectors(struct kunit * test)2923 static void dm_test_dmub_hpd_callback_empty_connectors(struct kunit *test)
2924 {
2925 struct dmub_notification notify = { 0 };
2926 struct amdgpu_device *adev;
2927 struct dc *dc;
2928
2929 adev = dm_kunit_alloc_adev(test);
2930 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2931 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2932 adev->dm.dc = dc;
2933 adev->dm.ddev = &adev->ddev;
2934 dc->link_count = 1;
2935 notify.type = DMUB_NOTIFICATION_HPD_SENSE_NOTIFY;
2936
2937 dmub_hpd_callback(adev, ¬ify);
2938 dmub_hpd_sense_callback(adev, ¬ify);
2939 }
2940
2941 /**
2942 * dm_test_dmub_hpd_callback_unknown_type_match - Test DMUB callback matched
2943 * connector, unknown type
2944 * @test: The KUnit test context
2945 *
2946 * A writeback connector must be skipped (continue) and a non-writeback
2947 * connector whose dc_link matches the notification link must be selected.
2948 * An unrecognized notification type takes the "unknown" warn branch, and the
2949 * post-loop dispatch is a no-op (neither HPD nor HPD_IRQ), so no real DC/MST
2950 * handler runs.
2951 */
dm_test_dmub_hpd_callback_unknown_type_match(struct kunit * test)2952 static void dm_test_dmub_hpd_callback_unknown_type_match(struct kunit *test)
2953 {
2954 struct dmub_notification notify = { 0 };
2955 struct amdgpu_dm_connector *aconn;
2956 struct drm_connector *wbconn;
2957 struct amdgpu_device *adev;
2958 struct dc_link *link;
2959 struct dc *dc;
2960
2961 adev = dm_kunit_alloc_adev(test);
2962 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
2963 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
2964 adev->dm.dc = dc;
2965 adev->dm.ddev = &adev->ddev;
2966 dc->link_count = 1;
2967
2968 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
2969 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
2970 dc->links[0] = link;
2971
2972 /* A writeback connector must be skipped by the loop. */
2973 wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL);
2974 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn);
2975 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs,
2976 DRM_MODE_CONNECTOR_WRITEBACK), 0);
2977 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0);
2978
2979 /* A DisplayPort connector whose dc_link matches drives the match branch. */
2980 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
2981 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
2982 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
2983 &dm_test_connector_funcs,
2984 DRM_MODE_CONNECTOR_DisplayPort), 0);
2985 KUNIT_ASSERT_EQ(test,
2986 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
2987 aconn->dc_link = link;
2988
2989 notify.link_index = 0;
2990 notify.type = DMUB_NOTIFICATION_HPD_SENSE_NOTIFY;
2991
2992 dmub_hpd_callback(adev, ¬ify);
2993 }
2994
2995 /**
2996 * dm_test_dmub_hpd_callback_hpd_type - Test DMUB callback HPD type dispatch
2997 * @test: The KUnit test context
2998 *
2999 * A matched connector with notification type DMUB_NOTIFICATION_HPD logs the
3000 * HPD callback and dispatches to handle_hpd_irq_helper(). Detection is stubbed
3001 * to report no connection and link detect to fail, so the connected branches
3002 * are skipped and no real DC/DRM hotplug path runs.
3003 */
dm_test_dmub_hpd_callback_hpd_type(struct kunit * test)3004 static void dm_test_dmub_hpd_callback_hpd_type(struct kunit *test)
3005 {
3006 struct dmub_notification notify = { 0 };
3007 struct amdgpu_dm_connector *aconn;
3008 struct link_service *link_srv;
3009 struct amdgpu_device *adev;
3010 struct dc_context *ctx;
3011 struct dc_link *link;
3012 struct dc *dc;
3013
3014 adev = dm_kunit_alloc_adev(test);
3015 mutex_init(&adev->dm.dc_lock);
3016
3017 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3018 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3019 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
3020 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
3021 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
3022 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
3023 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
3024 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
3025
3026 link_srv->detect_connection_type = dm_test_detect_connection_none;
3027 link_srv->detect_link = dm_test_detect_link_false;
3028 dc->ctx = ctx;
3029 dc->link_srv = link_srv;
3030 ctx->dc = dc;
3031 link->dc = dc;
3032 link->ctx = ctx;
3033
3034 adev->dm.dc = dc;
3035 adev->dm.ddev = &adev->ddev;
3036 dc->link_count = 1;
3037 dc->links[0] = link;
3038
3039 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
3040 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
3041 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
3042 &dm_test_connector_funcs,
3043 DRM_MODE_CONNECTOR_DisplayPort), 0);
3044 KUNIT_ASSERT_EQ(test,
3045 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
3046 mutex_init(&aconn->hpd_lock);
3047 INIT_DELAYED_WORK(&aconn->hdmi_hpd_debounce_work,
3048 amdgpu_dm_hdmi_hpd_debounce_work);
3049 aconn->dc_link = link;
3050
3051 notify.link_index = 0;
3052 notify.type = DMUB_NOTIFICATION_HPD;
3053
3054 dmub_hpd_callback(adev, ¬ify);
3055 }
3056
3057 /**
3058 * dm_test_dmub_hpd_callback_hpd_irq_type - Test DMUB callback HPD_IRQ dispatch
3059 * @test: The KUnit test context
3060 *
3061 * A matched connector with notification type DMUB_NOTIFICATION_HPD_IRQ logs
3062 * the HPD RX callback and dispatches to handle_hpd_rx_irq(). The HPD RX handler
3063 * stub reports no left work, so the function returns through the early goto
3064 * without scheduling offload work; an MST-branch link skips the trailing
3065 * drm_dp_cec_irq().
3066 */
dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit * test)3067 static void dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit *test)
3068 {
3069 struct hpd_rx_irq_offload_work_queue *offload_wq;
3070 struct dmub_notification notify = { 0 };
3071 struct amdgpu_dm_connector *aconn;
3072 struct link_service *link_srv;
3073 struct amdgpu_device *adev;
3074 struct dc_context *ctx;
3075 struct dc_link *link;
3076 struct dc *dc;
3077
3078 adev = dm_kunit_alloc_adev(test);
3079 mutex_init(&adev->dm.dc_lock);
3080
3081 offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL);
3082 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq);
3083 spin_lock_init(&offload_wq->offload_lock);
3084 adev->dm.hpd_rx_offload_wq = offload_wq;
3085
3086 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3087 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3088 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
3089 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
3090 link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
3091 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv);
3092 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
3093 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
3094
3095 link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work;
3096 dc->ctx = ctx;
3097 dc->link_srv = link_srv;
3098 ctx->dc = dc;
3099 link->dc = dc;
3100 link->ctx = ctx;
3101 link->link_index = 0;
3102 link->type = dc_connection_mst_branch;
3103
3104 adev->dm.dc = dc;
3105 adev->dm.ddev = &adev->ddev;
3106 dc->link_count = 1;
3107 dc->links[0] = link;
3108
3109 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
3110 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
3111 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
3112 &dm_test_connector_funcs,
3113 DRM_MODE_CONNECTOR_DisplayPort), 0);
3114 KUNIT_ASSERT_EQ(test,
3115 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
3116 mutex_init(&aconn->hpd_lock);
3117 aconn->mst_mgr.mst_state = true;
3118 aconn->dc_link = link;
3119
3120 notify.link_index = 0;
3121 notify.type = DMUB_NOTIFICATION_HPD_IRQ;
3122
3123 dmub_hpd_callback(adev, ¬ify);
3124 }
3125
3126 /* Tests for amdgpu_dm_register_hpd_handlers() */
3127
3128 /**
3129 * dm_test_register_hpd_handlers_empty - Test HPD registration with no connectors
3130 * @test: The KUnit test context
3131 */
dm_test_register_hpd_handlers_empty(struct kunit * test)3132 static void dm_test_register_hpd_handlers_empty(struct kunit *test)
3133 {
3134 struct amdgpu_device *adev;
3135 struct dc *dc;
3136
3137 adev = dm_kunit_alloc_adev(test);
3138 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3139 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3140 adev->dm.dc = dc;
3141
3142 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), 0);
3143 }
3144
3145 /**
3146 * dm_test_register_hpd_handlers_valid - Test HPD/HPDRX registration succeeds
3147 * @test: The KUnit test context
3148 */
dm_test_register_hpd_handlers_valid(struct kunit * test)3149 static void dm_test_register_hpd_handlers_valid(struct kunit *test)
3150 {
3151 struct amdgpu_dm_connector *aconn;
3152 struct amdgpu_device *adev;
3153 struct dc_link *link;
3154 struct dc *dc;
3155
3156 adev = dm_kunit_alloc_adev(test);
3157 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3158 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3159 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3160 adev->dm.dc = dc;
3161
3162 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
3163 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
3164 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
3165 &dm_test_connector_funcs,
3166 DRM_MODE_CONNECTOR_DisplayPort), 0);
3167 KUNIT_ASSERT_EQ(test,
3168 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
3169
3170 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
3171 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
3172 link->irq_source_hpd = DC_IRQ_SOURCE_HPD1;
3173 link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX;
3174 aconn->dc_link = link;
3175
3176 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), 0);
3177 KUNIT_EXPECT_FALSE(test,
3178 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]));
3179 KUNIT_EXPECT_FALSE(test,
3180 list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1RX]));
3181
3182 amdgpu_dm_irq_fini(adev);
3183 }
3184
3185 /**
3186 * dm_test_register_hpd_handlers_invalid_hpd - Test invalid HPD source fails
3187 * @test: The KUnit test context
3188 */
dm_test_register_hpd_handlers_invalid_hpd(struct kunit * test)3189 static void dm_test_register_hpd_handlers_invalid_hpd(struct kunit *test)
3190 {
3191 struct amdgpu_dm_connector *aconn;
3192 struct amdgpu_device *adev;
3193 struct dc_link *link;
3194 struct dc *dc;
3195
3196 adev = dm_kunit_alloc_adev(test);
3197 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3198 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3199 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3200 adev->dm.dc = dc;
3201
3202 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
3203 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
3204 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
3205 &dm_test_connector_funcs,
3206 DRM_MODE_CONNECTOR_DisplayPort), 0);
3207 KUNIT_ASSERT_EQ(test,
3208 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
3209
3210 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
3211 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
3212 link->irq_source_hpd = DC_IRQ_SOURCE_HPD1RX;
3213 link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
3214 aconn->dc_link = link;
3215
3216 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), -EINVAL);
3217 amdgpu_dm_irq_fini(adev);
3218 }
3219
3220 /**
3221 * dm_test_register_hpd_handlers_invalid_hpd_rx - Test invalid HPDRX source fails
3222 * @test: The KUnit test context
3223 */
dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit * test)3224 static void dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit *test)
3225 {
3226 struct amdgpu_dm_connector *aconn;
3227 struct amdgpu_device *adev;
3228 struct dc_link *link;
3229 struct dc *dc;
3230
3231 adev = dm_kunit_alloc_adev(test);
3232 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3233 dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
3234 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc);
3235 adev->dm.dc = dc;
3236
3237 aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL);
3238 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn);
3239 KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base,
3240 &dm_test_connector_funcs,
3241 DRM_MODE_CONNECTOR_DisplayPort), 0);
3242 KUNIT_ASSERT_EQ(test,
3243 kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0);
3244
3245 link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
3246 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link);
3247 link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
3248 link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1;
3249 aconn->dc_link = link;
3250
3251 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), -EINVAL);
3252 amdgpu_dm_irq_fini(adev);
3253 }
3254
3255 /**
3256 * dm_test_register_hpd_handlers_dmub_outbox - Test DMUB outbox callbacks register
3257 * @test: The KUnit test context
3258 *
3259 * Enables DMUB outbox support so dc_is_dmub_outbox_supported() returns true,
3260 * exercising the dm_register_dmub_notify_callback() block. Asserts that the
3261 * HPD, HPD_IRQ and HPD_SENSE_NOTIFY callbacks are registered.
3262 */
dm_test_register_hpd_handlers_dmub_outbox(struct kunit * test)3263 static void dm_test_register_hpd_handlers_dmub_outbox(struct kunit *test)
3264 {
3265 struct amdgpu_device *adev;
3266 struct dc *dc;
3267
3268 adev = dm_kunit_alloc_adev(test);
3269 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3270 dc = dm_kunit_alloc_dc_with_ctx(test);
3271 adev->dm.dc = dc;
3272
3273 /* Make dc_is_dmub_outbox_supported() return true. */
3274 dc->caps.dmcub_support = true;
3275 dc->ctx->asic_id.chip_family = AMDGPU_FAMILY_GC_11_0_1;
3276
3277 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), 0);
3278 KUNIT_EXPECT_PTR_EQ(test, adev->dm.dmub_callback[DMUB_NOTIFICATION_HPD],
3279 (dmub_notify_interrupt_callback_t)dmub_hpd_callback);
3280 KUNIT_EXPECT_PTR_EQ(test, adev->dm.dmub_callback[DMUB_NOTIFICATION_HPD_IRQ],
3281 (dmub_notify_interrupt_callback_t)dmub_hpd_callback);
3282 KUNIT_EXPECT_PTR_EQ(test,
3283 adev->dm.dmub_callback[DMUB_NOTIFICATION_HPD_SENSE_NOTIFY],
3284 (dmub_notify_interrupt_callback_t)dmub_hpd_sense_callback);
3285
3286 amdgpu_dm_irq_fini(adev);
3287 }
3288
3289 /* Tests for CRTC/pflip/vupdate high IRQ callbacks */
3290
3291 /**
3292 * dm_test_pflip_high_irq_no_crtc - Test pflip high IRQ with no matching CRTC
3293 * @test: The KUnit test context
3294 */
dm_test_pflip_high_irq_no_crtc(struct kunit * test)3295 static void dm_test_pflip_high_irq_no_crtc(struct kunit *test)
3296 {
3297 struct common_irq_params params = { 0 };
3298 struct amdgpu_device *adev;
3299
3300 adev = dm_kunit_alloc_adev(test);
3301 params.adev = adev;
3302 params.irq_src = (enum dc_irq_source)IRQ_TYPE_PFLIP;
3303
3304 dm_pflip_high_irq(¶ms);
3305 }
3306
3307 /**
3308 * dm_test_pflip_high_irq_not_submitted - Test pflip high IRQ early status exit
3309 * @test: The KUnit test context
3310 */
dm_test_pflip_high_irq_not_submitted(struct kunit * test)3311 static void dm_test_pflip_high_irq_not_submitted(struct kunit *test)
3312 {
3313 struct common_irq_params params = { 0 };
3314 struct amdgpu_crtc *acrtc;
3315 struct amdgpu_device *adev;
3316
3317 adev = dm_kunit_alloc_adev(test);
3318 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
3319 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
3320
3321 INIT_LIST_HEAD(&acrtc->base.head);
3322 acrtc->base.dev = &adev->ddev;
3323 acrtc->otg_inst = 0;
3324 acrtc->pflip_status = AMDGPU_FLIP_NONE;
3325 list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list);
3326 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test,
3327 dm_test_crtc_list_del, acrtc), 0);
3328
3329 params.adev = adev;
3330 params.irq_src = (enum dc_irq_source)IRQ_TYPE_PFLIP;
3331
3332 dm_pflip_high_irq(¶ms);
3333 KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE);
3334 }
3335
3336 /**
3337 * dm_test_vupdate_high_irq_no_crtc - Test vupdate high IRQ with no CRTC
3338 * @test: The KUnit test context
3339 */
dm_test_vupdate_high_irq_no_crtc(struct kunit * test)3340 static void dm_test_vupdate_high_irq_no_crtc(struct kunit *test)
3341 {
3342 struct common_irq_params params = { 0 };
3343 struct amdgpu_device *adev;
3344
3345 adev = dm_kunit_alloc_adev(test);
3346 params.adev = adev;
3347 params.irq_src = (enum dc_irq_source)IRQ_TYPE_VUPDATE;
3348
3349 dm_vupdate_high_irq(¶ms);
3350 }
3351
3352 /**
3353 * dm_test_crtc_high_irq_no_crtc - Test crtc high IRQ with no CRTC
3354 * @test: The KUnit test context
3355 */
dm_test_crtc_high_irq_no_crtc(struct kunit * test)3356 static void dm_test_crtc_high_irq_no_crtc(struct kunit *test)
3357 {
3358 struct common_irq_params params = { 0 };
3359 struct amdgpu_device *adev;
3360
3361 adev = dm_kunit_alloc_adev(test);
3362 params.adev = adev;
3363 params.irq_src = (enum dc_irq_source)IRQ_TYPE_VBLANK;
3364
3365 dm_crtc_high_irq(¶ms);
3366 }
3367
3368 /**
3369 * dm_test_crtc_high_irq_vrr_pre_ai - Test crtc high IRQ VRR path on pre-AI ASIC
3370 * @test: The KUnit test context
3371 *
3372 * With a matching CRTC, no writeback, VRR active (so the !vrr_active vblank
3373 * handler is skipped) and a pre-AI family, the handler runs through CRC
3374 * handling and returns before the freesync section.
3375 */
dm_test_crtc_high_irq_vrr_pre_ai(struct kunit * test)3376 static void dm_test_crtc_high_irq_vrr_pre_ai(struct kunit *test)
3377 {
3378 struct common_irq_params params = { 0 };
3379 struct amdgpu_crtc *acrtc;
3380 struct amdgpu_device *adev;
3381
3382 adev = dm_kunit_alloc_adev(test);
3383 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
3384 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
3385
3386 INIT_LIST_HEAD(&acrtc->base.head);
3387 acrtc->base.dev = &adev->ddev;
3388 acrtc->otg_inst = 0;
3389 /* VRR active so the !vrr_active vblank handler is skipped. */
3390 acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
3391 list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list);
3392 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test,
3393 dm_test_crtc_list_del, acrtc), 0);
3394
3395 /* Pre-AI family returns right after CRC handling. */
3396 adev->family = AMDGPU_FAMILY_SI;
3397
3398 params.adev = adev;
3399 params.irq_src = (enum dc_irq_source)IRQ_TYPE_VBLANK;
3400
3401 dm_crtc_high_irq(¶ms);
3402 }
3403
3404 /**
3405 * dm_test_crtc_high_irq_vrr_ai_no_stream - Test crtc high IRQ AI path, no stream
3406 * @test: The KUnit test context
3407 *
3408 * On an AI+ family the handler runs the post-CRC freesync section. With no
3409 * stream and no pending flip, both inner blocks are skipped and the handler
3410 * completes through the event-lock critical section, leaving pflip_status
3411 * untouched.
3412 */
dm_test_crtc_high_irq_vrr_ai_no_stream(struct kunit * test)3413 static void dm_test_crtc_high_irq_vrr_ai_no_stream(struct kunit *test)
3414 {
3415 struct common_irq_params params = { 0 };
3416 struct amdgpu_crtc *acrtc;
3417 struct amdgpu_device *adev;
3418
3419 adev = dm_kunit_alloc_adev(test);
3420 acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
3421 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc);
3422
3423 INIT_LIST_HEAD(&acrtc->base.head);
3424 acrtc->base.dev = &adev->ddev;
3425 acrtc->otg_inst = 0;
3426 acrtc->pflip_status = AMDGPU_FLIP_NONE;
3427 /* VRR active so the !vrr_active vblank handler is skipped. */
3428 acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
3429 list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list);
3430 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test,
3431 dm_test_crtc_list_del, acrtc), 0);
3432
3433 /* AI+ family runs the freesync section; no stream skips it. */
3434 adev->family = AMDGPU_FAMILY_AI;
3435
3436 params.adev = adev;
3437 params.irq_src = (enum dc_irq_source)IRQ_TYPE_VBLANK;
3438
3439 dm_crtc_high_irq(¶ms);
3440 KUNIT_EXPECT_EQ(test, acrtc->pflip_status, AMDGPU_FLIP_NONE);
3441 }
3442
3443 /* Tests for dm_handle_hpd_work() */
3444
3445 /**
3446 * dm_test_handle_hpd_work_out_of_range - Test HPD work frees unknown notification
3447 * @test: The KUnit test context
3448 */
dm_test_handle_hpd_work_out_of_range(struct kunit * test)3449 static void dm_test_handle_hpd_work_out_of_range(struct kunit *test)
3450 {
3451 struct dmub_hpd_work *hpd_work;
3452 struct amdgpu_device *adev;
3453
3454 adev = dm_kunit_alloc_adev(test);
3455 hpd_work = kzalloc_obj(*hpd_work);
3456 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work);
3457 hpd_work->dmub_notify = kzalloc_obj(*hpd_work->dmub_notify);
3458 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work->dmub_notify);
3459 hpd_work->dmub_notify->type =
3460 (enum dmub_notification_type)ARRAY_SIZE(adev->dm.dmub_callback);
3461 hpd_work->adev = adev;
3462 INIT_WORK(&hpd_work->handle_hpd_work, dm_handle_hpd_work);
3463
3464 dm_handle_hpd_work(&hpd_work->handle_hpd_work);
3465 }
3466
3467 /* Tests for dm_dmub_outbox1_low_irq() */
3468
3469 /**
3470 * dm_test_dmub_outbox1_low_irq_empty - Test outbox low IRQ with empty trace queue
3471 * @test: The KUnit test context
3472 */
dm_test_dmub_outbox1_low_irq_empty(struct kunit * test)3473 static void dm_test_dmub_outbox1_low_irq_empty(struct kunit *test)
3474 {
3475 struct common_irq_params params = { 0 };
3476 struct dc_dmub_srv *dc_dmub_srv;
3477 struct amdgpu_device *adev;
3478 struct dmub_srv *dmub;
3479 struct dc *dc;
3480
3481 adev = dm_kunit_alloc_adev(test);
3482 dc = dm_kunit_alloc_dc_with_ctx(test);
3483 dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
3484 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
3485 dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL);
3486 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub);
3487
3488 dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr;
3489 dc_dmub_srv->dmub = dmub;
3490 dc->ctx->dmub_srv = dc_dmub_srv;
3491 adev->dm.dc = dc;
3492 params.adev = adev;
3493 params.irq_src = DC_IRQ_SOURCE_DMCUB_OUTBOX;
3494
3495 dm_dmub_outbox1_low_irq(¶ms);
3496 }
3497
3498 /*
3499 * dm_test_alloc_adev_outbox_notify - Build an adev wired for DMUB outbox
3500 * notification handling.
3501 *
3502 * Configures dc/dc_dmub_srv/dmub so that the trace queue is empty and
3503 * dc_enable_dmub_notifications() returns true, allowing the notification
3504 * handling block of dm_dmub_outbox1_low_irq() to execute. The outbox1 ring
3505 * buffer is left empty, so each notification read returns
3506 * DMUB_NOTIFICATION_NO_DATA with no pending notification.
3507 */
dm_test_alloc_adev_outbox_notify(struct kunit * test)3508 static struct amdgpu_device *dm_test_alloc_adev_outbox_notify(struct kunit *test)
3509 {
3510 struct dc_dmub_srv *dc_dmub_srv;
3511 struct amdgpu_device *adev;
3512 struct dmub_srv *dmub;
3513 struct dc *dc;
3514
3515 adev = dm_kunit_alloc_adev(test);
3516 dc = dm_kunit_alloc_dc_with_ctx(test);
3517 dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
3518 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
3519 dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL);
3520 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub);
3521
3522 dmub->hw_init = true;
3523 dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr;
3524 dmub->hw_funcs.get_outbox1_wptr = dm_test_dmub_get_outbox1_wptr;
3525 dc_dmub_srv->dmub = dmub;
3526 dc->ctx->dmub_srv = dc_dmub_srv;
3527
3528 /* Make dc_enable_dmub_notifications() return true. */
3529 dc->caps.dmcub_support = true;
3530 dc->ctx->asic_id.chip_family = AMDGPU_FAMILY_GC_11_0_1;
3531
3532 adev->dm.dc = dc;
3533
3534 return adev;
3535 }
3536
3537 /**
3538 * dm_test_dmub_outbox1_low_irq_no_handler - Test notification with no handler
3539 * @test: The KUnit test context
3540 *
3541 * Notifications are enabled but no callback is registered for the returned
3542 * notification type, exercising the skip-with-warning path.
3543 */
dm_test_dmub_outbox1_low_irq_no_handler(struct kunit * test)3544 static void dm_test_dmub_outbox1_low_irq_no_handler(struct kunit *test)
3545 {
3546 struct common_irq_params params = { 0 };
3547 struct amdgpu_device *adev;
3548
3549 adev = dm_test_alloc_adev_outbox_notify(test);
3550 params.adev = adev;
3551 params.irq_src = DC_IRQ_SOURCE_DMCUB_OUTBOX;
3552
3553 dm_dmub_outbox1_low_irq(¶ms);
3554 }
3555
3556 /**
3557 * dm_test_dmub_outbox1_low_irq_direct_callback - Test direct callback dispatch
3558 * @test: The KUnit test context
3559 *
3560 * Notifications are enabled with a registered callback and thread offload
3561 * disabled, so the callback is invoked directly from the IRQ handler.
3562 */
dm_test_dmub_outbox1_low_irq_direct_callback(struct kunit * test)3563 static void dm_test_dmub_outbox1_low_irq_direct_callback(struct kunit *test)
3564 {
3565 struct common_irq_params params = { 0 };
3566 struct amdgpu_device *adev;
3567
3568 adev = dm_test_alloc_adev_outbox_notify(test);
3569 adev->dm.dmub_callback[DMUB_NOTIFICATION_NO_DATA] = dm_test_dmub_notify_callback;
3570 adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_NO_DATA] = false;
3571 params.adev = adev;
3572 params.irq_src = DC_IRQ_SOURCE_DMCUB_OUTBOX;
3573
3574 dm_test_dmub_notify_count = 0;
3575
3576 dm_dmub_outbox1_low_irq(¶ms);
3577
3578 KUNIT_EXPECT_EQ(test, dm_test_dmub_notify_count, 1);
3579 }
3580
3581 /**
3582 * dm_test_dmub_outbox1_low_irq_offload - Test offloaded callback dispatch
3583 * @test: The KUnit test context
3584 *
3585 * Notifications are enabled with a registered callback and thread offload
3586 * enabled, so the callback is dispatched via the delayed HPD work queue.
3587 */
dm_test_dmub_outbox1_low_irq_offload(struct kunit * test)3588 static void dm_test_dmub_outbox1_low_irq_offload(struct kunit *test)
3589 {
3590 struct common_irq_params params = { 0 };
3591 struct amdgpu_device *adev;
3592
3593 adev = dm_test_alloc_adev_outbox_notify(test);
3594 adev->dm.dmub_callback[DMUB_NOTIFICATION_NO_DATA] = dm_test_dmub_notify_callback;
3595 adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_NO_DATA] = true;
3596 adev->dm.delayed_hpd_wq = create_singlethread_workqueue("dm_irq_test_outbox");
3597 KUNIT_ASSERT_NOT_NULL(test, adev->dm.delayed_hpd_wq);
3598 params.adev = adev;
3599 params.irq_src = DC_IRQ_SOURCE_DMCUB_OUTBOX;
3600
3601 dm_test_dmub_notify_count = 0;
3602
3603 dm_dmub_outbox1_low_irq(¶ms);
3604
3605 flush_workqueue(adev->dm.delayed_hpd_wq);
3606 destroy_workqueue(adev->dm.delayed_hpd_wq);
3607
3608 KUNIT_EXPECT_EQ(test, dm_test_dmub_notify_count, 1);
3609 }
3610
3611
3612 /**
3613 * dm_test_dce110_register_irq_handlers_rejects_uninitialized_sources - Test DCE110 error
3614 * @test: The KUnit test context
3615 */
dm_test_dce110_register_irq_handlers_rejects_uninitialized_sources(struct kunit * test)3616 static void dm_test_dce110_register_irq_handlers_rejects_uninitialized_sources(struct kunit *test)
3617 {
3618 struct amdgpu_device *adev;
3619 struct dc *dc;
3620
3621 adev = dm_kunit_alloc_adev(test);
3622 dc = dm_kunit_alloc_dc_with_ctx(test);
3623 adev->dm.dc = dc;
3624
3625 KUNIT_EXPECT_EQ(test, amdgpu_dm_dce110_register_irq_handlers(adev), -EINVAL);
3626 }
3627
3628 /**
3629 * dm_test_dce110_register_irq_handlers_one_crtc - Test DCE110 with 1 CRTC
3630 * @test: The KUnit test context
3631 *
3632 * Exercises the VBLANK, VUPDATE, PFLIP and HPD for-loop bodies with a
3633 * fake IRQ service that maps source IDs to DC IRQ sources.
3634 */
dm_test_dce110_register_irq_handlers_one_crtc(struct kunit * test)3635 static void dm_test_dce110_register_irq_handlers_one_crtc(struct kunit *test)
3636 {
3637 struct amdgpu_device *adev;
3638 struct dc *dc;
3639
3640 adev = dm_kunit_alloc_adev(test);
3641 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_irq_sources,
3642 adev), 0);
3643 dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dce110);
3644 dc->ctx->dce_version = DCE_VERSION_11_0;
3645 adev->dm.dc = dc;
3646 adev->mode_info.num_crtc = 1;
3647 adev->mode_info.num_hpd = 1;
3648 amdgpu_dm_set_irq_funcs(adev);
3649 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3650
3651 KUNIT_EXPECT_EQ(test, amdgpu_dm_dce110_register_irq_handlers(adev), 0);
3652
3653 /* Verify VBLANK params were populated */
3654 KUNIT_EXPECT_EQ(test, (int)adev->dm.vblank_params[0].irq_src,
3655 (int)DC_IRQ_SOURCE_VBLANK1);
3656 KUNIT_EXPECT_PTR_EQ(test, adev->dm.vblank_params[0].adev, adev);
3657
3658 /* Verify VUPDATE params were populated (VRR supported on DCE 11) */
3659 KUNIT_EXPECT_EQ(test, (int)adev->dm.vupdate_params[0].irq_src,
3660 (int)DC_IRQ_SOURCE_VUPDATE1);
3661
3662 /* Verify PFLIP params were populated (6 fixed entries) */
3663 KUNIT_EXPECT_EQ(test, (int)adev->dm.pflip_params[0].irq_src,
3664 (int)DC_IRQ_SOURCE_PFLIP1);
3665 KUNIT_EXPECT_EQ(test, (int)adev->dm.pflip_params[5].irq_src,
3666 (int)DC_IRQ_SOURCE_PFLIP6);
3667
3668 amdgpu_dm_irq_fini(adev);
3669 }
3670
3671 /**
3672 * dm_test_dcn10_register_irq_handlers_zero_crtc - Test DCN10 zero-CRTC registration
3673 * @test: The KUnit test context
3674 */
dm_test_dcn10_register_irq_handlers_zero_crtc(struct kunit * test)3675 static void dm_test_dcn10_register_irq_handlers_zero_crtc(struct kunit *test)
3676 {
3677 struct amdgpu_device *adev;
3678 struct dc *dc;
3679
3680 adev = dm_kunit_alloc_adev(test);
3681 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_irq_sources,
3682 adev), 0);
3683 dc = dm_kunit_alloc_dc_with_ctx(test);
3684 adev->dm.dc = dc;
3685 adev->mode_info.num_hpd = 1;
3686 amdgpu_dm_set_irq_funcs(adev);
3687
3688 KUNIT_EXPECT_EQ(test, amdgpu_dm_dcn10_register_irq_handlers(adev), 0);
3689 KUNIT_ASSERT_NOT_NULL(test, adev->irq.client[SOC15_IH_CLIENTID_DCE].sources);
3690 KUNIT_EXPECT_PTR_EQ(test,
3691 adev->irq.client[SOC15_IH_CLIENTID_DCE].sources[DCN_1_0__SRCID__DC_HPD1_INT],
3692 &adev->hpd_irq);
3693 }
3694
3695 /**
3696 * dm_test_dcn10_register_irq_handlers_one_crtc - Test DCN10 with 1 CRTC
3697 * @test: The KUnit test context
3698 *
3699 * Exercises the VUPDATE_NO_LOCK for-loop bodies with a fake IRQ service, and
3700 * that it's the only one populated (other than VLINE0, for secure display).
3701 */
dm_test_dcn10_register_irq_handlers_one_crtc(struct kunit * test)3702 static void dm_test_dcn10_register_irq_handlers_one_crtc(struct kunit *test)
3703 {
3704 struct amdgpu_device *adev;
3705 struct dc *dc;
3706
3707 adev = dm_kunit_alloc_adev(test);
3708 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_irq_sources,
3709 adev), 0);
3710 dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
3711 adev->dm.dc = dc;
3712 adev->mode_info.num_crtc = 1;
3713 adev->mode_info.num_hpd = 1;
3714 dc->caps.max_otg_num = 1;
3715 amdgpu_dm_set_irq_funcs(adev);
3716 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3717
3718 KUNIT_EXPECT_EQ(test, amdgpu_dm_dcn10_register_irq_handlers(adev), 0);
3719
3720 /* Verify VBLANK params were *not* populated */
3721 KUNIT_EXPECT_EQ(test, (int)adev->dm.vblank_params[0].irq_src, 0);
3722 KUNIT_EXPECT_NULL(test, adev->dm.vblank_params[0].adev);
3723
3724 /* Verify VUPDATE params were populated */
3725 KUNIT_EXPECT_EQ(test, (int)adev->dm.vupdate_params[0].irq_src,
3726 (int)DC_IRQ_SOURCE_VUPDATE1);
3727
3728 /* Verify PFLIP params were *not* populated */
3729 KUNIT_EXPECT_EQ(test, (int)adev->dm.pflip_params[0].irq_src, 0);
3730
3731 amdgpu_dm_irq_fini(adev);
3732 }
3733
3734 /**
3735 * dm_test_register_outbox_irq_handlers_without_dmub - Test outbox registration without DMUB
3736 * @test: The KUnit test context
3737 */
dm_test_register_outbox_irq_handlers_without_dmub(struct kunit * test)3738 static void dm_test_register_outbox_irq_handlers_without_dmub(struct kunit *test)
3739 {
3740 struct amdgpu_device *adev;
3741 struct dc *dc;
3742
3743 adev = dm_kunit_alloc_adev(test);
3744 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_irq_sources,
3745 adev), 0);
3746 dc = dm_kunit_alloc_dc_with_ctx(test);
3747 adev->dm.dc = dc;
3748 amdgpu_dm_set_irq_funcs(adev);
3749
3750 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_outbox_irq_handlers(adev), 0);
3751 KUNIT_ASSERT_NOT_NULL(test, adev->irq.client[SOC15_IH_CLIENTID_DCE].sources);
3752 KUNIT_EXPECT_PTR_EQ(test,
3753 adev->irq.client[SOC15_IH_CLIENTID_DCE].sources[
3754 DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT],
3755 &adev->dmub_outbox_irq);
3756 }
3757
3758 /**
3759 * dm_test_register_outbox_irq_handlers_with_dmub - Test outbox registration with DMUB
3760 * @test: The KUnit test context
3761 *
3762 * Exercises the dc->ctx->dmub_srv branch which maps the outbox source and
3763 * registers dm_dmub_outbox1_low_irq in the low IRQ context table.
3764 */
dm_test_register_outbox_irq_handlers_with_dmub(struct kunit * test)3765 static void dm_test_register_outbox_irq_handlers_with_dmub(struct kunit *test)
3766 {
3767 struct dc_dmub_srv *dc_dmub_srv;
3768 struct amdgpu_device *adev;
3769 struct list_head *hnd_list;
3770 struct dc *dc;
3771
3772 adev = dm_kunit_alloc_adev(test);
3773 KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_irq_sources,
3774 adev), 0);
3775 dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10);
3776 dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL);
3777 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv);
3778 dc->ctx->dmub_srv = dc_dmub_srv;
3779 adev->dm.dc = dc;
3780 amdgpu_dm_set_irq_funcs(adev);
3781 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3782
3783 KUNIT_EXPECT_EQ(test, amdgpu_dm_register_outbox_irq_handlers(adev), 0);
3784
3785 /* Verify the outbox IRQ params were populated */
3786 KUNIT_EXPECT_EQ(test, (int)adev->dm.dmub_outbox_params[0].irq_src,
3787 (int)DC_IRQ_SOURCE_DMCUB_OUTBOX);
3788 KUNIT_EXPECT_PTR_EQ(test, adev->dm.dmub_outbox_params[0].adev, adev);
3789
3790 /* Verify a low-context handler was registered for the outbox source */
3791 hnd_list = &adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_DMCUB_OUTBOX];
3792 KUNIT_EXPECT_FALSE(test, list_empty(hnd_list));
3793
3794 amdgpu_dm_irq_fini(adev);
3795 }
3796
3797 /* Tests for amdgpu_dm_irq_handler() */
3798
3799 /**
3800 * dm_test_irq_handler_dispatches_work - Test the top-level IRQ handler
3801 * @test: The KUnit test context
3802 *
3803 * amdgpu_dm_irq_handler() translates the hardware IRQ entry to a DC IRQ
3804 * source, acknowledges it, then dispatches to the high-context (immediate)
3805 * and low-context (scheduled) handler lists. A fake dc with a stubbed
3806 * irq_service maps the source id to DC_IRQ_SOURCE_VBLANK1 and lets the ack
3807 * succeed without touching hardware registers.
3808 */
dm_test_irq_handler_dispatches_work(struct kunit * test)3809 static void dm_test_irq_handler_dispatches_work(struct kunit *test)
3810 {
3811 struct dc_interrupt_params int_params = { 0 };
3812 struct amdgpu_iv_entry entry = { 0 };
3813 struct amdgpu_device *adev;
3814 int high_count = 0;
3815 int low_count = 0;
3816 void *handler;
3817 struct dc *dc;
3818
3819 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
3820 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
3821 KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
3822
3823 dc = dm_test_alloc_dc_with_irq_service(test,
3824 &dm_test_irq_service_funcs_dce110);
3825 adev->dm.dc = dc;
3826
3827 /* High-context (immediate) handler on VBLANK1. */
3828 int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
3829 int_params.irq_source = DC_IRQ_SOURCE_VBLANK1;
3830 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
3831 dm_test_irq_handler_count,
3832 &high_count);
3833 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
3834
3835 /* Low-context (scheduled) handler on VBLANK1. */
3836 int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
3837 handler = amdgpu_dm_irq_register_interrupt(adev, &int_params,
3838 dm_test_irq_handler_count,
3839 &low_count);
3840 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler);
3841
3842 /* src_id maps to DC_IRQ_SOURCE_VBLANK1 via the dce110 stub. */
3843 entry.src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0;
3844 entry.src_data[0] = 0;
3845
3846 KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_handler(adev, NULL, &entry), 0);
3847
3848 /* High-context handler runs synchronously in-place. */
3849 KUNIT_EXPECT_EQ(test, high_count, 1);
3850
3851 /*
3852 * Low-context work runs asynchronously; flush the DM IRQ workqueue so
3853 * it completes before we check the count. amdgpu_dm_irq_fini() cancels
3854 * any still-pending work rather than running it.
3855 */
3856 flush_workqueue(adev->dm.irq_wq);
3857 KUNIT_EXPECT_EQ(test, low_count, 1);
3858
3859 amdgpu_dm_irq_fini(adev);
3860 }
3861
3862 /* Tests for dm_handle_vmin_vmax_update() */
3863
3864 /**
3865 * dm_test_handle_vmin_vmax_update - Test the deferred vmin/vmax worker
3866 * @test: The KUnit test context
3867 *
3868 * The worker applies the cached timing adjust to the stream via
3869 * dc_stream_adjust_vmin_vmax(), drops the stream reference taken when the
3870 * work was scheduled, and frees the work and its adjust copy. A fake dc with
3871 * a current_state lets the adjust walk an empty pipe list without touching
3872 * hardware. The work and adjust are kmalloc'd because the worker frees them.
3873 */
dm_test_handle_vmin_vmax_update(struct kunit * test)3874 static void dm_test_handle_vmin_vmax_update(struct kunit *test)
3875 {
3876 struct dc_crtc_timing_adjust *adjust;
3877 struct vupdate_offload_work *work;
3878 struct dc_stream_state *stream;
3879 struct amdgpu_device *adev;
3880 struct dc *dc;
3881
3882 adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
3883 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
3884 mutex_init(&adev->dm.dc_lock);
3885
3886 dc = dm_kunit_alloc_dc_with_ctx(test);
3887 dc->current_state = kunit_kzalloc(test, sizeof(*dc->current_state),
3888 GFP_KERNEL);
3889 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc->current_state);
3890 adev->dm.dc = dc;
3891
3892 stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
3893 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
3894 /*
3895 * Start at two references: the worker's dc_stream_release() drops one,
3896 * leaving the kunit-managed allocation intact (no kfree).
3897 */
3898 kref_init(&stream->refcount);
3899 kref_get(&stream->refcount);
3900
3901 /* The worker kfree()s both, so they must come from the slab. */
3902 work = kzalloc_obj(*work);
3903 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
3904 adjust = kzalloc_obj(*adjust);
3905 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adjust);
3906
3907 work->adev = adev;
3908 work->stream = stream;
3909 work->adjust = adjust;
3910 adjust->v_total_min = 1000;
3911 adjust->v_total_max = 1100;
3912
3913 dm_handle_vmin_vmax_update(&work->work);
3914
3915 /* The adjust was applied and one stream reference was dropped. */
3916 KUNIT_EXPECT_EQ(test, stream->adjust.v_total_min, 1000);
3917 KUNIT_EXPECT_EQ(test, stream->adjust.v_total_max, 1100);
3918 KUNIT_EXPECT_EQ(test, kref_read(&stream->refcount), 1);
3919 }
3920
3921 static struct kunit_case amdgpu_dm_irq_tests[] = {
3922 /* amdgpu_dm_hpd_to_dal_irq_source */
3923 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd1),
3924 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd2),
3925 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd3),
3926 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd4),
3927 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd5),
3928 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd6),
3929 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_invalid),
3930 KUNIT_CASE(dm_test_hpd_to_dal_irq_source_out_of_range),
3931 /* are_sinks_equal */
3932 KUNIT_CASE(dm_test_are_sinks_equal_both_null),
3933 KUNIT_CASE(dm_test_are_sinks_equal_first_null),
3934 KUNIT_CASE(dm_test_are_sinks_equal_second_null),
3935 KUNIT_CASE(dm_test_are_sinks_equal_different_signal),
3936 KUNIT_CASE(dm_test_are_sinks_equal_different_edid_length),
3937 KUNIT_CASE(dm_test_are_sinks_equal_different_edid_data),
3938 KUNIT_CASE(dm_test_are_sinks_equal_identical),
3939 KUNIT_CASE(dm_test_are_sinks_equal_zero_length),
3940 KUNIT_CASE(dm_test_are_sinks_equal_full_edid_identical),
3941 KUNIT_CASE(dm_test_are_sinks_equal_full_edid_last_byte_differs),
3942 /* dmub_notification_type_str */
3943 KUNIT_CASE(dm_test_notification_str_no_data),
3944 KUNIT_CASE(dm_test_notification_str_aux_reply),
3945 KUNIT_CASE(dm_test_notification_str_hpd),
3946 KUNIT_CASE(dm_test_notification_str_hpd_irq),
3947 KUNIT_CASE(dm_test_notification_str_set_config),
3948 KUNIT_CASE(dm_test_notification_str_dpia),
3949 KUNIT_CASE(dm_test_notification_str_hpd_sense),
3950 KUNIT_CASE(dm_test_notification_str_fused_io),
3951 KUNIT_CASE(dm_test_notification_str_unknown),
3952 /* amdgpu_dm_irq_init */
3953 KUNIT_CASE(dm_test_irq_init_initializes_lists),
3954 /* amdgpu_dm_irq_register_interrupt */
3955 KUNIT_CASE(dm_test_irq_register_rejects_null_params),
3956 KUNIT_CASE(dm_test_irq_register_rejects_invalid_context),
3957 KUNIT_CASE(dm_test_irq_register_rejects_invalid_source),
3958 KUNIT_CASE(dm_test_irq_register_adds_low_context_handler),
3959 KUNIT_CASE(dm_test_irq_register_adds_high_context_handler),
3960 KUNIT_CASE(dm_test_irq_register_multiple_handlers),
3961 KUNIT_CASE(dm_test_irq_register_separate_contexts),
3962 /* amdgpu_dm_irq_unregister_interrupt */
3963 KUNIT_CASE(dm_test_irq_unregister_rejects_invalid_source),
3964 KUNIT_CASE(dm_test_irq_unregister_rejects_null_handler),
3965 KUNIT_CASE(dm_test_irq_unregister_handler_not_found),
3966 /* amdgpu_dm_irq_fini */
3967 KUNIT_CASE(dm_test_irq_fini_removes_registered_handlers),
3968 KUNIT_CASE(dm_test_irq_fini_on_empty_tables),
3969 /* amdgpu_dm_get_crtc_by_otg_inst */
3970 KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_match),
3971 KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_null),
3972 KUNIT_CASE(dm_test_get_crtc_by_otg_inst_empty_list),
3973 /* amdgpu_dm_set_irq_funcs */
3974 KUNIT_CASE(dm_test_set_irq_funcs),
3975 /* amdgpu_dm_irq_suspend/resume_early/resume_late */
3976 KUNIT_CASE(dm_test_irq_suspend_empty),
3977 KUNIT_CASE(dm_test_irq_resume_early_empty),
3978 KUNIT_CASE(dm_test_irq_resume_late_empty),
3979 KUNIT_CASE(dm_test_irq_suspend_registered),
3980 KUNIT_CASE(dm_test_irq_suspend_disables_polling),
3981 KUNIT_CASE(dm_test_irq_resume_early_registered),
3982 KUNIT_CASE(dm_test_irq_resume_late_registered),
3983 KUNIT_CASE(dm_test_irq_resume_late_enables_polling),
3984 /* amdgpu_dm_hpd_rx_irq_create_workqueue */
3985 KUNIT_CASE(dm_test_hpd_rx_irq_create_workqueue),
3986 /* amdgpu_dm_hpd_rx_irq_work_suspend */
3987 KUNIT_CASE(dm_test_hpd_rx_irq_work_suspend_null),
3988 KUNIT_CASE(dm_test_hpd_rx_irq_work_suspend_flushes),
3989 /* CRTC-based irq state callbacks (no-CRTC early return) */
3990 KUNIT_CASE(dm_test_set_crtc_irq_state_no_crtc),
3991 KUNIT_CASE(dm_test_set_pflip_irq_state_no_crtc),
3992 KUNIT_CASE(dm_test_set_vline0_irq_state_no_crtc),
3993 KUNIT_CASE(dm_test_set_vupdate_irq_state_no_crtc),
3994 /* CRTC-based irq state callbacks (dm_irq_state happy path) */
3995 KUNIT_CASE(dm_test_set_crtc_irq_state_otg_disabled),
3996 KUNIT_CASE(dm_test_set_crtc_irq_state_enable),
3997 KUNIT_CASE(dm_test_set_pflip_irq_state_disable),
3998 KUNIT_CASE(dm_test_set_vline0_irq_state_enable),
3999 KUNIT_CASE(dm_test_set_vupdate_irq_state_enable),
4000 KUNIT_CASE(dm_test_set_crtc_irq_state_allows_idle),
4001 /* amdgpu_dm_irq_immediate_work */
4002 KUNIT_CASE(dm_test_irq_immediate_work_empty),
4003 KUNIT_CASE(dm_test_irq_immediate_work_invokes_handler),
4004 KUNIT_CASE(dm_test_irq_immediate_work_invokes_all),
4005 /* amdgpu_dm_irq_schedule_work */
4006 KUNIT_CASE(dm_test_irq_schedule_work_empty),
4007 KUNIT_CASE(dm_test_irq_schedule_work_queues_handler),
4008 KUNIT_CASE(dm_test_irq_schedule_work_requeue_fallback),
4009 /* amdgpu_dm_set_hpd_irq_state */
4010 KUNIT_CASE(dm_test_set_hpd_irq_state_null_dc),
4011 /* amdgpu_dm_set_dmub_outbox_irq_state */
4012 KUNIT_CASE(dm_test_set_dmub_outbox_irq_state_null_dc),
4013 /* amdgpu_dm_set_dmub_trace_irq_state */
4014 KUNIT_CASE(dm_test_set_dmub_trace_irq_state_null_dc),
4015 /* amdgpu_dm_outbox_init */
4016 KUNIT_CASE(dm_test_outbox_init_null_dc),
4017 /* amdgpu_dm_hpd_init/amdgpu_dm_hpd_fini */
4018 KUNIT_CASE(dm_test_hpd_init_empty_connectors),
4019 KUNIT_CASE(dm_test_hpd_fini_empty_connectors),
4020 KUNIT_CASE(dm_test_hpd_init_fini_with_connectors),
4021 KUNIT_CASE(dm_test_hpd_init_fini_analog_connector),
4022 KUNIT_CASE(dm_test_hpd_init_fini_irq_ref),
4023 /* dm_handle_hpd_rx_offload_work */
4024 KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connector),
4025 KUNIT_CASE(dm_test_hpd_rx_offload_work_no_connection),
4026 KUNIT_CASE(dm_test_hpd_rx_offload_work_automated_test),
4027 KUNIT_CASE(dm_test_hpd_rx_offload_work_link_loss),
4028 /* amdgpu_dm_hdmi_hpd_debounce_work */
4029 KUNIT_CASE(dm_test_hdmi_hpd_debounce_detect_false),
4030 KUNIT_CASE(dm_test_hdmi_hpd_debounce_reallow_idle),
4031 /* handle_hpd_irq/handle_hpd_irq_helper */
4032 KUNIT_CASE(dm_test_handle_hpd_irq_disabled),
4033 KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_schedule),
4034 KUNIT_CASE(dm_test_handle_hpd_irq_helper_debounce_release_prev),
4035 KUNIT_CASE(dm_test_handle_hpd_irq_helper_detect_false),
4036 /* handle_hpd_rx_irq/schedule_hpd_rx_offload_work */
4037 KUNIT_CASE(dm_test_handle_hpd_rx_irq_disabled),
4038 KUNIT_CASE(dm_test_handle_hpd_rx_irq_no_left_work),
4039 KUNIT_CASE(dm_test_handle_hpd_rx_irq_automated_test),
4040 KUNIT_CASE(dm_test_handle_hpd_rx_irq_msg_rdy),
4041 KUNIT_CASE(dm_test_handle_hpd_rx_irq_link_loss),
4042 KUNIT_CASE(dm_test_schedule_hpd_rx_offload_work),
4043 /* dmub_hpd_callback/dmub_hpd_sense_callback */
4044 KUNIT_CASE(dm_test_dmub_hpd_callback_null_inputs),
4045 KUNIT_CASE(dm_test_dmub_hpd_callback_invalid_index),
4046 KUNIT_CASE(dm_test_dmub_hpd_callback_empty_connectors),
4047 KUNIT_CASE(dm_test_dmub_hpd_callback_unknown_type_match),
4048 KUNIT_CASE(dm_test_dmub_hpd_callback_hpd_type),
4049 KUNIT_CASE(dm_test_dmub_hpd_callback_hpd_irq_type),
4050 /* amdgpu_dm_register_hpd_handlers */
4051 KUNIT_CASE(dm_test_register_hpd_handlers_empty),
4052 KUNIT_CASE(dm_test_register_hpd_handlers_valid),
4053 KUNIT_CASE(dm_test_register_hpd_handlers_invalid_hpd),
4054 KUNIT_CASE(dm_test_register_hpd_handlers_invalid_hpd_rx),
4055 KUNIT_CASE(dm_test_register_hpd_handlers_dmub_outbox),
4056 /* pflip/vupdate/crtc high IRQ callbacks */
4057 KUNIT_CASE(dm_test_pflip_high_irq_no_crtc),
4058 KUNIT_CASE(dm_test_pflip_high_irq_not_submitted),
4059 KUNIT_CASE(dm_test_vupdate_high_irq_no_crtc),
4060 KUNIT_CASE(dm_test_crtc_high_irq_no_crtc),
4061 KUNIT_CASE(dm_test_crtc_high_irq_vrr_pre_ai),
4062 KUNIT_CASE(dm_test_crtc_high_irq_vrr_ai_no_stream),
4063 /* dm_handle_hpd_work */
4064 KUNIT_CASE(dm_test_handle_hpd_work_out_of_range),
4065 /* dm_dmub_outbox1_low_irq */
4066 KUNIT_CASE(dm_test_dmub_outbox1_low_irq_empty),
4067 KUNIT_CASE(dm_test_dmub_outbox1_low_irq_no_handler),
4068 KUNIT_CASE(dm_test_dmub_outbox1_low_irq_direct_callback),
4069 KUNIT_CASE(dm_test_dmub_outbox1_low_irq_offload),
4070 /* IRQ handler registration helpers */
4071 KUNIT_CASE(dm_test_dce110_register_irq_handlers_rejects_uninitialized_sources),
4072 KUNIT_CASE(dm_test_dce110_register_irq_handlers_one_crtc),
4073 KUNIT_CASE(dm_test_dcn10_register_irq_handlers_zero_crtc),
4074 KUNIT_CASE(dm_test_dcn10_register_irq_handlers_one_crtc),
4075 KUNIT_CASE(dm_test_register_outbox_irq_handlers_without_dmub),
4076 KUNIT_CASE(dm_test_register_outbox_irq_handlers_with_dmub),
4077 /* amdgpu_dm_irq_handler */
4078 KUNIT_CASE(dm_test_irq_handler_dispatches_work),
4079 /* dm_handle_vmin_vmax_update */
4080 KUNIT_CASE(dm_test_handle_vmin_vmax_update),
4081 {}
4082 };
4083
4084 static struct kunit_suite amdgpu_dm_irq_test_suite = {
4085 .name = "amdgpu_dm_irq",
4086 .test_cases = amdgpu_dm_irq_tests,
4087 };
4088
4089 kunit_test_suite(amdgpu_dm_irq_test_suite);
4090
4091 MODULE_AUTHOR("AMD");
4092 MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_irq");
4093 MODULE_LICENSE("Dual MIT/GPL");
4094