]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c
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 function for ISP virtual address management in ISP driver
26 #include <linux/kernel.h>
27 #include <linux/types.h>
29 #include <linux/slab.h>
32 #include "atomisp_internal.h"
33 #include "mmu/isp_mmu.h"
34 #include "hmm/hmm_vm.h"
35 #include "hmm/hmm_common.h"
37 static unsigned int vm_node_end(unsigned int start
, unsigned int pgnr
)
39 return start
+ pgnr_to_size(pgnr
);
42 static int addr_in_vm_node(unsigned int addr
,
43 struct hmm_vm_node
*node
)
45 return (addr
>= node
->start
) && (addr
< (node
->start
+ node
->size
));
48 int hmm_vm_init(struct hmm_vm
*vm
, unsigned int start
,
55 vm
->pgnr
= size_to_pgnr_ceil(size
);
56 vm
->size
= pgnr_to_size(vm
->pgnr
);
58 INIT_LIST_HEAD(&vm
->vm_node_list
);
59 spin_lock_init(&vm
->lock
);
60 vm
->cache
= kmem_cache_create("atomisp_vm", sizeof(struct hmm_vm_node
),
63 return vm
->cache
!= NULL
? 0 : -ENOMEM
;
66 void hmm_vm_clean(struct hmm_vm
*vm
)
68 struct hmm_vm_node
*node
, *tmp
;
69 struct list_head new_head
;
75 list_replace_init(&vm
->vm_node_list
, &new_head
);
76 spin_unlock(&vm
->lock
);
78 list_for_each_entry_safe(node
, tmp
, &new_head
, list
) {
79 list_del(&node
->list
);
80 kmem_cache_free(vm
->cache
, node
);
83 kmem_cache_destroy(vm
->cache
);
86 static struct hmm_vm_node
*alloc_hmm_vm_node(unsigned int pgnr
,
89 struct hmm_vm_node
*node
;
91 node
= kmem_cache_alloc(vm
->cache
, GFP_KERNEL
);
93 dev_err(atomisp_dev
, "out of memory.\n");
97 INIT_LIST_HEAD(&node
->list
);
99 node
->size
= pgnr_to_size(pgnr
);
105 struct hmm_vm_node
*hmm_vm_alloc_node(struct hmm_vm
*vm
, unsigned int pgnr
)
107 struct list_head
*head
;
108 struct hmm_vm_node
*node
, *cur
, *next
;
109 unsigned int vm_start
, vm_end
;
116 vm_start
= vm
->start
;
117 vm_end
= vm_node_end(vm
->start
, vm
->pgnr
);
118 size
= pgnr_to_size(pgnr
);
121 head
= &vm
->vm_node_list
;
123 node
= alloc_hmm_vm_node(pgnr
, vm
);
125 dev_err(atomisp_dev
, "no memory to allocate hmm vm node.\n");
129 spin_lock(&vm
->lock
);
131 * if list is empty, the loop code will not be executed.
133 list_for_each_entry(cur
, head
, list
) {
134 /* Add gap between vm areas as helper to not hide overflow */
135 addr
= PAGE_ALIGN(vm_node_end(cur
->start
, cur
->pgnr
) + 1);
137 if (list_is_last(&cur
->list
, head
)) {
138 if (addr
+ size
> vm_end
) {
139 /* vm area does not have space anymore */
140 spin_unlock(&vm
->lock
);
141 kmem_cache_free(vm
->cache
, node
);
143 "no enough virtual address space.\n");
147 /* We still have vm space to add new node to tail */
151 next
= list_entry(cur
->list
.next
, struct hmm_vm_node
, list
);
152 if ((next
->start
- addr
) > size
)
157 list_add(&node
->list
, &cur
->list
);
158 spin_unlock(&vm
->lock
);
163 void hmm_vm_free_node(struct hmm_vm_node
*node
)
172 spin_lock(&vm
->lock
);
173 list_del(&node
->list
);
174 spin_unlock(&vm
->lock
);
176 kmem_cache_free(vm
->cache
, node
);
179 struct hmm_vm_node
*hmm_vm_find_node_start(struct hmm_vm
*vm
, unsigned int addr
)
181 struct hmm_vm_node
*node
;
186 spin_lock(&vm
->lock
);
188 list_for_each_entry(node
, &vm
->vm_node_list
, list
) {
189 if (node
->start
== addr
) {
190 spin_unlock(&vm
->lock
);
195 spin_unlock(&vm
->lock
);
199 struct hmm_vm_node
*hmm_vm_find_node_in_range(struct hmm_vm
*vm
,
202 struct hmm_vm_node
*node
;
207 spin_lock(&vm
->lock
);
209 list_for_each_entry(node
, &vm
->vm_node_list
, list
) {
210 if (addr_in_vm_node(addr
, node
)) {
211 spin_unlock(&vm
->lock
);
216 spin_unlock(&vm
->lock
);