1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2014-2015, 2018-2023 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <mali_kbase.h>
23 #include <linux/random.h>
24 #include "backend/gpu/mali_kbase_model_linux.h"
25
26 static struct kbase_error_atom *error_track_list;
27
28 #ifdef CONFIG_MALI_ERROR_INJECT_RANDOM
29
30 /** Kernel 6.1.0 has dropped prandom_u32(), use get_random_u32() */
31 #if (KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE)
32 #define prandom_u32 get_random_u32
33 #endif
34
35 /*following error probability are set quite high in order to stress the driver*/
36 static unsigned int error_probability = 50; /* to be set between 0 and 100 */
37 /* probability to have multiple error give that there is an error */
38 static unsigned int multiple_error_probability = 50;
39
40 /* all the error conditions supported by the model */
41 #define TOTAL_FAULTS 27
42 /* maximum number of levels in the MMU translation table tree */
43 #define MAX_MMU_TABLE_LEVEL 4
44 /* worst case scenario is <1 MMU fault + 1 job fault + 2 GPU faults> */
45 #define MAX_CONCURRENT_FAULTS 3
46
47 /**
48 * gpu_generate_error - Generate GPU error
49 */
gpu_generate_error(void)50 static void gpu_generate_error(void)
51 {
52 unsigned int errors_num = 0;
53
54 /*is there at least one error? */
55 if ((prandom_u32() % 100) < error_probability) {
56 /* pick up a faulty mmu address space */
57 hw_error_status.faulty_mmu_as = prandom_u32() % NUM_MMU_AS;
58 /* pick up an mmu table level */
59 hw_error_status.mmu_table_level =
60 1 + (prandom_u32() % MAX_MMU_TABLE_LEVEL);
61 hw_error_status.errors_mask =
62 (u32)(1 << (prandom_u32() % TOTAL_FAULTS));
63
64 /*is there also one or more errors? */
65 if ((prandom_u32() % 100) < multiple_error_probability) {
66 errors_num = 1 + (prandom_u32() %
67 (MAX_CONCURRENT_FAULTS - 1));
68 while (errors_num-- > 0) {
69 u32 temp_mask;
70
71 temp_mask = (u32)(
72 1 << (prandom_u32() % TOTAL_FAULTS));
73 /* below we check that no bit of the same error
74 * type is set again in the error mask
75 */
76 if ((temp_mask & IS_A_JOB_ERROR) &&
77 (hw_error_status.errors_mask &
78 IS_A_JOB_ERROR)) {
79 errors_num++;
80 continue;
81 }
82 if ((temp_mask & IS_A_MMU_ERROR) &&
83 (hw_error_status.errors_mask &
84 IS_A_MMU_ERROR)) {
85 errors_num++;
86 continue;
87 }
88 if ((temp_mask & IS_A_GPU_ERROR) &&
89 (hw_error_status.errors_mask &
90 IS_A_GPU_ERROR)) {
91 errors_num++;
92 continue;
93 }
94 /* this error mask is already set */
95 if ((hw_error_status.errors_mask | temp_mask) ==
96 hw_error_status.errors_mask) {
97 errors_num++;
98 continue;
99 }
100 hw_error_status.errors_mask |= temp_mask;
101 }
102 }
103 }
104 }
105 #endif
106
job_atom_inject_error(struct kbase_error_params * params)107 int job_atom_inject_error(struct kbase_error_params *params)
108 {
109 struct kbase_error_atom *new_elem;
110
111 KBASE_DEBUG_ASSERT(params);
112
113 new_elem = kzalloc(sizeof(*new_elem), GFP_KERNEL);
114
115 if (!new_elem) {
116 model_error_log(KBASE_CORE,
117 "\njob_atom_inject_error: kzalloc failed for new_elem\n"
118 );
119 return -ENOMEM;
120 }
121 new_elem->params.jc = params->jc;
122 new_elem->params.errors_mask = params->errors_mask;
123 new_elem->params.mmu_table_level = params->mmu_table_level;
124 new_elem->params.faulty_mmu_as = params->faulty_mmu_as;
125
126 /*circular list below */
127 if (error_track_list == NULL) { /*no elements */
128 error_track_list = new_elem;
129 new_elem->next = error_track_list;
130 } else {
131 struct kbase_error_atom *walker = error_track_list;
132
133 while (walker->next != error_track_list)
134 walker = walker->next;
135
136 new_elem->next = error_track_list;
137 walker->next = new_elem;
138 }
139 return 0;
140 }
141
midgard_set_error(int job_slot)142 void midgard_set_error(int job_slot)
143 {
144 #ifdef CONFIG_MALI_ERROR_INJECT_RANDOM
145 gpu_generate_error();
146 #else
147 struct kbase_error_atom *walker, *auxiliar;
148
149 if (error_track_list != NULL) {
150 walker = error_track_list->next;
151 auxiliar = error_track_list;
152 do {
153 if (walker->params.jc == hw_error_status.current_jc) {
154 /* found a faulty atom matching with the
155 * current one
156 */
157 hw_error_status.errors_mask =
158 walker->params.errors_mask;
159 hw_error_status.mmu_table_level =
160 walker->params.mmu_table_level;
161 hw_error_status.faulty_mmu_as =
162 walker->params.faulty_mmu_as;
163 hw_error_status.current_job_slot = job_slot;
164
165 if (walker->next == walker) {
166 /* only one element */
167 kfree(error_track_list);
168 error_track_list = NULL;
169 } else {
170 auxiliar->next = walker->next;
171 if (walker == error_track_list)
172 error_track_list = walker->next;
173
174 kfree(walker);
175 }
176 break;
177 }
178 auxiliar = walker;
179 walker = walker->next;
180 } while (auxiliar->next != error_track_list);
181 }
182 #endif /* CONFIG_MALI_ERROR_INJECT_RANDOM */
183 }
184