// SPDX-License-Identifier: GPL-2.0 AND MIT /* * Copyright © 2023 Intel Corporation */ #include #include "ttm_kunit_helpers.h" #define RES_SIZE SZ_4K #define TTM_PRIV_DUMMY_REG (TTM_NUM_MEM_TYPES - 1) struct ttm_resource_test_case { const char *description; uint32_t mem_type; uint32_t flags; }; struct ttm_resource_test_priv { struct ttm_test_devices *devs; struct ttm_buffer_object *bo; struct ttm_place *place; }; static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { }; static int ttm_resource_test_init(struct kunit *test) { struct ttm_resource_test_priv *priv; priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, priv); priv->devs = ttm_test_devices_all(test); KUNIT_ASSERT_NOT_NULL(test, priv->devs); test->priv = priv; return 0; } static void ttm_resource_test_fini(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; ttm_test_devices_put(test, priv->devs); } static void ttm_init_test_mocks(struct kunit *test, struct ttm_resource_test_priv *priv, uint32_t mem_type, uint32_t flags) { size_t size = RES_SIZE; /* Make sure we have what we need for a good BO mock */ KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev); priv->bo = ttm_bo_kunit_init(test, priv->devs, size); priv->place = ttm_place_kunit_init(test, mem_type, flags); } static void ttm_init_test_manager(struct kunit *test, struct ttm_resource_test_priv *priv, uint32_t mem_type) { struct ttm_device *ttm_dev = priv->devs->ttm_dev; struct ttm_resource_manager *man; size_t size = SZ_16K; man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, man); man->use_tt = false; man->func = &ttm_resource_manager_mock_funcs; ttm_resource_manager_init(man, ttm_dev, size); ttm_set_driver_manager(ttm_dev, mem_type, man); ttm_resource_manager_set_used(man, true); } static const struct ttm_resource_test_case ttm_resource_cases[] = { { .description = "Init resource in TTM_PL_SYSTEM", .mem_type = TTM_PL_SYSTEM, }, { .description = "Init resource in TTM_PL_VRAM", .mem_type = TTM_PL_VRAM, }, { .description = "Init resource in a private placement", .mem_type = TTM_PRIV_DUMMY_REG, }, { .description = "Init resource in TTM_PL_SYSTEM, set placement flags", .mem_type = TTM_PL_SYSTEM, .flags = TTM_PL_FLAG_TOPDOWN, }, }; static void ttm_resource_case_desc(const struct ttm_resource_test_case *t, char *desc) { strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc); static void ttm_resource_init_basic(struct kunit *test) { const struct ttm_resource_test_case *params = test->param_value; struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource *res; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource_manager *man; uint64_t expected_usage; ttm_init_test_mocks(test, priv, params->mem_type, params->flags); bo = priv->bo; place = priv->place; if (params->mem_type > TTM_PL_SYSTEM) ttm_init_test_manager(test, priv, params->mem_type); res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, res); man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); expected_usage = man->usage + RES_SIZE; KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); ttm_resource_init(bo, place, res); KUNIT_ASSERT_EQ(test, res->start, 0); KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); KUNIT_ASSERT_EQ(test, res->mem_type, place->mem_type); KUNIT_ASSERT_EQ(test, res->placement, place->flags); KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); KUNIT_ASSERT_NULL(test, res->bus.addr); KUNIT_ASSERT_EQ(test, res->bus.offset, 0); KUNIT_ASSERT_FALSE(test, res->bus.is_iomem); KUNIT_ASSERT_EQ(test, res->bus.caching, ttm_cached); KUNIT_ASSERT_EQ(test, man->usage, expected_usage); KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority])); ttm_resource_fini(man, res); } static void ttm_resource_init_pinned(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource *res; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource_manager *man; ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); bo = priv->bo; place = priv->place; man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, res); KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); dma_resv_lock(bo->base.resv, NULL); ttm_bo_pin(bo); ttm_resource_init(bo, place, res); KUNIT_ASSERT_TRUE(test, list_is_singular(&bo->bdev->pinned)); ttm_bo_unpin(bo); ttm_resource_fini(man, res); dma_resv_unlock(bo->base.resv); KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); } static void ttm_resource_fini_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource *res; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource_manager *man; ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); bo = priv->bo; place = priv->place; man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, res); ttm_resource_init(bo, place, res); ttm_resource_fini(man, res); KUNIT_ASSERT_TRUE(test, list_empty(&res->lru)); KUNIT_ASSERT_EQ(test, man->usage, 0); } static void ttm_resource_manager_init_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource_manager *man; size_t size = SZ_16K; man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, man); ttm_resource_manager_init(man, priv->devs->ttm_dev, size); KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev); KUNIT_ASSERT_EQ(test, man->size, size); KUNIT_ASSERT_EQ(test, man->usage, 0); KUNIT_ASSERT_NULL(test, man->move); KUNIT_ASSERT_NOT_NULL(test, &man->move_lock); for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i) KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i])); } static void ttm_resource_manager_usage_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource *res; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource_manager *man; uint64_t actual_usage; ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN); bo = priv->bo; place = priv->place; res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, res); man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); ttm_resource_init(bo, place, res); actual_usage = ttm_resource_manager_usage(man); KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE); ttm_resource_fini(man, res); } static void ttm_resource_manager_set_used_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource_manager *man; man = ttm_manager_type(priv->devs->ttm_dev, TTM_PL_SYSTEM); KUNIT_ASSERT_TRUE(test, man->use_type); ttm_resource_manager_set_used(man, false); KUNIT_ASSERT_FALSE(test, man->use_type); } static void ttm_sys_man_alloc_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource_manager *man; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource *res; uint32_t mem_type = TTM_PL_SYSTEM; int ret; ttm_init_test_mocks(test, priv, mem_type, 0); bo = priv->bo; place = priv->place; man = ttm_manager_type(priv->devs->ttm_dev, mem_type); ret = man->func->alloc(man, bo, place, &res); KUNIT_ASSERT_EQ(test, ret, 0); KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); KUNIT_ASSERT_EQ(test, res->mem_type, mem_type); KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); ttm_resource_fini(man, res); } static void ttm_sys_man_free_basic(struct kunit *test) { struct ttm_resource_test_priv *priv = test->priv; struct ttm_resource_manager *man; struct ttm_buffer_object *bo; struct ttm_place *place; struct ttm_resource *res; uint32_t mem_type = TTM_PL_SYSTEM; ttm_init_test_mocks(test, priv, mem_type, 0); bo = priv->bo; place = priv->place; res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, res); ttm_resource_alloc(bo, place, &res); man = ttm_manager_type(priv->devs->ttm_dev, mem_type); man->func->free(man, res); KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); KUNIT_ASSERT_EQ(test, man->usage, 0); } static struct kunit_case ttm_resource_test_cases[] = { KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params), KUNIT_CASE(ttm_resource_init_pinned), KUNIT_CASE(ttm_resource_fini_basic), KUNIT_CASE(ttm_resource_manager_init_basic), KUNIT_CASE(ttm_resource_manager_usage_basic), KUNIT_CASE(ttm_resource_manager_set_used_basic), KUNIT_CASE(ttm_sys_man_alloc_basic), KUNIT_CASE(ttm_sys_man_free_basic), {} }; static struct kunit_suite ttm_resource_test_suite = { .name = "ttm_resource", .init = ttm_resource_test_init, .exit = ttm_resource_test_fini, .test_cases = ttm_resource_test_cases, }; kunit_test_suites(&ttm_resource_test_suite); MODULE_LICENSE("GPL");