---
 drivers/gpu/drm/i915/i915_dma.c          |    4 -
 drivers/gpu/drm/i915/i915_gem.c          |   78 +++++++++----------------------
 drivers/gpu/drm/ttm/ttm_page_alloc.c     |   43 ++++++-----------
 drivers/gpu/drm/ttm/ttm_page_alloc_dma.c |   49 +++++++------------
 4 files changed, 61 insertions(+), 113 deletions(-)

--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1699,7 +1699,7 @@ int i915_driver_load(struct drm_device *
 	return 0;
 
 out_gem_unload:
-	if (dev_priv->mm.inactive_shrinker.scan_objects)
+	if (dev_priv->mm.inactive_shrinker.shrink)
 		unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
 	if (dev->pdev->msi_enabled)
@@ -1744,7 +1744,7 @@ int i915_driver_unload(struct drm_device
 
 	i915_teardown_sysfs(dev);
 
-	if (dev_priv->mm.inactive_shrinker.scan_objects)
+	if (dev_priv->mm.inactive_shrinker.shrink)
 		unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
 	mutex_lock(&dev->struct_mutex);
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -57,12 +57,10 @@ static void i915_gem_object_update_fence
 					 struct drm_i915_fence_reg *fence,
 					 bool enable);
 
-static unsigned long i915_gem_inactive_count(struct shrinker *shrinker,
-					     struct shrink_control *sc);
-static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker,
-					    struct shrink_control *sc);
+static int i915_gem_inactive_shrink(struct shrinker *shrinker,
+				    struct shrink_control *sc);
 static long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
-static long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
+static void i915_gem_shrink_all(struct drm_i915_private *dev_priv);
 static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
@@ -1782,21 +1780,16 @@ i915_gem_purge(struct drm_i915_private *
 	return __i915_gem_shrink(dev_priv, target, true);
 }
 
-static long
+static void
 i915_gem_shrink_all(struct drm_i915_private *dev_priv)
 {
 	struct drm_i915_gem_object *obj, *next;
-	long freed = 0;
 
 	i915_gem_evict_everything(dev_priv->dev);
 
 	list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
-				 global_list) {
-		if (obj->pages_pin_count == 0)
-			freed += obj->base.size >> PAGE_SHIFT;
+				 global_list)
 		i915_gem_object_put_pages(obj);
-	}
-	return freed;
 }
 
 static int
@@ -4589,8 +4582,7 @@ i915_gem_load(struct drm_device *dev)
 
 	dev_priv->mm.interruptible = true;
 
-	dev_priv->mm.inactive_shrinker.scan_objects = i915_gem_inactive_scan;
-	dev_priv->mm.inactive_shrinker.count_objects = i915_gem_inactive_count;
+	dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink;
 	dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS;
 	register_shrinker(&dev_priv->mm.inactive_shrinker);
 }
@@ -4813,8 +4805,8 @@ static bool mutex_is_locked_by(struct mu
 #endif
 }
 
-static unsigned long
-i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
+static int
+i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
 {
 	struct drm_i915_private *dev_priv =
 		container_of(shrinker,
@@ -4822,8 +4814,9 @@ i915_gem_inactive_count(struct shrinker
 			     mm.inactive_shrinker);
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_i915_gem_object *obj;
+	int nr_to_scan = sc->nr_to_scan;
 	bool unlock = true;
-	unsigned long count;
+	int cnt;
 
 	if (!mutex_trylock(&dev->struct_mutex)) {
 		if (!mutex_is_locked_by(&dev->struct_mutex, current))
@@ -4835,22 +4828,31 @@ i915_gem_inactive_count(struct shrinker
 		unlock = false;
 	}
 
-	count = 0;
+	if (nr_to_scan) {
+		nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
+		if (nr_to_scan > 0)
+			nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan,
+							false);
+		if (nr_to_scan > 0)
+			i915_gem_shrink_all(dev_priv);
+	}
+
+	cnt = 0;
 	list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
 		if (obj->pages_pin_count == 0)
-			count += obj->base.size >> PAGE_SHIFT;
+			cnt += obj->base.size >> PAGE_SHIFT;
 
 	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
 		if (obj->active)
 			continue;
 
 		if (obj->pin_count == 0 && obj->pages_pin_count == 0)
-			count += obj->base.size >> PAGE_SHIFT;
+			cnt += obj->base.size >> PAGE_SHIFT;
 	}
 
 	if (unlock)
 		mutex_unlock(&dev->struct_mutex);
-	return count;
+	return cnt;
 }
 
 /* All the new VM stuff */
@@ -4914,40 +4916,6 @@ unsigned long i915_gem_obj_size(struct d
 	return 0;
 }
 
-static unsigned long
-i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc)
-{
-	struct drm_i915_private *dev_priv =
-		container_of(shrinker,
-			     struct drm_i915_private,
-			     mm.inactive_shrinker);
-	struct drm_device *dev = dev_priv->dev;
-	int nr_to_scan = sc->nr_to_scan;
-	unsigned long freed;
-	bool unlock = true;
-
-	if (!mutex_trylock(&dev->struct_mutex)) {
-		if (!mutex_is_locked_by(&dev->struct_mutex, current))
-			return SHRINK_STOP;
-
-		if (dev_priv->mm.shrinker_no_lock_stealing)
-			return SHRINK_STOP;
-
-		unlock = false;
-	}
-
-	freed = i915_gem_purge(dev_priv, nr_to_scan);
-	if (freed < nr_to_scan)
-		freed += __i915_gem_shrink(dev_priv, nr_to_scan,
-							false);
-	if (freed < nr_to_scan)
-		freed += i915_gem_shrink_all(dev_priv);
-
-	if (unlock)
-		mutex_unlock(&dev->struct_mutex);
-	return freed;
-}
-
 struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 				     struct i915_address_space *vm)
 {
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -378,17 +378,22 @@ out:
 	return nr_free;
 }
 
