From: Michal Wajdeczko <michal.wajdeczko@intel.com>
To: intel-xe@lists.freedesktop.org
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Subject: [PATCH 13/13] drm/xe/tests: Add kunit tests for memory based interrupts
Date: Tue, 28 Apr 2026 16:27:20 +0200 [thread overview]
Message-ID: <20260428142722.582-14-michal.wajdeczko@intel.com> (raw)
In-Reply-To: <20260428142722.582-1-michal.wajdeczko@intel.com>
Add basic kunit tests for the memory based interrupts. For maximum
coverage, we will use non-real device definition with custom mix of
GT IPs that are defined with the largest number of engines.
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
drivers/gpu/drm/xe/tests/xe_memirq_kunit.c | 276 +++++++++++++++++++++
drivers/gpu/drm/xe/xe_memirq.c | 4 +
2 files changed, 280 insertions(+)
create mode 100644 drivers/gpu/drm/xe/tests/xe_memirq_kunit.c
diff --git a/drivers/gpu/drm/xe/tests/xe_memirq_kunit.c b/drivers/gpu/drm/xe/tests/xe_memirq_kunit.c
new file mode 100644
index 000000000000..c60b8fb1edc9
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_memirq_kunit.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0 AND MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/static_stub.h>
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+
+#include "xe_device.h"
+#include "xe_hw_engine.h"
+#include "xe_kunit_helpers.h"
+#include "xe_pci_test.h"
+#include "xe_uc_fw.h"
+
+static int __memirq_test_init(struct kunit *test, bool msix)
+{
+ struct xe_pci_fake_data fake = {
+ .sriov_mode = XE_SRIOV_MODE_VF,
+ .platform = XE_PANTHERLAKE, /* platform known to use memirq */
+ .subplatform = XE_SUBPLATFORM_NONE,
+ .graphics_verx100 = msix ? 3511 : 3000, /* either all BCS/CCS or RCS */
+ .media_verx100 = 3000,
+ .ggtt_start = SZ_1M,
+ .ggtt_size = SZ_64K,
+ .mmio_read = ~0, /* to cheat fuse readings */
+ };
+ struct xe_memirq *memirq;
+ struct xe_device *xe;
+ struct xe_gt *gt;
+ int id;
+
+ test->priv = &fake;
+ xe_kunit_helper_xe_device_test_init(test);
+
+ xe = test->priv;
+ KUNIT_ASSERT_EQ(test, xe_sriov_init(xe), 0);
+
+ /* sufficient to claim MSI-X support */
+ xe->irq.msix.nvec = msix ? 2 : 0;
+ KUNIT_EXPECT_EQ(test, msix, xe_device_has_msix(xe));
+
+ for_each_gt(gt, xe, id) {
+ xe_uc_fw_change_status(>->uc.gsc.fw, XE_UC_FIRMWARE_NOT_SUPPORTED);
+ xe_hw_engines_init_early(gt);
+ }
+
+ memirq = &xe_device_get_root_tile(xe)->memirq;
+ KUNIT_ASSERT_EQ(test, xe_memirq_init(memirq), 0);
+ KUNIT_EXPECT_TRUE(test, memirq->bo);
+ KUNIT_EXPECT_NE(test, xe_bo_ggtt_addr(memirq->bo), 0);
+
+ test->priv = memirq;
+ return 0;
+}
+
+static int memirq_test_init(struct kunit *test)
+{
+ return __memirq_test_init(test, false);
+}
+
+static int memirq_msix_test_init(struct kunit *test)
+{
+ return __memirq_test_init(test, true);
+}
+
+static u32 source_byte_offset(struct xe_memirq *memirq, u16 source, u16 instance)
+{
+ return memirq_source_page_offset(memirq, instance) + source;
+}
+
+static void set_source(struct xe_memirq *memirq, u16 source, u16 instance)
+{
+ iosys_map_wr(&memirq->bo->vmap,
+ source_byte_offset(memirq, source, instance), u8, 0xFF);
+}
+
+static void set_status(struct xe_memirq *memirq, u16 source, u16 instance, u16 status)
+{
+ iosys_map_wr(&memirq->bo->vmap,
+ memirq_status_vector_offset(memirq, source, instance) + status, u8, 0xFF);
+}
+
+static bool is_status_cleared(struct xe_memirq *memirq, u16 source, u16 instance, u16 status)
+{
+ struct iosys_map map =
+ IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap,
+ memirq_status_vector_offset(memirq, source, instance));
+
+ return !memirq_received_noclear(memirq, &map, status, "kunit");
+}
+
+struct memirq_test_param {
+ const char *name;
+ u16 source;
+ u16 instance;
+ u16 source0;
+ u16 status;
+ u16 iir;
+};
+
+static void replacement_xe_guc_irq_handler(struct xe_guc *guc, const u16 iir)
+{
+ struct kunit *test = kunit_get_current_test();
+ const struct memirq_test_param *p = test->param_value;
+ unsigned int *counter = test->priv;
+
+ *counter += 1;
+ kunit_info(test, "handler %u: IIR %#x\n", *counter, iir);
+
+ KUNIT_EXPECT_EQ(test, p->source == ilog2(INTR_GUC), xe_gt_is_main_type(guc_to_gt(guc)));
+ KUNIT_EXPECT_EQ(test, p->source == ilog2(INTR_MGUC), xe_gt_is_media_type(guc_to_gt(guc)));
+ KUNIT_EXPECT_EQ(test, p->instance, 0);
+ KUNIT_EXPECT_EQ(test, p->iir, iir);
+}
+
+static void test_guc(struct kunit *test)
+{
+ const struct memirq_test_param *p = test->param_value;
+ struct xe_memirq *memirq = test->priv;
+ unsigned int counter = 0;
+
+ test->priv = &counter;
+ kunit_activate_static_stub(test, xe_guc_irq_handler,
+ replacement_xe_guc_irq_handler);
+
+ set_source(memirq, p->source, 0);
+ set_status(memirq, p->source, 0, p->status);
+ KUNIT_ASSERT_FALSE(test, is_status_cleared(memirq, p->source, p->instance, p->status));
+
+ counter = 0;
+ xe_memirq_handler(memirq);
+ KUNIT_EXPECT_EQ(test, counter, 1);
+ KUNIT_EXPECT_TRUE(test, is_status_cleared(memirq, p->source, p->instance, p->status));
+}
+
+static void replacement_xe_hw_engine_handle_irq(struct xe_hw_engine *hwe, u16 intr_vec)
+{
+ struct kunit *test = kunit_get_current_test();
+ const struct memirq_test_param *p = test->param_value;
+ unsigned int *counter = test->priv;
+ u16 source;
+
+ *counter += 1;
+ kunit_info(test, "handler %u: %s IIR %#x\n", *counter, hwe->name, intr_vec);
+
+ source = hw_reports_to_instance_zero(&hwe->gt->tile->memirq) ? p->source0 : p->source;
+
+ KUNIT_EXPECT_EQ(test, source, hwe->irq_offset);
+ KUNIT_EXPECT_EQ(test, p->instance, hwe->instance);
+ KUNIT_EXPECT_EQ(test, p->iir, intr_vec);
+}
+
+static bool has_hwe(struct xe_memirq *memirq, u16 source, u16 instance)
+{
+ struct xe_tile *tile = memirq_to_tile(memirq);
+ struct xe_hw_engine *hwe;
+ unsigned int gid, eid;
+ struct xe_gt *gt;
+
+ for_each_gt_on_tile(gt, tile, gid)
+ for_each_hw_engine(hwe, gt, eid)
+ if (hwe->irq_offset == source &&
+ hwe->instance == instance)
+ return true;
+ return false;
+}
+
+static void test_hwe(struct kunit *test)
+{
+ const struct memirq_test_param *p = test->param_value;
+ struct xe_memirq *memirq = test->priv;
+ unsigned int counter = 0;
+ u16 source;
+
+ test->priv = &counter;
+ kunit_activate_static_stub(test, xe_hw_engine_handle_irq,
+ replacement_xe_hw_engine_handle_irq);
+
+ source = hw_reports_to_instance_zero(memirq) ? p->source0 : p->source;
+ if (!has_hwe(memirq, source, p->instance))
+ kunit_skip(test, "engine not available");
+
+ set_source(memirq, source, p->instance);
+ set_status(memirq, source, p->instance, p->status);
+ KUNIT_EXPECT_FALSE(test, is_status_cleared(memirq, source, p->instance, p->status));
+
+ counter = 0;
+ xe_memirq_handler(memirq);
+ KUNIT_EXPECT_EQ(test, counter, 1);
+ KUNIT_EXPECT_TRUE(test, is_status_cleared(memirq, source, p->instance, p->status));
+}
+
+/* small hacks to allow magic macros work */
+#define INTR_rcs(n) (INTR_RCS0 + BUILD_BUG_ON_ZERO(n))
+#define INTR_bcs(n) ((((n) < 8) ? INTR_BCS(n) : INTR_BCS8) + BUILD_BUG_ON_ZERO((n) > 8))
+
+#define MAKE_MEMIRQ_TEST_PARAM(NAME, SRC, S0, INST, IIR, ...) { \
+ .name = (NAME), \
+ .source = ilog2(INTR_##SRC) __VA_ARGS__, \
+ .source0 = ilog2(INTR_##S0) __VA_ARGS__, \
+ .instance = (INST), \
+ .status = ilog2(IIR), \
+ .iir = (IIR), \
+}
+
+#define MAKE_MEMIRQ_TEST_PARAM_GUC(GUC, IIR, ...) \
+ MAKE_MEMIRQ_TEST_PARAM(#GUC " " #IIR, GUC, GUC, 0, GUC_INTR_##IIR)
+
+#define MAKE_MEMIRQ_TEST_PARAM_HWE(ENG, INST, IIR, ...) \
+ MAKE_MEMIRQ_TEST_PARAM(#ENG #INST " " #IIR, ENG(INST), ENG(0), (INST), \
+ GT_##IIR, ##__VA_ARGS__)
+
+static const struct memirq_test_param guc_irqs[] = {
+ MAKE_MEMIRQ_TEST_PARAM_GUC(GUC, GUC2HOST),
+ MAKE_MEMIRQ_TEST_PARAM_GUC(GUC, SW_INT_0),
+ MAKE_MEMIRQ_TEST_PARAM_GUC(MGUC, GUC2HOST),
+ MAKE_MEMIRQ_TEST_PARAM_GUC(MGUC, SW_INT_0),
+};
+
+static const struct memirq_test_param hwe_irqs[] = {
+ MAKE_MEMIRQ_TEST_PARAM_HWE(rcs, 0, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 0, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 1, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 2, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 3, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 4, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 5, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 6, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 7, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(bcs, 8, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(CCS, 0, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(CCS, 1, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(CCS, 2, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(CCS, 3, MI_USER_INTERRUPT),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 0, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 1, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 2, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 3, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 4, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 5, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 6, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VCS, 7, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VECS, 0, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VECS, 1, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VECS, 2, MI_USER_INTERRUPT, +32),
+ MAKE_MEMIRQ_TEST_PARAM_HWE(VECS, 3, MI_USER_INTERRUPT, +32),
+};
+
+static void memirq_test_param_get_desc(const struct memirq_test_param *p, char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", p->name);
+}
+
+KUNIT_ARRAY_PARAM(guc_irqs, guc_irqs, memirq_test_param_get_desc);
+KUNIT_ARRAY_PARAM(hwe_irqs, hwe_irqs, memirq_test_param_get_desc);
+
+static struct kunit_case memirq_test_cases[] = {
+ KUNIT_CASE_PARAM(test_guc, guc_irqs_gen_params),
+ KUNIT_CASE_PARAM(test_hwe, hwe_irqs_gen_params),
+ {}
+};
+
+static struct kunit_suite memirq_suite = {
+ .name = "memirq",
+ .test_cases = memirq_test_cases,
+ .init = memirq_test_init,
+};
+
+static struct kunit_suite memirq_msix_suite = {
+ .name = "memirq_msix",
+ .test_cases = memirq_test_cases,
+ .init = memirq_msix_test_init,
+};
+
+kunit_test_suites(&memirq_suite, &memirq_msix_suite);
diff --git a/drivers/gpu/drm/xe/xe_memirq.c b/drivers/gpu/drm/xe/xe_memirq.c
index b6fdefaf9463..918a62a6fdf3 100644
--- a/drivers/gpu/drm/xe/xe_memirq.c
+++ b/drivers/gpu/drm/xe/xe_memirq.c
@@ -600,3 +600,7 @@ void xe_memirq_handler(struct xe_memirq *memirq)
memirq_dispatch_guc(memirq, &map, &tile->media_gt->uc.guc);
}
}
+
+#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_memirq_kunit.c"
+#endif
--
2.47.1
next prev parent reply other threads:[~2026-04-28 14:27 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 14:27 [PATCH 00/13] drm/xe/tests: Add kunit tests for memory based interrupts Michal Wajdeczko
2026-04-28 14:27 ` [PATCH 01/13] drm/xe/ggtt: Rename parameter name in xe_ggtt_init_kunit() Michal Wajdeczko
2026-04-29 20:29 ` Summers, Stuart
2026-04-30 8:32 ` Jani Nikula
2026-04-30 21:50 ` Summers, Stuart
2026-04-28 14:27 ` [PATCH 02/13] drm/xe/guc: Allow to replace xe_guc_irq_handler() with stub Michal Wajdeczko
2026-04-30 5:44 ` K V P, Satyanarayana
2026-04-28 14:27 ` [PATCH 03/13] drm/xe/hwe: Allow to replace xe_hw_engine_handle_irq() " Michal Wajdeczko
2026-04-30 5:47 ` K V P, Satyanarayana
2026-04-28 14:27 ` [PATCH 04/13] drm/xe/mmio: Allow to replace xe_mmio_read32|write32() " Michal Wajdeczko
2026-04-30 5:48 ` K V P, Satyanarayana
2026-04-28 14:27 ` [PATCH 05/13] drm/xe/kunit: Promote GGTT initialization to test_init() helper Michal Wajdeczko
2026-04-28 14:27 ` [PATCH 06/13] drm/xe/kunit: Promote fake BO activation " Michal Wajdeczko
2026-04-28 14:27 ` [PATCH 07/13] drm/xe/kunit: Activate empty MMIO stubs in test_init() Michal Wajdeczko
2026-04-28 14:27 ` [PATCH 08/13] drm/xe/memirq: Make page layout macros private Michal Wajdeczko
2026-05-05 7:54 ` Levi, Ilia
2026-04-28 14:27 ` [PATCH 09/13] drm/xe/memirq: Introduce helper to calculate source page offset Michal Wajdeczko
2026-05-05 8:27 ` Levi, Ilia
2026-04-28 14:27 ` [PATCH 10/13] drm/xe/memirq: Introduce helper to calculate status vector offset Michal Wajdeczko
2026-05-05 12:40 ` Levi, Ilia
2026-04-28 14:27 ` [PATCH 11/13] drm/xe/memirq: Refactor xe_memirq_hwe_handler Michal Wajdeczko
2026-05-05 12:46 ` Levi, Ilia
2026-04-28 14:27 ` [PATCH 12/13] drm/xe/memirq: Dump additional source pages if MSI-X Michal Wajdeczko
2026-05-05 13:12 ` Levi, Ilia
2026-04-28 14:27 ` Michal Wajdeczko [this message]
2026-04-28 16:33 ` ✗ CI.checkpatch: warning for drm/xe/tests: Add kunit tests for memory based interrupts Patchwork
2026-04-28 16:35 ` ✓ CI.KUnit: success " Patchwork
2026-04-28 17:43 ` ✓ Xe.CI.BAT: " Patchwork
2026-04-29 5:04 ` ✗ Xe.CI.FULL: failure " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260428142722.582-14-michal.wajdeczko@intel.com \
--to=michal.wajdeczko@intel.com \
--cc=intel-xe@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox