]> git.ipfire.org Git - thirdparty/kernel/linux.git/blame - drivers/staging/android/ion/ion_page_pool.c
staging: android: Remove redundant license text
[thirdparty/kernel/linux.git] / drivers / staging / android / ion / ion_page_pool.c
CommitLineData
bdcb7be6 1// SPDX-License-Identifier: GPL-2.0
0214c7f2
RSZ
2/*
3 * drivers/staging/android/ion/ion_mem_pool.c
4 *
5 * Copyright (C) 2011 Google, Inc.
0214c7f2
RSZ
6 */
7
797a95c4 8#include <linux/debugfs.h>
0214c7f2
RSZ
9#include <linux/dma-mapping.h>
10#include <linux/err.h>
797a95c4 11#include <linux/fs.h>
0214c7f2 12#include <linux/list.h>
30d79792 13#include <linux/init.h>
0214c7f2 14#include <linux/slab.h>
0cd2dc4d 15#include <linux/swap.h>
eb9751db
LA
16
17#include "ion.h"
0214c7f2 18
0214c7f2
RSZ
19static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
20{
21 struct page *page = alloc_pages(pool->gfp_mask, pool->order);
22
23 if (!page)
24 return NULL;
0214c7f2
RSZ
25 return page;
26}
27
28static void ion_page_pool_free_pages(struct ion_page_pool *pool,
29 struct page *page)
30{
31 __free_pages(page, pool->order);
32}
33
34static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
35{
efee5a0c 36 mutex_lock(&pool->mutex);
0fb9b815 37 if (PageHighMem(page)) {
38c003b1 38 list_add_tail(&page->lru, &pool->high_items);
0fb9b815
RSZ
39 pool->high_count++;
40 } else {
38c003b1 41 list_add_tail(&page->lru, &pool->low_items);
0fb9b815
RSZ
42 pool->low_count++;
43 }
efee5a0c 44 mutex_unlock(&pool->mutex);
0214c7f2
RSZ
45 return 0;
46}
47
0fb9b815 48static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
0214c7f2 49{
0214c7f2
RSZ
50 struct page *page;
51
0fb9b815
RSZ
52 if (high) {
53 BUG_ON(!pool->high_count);
38c003b1 54 page = list_first_entry(&pool->high_items, struct page, lru);
0fb9b815
RSZ
55 pool->high_count--;
56 } else {
57 BUG_ON(!pool->low_count);
38c003b1 58 page = list_first_entry(&pool->low_items, struct page, lru);
0fb9b815
RSZ
59 pool->low_count--;
60 }
0214c7f2 61
38c003b1 62 list_del(&page->lru);
0214c7f2
RSZ
63 return page;
64}
65
79240748 66struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
0214c7f2
RSZ
67{
68 struct page *page = NULL;
69
70 BUG_ON(!pool);
71
72 mutex_lock(&pool->mutex);
0fb9b815
RSZ
73 if (pool->high_count)
74 page = ion_page_pool_remove(pool, true);
75 else if (pool->low_count)
76 page = ion_page_pool_remove(pool, false);
0214c7f2
RSZ
77 mutex_unlock(&pool->mutex);
78
0fb9b815
RSZ
79 if (!page)
80 page = ion_page_pool_alloc_pages(pool);
81
0214c7f2
RSZ
82 return page;
83}
84
e1d855b0 85void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
0214c7f2
RSZ
86{
87 int ret;
88
bdeb9f1c
HS
89 BUG_ON(pool->order != compound_order(page));
90
0214c7f2
RSZ
91 ret = ion_page_pool_add(pool, page);
92 if (ret)
93 ion_page_pool_free_pages(pool, page);
0214c7f2
RSZ
94}
95
ea313b5f 96static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
797a95c4 97{
80cb77dc 98 int count = pool->low_count;
797a95c4 99
80cb77dc
HS
100 if (high)
101 count += pool->high_count;
102
103 return count << pool->order;
797a95c4
RSZ
104}
105
ea313b5f 106int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
679011bd 107 int nr_to_scan)
0214c7f2 108{
b44d9ce3 109 int freed = 0;
0fb9b815
RSZ
110 bool high;
111
0cd2dc4d 112 if (current_is_kswapd())
17fbab1e 113 high = true;
0cd2dc4d
HS
114 else
115 high = !!(gfp_mask & __GFP_HIGHMEM);
0214c7f2 116
797a95c4 117 if (nr_to_scan == 0)
ea313b5f
RSZ
118 return ion_page_pool_total(pool, high);
119
b44d9ce3 120 while (freed < nr_to_scan) {
ea313b5f
RSZ
121 struct page *page;
122
123 mutex_lock(&pool->mutex);
ce3d1093 124 if (pool->low_count) {
ea313b5f 125 page = ion_page_pool_remove(pool, false);
ce3d1093
CC
126 } else if (high && pool->high_count) {
127 page = ion_page_pool_remove(pool, true);
ea313b5f 128 } else {
0fb9b815 129 mutex_unlock(&pool->mutex);
ea313b5f 130 break;
0214c7f2 131 }
ea313b5f
RSZ
132 mutex_unlock(&pool->mutex);
133 ion_page_pool_free_pages(pool, page);
b44d9ce3 134 freed += (1 << pool->order);
0214c7f2 135 }
0214c7f2 136
b9daf0b6 137 return freed;
0214c7f2
RSZ
138}
139
e7f63771
CF
140struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
141 bool cached)
0214c7f2 142{
8fb78ad6
BM
143 struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
144
0214c7f2
RSZ
145 if (!pool)
146 return NULL;
0fb9b815
RSZ
147 pool->high_count = 0;
148 pool->low_count = 0;
149 INIT_LIST_HEAD(&pool->low_items);
150 INIT_LIST_HEAD(&pool->high_items);
bdeb9f1c 151 pool->gfp_mask = gfp_mask | __GFP_COMP;
0214c7f2
RSZ
152 pool->order = order;
153 mutex_init(&pool->mutex);
797a95c4 154 plist_node_init(&pool->list, order);
e7f63771
CF
155 if (cached)
156 pool->cached = true;
0214c7f2
RSZ
157
158 return pool;
159}
160
161void ion_page_pool_destroy(struct ion_page_pool *pool)
162{
0214c7f2
RSZ
163 kfree(pool);
164}
165
797a95c4
RSZ
166static int __init ion_page_pool_init(void)
167{
797a95c4
RSZ
168 return 0;
169}
30d79792 170device_initcall(ion_page_pool_init);