+/* Get good estimation how many pages are free in pools */
+static int ttm_pool_get_num_unused_pages(void)
+{
+	unsigned i;
+	int total = 0;
+	for (i = 0; i < NUM_POOLS; ++i)
+		total += _manager->pools[i].npages;
+
+	return total;
+}
+
 /**
  * Callback for mm to request pool to reduce number of page held.
- *
- * XXX: (dchinner) Deadlock warning!
- *
- * We need to pass sc->gfp_mask to ttm_page_pool_free().
- *
- * This code is crying out for a shrinker per pool....
  */
-static unsigned long
-ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+static int ttm_pool_mm_shrink(struct shrinker *shrink,
+			      struct shrink_control *sc)
 {
 	static DEFINE_MUTEX(lock);
 	static unsigned start_pool;
@@ -396,7 +401,6 @@ ttm_pool_shrink_scan(struct shrinker *sh
 	unsigned pool_offset;
 	struct ttm_page_pool *pool;
 	int shrink_pages = sc->nr_to_scan;
-	unsigned long freed = 0;
 
 	if (!mutex_trylock(&lock))
 		return SHRINK_STOP;
@@ -409,29 +413,16 @@ ttm_pool_shrink_scan(struct shrinker *sh
 		pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
 		shrink_pages = ttm_page_pool_free(pool, nr_free,
 						  sc->gfp_mask);
-		freed += nr_free - shrink_pages;
+
 	}
 	mutex_unlock(&lock);
-	return freed;
-}
-
-
-static unsigned long
-ttm_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
-{
-	unsigned i;
-	unsigned long count = 0;
-
-	for (i = 0; i < NUM_POOLS; ++i)
-		count += _manager->pools[i].npages;
-
-	return count;
+	/* return estimated number of unused pages in pool */
+	return ttm_pool_get_num_unused_pages();
 }
 
 static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager)
 {
-	manager->mm_shrink.count_objects = ttm_pool_shrink_count;
-	manager->mm_shrink.scan_objects = ttm_pool_shrink_scan;
+	manager->mm_shrink.shrink = &ttm_pool_mm_shrink;
 	manager->mm_shrink.seeks = 1;
 	register_shrinker(&manager->mm_shrink);
 }
--- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
@@ -919,6 +919,19 @@ int ttm_dma_populate(struct ttm_dma_tt *
 }
 EXPORT_SYMBOL_GPL(ttm_dma_populate);
 
+/* Get good estimation how many pages are free in pools */
+static int ttm_dma_pool_get_num_unused_pages(void)
+{
+	struct device_pools *p;
+	unsigned total = 0;
+
+	mutex_lock(&_manager->lock);
+	list_for_each_entry(p, &_manager->pools, pools)
+		total += p->pool->npages_free;
+	mutex_unlock(&_manager->lock);
+	return total;
+}
+
 /* Put all pages in pages list to correct pool to wait for reuse */
 void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 {
@@ -990,26 +1003,18 @@ EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
 
 /**
  * Callback for mm to request pool to reduce number of page held.
- *
- * XXX: (dchinner) Deadlock warning!
- *
- * We need to pass sc->gfp_mask to ttm_dma_page_pool_free().
- *
- * I'm getting sadder as I hear more pathetical whimpers about needing per-pool
- * shrinkers
  */
-static unsigned long
-ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+static int ttm_dma_pool_mm_shrink(struct shrinker *shrink,
+				  struct shrink_control *sc)
 {
 	static unsigned start_pool;
 	unsigned idx = 0;
 	unsigned pool_offset;
 	unsigned shrink_pages = sc->nr_to_scan;
 	struct device_pools *p;
-	unsigned long freed = 0;
 
 	if (list_empty(&_manager->pools))
-		return SHRINK_STOP;
+		return 0;
 
 	if (!mutex_trylock(&_manager->lock))
 		return SHRINK_STOP;
@@ -1029,35 +1034,19 @@ ttm_dma_pool_shrink_scan(struct shrinker
 		nr_free = shrink_pages;
 		shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free,
 						      sc->gfp_mask);
-		freed += nr_free - shrink_pages;
-
 		pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
 			 p->pool->dev_name, p->pool->name, current->pid,
 			 nr_free, shrink_pages);
 	}
 out:
 	mutex_unlock(&_manager->lock);
-	return freed;
-}
-
-static unsigned long
-ttm_dma_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
-{
-	struct device_pools *p;
-	unsigned long count = 0;
-
-	if (!mutex_trylock(&_manager->lock))
-		return 0;
-	list_for_each_entry(p, &_manager->pools, pools)
-		count += p->pool->npages_free;
-	mutex_unlock(&_manager->lock);
-	return count;
+	/* return estimated number of unused pages in pool */
+	return ttm_dma_pool_get_num_unused_pages();
 }
 
 static void ttm_dma_pool_mm_shrink_init(struct ttm_pool_manager *manager)
 {
-	manager->mm_shrink.count_objects = ttm_dma_pool_shrink_count;
-	manager->mm_shrink.scan_objects = &ttm_dma_pool_shrink_scan;
+	manager->mm_shrink.shrink = &ttm_dma_pool_mm_shrink;
 	manager->mm_shrink.seeks = 1;
 	register_shrinker(&manager->mm_shrink);
 }
