ion_page_pool.c revision efee5a0c62d827c0eca7044c2d14dd3324b325aa
1/* 2 * drivers/staging/android/ion/ion_mem_pool.c 3 * 4 * Copyright (C) 2011 Google, Inc. 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17#include <linux/dma-mapping.h> 18#include <linux/err.h> 19#include <linux/list.h> 20#include <linux/slab.h> 21#include <linux/shrinker.h> 22#include "ion_priv.h" 23 24struct ion_page_pool_item { 25 struct page *page; 26 struct list_head list; 27}; 28 29static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) 30{ 31 struct page *page = alloc_pages(pool->gfp_mask, pool->order); 32 33 if (!page) 34 return NULL; 35 /* this is only being used to flush the page for dma, 36 this api is not really suitable for calling from a driver 37 but no better way to flush a page for dma exist at this time */ 38 __dma_page_cpu_to_dev(page, 0, PAGE_SIZE << pool->order, 39 DMA_BIDIRECTIONAL); 40 return page; 41} 42 43static void ion_page_pool_free_pages(struct ion_page_pool *pool, 44 struct page *page) 45{ 46 __free_pages(page, pool->order); 47} 48 49static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) 50{ 51 struct ion_page_pool_item *item; 52 53 item = kmalloc(sizeof(struct ion_page_pool_item), GFP_KERNEL); 54 if (!item) 55 return -ENOMEM; 56 57 mutex_lock(&pool->mutex); 58 item->page = page; 59 if (PageHighMem(page)) { 60 list_add_tail(&item->list, &pool->high_items); 61 pool->high_count++; 62 } else { 63 list_add_tail(&item->list, &pool->low_items); 64 pool->low_count++; 65 } 66 mutex_unlock(&pool->mutex); 67 return 0; 68} 69 70static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) 71{ 72 struct ion_page_pool_item *item; 73 struct page *page; 74 75 if (high) { 76 BUG_ON(!pool->high_count); 77 item = list_first_entry(&pool->high_items, 78 struct ion_page_pool_item, list); 79 pool->high_count--; 80 } else { 81 BUG_ON(!pool->low_count); 82 item = list_first_entry(&pool->low_items, 83 struct ion_page_pool_item, list); 84 pool->low_count--; 85 } 86 87 list_del(&item->list); 88 page = item->page; 89 kfree(item); 90 return page; 91} 92 93void *ion_page_pool_alloc(struct ion_page_pool *pool) 94{ 95 struct page *page = NULL; 96 97 BUG_ON(!pool); 98 99 mutex_lock(&pool->mutex); 100 if (pool->high_count) 101 page = ion_page_pool_remove(pool, true); 102 else if (pool->low_count) 103 page = ion_page_pool_remove(pool, false); 104 mutex_unlock(&pool->mutex); 105 106 if (!page) 107 page = ion_page_pool_alloc_pages(pool); 108 109 return page; 110} 111 112void ion_page_pool_free(struct ion_page_pool *pool, struct page* page) 113{ 114 int ret; 115 116 ret = ion_page_pool_add(pool, page); 117 if (ret) 118 ion_page_pool_free_pages(pool, page); 119} 120 121static int ion_page_pool_shrink(struct shrinker *shrinker, 122 struct shrink_control *sc) 123{ 124 struct ion_page_pool *pool = container_of(shrinker, 125 struct ion_page_pool, 126 shrinker); 127 int nr_freed = 0; 128 int i; 129 bool high; 130 131 if (sc->gfp_mask & __GFP_HIGHMEM) 132 high = true; 133 134 if (sc->nr_to_scan == 0) 135 return high ? (pool->high_count + pool->low_count) * 136 (1 << pool->order) : 137 pool->low_count * (1 << pool->order); 138 139 for (i = 0; i < sc->nr_to_scan; i++) { 140 struct page *page; 141 142 mutex_lock(&pool->mutex); 143 if (high && pool->high_count) { 144 page = ion_page_pool_remove(pool, true); 145 } else if (pool->low_count) { 146 page = ion_page_pool_remove(pool, false); 147 } else { 148 mutex_unlock(&pool->mutex); 149 break; 150 } 151 mutex_unlock(&pool->mutex); 152 ion_page_pool_free_pages(pool, page); 153 nr_freed += (1 << pool->order); 154 } 155 pr_info("%s: shrunk page_pool of order %d by %d pages\n", __func__, 156 pool->order, nr_freed); 157 158 return high ? (pool->high_count + pool->low_count) * 159 (1 << pool->order) : 160 pool->low_count * (1 << pool->order); 161} 162 163struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) 164{ 165 struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool), 166 GFP_KERNEL); 167 if (!pool) 168 return NULL; 169 pool->high_count = 0; 170 pool->low_count = 0; 171 INIT_LIST_HEAD(&pool->low_items); 172 INIT_LIST_HEAD(&pool->high_items); 173 pool->shrinker.shrink = ion_page_pool_shrink; 174 pool->shrinker.seeks = DEFAULT_SEEKS * 16; 175 pool->shrinker.batch = 0; 176 register_shrinker(&pool->shrinker); 177 pool->gfp_mask = gfp_mask; 178 pool->order = order; 179 mutex_init(&pool->mutex); 180 181 return pool; 182} 183 184void ion_page_pool_destroy(struct ion_page_pool *pool) 185{ 186 unregister_shrinker(&pool->shrinker); 187 kfree(pool); 188} 189 190