From: "Piórkowski, Piotr" <piotr.piorkowski@intel.com>
To: <intel-xe@lists.freedesktop.org>
Cc: "Piotr Piórkowski" <piotr.piorkowski@intel.com>,
"Michal Wajdeczko" <michal.wajdeczko@intel.com>,
"Ville Syrjälä" <ville.syrjala@linux.intel.com>,
"Maarten Lankhorst" <dev@lankhorst.se>
Subject: [PATCH v5 4/4] drm/xe/ggtt: Add KUnit tests for usable and shareable pools
Date: Tue, 8 Sep 2026 12:06:02 +0200 [thread overview]
Message-ID: <20260908100602.1626556-5-piotr.piorkowski@intel.com> (raw)
In-Reply-To: <20260908100602.1626556-1-piotr.piorkowski@intel.com>
From: Piotr Piórkowski <piotr.piorkowski@intel.com>
Add GGTT KUnit tests focused on the newly introduced usable and
shareable pools.
Cover range initialization for native and PF modes, including partially
overlapping pools. Exercise allocation direction and conflicts between
the pools, as well as the unavailable shareable pool and requests
exceeding pool capacity.
v2:
- Init ggtt.lock with mutex_init() in each test.
v3:
- Rename the test file to use the _kunit.c suffix.
- Use shared GGTT setup and cleanup helpers.
- Split PCI IOV coverage into a separate KUnit suite.
Assisted-by: Claude:claude-5-sonnet
Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Maarten Lankhorst <dev@lankhorst.se>
---
drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c | 327 +++++++++++++++++++++++
drivers/gpu/drm/xe/xe_ggtt.c | 4 +
2 files changed, 331 insertions(+)
create mode 100644 drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c
diff --git a/drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c b/drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c
new file mode 100644
index 0000000000000..9bac48982a81b
--- /dev/null
+++ b/drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0 AND MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/test.h>
+
+#include "xe_device.h"
+#include "xe_kunit_helpers.h"
+
+#define GGTT_TEST_START SZ_1M
+
+static u64 ggtt_test_accessible_size(struct kunit *test)
+{
+ struct xe_tile *tile = xe_device_get_root_tile(test->priv);
+
+ return GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
+}
+
+static void ggtt_test_fini(void *data)
+{
+ struct xe_ggtt *ggtt = data;
+
+ drm_mm_takedown(&ggtt->mm);
+}
+
+static struct xe_ggtt *ggtt_test_create(struct kunit *test, u64 full_size,
+ u64 usable_size, u64 shareable_size)
+{
+ struct xe_tile *tile = xe_device_get_root_tile(test->priv);
+ struct xe_ggtt *ggtt;
+ int err;
+
+ ggtt = kunit_kzalloc(test, sizeof(*ggtt), GFP_KERNEL);
+ if (!ggtt)
+ return NULL;
+
+ ggtt->tile = tile;
+ mutex_init(&ggtt->lock);
+ ggtt_init_ranges(ggtt, GGTT_TEST_START, full_size, usable_size, shareable_size);
+
+ err = kunit_add_action_or_reset(test, ggtt_test_fini, ggtt);
+ if (err)
+ return NULL;
+
+ return ggtt;
+}
+
+static void ggtt_test_remove_node(struct xe_ggtt_node *node)
+{
+ struct xe_ggtt *ggtt = node->ggtt;
+
+ mutex_lock(&ggtt->lock);
+ drm_mm_remove_node(&node->base);
+ node->base.size = 0;
+ mutex_unlock(&ggtt->lock);
+
+ ggtt_node_fini(node);
+}
+
+static void init_native(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = min_t(u64, SZ_1G, accessible);
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, usable, usable, 0);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ KUNIT_EXPECT_EQ(test, ggtt->start, GGTT_TEST_START);
+ KUNIT_EXPECT_EQ(test, ggtt->size, usable);
+ KUNIT_EXPECT_EQ(test, ggtt->full_size, usable);
+}
+
+static void alloc_usable_pool_high(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ struct xe_ggtt_node *usable_node;
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, usable, usable, 0);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ usable_node = xe_ggtt_insert_node(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_addr(usable_node),
+ GGTT_TEST_START + usable - XE_PAGE_SIZE);
+
+ ggtt_test_remove_node(usable_node);
+}
+
+static void alloc_usable_pool_oversized(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ struct xe_ggtt_node *node;
+ struct xe_ggtt *ggtt;
+
+ KUNIT_ASSERT_LE(test, usable + XE_PAGE_SIZE, (u64)U32_MAX);
+
+ ggtt = ggtt_test_create(test, usable, usable, 0);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ node = xe_ggtt_insert_node(ggtt, usable + XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(node));
+ KUNIT_EXPECT_EQ(test, PTR_ERR(node), -ENOSPC);
+}
+
+static struct kunit_case ggtt_test_cases[] = {
+ KUNIT_CASE(init_native),
+ KUNIT_CASE(alloc_usable_pool_high),
+ KUNIT_CASE(alloc_usable_pool_oversized),
+ {}
+};
+
+static struct kunit_suite ggtt_suite = {
+ .name = "xe_ggtt",
+ .test_cases = ggtt_test_cases,
+ .init = xe_kunit_helper_xe_device_test_init,
+};
+
+#if IS_ENABLED(CONFIG_PCI_IOV)
+static void init_shared_pf(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, accessible, accessible, accessible);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ KUNIT_EXPECT_EQ(test, ggtt->size, accessible);
+ KUNIT_EXPECT_EQ(test, ggtt_shareable_start(ggtt), 0);
+ KUNIT_EXPECT_EQ(test, ggtt->shareable_size, accessible);
+ KUNIT_EXPECT_EQ(test, ggtt->full_size, accessible);
+}
+
+static void init_partial_overlap(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt *ggtt;
+
+ KUNIT_ASSERT_GT(test, accessible, 0ULL);
+ KUNIT_ASSERT_GT(test, usable, shareable);
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ KUNIT_EXPECT_EQ(test, ggtt->size, usable);
+ KUNIT_EXPECT_EQ(test, ggtt_shareable_start(ggtt), accessible - shareable);
+ KUNIT_EXPECT_EQ(test, ggtt->shareable_size, shareable);
+ KUNIT_EXPECT_LT(test, ggtt_shareable_start(ggtt), usable);
+ KUNIT_EXPECT_EQ(test, ggtt->full_size, accessible);
+}
+
+static void alloc_usable_pool_low(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *usable_node;
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ usable_node = xe_ggtt_insert_node(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_addr(usable_node), GGTT_TEST_START);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_size(usable_node), (u64)XE_PAGE_SIZE);
+
+ ggtt_test_remove_node(usable_node);
+}
+
+static void alloc_shareable_pool_high(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *shareable_node;
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ shareable_node = xe_ggtt_insert_node_shareable(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shareable_node);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_addr(shareable_node),
+ GGTT_TEST_START + accessible - XE_PAGE_SIZE);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_size(shareable_node), (u64)XE_PAGE_SIZE);
+
+ ggtt_test_remove_node(shareable_node);
+}
+
+static void alloc_partial_overlap(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *shareable_node;
+ struct xe_ggtt_node *usable_node;
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ usable_node = xe_ggtt_insert_node(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
+ shareable_node = xe_ggtt_insert_node_shareable(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shareable_node);
+
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_addr(usable_node), GGTT_TEST_START);
+ KUNIT_EXPECT_EQ(test, xe_ggtt_node_addr(shareable_node),
+ GGTT_TEST_START + accessible - XE_PAGE_SIZE);
+
+ ggtt_test_remove_node(shareable_node);
+ ggtt_test_remove_node(usable_node);
+}
+
+static void alloc_partial_overlap_usable_full(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *shareable_node;
+ struct xe_ggtt_node *usable_node;
+ struct xe_ggtt *ggtt;
+
+ KUNIT_ASSERT_LE(test, usable, (u64)U32_MAX);
+ KUNIT_ASSERT_LE(test, shareable, (u64)U32_MAX);
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ usable_node = xe_ggtt_insert_node(ggtt, usable, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
+ shareable_node = xe_ggtt_insert_node_shareable(ggtt, shareable, XE_PAGE_SIZE);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(shareable_node));
+ KUNIT_EXPECT_EQ(test, PTR_ERR(shareable_node), -ENOSPC);
+
+ ggtt_test_remove_node(usable_node);
+}
+
+static void alloc_partial_overlap_shareable_full(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *shareable_node;
+ struct xe_ggtt_node *usable_node;
+ struct xe_ggtt *ggtt;
+
+ KUNIT_ASSERT_LE(test, usable, (u64)U32_MAX);
+ KUNIT_ASSERT_LE(test, shareable, (u64)U32_MAX);
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ shareable_node = xe_ggtt_insert_node_shareable(ggtt, shareable, XE_PAGE_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shareable_node);
+ usable_node = xe_ggtt_insert_node(ggtt, usable, XE_PAGE_SIZE);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(usable_node));
+ KUNIT_EXPECT_EQ(test, PTR_ERR(usable_node), -ENOSPC);
+
+ ggtt_test_remove_node(shareable_node);
+}
+
+static void alloc_shareable_pool_unavailable(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ struct xe_ggtt_node *node;
+ struct xe_ggtt *ggtt;
+
+ ggtt = ggtt_test_create(test, usable, usable, 0);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ node = xe_ggtt_insert_node_shareable(ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(node));
+ KUNIT_EXPECT_EQ(test, PTR_ERR(node), -ENOSPC);
+}
+
+static void alloc_shareable_pool_oversized(struct kunit *test)
+{
+ u64 accessible = ggtt_test_accessible_size(test);
+ u64 usable = (accessible * 3) / 4;
+ u64 shareable = accessible / 2;
+ struct xe_ggtt_node *node;
+ struct xe_ggtt *ggtt;
+
+ KUNIT_ASSERT_LE(test, shareable + XE_PAGE_SIZE, (u64)U32_MAX);
+
+ ggtt = ggtt_test_create(test, accessible, usable, shareable);
+ KUNIT_ASSERT_NOT_NULL(test, ggtt);
+
+ node = xe_ggtt_insert_node_shareable(ggtt, shareable + XE_PAGE_SIZE,
+ XE_PAGE_SIZE);
+ KUNIT_ASSERT_TRUE(test, IS_ERR(node));
+ KUNIT_EXPECT_EQ(test, PTR_ERR(node), -ENOSPC);
+}
+
+static struct kunit_case ggtt_iov_test_cases[] = {
+ KUNIT_CASE(init_shared_pf),
+ KUNIT_CASE(init_partial_overlap),
+ KUNIT_CASE(alloc_usable_pool_low),
+ KUNIT_CASE(alloc_shareable_pool_high),
+ KUNIT_CASE(alloc_partial_overlap),
+ KUNIT_CASE(alloc_partial_overlap_usable_full),
+ KUNIT_CASE(alloc_partial_overlap_shareable_full),
+ KUNIT_CASE(alloc_shareable_pool_unavailable),
+ KUNIT_CASE(alloc_shareable_pool_oversized),
+ {}
+};
+
+static struct kunit_suite ggtt_iov_suite = {
+ .name = "xe_ggtt_iov",
+ .test_cases = ggtt_iov_test_cases,
+ .init = xe_kunit_helper_xe_device_test_init,
+};
+#endif
+
+kunit_test_suites(&ggtt_suite);
+#if IS_ENABLED(CONFIG_PCI_IOV)
+kunit_test_suites(&ggtt_iov_suite);
+#endif
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index 4eec94e377c98..cc64ae68661dc 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -1385,3 +1385,7 @@ u64 xe_ggtt_node_size(const struct xe_ggtt_node *node)
{
return node->base.size;
}
+
+#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
+#include "tests/xe_ggtt_kunit.c"
+#endif
--
2.34.1
next prev parent reply other threads:[~2026-09-08 10:06 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 10:05 [PATCH v5 0/4] Separate GGTT pools for submissions and VFs provisioning Piórkowski, Piotr
2026-09-08 10:05 ` [PATCH v5 1/4] drm/xe/ggtt: Introduce full GGTT range size Piórkowski, Piotr
2026-09-08 10:06 ` [PATCH v5 2/4] drm/xe/ggtt: Split GGTT into usable and shareable pools Piórkowski, Piotr
2026-09-08 10:06 ` [PATCH v5 3/4] drm/xe/ggtt: Initialize GGTT pools by SR-IOV mode Piórkowski, Piotr
2026-09-08 10:06 ` Piórkowski, Piotr [this message]
2026-09-08 10:27 ` [PATCH v5 4/4] drm/xe/ggtt: Add KUnit tests for usable and shareable pools sashiko-bot
2026-09-08 11:46 ` ✗ CI.checkpatch: warning for Separate GGTT pools for submissions and VFs provisioning (rev5) Patchwork
2026-09-08 11:48 ` ✓ CI.KUnit: success " Patchwork
2026-09-08 12:53 ` ✓ Xe.CI.BAT: " Patchwork
2026-09-08 15:44 ` ✗ 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=20260908100602.1626556-5-piotr.piorkowski@intel.com \
--to=piotr.piorkowski@intel.com \
--cc=dev@lankhorst.se \
--cc=intel-xe@lists.freedesktop.org \
--cc=michal.wajdeczko@intel.com \
--cc=ville.syrjala@linux.intel.com \
/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;
as well as URLs for NNTP newsgroup(s).