sis_mm.c 8.2 KB
Newer Older
1
/**************************************************************************
L
Linus Torvalds 已提交
2
 *
3 4
 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
 * All Rights Reserved.
L
Linus Torvalds 已提交
5 6
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
7 8 9 10 11 12
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
D
Dave Airlie 已提交
13
 *
14 15 16
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
D
Dave Airlie 已提交
17
 *
L
Linus Torvalds 已提交
18 19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 21 22 23 24
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
D
Dave Airlie 已提交
25 26
 *
 *
27 28 29 30
 **************************************************************************/

/*
 * Authors:
31
 *    Thomas Hellström <thomas-at-tungstengraphics-dot-com>
L
Linus Torvalds 已提交
32 33 34 35 36
 */

#include "drmP.h"
#include "sis_drm.h"
#include "sis_drv.h"
37

L
Linus Torvalds 已提交
38 39
#include <video/sisfb.h>

D
Dave Airlie 已提交
40
#define VIDEO_TYPE 0
L
Linus Torvalds 已提交
41 42 43
#define AGP_TYPE 1


44 45
#if defined(CONFIG_FB_SIS)
/* fb management via fb device */
D
Dave Airlie 已提交
46

47 48
#define SIS_MM_ALIGN_SHIFT 0
#define SIS_MM_ALIGN_MASK 0
L
Linus Torvalds 已提交
49

50 51
static void *sis_sman_mm_allocate(void *private, unsigned long size,
				  unsigned alignment)
D
Dave Airlie 已提交
52
{
53
	struct sis_memreq req;
L
Linus Torvalds 已提交
54

55 56 57 58 59 60
	req.size = size;
	sis_malloc(&req);
	if (req.size == 0)
		return NULL;
	else
		return (void *)~req.offset;
L
Linus Torvalds 已提交
61 62
}

63
static void sis_sman_mm_free(void *private, void *ref)
L
Linus Torvalds 已提交
64
{
65
	sis_free(~((unsigned long)ref));
L
Linus Torvalds 已提交
66 67
}

68
static void sis_sman_mm_destroy(void *private)
L
Linus Torvalds 已提交
69
{
70
	;
L
Linus Torvalds 已提交
71 72
}

A
Adrian Bunk 已提交
73
static unsigned long sis_sman_mm_offset(void *private, void *ref)
L
Linus Torvalds 已提交
74
{
75
	return ~((unsigned long)ref);
L
Linus Torvalds 已提交
76 77
}

A
Adrian Bunk 已提交
78 79 80 81 82 83
#else /* CONFIG_FB_SIS */

#define SIS_MM_ALIGN_SHIFT 4
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)

#endif /* CONFIG_FB_SIS */
L
Linus Torvalds 已提交
84

85
static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
86 87
{
	drm_sis_private_t *dev_priv = dev->dev_private;
88
	drm_sis_fb_t *fb = data;
89
	int ret;
L
Linus Torvalds 已提交
90

91 92 93
	mutex_lock(&dev->struct_mutex);
#if defined(CONFIG_FB_SIS)
	{
94
		struct drm_sman_mm sman_mm;
95 96 97 98 99 100 101
		sman_mm.private = (void *)0xFFFFFFFF;
		sman_mm.allocate = sis_sman_mm_allocate;
		sman_mm.free = sis_sman_mm_free;
		sman_mm.destroy = sis_sman_mm_destroy;
		sman_mm.offset = sis_sman_mm_offset;
		ret =
		    drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
L
Linus Torvalds 已提交
102
	}
103 104
#else
	ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
105
				 fb->size >> SIS_MM_ALIGN_SHIFT);
106
#endif
L
Linus Torvalds 已提交
107

108 109 110 111 112
	if (ret) {
		DRM_ERROR("VRAM memory manager initialisation error\n");
		mutex_unlock(&dev->struct_mutex);
		return ret;
	}
L
Linus Torvalds 已提交
113

114
	dev_priv->vram_initialized = 1;
115
	dev_priv->vram_offset = fb->offset;
L
Linus Torvalds 已提交
116

117
	mutex_unlock(&dev->struct_mutex);
118
	DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
L
Linus Torvalds 已提交
119 120 121 122

	return 0;
}

123
static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv,
124
			 void *data, int pool)
L
Linus Torvalds 已提交
125 126
{
	drm_sis_private_t *dev_priv = dev->dev_private;
127
	drm_sis_mem_t *mem = data;
L
Linus Torvalds 已提交
128
	int retval = 0;
D
Dave Airlie 已提交
129
	struct drm_memblock_item *item;
L
Linus Torvalds 已提交
130

131 132
	mutex_lock(&dev->struct_mutex);

133
	if (0 == ((pool == 0) ? dev_priv->vram_initialized :
134 135 136
		      dev_priv->agp_initialized)) {
		DRM_ERROR
		    ("Attempt to allocate from uninitialized memory manager.\n");
137
		mutex_unlock(&dev->struct_mutex);
E
Eric Anholt 已提交
138
		return -EINVAL;
139
	}
D
Dave Airlie 已提交
140

141 142
	mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
	item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0,
143
			      (unsigned long)file_priv);
144 145 146

	mutex_unlock(&dev->struct_mutex);
	if (item) {
147
		mem->offset = ((pool == 0) ?
148 149 150
			      dev_priv->vram_offset : dev_priv->agp_offset) +
		    (item->mm->
		     offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
151 152
		mem->free = item->user_hash.key;
		mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
L
Linus Torvalds 已提交
153
	} else {
154 155 156
		mem->offset = 0;
		mem->size = 0;
		mem->free = 0;
E
Eric Anholt 已提交
157
		retval = -ENOMEM;
L
Linus Torvalds 已提交
158 159
	}

160 161
	DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size,
		  mem->offset);
