From: Michal Wajdeczko <michal.wajdeczko@intel.com>
To: "Piórkowski, Piotr" <piotr.piorkowski@intel.com>,
intel-xe@lists.freedesktop.org
Cc: "Ville Syrjälä" <ville.syrjala@linux.intel.com>,
"Maarten Lankhorst" <dev@lankhorst.se>
Subject: Re: [PATCH v4 3/3] drm/xe/ggtt: Add KUnit tests for usable and shareable pools
Date: Wed, 2 Sep 2026 20:21:54 +0200 [thread overview]
Message-ID: <5d4de95b-24ea-4aed-817a-c12e9974d183@intel.com> (raw)
In-Reply-To: <20260901164435.1395260-4-piotr.piorkowski@intel.com>
On 9/1/2026 6:44 PM, Piórkowski, Piotr wrote:
> 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.
nit: keep change log under ---
>
> 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_test.c | 336 ++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_ggtt.c | 4 +
> 2 files changed, 340 insertions(+)
> create mode 100644 drivers/gpu/drm/xe/tests/xe_ggtt_test.c
>
> diff --git a/drivers/gpu/drm/xe/tests/xe_ggtt_test.c b/drivers/gpu/drm/xe/tests/xe_ggtt_test.c
> new file mode 100644
> index 000000000000..7d28b97f8afe
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/tests/xe_ggtt_test.c
for pure kunit tests we should use _kunit.c suffix instead
[1] https://elixir.bootlin.com/linux/v7.2.2/source/Documentation/dev-tools/kunit/style.rst#L188
> @@ -0,0 +1,336 @@
> +// 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 int ggtt_test_init(struct kunit *test)
> +{
> + xe_kunit_helper_xe_device_test_init(test);
> + return 0;
> +}
nit: if you are not planning to add custom initialization steps,
just plugin the xe_kunit_helper_xe_device_test_init() directly
> +
> +static void init_native(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = min_t(u64, SZ_1G, accessible);
> +
> + ggtt.hw_size = usable;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, 0);
> +
> + KUNIT_EXPECT_EQ(test, ggtt.start, GGTT_TEST_START);
> + KUNIT_EXPECT_EQ(test, ggtt.size, usable);
> + KUNIT_EXPECT_EQ(test, ggtt.hw_size, usable);
> +
> + drm_mm_takedown(&ggtt.mm);
but maybe this should be done in a cleanup action registered
in the custom ggtt_test_init() ?
> +}
> +
> +static void alloc_usable_pool_high(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *usable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> +
> + mutex_init(&ggtt.lock);
this too
> + ggtt.hw_size = usable;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, 0);
> +
> + usable_node = xe_ggtt_insert_node(&ggtt, XE_PAGE_SIZE, XE_PAGE_SIZE);
did you run kunit with --raw_output flag?
did you see
xe_tile_WARN_ON_ONCE(mmio->tile, !mmio->tile->xe->mmio.regs);
as likely GGTT would try some TLB invalidation ...
> + 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_node_remove(usable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_usable_pool_oversized(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> +
> + KUNIT_ASSERT_LE(test, usable + XE_PAGE_SIZE, (u64)U32_MAX);
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = usable;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, 0);
> +
> + 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);
> +
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +#if IS_ENABLED(CONFIG_PCI_IOV)
> +static void init_shared_pf(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> +
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, accessible, accessible);
> +
> + KUNIT_EXPECT_EQ(test, ggtt.size, accessible);
> + KUNIT_EXPECT_EQ(test, ggtt.shareable.start, 0);
> + KUNIT_EXPECT_EQ(test, ggtt.shareable.size, accessible);
> + KUNIT_EXPECT_EQ(test, ggtt.hw_size, accessible);
> +
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void init_partial_overlap(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + KUNIT_ASSERT_GT(test, accessible, 0ULL);
> + KUNIT_ASSERT_GT(test, usable, shareable);
> +
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + KUNIT_EXPECT_EQ(test, ggtt.size, usable);
> + KUNIT_EXPECT_EQ(test, ggtt.shareable.start, accessible - shareable);
> + KUNIT_EXPECT_EQ(test, ggtt.shareable.size, shareable);
> + KUNIT_EXPECT_LT(test, ggtt.shareable.start, usable);
> + KUNIT_EXPECT_EQ(test, ggtt.hw_size, accessible);
> +
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_usable_pool_low(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *usable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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_node_remove(usable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_shareable_pool_high(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *shareable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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_node_remove(shareable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_partial_overlap(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *usable_node, *shareable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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_node_remove(shareable_node);
> + ggtt_node_remove(usable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_partial_overlap_usable_full(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *usable_node, *shareable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + KUNIT_ASSERT_LE(test, usable, (u64)U32_MAX);
> + KUNIT_ASSERT_LE(test, shareable, (u64)U32_MAX);
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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_node_remove(usable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_partial_overlap_shareable_full(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *usable_node, *shareable_node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + KUNIT_ASSERT_LE(test, usable, (u64)U32_MAX);
> + KUNIT_ASSERT_LE(test, shareable, (u64)U32_MAX);
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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_node_remove(shareable_node);
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_shareable_pool_unavailable(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = usable;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, 0);
> +
> + 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);
> +
> + drm_mm_takedown(&ggtt.mm);
> +}
> +
> +static void alloc_shareable_pool_oversized(struct kunit *test)
> +{
> + struct xe_tile *tile = xe_device_get_root_tile(test->priv);
> + struct xe_ggtt ggtt = { .tile = tile };
> + struct xe_ggtt_node *node;
> + u64 accessible = GUC_GGTT_TOP - xe_wopcm_size(tile_to_xe(tile));
> + u64 usable = (accessible * 3) / 4;
> + u64 shareable = accessible / 2;
> +
> + KUNIT_ASSERT_LE(test, shareable + XE_PAGE_SIZE, (u64)U32_MAX);
> +
> + mutex_init(&ggtt.lock);
> + ggtt.hw_size = accessible;
> + ggtt_init_ranges(&ggtt, GGTT_TEST_START, usable, shareable);
> +
> + 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);
> +
> + drm_mm_takedown(&ggtt.mm);
> +}
> +#else
> +#define GGTT_PCI_IOV_TEST_SKIP(_name) \
> + static void _name(struct kunit *test) \
> + { \
> + kunit_skip(test, "requires CONFIG_PCI_IOV"); \
> + }
> +
> +GGTT_PCI_IOV_TEST_SKIP(init_shared_pf)
> +GGTT_PCI_IOV_TEST_SKIP(init_partial_overlap)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_usable_pool_low)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_shareable_pool_high)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_partial_overlap)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_partial_overlap_usable_full)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_partial_overlap_shareable_full)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_shareable_pool_unavailable)
> +GGTT_PCI_IOV_TEST_SKIP(alloc_shareable_pool_oversized)
> +
> +#undef GGTT_PCI_IOV_TEST_SKIP
> +#endif /* CONFIG_PCI_IOV */
instead of defining test stubs, just add separate suite
+static struct kunit_suite ggtt_iov_suite = {
+ .name = "xe_ggtt_iov",
+ .test_cases = ggtt_iov_test_cases,
+ .init = ggtt_test_init,
under the same if ENABLED(CONFIG_PCI_IOV)
> +
> +static struct kunit_case ggtt_test_cases[] = {
> + KUNIT_CASE(init_native),
> + KUNIT_CASE(alloc_usable_pool_high),
> + KUNIT_CASE(alloc_usable_pool_oversized),
> + 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_suite = {
> + .name = "xe_ggtt",
> + .test_cases = ggtt_test_cases,
> + .init = ggtt_test_init,
> +};
> +
> +kunit_test_suites(&ggtt_suite);
> diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
> index 7fcd686f9729..19f9c564030b 100644
> --- a/drivers/gpu/drm/xe/xe_ggtt.c
> +++ b/drivers/gpu/drm/xe/xe_ggtt.c
> @@ -1397,3 +1397,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_test.c"
> +#endif
next prev parent reply other threads:[~2026-09-02 18:22 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 16:44 [PATCH v4 0/3] Separate GGTT pools for submissions and VFs provisioning Piórkowski, Piotr
2026-09-01 16:44 ` [PATCH v4 1/3] drm/xe/ggtt: Split GGTT into usable and shareable pools Piórkowski, Piotr
2026-09-02 17:59 ` Michal Wajdeczko
2026-09-03 16:14 ` Piotr Piórkowski
2026-09-01 16:44 ` [PATCH v4 2/3] drm/xe/ggtt: Initialize GGTT pools by SR-IOV mode Piórkowski, Piotr
2026-09-01 16:53 ` sashiko-bot
2026-09-02 18:07 ` Michal Wajdeczko
2026-09-01 16:44 ` [PATCH v4 3/3] drm/xe/ggtt: Add KUnit tests for usable and shareable pools Piórkowski, Piotr
2026-09-02 18:21 ` Michal Wajdeczko [this message]
2026-09-01 16:51 ` ✗ CI.checkpatch: warning for Separate GGTT pools for submissions and VFs provisioning (rev4) Patchwork
2026-09-01 16:53 ` ✓ CI.KUnit: success " Patchwork
2026-09-01 17:35 ` ✓ Xe.CI.BAT: " Patchwork
2026-09-01 19:38 ` ✓ Xe.CI.FULL: " 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=5d4de95b-24ea-4aed-817a-c12e9974d183@intel.com \
--to=michal.wajdeczko@intel.com \
--cc=dev@lankhorst.se \
--cc=intel-xe@lists.freedesktop.org \
--cc=piotr.piorkowski@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