diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_evict.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 187 |
1 files changed, 75 insertions, 112 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 3c1280ec7ff6..f76c06e92677 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c | |||
@@ -33,41 +33,23 @@ | |||
33 | #include "intel_drv.h" | 33 | #include "intel_drv.h" |
34 | #include "i915_trace.h" | 34 | #include "i915_trace.h" |
35 | 35 | ||
36 | static int switch_to_pinned_context(struct drm_i915_private *dev_priv) | 36 | static bool |
37 | gpu_is_idle(struct drm_i915_private *dev_priv) | ||
37 | { | 38 | { |
38 | struct intel_engine_cs *engine; | 39 | struct intel_engine_cs *engine; |
39 | 40 | ||
40 | if (i915.enable_execlists) | ||
41 | return 0; | ||
42 | |||
43 | for_each_engine(engine, dev_priv) { | 41 | for_each_engine(engine, dev_priv) { |
44 | struct drm_i915_gem_request *req; | 42 | if (intel_engine_is_active(engine)) |
45 | int ret; | 43 | return false; |
46 | |||
47 | if (engine->last_context == NULL) | ||
48 | continue; | ||
49 | |||
50 | if (engine->last_context == dev_priv->kernel_context) | ||
51 | continue; | ||
52 | |||
53 | req = i915_gem_request_alloc(engine, dev_priv->kernel_context); | ||
54 | if (IS_ERR(req)) | ||
55 | return PTR_ERR(req); | ||
56 | |||
57 | ret = i915_switch_context(req); | ||
58 | i915_add_request_no_flush(req); | ||
59 | if (ret) | ||
60 | return ret; | ||
61 | } | 44 | } |
62 | 45 | ||
63 | return 0; | 46 | return true; |
64 | } | 47 | } |
65 | 48 | ||
66 | |||
67 | static bool | 49 | static bool |
68 | mark_free(struct i915_vma *vma, struct list_head *unwind) | 50 | mark_free(struct i915_vma *vma, struct list_head *unwind) |
69 | { | 51 | { |
70 | if (vma->pin_count) | 52 | if (i915_vma_is_pinned(vma)) |
71 | return false; | 53 | return false; |
72 | 54 | ||
73 | if (WARN_ON(!list_empty(&vma->exec_list))) | 55 | if (WARN_ON(!list_empty(&vma->exec_list))) |
@@ -79,7 +61,6 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) | |||
79 | 61 | ||
80 | /** | 62 | /** |
81 | * i915_gem_evict_something - Evict vmas to make room for binding a new one | 63 | * i915_gem_evict_something - Evict vmas to make room for binding a new one |
82 | * @dev: drm_device | ||
83 | * @vm: address space to evict from | 64 | * @vm: address space to evict from |
84 | * @min_size: size of the desired free space | 65 | * @min_size: size of the desired free space |
85 | * @alignment: alignment constraint of the desired free space | 66 | * @alignment: alignment constraint of the desired free space |
@@ -102,42 +83,37 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) | |||
102 | * memory in e.g. the shrinker. | 83 | * memory in e.g. the shrinker. |
103 | */ | 84 | */ |
104 | int | 85 | int |
105 | i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, | 86 | i915_gem_evict_something(struct i915_address_space *vm, |
106 | int min_size, unsigned alignment, unsigned cache_level, | 87 | u64 min_size, u64 alignment, |
107 | unsigned long start, unsigned long end, | 88 | unsigned cache_level, |
89 | u64 start, u64 end, | ||
108 | unsigned flags) | 90 | unsigned flags) |
109 | { | 91 | { |
110 | struct list_head eviction_list, unwind_list; | 92 | struct drm_i915_private *dev_priv = to_i915(vm->dev); |
111 | struct i915_vma *vma; | 93 | struct list_head eviction_list; |
112 | int ret = 0; | 94 | struct list_head *phases[] = { |
113 | int pass = 0; | 95 | &vm->inactive_list, |
96 | &vm->active_list, | ||
97 | NULL, | ||
98 | }, **phase; | ||
99 | struct i915_vma *vma, *next; | ||
100 | int ret; | ||
114 | 101 | ||
115 | trace_i915_gem_evict(dev, min_size, alignment, flags); | 102 | trace_i915_gem_evict(vm, min_size, alignment, flags); |
116 | 103 | ||
117 | /* | 104 | /* |
118 | * The goal is to evict objects and amalgamate space in LRU order. | 105 | * The goal is to evict objects and amalgamate space in LRU order. |
119 | * The oldest idle objects reside on the inactive list, which is in | 106 | * The oldest idle objects reside on the inactive list, which is in |
120 | * retirement order. The next objects to retire are those on the (per | 107 | * retirement order. The next objects to retire are those in flight, |
121 | * ring) active list that do not have an outstanding flush. Once the | 108 | * on the active list, again in retirement order. |
122 | * hardware reports completion (the seqno is updated after the | ||
123 | * batchbuffer has been finished) the clean buffer objects would | ||
124 | * be retired to the inactive list. Any dirty objects would be added | ||
125 | * to the tail of the flushing list. So after processing the clean | ||
126 | * active objects we need to emit a MI_FLUSH to retire the flushing | ||
127 | * list, hence the retirement order of the flushing list is in | ||
128 | * advance of the dirty objects on the active lists. | ||
129 | * | 109 | * |
130 | * The retirement sequence is thus: | 110 | * The retirement sequence is thus: |
131 | * 1. Inactive objects (already retired) | 111 | * 1. Inactive objects (already retired) |
132 | * 2. Clean active objects | 112 | * 2. Active objects (will stall on unbinding) |
133 | * 3. Flushing list | ||
134 | * 4. Dirty active objects. | ||
135 | * | 113 | * |
136 | * On each list, the oldest objects lie at the HEAD with the freshest | 114 | * On each list, the oldest objects lie at the HEAD with the freshest |
137 | * object on the TAIL. | 115 | * object on the TAIL. |
138 | */ | 116 | */ |
139 | |||
140 | INIT_LIST_HEAD(&unwind_list); | ||
141 | if (start != 0 || end != vm->total) { | 117 | if (start != 0 || end != vm->total) { |
142 | drm_mm_init_scan_with_range(&vm->mm, min_size, | 118 | drm_mm_init_scan_with_range(&vm->mm, min_size, |
143 | alignment, cache_level, | 119 | alignment, cache_level, |
@@ -145,96 +121,84 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, | |||
145 | } else | 121 | } else |
146 | drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level); | 122 | drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level); |
147 | 123 | ||
148 | search_again: | ||
149 | /* First see if there is a large enough contiguous idle region... */ | ||
150 | list_for_each_entry(vma, &vm->inactive_list, vm_link) { | ||
151 | if (mark_free(vma, &unwind_list)) | ||
152 | goto found; | ||
153 | } | ||
154 | |||
155 | if (flags & PIN_NONBLOCK) | 124 | if (flags & PIN_NONBLOCK) |
156 | goto none; | 125 | phases[1] = NULL; |
157 | 126 | ||
158 | /* Now merge in the soon-to-be-expired objects... */ | 127 | search_again: |
159 | list_for_each_entry(vma, &vm->active_list, vm_link) { | 128 | INIT_LIST_HEAD(&eviction_list); |
160 | if (mark_free(vma, &unwind_list)) | 129 | phase = phases; |
161 | goto found; | 130 | do { |
162 | } | 131 | list_for_each_entry(vma, *phase, vm_link) |
132 | if (mark_free(vma, &eviction_list)) | ||
133 | goto found; | ||
134 | } while (*++phase); | ||
163 | 135 | ||
164 | none: | ||
165 | /* Nothing found, clean up and bail out! */ | 136 | /* Nothing found, clean up and bail out! */ |
166 | while (!list_empty(&unwind_list)) { | 137 | list_for_each_entry_safe(vma, next, &eviction_list, exec_list) { |
167 | vma = list_first_entry(&unwind_list, | ||
168 | struct i915_vma, | ||
169 | exec_list); | ||
170 | ret = drm_mm_scan_remove_block(&vma->node); | 138 | ret = drm_mm_scan_remove_block(&vma->node); |
171 | BUG_ON(ret); | 139 | BUG_ON(ret); |
172 | 140 | ||
173 | list_del_init(&vma->exec_list); | 141 | INIT_LIST_HEAD(&vma->exec_list); |
174 | } | 142 | } |
175 | 143 | ||
176 | /* Can we unpin some objects such as idle hw contents, | 144 | /* Can we unpin some objects such as idle hw contents, |
177 | * or pending flips? | 145 | * or pending flips? But since only the GGTT has global entries |
146 | * such as scanouts, rinbuffers and contexts, we can skip the | ||
147 | * purge when inspecting per-process local address spaces. | ||
178 | */ | 148 | */ |
179 | if (flags & PIN_NONBLOCK) | 149 | if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK) |
180 | return -ENOSPC; | 150 | return -ENOSPC; |
181 | 151 | ||
182 | /* Only idle the GPU and repeat the search once */ | 152 | if (gpu_is_idle(dev_priv)) { |
183 | if (pass++ == 0) { | 153 | /* If we still have pending pageflip completions, drop |
184 | struct drm_i915_private *dev_priv = to_i915(dev); | 154 | * back to userspace to give our workqueues time to |
185 | 155 | * acquire our locks and unpin the old scanouts. | |
186 | if (i915_is_ggtt(vm)) { | 156 | */ |
187 | ret = switch_to_pinned_context(dev_priv); | 157 | return intel_has_pending_fb_unpin(vm->dev) ? -EAGAIN : -ENOSPC; |
188 | if (ret) | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | ret = i915_gem_wait_for_idle(dev_priv); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | i915_gem_retire_requests(dev_priv); | ||
197 | goto search_again; | ||
198 | } | 158 | } |
199 | 159 | ||
200 | /* If we still have pending pageflip completions, drop | 160 | /* Not everything in the GGTT is tracked via vma (otherwise we |
201 | * back to userspace to give our workqueues time to | 161 | * could evict as required with minimal stalling) so we are forced |
202 | * acquire our locks and unpin the old scanouts. | 162 | * to idle the GPU and explicitly retire outstanding requests in |
163 | * the hopes that we can then remove contexts and the like only | ||
164 | * bound by their active reference. | ||
203 | */ | 165 | */ |
204 | return intel_has_pending_fb_unpin(dev) ? -EAGAIN : -ENOSPC; | 166 | ret = i915_gem_switch_to_kernel_context(dev_priv); |
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | ret = i915_gem_wait_for_idle(dev_priv, true); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | i915_gem_retire_requests(dev_priv); | ||
175 | goto search_again; | ||
205 | 176 | ||
206 | found: | 177 | found: |
207 | /* drm_mm doesn't allow any other other operations while | 178 | /* drm_mm doesn't allow any other other operations while |
208 | * scanning, therefore store to be evicted objects on a | 179 | * scanning, therefore store to-be-evicted objects on a |
209 | * temporary list. */ | 180 | * temporary list and take a reference for all before |
210 | INIT_LIST_HEAD(&eviction_list); | 181 | * calling unbind (which may remove the active reference |
211 | while (!list_empty(&unwind_list)) { | 182 | * of any of our objects, thus corrupting the list). |
212 | vma = list_first_entry(&unwind_list, | 183 | */ |
213 | struct i915_vma, | 184 | list_for_each_entry_safe(vma, next, &eviction_list, exec_list) { |
214 | exec_list); | 185 | if (drm_mm_scan_remove_block(&vma->node)) |
215 | if (drm_mm_scan_remove_block(&vma->node)) { | 186 | __i915_vma_pin(vma); |
216 | list_move(&vma->exec_list, &eviction_list); | 187 | else |
217 | drm_gem_object_reference(&vma->obj->base); | 188 | list_del_init(&vma->exec_list); |
218 | continue; | ||
219 | } | ||
220 | list_del_init(&vma->exec_list); | ||
221 | } | 189 | } |
222 | 190 | ||
223 | /* Unbinding will emit any required flushes */ | 191 | /* Unbinding will emit any required flushes */ |
224 | while (!list_empty(&eviction_list)) { | 192 | while (!list_empty(&eviction_list)) { |
225 | struct drm_gem_object *obj; | ||
226 | vma = list_first_entry(&eviction_list, | 193 | vma = list_first_entry(&eviction_list, |
227 | struct i915_vma, | 194 | struct i915_vma, |
228 | exec_list); | 195 | exec_list); |
229 | 196 | ||
230 | obj = &vma->obj->base; | ||
231 | list_del_init(&vma->exec_list); | 197 | list_del_init(&vma->exec_list); |
198 | __i915_vma_unpin(vma); | ||
232 | if (ret == 0) | 199 | if (ret == 0) |
233 | ret = i915_vma_unbind(vma); | 200 | ret = i915_vma_unbind(vma); |
234 | |||
235 | drm_gem_object_unreference(obj); | ||
236 | } | 201 | } |
237 | |||
238 | return ret; | 202 | return ret; |
239 | } | 203 | } |
240 | 204 | ||
@@ -256,8 +220,8 @@ i915_gem_evict_for_vma(struct i915_vma *target) | |||
256 | 220 | ||
257 | vma = container_of(node, typeof(*vma), node); | 221 | vma = container_of(node, typeof(*vma), node); |
258 | 222 | ||
259 | if (vma->pin_count) { | 223 | if (i915_vma_is_pinned(vma)) { |
260 | if (!vma->exec_entry || (vma->pin_count > 1)) | 224 | if (!vma->exec_entry || i915_vma_pin_count(vma) > 1) |
261 | /* Object is pinned for some other use */ | 225 | /* Object is pinned for some other use */ |
262 | return -EBUSY; | 226 | return -EBUSY; |
263 | 227 | ||
@@ -303,22 +267,21 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) | |||
303 | struct drm_i915_private *dev_priv = to_i915(vm->dev); | 267 | struct drm_i915_private *dev_priv = to_i915(vm->dev); |
304 | 268 | ||
305 | if (i915_is_ggtt(vm)) { | 269 | if (i915_is_ggtt(vm)) { |
306 | ret = switch_to_pinned_context(dev_priv); | 270 | ret = i915_gem_switch_to_kernel_context(dev_priv); |
307 | if (ret) | 271 | if (ret) |
308 | return ret; | 272 | return ret; |
309 | } | 273 | } |
310 | 274 | ||
311 | ret = i915_gem_wait_for_idle(dev_priv); | 275 | ret = i915_gem_wait_for_idle(dev_priv, true); |
312 | if (ret) | 276 | if (ret) |
313 | return ret; | 277 | return ret; |
314 | 278 | ||
315 | i915_gem_retire_requests(dev_priv); | 279 | i915_gem_retire_requests(dev_priv); |
316 | |||
317 | WARN_ON(!list_empty(&vm->active_list)); | 280 | WARN_ON(!list_empty(&vm->active_list)); |
318 | } | 281 | } |
319 | 282 | ||
320 | list_for_each_entry_safe(vma, next, &vm->inactive_list, vm_link) | 283 | list_for_each_entry_safe(vma, next, &vm->inactive_list, vm_link) |
321 | if (vma->pin_count == 0) | 284 | if (!i915_vma_is_pinned(vma)) |
322 | WARN_ON(i915_vma_unbind(vma)); | 285 | WARN_ON(i915_vma_unbind(vma)); |
323 | 286 | ||
324 | return 0; | 287 | return 0; |