aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/atomisp/include/hmm/hmm_bo.h
blob: 385e22fc4a46abe63659395e1f8977ab36c4a2d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Support for Medifield PNW Camera Imaging ISP subsystem.
 *
 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
 *
 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *
 */

#ifndef	__HMM_BO_H__
#define	__HMM_BO_H__

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include "mmu/isp_mmu.h"
#include "hmm/hmm_common.h"
#include "ia_css_types.h"

#define	check_bodev_null_return(bdev, exp)	\
		check_null_return(bdev, exp, \
			"NULL hmm_bo_device.\n")

#define	check_bodev_null_return_void(bdev)	\
		check_null_return_void(bdev, \
			"NULL hmm_bo_device.\n")

#define	check_bo_status_yes_goto(bo, _status, label) \
	var_not_equal_goto((bo->status & (_status)), (_status), \
			label, \
			"HMM buffer status not contain %s.\n", \
			#_status)

#define	check_bo_status_no_goto(bo, _status, label) \
	var_equal_goto((bo->status & (_status)), (_status), \
			label, \
			"HMM buffer status contains %s.\n", \
			#_status)

#define rbtree_node_to_hmm_bo(root_node)	\
	container_of((root_node), struct hmm_buffer_object, node)

#define	list_to_hmm_bo(list_ptr)	\
	list_entry((list_ptr), struct hmm_buffer_object, list)

#define	kref_to_hmm_bo(kref_ptr)	\
	list_entry((kref_ptr), struct hmm_buffer_object, kref)

#define	check_bo_null_return(bo, exp)	\
	check_null_return(bo, exp, "NULL hmm buffer object.\n")

#define	check_bo_null_return_void(bo)	\
	check_null_return_void(bo, "NULL hmm buffer object.\n")

#define	HMM_MAX_ORDER		3
#define	HMM_MIN_ORDER		0

#define	ISP_VM_START	0x0
#define	ISP_VM_SIZE	(0x7FFFFFFF)	/* 2G address space */
#define	ISP_PTR_NULL	NULL

#define	HMM_BO_DEVICE_INITED	0x1

enum hmm_bo_type {
	HMM_BO_PRIVATE,
	HMM_BO_USER,
	HMM_BO_LAST,
};

#define	HMM_BO_MASK		0x1
#define	HMM_BO_FREE		0x0
#define	HMM_BO_ALLOCED	0x1
#define	HMM_BO_PAGE_ALLOCED	0x2
#define	HMM_BO_BINDED		0x4
#define	HMM_BO_MMAPED		0x8
#define	HMM_BO_VMAPED		0x10
#define	HMM_BO_VMAPED_CACHED	0x20
#define	HMM_BO_ACTIVE		0x1000
#define	HMM_BO_MEM_TYPE_USER     0x1
#define	HMM_BO_MEM_TYPE_PFN      0x2

struct hmm_bo_device {
	struct isp_mmu		mmu;

	/* start/pgnr/size is used to record the virtual memory of this bo */
	unsigned int start;
	unsigned int pgnr;
	unsigned int size;

	/* list lock is used to protect the entire_bo_list */
	spinlock_t	list_lock;
	int flag;

	/* linked list for entire buffer object */
	struct list_head entire_bo_list;
	/* rbtree for maintain entire allocated vm */
	struct rb_root allocated_rbtree;
	/* rbtree for maintain entire free vm */
	struct rb_root free_rbtree;
	struct mutex rbtree_mutex;
	struct kmem_cache *bo_cache;
};

struct hmm_buffer_object {
	struct hmm_bo_device	*bdev;
	struct list_head	list;
	struct kref	kref;

	struct page **pages;

	/* mutex protecting this BO */
	struct mutex		mutex;
	enum hmm_bo_type	type;
	int		mmap_count;
	int		status;
	int		mem_type;
	void		*vmap_addr; /* kernel virtual address by vmap */

	struct rb_node	node;
	unsigned int	start;
	unsigned int	end;
	unsigned int	pgnr;
	/*
	 * When insert a bo which has the same pgnr with an existed
	 * bo node in the free_rbtree, using "prev & next" pointer
	 * to maintain a bo linked list instead of insert this bo
	 * into free_rbtree directly, it will make sure each node
	 * in free_rbtree has different pgnr.
	 * "prev & next" default is NULL.
	 */
	struct hmm_buffer_object	*prev;
	struct hmm_buffer_object	*next;
};

struct hmm_buffer_object *hmm_bo_alloc(struct hmm_bo_device *bdev,
				       unsigned int pgnr);

void hmm_bo_release(struct hmm_buffer_object *bo);

int hmm_bo_device_init(struct hmm_bo_device *bdev,
		       struct isp_mmu_client *mmu_driver,
		       unsigned int vaddr_start, unsigned int size);

/*
 * clean up all hmm_bo_device related things.
 */
void hmm_bo_device_exit(struct hmm_bo_device *bdev);

/*
 * whether the bo device is inited or not.
 */
int hmm_bo_device_inited(struct hmm_bo_device *bdev);

/*
 * increse buffer object reference.
 */
void hmm_bo_ref(struct hmm_buffer_object *bo);

/*
 * decrese buffer object reference. if reference reaches 0,
 * release function of the buffer object will be called.
 *
 * this call is also used to release hmm_buffer_object or its
 * upper level object with it embedded in. you need to call
 * this function when it is no longer used.
 *
 * Note:
 *
 * user dont need to care about internal resource release of
 * the buffer object in the release callback, it will be
 * handled internally.
 *
 * this call will only release internal resource of the buffer
 * object but will not free the buffer object itself, as the
 * buffer object can be both pre-allocated statically or
 * dynamically allocated. so user need to deal with the release
 * of the buffer object itself manually. below example shows
 * the normal case of using the buffer object.
 *
 *	struct hmm_buffer_object *bo = hmm_bo_create(bdev, pgnr);
 *	......
 *	hmm_bo_unref(bo);
 *
 * or:
 *
 *	struct hmm_buffer_object bo;
 *
 *	hmm_bo_init(bdev, &bo, pgnr, NULL);
 *	...
 *	hmm_bo_unref(&bo);
 */
void hmm_bo_unref(struct hmm_buffer_object *bo);

int hmm_bo_allocated(struct hmm_buffer_object *bo);

/*
 * Allocate/Free physical pages for the bo. Type indicates if the
 * pages will be allocated by using video driver (for share buffer)
 * or by ISP driver itself.
 */
int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
		       enum hmm_bo_type type,
		       const void __user *userptr);
void hmm_bo_free_pages(struct hmm_buffer_object *bo);
int hmm_bo_page_allocated(struct hmm_buffer_object *bo);

/*
 * bind/unbind the physical pages to a virtual address space.
 */
int hmm_bo_bind(struct hmm_buffer_object *bo);
void hmm_bo_unbind(struct hmm_buffer_object *bo);
int hmm_bo_binded(struct hmm_buffer_object *bo);

/*
 * vmap buffer object's pages to contiguous kernel virtual address.
 * if the buffer has been vmaped, return the virtual address directly.
 */
void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached);

