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