Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Laguna, Lukasz" <lukasz.laguna@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: [v7,5/5] drm/xe/ggtt: Add KUnit tests for usable and shareable pools
Date: Tue, 10 Nov 2026 16:31:45 +0100	[thread overview]
Message-ID: <cfb7a910-823d-416d-beab-7a6e3077788f@intel.com> (raw)
In-Reply-To: <20261021085716.709503-6-piotr.piorkowski@intel.com>


On 10/21/2026 10:57, 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.
> 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.
> v4:
>   - Release allocated nodes through KUnit deferred actions, so that an
>     aborted test does not leak them into drm_mm_takedown() (Sashiko).
> v5:
>   - Move ggtt_test_insert_node_shareable() under CONFIG_PCI_IOV to fix
>     the !CONFIG_PCI_IOV build (Sashiko).
>
> Assisted-by: Claude:claude-5-sonnet
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@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 | 341 +++++++++++++++++++++++
>   drivers/gpu/drm/xe/xe_ggtt.c             |   4 +
>   2 files changed, 345 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..53c17d4c1da99
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/tests/xe_ggtt_kunit.c
> @@ -0,0 +1,341 @@
> +// 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);

Can't we use ggtt = xe_device_get_root_tile(test->priv)->mem.ggtt; ?

Thanks,
Lukasz

> +	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(void *data)
> +{
> +	struct xe_ggtt_node *node = data;
> +	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);
> +}
> +
> +/*
> + * Release the node on test exit, before the GGTT is torn down, so that an
> + * aborted test does not leave it in the drm_mm.
> + */
> +static struct xe_ggtt_node *ggtt_test_track_node(struct kunit *test,
> +						 struct xe_ggtt_node *node)
> +{
> +	if (!IS_ERR_OR_NULL(node) &&
> +	    kunit_add_action_or_reset(test, ggtt_test_remove_node, node))
> +		return ERR_PTR(-ENOMEM);
> +
> +	return node;
> +}
> +
> +static struct xe_ggtt_node *ggtt_test_insert_node(struct kunit *test,
> +						  struct xe_ggtt *ggtt, u32 size)
> +{
> +	return ggtt_test_track_node(test, xe_ggtt_insert_node(ggtt, size, XE_PAGE_SIZE));
> +}
> +
> +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 = ggtt_test_insert_node(test, ggtt, 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);
> +}
> +
> +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 = ggtt_test_insert_node(test, ggtt, usable + 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 struct xe_ggtt_node *ggtt_test_insert_node_shareable(struct kunit *test,
> +							    struct xe_ggtt *ggtt, u32 size)
> +{
> +	return ggtt_test_track_node(test,
> +				    xe_ggtt_insert_node_shareable(ggtt, size, XE_PAGE_SIZE));
> +}
> +
> +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_offset(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_offset(ggtt), accessible - shareable);
> +	KUNIT_EXPECT_EQ(test, ggtt->shareable_size, shareable);
> +	KUNIT_EXPECT_LT(test, ggtt_shareable_offset(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 = ggtt_test_insert_node(test, ggtt, 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);
> +}
> +
> +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 = ggtt_test_insert_node_shareable(test, ggtt, 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);
> +}
> +
> +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 = ggtt_test_insert_node(test, ggtt, XE_PAGE_SIZE);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
> +	shareable_node = ggtt_test_insert_node_shareable(test, ggtt, 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);
> +}
> +
> +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 = ggtt_test_insert_node(test, ggtt, usable);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, usable_node);
> +	shareable_node = ggtt_test_insert_node_shareable(test, ggtt, shareable);
> +	KUNIT_ASSERT_TRUE(test, IS_ERR(shareable_node));
> +	KUNIT_EXPECT_EQ(test, PTR_ERR(shareable_node), -ENOSPC);
> +}
> +
> +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 = ggtt_test_insert_node_shareable(test, ggtt, shareable);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, shareable_node);
> +	usable_node = ggtt_test_insert_node(test, ggtt, usable);
> +	KUNIT_ASSERT_TRUE(test, IS_ERR(usable_node));
> +	KUNIT_EXPECT_EQ(test, PTR_ERR(usable_node), -ENOSPC);
> +}
> +
> +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 = ggtt_test_insert_node_shareable(test, ggtt, 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 = ggtt_test_insert_node_shareable(test, ggtt, shareable + 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 b7e3d626e8cb8..3dd029bc76dfc 100644
> --- a/drivers/gpu/drm/xe/xe_ggtt.c
> +++ b/drivers/gpu/drm/xe/xe_ggtt.c
> @@ -1395,3 +1395,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

  parent reply	other threads:[~2026-11-10 15:32 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-21  8:57 [PATCH v7 0/5] Separate GGTT pools for submissions and VFs provisioning Piórkowski, Piotr
2026-10-21  8:57 ` [PATCH v7 1/5] drm/xe/ggtt: Assert lower bound of GGTT PTE address Piórkowski, Piotr
2026-10-28 15:50   ` Lis, Tomasz
2026-10-21  8:57 ` [PATCH v7 2/5] drm/xe/ggtt: Introduce full GGTT range size Piórkowski, Piotr
2026-10-28 15:56   ` Lis, Tomasz
2026-10-21  8:57 ` [PATCH v7 3/5] drm/xe/ggtt: Split GGTT into usable and shareable pools Piórkowski, Piotr
2026-10-28 23:59   ` Lis, Tomasz
2026-10-21  8:57 ` [PATCH v7 4/5] drm/xe/ggtt: Initialize GGTT pools by SR-IOV mode Piórkowski, Piotr
2026-10-28 15:23   ` Lis, Tomasz
2026-10-21  8:57 ` [PATCH v7 5/5] drm/xe/ggtt: Add KUnit tests for usable and shareable pools Piórkowski, Piotr
2026-10-27 16:31   ` Jani Nikula
2026-10-29 12:12     ` Piotr Piórkowski
2026-11-09  8:54       ` Piotr Piórkowski
2026-11-10 15:31   ` Laguna, Lukasz [this message]
2026-11-12 11:00     ` [v7,5/5] " Piotr Piórkowski
2026-10-21  9:04 ` ✗ CI.checkpatch: warning for Separate GGTT pools for submissions and VFs provisioning (rev7) Patchwork
2026-10-21  9:06 ` ✓ CI.KUnit: success " Patchwork
2026-10-21  9:44 ` ✓ Xe.CI.BAT: " Patchwork
2026-10-21 12:03 ` ✗ 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=cfb7a910-823d-416d-beab-7a6e3077788f@intel.com \
    --to=lukasz.laguna@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