4af3e4815e9532df957d49b3434d098b2a835fe4
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / midgard / mali_kbase_gator_api.c
1 /*
2  *
3  * (C) COPYRIGHT 2014-2016 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
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 gpu_id;
45         uint32_t product_id;
46         uint32_t count;
47
48         if (!total_counters)
49                 return NULL;
50
51         /* Get the first device - it doesn't matter in this case */
52         kbdev = kbase_find_device(-1);
53         if (!kbdev)
54                 return NULL;
55
56         gpu_id = kbdev->gpu_props.props.core_props.product_id;
57         product_id = gpu_id & GPU_ID_VERSION_PRODUCT_ID;
58         product_id >>= GPU_ID_VERSION_PRODUCT_ID_SHIFT;
59
60         if (GPU_ID_IS_NEW_FORMAT(product_id)) {
61                 switch (gpu_id & GPU_ID2_PRODUCT_MODEL) {
62                 case GPU_ID2_PRODUCT_TMIX:
63                         hardware_counters = hardware_counters_mali_tMIx;
64                         count = ARRAY_SIZE(hardware_counters_mali_tMIx);
65                         break;
66                 default:
67                         hardware_counters = NULL;
68                         count = 0;
69                         dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
70                                 gpu_id);
71                         break;
72                 }
73         } else {
74                 switch (gpu_id) {
75                         /* If we are using a Mali-T60x device */
76                 case GPU_ID_PI_T60X:
77                         hardware_counters = hardware_counters_mali_t60x;
78                         count = ARRAY_SIZE(hardware_counters_mali_t60x);
79                         break;
80                         /* If we are using a Mali-T62x device */
81                 case GPU_ID_PI_T62X:
82                         hardware_counters = hardware_counters_mali_t62x;
83                         count = ARRAY_SIZE(hardware_counters_mali_t62x);
84                         break;
85                         /* If we are using a Mali-T72x device */
86                 case GPU_ID_PI_T72X:
87                         hardware_counters = hardware_counters_mali_t72x;
88                         count = ARRAY_SIZE(hardware_counters_mali_t72x);
89                         break;
90                         /* If we are using a Mali-T76x device */
91                 case GPU_ID_PI_T76X:
92                         hardware_counters = hardware_counters_mali_t76x;
93                         count = ARRAY_SIZE(hardware_counters_mali_t76x);
94                         break;
95                         /* If we are using a Mali-T82x device */
96                 case GPU_ID_PI_T82X:
97                         hardware_counters = hardware_counters_mali_t82x;
98                         count = ARRAY_SIZE(hardware_counters_mali_t82x);
99                         break;
100                         /* If we are using a Mali-T83x device */
101                 case GPU_ID_PI_T83X:
102                         hardware_counters = hardware_counters_mali_t83x;
103                         count = ARRAY_SIZE(hardware_counters_mali_t83x);
104                         break;
105                         /* If we are using a Mali-T86x device */
106                 case GPU_ID_PI_T86X:
107                         hardware_counters = hardware_counters_mali_t86x;
108                         count = ARRAY_SIZE(hardware_counters_mali_t86x);
109                         break;
110                         /* If we are using a Mali-T88x device */
111                 case GPU_ID_PI_TFRX:
112                         hardware_counters = hardware_counters_mali_t88x;
113                         count = ARRAY_SIZE(hardware_counters_mali_t88x);
114                         break;
115                 default:
116                         hardware_counters = NULL;
117                         count = 0;
118                         dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
119                                 gpu_id);
120                         break;
121                 }
122         }
123
124         /* Release the kbdev reference. */
125         kbase_release_device(kbdev);
126
127         *total_counters = count;
128
129         /* If we return a string array take a reference on the module (or fail). */
130         if (hardware_counters && !try_module_get(THIS_MODULE))
131                 return NULL;
132
133         return hardware_counters;
134 }
135 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init_names);
136
137 void kbase_gator_hwcnt_term_names(void)
138 {
139         /* Release the module reference. */
140         module_put(THIS_MODULE);
141 }
142 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names);
143
144 struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info)
145 {
146         struct kbase_gator_hwcnt_handles *hand;
147         struct kbase_uk_hwcnt_reader_setup setup;
148         uint32_t dump_size = 0, i = 0;
149
150         if (!in_out_info)
151                 return NULL;
152
153         hand = kzalloc(sizeof(*hand), GFP_KERNEL);
154         if (!hand)
155                 return NULL;
156
157         INIT_WORK(&hand->dump_work, dump_worker);
158         spin_lock_init(&hand->dump_lock);
159
160         /* Get the first device */
161         hand->kbdev = kbase_find_device(-1);
162         if (!hand->kbdev)
163                 goto free_hand;
164
165         dump_size = kbase_vinstr_dump_size(hand->kbdev);
166         hand->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL);
167         if (!hand->vinstr_buffer)
168                 goto release_device;
169         in_out_info->kernel_dump_buffer = hand->vinstr_buffer;
170
171         in_out_info->nr_cores = hand->kbdev->gpu_props.num_cores;
172         in_out_info->nr_core_groups = hand->kbdev->gpu_props.num_core_groups;
173         in_out_info->gpu_id = hand->kbdev->gpu_props.props.core_props.product_id;
174
175         /* If we are using a v4 device (Mali-T6xx or Mali-T72x) */
176         if (kbase_hw_has_feature(hand->kbdev, BASE_HW_FEATURE_V4)) {
177                 uint32_t cg, j;
178                 uint64_t core_mask;
179
180                 /* There are 8 hardware counters blocks per core group */
181                 in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) *
182                         MALI_MAX_NUM_BLOCKS_PER_GROUP *
183                         in_out_info->nr_core_groups, GFP_KERNEL);
184
185                 if (!in_out_info->hwc_layout)
186                         goto free_vinstr_buffer;
187
188                 dump_size = in_out_info->nr_core_groups *
189                         MALI_MAX_NUM_BLOCKS_PER_GROUP *
190                         MALI_COUNTERS_PER_BLOCK *
191                         MALI_BYTES_PER_COUNTER;
192
193                 for (cg = 0; cg < in_out_info->nr_core_groups; cg++) {
194                         core_mask = hand->kbdev->gpu_props.props.coherency_info.group[cg].core_mask;
195
196                         for (j = 0; j < MALI_MAX_CORES_PER_GROUP; j++) {
197                                 if (core_mask & (1u << j))
198                                         in_out_info->hwc_layout[i++] = SHADER_BLOCK;
199                                 else
200                                         in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
201                         }
202
203                         in_out_info->hwc_layout[i++] = TILER_BLOCK;
204                         in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
205
206                         in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
207
208                         if (0 == cg)
209                                 in_out_info->hwc_layout[i++] = JM_BLOCK;
210                         else
211                                 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
212                 }
213         /* If we are using any other device */
214         } else {
215                 uint32_t nr_l2, nr_sc_bits, j;
216                 uint64_t core_mask;
217
218                 nr_l2 = hand->kbdev->gpu_props.props.l2_props.num_l2_slices;
219
220                 core_mask = hand->kbdev->gpu_props.props.coherency_info.group[0].core_mask;
221
222                 nr_sc_bits = fls64(core_mask);
223
224                 /* The job manager and tiler sets of counters
225                  * are always present */
226                 in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * (2 + nr_sc_bits + nr_l2), GFP_KERNEL);
227
228                 if (!in_out_info->hwc_layout)
229                         goto free_vinstr_buffer;
230
231                 dump_size = (2 + nr_sc_bits + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER;
232
233                 in_out_info->hwc_layout[i++] = JM_BLOCK;
234                 in_out_info->hwc_layout[i++] = TILER_BLOCK;
235
236                 for (j = 0; j < nr_l2; j++)
237                         in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
238
239                 while (core_mask != 0ull) {
240                         if ((core_mask & 1ull) != 0ull)
241                                 in_out_info->hwc_layout[i++] = SHADER_BLOCK;
242                         else
243                                 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
244                         core_mask >>= 1;
245                 }
246         }
247
248         in_out_info->nr_hwc_blocks = i;
249         in_out_info->size = dump_size;
250
251         setup.jm_bm = in_out_info->bitmask[0];
252         setup.tiler_bm = in_out_info->bitmask[1];
253         setup.shader_bm = in_out_info->bitmask[2];
254         setup.mmu_l2_bm = in_out_info->bitmask[3];
255         hand->vinstr_cli = kbase_vinstr_hwcnt_kernel_setup(hand->kbdev->vinstr_ctx,
256                         &setup, hand->vinstr_buffer);
257         if (!hand->vinstr_cli) {
258                 dev_err(hand->kbdev->dev, "Failed to register gator with vinstr core");
259                 goto free_layout;
260         }
261
262         return hand;
263
264 free_layout:
265         kfree(in_out_info->hwc_layout);
266
267 free_vinstr_buffer:
268         kfree(hand->vinstr_buffer);
269
270 release_device:
271         kbase_release_device(hand->kbdev);
272
273 free_hand:
274         kfree(hand);
275         return NULL;
276 }
277 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init);
278
279 void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles)
280 {
281         if (in_out_info)
282                 kfree(in_out_info->hwc_layout);
283
284         if (opaque_handles) {
285                 cancel_work_sync(&opaque_handles->dump_work);
286                 kbase_vinstr_detach_client(opaque_handles->vinstr_cli);
287                 kfree(opaque_handles->vinstr_buffer);
288                 kbase_release_device(opaque_handles->kbdev);
289                 kfree(opaque_handles);
290         }
291 }
292 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term);
293
294 static void dump_worker(struct work_struct *work)
295 {
296         struct kbase_gator_hwcnt_handles *hand;
297
298         hand = container_of(work, struct kbase_gator_hwcnt_handles, dump_work);
299         if (!kbase_vinstr_hwc_dump(hand->vinstr_cli,
300                         BASE_HWCNT_READER_EVENT_MANUAL)) {
301                 spin_lock_bh(&hand->dump_lock);
302                 hand->dump_complete = 1;
303                 spin_unlock_bh(&hand->dump_lock);
304         } else {
305                 schedule_work(&hand->dump_work);
306         }
307 }
308
309 uint32_t kbase_gator_instr_hwcnt_dump_complete(
310                 struct kbase_gator_hwcnt_handles *opaque_handles,
311                 uint32_t * const success)
312 {
313
314         if (opaque_handles && success) {
315                 *success = opaque_handles->dump_complete;
316                 opaque_handles->dump_complete = 0;
317                 return *success;
318         }
319         return 0;
320 }
321 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete);
322
323 uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles)
324 {
325         if (opaque_handles)
326                 schedule_work(&opaque_handles->dump_work);
327         return 0;
328 }
329 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq);