hc
2024-03-25 edb30157bad0c0001c32b854271ace01d3b9a16a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// 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");