L
Linus Torvalds 已提交
162 163 164 165

	return retval;
}

166
static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
167 168
{
	drm_sis_private_t *dev_priv = dev->dev_private;
169
	drm_sis_mem_t *mem = data;
170
	int ret;
L
Linus Torvalds 已提交
171

172
	mutex_lock(&dev->struct_mutex);
173
	ret = drm_sman_free_key(&dev_priv->sman, mem->free);
174
	mutex_unlock(&dev->struct_mutex);
175
	DRM_DEBUG("free = 0x%lx\n", mem->free);
L
Linus Torvalds 已提交
176

177
	return ret;
L
Linus Torvalds 已提交
178 179
}

180 181
static int sis_fb_alloc(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
182
{
183
	return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
184
}
L
Linus Torvalds 已提交
185

186 187
static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
			      struct drm_file *file_priv)
L
Linus Torvalds 已提交
188 189
{
	drm_sis_private_t *dev_priv = dev->dev_private;
190
	drm_sis_agp_t *agp = data;
191 192
	int ret;
	dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
193

194 195
	mutex_lock(&dev->struct_mutex);
	ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
196
				 agp->size >> SIS_MM_ALIGN_SHIFT);
197 198 199 200 201 202

	if (ret) {
		DRM_ERROR("AGP memory manager initialisation error\n");
		mutex_unlock(&dev->struct_mutex);
		return ret;
	}
L
Linus Torvalds 已提交
203

204
	dev_priv->agp_initialized = 1;
205
	dev_priv->agp_offset = agp->offset;
206
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
207

208
	DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
L
Linus Torvalds 已提交
209 210 211
	return 0;
}

212 213
static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
			       struct drm_file *file_priv)
L
Linus Torvalds 已提交
214 215
{

216
	return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
L
Linus Torvalds 已提交
217 218
}

219
static drm_local_map_t *sis_reg_init(struct drm_device *dev)
T
Thomas Hellstrom 已提交
220
{
D
Dave Airlie 已提交
221
	struct drm_map_list *entry;
T
Thomas Hellstrom 已提交
222 223
	drm_local_map_t *map;

224
	list_for_each_entry(entry, &dev->maplist, head) {
T
Thomas Hellstrom 已提交
225 226 227 228 229 230 231 232 233 234
		map = entry->map;
		if (!map)
			continue;
		if (map->type == _DRM_REGISTERS) {
			return map;
		}
	}
	return NULL;
}

235
int sis_idle(struct drm_device *dev)
T
Thomas Hellstrom 已提交
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
{
	drm_sis_private_t *dev_priv = dev->dev_private;
	uint32_t idle_reg;
	unsigned long end;
	int i;

	if (dev_priv->idle_fault)
		return 0;

	if (dev_priv->mmio == NULL) {
		dev_priv->mmio = sis_reg_init(dev);
		if (dev_priv->mmio == NULL) {
			DRM_ERROR("Could not find register map.\n");
			return 0;
		}
	}
	
	/*
	 * Implement a device switch here if needed
	 */

	if (dev_priv->chipset != SIS_CHIP_315)
		return 0;

	/*
	 * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
	 * because its polling frequency is too low.
	 */

	end = jiffies + (DRM_HZ * 3);

	for (i=0; i<4; ++i) {
		do {
			idle_reg = SIS_READ(0x85cc);
		} while ( !time_after_eq(jiffies, end) &&
			  ((idle_reg & 0x80000000) != 0x80000000));
	}

	if (time_after_eq(jiffies, end)) {
		DRM_ERROR("Graphics engine idle timeout. "
			  "Disabling idle check\n");
277
		dev_priv->idle_fault = 1;
T
Thomas Hellstrom 已提交
278 279 280 281 282 283 284 285 286 287 288
	}

	/*
	 * The caller never sees an error code. It gets trapped
	 * in libdrm.
	 */

	return 0;
}


289
void sis_lastclose(struct drm_device *dev)
L
Linus Torvalds 已提交
290 291 292
{
	drm_sis_private_t *dev_priv = dev->dev_private;

293 294
	if (!dev_priv)
		return;
L
Linus Torvalds 已提交
295

296 297
	mutex_lock(&dev->struct_mutex);
	drm_sman_cleanup(&dev_priv->sman);
298 299
	dev_priv->vram_initialized = 0;
	dev_priv->agp_initialized = 0;
T
Thomas Hellstrom 已提交
300
	dev_priv->mmio = NULL;
301
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
302 303
}

304 305
void sis_reclaim_buffers_locked(struct drm_device * dev,
				struct drm_file *file_priv)
L
Linus Torvalds 已提交
306
{
307
	drm_sis_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
308

309
	mutex_lock(&dev->struct_mutex);
310
	if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
311 312
		mutex_unlock(&dev->struct_mutex);
		return;
L
Linus Torvalds 已提交
313 314
	}

315 316
	if (dev->driver->dma_quiescent) {
		dev->driver->dma_quiescent(dev);
D
Dave Airlie 已提交
317 318
	}

319
	drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
320 321
	mutex_unlock(&dev->struct_mutex);
	return;
L
Linus Torvalds 已提交
322 323
}

324 325 326 327 328 329 330
struct drm_ioctl_desc sis_ioctls[] = {
	DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
L
Linus Torvalds 已提交
331 332 333
};

int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);