2 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * This file contains functions for dynamic memory pool management
26 #include <linux/kernel.h>
27 #include <linux/types.h>
30 #include <asm/set_memory.h>
32 #include "atomisp_internal.h"
34 #include "hmm/hmm_pool.h"
37 * dynamic memory pool ops.
39 static unsigned int get_pages_from_dynamic_pool(void *pool,
40 struct hmm_page_object *page_obj,
41 unsigned int size, bool cached)
43 struct hmm_page *hmm_page;
46 struct hmm_dynamic_pool_info *dypool_info = pool;
51 spin_lock_irqsave(&dypool_info->list_lock, flags);
52 if (dypool_info->initialized) {
53 while (!list_empty(&dypool_info->pages_list)) {
54 hmm_page = list_entry(dypool_info->pages_list.next,
55 struct hmm_page, list);
57 list_del(&hmm_page->list);
59 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
61 page_obj[i].page = hmm_page->page;
62 page_obj[i++].type = HMM_PAGE_TYPE_DYNAMIC;
63 kmem_cache_free(dypool_info->pgptr_cache, hmm_page);
68 spin_lock_irqsave(&dypool_info->list_lock, flags);
71 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
76 static void free_pages_to_dynamic_pool(void *pool,
77 struct hmm_page_object *page_obj)
79 struct hmm_page *hmm_page;
82 struct hmm_dynamic_pool_info *dypool_info = pool;
87 spin_lock_irqsave(&dypool_info->list_lock, flags);
88 if (!dypool_info->initialized) {
89 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
92 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
94 if (page_obj->type == HMM_PAGE_TYPE_RESERVED)
97 if (dypool_info->pgnr >= dypool_info->pool_size) {
98 /* free page directly back to system */
99 ret = set_pages_wb(page_obj->page, 1);
102 "set page to WB err ...ret=%d\n", ret);
104 W/A: set_pages_wb seldom return value = -EFAULT
105 indicate that address of page is not in valid
106 range(0xffff880000000000~0xffffc7ffffffffff)
107 then, _free_pages would panic; Do not know why page
108 address be valid, it maybe memory corruption by lowmemory
111 __free_pages(page_obj->page, 0);
112 hmm_mem_stat.sys_size--;
116 hmm_page = kmem_cache_zalloc(dypool_info->pgptr_cache,
119 dev_err(atomisp_dev, "out of memory for hmm_page.\n");
121 /* free page directly */
122 ret = set_pages_wb(page_obj->page, 1);
125 "set page to WB err ...ret=%d\n", ret);
127 __free_pages(page_obj->page, 0);
128 hmm_mem_stat.sys_size--;
133 hmm_page->page = page_obj->page;
136 * add to pages_list of pages_pool
138 spin_lock_irqsave(&dypool_info->list_lock, flags);
139 list_add_tail(&hmm_page->list, &dypool_info->pages_list);
141 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
142 hmm_mem_stat.dyc_size++;
145 static int hmm_dynamic_pool_init(void **pool, unsigned int pool_size)
147 struct hmm_dynamic_pool_info *dypool_info;
152 dypool_info = kmalloc(sizeof(struct hmm_dynamic_pool_info),
154 if (unlikely(!dypool_info)) {
155 dev_err(atomisp_dev, "out of memory for repool_info.\n");
159 dypool_info->pgptr_cache = kmem_cache_create("pgptr_cache",
160 sizeof(struct hmm_page), 0,
161 SLAB_HWCACHE_ALIGN, NULL);
162 if (!dypool_info->pgptr_cache) {
167 INIT_LIST_HEAD(&dypool_info->pages_list);
168 spin_lock_init(&dypool_info->list_lock);
169 dypool_info->initialized = true;
170 dypool_info->pool_size = pool_size;
171 dypool_info->pgnr = 0;
178 static void hmm_dynamic_pool_exit(void **pool)
180 struct hmm_dynamic_pool_info *dypool_info = *pool;
181 struct hmm_page *hmm_page;
188 spin_lock_irqsave(&dypool_info->list_lock, flags);
189 if (!dypool_info->initialized) {
190 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
193 dypool_info->initialized = false;
195 while (!list_empty(&dypool_info->pages_list)) {
196 hmm_page = list_entry(dypool_info->pages_list.next,
197 struct hmm_page, list);
199 list_del(&hmm_page->list);
200 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
202 /* can cause thread sleep, so cannot be put into spin_lock */
203 ret = set_pages_wb(hmm_page->page, 1);
206 "set page to WB err...ret=%d\n", ret);
208 __free_pages(hmm_page->page, 0);
209 hmm_mem_stat.dyc_size--;
210 hmm_mem_stat.sys_size--;
212 kmem_cache_free(dypool_info->pgptr_cache, hmm_page);
213 spin_lock_irqsave(&dypool_info->list_lock, flags);
216 spin_unlock_irqrestore(&dypool_info->list_lock, flags);
218 kmem_cache_destroy(dypool_info->pgptr_cache);
225 static int hmm_dynamic_pool_inited(void *pool)
227 struct hmm_dynamic_pool_info *dypool_info = pool;
232 return dypool_info->initialized;
235 struct hmm_pool_ops dynamic_pops = {
236 .pool_init = hmm_dynamic_pool_init,
237 .pool_exit = hmm_dynamic_pool_exit,
238 .pool_alloc_pages = get_pages_from_dynamic_pool,
239 .pool_free_pages = free_pages_to_dynamic_pool,
240 .pool_inited = hmm_dynamic_pool_inited,