OSDN Git Service

initial import
[android-x86/device-viliv-s5.git] / psb-kernel-source-4.41.1 / drm_object.c
1 /**************************************************************************
2  *
3  * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
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
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
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,
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,
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
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 /*
28  * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
29  */
30
31 #include "drmP.h"
32
33 int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item,
34                         int shareable)
35 {
36         struct drm_device *dev = priv->head->dev;
37         int ret;
38
39         DRM_ASSERT_LOCKED(&dev->struct_mutex);
40
41         /* The refcount will be bumped to 1 when we add the ref object below. */
42         atomic_set(&item->refcount, 0);
43         item->shareable = shareable;
44         item->owner = priv;
45
46         ret = drm_ht_just_insert_please(&dev->object_hash, &item->hash,
47                                         (unsigned long)item, 32, 0, 0);
48         if (ret)
49                 return ret;
50
51         ret = drm_add_ref_object(priv, item, _DRM_REF_USE);
52         if (ret)
53                 ret = drm_ht_remove_item(&dev->object_hash, &item->hash);
54
55         return ret;
56 }
57 EXPORT_SYMBOL(drm_add_user_object);
58
59 struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key)
60 {
61         struct drm_device *dev = priv->head->dev;
62         struct drm_hash_item *hash;
63         int ret;
64         struct drm_user_object *item;
65
66         DRM_ASSERT_LOCKED(&dev->struct_mutex);
67
68         ret = drm_ht_find_item(&dev->object_hash, key, &hash);
69         if (ret)
70                 return NULL;
71
72         item = drm_hash_entry(hash, struct drm_user_object, hash);
73
74         if (priv != item->owner) {
75                 struct drm_open_hash *ht = &priv->refd_object_hash[_DRM_REF_USE];
76                 ret = drm_ht_find_item(ht, (unsigned long)item, &hash);
77                 if (ret) {
78                         DRM_ERROR("Object not registered for usage\n");
79                         return NULL;
80                 }
81         }
82         return item;
83 }
84 EXPORT_SYMBOL(drm_lookup_user_object);
85
86 static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item)
87 {
88         struct drm_device *dev = priv->head->dev;
89         int ret;
90
91         if (atomic_dec_and_test(&item->refcount)) {
92                 ret = drm_ht_remove_item(&dev->object_hash, &item->hash);
93                 BUG_ON(ret);
94                 item->remove(priv, item);
95         }
96 }
97
98 static int drm_object_ref_action(struct drm_file *priv, struct drm_user_object *ro,
99                                  enum drm_ref_type action)
100 {
101         int ret = 0;
102
103         switch (action) {
104         case _DRM_REF_USE:
105                 atomic_inc(&ro->refcount);
106                 break;
107         default:
108                 if (!ro->ref_struct_locked) {
109                         break;
110                 } else {
111                         ro->ref_struct_locked(priv, ro, action);
112                 }
113         }
114         return ret;
115 }
116
117 int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced_object,
118                        enum drm_ref_type ref_action)
119 {
120         int ret = 0;
121         struct drm_ref_object *item;
122         struct drm_open_hash *ht = &priv->refd_object_hash[ref_action];
123
124         DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
125         if (!referenced_object->shareable && priv != referenced_object->owner) {
126                 DRM_ERROR("Not allowed to reference this object\n");
127                 return -EINVAL;
128         }
129
130         /*
131          * If this is not a usage reference, Check that usage has been registered
132          * first. Otherwise strange things may happen on destruction.
133          */
134
135         if ((ref_action != _DRM_REF_USE) && priv != referenced_object->owner) {
136                 item =
137                     drm_lookup_ref_object(priv, referenced_object,
138                                           _DRM_REF_USE);
139                 if (!item) {
140                         DRM_ERROR
141                             ("Object not registered for usage by this client\n");
142                         return -EINVAL;
143                 }
144         }
145
146         if (NULL !=
147             (item =
148              drm_lookup_ref_object(priv, referenced_object, ref_action))) {
149                 atomic_inc(&item->refcount);
150                 return drm_object_ref_action(priv, referenced_object,
151                                              ref_action);
152         }
153
154         item = drm_ctl_calloc(1, sizeof(*item), DRM_MEM_OBJECTS);
155         if (item == NULL) {
156                 DRM_ERROR("Could not allocate reference object\n");
157                 return -ENOMEM;
158         }
159
160         atomic_set(&item->refcount, 1);
161         item->hash.key = (unsigned long)referenced_object;
162         ret = drm_ht_insert_item(ht, &item->hash);
163         item->unref_action = ref_action;
164
165         if (ret)
166                 goto out;
167
168         list_add(&item->list, &priv->refd_objects);
169         ret = drm_object_ref_action(priv, referenced_object, ref_action);
170 out:
171         return ret;
172 }
173
174 struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv,
175                                         struct drm_user_object *referenced_object,
176                                         enum drm_ref_type ref_action)
177 {
178         struct drm_hash_item *hash;
179         int ret;
180
181         DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
182         ret = drm_ht_find_item(&priv->refd_object_hash[ref_action],
183                                (unsigned long)referenced_object, &hash);
184         if (ret)
185                 return NULL;
186
187         return drm_hash_entry(hash, struct drm_ref_object, hash);
188 }
189 EXPORT_SYMBOL(drm_lookup_ref_object);
190
191 static void drm_remove_other_references(struct drm_file *priv,
192                                         struct drm_user_object *ro)
193 {
194         int i;
195         struct drm_open_hash *ht;
196         struct drm_hash_item *hash;
197         struct drm_ref_object *item;
198
199         for (i = _DRM_REF_USE + 1; i < _DRM_NO_REF_TYPES; ++i) {
200                 ht = &priv->refd_object_hash[i];
201                 while (!drm_ht_find_item(ht, (unsigned long)ro, &hash)) {
202                         item = drm_hash_entry(hash, struct drm_ref_object, hash);
203                         drm_remove_ref_object(priv, item);
204                 }
205         }
206 }
207
208 void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item)
209 {
210         int ret;
211         struct drm_user_object *user_object = (struct drm_user_object *) item->hash.key;
212         struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action];
213         enum drm_ref_type unref_action;
214
215         DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
216         unref_action = item->unref_action;
217         if (atomic_dec_and_test(&item->refcount)) {
218                 ret = drm_ht_remove_item(ht, &item->hash);
219                 BUG_ON(ret);
220                 list_del_init(&item->list);
221                 if (unref_action == _DRM_REF_USE)
222                         drm_remove_other_references(priv, user_object);
223                 drm_ctl_free(item, sizeof(*item), DRM_MEM_OBJECTS);
224         }
225
226         switch (unref_action) {
227         case _DRM_REF_USE:
228                 drm_deref_user_object(priv, user_object);
229                 break;
230         default:
231                 BUG_ON(!user_object->unref);
232                 user_object->unref(priv, user_object, unref_action);
233                 break;
234         }
235
236 }
237 EXPORT_SYMBOL(drm_remove_ref_object);
238
239 int drm_user_object_ref(struct drm_file *priv, uint32_t user_token,
240                         enum drm_object_type type, struct drm_user_object **object)
241 {
242         struct drm_device *dev = priv->head->dev;
243         struct drm_user_object *uo;
244         struct drm_hash_item *hash;
245         int ret;
246
247         mutex_lock(&dev->struct_mutex);
248         ret = drm_ht_find_item(&dev->object_hash, user_token, &hash);
249         if (ret) {
250                 DRM_ERROR("Could not find user object to reference.\n");
251                 goto out_err;
252         }
253         uo = drm_hash_entry(hash, struct drm_user_object, hash);
254         if (uo->type != type) {
255                 ret = -EINVAL;
256                 goto out_err;
257         }
258         ret = drm_add_ref_object(priv, uo, _DRM_REF_USE);
259         if (ret)
260                 goto out_err;
261         mutex_unlock(&dev->struct_mutex);
262         *object = uo;
263         return 0;
264 out_err:
265         mutex_unlock(&dev->struct_mutex);
266         return ret;
267 }
268
269 int drm_user_object_unref(struct drm_file *priv, uint32_t user_token,
270                           enum drm_object_type type)
271 {
272         struct drm_device *dev = priv->head->dev;
273         struct drm_user_object *uo;
274         struct drm_ref_object *ro;
275         int ret;
276
277         mutex_lock(&dev->struct_mutex);
278         uo = drm_lookup_user_object(priv, user_token);
279         if (!uo || (uo->type != type)) {
280                 ret = -EINVAL;
281                 goto out_err;
282         }
283         ro = drm_lookup_ref_object(priv, uo, _DRM_REF_USE);
284         if (!ro) {
285                 ret = -EINVAL;
286                 goto out_err;
287         }
288         drm_remove_ref_object(priv, ro);
289         mutex_unlock(&dev->struct_mutex);
290         return 0;
291 out_err:
292         mutex_unlock(&dev->struct_mutex);
293         return ret;
294 }