268676a6f2fabf9c63778c07b8b886e7c6b2b231
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / common / mali_timeline.h
1 /*
2  * Copyright (C) 2013-2016 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 #ifndef __MALI_TIMELINE_H__
12 #define __MALI_TIMELINE_H__
13
14 #include "mali_osk.h"
15 #include "mali_ukk.h"
16 #include "mali_session.h"
17 #include "mali_kernel_common.h"
18 #include "mali_spinlock_reentrant.h"
19 #include "mali_sync.h"
20 #include "mali_scheduler_types.h"
21 #include <linux/version.h>
22
23 /**
24  * Soft job timeout.
25  *
26  * Soft jobs have to be signaled as complete after activation.  Normally this is done by user space,
27  * but in order to guarantee that every soft job is completed, we also have a timer.
28  */
29 #define MALI_TIMELINE_TIMEOUT_HZ ((unsigned long) (HZ * 3 / 2)) /* 1500 ms. */
30
31 /**
32  * Timeline type.
33  */
34 typedef enum mali_timeline_id {
35         MALI_TIMELINE_GP   = MALI_UK_TIMELINE_GP,   /**< GP job timeline. */
36         MALI_TIMELINE_PP   = MALI_UK_TIMELINE_PP,   /**< PP job timeline. */
37         MALI_TIMELINE_SOFT = MALI_UK_TIMELINE_SOFT, /**< Soft job timeline. */
38         MALI_TIMELINE_MAX  = MALI_UK_TIMELINE_MAX
39 } mali_timeline_id;
40
41 /**
42  * Used by trackers that should not be added to a timeline (@ref mali_timeline_system_add_tracker).
43  */
44 #define MALI_TIMELINE_NONE MALI_TIMELINE_MAX
45
46 /**
47  * Tracker type.
48  */
49 typedef enum mali_timeline_tracker_type {
50         MALI_TIMELINE_TRACKER_GP   = 0, /**< Tracker used by GP jobs. */
51         MALI_TIMELINE_TRACKER_PP   = 1, /**< Tracker used by PP jobs. */
52         MALI_TIMELINE_TRACKER_SOFT = 2, /**< Tracker used by soft jobs. */
53         MALI_TIMELINE_TRACKER_WAIT = 3, /**< Tracker used for fence wait. */
54         MALI_TIMELINE_TRACKER_SYNC = 4, /**< Tracker used for sync fence. */
55         MALI_TIMELINE_TRACKER_MAX  = 5,
56 } mali_timeline_tracker_type;
57
58 /**
59  * Tracker activation error.
60  */
61 typedef u32 mali_timeline_activation_error;
62 #define MALI_TIMELINE_ACTIVATION_ERROR_NONE      0
63 #define MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT  (1<<1)
64 #define MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT (1<<0)
65
66 /**
67  * Type used to represent a point on a timeline.
68  */
69 typedef u32 mali_timeline_point;
70
71 /**
72  * Used to represent that no point on a timeline.
73  */
74 #define MALI_TIMELINE_NO_POINT ((mali_timeline_point) 0)
75
76 /**
77  * The maximum span of points on a timeline.  A timeline will be considered full if the difference
78  * between the oldest and newest points is equal or larger to this value.
79  */
80 #define MALI_TIMELINE_MAX_POINT_SPAN 65536
81
82 /**
83  * Magic value used to assert on validity of trackers.
84  */
85 #define MALI_TIMELINE_TRACKER_MAGIC 0xabcdabcd
86
87 struct mali_timeline;
88 struct mali_timeline_waiter;
89 struct mali_timeline_tracker;
90
91 /**
92  * Timeline fence.
93  */
94 struct mali_timeline_fence {
95         mali_timeline_point points[MALI_TIMELINE_MAX]; /**< For each timeline, a point or MALI_TIMELINE_NO_POINT. */
96         s32                 sync_fd;                   /**< A file descriptor representing a sync fence, or -1. */
97 };
98
99 /**
100  * Timeline system.
101  *
102  * The Timeline system has a set of timelines associated with a session.
103  */
104 struct mali_timeline_system {
105         struct mali_spinlock_reentrant *spinlock;   /**< Spin lock protecting the timeline system */
106         struct mali_timeline           *timelines[MALI_TIMELINE_MAX]; /**< The timelines in this system */
107
108         /* Single-linked list of unused waiter objects.  Uses the tracker_next field in tracker. */
109         struct mali_timeline_waiter    *waiter_empty_list;
110
111         struct mali_session_data       *session;    /**< Session that owns this system. */
112
113         mali_bool                       timer_enabled; /**< Set to MALI_TRUE if soft job timer should be enabled, MALI_FALSE if not. */
114
115         _mali_osk_wait_queue_t         *wait_queue; /**< Wait queue. */
116
117 #if defined(CONFIG_SYNC)
118         struct sync_timeline           *signaled_sync_tl; /**< Special sync timeline used to create pre-signaled sync fences */
119 #endif /* defined(CONFIG_SYNC) */
120 };
121
122 /**
123  * Timeline.  Each Timeline system will have MALI_TIMELINE_MAX timelines.
124  */
125 struct mali_timeline {
126         mali_timeline_point           point_next;   /**< The next available point. */
127         mali_timeline_point           point_oldest; /**< The oldest point not released. */
128
129         /* Double-linked list of trackers.  Sorted in ascending order by tracker->time_number with
130          * tail pointing to the tracker with the oldest time. */
131         struct mali_timeline_tracker *tracker_head;
132         struct mali_timeline_tracker *tracker_tail;
133
134         /* Double-linked list of waiters.  Sorted in ascending order by waiter->time_number_wait
135          * with tail pointing to the waiter with oldest wait time. */
136         struct mali_timeline_waiter  *waiter_head;
137         struct mali_timeline_waiter  *waiter_tail;
138
139         struct mali_timeline_system  *system;       /**< Timeline system this timeline belongs to. */
140         enum mali_timeline_id         id;           /**< Timeline type. */
141
142 #if defined(CONFIG_SYNC)
143         struct sync_timeline         *sync_tl;      /**< Sync timeline that corresponds to this timeline. */
144         mali_bool destroyed;
145         struct mali_spinlock_reentrant *spinlock;       /**< Spin lock protecting the timeline system */
146 #endif /* defined(CONFIG_SYNC) */
147
148         /* The following fields are used to time out soft job trackers. */
149         _mali_osk_wq_delayed_work_t  *delayed_work;
150         mali_bool                     timer_active;
151 };
152
153 /**
154  * Timeline waiter.
155  */
156 struct mali_timeline_waiter {
157         mali_timeline_point           point;         /**< Point on timeline we are waiting for to be released. */
158         struct mali_timeline_tracker *tracker;       /**< Tracker that is waiting. */
159
160         struct mali_timeline_waiter  *timeline_next; /**< Next waiter on timeline's waiter list. */
161         struct mali_timeline_waiter  *timeline_prev; /**< Previous waiter on timeline's waiter list. */
162
163         struct mali_timeline_waiter  *tracker_next;  /**< Next waiter on tracker's waiter list. */
164 };
165
166 /**
167  * Timeline tracker.
168  */
169 struct mali_timeline_tracker {
170         MALI_DEBUG_CODE(u32            magic); /**< Should always be MALI_TIMELINE_TRACKER_MAGIC for a valid tracker. */
171
172         mali_timeline_point            point; /**< Point on timeline for this tracker */
173
174         struct mali_timeline_tracker  *timeline_next; /**< Next tracker on timeline's tracker list */
175         struct mali_timeline_tracker  *timeline_prev; /**< Previous tracker on timeline's tracker list */
176
177         u32                            trigger_ref_count; /**< When zero tracker will be activated */
178         mali_timeline_activation_error activation_error;  /**< Activation error. */
179         struct mali_timeline_fence     fence;             /**< Fence used to create this tracker */
180
181         /* Single-linked list of waiters.  Sorted in order of insertions with
182          * tail pointing to first waiter. */
183         struct mali_timeline_waiter   *waiter_head;
184         struct mali_timeline_waiter   *waiter_tail;
185
186 #if defined(CONFIG_SYNC)
187         /* These are only used if the tracker is waiting on a sync fence. */
188         struct mali_timeline_waiter   *waiter_sync; /**< A direct pointer to timeline waiter representing sync fence. */
189         struct sync_fence_waiter       sync_fence_waiter; /**< Used to connect sync fence and tracker in sync fence wait callback. */
190         struct sync_fence             *sync_fence;   /**< The sync fence this tracker is waiting on. */
191         _mali_osk_list_t               sync_fence_cancel_list; /**< List node used to cancel sync fence waiters. */
192 #endif /* defined(CONFIG_SYNC) */
193
194         struct mali_timeline_system   *system;       /**< Timeline system. */
195         struct mali_timeline          *timeline;     /**< Timeline, or NULL if not on a timeline. */
196         enum mali_timeline_tracker_type type;        /**< Type of tracker. */
197         void                          *job;          /**< Owner of tracker. */
198
199         /* The following fields are used to time out soft job trackers. */
200         unsigned long                 os_tick_create;
201         unsigned long                 os_tick_activate;
202         mali_bool                     timer_active;
203 };
204
205 extern _mali_osk_atomic_t gp_tracker_count;
206 extern _mali_osk_atomic_t phy_pp_tracker_count;
207 extern _mali_osk_atomic_t virt_pp_tracker_count;
208
209 /**
210  * What follows is a set of functions to check the state of a timeline and to determine where on a
211  * timeline a given point is.  Most of these checks will translate the timeline so the oldest point
212  * on the timeline is aligned with zero.  Remember that all of these calculation are done on
213  * unsigned integers.
214  *
215  * The following example illustrates the three different states a point can be in.  The timeline has
216  * been translated to put the oldest point at zero:
217  *
218  *
219  *
220  *                               [ point is in forbidden zone ]
221  *                                          64k wide
222  *                                MALI_TIMELINE_MAX_POINT_SPAN
223  *
224  *    [ point is on timeline     )                            ( point is released ]
225  *
226  *    0--------------------------##############################--------------------2^32 - 1
227  *    ^                          ^
228  *    \                          |
229  *     oldest point on timeline  |
230  *                               \
231  *                                next point on timeline
232  */
233
234 /**
235  * Compare two timeline points
236  *
237  * Returns true if a is after b, false if a is before or equal to b.
238  *
239  * This funcion ignores MALI_TIMELINE_MAX_POINT_SPAN. Wrapping is supported and
240  * the result will be correct if the points is less then UINT_MAX/2 apart.
241  *
242  * @param a Point on timeline
243  * @param b Point on timeline
244  * @return MALI_TRUE if a is after b
245  */
246 MALI_STATIC_INLINE mali_bool mali_timeline_point_after(mali_timeline_point a, mali_timeline_point b)
247 {
248         return 0 > ((s32)b) - ((s32)a);
249 }
250
251 /**
252  * Check if a point is on timeline.  A point is on a timeline if it is greater than, or equal to,
253  * the oldest point, and less than the next point.
254  *
255  * @param timeline Timeline.
256  * @param point Point on timeline.
257  * @return MALI_TRUE if point is on timeline, MALI_FALSE if not.
258  */
259 MALI_STATIC_INLINE mali_bool mali_timeline_is_point_on(struct mali_timeline *timeline, mali_timeline_point point)
260 {
261         MALI_DEBUG_ASSERT_POINTER(timeline);
262         MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point);
263
264         return (point - timeline->point_oldest) < (timeline->point_next - timeline->point_oldest);
265 }
266
267 /**
268  * Check if a point has been released.  A point is released if it is older than the oldest point on
269  * the timeline, newer than the next point, and also not in the forbidden zone.
270  *
271  * @param timeline Timeline.
272  * @param point Point on timeline.
273  * @return MALI_TRUE if point has been release, MALI_FALSE if not.
274  */
275 MALI_STATIC_INLINE mali_bool mali_timeline_is_point_released(struct mali_timeline *timeline, mali_timeline_point point)
276 {
277         mali_timeline_point point_normalized;
278         mali_timeline_point next_normalized;
279
280         MALI_DEBUG_ASSERT_POINTER(timeline);
281         MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point);
282
283         point_normalized = point - timeline->point_oldest;
284         next_normalized = timeline->point_next - timeline->point_oldest;
285
286         return point_normalized > (next_normalized + MALI_TIMELINE_MAX_POINT_SPAN);
287 }
288
289 /**
290  * Check if a point is valid.  A point is valid if is on the timeline or has been released.
291  *
292  * @param timeline Timeline.
293  * @param point Point on timeline.
294  * @return MALI_TRUE if point is valid, MALI_FALSE if not.
295  */
296 MALI_STATIC_INLINE mali_bool mali_timeline_is_point_valid(struct mali_timeline *timeline, mali_timeline_point point)
297 {
298         MALI_DEBUG_ASSERT_POINTER(timeline);
299         return mali_timeline_is_point_on(timeline, point) || mali_timeline_is_point_released(timeline, point);
300 }
301
302 /**
303  * Check if timeline is empty (has no points on it).  A timeline is empty if next == oldest.
304  *
305  * @param timeline Timeline.
306  * @return MALI_TRUE if timeline is empty, MALI_FALSE if not.
307  */
308 MALI_STATIC_INLINE mali_bool mali_timeline_is_empty(struct mali_timeline *timeline)
309 {
310         MALI_DEBUG_ASSERT_POINTER(timeline);
311         return timeline->point_next == timeline->point_oldest;
312 }
313
314 /**
315  * Check if timeline is full.  A valid timeline cannot span more than 64k points (@ref
316  * MALI_TIMELINE_MAX_POINT_SPAN).
317  *
318  * @param timeline Timeline.
319  * @return MALI_TRUE if timeline is full, MALI_FALSE if not.
320  */
321 MALI_STATIC_INLINE mali_bool mali_timeline_is_full(struct mali_timeline *timeline)
322 {
323         MALI_DEBUG_ASSERT_POINTER(timeline);
324         return MALI_TIMELINE_MAX_POINT_SPAN <= (timeline->point_next - timeline->point_oldest);
325 }
326
327 /**
328  * Create a new timeline system.
329  *
330  * @param session The session this timeline system will belong to.
331  * @return New timeline system.
332  */
333 struct mali_timeline_system *mali_timeline_system_create(struct mali_session_data *session);
334
335 /**
336  * Abort timeline system.
337  *
338  * This will release all pending waiters in the timeline system causing all trackers to be
339  * activated.
340  *
341  * @param system Timeline system to abort all jobs from.
342  */
343 void mali_timeline_system_abort(struct mali_timeline_system *system);
344
345 /**
346  * Destroy an empty timeline system.
347  *
348  * @note @ref mali_timeline_system_abort() should be called prior to this function.
349  *
350  * @param system Timeline system to destroy.
351  */
352 void mali_timeline_system_destroy(struct mali_timeline_system *system);
353
354 /**
355  * Stop the soft job timer.
356  *
357  * @param system Timeline system
358  */
359 void mali_timeline_system_stop_timer(struct mali_timeline_system *system);
360
361 /**
362  * Add a tracker to a timeline system and optionally also on a timeline.
363  *
364  * Once added to the timeline system, the tracker is guaranteed to be activated.  The tracker can be
365  * activated before this function returns.  Thus, it is also possible that the tracker is released
366  * before this function returns, depending on the tracker type.
367  *
368  * @note Tracker must be initialized (@ref mali_timeline_tracker_init) before being added to the
369  * timeline system.
370  *
371  * @param system Timeline system the tracker will be added to.
372  * @param tracker The tracker to be added.
373  * @param timeline_id Id of the timeline the tracker will be added to, or
374  *                    MALI_TIMELINE_NONE if it should not be added on a timeline.
375  * @return Point on timeline identifying this tracker, or MALI_TIMELINE_NO_POINT if not on timeline.
376  */
377 mali_timeline_point mali_timeline_system_add_tracker(struct mali_timeline_system *system,
378                 struct mali_timeline_tracker *tracker,
379                 enum mali_timeline_id timeline_id);
380
381 /**
382  * Get latest point on timeline.
383  *
384  * @param system Timeline system.
385  * @param timeline_id Id of timeline to get latest point from.
386  * @return Latest point on timeline, or MALI_TIMELINE_NO_POINT if the timeline is empty.
387  */
388 mali_timeline_point mali_timeline_system_get_latest_point(struct mali_timeline_system *system,
389                 enum mali_timeline_id timeline_id);
390
391 /**
392  * Initialize tracker.
393  *
394  * Must be called before tracker is added to timeline system (@ref mali_timeline_system_add_tracker).
395  *
396  * @param tracker Tracker to initialize.
397  * @param type Type of tracker.
398  * @param fence Fence used to set up dependencies for tracker.
399  * @param job Pointer to job struct this tracker is associated with.
400  */
401 void mali_timeline_tracker_init(struct mali_timeline_tracker *tracker,
402                                 mali_timeline_tracker_type type,
403                                 struct mali_timeline_fence *fence,
404                                 void *job);
405
406 /**
407  * Grab trigger ref count on tracker.
408  *
409  * This will prevent tracker from being activated until the trigger ref count reaches zero.
410  *
411  * @note Tracker must have been initialized (@ref mali_timeline_tracker_init).
412  *
413  * @param system Timeline system.
414  * @param tracker Tracker.
415  */
416 void mali_timeline_system_tracker_get(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker);
417
418 /**
419  * Release trigger ref count on tracker.
420  *
421  * If the trigger ref count reaches zero, the tracker will be activated.
422  *
423  * @param system Timeline system.
424  * @param tracker Tracker.
425  * @param activation_error Error bitmask if activated with error, or MALI_TIMELINE_ACTIVATION_ERROR_NONE if no error.
426  * @return Scheduling bitmask.
427  */
428 mali_scheduler_mask mali_timeline_system_tracker_put(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker, mali_timeline_activation_error activation_error);
429
430 /**
431  * Release a tracker from the timeline system.
432  *
433  * This is used to signal that the job being tracker is finished, either due to normal circumstances
434  * (job complete/abort) or due to a timeout.
435  *
436  * We may need to schedule some subsystems after a tracker has been released and the returned
437  * bitmask will tell us if it is necessary.  If the return value is non-zero, this value needs to be
438  * sent as an input parameter to @ref mali_scheduler_schedule_from_mask() to do the scheduling.
439  *
440  * @note Tracker must have been activated before being released.
441  * @warning Not calling @ref mali_scheduler_schedule_from_mask() after releasing a tracker can lead
442  * to a deadlock.
443  *
444  * @param tracker Tracker being released.
445  * @return Scheduling bitmask.
446  */
447 mali_scheduler_mask mali_timeline_tracker_release(struct mali_timeline_tracker *tracker);
448
449 MALI_STATIC_INLINE mali_bool mali_timeline_tracker_activation_error(
450         struct mali_timeline_tracker *tracker)
451 {
452         MALI_DEBUG_ASSERT_POINTER(tracker);
453         return (MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT &
454                 tracker->activation_error) ? MALI_TRUE : MALI_FALSE;
455 }
456
457 /**
458  * Copy data from a UK fence to a Timeline fence.
459  *
460  * @param fence Timeline fence.
461  * @param uk_fence UK fence.
462  */
463 void mali_timeline_fence_copy_uk_fence(struct mali_timeline_fence *fence, _mali_uk_fence_t *uk_fence);
464
465 void mali_timeline_initialize(void);
466
467 void mali_timeline_terminate(void);
468
469 MALI_STATIC_INLINE mali_bool mali_timeline_has_gp_job(void)
470 {
471         return 0 < _mali_osk_atomic_read(&gp_tracker_count);
472 }
473
474 MALI_STATIC_INLINE mali_bool mali_timeline_has_physical_pp_job(void)
475 {
476         return 0 < _mali_osk_atomic_read(&phy_pp_tracker_count);
477 }
478
479 MALI_STATIC_INLINE mali_bool mali_timeline_has_virtual_pp_job(void)
480 {
481         return 0 < _mali_osk_atomic_read(&virt_pp_tracker_count);
482 }
483
484 #if defined(DEBUG)
485 #define MALI_TIMELINE_DEBUG_FUNCTIONS
486 #endif /* DEBUG */
487 #if defined(MALI_TIMELINE_DEBUG_FUNCTIONS)
488
489 /**
490  * Tracker state.  Used for debug printing.
491  */
492 typedef enum mali_timeline_tracker_state {
493         MALI_TIMELINE_TS_INIT    = 0,
494         MALI_TIMELINE_TS_WAITING = 1,
495         MALI_TIMELINE_TS_ACTIVE  = 2,
496         MALI_TIMELINE_TS_FINISH  = 3,
497 } mali_timeline_tracker_state;
498
499 /**
500  * Get tracker state.
501  *
502  * @param tracker Tracker to check.
503  * @return State of tracker.
504  */
505 mali_timeline_tracker_state mali_timeline_debug_get_tracker_state(struct mali_timeline_tracker *tracker);
506
507 /**
508  * Print debug information about tracker.
509  *
510  * @param tracker Tracker to print.
511  */
512 void mali_timeline_debug_print_tracker(struct mali_timeline_tracker *tracker, _mali_osk_print_ctx *print_ctx);
513
514 /**
515  * Print debug information about timeline.
516  *
517  * @param timeline Timeline to print.
518  */
519 void mali_timeline_debug_print_timeline(struct mali_timeline *timeline, _mali_osk_print_ctx *print_ctx);
520
521 #if !(LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0))
522 void mali_timeline_debug_direct_print_tracker(struct mali_timeline_tracker *tracker);
523 void mali_timeline_debug_direct_print_timeline(struct mali_timeline *timeline);
524 #endif
525
526 /**
527  * Print debug information about timeline system.
528  *
529  * @param system Timeline system to print.
530  */
531 void mali_timeline_debug_print_system(struct mali_timeline_system *system, _mali_osk_print_ctx *print_ctx);
532
533 #endif /* defined(MALI_TIMELINE_DEBUG_FUNCTIONS) */
534
535 #endif /* __MALI_TIMELINE_H__ */