/*
 * flush the cache for the vmapped buffer object's pages,
 * if the buffer has not been vmapped, return directly.
 */
void hmm_bo_flush_vmap(struct hmm_buffer_object *bo);

/*
 * vunmap buffer object's kernel virtual address.
 */
void hmm_bo_vunmap(struct hmm_buffer_object *bo);

/*
 * mmap the bo's physical pages to specific vma.
 *
 * vma's address space size must be the same as bo's size,
 * otherwise it will return -EINVAL.
 *
 * vma->vm_flags will be set to (VM_RESERVED | VM_IO).
 */
int hmm_bo_mmap(struct vm_area_struct *vma,
		struct hmm_buffer_object *bo);

/*
 * find the buffer object by its virtual address vaddr.
 * return NULL if no such buffer object found.
 */
struct hmm_buffer_object *hmm_bo_device_search_start(
    struct hmm_bo_device *bdev, ia_css_ptr vaddr);

/*
 * find the buffer object by its virtual address.
 * it does not need to be the start address of one bo,
 * it can be an address within the range of one bo.
 * return NULL if no such buffer object found.
 */
struct hmm_buffer_object *hmm_bo_device_search_in_range(
    struct hmm_bo_device *bdev, ia_css_ptr vaddr);

/*
 * find the buffer object with kernel virtual address vaddr.
 * return NULL if no such buffer object found.
 */
struct hmm_buffer_object *hmm_bo_device_search_vmap_start(
    struct hmm_bo_device *bdev, const void *vaddr);

#endif