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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.