blob: 5a42bd675c2a79d1806685ff4fea65140421a919 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
*
* (C) COPYRIGHT 2022 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
*/
#include <linux/module.h>
#include "mali_kbase.h"
#include <kutf/kutf_suite.h>
#include <kutf/kutf_utils.h>
#include <kutf/kutf_helpers.h>
#include <kutf/kutf_helpers_user.h>
#define MINOR_FOR_FIRST_KBASE_DEV (-1)
#define BASE_MEM_GROUP_COUNT (16)
#define PA_MAX ((1ULL << 48) - 1)
#define PA_START_BIT 12
#define ENTRY_ACCESS_BIT (1ULL << 10)
#define ENTRY_IS_ATE_L3 3ULL
#define ENTRY_IS_ATE_L02 1ULL
#define MGM_INTEGRATION_SUITE_NAME "mgm_integration"
#define MGM_INTEGRATION_PTE_TRANSLATION "pte_translation"
static char msg_buf[KUTF_MAX_LINE_LENGTH];
/* KUTF test application pointer for this test */
struct kutf_application *mgm_app;
/**
* struct kutf_mgm_fixture_data - test fixture used by test functions
* @kbdev: kbase device for the GPU.
* @group_id: Memory group ID to test based on fixture index.
*/
struct kutf_mgm_fixture_data {
struct kbase_device *kbdev;
int group_id;
};
/**
* mali_kutf_mgm_pte_translation_test() - Tests forward and reverse translation
* of PTE by the MGM module
* @context: KUTF context within which to perform the test.
*
* This test creates PTEs with physical addresses in the range
* 0x0000-0xFFFFFFFFF000 and tests that mgm_update_gpu_pte() returns a different
* PTE and mgm_pte_to_original_pte() returns the original PTE. This is tested
* at MMU level 2 and 3 as mgm_update_gpu_pte() is called for ATEs only.
*
* This test is run for a specific group_id depending on the fixture_id.
*/
static void mali_kutf_mgm_pte_translation_test(struct kutf_context *context)
{
struct kutf_mgm_fixture_data *data = context->fixture;
struct kbase_device *kbdev = data->kbdev;
struct memory_group_manager_device *mgm_dev = kbdev->mgm_dev;
u64 addr;
for (addr = 1 << (PA_START_BIT - 1); addr <= PA_MAX; addr <<= 1) {
/* Mask 1 << 11 by ~0xFFF to get 0x0000 at first iteration */
phys_addr_t pa = addr;
u8 mmu_level;
/* Test MMU level 3 and 2 (2MB pages) only */
for (mmu_level = MIDGARD_MMU_LEVEL(2); mmu_level <= MIDGARD_MMU_LEVEL(3);
mmu_level++) {
u64 translated_pte;
u64 returned_pte;
u64 original_pte;
if (mmu_level == MIDGARD_MMU_LEVEL(3))
original_pte =
(pa & PAGE_MASK) | ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L3;
else
original_pte =
(pa & PAGE_MASK) | ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L02;
dev_dbg(kbdev->dev, "Testing group_id=%u, mmu_level=%u, pte=0x%llx\n",
data->group_id, mmu_level, original_pte);
translated_pte = mgm_dev->ops.mgm_update_gpu_pte(mgm_dev, data->group_id,
mmu_level, original_pte);
if (translated_pte == original_pte) {
snprintf(
msg_buf, sizeof(msg_buf),
"PTE unchanged. translated_pte (0x%llx) == original_pte (0x%llx) for mmu_level=%u, group_id=%d",
translated_pte, original_pte, mmu_level, data->group_id);
kutf_test_fail(context, msg_buf);
return;
}
returned_pte = mgm_dev->ops.mgm_pte_to_original_pte(
mgm_dev, data->group_id, mmu_level, translated_pte);
dev_dbg(kbdev->dev, "\treturned_pte=%llx\n", returned_pte);
if (returned_pte != original_pte) {
snprintf(
msg_buf, sizeof(msg_buf),
"Original PTE not returned. returned_pte (0x%llx) != origin al_pte (0x%llx) for mmu_level=%u, group_id=%d",
returned_pte, original_pte, mmu_level, data->group_id);
kutf_test_fail(context, msg_buf);
return;
}
}
}
snprintf(msg_buf, sizeof(msg_buf), "Translation passed for group_id=%d", data->group_id);
kutf_test_pass(context, msg_buf);
}
/**
* mali_kutf_mgm_integration_create_fixture() - Creates the fixture data
* required for all tests in the mgm integration suite.
* @context: KUTF context.
*
* Return: Fixture data created on success or NULL on failure
*/
static void *mali_kutf_mgm_integration_create_fixture(struct kutf_context *context)
{
struct kutf_mgm_fixture_data *data;
struct kbase_device *kbdev;
pr_debug("Finding kbase device\n");
kbdev = kbase_find_device(MINOR_FOR_FIRST_KBASE_DEV);
if (kbdev == NULL) {
kutf_test_fail(context, "Failed to find kbase device");
return NULL;
}
pr_debug("Creating fixture\n");
data = kutf_mempool_alloc(&context->fixture_pool, sizeof(struct kutf_mgm_fixture_data));
if (!data)
return NULL;
data->kbdev = kbdev;
data->group_id = context->fixture_index;
pr_debug("Fixture created\n");
return data;
}
/**
* mali_kutf_mgm_integration_remove_fixture() - Destroy fixture data previously
* created by mali_kutf_mgm_integration_create_fixture.
* @context: KUTF context.
*/
static void mali_kutf_mgm_integration_remove_fixture(struct kutf_context *context)
{
struct kutf_mgm_fixture_data *data = context->fixture;
struct kbase_device *kbdev = data->kbdev;
kbase_release_device(kbdev);
}
/**
* mali_kutf_mgm_integration_test_main_init() - Module entry point for this test.
*
* Return: 0 on success, error code on failure.
*/
static int __init mali_kutf_mgm_integration_test_main_init(void)
{
struct kutf_suite *suite;
mgm_app = kutf_create_application("mgm");
if (mgm_app == NULL) {
pr_warn("Creation of mgm KUTF app failed!\n");
return -ENOMEM;
}
suite = kutf_create_suite(mgm_app, MGM_INTEGRATION_SUITE_NAME, BASE_MEM_GROUP_COUNT,
mali_kutf_mgm_integration_create_fixture,
mali_kutf_mgm_integration_remove_fixture);
if (suite == NULL) {
pr_warn("Creation of %s suite failed!\n", MGM_INTEGRATION_SUITE_NAME);
kutf_destroy_application(mgm_app);
return -ENOMEM;
}
kutf_add_test(suite, 0x0, MGM_INTEGRATION_PTE_TRANSLATION,
mali_kutf_mgm_pte_translation_test);
return 0;
}
/**
* mali_kutf_mgm_integration_test_main_exit() - Module exit point for this test.
*/
static void __exit mali_kutf_mgm_integration_test_main_exit(void)
{
kutf_destroy_application(mgm_app);
}
module_init(mali_kutf_mgm_integration_test_main_init);
module_exit(mali_kutf_mgm_integration_test_main_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARM Ltd.");
MODULE_VERSION("1.0");