OSDN Git Service

libdrm/nouveau: incr refcount on ref fence before decr on old fence
[android-x86/external-libdrm.git] / linux-core / drm_compat.c
1 /**************************************************************************
2  *
3  * This kernel module is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License as
5  * published by the Free Software Foundation; either version 2 of the
6  * License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  **************************************************************************/
18 /*
19  * This code provides access to unexported mm kernel features. It is necessary
20  * to use the new DRM memory manager code with kernels that don't support it
21  * directly.
22  *
23  * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
24  *          Linux kernel mm subsystem authors.
25  *          (Most code taken from there).
26  */
27
28 #include "drmP.h"
29
30 #ifdef DRM_IDR_COMPAT_FN
31 /* only called when idp->lock is held */
32 static void __free_layer(struct idr *idp, struct idr_layer *p)
33 {
34         p->ary[0] = idp->id_free;
35         idp->id_free = p;
36         idp->id_free_cnt++;
37 }
38
39 static void free_layer(struct idr *idp, struct idr_layer *p)
40 {
41         unsigned long flags;
42
43         /*
44          * Depends on the return element being zeroed.
45          */
46         spin_lock_irqsave(&idp->lock, flags);
47         __free_layer(idp, p);
48         spin_unlock_irqrestore(&idp->lock, flags);
49 }
50
51 /**
52  * idr_for_each - iterate through all stored pointers
53  * @idp: idr handle
54  * @fn: function to be called for each pointer
55  * @data: data passed back to callback function
56  *
57  * Iterate over the pointers registered with the given idr.  The
58  * callback function will be called for each pointer currently
59  * registered, passing the id, the pointer and the data pointer passed
60  * to this function.  It is not safe to modify the idr tree while in
61  * the callback, so functions such as idr_get_new and idr_remove are
62  * not allowed.
63  *
64  * We check the return of @fn each time. If it returns anything other
65  * than 0, we break out and return that value.
66  *
67 * The caller must serialize idr_find() vs idr_get_new() and idr_remove().
68  */
69 int idr_for_each(struct idr *idp,
70                  int (*fn)(int id, void *p, void *data), void *data)
71 {
72         int n, id, max, error = 0;
73         struct idr_layer *p;
74         struct idr_layer *pa[MAX_LEVEL];
75         struct idr_layer **paa = &pa[0];
76
77         n = idp->layers * IDR_BITS;
78         p = idp->top;
79         max = 1 << n;
80
81         id = 0;
82         while (id < max) {
83                 while (n > 0 && p) {
84                         n -= IDR_BITS;
85                         *paa++ = p;
86                         p = p->ary[(id >> n) & IDR_MASK];
87                 }
88
89                 if (p) {
90                         error = fn(id, (void *)p, data);
91                         if (error)
92                                 break;
93                 }
94
95                 id += 1 << n;
96                 while (n < fls(id)) {
97                         n += IDR_BITS;
98                         p = *--paa;
99                 }
100         }
101
102         return error;
103 }
104 EXPORT_SYMBOL(idr_for_each);
105
106 /**
107  * idr_remove_all - remove all ids from the given idr tree
108  * @idp: idr handle
109  *
110  * idr_destroy() only frees up unused, cached idp_layers, but this
111  * function will remove all id mappings and leave all idp_layers
112  * unused.
113  *
114  * A typical clean-up sequence for objects stored in an idr tree, will
115  * use idr_for_each() to free all objects, if necessay, then
116  * idr_remove_all() to remove all ids, and idr_destroy() to free
117  * up the cached idr_layers.
118  */
119 void idr_remove_all(struct idr *idp)
120 {
121        int n, id, max, error = 0;
122        struct idr_layer *p;
123        struct idr_layer *pa[MAX_LEVEL];
124        struct idr_layer **paa = &pa[0];
125
126        n = idp->layers * IDR_BITS;
127        p = idp->top;
128        max = 1 << n;
129
130        id = 0;
131        while (id < max && !error) {
132                while (n > IDR_BITS && p) {
133                        n -= IDR_BITS;
134                        *paa++ = p;
135                        p = p->ary[(id >> n) & IDR_MASK];
136                }
137
138                id += 1 << n;
139                while (n < fls(id)) {
140                        if (p) {
141                                memset(p, 0, sizeof *p);
142                                free_layer(idp, p);
143                        }
144                        n += IDR_BITS;
145                        p = *--paa;
146                }
147        }
148        idp->top = NULL;
149        idp->layers = 0;
150 }
151 EXPORT_SYMBOL(idr_remove_all);
152
153 #endif /* DRM_IDR_COMPAT_FN */
154
155
156 #ifdef DRM_NO_FAULT
157 unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
158                               unsigned long address)
159 {
160         struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data;
161         unsigned long page_offset;
162         struct page *page = NULL;
163         struct drm_ttm *ttm;
164         struct drm_device *dev;
165         unsigned long pfn;
166         int err;
167         unsigned long bus_base;
168         unsigned long bus_offset;
169         unsigned long bus_size;
170         unsigned long ret = NOPFN_REFAULT;
171
172         if (address > vma->vm_end)
173                 return NOPFN_SIGBUS;
174
175         dev = bo->dev;
176         err = drm_bo_read_lock(&dev->bm.bm_lock, 1);
177         if (err)
178                 return NOPFN_REFAULT;
179
180         err = mutex_lock_interruptible(&bo->mutex);
181         if (err) {
182                 drm_bo_read_unlock(&dev->bm.bm_lock);
183                 return NOPFN_REFAULT;
184         }
185
186         err = drm_bo_wait(bo, 0, 1, 0, 1);
187         if (err) {
188                 ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
189                 bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED;
190                 goto out_unlock;
191         }
192
193         bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED;
194
195         /*
196          * If buffer happens to be in a non-mappable location,
197          * move it to a mappable.
198          */
199
200         if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
201                 uint32_t new_flags = bo->mem.proposed_flags |
202                         DRM_BO_FLAG_MAPPABLE |
203                         DRM_BO_FLAG_FORCE_MAPPABLE;
204                 err = drm_bo_move_buffer(bo, new_flags, 0, 0);
205                 if (err) {
206                         ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
207                         goto out_unlock;
208                 }
209         }
210
211         err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
212                                 &bus_size);
213
214         if (err) {
215                 ret = NOPFN_SIGBUS;
216                 goto out_unlock;
217         }
218
219         page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
220
221         if (bus_size) {
222                 struct drm_mem_type_manager *man = &dev->bm.man[bo->mem.mem_type];
223
224                 pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset;
225                 vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma);
226         } else {
227                 ttm = bo->ttm;
228
229                 drm_ttm_fixup_caching(ttm);
230                 page = drm_ttm_get_page(ttm, page_offset);
231                 if (!page) {
232                         ret = NOPFN_OOM;
233                         goto out_unlock;
234                 }
235                 pfn = page_to_pfn(page);
236                 vma->vm_page_prot = (bo->mem.flags & DRM_BO_FLAG_CACHED) ?
237                         vm_get_page_prot(vma->vm_flags) :
238                         drm_io_prot(_DRM_TTM, vma);
239         }
240
241         err = vm_insert_pfn(vma, address, pfn);
242         if (err) {
243                 ret = (err != -EAGAIN) ? NOPFN_OOM : NOPFN_REFAULT;
244                 goto out_unlock;
245         }
246 out_unlock:
247         BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED);
248         mutex_unlock(&bo->mutex);
249         drm_bo_read_unlock(&dev->bm.bm_lock);
250         return ret;
251 }
252 #endif