diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_evict.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_evict.c | 132 |
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 | ||
34 | static bool | 34 | static bool |
35 | mark_free(struct drm_i915_gem_object *obj_priv, | 35 | mark_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 | ||
43 | int | 42 | int |
44 | i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment) | 43 | i915_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 | ||
159 | int | 179 | int |
160 | i915_gem_evict_everything(struct drm_device *dev) | 180 | i915_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. */ |
192 | int | 203 | int |
193 | i915_gem_evict_inactive(struct drm_device *dev) | 204 | i915_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 | ||