[PATCH 47/59] drm/amd/display: Test vline0 irq control
Alex Hung <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
[WHAT] The vline0 interrupt handling in amdgpu_dm_crtc_set_vblank() sits inside a CONFIG_DRM_AMD_SECURE_DISPLAY block. That symbol depends on CONFIG_DRM_AMD_DC_FP, which cannot be enabled on UML because UML does not select ARCH_HAS_KERNEL_FPU_SUPPORT, so the logic is never built by the KUnit tests and stays uncovered. [HOW] Move the block into amdgpu_dm_crtc_set_vline0_irq() and build it whenever CONFIG_DRM_AMD_SECURE_DISPLAY or the KUnit tests are enabled. The DCN-only check becomes an early return. Behaviour of amdgpu_dm_crtc_set_vblank() is unchanged. Add tests for amdgpu_dm_crtc_set_vline0_irq() covering the DCE no-op path, error propagation from amdgpu_irq_get() and the enable/disable refcount round-trip. Assisted-by: Copilot:Claude-Opus-5 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 40 ++++--- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.h | 1 + .../amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 101 ++++++++++++++++++ 3 files changed, 129 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 2de758aceda5..4b8530d734e5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -249,6 +249,30 @@ STATIC_IFN_KUNIT void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *w } EXPORT_IF_KUNIT(amdgpu_dm_crtc_vblank_control_worker); +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +STATIC_IFN_KUNIT int amdgpu_dm_crtc_set_vline0_irq(struct drm_crtc *crtc, int irq_type, + bool enable) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + int rc; + + /* crtc vline0 interrupt, only available on DCN+ */ + if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) + return 0; + + if (enable) { + rc = amdgpu_irq_get(adev, &adev->vline0_irq, irq_type); + drm_dbg_vbl(crtc->dev, "Get vline0_irq ret=%d\n", rc); + } else { + rc = amdgpu_irq_put(adev, &adev->vline0_irq, irq_type); + drm_dbg_vbl(crtc->dev, "Put vline0_irq ret=%d\n", rc); + } + + return rc; +} +EXPORT_IF_KUNIT(amdgpu_dm_crtc_set_vline0_irq); +#endif + static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) { struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); @@ -358,19 +382,9 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) } #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - /* crtc vline0 interrupt, only available on DCN+ */ - if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) { - if (enable) { - rc = amdgpu_irq_get(adev, &adev->vline0_irq, irq_type); - drm_dbg_vbl(crtc->dev, "Get vline0_irq ret=%d\n", rc); - } else { - rc = amdgpu_irq_put(adev, &adev->vline0_irq, irq_type); - drm_dbg_vbl(crtc->dev, "Put vline0_irq ret=%d\n", rc); - } - - if (rc) - return rc; - } + rc = amdgpu_dm_crtc_set_vline0_irq(crtc, irq_type, enable); + if (rc) + return rc; #endif if (amdgpu_in_reset(adev)) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h index 7de79796a56d..91fdd262c2d2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h @@ -56,6 +56,7 @@ void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc, struct drm_crtc_state *new_crtc_state); void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work); void amdgpu_dm_idle_worker(struct work_struct *work); +int amdgpu_dm_crtc_set_vline0_irq(struct drm_crtc *crtc, int irq_type, bool enable); int amdgpu_dm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *state); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c index a88175d99092..544445fbc770 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c @@ -1226,6 +1226,103 @@ static void dm_test_crtc_enable_vblank_ips_restore_replay(struct kunit *test) KUNIT_EXPECT_EQ(test, amdgpu_dm_crtc_enable_vblank(&acrtc->base), 0); } +/* Tests for amdgpu_dm_crtc_set_vline0_irq() */ + +/* + * dm_test_crtc_setup_vline0 - Build an adev/CRTC for the vline0 IRQ helper. + * @test: The KUnit test context + * @adev_out: Receives the allocated device + * @ip_version: DCE IP version stamped on the device (0 selects the DCE path) + * + * Returns a bare CRTC attached to the device. The IRQ subsystem is left + * uninstalled for callers to arm. + */ +static struct drm_crtc *dm_test_crtc_setup_vline0(struct kunit *test, + struct amdgpu_device **adev_out, + uint32_t ip_version) +{ + struct amdgpu_device *adev; + struct drm_crtc *crtc; + + adev = dm_kunit_alloc_adev(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + crtc->dev = &adev->ddev; + + adev->ip_versions[DCE_HWIP][0] = ip_version; + + *adev_out = adev; + return crtc; +} + +/** + * dm_test_crtc_set_vline0_irq_dce_noop - Test vline0 irq is skipped on DCE + * @test: The KUnit test context + * + * VLINE0 only exists on DCN+. With no DCE IP version stamped the helper must + * return 0 without touching the IRQ source, even though the IRQ subsystem is + * uninstalled (which would otherwise make amdgpu_irq_get() fail). + */ +static void dm_test_crtc_set_vline0_irq_dce_noop(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_crtc *crtc; + + crtc = dm_test_crtc_setup_vline0(test, &adev, 0); + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_crtc_set_vline0_irq(crtc, AMDGPU_CRTC_IRQ_VBLANK1, true), 0); +} + +/** + * dm_test_crtc_set_vline0_irq_error - Test vline0 irq failure is propagated + * @test: The KUnit test context + * + * On DCN with the IRQ subsystem uninstalled, amdgpu_irq_get() returns -ENOENT + * and the helper must propagate it. + */ +static void dm_test_crtc_set_vline0_irq_error(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_crtc *crtc; + + crtc = dm_test_crtc_setup_vline0(test, &adev, IP_VERSION(3, 5, 0)); + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_crtc_set_vline0_irq(crtc, AMDGPU_CRTC_IRQ_VBLANK1, true), + -ENOENT); +} + +/** + * dm_test_crtc_set_vline0_irq_enable_disable - Test vline0 irq refcounting + * @test: The KUnit test context + * + * On DCN with an armed IRQ source, enabling takes a vline0 reference and + * disabling drops it again. + */ +static void dm_test_crtc_set_vline0_irq_enable_disable(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_crtc *crtc; + atomic_t *refcount; + + crtc = dm_test_crtc_setup_vline0(test, &adev, IP_VERSION(3, 5, 0)); + + adev->irq.installed = true; + dm_test_crtc_arm_irq_src(test, &adev->vline0_irq, 1); + refcount = &adev->vline0_irq.enabled_types[AMDGPU_CRTC_IRQ_VBLANK1]; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_crtc_set_vline0_irq(crtc, AMDGPU_CRTC_IRQ_VBLANK1, true), 0); + KUNIT_EXPECT_EQ(test, atomic_read(refcount), 2); + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_crtc_set_vline0_irq(crtc, AMDGPU_CRTC_IRQ_VBLANK1, false), 0); + KUNIT_EXPECT_EQ(test, atomic_read(refcount), 1); +} + /* Tests for amdgpu_dm_crtc_update_crtc_active_planes() */ /** @@ -2526,6 +2623,10 @@ static struct kunit_case amdgpu_dm_crtc_tests[] = { KUNIT_CASE(dm_test_crtc_enable_vblank_queues_work), KUNIT_CASE(dm_test_crtc_enable_vblank_ips_restore), KUNIT_CASE(dm_test_crtc_enable_vblank_ips_restore_replay), + /* amdgpu_dm_crtc_set_vline0_irq */ + KUNIT_CASE(dm_test_crtc_set_vline0_irq_dce_noop), + KUNIT_CASE(dm_test_crtc_set_vline0_irq_error), + KUNIT_CASE(dm_test_crtc_set_vline0_irq_enable_disable), /* amdgpu_dm_crtc_update_crtc_active_planes */ KUNIT_CASE(dm_test_crtc_update_active_planes_no_stream), /* amdgpu_dm_crtc_count_crtc_active_planes */ -- 2.43.0