1 /*
2 *
3 * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved.
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * A copy of the licence is included with the program, and can also be obtained
11 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12 * Boston, MA 02110-1301, USA.
13 *
14 */
15
16
17
18 #include "mali_kbase.h"
19 #include "mali_kbase_hw.h"
20 #include "mali_kbase_mem_linux.h"
21 #include "mali_kbase_gator_api.h"
22 #include "mali_kbase_gator_hwcnt_names.h"
23
24 #define MALI_MAX_CORES_PER_GROUP 4
25 #define MALI_MAX_NUM_BLOCKS_PER_GROUP 8
26 #define MALI_COUNTERS_PER_BLOCK 64
27 #define MALI_BYTES_PER_COUNTER 4
28
29 struct kbase_gator_hwcnt_handles {
30 struct kbase_device *kbdev;
31 struct kbase_vinstr_client *vinstr_cli;
32 void *vinstr_buffer;
33 struct work_struct dump_work;
34 int dump_complete;
35 spinlock_t dump_lock;
36 };
37
38 static void dump_worker(struct work_struct *work);
39
kbase_gator_hwcnt_init_names(uint32_t * total_counters)40 const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters)
41 {
42 const char * const *hardware_counters;
43 struct kbase_device *kbdev;
44 uint32_t product_id;
45 uint32_t count;
46
47 if (!total_counters)
48 return NULL;
49
50 /* Get the first device - it doesn't matter in this case */
51 kbdev = kbase_find_device(-1);
52 if (!kbdev)
53 return NULL;
54
55 product_id = kbdev->gpu_props.props.core_props.product_id;
56
57 if (GPU_ID_IS_NEW_FORMAT(product_id)) {
58 switch (GPU_ID2_MODEL_MATCH_VALUE(product_id)) {
59 case GPU_ID2_PRODUCT_TMIX:
60 hardware_counters = hardware_counters_mali_tMIx;
61 count = ARRAY_SIZE(hardware_counters_mali_tMIx);
62 break;
63 case GPU_ID2_PRODUCT_THEX:
64 hardware_counters = hardware_counters_mali_tHEx;
65 count = ARRAY_SIZE(hardware_counters_mali_tHEx);
66 break;
67 case GPU_ID2_PRODUCT_TSIX:
68 hardware_counters = hardware_counters_mali_tSIx;
69 count = ARRAY_SIZE(hardware_counters_mali_tSIx);
70 break;
71 default:
72 hardware_counters = NULL;
73 count = 0;
74 dev_err(kbdev->dev, "Unrecognized product ID: %u\n",
75 product_id);
76 break;
77 }
78 } else {
79 switch (product_id) {
80 /* If we are using a Mali-T60x device */
81 case GPU_ID_PI_T60X:
82 hardware_counters = hardware_counters_mali_t60x;
83 count = ARRAY_SIZE(hardware_counters_mali_t60x);
84 break;
85 /* If we are using a Mali-T62x device */
86 case GPU_ID_PI_T62X:
87 hardware_counters = hardware_counters_mali_t62x;
88 count = ARRAY_SIZE(hardware_counters_mali_t62x);
89 break;
90 /* If we are using a Mali-T72x device */
91 case GPU_ID_PI_T72X:
92 hardware_counters = hardware_counters_mali_t72x;
93 count = ARRAY_SIZE(hardware_counters_mali_t72x);
94 break;
95 /* If we are using a Mali-T76x device */
96 case GPU_ID_PI_T76X:
97 hardware_counters = hardware_counters_mali_t76x;
98 count = ARRAY_SIZE(hardware_counters_mali_t76x);
99 break;
100 /* If we are using a Mali-T82x device */
101 case GPU_ID_PI_T82X:
102 hardware_counters = hardware_counters_mali_t82x;
103 count = ARRAY_SIZE(hardware_counters_mali_t82x);
104 break;
105 /* If we are using a Mali-T83x device */
106 case GPU_ID_PI_T83X:
107 hardware_counters = hardware_counters_mali_t83x;
108 count = ARRAY_SIZE(hardware_counters_mali_t83x);
109 break;
110 /* If we are using a Mali-T86x device */
111 case GPU_ID_PI_T86X:
112 hardware_counters = hardware_counters_mali_t86x;
113 count = ARRAY_SIZE(hardware_counters_mali_t86x);
114 break;
115 /* If we are using a Mali-T88x device */
116 case GPU_ID_PI_TFRX:
117 hardware_counters = hardware_counters_mali_t88x;
118 count = ARRAY_SIZE(hardware_counters_mali_t88x);
119 break;
120 default:
121 hardware_counters = NULL;
122 count = 0;
123 dev_err(kbdev->dev, "Unrecognized product ID: %u\n",
124 product_id);
125 break;
126 }
127 }
128
129 /* Release the kbdev reference. */
130 kbase_release_device(kbdev);
131
132 *total_counters = count;
133
134 /* If we return a string array take a reference on the module (or fail). */
135 if (hardware_counters && !try_module_get(THIS_MODULE))
136 return NULL;
137
138 return hardware_counters;
139 }
140 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init_names);
141
kbase_gator_hwcnt_term_names(void)142 void kbase_gator_hwcnt_term_names(void)
143 {
144 /* Release the module reference. */
145 module_put(THIS_MODULE);
146 }
147 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names);
148
kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info * in_out_info)149 struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info)
150 {
151 struct kbase_gator_hwcnt_handles *hand;
152 struct kbase_uk_hwcnt_reader_setup setup;
153 uint32_t dump_size = 0, i = 0;
154
155 if (!in_out_info)
156 return NULL;
157
158 hand = kzalloc(sizeof(*hand), GFP_KERNEL);
159 if (!hand)
160 return NULL;
161
162 INIT_WORK(&hand->dump_work, dump_worker);
163 spin_lock_init(&hand->dump_lock);
164
165 /* Get the first device */
166 hand->kbdev = kbase_find_device(-1);
167 if (!hand->kbdev)
168 goto free_hand;
169
170 dump_size = kbase_vinstr_dump_size(hand->kbdev);
171 hand->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL);
172 if (!hand->vinstr_buffer)
173 goto release_device;
174 in_out_info->kernel_dump_buffer = hand->vinstr_buffer;
175
176 in_out_info->nr_cores = hand->kbdev->gpu_props.num_cores;
177 in_out_info->nr_core_groups = hand->kbdev->gpu_props.num_core_groups;
178 in_out_info->gpu_id = hand->kbdev->gpu_props.props.core_props.product_id;
179
180 /* If we are using a v4 device (Mali-T6xx or Mali-T72x) */
181 if (kbase_hw_has_feature(hand->kbdev, BASE_HW_FEATURE_V4)) {
182 uint32_t cg, j;
183 uint64_t core_mask;
184
185 /* There are 8 hardware counters blocks per core group */
186 in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) *
187 MALI_MAX_NUM_BLOCKS_PER_GROUP *
188 in_out_info->nr_core_groups, GFP_KERNEL);
189
190 if (!in_out_info->hwc_layout)
191 goto free_vinstr_buffer;
192
193 dump_size = in_out_info->nr_core_groups *
194 MALI_MAX_NUM_BLOCKS_PER_GROUP *
195 MALI_COUNTERS_PER_BLOCK *
196 MALI_BYTES_PER_COUNTER;
197
198 for (cg = 0; cg < in_out_info->nr_core_groups; cg++) {
199 core_mask = hand->kbdev->gpu_props.props.coherency_info.group[cg].core_mask;
200
201 for (j = 0; j < MALI_MAX_CORES_PER_GROUP; j++) {
202 if (core_mask & (1u << j))
203 in_out_info->hwc_layout[i++] = SHADER_BLOCK;
204 else
205 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
206 }
207
208 in_out_info->hwc_layout[i++] = TILER_BLOCK;
209 in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
210
211 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
212
213 if (0 == cg)
214 in_out_info->hwc_layout[i++] = JM_BLOCK;
215 else
216 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
217 }
218 /* If we are using any other device */
219 } else {
220 uint32_t nr_l2, nr_sc_bits, j;
221 uint64_t core_mask;
222
223 nr_l2 = hand->kbdev->gpu_props.props.l2_props.num_l2_slices;
224
225 core_mask = hand->kbdev->gpu_props.props.coherency_info.group[0].core_mask;
226
227 nr_sc_bits = fls64(core_mask);
228
229 /* The job manager and tiler sets of counters
230 * are always present */
231 in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * (2 + nr_sc_bits + nr_l2), GFP_KERNEL);
232
233 if (!in_out_info->hwc_layout)
234 goto free_vinstr_buffer;
235
236 dump_size = (2 + nr_sc_bits + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER;
237
238 in_out_info->hwc_layout[i++] = JM_BLOCK;
239 in_out_info->hwc_layout[i++] = TILER_BLOCK;
240
241 for (j = 0; j < nr_l2; j++)
242 in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
243
244 while (core_mask != 0ull) {
245 if ((core_mask & 1ull) != 0ull)
246 in_out_info->hwc_layout[i++] = SHADER_BLOCK;
247 else
248 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
249 core_mask >>= 1;
250 }
251 }
252
253 in_out_info->nr_hwc_blocks = i;
254 in_out_info->size = dump_size;
255
256 setup.jm_bm = in_out_info->bitmask[0];
257 setup.tiler_bm = in_out_info->bitmask[1];
258 setup.shader_bm = in_out_info->bitmask[2];
259 setup.mmu_l2_bm = in_out_info->bitmask[3];
260 hand->vinstr_cli = kbase_vinstr_hwcnt_kernel_setup(hand->kbdev->vinstr_ctx,
261 &setup, hand->vinstr_buffer);
262 if (!hand->vinstr_cli) {
263 dev_err(hand->kbdev->dev, "Failed to register gator with vinstr core");
264 goto free_layout;
265 }
266
267 return hand;
268
269 free_layout:
270 kfree(in_out_info->hwc_layout);
271
272 free_vinstr_buffer:
273 kfree(hand->vinstr_buffer);
274
275 release_device:
276 kbase_release_device(hand->kbdev);
277
278 free_hand:
279 kfree(hand);
280 return NULL;
281 }
282 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init);
283
kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info * in_out_info,struct kbase_gator_hwcnt_handles * opaque_handles)284 void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles)
285 {
286 if (in_out_info)
287 kfree(in_out_info->hwc_layout);
288
289 if (opaque_handles) {
290 cancel_work_sync(&opaque_handles->dump_work);
291 kbase_vinstr_detach_client(opaque_handles->vinstr_cli);
292 kfree(opaque_handles->vinstr_buffer);
293 kbase_release_device(opaque_handles->kbdev);
294 kfree(opaque_handles);
295 }
296 }
297 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term);
298
dump_worker(struct work_struct * work)299 static void dump_worker(struct work_struct *work)
300 {
301 struct kbase_gator_hwcnt_handles *hand;
302
303 hand = container_of(work, struct kbase_gator_hwcnt_handles, dump_work);
304 if (!kbase_vinstr_hwc_dump(hand->vinstr_cli,
305 BASE_HWCNT_READER_EVENT_MANUAL)) {
306 spin_lock_bh(&hand->dump_lock);
307 hand->dump_complete = 1;
308 spin_unlock_bh(&hand->dump_lock);
309 } else {
310 schedule_work(&hand->dump_work);
311 }
312 }
313
kbase_gator_instr_hwcnt_dump_complete(struct kbase_gator_hwcnt_handles * opaque_handles,uint32_t * const success)314 uint32_t kbase_gator_instr_hwcnt_dump_complete(
315 struct kbase_gator_hwcnt_handles *opaque_handles,
316 uint32_t * const success)
317 {
318
319 if (opaque_handles && success) {
320 *success = opaque_handles->dump_complete;
321 opaque_handles->dump_complete = 0;
322 return *success;
323 }
324 return 0;
325 }
326 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete);
327
kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles * opaque_handles)328 uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles)
329 {
330 if (opaque_handles)
331 schedule_work(&opaque_handles->dump_work);
332 return 0;
333 }
334 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq);
335