aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem_evict.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_evict.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c187
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
36static int switch_to_pinned_context(struct drm_i915_private *dev_priv) 36static bool
37gpu_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
67static bool 49static bool
68mark_free(struct i915_vma *vma, struct list_head *unwind) 50mark_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 */
104int 85int
105i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm, 86i915_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
148search_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... */ 127search_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
164none:
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
206found: 177found:
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;