2 * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
25 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
29 #include <drm/via_drm.h>
32 #define VIA_MM_ALIGN_SHIFT 4
33 #define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1)
36 struct drm_mm_node mm_node
;
37 struct list_head owner_list
;
40 int via_agp_init(struct drm_device
*dev
, void *data
, struct drm_file
*file_priv
)
42 drm_via_agp_t
*agp
= data
;
43 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
45 mutex_lock(&dev
->struct_mutex
);
46 drm_mm_init(&dev_priv
->agp_mm
, 0, agp
->size
>> VIA_MM_ALIGN_SHIFT
);
48 dev_priv
->agp_initialized
= 1;
49 dev_priv
->agp_offset
= agp
->offset
;
50 mutex_unlock(&dev
->struct_mutex
);
52 DRM_DEBUG("offset = %u, size = %u\n", agp
->offset
, agp
->size
);
56 int via_fb_init(struct drm_device
*dev
, void *data
, struct drm_file
*file_priv
)
58 drm_via_fb_t
*fb
= data
;
59 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
61 mutex_lock(&dev
->struct_mutex
);
62 drm_mm_init(&dev_priv
->vram_mm
, 0, fb
->size
>> VIA_MM_ALIGN_SHIFT
);
64 dev_priv
->vram_initialized
= 1;
65 dev_priv
->vram_offset
= fb
->offset
;
67 mutex_unlock(&dev
->struct_mutex
);
68 DRM_DEBUG("offset = %u, size = %u\n", fb
->offset
, fb
->size
);
74 int via_final_context(struct drm_device
*dev
, int context
)
76 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
78 via_release_futex(dev_priv
, context
);
80 /* Linux specific until context tracking code gets ported to BSD */
81 /* Last context, perform cleanup */
82 if (list_is_singular(&dev
->ctxlist
)) {
83 DRM_DEBUG("Last Context\n");
84 drm_irq_uninstall(dev
);
85 via_cleanup_futex(dev_priv
);
86 via_do_cleanup_map(dev
);
91 void via_lastclose(struct drm_device
*dev
)
93 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
98 mutex_lock(&dev
->struct_mutex
);
99 if (dev_priv
->vram_initialized
) {
100 drm_mm_takedown(&dev_priv
->vram_mm
);
101 dev_priv
->vram_initialized
= 0;
103 if (dev_priv
->agp_initialized
) {
104 drm_mm_takedown(&dev_priv
->agp_mm
);
105 dev_priv
->agp_initialized
= 0;
107 mutex_unlock(&dev
->struct_mutex
);
110 int via_mem_alloc(struct drm_device
*dev
, void *data
,
111 struct drm_file
*file
)
113 drm_via_mem_t
*mem
= data
;
114 int retval
= 0, user_key
;
115 struct via_memblock
*item
;
116 drm_via_private_t
*dev_priv
= (drm_via_private_t
*) dev
->dev_private
;
117 struct via_file_private
*file_priv
= file
->driver_priv
;
118 unsigned long tmpSize
;
120 if (mem
->type
> VIA_MEM_AGP
) {
121 DRM_ERROR("Unknown memory type allocation\n");
124 mutex_lock(&dev
->struct_mutex
);
125 if (0 == ((mem
->type
== VIA_MEM_VIDEO
) ? dev_priv
->vram_initialized
:
126 dev_priv
->agp_initialized
)) {
128 ("Attempt to allocate from uninitialized memory manager.\n");
129 mutex_unlock(&dev
->struct_mutex
);
133 item
= kzalloc(sizeof(*item
), GFP_KERNEL
);
139 tmpSize
= (mem
->size
+ VIA_MM_ALIGN_MASK
) >> VIA_MM_ALIGN_SHIFT
;
140 if (mem
->type
== VIA_MEM_AGP
)
141 retval
= drm_mm_insert_node(&dev_priv
->agp_mm
,
143 tmpSize
, 0, DRM_MM_SEARCH_DEFAULT
);
145 retval
= drm_mm_insert_node(&dev_priv
->vram_mm
,
147 tmpSize
, 0, DRM_MM_SEARCH_DEFAULT
);
151 retval
= idr_alloc(&dev_priv
->object_idr
, item
, 1, 0, GFP_KERNEL
);
156 list_add(&item
->owner_list
, &file_priv
->obj_list
);
157 mutex_unlock(&dev
->struct_mutex
);
159 mem
->offset
= ((mem
->type
== VIA_MEM_VIDEO
) ?
160 dev_priv
->vram_offset
: dev_priv
->agp_offset
) +
161 ((item
->mm_node
.start
) << VIA_MM_ALIGN_SHIFT
);
162 mem
->index
= user_key
;
167 drm_mm_remove_node(&item
->mm_node
);
170 mutex_unlock(&dev
->struct_mutex
);
175 DRM_DEBUG("Video memory allocation failed\n");
180 int via_mem_free(struct drm_device
*dev
, void *data
, struct drm_file
*file_priv
)
182 drm_via_private_t
*dev_priv
= dev
->dev_private
;
183 drm_via_mem_t
*mem
= data
;
184 struct via_memblock
*obj
;
186 mutex_lock(&dev
->struct_mutex
);
187 obj
= idr_find(&dev_priv
->object_idr
, mem
->index
);
189 mutex_unlock(&dev
->struct_mutex
);
193 idr_remove(&dev_priv
->object_idr
, mem
->index
);
194 list_del(&obj
->owner_list
);
195 drm_mm_remove_node(&obj
->mm_node
);
197 mutex_unlock(&dev
->struct_mutex
);
199 DRM_DEBUG("free = 0x%lx\n", mem
->index
);
205 void via_reclaim_buffers_locked(struct drm_device
*dev
,
206 struct drm_file
*file
)
208 struct via_file_private
*file_priv
= file
->driver_priv
;
209 struct via_memblock
*entry
, *next
;
211 if (!(dev
->master
&& file
->master
->lock
.hw_lock
))
214 drm_legacy_idlelock_take(&file
->master
->lock
);
216 mutex_lock(&dev
->struct_mutex
);
217 if (list_empty(&file_priv
->obj_list
)) {
218 mutex_unlock(&dev
->struct_mutex
);
219 drm_legacy_idlelock_release(&file
->master
->lock
);
224 via_driver_dma_quiescent(dev
);
226 list_for_each_entry_safe(entry
, next
, &file_priv
->obj_list
,
228 list_del(&entry
->owner_list
);
229 drm_mm_remove_node(&entry
->mm_node
);
232 mutex_unlock(&dev
->struct_mutex
);
234 drm_legacy_idlelock_release(&file
->master
->lock
);