diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index 0713d723996c..cace5bb18027 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -155,6 +155,35 @@ static int kgsl_pool_size_total(void) return total; } +/* + * Returns a page from specified pool only if pool + * currently holds more number of pages than reserved + * pages. + */ +static struct page * +_kgsl_pool_get_nonreserved_page(struct kgsl_page_pool *pool) +{ + struct page *p = NULL; + + spin_lock(&pool->list_lock); + if (pool->page_count <= pool->reserved_pages) { + spin_unlock(&pool->list_lock); + return NULL; + } + + p = list_first_entry_or_null(&pool->page_list, struct page, lru); + if (p == NULL) { + spin_unlock(&pool->list_lock); + return NULL; + } + pool->page_count--; + list_del(&p->lru); + spin_unlock(&pool->list_lock); + mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE, + -(1 << pool->pool_order)); + return p; +} + /* * This will shrink the specified pool by num_pages or by * (page_count - reserved_pages), whichever is smaller. @@ -165,19 +194,21 @@ _kgsl_pool_shrink(struct kgsl_page_pool *pool, { int j; unsigned int pcount = 0; + struct page *(*get_page)(struct kgsl_page_pool *) = + _kgsl_pool_get_nonreserved_page; if (pool == NULL || num_pages == 0) return pcount; - num_pages = num_pages >> pool->pool_order; + num_pages = (num_pages + (1 << pool->pool_order) - 1) >> + pool->pool_order; - /* This is to ensure that we don't free reserved pages */ - if (!exit) - num_pages = min(num_pages, (pool->page_count - - pool->reserved_pages)); + /* This is to ensure that we free reserved pages */ + if (exit) + get_page = _kgsl_pool_get_page; for (j = 0; j < num_pages; j++) { - struct page *page = _kgsl_pool_get_page(pool); + struct page *page = get_page(pool); if (!page) break;