1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2016-2018 Intel Corporation
5  */
6 
7 #include "i915_drv.h"
8 
9 #include "i915_timeline.h"
10 #include "i915_syncmap.h"
11 
i915_timeline_init(struct drm_i915_private * i915,struct i915_timeline * timeline,const char * name)12 void i915_timeline_init(struct drm_i915_private *i915,
13 			struct i915_timeline *timeline,
14 			const char *name)
15 {
16 	lockdep_assert_held(&i915->drm.struct_mutex);
17 
18 	/*
19 	 * Ideally we want a set of engines on a single leaf as we expect
20 	 * to mostly be tracking synchronisation between engines. It is not
21 	 * a huge issue if this is not the case, but we may want to mitigate
22 	 * any page crossing penalties if they become an issue.
23 	 */
24 	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
25 
26 	timeline->name = name;
27 
28 	list_add(&timeline->link, &i915->gt.timelines);
29 
30 	/* Called during early_init before we know how many engines there are */
31 
32 	timeline->fence_context = dma_fence_context_alloc(1);
33 
34 	spin_lock_init(&timeline->lock);
35 
36 	init_request_active(&timeline->last_request, NULL);
37 	INIT_LIST_HEAD(&timeline->requests);
38 
39 	i915_syncmap_init(&timeline->sync);
40 }
41 
42 /**
43  * i915_timelines_park - called when the driver idles
44  * @i915: the drm_i915_private device
45  *
46  * When the driver is completely idle, we know that all of our sync points
47  * have been signaled and our tracking is then entirely redundant. Any request
48  * to wait upon an older sync point will be completed instantly as we know
49  * the fence is signaled and therefore we will not even look them up in the
50  * sync point map.
51  */
i915_timelines_park(struct drm_i915_private * i915)52 void i915_timelines_park(struct drm_i915_private *i915)
53 {
54 	struct i915_timeline *timeline;
55 
56 	lockdep_assert_held(&i915->drm.struct_mutex);
57 
58 	list_for_each_entry(timeline, &i915->gt.timelines, link) {
59 		/*
60 		 * All known fences are completed so we can scrap
61 		 * the current sync point tracking and start afresh,
62 		 * any attempt to wait upon a previous sync point
63 		 * will be skipped as the fence was signaled.
64 		 */
65 		i915_syncmap_free(&timeline->sync);
66 	}
67 }
68 
i915_timeline_fini(struct i915_timeline * timeline)69 void i915_timeline_fini(struct i915_timeline *timeline)
70 {
71 	GEM_BUG_ON(!list_empty(&timeline->requests));
72 
73 	i915_syncmap_free(&timeline->sync);
74 
75 	list_del(&timeline->link);
76 }
77 
78 struct i915_timeline *
i915_timeline_create(struct drm_i915_private * i915,const char * name)79 i915_timeline_create(struct drm_i915_private *i915, const char *name)
80 {
81 	struct i915_timeline *timeline;
82 
83 	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
84 	if (!timeline)
85 		return ERR_PTR(-ENOMEM);
86 
87 	i915_timeline_init(i915, timeline, name);
88 	kref_init(&timeline->kref);
89 
90 	return timeline;
91 }
92 
__i915_timeline_free(struct kref * kref)93 void __i915_timeline_free(struct kref *kref)
94 {
95 	struct i915_timeline *timeline =
96 		container_of(kref, typeof(*timeline), kref);
97 
98 	i915_timeline_fini(timeline);
99 	kfree(timeline);
100 }
101 
102 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
103 #include "selftests/mock_timeline.c"
104 #include "selftests/i915_timeline.c"
105 #endif
106