3 * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
5 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
8 * A copy of the licence is included with the program, and can also be obtained from Free Software
9 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * @file mali_kbase_instr.c
17 * Base kernel instrumentation APIs.
20 #include <kbase/src/common/mali_kbase.h>
21 #include <kbase/src/common/mali_midg_regmap.h>
24 * @brief Issue Cache Clean & Invalidate command to hardware
26 static void kbasep_instr_hwcnt_cacheclean(kbase_device *kbdev)
30 OSK_ASSERT(NULL != kbdev);
32 /* Enable interrupt */
33 irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
34 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask | CLEAN_CACHES_COMPLETED, NULL);
35 /* clean&invalidate the caches so we're sure the mmu tables for the dump buffer is valid */
36 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CLEAN_INV_CACHES, NULL);
40 * @brief Enable HW counters collection
42 * Note: will wait for a cache clean to complete
44 mali_error kbase_instr_hwcnt_enable(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
46 mali_error err = MALI_ERROR_FUNCTION_FAILED;
47 kbasep_js_device_data *js_devdata;
48 mali_bool access_allowed;
52 OSK_ASSERT(NULL != kctx);
54 OSK_ASSERT(NULL != kbdev);
55 OSK_ASSERT(NULL != setup);
57 js_devdata = &kbdev->js_data;
58 OSK_ASSERT(NULL != js_devdata);
60 /* Determine if the calling task has access to this capability */
61 access_allowed = kbase_security_has_capability(kctx, KBASE_SEC_INSTR_HW_COUNTERS_COLLECT, KBASE_SEC_FLAG_NOAUDIT);
62 if (MALI_FALSE == access_allowed)
67 if ((setup->dump_buffer == 0ULL) ||
68 (setup->dump_buffer & (2048-1)))
70 /* alignment failure */
75 /* Mark the context as active so the GPU is kept turned on */
76 kbase_pm_context_active(kbdev);
78 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
80 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
82 /* GPU is being reset*/
83 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
84 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
85 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
89 if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
91 /* Instrumentation is already enabled */
92 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
93 kbase_pm_context_idle(kbdev);
97 /* Enable interrupt */
98 irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
99 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask | PRFCNT_SAMPLE_COMPLETED, NULL);
101 /* In use, this context is the owner */
102 kbdev->hwcnt.kctx = kctx;
103 /* Remember the dump address so we can reprogram it later */
104 kbdev->hwcnt.addr = setup->dump_buffer;
106 /* Precleaning so that state does not transition to IDLE */
107 kbdev->hwcnt.state = KBASE_INSTR_STATE_PRECLEANING;
108 osk_waitq_clear(&kbdev->hwcnt.waitqueue);
110 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
112 /* Clean&invalidate the caches so we're sure the mmu tables for the dump buffer is valid */
113 kbasep_instr_hwcnt_cacheclean(kbdev);
114 /* Wait for cacheclean to complete */
115 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
116 OSK_ASSERT(kbdev->hwcnt.state == KBASE_INSTR_STATE_CLEANED);
118 /* Schedule the context in */
119 kbasep_js_schedule_privileged_ctx(kbdev, kctx);
122 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), setup->dump_buffer & 0xFFFFFFFF, kctx);
123 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), setup->dump_buffer >> 32, kctx);
124 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN), setup->jm_bm, kctx);
125 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN), setup->shader_bm, kctx);
126 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_L3_CACHE_EN), setup->l3_cache_bm, kctx);
127 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN), setup->mmu_l2_bm, kctx);
128 #if BASE_HW_ISSUE_8186
129 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), 0, kctx);
131 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), (kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT) | PRFCNT_CONFIG_MODE_MANUAL, kctx);
132 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), setup->tiler_bm, kctx);
134 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
136 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
138 /* GPU is being reset*/
139 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
140 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
141 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
144 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
145 osk_waitq_set(&kbdev->hwcnt.waitqueue);
147 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
149 err = MALI_ERROR_NONE;
151 OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping set-up for context %p", kctx);
156 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_enable)
159 * @brief Disable HW counters collection
161 * Note: might sleep, waiting for an ongoing dump to complete
163 mali_error kbase_instr_hwcnt_disable(kbase_context * kctx)
165 mali_error err = MALI_ERROR_FUNCTION_FAILED;
169 OSK_ASSERT(NULL != kctx);
171 OSK_ASSERT(NULL != kbdev);
175 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
177 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_DISABLED)
179 /* Instrumentation is not enabled */
180 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
184 if (kbdev->hwcnt.kctx != kctx)
186 /* Instrumentation has been setup for another context */
187 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
191 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
196 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
198 /* Ongoing dump/setup - wait for its completion */
199 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
202 kbdev->hwcnt.state = KBASE_INSTR_STATE_DISABLED;
203 osk_waitq_clear(&kbdev->hwcnt.waitqueue);
205 /* Disable interrupt */
206 irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
207 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask & ~PRFCNT_SAMPLE_COMPLETED, NULL);
209 /* Disable the counters */
210 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), 0, kctx);
212 kbdev->hwcnt.kctx = NULL;
213 kbdev->hwcnt.addr = 0ULL;
215 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
217 /* Release the context, this implicitly (and indirectly) calls kbase_pm_context_idle */
218 kbasep_js_release_privileged_ctx(kbdev, kctx);
220 OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping disabled for context %p", kctx);
222 err = MALI_ERROR_NONE;
227 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_disable)
230 * @brief Configure HW counters collection
232 mali_error kbase_instr_hwcnt_setup(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
234 mali_error err = MALI_ERROR_FUNCTION_FAILED;
237 OSK_ASSERT(NULL != kctx);
240 OSK_ASSERT(NULL != kbdev);
244 /* Bad parameter - abort */
248 if (setup->dump_buffer != 0ULL)
250 /* Enable HW counters */
251 err = kbase_instr_hwcnt_enable(kctx, setup);
255 /* Disable HW counters */
256 err = kbase_instr_hwcnt_disable(kctx);
264 * @brief Issue Dump command to hardware
266 mali_error kbase_instr_hwcnt_dump_irq(kbase_context * kctx)
268 mali_error err = MALI_ERROR_FUNCTION_FAILED;
271 OSK_ASSERT(NULL != kctx);
273 OSK_ASSERT(NULL != kbdev);
275 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
277 OSK_ASSERT(kbdev->hwcnt.state != KBASE_INSTR_STATE_RESETTING);
279 if (kbdev->hwcnt.kctx != kctx)
281 /* The instrumentation has been setup for another context */
285 if (kbdev->hwcnt.state != KBASE_INSTR_STATE_IDLE)
287 /* HW counters are disabled or another dump is ongoing */
291 osk_waitq_clear(&kbdev->hwcnt.waitqueue);
293 /* Mark that we're dumping - the PF handler can signal that we faulted */
294 kbdev->hwcnt.state = KBASE_INSTR_STATE_DUMPING;
296 /* Reconfigure the dump address */
297 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), kbdev->hwcnt.addr & 0xFFFFFFFF, NULL);
298 kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), kbdev->hwcnt.addr >> 32, NULL);
301 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_SAMPLE, kctx);
303 OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping done for context %p", kctx);
305 err = MALI_ERROR_NONE;
308 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
311 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_irq)
314 * @brief Tell whether the HW counters dump has completed
318 * - success will be set to MALI_TRUE if the dump succeeded or
319 * MALI_FALSE on failure
321 mali_bool kbase_instr_hwcnt_dump_complete(kbase_context * kctx, mali_bool *success)
323 mali_bool complete = MALI_FALSE;
326 OSK_ASSERT(NULL != kctx);
328 OSK_ASSERT(NULL != kbdev);
329 OSK_ASSERT(NULL != success);
331 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
333 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
335 *success = MALI_TRUE;
336 complete = MALI_TRUE;
338 else if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
340 *success = MALI_FALSE;
341 complete = MALI_TRUE;
342 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
345 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
349 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_complete)
352 * @brief Issue Dump command to hardware and wait for completion
354 mali_error kbase_instr_hwcnt_dump(kbase_context * kctx)
356 mali_error err = MALI_ERROR_FUNCTION_FAILED;
359 OSK_ASSERT(NULL != kctx);
361 OSK_ASSERT(NULL != kbdev);
363 err = kbase_instr_hwcnt_dump_irq(kctx);
364 if (MALI_ERROR_NONE != err)
366 /* Can't dump HW counters */
370 /* Wait for dump & cacheclean to complete */
371 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
373 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
375 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
377 /* GPU is being reset*/
378 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
379 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
380 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
383 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
385 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
390 OSK_ASSERT(kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE);
391 err = MALI_ERROR_NONE;
394 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
398 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump)
401 * @brief Clear the HW counters
403 mali_error kbase_instr_hwcnt_clear(kbase_context * kctx)
405 mali_error err = MALI_ERROR_FUNCTION_FAILED;
408 OSK_ASSERT(NULL != kctx);
410 OSK_ASSERT(NULL != kbdev);
412 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
414 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
416 /* GPU is being reset*/
417 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
418 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
419 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
422 /* Check it's the context previously set up and we're not already dumping */
423 if (kbdev->hwcnt.kctx != kctx ||
424 kbdev->hwcnt.state != KBASE_INSTR_STATE_IDLE)
429 /* Clear the counters */
430 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_CLEAR, kctx);
432 err = MALI_ERROR_NONE;
435 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
438 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_clear)
441 * @brief Dump complete interrupt received
443 void kbase_instr_hwcnt_sample_done(kbase_device *kbdev)
445 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
447 osk_waitq_set(&kbdev->hwcnt.waitqueue);
451 /* Always clean and invalidate the cache after a successful dump */
452 kbdev->hwcnt.state = KBASE_INSTR_STATE_POSTCLEANING;
453 kbasep_instr_hwcnt_cacheclean(kbdev);
458 * @brief Cache clean interrupt received
460 void kbase_clean_caches_done(kbase_device *kbdev)
464 if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
466 /* Disable interrupt */
467 irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
468 kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask & ~CLEAN_CACHES_COMPLETED, NULL);
470 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_PRECLEANING)
472 /* Don't return IDLE as we need kbase_instr_hwcnt_setup to continue rather than
473 allow access to another waiting thread */
474 kbdev->hwcnt.state = KBASE_INSTR_STATE_CLEANED;
478 /* All finished and idle */
479 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
482 osk_waitq_set(&kbdev->hwcnt.waitqueue);