1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/mm.h>
26
27#include <asm/set_memory.h>
28
29#include "atomisp_internal.h"
30#include "hmm/hmm_pool.h"
31
32
33
34
35static unsigned int get_pages_from_reserved_pool(void *pool,
36 struct hmm_page_object *page_obj,
37 unsigned int size, bool cached)
38{
39 unsigned long flags;
40 unsigned int i = 0;
41 unsigned int repool_pgnr;
42 int j;
43 struct hmm_reserved_pool_info *repool_info = pool;
44
45 if (!repool_info)
46 return 0;
47
48 spin_lock_irqsave(&repool_info->list_lock, flags);
49 if (repool_info->initialized) {
50 repool_pgnr = repool_info->index;
51
52 for (j = repool_pgnr - 1; j >= 0; j--) {
53 page_obj[i].page = repool_info->pages[j];
54 page_obj[i].type = HMM_PAGE_TYPE_RESERVED;
55 i++;
56 repool_info->index--;
57 if (i == size)
58 break;
59 }
60 }
61 spin_unlock_irqrestore(&repool_info->list_lock, flags);
62 return i;
63}
64
65static void free_pages_to_reserved_pool(void *pool,
66 struct hmm_page_object *page_obj)
67{
68 unsigned long flags;
69 struct hmm_reserved_pool_info *repool_info = pool;
70
71 if (!repool_info)
72 return;
73
74 spin_lock_irqsave(&repool_info->list_lock, flags);
75
76 if (repool_info->initialized &&
77 repool_info->index < repool_info->pgnr &&
78 page_obj->type == HMM_PAGE_TYPE_RESERVED) {
79 repool_info->pages[repool_info->index++] = page_obj->page;
80 }
81
82 spin_unlock_irqrestore(&repool_info->list_lock, flags);
83}
84
85static int hmm_reserved_pool_setup(struct hmm_reserved_pool_info **repool_info,
86 unsigned int pool_size)
87{
88 struct hmm_reserved_pool_info *pool_info;
89
90 pool_info = kmalloc(sizeof(struct hmm_reserved_pool_info),
91 GFP_KERNEL);
92 if (unlikely(!pool_info))
93 return -ENOMEM;
94
95 pool_info->pages = kmalloc(sizeof(struct page *) * pool_size,
96 GFP_KERNEL);
97 if (unlikely(!pool_info->pages)) {
98 kfree(pool_info);
99 return -ENOMEM;
100 }
101
102 pool_info->index = 0;
103 pool_info->pgnr = 0;
104 spin_lock_init(&pool_info->list_lock);
105 pool_info->initialized = true;
106
107 *repool_info = pool_info;
108
109 return 0;
110}
111
112static int hmm_reserved_pool_init(void **pool, unsigned int pool_size)
113{
114 int ret;
115 unsigned int blk_pgnr;
116 unsigned int pgnr = pool_size;
117 unsigned int order = 0;
118 unsigned int i = 0;
119 int fail_number = 0;
120 struct page *pages;
121 int j;
122 struct hmm_reserved_pool_info *repool_info;
123
124 if (pool_size == 0)
125 return 0;
126
127 ret = hmm_reserved_pool_setup(&repool_info, pool_size);
128 if (ret) {
129 dev_err(atomisp_dev, "hmm_reserved_pool_setup failed.\n");
130 return ret;
131 }
132
133 pgnr = pool_size;
134
135 i = 0;
136 order = MAX_ORDER;
137
138 while (pgnr) {
139 blk_pgnr = 1U << order;
140 while (blk_pgnr > pgnr) {
141 order--;
142 blk_pgnr >>= 1U;
143 }
144 BUG_ON(order > MAX_ORDER);
145
146 pages = alloc_pages(GFP_KERNEL | __GFP_NOWARN, order);
147 if (unlikely(!pages)) {
148 if (order == 0) {
149 fail_number++;
150 dev_err(atomisp_dev, "%s: alloc_pages failed: %d\n",
151 __func__, fail_number);
152
153
154
155 if (fail_number == ALLOC_PAGE_FAIL_NUM)
156 goto end;
157 } else {
158 order--;
159 }
160 } else {
161 blk_pgnr = 1U << order;
162
163 ret = set_pages_uc(pages, blk_pgnr);
164 if (ret) {
165 dev_err(atomisp_dev,
166 "set pages uncached failed\n");
167 __free_pages(pages, order);
168 goto end;
169 }
170
171 for (j = 0; j < blk_pgnr; j++)
172 repool_info->pages[i++] = pages + j;
173
174 repool_info->index += blk_pgnr;
175 repool_info->pgnr += blk_pgnr;
176
177 pgnr -= blk_pgnr;
178
179 fail_number = 0;
180 }
181 }
182
183end:
184 repool_info->initialized = true;
185
186 *pool = repool_info;
187
188 dev_info(atomisp_dev,
189 "hmm_reserved_pool init successfully,hmm_reserved_pool is with %d pages.\n",
190 repool_info->pgnr);
191 return 0;
192}
193
194static void hmm_reserved_pool_exit(void **pool)
195{
196 unsigned long flags;
197 int i, ret;
198 unsigned int pgnr;
199 struct hmm_reserved_pool_info *repool_info = *pool;
200
201 if (!repool_info)
202 return;
203
204 spin_lock_irqsave(&repool_info->list_lock, flags);
205 if (!repool_info->initialized) {
206 spin_unlock_irqrestore(&repool_info->list_lock, flags);
207 return;
208 }
209 pgnr = repool_info->pgnr;
210 repool_info->index = 0;
211 repool_info->pgnr = 0;
212 repool_info->initialized = false;
213 spin_unlock_irqrestore(&repool_info->list_lock, flags);
214
215 for (i = 0; i < pgnr; i++) {
216 ret = set_pages_wb(repool_info->pages[i], 1);
217 if (ret)
218 dev_err(atomisp_dev,
219 "set page to WB err...ret=%d\n", ret);
220
221
222
223
224
225
226
227 if (!ret)
228 __free_pages(repool_info->pages[i], 0);
229 }
230
231 kfree(repool_info->pages);
232 kfree(repool_info);
233
234 *pool = NULL;
235}
236
237static int hmm_reserved_pool_inited(void *pool)
238{
239 struct hmm_reserved_pool_info *repool_info = pool;
240
241 if (!repool_info)
242 return 0;
243
244 return repool_info->initialized;
245}
246
247struct hmm_pool_ops reserved_pops = {
248 .pool_init = hmm_reserved_pool_init,
249 .pool_exit = hmm_reserved_pool_exit,
250 .pool_alloc_pages = get_pages_from_reserved_pool,
251 .pool_free_pages = free_pages_to_reserved_pool,
252 .pool_inited = hmm_reserved_pool_inited,
253};
254