OSDN Git Service

drm: convert drawable handling to use Linux idr
[android-x86/external-libdrm.git] / linux-core / via_mm.c
1 /*
2  * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
3  * All rights reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sub license,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 /*
25  * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
26  */
27
28 #include "drmP.h"
29 #include "via_drm.h"
30 #include "via_drv.h"
31 #include "drm_sman.h"
32
33 #define VIA_MM_ALIGN_SHIFT 4
34 #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
35
36 int via_agp_init(DRM_IOCTL_ARGS)
37 {
38         DRM_DEVICE;
39         drm_via_agp_t agp;
40         drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
41         int ret;
42
43         DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
44                                  sizeof(agp));
45         mutex_lock(&dev->struct_mutex);
46         ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
47                                  agp.size >> VIA_MM_ALIGN_SHIFT);
48
49         if (ret) {
50                 DRM_ERROR("AGP memory manager initialisation error\n");
51                 mutex_unlock(&dev->struct_mutex);
52                 return ret;
53         }
54
55         dev_priv->agp_initialized = 1;
56         dev_priv->agp_offset = agp.offset;
57         mutex_unlock(&dev->struct_mutex);
58
59         DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
60         return 0;
61 }
62
63 int via_fb_init(DRM_IOCTL_ARGS)
64 {
65         DRM_DEVICE;
66         drm_via_fb_t fb;
67         drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
68         int ret;
69
70         DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
71
72         mutex_lock(&dev->struct_mutex);
73         ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
74                                  fb.size >> VIA_MM_ALIGN_SHIFT);
75
76         if (ret) {
77                 DRM_ERROR("VRAM memory manager initialisation error\n");
78                 mutex_unlock(&dev->struct_mutex);
79                 return ret;
80         }
81
82         dev_priv->vram_initialized = 1;
83         dev_priv->vram_offset = fb.offset;
84
85         mutex_unlock(&dev->struct_mutex);
86         DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
87
88         return 0;
89
90 }
91
92 int via_final_context(struct drm_device *dev, int context)
93 {
94         drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
95
96         via_release_futex(dev_priv, context);
97
98 #if defined(__linux__)
99         /* Linux specific until context tracking code gets ported to BSD */
100         /* Last context, perform cleanup */
101         if (dev->ctx_count == 1 && dev->dev_private) {
102                 DRM_DEBUG("Last Context\n");
103                 if (dev->irq)
104                         drm_irq_uninstall(dev);
105                 via_cleanup_futex(dev_priv);
106                 via_do_cleanup_map(dev);
107         }
108 #endif
109         return 1;
110 }
111
112 void via_lastclose(struct drm_device *dev)
113 {
114         drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
115
116         if (!dev_priv)
117                 return;
118
119         mutex_lock(&dev->struct_mutex);
120         drm_sman_cleanup(&dev_priv->sman);
121         dev_priv->vram_initialized = 0;
122         dev_priv->agp_initialized = 0;
123         mutex_unlock(&dev->struct_mutex);
124 }       
125
126 int via_mem_alloc(DRM_IOCTL_ARGS)
127 {
128         DRM_DEVICE;
129
130         drm_via_mem_t mem;
131         int retval = 0;
132         drm_memblock_item_t *item;
133         drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
134         unsigned long tmpSize;
135
136         DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
137                                  sizeof(mem));
138
139         if (mem.type > VIA_MEM_AGP) {
140                 DRM_ERROR("Unknown memory type allocation\n");
141                 return DRM_ERR(EINVAL);
142         }
143         mutex_lock(&dev->struct_mutex);
144         if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
145                       dev_priv->agp_initialized)) {
146                 DRM_ERROR
147                     ("Attempt to allocate from uninitialized memory manager.\n");
148                 mutex_unlock(&dev->struct_mutex);
149                 return DRM_ERR(EINVAL);
150         }
151
152         tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
153         item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
154                               (unsigned long)priv);
155         mutex_unlock(&dev->struct_mutex);
156         if (item) {
157                 mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
158                               dev_priv->vram_offset : dev_priv->agp_offset) +
159                     (item->mm->
160                      offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
161                 mem.index = item->user_hash.key;
162         } else {
163                 mem.offset = 0;
164                 mem.size = 0;
165                 mem.index = 0;
166                 DRM_DEBUG("Video memory allocation failed\n");
167                 retval = DRM_ERR(ENOMEM);
168         }
169         DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
170
171         return retval;
172 }
173
174 int via_mem_free(DRM_IOCTL_ARGS)
175 {
176         DRM_DEVICE;
177         drm_via_private_t *dev_priv = dev->dev_private;
178         drm_via_mem_t mem;
179         int ret;
180
181         DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
182                                  sizeof(mem));
183
184         mutex_lock(&dev->struct_mutex);
185         ret = drm_sman_free_key(&dev_priv->sman, mem.index);
186         mutex_unlock(&dev->struct_mutex);
187         DRM_DEBUG("free = 0x%lx\n", mem.index);
188
189         return ret;
190 }
191
192
193 void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
194 {
195         drm_via_private_t *dev_priv = dev->dev_private;
196         drm_file_t *priv = filp->private_data;
197
198         mutex_lock(&dev->struct_mutex);
199         if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
200                 mutex_unlock(&dev->struct_mutex);
201                 return;
202         }
203
204         if (dev->driver->dma_quiescent) {
205                 dev->driver->dma_quiescent(dev);
206         }
207
208         drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
209         mutex_unlock(&dev->struct_mutex);
210         return;
211 }