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.c132
1 files changed, 69 insertions, 63 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index d8ae7d1d0cc6..3d39005540aa 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -32,28 +32,36 @@
32#include "i915_drm.h" 32#include "i915_drm.h"
33 33
34static bool 34static bool
35mark_free(struct drm_i915_gem_object *obj_priv, 35mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
36 struct list_head *unwind)
37{ 36{
38 list_add(&obj_priv->evict_list, unwind); 37 list_add(&obj->exec_list, unwind);
39 drm_gem_object_reference(&obj_priv->base); 38 drm_gem_object_reference(&obj->base);
40 return drm_mm_scan_add_block(obj_priv->gtt_space); 39 return drm_mm_scan_add_block(obj->gtt_space);
41} 40}
42 41
43int 42int
44i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment) 43i915_gem_evict_something(struct drm_device *dev, int min_size,
44 unsigned alignment, bool mappable)
45{ 45{
46 drm_i915_private_t *dev_priv = dev->dev_private; 46 drm_i915_private_t *dev_priv = dev->dev_private;
47 struct list_head eviction_list, unwind_list; 47 struct list_head eviction_list, unwind_list;
48 struct drm_i915_gem_object *obj_priv; 48 struct drm_i915_gem_object *obj;
49 int ret = 0; 49 int ret = 0;
50 50
51 i915_gem_retire_requests(dev); 51 i915_gem_retire_requests(dev);
52 52
53 /* Re-check for free space after retiring requests */ 53 /* Re-check for free space after retiring requests */
54 if (drm_mm_search_free(&dev_priv->mm.gtt_space, 54 if (mappable) {
55 min_size, alignment, 0)) 55 if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
56 return 0; 56 min_size, alignment, 0,
57 dev_priv->mm.gtt_mappable_end,
58 0))
59 return 0;
60 } else {
61 if (drm_mm_search_free(&dev_priv->mm.gtt_space,
62 min_size, alignment, 0))
63 return 0;
64 }
57 65
58 /* 66 /*
59 * The goal is to evict objects and amalgamate space in LRU order. 67 * The goal is to evict objects and amalgamate space in LRU order.
@@ -79,45 +87,56 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
79 */ 87 */
80 88
81 INIT_LIST_HEAD(&unwind_list); 89 INIT_LIST_HEAD(&unwind_list);
82 drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); 90 if (mappable)
91 drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size,
92 alignment, 0,
93 dev_priv->mm.gtt_mappable_end);
94 else
95 drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
83 96
84 /* First see if there is a large enough contiguous idle region... */ 97 /* First see if there is a large enough contiguous idle region... */
85 list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) { 98 list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
86 if (mark_free(obj_priv, &unwind_list)) 99 if (mark_free(obj, &unwind_list))
87 goto found; 100 goto found;
88 } 101 }
89 102
90 /* Now merge in the soon-to-be-expired objects... */ 103 /* Now merge in the soon-to-be-expired objects... */
91 list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { 104 list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
92 /* Does the object require an outstanding flush? */ 105 /* Does the object require an outstanding flush? */
93 if (obj_priv->base.write_domain || obj_priv->pin_count) 106 if (obj->base.write_domain || obj->pin_count)
94 continue; 107 continue;
95 108
96 if (mark_free(obj_priv, &unwind_list)) 109 if (mark_free(obj, &unwind_list))
97 goto found; 110 goto found;
98 } 111 }
99 112
100 /* Finally add anything with a pending flush (in order of retirement) */ 113 /* Finally add anything with a pending flush (in order of retirement) */
101 list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) { 114 list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
102 if (obj_priv->pin_count) 115 if (obj->pin_count)
103 continue; 116 continue;
104 117
105 if (mark_free(obj_priv, &unwind_list)) 118 if (mark_free(obj, &unwind_list))
106 goto found; 119 goto found;
107 } 120 }
108 list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { 121 list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
109 if (! obj_priv->base.write_domain || obj_priv->pin_count) 122 if (! obj->base.write_domain || obj->pin_count)
110 continue; 123 continue;
111 124
112 if (mark_free(obj_priv, &unwind_list)) 125 if (mark_free(obj, &unwind_list))
113 goto found; 126 goto found;
114 } 127 }
115 128
116 /* Nothing found, clean up and bail out! */ 129 /* Nothing found, clean up and bail out! */
117 list_for_each_entry(obj_priv, &unwind_list, evict_list) { 130 while (!list_empty(&unwind_list)) {
118 ret = drm_mm_scan_remove_block(obj_priv->gtt_space); 131 obj = list_first_entry(&unwind_list,
132 struct drm_i915_gem_object,
133 exec_list);
134
135 ret = drm_mm_scan_remove_block(obj->gtt_space);
119 BUG_ON(ret); 136 BUG_ON(ret);
120 drm_gem_object_unreference(&obj_priv->base); 137
138 list_del_init(&obj->exec_list);
139 drm_gem_object_unreference(&obj->base);
121 } 140 }
122 141
123 /* We expect the caller to unpin, evict all and try again, or give up. 142 /* We expect the caller to unpin, evict all and try again, or give up.
@@ -131,33 +150,34 @@ found:
131 * temporary list. */ 150 * temporary list. */
132 INIT_LIST_HEAD(&eviction_list); 151 INIT_LIST_HEAD(&eviction_list);
133 while (!list_empty(&unwind_list)) { 152 while (!list_empty(&unwind_list)) {
134 obj_priv = list_first_entry(&unwind_list, 153 obj = list_first_entry(&unwind_list,
135 struct drm_i915_gem_object, 154 struct drm_i915_gem_object,
136 evict_list); 155 exec_list);
137 if (drm_mm_scan_remove_block(obj_priv->gtt_space)) { 156 if (drm_mm_scan_remove_block(obj->gtt_space)) {
138 list_move(&obj_priv->evict_list, &eviction_list); 157 list_move(&obj->exec_list, &eviction_list);
139 continue; 158 continue;
140 } 159 }
141 list_del(&obj_priv->evict_list); 160 list_del_init(&obj->exec_list);
142 drm_gem_object_unreference(&obj_priv->base); 161 drm_gem_object_unreference(&obj->base);
143 } 162 }
144 163
145 /* Unbinding will emit any required flushes */ 164 /* Unbinding will emit any required flushes */
146 while (!list_empty(&eviction_list)) { 165 while (!list_empty(&eviction_list)) {
147 obj_priv = list_first_entry(&eviction_list, 166 obj = list_first_entry(&eviction_list,
148 struct drm_i915_gem_object, 167 struct drm_i915_gem_object,
149 evict_list); 168 exec_list);
150 if (ret == 0) 169 if (ret == 0)
151 ret = i915_gem_object_unbind(&obj_priv->base); 170 ret = i915_gem_object_unbind(obj);
152 list_del(&obj_priv->evict_list); 171
153 drm_gem_object_unreference(&obj_priv->base); 172 list_del_init(&obj->exec_list);
173 drm_gem_object_unreference(&obj->base);
154 } 174 }
155 175
156 return ret; 176 return ret;
157} 177}
158 178
159int 179int
160i915_gem_evict_everything(struct drm_device *dev) 180i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
161{ 181{
162 drm_i915_private_t *dev_priv = dev->dev_private; 182 drm_i915_private_t *dev_priv = dev->dev_private;
163 int ret; 183 int ret;
@@ -176,36 +196,22 @@ i915_gem_evict_everything(struct drm_device *dev)
176 196
177 BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); 197 BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
178 198
179 ret = i915_gem_evict_inactive(dev); 199 return i915_gem_evict_inactive(dev, purgeable_only);
180 if (ret)
181 return ret;
182
183 lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
184 list_empty(&dev_priv->mm.flushing_list) &&
185 list_empty(&dev_priv->mm.active_list));
186 BUG_ON(!lists_empty);
187
188 return 0;
189} 200}
190 201
191/** Unbinds all inactive objects. */ 202/** Unbinds all inactive objects. */
192int 203int
193i915_gem_evict_inactive(struct drm_device *dev) 204i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only)
194{ 205{
195 drm_i915_private_t *dev_priv = dev->dev_private; 206 drm_i915_private_t *dev_priv = dev->dev_private;
196 207 struct drm_i915_gem_object *obj, *next;
197 while (!list_empty(&dev_priv->mm.inactive_list)) { 208
198 struct drm_gem_object *obj; 209 list_for_each_entry_safe(obj, next,
199 int ret; 210 &dev_priv->mm.inactive_list, mm_list) {
200 211 if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
201 obj = &list_first_entry(&dev_priv->mm.inactive_list, 212 int ret = i915_gem_object_unbind(obj);
202 struct drm_i915_gem_object, 213 if (ret)
203 mm_list)->base; 214 return ret;
204
205 ret = i915_gem_object_unbind(obj);
206 if (ret != 0) {
207 DRM_ERROR("Error unbinding object: %d\n", ret);
208 return ret;
209 } 215 }
210 } 216 }
211 217