Rev 4569 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4569 | Rev 6296 | ||
---|---|---|---|
1 | /************************************************************************** |
1 | /************************************************************************** |
2 | * |
2 | * |
3 | * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA |
3 | * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA |
4 | * All Rights Reserved. |
4 | * All Rights Reserved. |
5 | * |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the |
7 | * copy of this software and associated documentation files (the |
8 | * "Software"), to deal in the Software without restriction, including |
8 | * "Software"), to deal in the Software without restriction, including |
9 | * without limitation the rights to use, copy, modify, merge, publish, |
9 | * without limitation the rights to use, copy, modify, merge, publish, |
10 | * distribute, sub license, and/or sell copies of the Software, and to |
10 | * distribute, sub license, and/or sell copies of the Software, and to |
11 | * permit persons to whom the Software is furnished to do so, subject to |
11 | * permit persons to whom the Software is furnished to do so, subject to |
12 | * the following conditions: |
12 | * the following conditions: |
13 | * |
13 | * |
14 | * The above copyright notice and this permission notice (including the |
14 | * The above copyright notice and this permission notice (including the |
15 | * next paragraph) shall be included in all copies or substantial portions |
15 | * next paragraph) shall be included in all copies or substantial portions |
16 | * of the Software. |
16 | * of the Software. |
17 | * |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
25 | * |
25 | * |
26 | **************************************************************************/ |
26 | **************************************************************************/ |
27 | /* |
27 | /* |
28 | * Authors: Thomas Hellstrom |
28 | * Authors: Thomas Hellstrom |
29 | * |
29 | * |
30 | * While no substantial code is shared, the prime code is inspired by |
30 | * While no substantial code is shared, the prime code is inspired by |
31 | * drm_prime.c, with |
31 | * drm_prime.c, with |
32 | * Authors: |
32 | * Authors: |
33 | * Dave Airlie |
33 | * Dave Airlie |
34 | * Rob Clark |
34 | * Rob Clark |
35 | */ |
35 | */ |
36 | /** @file ttm_ref_object.c |
36 | /** @file ttm_ref_object.c |
37 | * |
37 | * |
38 | * Base- and reference object implementation for the various |
38 | * Base- and reference object implementation for the various |
39 | * ttm objects. Implements reference counting, minimal security checks |
39 | * ttm objects. Implements reference counting, minimal security checks |
40 | * and release on file close. |
40 | * and release on file close. |
41 | */ |
41 | */ |
42 | 42 | ||
43 | 43 | ||
44 | /** |
44 | /** |
45 | * struct ttm_object_file |
45 | * struct ttm_object_file |
46 | * |
46 | * |
47 | * @tdev: Pointer to the ttm_object_device. |
47 | * @tdev: Pointer to the ttm_object_device. |
48 | * |
48 | * |
49 | * @lock: Lock that protects the ref_list list and the |
49 | * @lock: Lock that protects the ref_list list and the |
50 | * ref_hash hash tables. |
50 | * ref_hash hash tables. |
51 | * |
51 | * |
52 | * @ref_list: List of ttm_ref_objects to be destroyed at |
52 | * @ref_list: List of ttm_ref_objects to be destroyed at |
53 | * file release. |
53 | * file release. |
54 | * |
54 | * |
55 | * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, |
55 | * @ref_hash: Hash tables of ref objects, one per ttm_ref_type, |
56 | * for fast lookup of ref objects given a base object. |
56 | * for fast lookup of ref objects given a base object. |
57 | */ |
57 | */ |
58 | 58 | ||
59 | #define pr_fmt(fmt) "[TTM] " fmt |
59 | #define pr_fmt(fmt) "[TTM] " fmt |
60 | - | ||
61 | #include |
- | |
62 | 60 | ||
63 | #include |
61 | #include |
64 | #include |
62 | #include |
65 | #include |
63 | #include |
66 | #include |
64 | #include |
67 | #include |
65 | #include |
68 | #include |
66 | #include |
69 | //#include |
67 | #include |
70 | - | ||
71 | static inline int __must_check kref_get_unless_zero(struct kref *kref) |
- | |
72 | { |
- | |
73 | return atomic_add_unless(&kref->refcount, 1, 0); |
- | |
74 | } |
- | |
75 | - | ||
76 | #define pr_err(fmt, ...) \ |
- | |
77 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
- | |
78 | 68 | ||
79 | struct ttm_object_file { |
69 | struct ttm_object_file { |
80 | struct ttm_object_device *tdev; |
70 | struct ttm_object_device *tdev; |
81 | spinlock_t lock; |
71 | spinlock_t lock; |
82 | struct list_head ref_list; |
72 | struct list_head ref_list; |
83 | struct drm_open_hash ref_hash[TTM_REF_NUM]; |
73 | struct drm_open_hash ref_hash[TTM_REF_NUM]; |
84 | struct kref refcount; |
74 | struct kref refcount; |
85 | }; |
75 | }; |
86 | 76 | ||
87 | /** |
77 | /** |
88 | * struct ttm_object_device |
78 | * struct ttm_object_device |
89 | * |
79 | * |
90 | * @object_lock: lock that protects the object_hash hash table. |
80 | * @object_lock: lock that protects the object_hash hash table. |
91 | * |
81 | * |
92 | * @object_hash: hash table for fast lookup of object global names. |
82 | * @object_hash: hash table for fast lookup of object global names. |
93 | * |
83 | * |
94 | * @object_count: Per device object count. |
84 | * @object_count: Per device object count. |
95 | * |
85 | * |
96 | * This is the per-device data structure needed for ttm object management. |
86 | * This is the per-device data structure needed for ttm object management. |
97 | */ |
87 | */ |
98 | 88 | ||
99 | struct ttm_object_device { |
89 | struct ttm_object_device { |
100 | spinlock_t object_lock; |
90 | spinlock_t object_lock; |
101 | struct drm_open_hash object_hash; |
91 | struct drm_open_hash object_hash; |
102 | atomic_t object_count; |
92 | atomic_t object_count; |
103 | struct ttm_mem_global *mem_glob; |
93 | struct ttm_mem_global *mem_glob; |
- | 94 | struct dma_buf_ops ops; |
|
- | 95 | void (*dmabuf_release)(struct dma_buf *dma_buf); |
|
- | 96 | size_t dma_buf_size; |
|
104 | }; |
97 | }; |
105 | 98 | ||
106 | /** |
99 | /** |
107 | * struct ttm_ref_object |
100 | * struct ttm_ref_object |
108 | * |
101 | * |
109 | * @hash: Hash entry for the per-file object reference hash. |
102 | * @hash: Hash entry for the per-file object reference hash. |
110 | * |
103 | * |
111 | * @head: List entry for the per-file list of ref-objects. |
104 | * @head: List entry for the per-file list of ref-objects. |
112 | * |
105 | * |
113 | * @kref: Ref count. |
106 | * @kref: Ref count. |
114 | * |
107 | * |
115 | * @obj: Base object this ref object is referencing. |
108 | * @obj: Base object this ref object is referencing. |
116 | * |
109 | * |
117 | * @ref_type: Type of ref object. |
110 | * @ref_type: Type of ref object. |
118 | * |
111 | * |
119 | * This is similar to an idr object, but it also has a hash table entry |
112 | * This is similar to an idr object, but it also has a hash table entry |
120 | * that allows lookup with a pointer to the referenced object as a key. In |
113 | * that allows lookup with a pointer to the referenced object as a key. In |
121 | * that way, one can easily detect whether a base object is referenced by |
114 | * that way, one can easily detect whether a base object is referenced by |
122 | * a particular ttm_object_file. It also carries a ref count to avoid creating |
115 | * a particular ttm_object_file. It also carries a ref count to avoid creating |
123 | * multiple ref objects if a ttm_object_file references the same base |
116 | * multiple ref objects if a ttm_object_file references the same base |
124 | * object more than once. |
117 | * object more than once. |
125 | */ |
118 | */ |
126 | 119 | ||
127 | struct ttm_ref_object { |
120 | struct ttm_ref_object { |
- | 121 | struct rcu_head rcu_head; |
|
128 | struct drm_hash_item hash; |
122 | struct drm_hash_item hash; |
129 | struct list_head head; |
123 | struct list_head head; |
130 | struct kref kref; |
124 | struct kref kref; |
131 | enum ttm_ref_type ref_type; |
125 | enum ttm_ref_type ref_type; |
132 | struct ttm_base_object *obj; |
126 | struct ttm_base_object *obj; |
133 | struct ttm_object_file *tfile; |
127 | struct ttm_object_file *tfile; |
134 | }; |
128 | }; |
135 | 129 | ||
136 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); |
130 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf); |
137 | 131 | ||
138 | static inline struct ttm_object_file * |
132 | static inline struct ttm_object_file * |
139 | ttm_object_file_ref(struct ttm_object_file *tfile) |
133 | ttm_object_file_ref(struct ttm_object_file *tfile) |
140 | { |
134 | { |
141 | kref_get(&tfile->refcount); |
135 | kref_get(&tfile->refcount); |
142 | return tfile; |
136 | return tfile; |
143 | } |
137 | } |
144 | 138 | ||
145 | static void ttm_object_file_destroy(struct kref *kref) |
139 | static void ttm_object_file_destroy(struct kref *kref) |
146 | { |
140 | { |
147 | struct ttm_object_file *tfile = |
141 | struct ttm_object_file *tfile = |
148 | container_of(kref, struct ttm_object_file, refcount); |
142 | container_of(kref, struct ttm_object_file, refcount); |
149 | 143 | ||
150 | kfree(tfile); |
144 | kfree(tfile); |
151 | } |
145 | } |
152 | 146 | ||
153 | 147 | ||
154 | static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) |
148 | static inline void ttm_object_file_unref(struct ttm_object_file **p_tfile) |
155 | { |
149 | { |
156 | struct ttm_object_file *tfile = *p_tfile; |
150 | struct ttm_object_file *tfile = *p_tfile; |
157 | 151 | ||
158 | *p_tfile = NULL; |
152 | *p_tfile = NULL; |
159 | kref_put(&tfile->refcount, ttm_object_file_destroy); |
153 | kref_put(&tfile->refcount, ttm_object_file_destroy); |
160 | } |
154 | } |
161 | 155 | ||
162 | 156 | ||
163 | int ttm_base_object_init(struct ttm_object_file *tfile, |
157 | int ttm_base_object_init(struct ttm_object_file *tfile, |
164 | struct ttm_base_object *base, |
158 | struct ttm_base_object *base, |
165 | bool shareable, |
159 | bool shareable, |
166 | enum ttm_object_type object_type, |
160 | enum ttm_object_type object_type, |
167 | void (*refcount_release) (struct ttm_base_object **), |
161 | void (*refcount_release) (struct ttm_base_object **), |
168 | void (*ref_obj_release) (struct ttm_base_object *, |
162 | void (*ref_obj_release) (struct ttm_base_object *, |
169 | enum ttm_ref_type ref_type)) |
163 | enum ttm_ref_type ref_type)) |
170 | { |
164 | { |
171 | struct ttm_object_device *tdev = tfile->tdev; |
165 | struct ttm_object_device *tdev = tfile->tdev; |
172 | int ret; |
166 | int ret; |
173 | 167 | ||
174 | base->shareable = shareable; |
168 | base->shareable = shareable; |
175 | base->tfile = ttm_object_file_ref(tfile); |
169 | base->tfile = ttm_object_file_ref(tfile); |
176 | base->refcount_release = refcount_release; |
170 | base->refcount_release = refcount_release; |
177 | base->ref_obj_release = ref_obj_release; |
171 | base->ref_obj_release = ref_obj_release; |
178 | base->object_type = object_type; |
172 | base->object_type = object_type; |
179 | kref_init(&base->refcount); |
173 | kref_init(&base->refcount); |
180 | spin_lock(&tdev->object_lock); |
174 | spin_lock(&tdev->object_lock); |
181 | ret = drm_ht_just_insert_please_rcu(&tdev->object_hash, |
175 | ret = drm_ht_just_insert_please_rcu(&tdev->object_hash, |
182 | &base->hash, |
176 | &base->hash, |
183 | (unsigned long)base, 31, 0, 0); |
177 | (unsigned long)base, 31, 0, 0); |
184 | spin_unlock(&tdev->object_lock); |
178 | spin_unlock(&tdev->object_lock); |
185 | if (unlikely(ret != 0)) |
179 | if (unlikely(ret != 0)) |
186 | goto out_err0; |
180 | goto out_err0; |
187 | 181 | ||
188 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); |
182 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); |
189 | if (unlikely(ret != 0)) |
183 | if (unlikely(ret != 0)) |
190 | goto out_err1; |
184 | goto out_err1; |
191 | 185 | ||
192 | ttm_base_object_unref(&base); |
186 | ttm_base_object_unref(&base); |
193 | 187 | ||
194 | return 0; |
188 | return 0; |
195 | out_err1: |
189 | out_err1: |
196 | spin_lock(&tdev->object_lock); |
190 | spin_lock(&tdev->object_lock); |
197 | (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash); |
191 | (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash); |
198 | spin_unlock(&tdev->object_lock); |
192 | spin_unlock(&tdev->object_lock); |
199 | out_err0: |
193 | out_err0: |
200 | return ret; |
194 | return ret; |
201 | } |
195 | } |
202 | EXPORT_SYMBOL(ttm_base_object_init); |
196 | EXPORT_SYMBOL(ttm_base_object_init); |
203 | 197 | ||
204 | static void ttm_release_base(struct kref *kref) |
198 | static void ttm_release_base(struct kref *kref) |
205 | { |
199 | { |
206 | struct ttm_base_object *base = |
200 | struct ttm_base_object *base = |
207 | container_of(kref, struct ttm_base_object, refcount); |
201 | container_of(kref, struct ttm_base_object, refcount); |
208 | struct ttm_object_device *tdev = base->tfile->tdev; |
202 | struct ttm_object_device *tdev = base->tfile->tdev; |
209 | 203 | ||
210 | spin_lock(&tdev->object_lock); |
204 | spin_lock(&tdev->object_lock); |
211 | (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash); |
205 | (void)drm_ht_remove_item_rcu(&tdev->object_hash, &base->hash); |
212 | spin_unlock(&tdev->object_lock); |
206 | spin_unlock(&tdev->object_lock); |
213 | 207 | ||
214 | /* |
208 | /* |
215 | * Note: We don't use synchronize_rcu() here because it's far |
209 | * Note: We don't use synchronize_rcu() here because it's far |
216 | * too slow. It's up to the user to free the object using |
210 | * too slow. It's up to the user to free the object using |
217 | * call_rcu() or ttm_base_object_kfree(). |
211 | * call_rcu() or ttm_base_object_kfree(). |
218 | */ |
212 | */ |
219 | 213 | ||
220 | ttm_object_file_unref(&base->tfile); |
214 | ttm_object_file_unref(&base->tfile); |
221 | if (base->refcount_release) |
215 | if (base->refcount_release) |
222 | base->refcount_release(&base); |
216 | base->refcount_release(&base); |
223 | } |
217 | } |
224 | 218 | ||
225 | void ttm_base_object_unref(struct ttm_base_object **p_base) |
219 | void ttm_base_object_unref(struct ttm_base_object **p_base) |
226 | { |
220 | { |
227 | struct ttm_base_object *base = *p_base; |
221 | struct ttm_base_object *base = *p_base; |
228 | 222 | ||
229 | *p_base = NULL; |
223 | *p_base = NULL; |
230 | 224 | ||
231 | kref_put(&base->refcount, ttm_release_base); |
225 | kref_put(&base->refcount, ttm_release_base); |
232 | } |
226 | } |
233 | EXPORT_SYMBOL(ttm_base_object_unref); |
227 | EXPORT_SYMBOL(ttm_base_object_unref); |
234 | 228 | ||
235 | struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, |
229 | struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, |
236 | uint32_t key) |
230 | uint32_t key) |
237 | { |
231 | { |
238 | struct ttm_base_object *base = NULL; |
232 | struct ttm_base_object *base = NULL; |
239 | struct drm_hash_item *hash; |
233 | struct drm_hash_item *hash; |
240 | struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
234 | struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; |
241 | int ret; |
235 | int ret; |
242 | 236 | ||
243 | // rcu_read_lock(); |
237 | rcu_read_lock(); |
244 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
238 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
245 | 239 | ||
246 | if (likely(ret == 0)) { |
240 | if (likely(ret == 0)) { |
247 | base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
241 | base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; |
248 | if (!kref_get_unless_zero(&base->refcount)) |
242 | if (!kref_get_unless_zero(&base->refcount)) |
249 | base = NULL; |
243 | base = NULL; |
250 | } |
244 | } |
251 | // rcu_read_unlock(); |
245 | rcu_read_unlock(); |
252 | 246 | ||
253 | return base; |
247 | return base; |
254 | } |
248 | } |
255 | EXPORT_SYMBOL(ttm_base_object_lookup); |
249 | EXPORT_SYMBOL(ttm_base_object_lookup); |
256 | 250 | ||
257 | struct ttm_base_object * |
251 | struct ttm_base_object * |
258 | ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) |
252 | ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) |
259 | { |
253 | { |
260 | struct ttm_base_object *base = NULL; |
254 | struct ttm_base_object *base = NULL; |
261 | struct drm_hash_item *hash; |
255 | struct drm_hash_item *hash; |
262 | struct drm_open_hash *ht = &tdev->object_hash; |
256 | struct drm_open_hash *ht = &tdev->object_hash; |
263 | int ret; |
257 | int ret; |
- | 258 | ||
264 | 259 | rcu_read_lock(); |
|
265 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
260 | ret = drm_ht_find_item_rcu(ht, key, &hash); |
266 | 261 | ||
267 | if (likely(ret == 0)) { |
262 | if (likely(ret == 0)) { |
268 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
263 | base = drm_hash_entry(hash, struct ttm_base_object, hash); |
269 | if (!kref_get_unless_zero(&base->refcount)) |
264 | if (!kref_get_unless_zero(&base->refcount)) |
270 | base = NULL; |
265 | base = NULL; |
271 | } |
266 | } |
- | 267 | rcu_read_unlock(); |
|
272 | 268 | ||
273 | return base; |
269 | return base; |
274 | } |
270 | } |
275 | EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); |
271 | EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); |
276 | 272 | ||
277 | int ttm_ref_object_add(struct ttm_object_file *tfile, |
273 | int ttm_ref_object_add(struct ttm_object_file *tfile, |
278 | struct ttm_base_object *base, |
274 | struct ttm_base_object *base, |
279 | enum ttm_ref_type ref_type, bool *existed) |
275 | enum ttm_ref_type ref_type, bool *existed) |
280 | { |
276 | { |
281 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
277 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
282 | struct ttm_ref_object *ref; |
278 | struct ttm_ref_object *ref; |
283 | struct drm_hash_item *hash; |
279 | struct drm_hash_item *hash; |
284 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
280 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
285 | int ret = -EINVAL; |
281 | int ret = -EINVAL; |
286 | 282 | ||
287 | if (existed != NULL) |
283 | if (existed != NULL) |
288 | *existed = true; |
284 | *existed = true; |
289 | 285 | ||
290 | while (ret == -EINVAL) { |
286 | while (ret == -EINVAL) { |
- | 287 | rcu_read_lock(); |
|
291 | ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
288 | ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash); |
292 | 289 | ||
293 | if (ret == 0) { |
290 | if (ret == 0) { |
294 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
291 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
295 | if (!kref_get_unless_zero(&ref->kref)) { |
292 | if (kref_get_unless_zero(&ref->kref)) { |
- | 293 | rcu_read_unlock(); |
|
296 | break; |
294 | break; |
297 | } |
295 | } |
298 | } |
296 | } |
- | 297 | ||
299 | 298 | rcu_read_unlock(); |
|
300 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
299 | ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref), |
301 | false, false); |
300 | false, false); |
302 | if (unlikely(ret != 0)) |
301 | if (unlikely(ret != 0)) |
303 | return ret; |
302 | return ret; |
304 | ref = kmalloc(sizeof(*ref), GFP_KERNEL); |
303 | ref = kmalloc(sizeof(*ref), GFP_KERNEL); |
305 | if (unlikely(ref == NULL)) { |
304 | if (unlikely(ref == NULL)) { |
306 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
305 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
307 | return -ENOMEM; |
306 | return -ENOMEM; |
308 | } |
307 | } |
309 | 308 | ||
310 | ref->hash.key = base->hash.key; |
309 | ref->hash.key = base->hash.key; |
311 | ref->obj = base; |
310 | ref->obj = base; |
312 | ref->tfile = tfile; |
311 | ref->tfile = tfile; |
313 | ref->ref_type = ref_type; |
312 | ref->ref_type = ref_type; |
314 | kref_init(&ref->kref); |
313 | kref_init(&ref->kref); |
315 | 314 | ||
316 | spin_lock(&tfile->lock); |
315 | spin_lock(&tfile->lock); |
317 | ret = drm_ht_insert_item_rcu(ht, &ref->hash); |
316 | ret = drm_ht_insert_item_rcu(ht, &ref->hash); |
318 | 317 | ||
319 | if (likely(ret == 0)) { |
318 | if (likely(ret == 0)) { |
320 | list_add_tail(&ref->head, &tfile->ref_list); |
319 | list_add_tail(&ref->head, &tfile->ref_list); |
321 | kref_get(&base->refcount); |
320 | kref_get(&base->refcount); |
322 | spin_unlock(&tfile->lock); |
321 | spin_unlock(&tfile->lock); |
323 | if (existed != NULL) |
322 | if (existed != NULL) |
324 | *existed = false; |
323 | *existed = false; |
325 | break; |
324 | break; |
326 | } |
325 | } |
327 | 326 | ||
328 | spin_unlock(&tfile->lock); |
327 | spin_unlock(&tfile->lock); |
329 | BUG_ON(ret != -EINVAL); |
328 | BUG_ON(ret != -EINVAL); |
330 | 329 | ||
331 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
330 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
332 | kfree(ref); |
331 | kfree(ref); |
333 | } |
332 | } |
334 | 333 | ||
335 | return ret; |
334 | return ret; |
336 | } |
335 | } |
337 | EXPORT_SYMBOL(ttm_ref_object_add); |
336 | EXPORT_SYMBOL(ttm_ref_object_add); |
338 | 337 | ||
339 | static void ttm_ref_object_release(struct kref *kref) |
338 | static void ttm_ref_object_release(struct kref *kref) |
340 | { |
339 | { |
341 | struct ttm_ref_object *ref = |
340 | struct ttm_ref_object *ref = |
342 | container_of(kref, struct ttm_ref_object, kref); |
341 | container_of(kref, struct ttm_ref_object, kref); |
343 | struct ttm_base_object *base = ref->obj; |
342 | struct ttm_base_object *base = ref->obj; |
344 | struct ttm_object_file *tfile = ref->tfile; |
343 | struct ttm_object_file *tfile = ref->tfile; |
345 | struct drm_open_hash *ht; |
344 | struct drm_open_hash *ht; |
346 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
345 | struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob; |
347 | 346 | ||
348 | ht = &tfile->ref_hash[ref->ref_type]; |
347 | ht = &tfile->ref_hash[ref->ref_type]; |
349 | (void)drm_ht_remove_item_rcu(ht, &ref->hash); |
348 | (void)drm_ht_remove_item_rcu(ht, &ref->hash); |
350 | list_del(&ref->head); |
349 | list_del(&ref->head); |
351 | spin_unlock(&tfile->lock); |
350 | spin_unlock(&tfile->lock); |
352 | 351 | ||
353 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
352 | if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) |
354 | base->ref_obj_release(base, ref->ref_type); |
353 | base->ref_obj_release(base, ref->ref_type); |
355 | 354 | ||
356 | ttm_base_object_unref(&ref->obj); |
355 | ttm_base_object_unref(&ref->obj); |
357 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
356 | ttm_mem_global_free(mem_glob, sizeof(*ref)); |
358 | kfree(ref); |
357 | kfree_rcu(ref, rcu_head); |
359 | spin_lock(&tfile->lock); |
358 | spin_lock(&tfile->lock); |
360 | } |
359 | } |
361 | 360 | ||
362 | int ttm_ref_object_base_unref(struct ttm_object_file *tfile, |
361 | int ttm_ref_object_base_unref(struct ttm_object_file *tfile, |
363 | unsigned long key, enum ttm_ref_type ref_type) |
362 | unsigned long key, enum ttm_ref_type ref_type) |
364 | { |
363 | { |
365 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
364 | struct drm_open_hash *ht = &tfile->ref_hash[ref_type]; |
366 | struct ttm_ref_object *ref; |
365 | struct ttm_ref_object *ref; |
367 | struct drm_hash_item *hash; |
366 | struct drm_hash_item *hash; |
368 | int ret; |
367 | int ret; |
369 | 368 | ||
370 | spin_lock(&tfile->lock); |
369 | spin_lock(&tfile->lock); |
371 | ret = drm_ht_find_item(ht, key, &hash); |
370 | ret = drm_ht_find_item(ht, key, &hash); |
372 | if (unlikely(ret != 0)) { |
371 | if (unlikely(ret != 0)) { |
373 | spin_unlock(&tfile->lock); |
372 | spin_unlock(&tfile->lock); |
374 | return -EINVAL; |
373 | return -EINVAL; |
375 | } |
374 | } |
376 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
375 | ref = drm_hash_entry(hash, struct ttm_ref_object, hash); |
377 | kref_put(&ref->kref, ttm_ref_object_release); |
376 | kref_put(&ref->kref, ttm_ref_object_release); |
378 | spin_unlock(&tfile->lock); |
377 | spin_unlock(&tfile->lock); |
379 | return 0; |
378 | return 0; |
380 | } |
379 | } |
381 | EXPORT_SYMBOL(ttm_ref_object_base_unref); |
380 | EXPORT_SYMBOL(ttm_ref_object_base_unref); |
382 | 381 | ||
383 | void ttm_object_file_release(struct ttm_object_file **p_tfile) |
382 | void ttm_object_file_release(struct ttm_object_file **p_tfile) |
384 | { |
383 | { |
385 | struct ttm_ref_object *ref; |
384 | struct ttm_ref_object *ref; |
386 | struct list_head *list; |
385 | struct list_head *list; |
387 | unsigned int i; |
386 | unsigned int i; |
388 | struct ttm_object_file *tfile = *p_tfile; |
387 | struct ttm_object_file *tfile = *p_tfile; |
389 | 388 | ||
390 | *p_tfile = NULL; |
389 | *p_tfile = NULL; |
391 | spin_lock(&tfile->lock); |
390 | spin_lock(&tfile->lock); |
392 | 391 | ||
393 | /* |
392 | /* |
394 | * Since we release the lock within the loop, we have to |
393 | * Since we release the lock within the loop, we have to |
395 | * restart it from the beginning each time. |
394 | * restart it from the beginning each time. |
396 | */ |
395 | */ |
397 | 396 | ||
398 | while (!list_empty(&tfile->ref_list)) { |
397 | while (!list_empty(&tfile->ref_list)) { |
399 | list = tfile->ref_list.next; |
398 | list = tfile->ref_list.next; |
400 | ref = list_entry(list, struct ttm_ref_object, head); |
399 | ref = list_entry(list, struct ttm_ref_object, head); |
401 | ttm_ref_object_release(&ref->kref); |
400 | ttm_ref_object_release(&ref->kref); |
402 | } |
401 | } |
403 | 402 | ||
404 | for (i = 0; i < TTM_REF_NUM; ++i) |
403 | for (i = 0; i < TTM_REF_NUM; ++i) |
405 | drm_ht_remove(&tfile->ref_hash[i]); |
404 | drm_ht_remove(&tfile->ref_hash[i]); |
406 | 405 | ||
407 | spin_unlock(&tfile->lock); |
406 | spin_unlock(&tfile->lock); |
408 | ttm_object_file_unref(&tfile); |
407 | ttm_object_file_unref(&tfile); |
409 | } |
408 | } |
410 | EXPORT_SYMBOL(ttm_object_file_release); |
409 | EXPORT_SYMBOL(ttm_object_file_release); |
411 | 410 | ||
412 | struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, |
411 | struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, |
413 | unsigned int hash_order) |
412 | unsigned int hash_order) |
414 | { |
413 | { |
415 | struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); |
414 | struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); |
416 | unsigned int i; |
415 | unsigned int i; |
417 | unsigned int j = 0; |
416 | unsigned int j = 0; |
418 | int ret; |
417 | int ret; |
419 | 418 | ||
420 | if (unlikely(tfile == NULL)) |
419 | if (unlikely(tfile == NULL)) |
421 | return NULL; |
420 | return NULL; |
422 | 421 | ||
423 | spin_lock_init(&tfile->lock); |
422 | spin_lock_init(&tfile->lock); |
424 | tfile->tdev = tdev; |
423 | tfile->tdev = tdev; |
425 | kref_init(&tfile->refcount); |
424 | kref_init(&tfile->refcount); |
426 | INIT_LIST_HEAD(&tfile->ref_list); |
425 | INIT_LIST_HEAD(&tfile->ref_list); |
427 | 426 | ||
428 | for (i = 0; i < TTM_REF_NUM; ++i) { |
427 | for (i = 0; i < TTM_REF_NUM; ++i) { |
429 | ret = drm_ht_create(&tfile->ref_hash[i], hash_order); |
428 | ret = drm_ht_create(&tfile->ref_hash[i], hash_order); |
430 | if (ret) { |
429 | if (ret) { |
431 | j = i; |
430 | j = i; |
432 | goto out_err; |
431 | goto out_err; |
433 | } |
432 | } |
434 | } |
433 | } |
435 | 434 | ||
436 | return tfile; |
435 | return tfile; |
437 | out_err: |
436 | out_err: |
438 | for (i = 0; i < j; ++i) |
437 | for (i = 0; i < j; ++i) |
439 | drm_ht_remove(&tfile->ref_hash[i]); |
438 | drm_ht_remove(&tfile->ref_hash[i]); |
440 | 439 | ||
441 | kfree(tfile); |
440 | kfree(tfile); |
442 | 441 | ||
443 | return NULL; |
442 | return NULL; |
444 | } |
443 | } |
445 | EXPORT_SYMBOL(ttm_object_file_init); |
444 | EXPORT_SYMBOL(ttm_object_file_init); |
446 | 445 | ||
447 | struct ttm_object_device * |
446 | struct ttm_object_device * |
448 | ttm_object_device_init(struct ttm_mem_global *mem_glob, |
447 | ttm_object_device_init(struct ttm_mem_global *mem_glob, |
449 | unsigned int hash_order, |
448 | unsigned int hash_order, |
450 | const struct dma_buf_ops *ops) |
449 | const struct dma_buf_ops *ops) |
451 | { |
450 | { |
452 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
451 | struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); |
453 | int ret; |
452 | int ret; |
454 | 453 | ||
455 | if (unlikely(tdev == NULL)) |
454 | if (unlikely(tdev == NULL)) |
456 | return NULL; |
455 | return NULL; |
457 | 456 | ||
458 | tdev->mem_glob = mem_glob; |
457 | tdev->mem_glob = mem_glob; |
459 | spin_lock_init(&tdev->object_lock); |
458 | spin_lock_init(&tdev->object_lock); |
460 | atomic_set(&tdev->object_count, 0); |
459 | atomic_set(&tdev->object_count, 0); |
461 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
460 | ret = drm_ht_create(&tdev->object_hash, hash_order); |
462 | if (ret != 0) |
461 | if (ret != 0) |
463 | goto out_no_object_hash; |
462 | goto out_no_object_hash; |
464 | 463 | ||
465 | // tdev->ops = *ops; |
464 | tdev->ops = *ops; |
466 | // tdev->dmabuf_release = tdev->ops.release; |
465 | tdev->dmabuf_release = tdev->ops.release; |
467 | // tdev->ops.release = ttm_prime_dmabuf_release; |
466 | tdev->ops.release = ttm_prime_dmabuf_release; |
468 | // tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
467 | tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) + |
469 | // ttm_round_pot(sizeof(struct file)); |
468 | ttm_round_pot(sizeof(struct file)); |
470 | return tdev; |
469 | return tdev; |
471 | 470 | ||
472 | out_no_object_hash: |
471 | out_no_object_hash: |
473 | kfree(tdev); |
472 | kfree(tdev); |
474 | return NULL; |
473 | return NULL; |
475 | } |
474 | } |
476 | EXPORT_SYMBOL(ttm_object_device_init); |
475 | EXPORT_SYMBOL(ttm_object_device_init); |
477 | 476 | ||
478 | void ttm_object_device_release(struct ttm_object_device **p_tdev) |
477 | void ttm_object_device_release(struct ttm_object_device **p_tdev) |
479 | { |
478 | { |
480 | struct ttm_object_device *tdev = *p_tdev; |
479 | struct ttm_object_device *tdev = *p_tdev; |
481 | 480 | ||
482 | *p_tdev = NULL; |
481 | *p_tdev = NULL; |
483 | 482 | ||
484 | spin_lock(&tdev->object_lock); |
483 | spin_lock(&tdev->object_lock); |
485 | drm_ht_remove(&tdev->object_hash); |
484 | drm_ht_remove(&tdev->object_hash); |
486 | spin_unlock(&tdev->object_lock); |
485 | spin_unlock(&tdev->object_lock); |
487 | 486 | ||
488 | kfree(tdev); |
487 | kfree(tdev); |
489 | } |
488 | } |
490 | EXPORT_SYMBOL(ttm_object_device_release);>>> |
489 | EXPORT_SYMBOL(ttm_object_device_release); |
- | 490 | ||
- | 491 | /** |
|
- | 492 | * get_dma_buf_unless_doomed - get a dma_buf reference if possible. |
|
- | 493 | * |
|
- | 494 | * @dma_buf: Non-refcounted pointer to a struct dma-buf. |
|
- | 495 | * |
|
- | 496 | * Obtain a file reference from a lookup structure that doesn't refcount |
|
- | 497 | * the file, but synchronizes with its release method to make sure it has |
|
- | 498 | * not been freed yet. See for example kref_get_unless_zero documentation. |
|
- | 499 | * Returns true if refcounting succeeds, false otherwise. |
|
- | 500 | * |
|
- | 501 | * Nobody really wants this as a public API yet, so let it mature here |
|
- | 502 | * for some time... |
|
- | 503 | */ |
|
- | 504 | static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) |
|
- | 505 | { |
|
- | 506 | return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; |
|
- | 507 | } |
|
- | 508 | ||
- | 509 | /** |
|
- | 510 | * ttm_prime_refcount_release - refcount release method for a prime object. |
|
- | 511 | * |
|
- | 512 | * @p_base: Pointer to ttm_base_object pointer. |
|
- | 513 | * |
|
- | 514 | * This is a wrapper that calls the refcount_release founction of the |
|
- | 515 | * underlying object. At the same time it cleans up the prime object. |
|
- | 516 | * This function is called when all references to the base object we |
|
- | 517 | * derive from are gone. |
|
- | 518 | */ |
|
- | 519 | static void ttm_prime_refcount_release(struct ttm_base_object **p_base) |
|
- | 520 | { |
|
- | 521 | struct ttm_base_object *base = *p_base; |
|
- | 522 | struct ttm_prime_object *prime; |
|
- | 523 | ||
- | 524 | *p_base = NULL; |
|
- | 525 | prime = container_of(base, struct ttm_prime_object, base); |
|
- | 526 | BUG_ON(prime->dma_buf != NULL); |
|
- | 527 | mutex_destroy(&prime->mutex); |
|
- | 528 | if (prime->refcount_release) |
|
- | 529 | prime->refcount_release(&base); |
|
- | 530 | } |
|
- | 531 | ||
- | 532 | /** |
|
- | 533 | * ttm_prime_dmabuf_release - Release method for the dma-bufs we export |
|
- | 534 | * |
|
- | 535 | * @dma_buf: |
|
- | 536 | * |
|
- | 537 | * This function first calls the dma_buf release method the driver |
|
- | 538 | * provides. Then it cleans up our dma_buf pointer used for lookup, |
|
- | 539 | * and finally releases the reference the dma_buf has on our base |
|
- | 540 | * object. |
|
- | 541 | */ |
|
- | 542 | static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf) |
|
- | 543 | { |
|
- | 544 | struct ttm_prime_object *prime = |
|
- | 545 | (struct ttm_prime_object *) dma_buf->priv; |
|
- | 546 | struct ttm_base_object *base = &prime->base; |
|
- | 547 | struct ttm_object_device *tdev = base->tfile->tdev; |
|
- | 548 | ||
- | 549 | if (tdev->dmabuf_release) |
|
- | 550 | tdev->dmabuf_release(dma_buf); |
|
- | 551 | mutex_lock(&prime->mutex); |
|
- | 552 | if (prime->dma_buf == dma_buf) |
|
- | 553 | prime->dma_buf = NULL; |
|
- | 554 | mutex_unlock(&prime->mutex); |
|
- | 555 | ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size); |
|
- | 556 | ttm_base_object_unref(&base); |
|
- | 557 | } |
|
- | 558 | ||
- | 559 | /** |
|
- | 560 | * ttm_prime_fd_to_handle - Get a base object handle from a prime fd |
|
- | 561 | * |
|
- | 562 | * @tfile: A struct ttm_object_file identifying the caller. |
|
- | 563 | * @fd: The prime / dmabuf fd. |
|
- | 564 | * @handle: The returned handle. |
|
- | 565 | * |
|
- | 566 | * This function returns a handle to an object that previously exported |
|
- | 567 | * a dma-buf. Note that we don't handle imports yet, because we simply |
|
- | 568 | * have no consumers of that implementation. |
|
- | 569 | */ |
|
- | 570 | int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, |
|
- | 571 | int fd, u32 *handle) |
|
- | 572 | { |
|
- | 573 | struct ttm_object_device *tdev = tfile->tdev; |
|
- | 574 | struct dma_buf *dma_buf; |
|
- | 575 | struct ttm_prime_object *prime; |
|
- | 576 | struct ttm_base_object *base; |
|
- | 577 | int ret; |
|
- | 578 | ||
- | 579 | dma_buf = dma_buf_get(fd); |
|
- | 580 | if (IS_ERR(dma_buf)) |
|
- | 581 | return PTR_ERR(dma_buf); |
|
- | 582 | ||
- | 583 | if (dma_buf->ops != &tdev->ops) |
|
- | 584 | return -ENOSYS; |
|
- | 585 | ||
- | 586 | prime = (struct ttm_prime_object *) dma_buf->priv; |
|
- | 587 | base = &prime->base; |
|
- | 588 | *handle = base->hash.key; |
|
- | 589 | ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); |
|
- | 590 | ||
- | 591 | dma_buf_put(dma_buf); |
|
- | 592 | ||
- | 593 | return ret; |
|
- | 594 | } |
|
- | 595 | EXPORT_SYMBOL_GPL(ttm_prime_fd_to_handle); |
|
- | 596 | ||
- | 597 | /** |
|
- | 598 | * ttm_prime_handle_to_fd - Return a dma_buf fd from a ttm prime object |
|
- | 599 | * |
|
- | 600 | * @tfile: Struct ttm_object_file identifying the caller. |
|
- | 601 | * @handle: Handle to the object we're exporting from. |
|
- | 602 | * @flags: flags for dma-buf creation. We just pass them on. |
|
- | 603 | * @prime_fd: The returned file descriptor. |
|
- | 604 | * |
|
- | 605 | */ |
|
- | 606 | int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, |
|
- | 607 | uint32_t handle, uint32_t flags, |
|
- | 608 | int *prime_fd) |
|
- | 609 | { |
|
- | 610 | struct ttm_object_device *tdev = tfile->tdev; |
|
- | 611 | struct ttm_base_object *base; |
|
- | 612 | struct dma_buf *dma_buf; |
|
- | 613 | struct ttm_prime_object *prime; |
|
- | 614 | int ret; |
|
- | 615 | ||
- | 616 | base = ttm_base_object_lookup(tfile, handle); |
|
- | 617 | if (unlikely(base == NULL || |
|
- | 618 | base->object_type != ttm_prime_type)) { |
|
- | 619 | ret = -ENOENT; |
|
- | 620 | goto out_unref; |
|
- | 621 | } |
|
- | 622 | ||
- | 623 | prime = container_of(base, struct ttm_prime_object, base); |
|
- | 624 | if (unlikely(!base->shareable)) { |
|
- | 625 | ret = -EPERM; |
|
- | 626 | goto out_unref; |
|
- | 627 | } |
|
- | 628 | ||
- | 629 | ret = mutex_lock_interruptible(&prime->mutex); |
|
- | 630 | if (unlikely(ret != 0)) { |
|
- | 631 | ret = -ERESTARTSYS; |
|
- | 632 | goto out_unref; |
|
- | 633 | } |
|
- | 634 | ||
- | 635 | dma_buf = prime->dma_buf; |
|
- | 636 | if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { |
|
- | 637 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); |
|
- | 638 | ||
- | 639 | exp_info.ops = &tdev->ops; |
|
- | 640 | exp_info.size = prime->size; |
|
- | 641 | exp_info.flags = flags; |
|
- | 642 | exp_info.priv = prime; |
|
- | 643 | ||
- | 644 | /* |
|
- | 645 | * Need to create a new dma_buf, with memory accounting. |
|
- | 646 | */ |
|
- | 647 | ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size, |
|
- | 648 | false, true); |
|
- | 649 | if (unlikely(ret != 0)) { |
|
- | 650 | mutex_unlock(&prime->mutex); |
|
- | 651 | goto out_unref; |
|
- | 652 | } |
|
- | 653 | ||
- | 654 | dma_buf = dma_buf_export(&exp_info); |
|
- | 655 | if (IS_ERR(dma_buf)) { |
|
- | 656 | ret = PTR_ERR(dma_buf); |
|
- | 657 | ttm_mem_global_free(tdev->mem_glob, |
|
- | 658 | tdev->dma_buf_size); |
|
- | 659 | mutex_unlock(&prime->mutex); |
|
- | 660 | goto out_unref; |
|
- | 661 | } |
|
- | 662 | ||
- | 663 | /* |
|
- | 664 | * dma_buf has taken the base object reference |
|
- | 665 | */ |
|
- | 666 | base = NULL; |
|
- | 667 | prime->dma_buf = dma_buf; |
|
- | 668 | } |
|
- | 669 | mutex_unlock(&prime->mutex); |
|
- | 670 | ||
- | 671 | ret = dma_buf_fd(dma_buf, flags); |
|
- | 672 | if (ret >= 0) { |
|
- | 673 | *prime_fd = ret; |
|
- | 674 | ret = 0; |
|
- | 675 | } else |
|
- | 676 | dma_buf_put(dma_buf); |
|
- | 677 | ||
- | 678 | out_unref: |
|
- | 679 | if (base) |
|
- | 680 | ttm_base_object_unref(&base); |
|
- | 681 | return ret; |
|
- | 682 | } |
|
- | 683 | EXPORT_SYMBOL_GPL(ttm_prime_handle_to_fd); |
|
- | 684 | ||
- | 685 | /** |
|
- | 686 | * ttm_prime_object_init - Initialize a ttm_prime_object |
|
- | 687 | * |
|
- | 688 | * @tfile: struct ttm_object_file identifying the caller |
|
- | 689 | * @size: The size of the dma_bufs we export. |
|
- | 690 | * @prime: The object to be initialized. |
|
- | 691 | * @shareable: See ttm_base_object_init |
|
- | 692 | * @type: See ttm_base_object_init |
|
- | 693 | * @refcount_release: See ttm_base_object_init |
|
- | 694 | * @ref_obj_release: See ttm_base_object_init |
|
- | 695 | * |
|
- | 696 | * Initializes an object which is compatible with the drm_prime model |
|
- | 697 | * for data sharing between processes and devices. |
|
- | 698 | */ |
|
- | 699 | int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, |
|
- | 700 | struct ttm_prime_object *prime, bool shareable, |
|
- | 701 | enum ttm_object_type type, |
|
- | 702 | void (*refcount_release) (struct ttm_base_object **), |
|
- | 703 | void (*ref_obj_release) (struct ttm_base_object *, |
|
- | 704 | enum ttm_ref_type ref_type)) |
|
- | 705 | { |
|
- | 706 | mutex_init(&prime->mutex); |
|
- | 707 | prime->size = PAGE_ALIGN(size); |
|
- | 708 | prime->real_type = type; |
|
- | 709 | prime->dma_buf = NULL; |
|
- | 710 | prime->refcount_release = refcount_release; |
|
- | 711 | return ttm_base_object_init(tfile, &prime->base, shareable, |
|
- | 712 | ttm_prime_type, |
|
- | 713 | ttm_prime_refcount_release, |
|
- | 714 | ref_obj_release); |
|
- | 715 | } |
|
- | 716 | EXPORT_SYMBOL(ttm_prime_object_init);>>> |