1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
27 **************************************************************************/
31 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
38 #include <video/sisfb.h>
44 #if defined(CONFIG_FB_SIS)
45 /* fb management via fb device */
47 #define SIS_MM_ALIGN_SHIFT 0
48 #define SIS_MM_ALIGN_MASK 0
50 static void *sis_sman_mm_allocate(void *private, unsigned long size
,
53 struct sis_memreq req
;
60 return (void *)~req
.offset
;
63 static void sis_sman_mm_free(void *private, void *ref
)
65 sis_free(~((unsigned long)ref
));
68 static void sis_sman_mm_destroy(void *private)
73 static unsigned long sis_sman_mm_offset(void *private, void *ref
)
75 return ~((unsigned long)ref
);
78 #else /* CONFIG_FB_SIS */
80 #define SIS_MM_ALIGN_SHIFT 4
81 #define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
83 #endif /* CONFIG_FB_SIS */
85 static int sis_fb_init(DRM_IOCTL_ARGS
)
88 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
92 DRM_COPY_FROM_USER_IOCTL(fb
, (drm_sis_fb_t __user
*) data
, sizeof(fb
));
94 mutex_lock(&dev
->struct_mutex
);
95 #if defined(CONFIG_FB_SIS)
97 drm_sman_mm_t sman_mm
;
98 sman_mm
.private = (void *)0xFFFFFFFF;
99 sman_mm
.allocate
= sis_sman_mm_allocate
;
100 sman_mm
.free
= sis_sman_mm_free
;
101 sman_mm
.destroy
= sis_sman_mm_destroy
;
102 sman_mm
.offset
= sis_sman_mm_offset
;
104 drm_sman_set_manager(&dev_priv
->sman
, VIDEO_TYPE
, &sman_mm
);
107 ret
= drm_sman_set_range(&dev_priv
->sman
, VIDEO_TYPE
, 0,
108 fb
.size
>> SIS_MM_ALIGN_SHIFT
);
112 DRM_ERROR("VRAM memory manager initialisation error\n");
113 mutex_unlock(&dev
->struct_mutex
);
117 dev_priv
->vram_initialized
= 1;
118 dev_priv
->vram_offset
= fb
.offset
;
120 mutex_unlock(&dev
->struct_mutex
);
121 DRM_DEBUG("offset = %u, size = %u", fb
.offset
, fb
.size
);
126 static int sis_drm_alloc(drm_device_t
* dev
, drm_file_t
* priv
,
127 unsigned long data
, int pool
)
129 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
130 drm_sis_mem_t __user
*argp
= (drm_sis_mem_t __user
*) data
;
133 drm_memblock_item_t
*item
;
135 DRM_COPY_FROM_USER_IOCTL(mem
, argp
, sizeof(mem
));
137 mutex_lock(&dev
->struct_mutex
);
139 if (0 == ((pool
== 0) ? dev_priv
->vram_initialized
:
140 dev_priv
->agp_initialized
)) {
142 ("Attempt to allocate from uninitialized memory manager.\n");
143 return DRM_ERR(EINVAL
);
146 mem
.size
= (mem
.size
+ SIS_MM_ALIGN_MASK
) >> SIS_MM_ALIGN_SHIFT
;
147 item
= drm_sman_alloc(&dev_priv
->sman
, pool
, mem
.size
, 0,
148 (unsigned long)priv
);
150 mutex_unlock(&dev
->struct_mutex
);
152 mem
.offset
= ((pool
== 0) ?
153 dev_priv
->vram_offset
: dev_priv
->agp_offset
) +
155 offset(item
->mm
, item
->mm_info
) << SIS_MM_ALIGN_SHIFT
);
156 mem
.free
= item
->user_hash
.key
;
157 mem
.size
= mem
.size
<< SIS_MM_ALIGN_SHIFT
;
162 retval
= DRM_ERR(ENOMEM
);
165 DRM_COPY_TO_USER_IOCTL(argp
, mem
, sizeof(mem
));
167 DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool
, mem
.size
,
173 static int sis_drm_free(DRM_IOCTL_ARGS
)
176 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
180 DRM_COPY_FROM_USER_IOCTL(mem
, (drm_sis_mem_t __user
*) data
,
183 mutex_lock(&dev
->struct_mutex
);
184 ret
= drm_sman_free_key(&dev_priv
->sman
, mem
.free
);
185 mutex_unlock(&dev
->struct_mutex
);
186 DRM_DEBUG("free = 0x%lx\n", mem
.free
);
191 static int sis_fb_alloc(DRM_IOCTL_ARGS
)
194 return sis_drm_alloc(dev
, priv
, data
, VIDEO_TYPE
);
197 static int sis_ioctl_agp_init(DRM_IOCTL_ARGS
)
200 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
203 dev_priv
= dev
->dev_private
;
205 DRM_COPY_FROM_USER_IOCTL(agp
, (drm_sis_agp_t __user
*) data
,
207 mutex_lock(&dev
->struct_mutex
);
208 ret
= drm_sman_set_range(&dev_priv
->sman
, AGP_TYPE
, 0,
209 agp
.size
>> SIS_MM_ALIGN_SHIFT
);
212 DRM_ERROR("AGP memory manager initialisation error\n");
213 mutex_unlock(&dev
->struct_mutex
);
217 dev_priv
->agp_initialized
= 1;
218 dev_priv
->agp_offset
= agp
.offset
;
219 mutex_unlock(&dev
->struct_mutex
);
221 DRM_DEBUG("offset = %u, size = %u", agp
.offset
, agp
.size
);
225 static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS
)
229 return sis_drm_alloc(dev
, priv
, data
, AGP_TYPE
);
232 static drm_local_map_t
*sis_reg_init(drm_device_t
*dev
)
234 drm_map_list_t
*entry
;
235 drm_local_map_t
*map
;
237 list_for_each_entry(entry
, &dev
->maplist
->head
, head
) {
241 if (map
->type
== _DRM_REGISTERS
) {
248 int sis_idle(drm_device_t
*dev
)
250 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
255 if (dev_priv
->idle_fault
)
258 if (dev_priv
->mmio
== NULL
) {
259 dev_priv
->mmio
= sis_reg_init(dev
);
260 if (dev_priv
->mmio
== NULL
) {
261 DRM_ERROR("Could not find register map.\n");
267 * Implement a device switch here if needed
270 if (dev_priv
->chipset
!= SIS_CHIP_315
)
274 * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
275 * because its polling frequency is too low.
278 end
= jiffies
+ (DRM_HZ
* 3);
280 for (i
=0; i
<4; ++i
) {
282 idle_reg
= SIS_READ(0x85cc);
283 } while ( !time_after_eq(jiffies
, end
) &&
284 ((idle_reg
& 0x80000000) != 0x80000000));
287 if (time_after_eq(jiffies
, end
)) {
288 DRM_ERROR("Graphics engine idle timeout. "
289 "Disabling idle check\n");
290 dev_priv
->idle_fault
= 1;
294 * The caller never sees an error code. It gets trapped
302 void sis_lastclose(struct drm_device
*dev
)
304 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
309 mutex_lock(&dev
->struct_mutex
);
310 drm_sman_cleanup(&dev_priv
->sman
);
311 dev_priv
->vram_initialized
= 0;
312 dev_priv
->agp_initialized
= 0;
313 dev_priv
->mmio
= NULL
;
314 mutex_unlock(&dev
->struct_mutex
);
317 void sis_reclaim_buffers_locked(drm_device_t
* dev
, struct file
*filp
)
319 drm_sis_private_t
*dev_priv
= dev
->dev_private
;
320 drm_file_t
*priv
= filp
->private_data
;
322 mutex_lock(&dev
->struct_mutex
);
323 if (drm_sman_owner_clean(&dev_priv
->sman
, (unsigned long)priv
)) {
324 mutex_unlock(&dev
->struct_mutex
);
328 if (dev
->driver
->dma_quiescent
) {
329 dev
->driver
->dma_quiescent(dev
);
332 drm_sman_owner_cleanup(&dev_priv
->sman
, (unsigned long)priv
);
333 mutex_unlock(&dev
->struct_mutex
);
337 drm_ioctl_desc_t sis_ioctls
[] = {
338 [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC
)] = {sis_fb_alloc
, DRM_AUTH
},
339 [DRM_IOCTL_NR(DRM_SIS_FB_FREE
)] = {sis_drm_free
, DRM_AUTH
},
340 [DRM_IOCTL_NR(DRM_SIS_AGP_INIT
)] =
341 {sis_ioctl_agp_init
, DRM_AUTH
| DRM_MASTER
| DRM_ROOT_ONLY
},
342 [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC
)] = {sis_ioctl_agp_alloc
, DRM_AUTH
},
343 [DRM_IOCTL_NR(DRM_SIS_AGP_FREE
)] = {sis_drm_free
, DRM_AUTH
},
344 [DRM_IOCTL_NR(DRM_SIS_FB_INIT
)] =
345 {sis_fb_init
, DRM_AUTH
| DRM_MASTER
| DRM_ROOT_ONLY
}
348 int sis_max_ioctl
= DRM_ARRAY_SIZE(sis_ioctls
);