@@ -2120,45 +2120,70 @@ i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size,
unsigned alignment, int *found)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
- struct drm_gem_object *best = NULL;
- struct drm_gem_object *first = NULL;
+ struct list_head eviction_list;
+ struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
+ int ret = 0;
+
+ INIT_LIST_HEAD(&eviction_list);
+ *found = 0;
+
+ drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
- /* Try to find the smallest clean object */
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
- struct drm_gem_object *obj = &obj_priv->base;
- if (obj->size >= min_size) {
- if ((!obj_priv->dirty ||
- i915_gem_object_is_purgeable(obj_priv)) &&
- (!best || obj->size < best->size)) {
- best = obj;
- if (best->size == min_size)
- break;
- }
- if (!first)
- first = obj;
- }
+ *found = drm_mm_scan_add_block(obj_priv->gtt_space);
+
+ if (*found)
+ break;
}
- obj = best ? best : first;
+ if (!*found) {
+ /* Nothing found, clean up and bail out! */
+ list_for_each_entry_safe_reverse(obj_priv, tmp_obj_priv,
+ &dev_priv->mm.inactive_list,
+ list) {
+ ret = drm_mm_scan_remove_block(obj_priv->gtt_space);
+
+ BUG_ON(ret);
+ }
- if (!obj) {
- *found = 0;
return 0;
}
- *found = 1;
+ list_for_each_entry_safe_from_reverse(obj_priv, tmp_obj_priv,
+ &dev_priv->mm.inactive_list,
+ list) {
+ if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
+ /* drm_mm doesn't allow any other other operations while
+ * scanning, therefore store to be evicted objects on a
+ * temporary list. */
+ list_move(&obj_priv->list, &eviction_list);
+ }
+ }
+ list_for_each_entry_safe(obj_priv, tmp_obj_priv,
+ &eviction_list, list) {
#if WATCH_LRU
- DRM_INFO("%s: evicting %p\n", __func__, obj);
+ DRM_INFO("%s: evicting %p\n", __func__, obj);
#endif
- obj_priv = to_intel_bo(obj);
- BUG_ON(obj_priv->pin_count != 0);
- BUG_ON(obj_priv->active);
+ ret = i915_gem_object_unbind(&obj_priv->base);
+
+ if (ret != 0)
+ goto fail;
+ }
- /* Wait on the rendering and unbind the buffer. */
- return i915_gem_object_unbind(obj);
+ /* The just created free hole should be on the top of the free stack
+ * maintained by drm_mm, so this BUG_ON actually executes in O(1).
+ * Furthermore all accessed data has just recently been used, so it
+ * should be really fast, too. */
+ BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
+ alignment, 0));
+
+ return 0;
+
+fail:
+ list_splice(&eviction_list, &dev_priv->mm.inactive_list);
+
+ return ret;
}
static int