tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / linux / mali_profiling_internal.c
1 /*
2  * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 #include "mali_kernel_common.h"
12 #include "mali_osk.h"
13 #include "mali_osk_mali.h"
14 #include "mali_ukk.h"
15 #include "mali_timestamp.h"
16 #include "mali_osk_profiling.h"
17 #include "mali_user_settings_db.h"
18 #include "mali_profiling_internal.h"
19
20 typedef struct mali_profiling_entry
21 {
22         u64 timestamp;
23         u32 event_id;
24         u32 data[5];
25 } mali_profiling_entry;
26
27
28 typedef enum mali_profiling_state
29 {
30         MALI_PROFILING_STATE_UNINITIALIZED,
31         MALI_PROFILING_STATE_IDLE,
32         MALI_PROFILING_STATE_RUNNING,
33         MALI_PROFILING_STATE_RETURN,
34 } mali_profiling_state;
35
36 static _mali_osk_lock_t *lock = NULL;
37 static mali_profiling_state prof_state = MALI_PROFILING_STATE_UNINITIALIZED;
38 static mali_profiling_entry* profile_entries = NULL;
39 static _mali_osk_atomic_t profile_insert_index;
40 static u32 profile_mask = 0;
41 static inline void add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4);
42
43 void probe_mali_timeline_event(void *data, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned
44                         int d2, unsigned int d3, unsigned int d4))
45 {
46         add_event(event_id, d0, d1, d2, d3, d4);
47 }
48
49 _mali_osk_errcode_t _mali_internal_profiling_init(mali_bool auto_start)
50 {
51         profile_entries = NULL;
52         profile_mask = 0;
53         _mali_osk_atomic_init(&profile_insert_index, 0);
54
55         lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PROFILING);
56         if (NULL == lock)
57         {
58                 return _MALI_OSK_ERR_FAULT;
59         }
60
61         prof_state = MALI_PROFILING_STATE_IDLE;
62
63         if (MALI_TRUE == auto_start)
64         {
65                 u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* Use maximum buffer size */
66
67                 mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, MALI_TRUE);
68                 if (_MALI_OSK_ERR_OK != _mali_internal_profiling_start(&limit))
69                 {
70                         return _MALI_OSK_ERR_FAULT;
71                 }
72         }
73
74         return _MALI_OSK_ERR_OK;
75 }
76
77 void _mali_internal_profiling_term(void)
78 {
79         u32 count;
80
81         /* Ensure profiling is stopped */
82         _mali_internal_profiling_stop(&count);
83
84         prof_state = MALI_PROFILING_STATE_UNINITIALIZED;
85
86         if (NULL != profile_entries)
87         {
88                 _mali_osk_vfree(profile_entries);
89                 profile_entries = NULL;
90         }
91
92         if (NULL != lock)
93         {
94                 _mali_osk_lock_term(lock);
95                 lock = NULL;
96         }
97 }
98
99 _mali_osk_errcode_t _mali_internal_profiling_start(u32 * limit)
100 {
101         _mali_osk_errcode_t ret;
102         mali_profiling_entry *new_profile_entries;
103
104         _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
105
106         if (MALI_PROFILING_STATE_RUNNING == prof_state)
107         {
108                 _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
109                 return _MALI_OSK_ERR_BUSY;
110         }
111
112         new_profile_entries = _mali_osk_valloc(*limit * sizeof(mali_profiling_entry));
113
114         if (NULL == new_profile_entries)
115         {
116                 _mali_osk_vfree(new_profile_entries);
117                 return _MALI_OSK_ERR_NOMEM;
118         }
119
120         if (MALI_PROFILING_MAX_BUFFER_ENTRIES < *limit)
121         {
122                 *limit = MALI_PROFILING_MAX_BUFFER_ENTRIES;
123         }
124
125         profile_mask = 1;
126         while (profile_mask <= *limit)
127         {
128                 profile_mask <<= 1;
129         }
130         profile_mask >>= 1;
131
132         *limit = profile_mask;
133
134         profile_mask--; /* turns the power of two into a mask of one less */
135
136         if (MALI_PROFILING_STATE_IDLE != prof_state)
137         {
138                 _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
139                 _mali_osk_vfree(new_profile_entries);
140                 return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
141         }
142
143         profile_entries = new_profile_entries;
144
145         ret = _mali_timestamp_reset();
146
147         if (_MALI_OSK_ERR_OK == ret)
148         {
149                 prof_state = MALI_PROFILING_STATE_RUNNING;
150         }
151         else
152         {
153                 _mali_osk_vfree(profile_entries);
154                 profile_entries = NULL;
155         }
156
157         register_trace_mali_timeline_event(probe_mali_timeline_event, NULL);
158
159         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
160         return ret;
161 }
162
163 static inline void add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4)
164 {
165         u32 cur_index = (_mali_osk_atomic_inc_return(&profile_insert_index) - 1) & profile_mask;
166
167         profile_entries[cur_index].timestamp = _mali_timestamp_get();
168         profile_entries[cur_index].event_id = event_id;
169         profile_entries[cur_index].data[0] = data0;
170         profile_entries[cur_index].data[1] = data1;
171         profile_entries[cur_index].data[2] = data2;
172         profile_entries[cur_index].data[3] = data3;
173         profile_entries[cur_index].data[4] = data4;
174
175         /* If event is "leave API function", add current memory usage to the event
176          * as data point 4.  This is used in timeline profiling to indicate how
177          * much memory was used when leaving a function. */
178         if (event_id == (MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC))
179         {
180                 profile_entries[cur_index].data[4] = _mali_ukk_report_memory_usage();
181         }
182 }
183
184 _mali_osk_errcode_t _mali_internal_profiling_stop(u32 * count)
185 {
186         _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
187
188         if (MALI_PROFILING_STATE_RUNNING != prof_state)
189         {
190                 _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
191                 return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
192         }
193
194         /* go into return state (user to retreive events), no more events will be added after this */
195         prof_state = MALI_PROFILING_STATE_RETURN;
196
197         unregister_trace_mali_timeline_event(probe_mali_timeline_event, NULL);
198
199         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
200
201         tracepoint_synchronize_unregister();
202
203         *count = _mali_osk_atomic_read(&profile_insert_index);
204         if (*count > profile_mask) *count = profile_mask;
205
206         return _MALI_OSK_ERR_OK;
207 }
208
209 u32 _mali_internal_profiling_get_count(void)
210 {
211         u32 retval = 0;
212
213         _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
214         if (MALI_PROFILING_STATE_RETURN == prof_state)
215         {
216                 retval = _mali_osk_atomic_read(&profile_insert_index);
217                 if (retval > profile_mask) retval = profile_mask;
218         }
219         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
220
221         return retval;
222 }
223
224 _mali_osk_errcode_t _mali_internal_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5])
225 {
226         u32 raw_index = _mali_osk_atomic_read(&profile_insert_index);
227
228         _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
229
230         if (index < profile_mask)
231         {
232                 if ((raw_index & ~profile_mask) != 0)
233                 {
234                         index += raw_index;
235                         index &= profile_mask;
236                 }
237
238                 if (prof_state != MALI_PROFILING_STATE_RETURN)
239                 {
240                         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
241                         return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
242                 }
243
244                 if(index >= raw_index)
245                 {
246                         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
247                         return _MALI_OSK_ERR_FAULT;
248                 }
249
250                 *timestamp = profile_entries[index].timestamp;
251                 *event_id = profile_entries[index].event_id;
252                 data[0] = profile_entries[index].data[0];
253                 data[1] = profile_entries[index].data[1];
254                 data[2] = profile_entries[index].data[2];
255                 data[3] = profile_entries[index].data[3];
256                 data[4] = profile_entries[index].data[4];
257         }
258         else
259         {
260                 _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
261                 return _MALI_OSK_ERR_FAULT;
262         }
263
264         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
265         return _MALI_OSK_ERR_OK;
266 }
267
268 _mali_osk_errcode_t _mali_internal_profiling_clear(void)
269 {
270         _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW);
271
272         if (MALI_PROFILING_STATE_RETURN != prof_state)
273         {
274                 _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
275                 return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */
276         }
277
278         prof_state = MALI_PROFILING_STATE_IDLE;
279         profile_mask = 0;
280         _mali_osk_atomic_init(&profile_insert_index, 0);
281
282         if (NULL != profile_entries)
283         {
284                 _mali_osk_vfree(profile_entries);
285                 profile_entries = NULL;
286         }
287
288         _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW);
289         return _MALI_OSK_ERR_OK;
290 }
291
292 mali_bool _mali_internal_profiling_is_recording(void)
293 {
294         return prof_state == MALI_PROFILING_STATE_RUNNING ? MALI_TRUE : MALI_FALSE;
295 }
296
297 mali_bool _mali_internal_profiling_have_recording(void)
298 {
299         return prof_state == MALI_PROFILING_STATE_RETURN ? MALI_TRUE : MALI_FALSE;
300 }