3 * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
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
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.
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"
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
29 struct kbase_gator_hwcnt_handles {
30 struct kbase_device *kbdev;
31 struct kbase_vinstr_client *vinstr_cli;
33 struct work_struct dump_work;
38 static void dump_worker(struct work_struct *work);
40 const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters)
42 const char * const *hardware_counters;
43 struct kbase_device *kbdev;
51 /* Get the first device - it doesn't matter in this case */
52 kbdev = kbase_find_device(-1);
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;
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);
67 hardware_counters = NULL;
69 dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
75 /* If we are using a Mali-T60x device */
77 hardware_counters = hardware_counters_mali_t60x;
78 count = ARRAY_SIZE(hardware_counters_mali_t60x);
80 /* If we are using a Mali-T62x device */
82 hardware_counters = hardware_counters_mali_t62x;
83 count = ARRAY_SIZE(hardware_counters_mali_t62x);
85 /* If we are using a Mali-T72x device */
87 hardware_counters = hardware_counters_mali_t72x;
88 count = ARRAY_SIZE(hardware_counters_mali_t72x);
90 /* If we are using a Mali-T76x device */
92 hardware_counters = hardware_counters_mali_t76x;
93 count = ARRAY_SIZE(hardware_counters_mali_t76x);
95 /* If we are using a Mali-T82x device */
97 hardware_counters = hardware_counters_mali_t82x;
98 count = ARRAY_SIZE(hardware_counters_mali_t82x);
100 /* If we are using a Mali-T83x device */
102 hardware_counters = hardware_counters_mali_t83x;
103 count = ARRAY_SIZE(hardware_counters_mali_t83x);
105 /* If we are using a Mali-T86x device */
107 hardware_counters = hardware_counters_mali_t86x;
108 count = ARRAY_SIZE(hardware_counters_mali_t86x);
110 /* If we are using a Mali-T88x device */
112 hardware_counters = hardware_counters_mali_t88x;
113 count = ARRAY_SIZE(hardware_counters_mali_t88x);
116 hardware_counters = NULL;
118 dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
124 /* Release the kbdev reference. */
125 kbase_release_device(kbdev);
127 *total_counters = count;
129 /* If we return a string array take a reference on the module (or fail). */
130 if (hardware_counters && !try_module_get(THIS_MODULE))
133 return hardware_counters;
135 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init_names);
137 void kbase_gator_hwcnt_term_names(void)
139 /* Release the module reference. */
140 module_put(THIS_MODULE);
142 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names);
144 struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info)
146 struct kbase_gator_hwcnt_handles *hand;
147 struct kbase_uk_hwcnt_reader_setup setup;
148 uint32_t dump_size = 0, i = 0;
153 hand = kzalloc(sizeof(*hand), GFP_KERNEL);
157 INIT_WORK(&hand->dump_work, dump_worker);
158 spin_lock_init(&hand->dump_lock);
160 /* Get the first device */
161 hand->kbdev = kbase_find_device(-1);
165 dump_size = kbase_vinstr_dump_size(hand->kbdev);
166 hand->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL);
167 if (!hand->vinstr_buffer)
169 in_out_info->kernel_dump_buffer = hand->vinstr_buffer;
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;
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)) {
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);
185 if (!in_out_info->hwc_layout)
186 goto free_vinstr_buffer;
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;
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;
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;
200 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
203 in_out_info->hwc_layout[i++] = TILER_BLOCK;
204 in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
206 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
209 in_out_info->hwc_layout[i++] = JM_BLOCK;
211 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
213 /* If we are using any other device */
215 uint32_t nr_l2, nr_sc_bits, j;
218 nr_l2 = hand->kbdev->gpu_props.props.l2_props.num_l2_slices;
220 core_mask = hand->kbdev->gpu_props.props.coherency_info.group[0].core_mask;
222 nr_sc_bits = fls64(core_mask);
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);
228 if (!in_out_info->hwc_layout)
229 goto free_vinstr_buffer;
231 dump_size = (2 + nr_sc_bits + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER;
233 in_out_info->hwc_layout[i++] = JM_BLOCK;
234 in_out_info->hwc_layout[i++] = TILER_BLOCK;
236 for (j = 0; j < nr_l2; j++)
237 in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
239 while (core_mask != 0ull) {
240 if ((core_mask & 1ull) != 0ull)
241 in_out_info->hwc_layout[i++] = SHADER_BLOCK;
243 in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
248 in_out_info->nr_hwc_blocks = i;
249 in_out_info->size = dump_size;
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");
265 kfree(in_out_info->hwc_layout);
268 kfree(hand->vinstr_buffer);
271 kbase_release_device(hand->kbdev);
277 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init);
279 void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles)
282 kfree(in_out_info->hwc_layout);
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);
292 KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term);
294 static void dump_worker(struct work_struct *work)
296 struct kbase_gator_hwcnt_handles *hand;
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);
305 schedule_work(&hand->dump_work);
309 uint32_t kbase_gator_instr_hwcnt_dump_complete(
310 struct kbase_gator_hwcnt_handles *opaque_handles,
311 uint32_t * const success)
314 if (opaque_handles && success) {
315 *success = opaque_handles->dump_complete;
316 opaque_handles->dump_complete = 0;
321 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete);
323 uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles)
326 schedule_work(&opaque_handles->dump_work);
329 KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq);