Initial commit
[kernel/linux-3.0.git] / drivers / gpu / vithar / kbase / src / common / mali_kbase_instr.c
1 /*
2  *
3  * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
4  *
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.
7  * 
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.
10  * 
11  */
12
13
14
15 /**
16  * @file mali_kbase_instr.c
17  * Base kernel instrumentation APIs.
18  */
19
20 #include <kbase/src/common/mali_kbase.h>
21 #include <kbase/src/common/mali_midg_regmap.h>
22
23 /**
24  * @brief Issue Cache Clean & Invalidate command to hardware
25  */
26 static void kbasep_instr_hwcnt_cacheclean(kbase_device *kbdev)
27 {
28         u32 irq_mask;
29
30         OSK_ASSERT(NULL != kbdev);
31
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);
37 }
38
39 /**
40  * @brief Enable HW counters collection
41  *
42  * Note: will wait for a cache clean to complete
43  */
44 mali_error kbase_instr_hwcnt_enable(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
45 {
46         mali_error err = MALI_ERROR_FUNCTION_FAILED;
47         kbasep_js_device_data *js_devdata;
48         mali_bool access_allowed;
49         u32 irq_mask;
50         kbase_device *kbdev;
51
52         OSK_ASSERT(NULL != kctx);
53         kbdev = kctx->kbdev;
54         OSK_ASSERT(NULL != kbdev);
55         OSK_ASSERT(NULL != setup);
56
57         js_devdata = &kbdev->js_data;
58         OSK_ASSERT(NULL != js_devdata);
59
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)
63         {
64                 goto out;
65         }
66
67         if ((setup->dump_buffer == 0ULL) ||
68             (setup->dump_buffer & (2048-1)))
69         {
70                 /* alignment failure */
71                 goto out;
72         }
73         
74
75         /* Mark the context as active so the GPU is kept turned on */
76         kbase_pm_context_active(kbdev);
77
78         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
79
80         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
81         {
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);
86         }
87
88
89         if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
90         {
91                 /* Instrumentation is already enabled */
92                 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
93                 kbase_pm_context_idle(kbdev);
94                 goto out;
95         }
96
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);
100
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;
105
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);
109
110         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
111
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);
117
118         /* Schedule the context in */
119         kbasep_js_schedule_privileged_ctx(kbdev, kctx);
120
121         /* Configure */
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);
130 #endif
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);
133
134         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
135
136         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
137         {
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);
142         }
143
144         kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
145         osk_waitq_set(&kbdev->hwcnt.waitqueue);
146
147         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
148
149         err = MALI_ERROR_NONE;
150
151         OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping set-up for context %p", kctx);
152
153 out:
154         return err;
155 }
156 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_enable)
157
158 /**
159  * @brief Disable HW counters collection
160  *
161  * Note: might sleep, waiting for an ongoing dump to complete
162  */
163 mali_error kbase_instr_hwcnt_disable(kbase_context * kctx)
164 {
165         mali_error err = MALI_ERROR_FUNCTION_FAILED;
166         u32 irq_mask;
167         kbase_device *kbdev;
168
169         OSK_ASSERT(NULL != kctx);
170         kbdev = kctx->kbdev;
171         OSK_ASSERT(NULL != kbdev);
172
173         while (1)
174         {
175                 osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
176
177                 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_DISABLED)
178                 {
179                         /* Instrumentation is not enabled */
180                         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
181                         goto out;
182                 }
183
184                 if (kbdev->hwcnt.kctx != kctx)
185                 {
186                         /* Instrumentation has been setup for another context */
187                         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
188                         goto out;
189                 }
190
191                 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
192                 {
193                         break;
194                 }
195
196                 osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
197
198                 /* Ongoing dump/setup - wait for its completion */
199                 osk_waitq_wait(&kbdev->hwcnt.waitqueue);
200         }
201
202         kbdev->hwcnt.state = KBASE_INSTR_STATE_DISABLED;
203         osk_waitq_clear(&kbdev->hwcnt.waitqueue);
204
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);
208
209         /* Disable the counters */
210         kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), 0, kctx);
211
212         kbdev->hwcnt.kctx = NULL;
213         kbdev->hwcnt.addr = 0ULL;
214
215         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
216
217         /* Release the context, this implicitly (and indirectly) calls kbase_pm_context_idle */
218         kbasep_js_release_privileged_ctx(kbdev, kctx);
219
220         OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping disabled for context %p", kctx);
221
222         err = MALI_ERROR_NONE;
223
224 out:
225         return err;
226 }
227 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_disable)
228
229 /**
230  * @brief Configure HW counters collection
231  */
232 mali_error kbase_instr_hwcnt_setup(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
233 {
234         mali_error err = MALI_ERROR_FUNCTION_FAILED;
235         kbase_device *kbdev;
236
237         OSK_ASSERT(NULL != kctx);
238
239         kbdev = kctx->kbdev;
240         OSK_ASSERT(NULL != kbdev);
241
242         if (NULL == setup)
243         {
244                 /* Bad parameter - abort */
245                 goto out;
246         }
247
248         if (setup->dump_buffer != 0ULL)
249         {
250                 /* Enable HW counters */
251                 err = kbase_instr_hwcnt_enable(kctx, setup);
252         }
253         else
254         {
255                 /* Disable HW counters */
256                 err = kbase_instr_hwcnt_disable(kctx);
257         }
258
259 out:
260         return err;
261 }
262
263 /**
264  * @brief Issue Dump command to hardware
265  */
266 mali_error kbase_instr_hwcnt_dump_irq(kbase_context * kctx)
267 {
268         mali_error err = MALI_ERROR_FUNCTION_FAILED;
269         kbase_device *kbdev;
270
271         OSK_ASSERT(NULL != kctx);
272         kbdev = kctx->kbdev;
273         OSK_ASSERT(NULL != kbdev);
274
275         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
276
277         OSK_ASSERT(kbdev->hwcnt.state != KBASE_INSTR_STATE_RESETTING);
278
279         if (kbdev->hwcnt.kctx != kctx)
280         {
281                  /* The instrumentation has been setup for another context */
282                 goto unlock;
283         }
284
285         if (kbdev->hwcnt.state != KBASE_INSTR_STATE_IDLE)
286         {
287                 /* HW counters are disabled or another dump is ongoing */
288                 goto unlock;
289         }
290
291         osk_waitq_clear(&kbdev->hwcnt.waitqueue);
292
293         /* Mark that we're dumping - the PF handler can signal that we faulted */
294         kbdev->hwcnt.state = KBASE_INSTR_STATE_DUMPING;
295
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);
299
300         /* Start dumping */
301         kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_SAMPLE, kctx);
302
303         OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping done for context %p", kctx);
304
305         err = MALI_ERROR_NONE;
306
307 unlock:
308         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
309         return err;
310 }
311 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_irq)
312
313 /**
314  * @brief Tell whether the HW counters dump has completed
315  *
316  * Notes:
317  * - does not sleep
318  * - success will be set to MALI_TRUE if the dump succeeded or
319  *   MALI_FALSE on failure
320  */
321 mali_bool kbase_instr_hwcnt_dump_complete(kbase_context * kctx, mali_bool *success)
322 {
323         mali_bool complete = MALI_FALSE;
324         kbase_device *kbdev;
325
326         OSK_ASSERT(NULL != kctx);
327         kbdev = kctx->kbdev;
328         OSK_ASSERT(NULL != kbdev);
329         OSK_ASSERT(NULL != success);
330
331         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
332
333         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
334         {
335                 *success = MALI_TRUE;
336                 complete = MALI_TRUE;
337         }
338         else if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
339         {
340                 *success = MALI_FALSE;
341                 complete = MALI_TRUE;
342                 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
343         }
344
345         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
346
347         return complete;
348 }
349 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_complete)
350
351 /**
352  * @brief Issue Dump command to hardware and wait for completion
353  */
354 mali_error kbase_instr_hwcnt_dump(kbase_context * kctx)
355 {
356         mali_error err = MALI_ERROR_FUNCTION_FAILED;
357         kbase_device *kbdev;
358
359         OSK_ASSERT(NULL != kctx);
360         kbdev = kctx->kbdev;
361         OSK_ASSERT(NULL != kbdev);
362
363         err = kbase_instr_hwcnt_dump_irq(kctx);
364         if (MALI_ERROR_NONE != err)
365         {
366                  /* Can't dump HW counters */
367                 goto out;
368         }
369
370         /* Wait for dump & cacheclean to complete */
371         osk_waitq_wait(&kbdev->hwcnt.waitqueue);
372
373         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
374
375         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
376         {
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);
381         }
382
383         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
384         {
385                 kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
386         }
387         else
388         {
389                 /* Dump done */
390                 OSK_ASSERT(kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE);
391                 err = MALI_ERROR_NONE;
392         }
393
394         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
395 out:
396         return err;
397 }
398 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump)
399
400 /**
401  * @brief Clear the HW counters
402  */
403 mali_error kbase_instr_hwcnt_clear(kbase_context * kctx)
404 {
405         mali_error err = MALI_ERROR_FUNCTION_FAILED;
406         kbase_device *kbdev;
407
408         OSK_ASSERT(NULL != kctx);
409         kbdev = kctx->kbdev;
410         OSK_ASSERT(NULL != kbdev);
411
412         osk_spinlock_irq_lock(&kbdev->hwcnt.lock);
413
414         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
415         {
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);
420         }
421
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)
425         {
426                 goto out;
427         }
428
429         /* Clear the counters */
430         kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_CLEAR, kctx);
431
432         err = MALI_ERROR_NONE;
433
434 out:
435         osk_spinlock_irq_unlock(&kbdev->hwcnt.lock);
436         return err;
437 }
438 KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_clear)
439
440 /**
441  * @brief Dump complete interrupt received
442  */
443 void kbase_instr_hwcnt_sample_done(kbase_device *kbdev)
444 {
445         if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
446         {
447                 osk_waitq_set(&kbdev->hwcnt.waitqueue);
448         }
449         else
450         {
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);
454         }
455 }
456
457 /**
458  * @brief Cache clean interrupt received
459  */
460 void kbase_clean_caches_done(kbase_device *kbdev)
461 {
462         u32 irq_mask;
463
464         if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
465         {
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);
469
470                 if (kbdev->hwcnt.state == KBASE_INSTR_STATE_PRECLEANING)
471                 {
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;
475                 }
476                 else
477                 {
478                         /* All finished and idle */
479                         kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
480                 }
481
482                 osk_waitq_set(&kbdev->hwcnt.waitqueue);
483         }
484 }