mga_state.c 28.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*-
 * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
 *
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * 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, sublicense,
 * 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:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * VA LINUX SYSTEMS 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.
 *
 * Authors:
 *    Jeff Hartmann <jhartmann@valinux.com>
 *    Keith Whitwell <keith@tungstengraphics.com>
 *
 * Rewritten by:
 *    Gareth Hughes <gareth@valinux.com>
 */

35 36
#include <drm/drmP.h>
#include <drm/mga_drm.h>
L
Linus Torvalds 已提交
37 38 39 40 41 42
#include "mga_drv.h"

/* ================================================================
 * DMA hardware state programming functions
 */

43 44
static void mga_emit_clip_rect(drm_mga_private_t *dev_priv,
			       struct drm_clip_rect *box)
L
Linus Torvalds 已提交
45 46 47 48 49 50
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
	unsigned int pitch = dev_priv->front_pitch;
	DMA_LOCALS;

D
Dave Airlie 已提交
51
	BEGIN_DMA(2);
L
Linus Torvalds 已提交
52 53 54

	/* Force reset of DWGCTL on G400 (eliminates clip disable bit).
	 */
D
Dave Airlie 已提交
55
	if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
56 57 58 59
		DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
			  MGA_LEN + MGA_EXEC, 0x80000000,
			  MGA_DWGCTL, ctx->dwgctl,
			  MGA_LEN + MGA_EXEC, 0x80000000);
L
Linus Torvalds 已提交
60
	}
61 62
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
D
Dave Airlie 已提交
63
		  MGA_YTOP, box->y1 * pitch, MGA_YBOT, (box->y2 - 1) * pitch);
L
Linus Torvalds 已提交
64 65 66 67

	ADVANCE_DMA();
}

68
static __inline__ void mga_g200_emit_context(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
69 70 71 72 73
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
	DMA_LOCALS;

D
Dave Airlie 已提交
74
	BEGIN_DMA(3);
L
Linus Torvalds 已提交
75

D
Dave Airlie 已提交
76 77 78
	DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
		  MGA_MACCESS, ctx->maccess,
		  MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
L
Linus Torvalds 已提交
79

D
Dave Airlie 已提交
80 81 82
	DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
		  MGA_FOGCOL, ctx->fogcolor,
		  MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset);
L
Linus Torvalds 已提交
83

D
Dave Airlie 已提交
84 85 86
	DMA_BLOCK(MGA_FCOL, ctx->fcol,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
87 88 89 90

	ADVANCE_DMA();
}

91
static __inline__ void mga_g400_emit_context(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
92 93 94 95 96
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
	DMA_LOCALS;

D
Dave Airlie 已提交
97
	BEGIN_DMA(4);
L
Linus Torvalds 已提交
98

D
Dave Airlie 已提交
99 100 101
	DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
		  MGA_MACCESS, ctx->maccess,
		  MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
L
Linus Torvalds 已提交
102

D
Dave Airlie 已提交
103 104 105
	DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
		  MGA_FOGCOL, ctx->fogcolor,
		  MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset);
L
Linus Torvalds 已提交
106

D
Dave Airlie 已提交
107 108 109
	DMA_BLOCK(MGA_WFLAG1, ctx->wflag,
		  MGA_TDUALSTAGE0, ctx->tdualstage0,
		  MGA_TDUALSTAGE1, ctx->tdualstage1, MGA_FCOL, ctx->fcol);
L
Linus Torvalds 已提交
110

D
Dave Airlie 已提交
111 112 113
	DMA_BLOCK(MGA_STENCIL, ctx->stencil,
		  MGA_STENCILCTL, ctx->stencilctl,
		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
114 115 116 117

	ADVANCE_DMA();
}

118
static __inline__ void mga_g200_emit_tex0(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
119 120 121 122 123
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
	DMA_LOCALS;

D
Dave Airlie 已提交
124
	BEGIN_DMA(4);
L
Linus Torvalds 已提交
125

D
Dave Airlie 已提交
126 127 128 129
	DMA_BLOCK(MGA_TEXCTL2, tex->texctl2,
		  MGA_TEXCTL, tex->texctl,
		  MGA_TEXFILTER, tex->texfilter,
		  MGA_TEXBORDERCOL, tex->texbordercol);
L
Linus Torvalds 已提交
130

D
Dave Airlie 已提交
131 132 133
	DMA_BLOCK(MGA_TEXORG, tex->texorg,
		  MGA_TEXORG1, tex->texorg1,
		  MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
L
Linus Torvalds 已提交
134

D
Dave Airlie 已提交
135 136 137
	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
		  MGA_TEXWIDTH, tex->texwidth,
		  MGA_TEXHEIGHT, tex->texheight, MGA_WR24, tex->texwidth);
L
Linus Torvalds 已提交
138

D
Dave Airlie 已提交
139 140 141
	DMA_BLOCK(MGA_WR34, tex->texheight,
		  MGA_TEXTRANS, 0x0000ffff,
		  MGA_TEXTRANSHIGH, 0x0000ffff, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
142 143 144 145

	ADVANCE_DMA();
}

146
static __inline__ void mga_g400_emit_tex0(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
147 148 149 150 151
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
	DMA_LOCALS;

D
Dave Airlie 已提交
152 153
/*	printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
/*	       tex->texctl, tex->texctl2); */
L
Linus Torvalds 已提交
154

D
Dave Airlie 已提交
155
	BEGIN_DMA(6);
L
Linus Torvalds 已提交
156

D
Dave Airlie 已提交
157 158 159 160
	DMA_BLOCK(MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC,
		  MGA_TEXCTL, tex->texctl,
		  MGA_TEXFILTER, tex->texfilter,
		  MGA_TEXBORDERCOL, tex->texbordercol);
L
Linus Torvalds 已提交
161

D
Dave Airlie 已提交
162 163 164
	DMA_BLOCK(MGA_TEXORG, tex->texorg,
		  MGA_TEXORG1, tex->texorg1,
		  MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
L
Linus Torvalds 已提交
165

D
Dave Airlie 已提交
166 167 168
	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
		  MGA_TEXWIDTH, tex->texwidth,
		  MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000);
L
Linus Torvalds 已提交
169

D
Dave Airlie 已提交
170 171 172
	DMA_BLOCK(MGA_WR57, 0x00000000,
		  MGA_WR53, 0x00000000,
		  MGA_WR61, 0x00000000, MGA_WR52, MGA_G400_WR_MAGIC);
L
Linus Torvalds 已提交
173

D
Dave Airlie 已提交
174 175 176 177
	DMA_BLOCK(MGA_WR60, MGA_G400_WR_MAGIC,
		  MGA_WR54, tex->texwidth | MGA_G400_WR_MAGIC,
		  MGA_WR62, tex->texheight | MGA_G400_WR_MAGIC,
		  MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
178

D
Dave Airlie 已提交
179 180 181
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_TEXTRANS, 0x0000ffff, MGA_TEXTRANSHIGH, 0x0000ffff);
L
Linus Torvalds 已提交
182 183 184 185

	ADVANCE_DMA();
}

186
static __inline__ void mga_g400_emit_tex1(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
187 188 189 190 191
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
	DMA_LOCALS;

D
Dave Airlie 已提交
192 193
/*	printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg,  */
/*	       tex->texctl, tex->texctl2); */
L
Linus Torvalds 已提交
194

D
Dave Airlie 已提交
195
	BEGIN_DMA(5);
L
Linus Torvalds 已提交
196

D
Dave Airlie 已提交
197 198 199 200 201 202
	DMA_BLOCK(MGA_TEXCTL2, (tex->texctl2 |
				MGA_MAP1_ENABLE |
				MGA_G400_TC2_MAGIC),
		  MGA_TEXCTL, tex->texctl,
		  MGA_TEXFILTER, tex->texfilter,
		  MGA_TEXBORDERCOL, tex->texbordercol);
L
Linus Torvalds 已提交
203

D
Dave Airlie 已提交
204 205 206
	DMA_BLOCK(MGA_TEXORG, tex->texorg,
		  MGA_TEXORG1, tex->texorg1,
		  MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
L
Linus Torvalds 已提交
207

D
Dave Airlie 已提交
208 209 210
	DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
		  MGA_TEXWIDTH, tex->texwidth,
		  MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000);
L
Linus Torvalds 已提交
211

D
Dave Airlie 已提交
212 213 214 215
	DMA_BLOCK(MGA_WR57, 0x00000000,
		  MGA_WR53, 0x00000000,
		  MGA_WR61, 0x00000000,
		  MGA_WR52, tex->texwidth | MGA_G400_WR_MAGIC);
L
Linus Torvalds 已提交
216

D
Dave Airlie 已提交
217 218 219 220
	DMA_BLOCK(MGA_WR60, tex->texheight | MGA_G400_WR_MAGIC,
		  MGA_TEXTRANS, 0x0000ffff,
		  MGA_TEXTRANSHIGH, 0x0000ffff,
		  MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC);
L
Linus Torvalds 已提交
221 222 223 224

	ADVANCE_DMA();
}

225
static __inline__ void mga_g200_emit_pipe(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
226 227 228 229 230
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	unsigned int pipe = sarea_priv->warp_pipe;
	DMA_LOCALS;

D
Dave Airlie 已提交
231
	BEGIN_DMA(3);
L
Linus Torvalds 已提交
232

D
Dave Airlie 已提交
233 234 235
	DMA_BLOCK(MGA_WIADDR, MGA_WMODE_SUSPEND,
		  MGA_WVRTXSZ, 0x00000007,
		  MGA_WFLAG, 0x00000000, MGA_WR24, 0x00000000);
L
Linus Torvalds 已提交
236

D
Dave Airlie 已提交
237 238 239
	DMA_BLOCK(MGA_WR25, 0x00000100,
		  MGA_WR34, 0x00000000,
		  MGA_WR42, 0x0000ffff, MGA_WR60, 0x0000ffff);
L
Linus Torvalds 已提交
240

241
	/* Padding required due to hardware bug.
L
Linus Torvalds 已提交
242
	 */
243 244 245 246 247
	DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
		  MGA_DMAPAD, 0xffffffff,
		  MGA_DMAPAD, 0xffffffff,
		  MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
			       MGA_WMODE_START | dev_priv->wagp_enable));
L
Linus Torvalds 已提交
248 249 250 251

	ADVANCE_DMA();
}

252
static __inline__ void mga_g400_emit_pipe(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
253 254 255 256 257
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	unsigned int pipe = sarea_priv->warp_pipe;
	DMA_LOCALS;

D
Dave Airlie 已提交
258
/*	printk("mga_g400_emit_pipe %x\n", pipe); */
L
Linus Torvalds 已提交
259

D
Dave Airlie 已提交
260
	BEGIN_DMA(10);
L
Linus Torvalds 已提交
261

D
Dave Airlie 已提交
262 263 264
	DMA_BLOCK(MGA_WIADDR2, MGA_WMODE_SUSPEND,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
265

D
Dave Airlie 已提交
266 267 268 269
	if (pipe & MGA_T2) {
		DMA_BLOCK(MGA_WVRTXSZ, 0x00001e09,
			  MGA_DMAPAD, 0x00000000,
			  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
270

D
Dave Airlie 已提交
271 272 273 274
		DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x1e000000);
L
Linus Torvalds 已提交
275
	} else {
D
Dave Airlie 已提交
276
		if (dev_priv->warp_pipe & MGA_T2) {
L
Linus Torvalds 已提交
277
			/* Flush the WARP pipe */
D
Dave Airlie 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
			DMA_BLOCK(MGA_YDST, 0x00000000,
				  MGA_FXLEFT, 0x00000000,
				  MGA_FXRIGHT, 0x00000001,
				  MGA_DWGCTL, MGA_DWGCTL_FLUSH);

			DMA_BLOCK(MGA_LEN + MGA_EXEC, 0x00000001,
				  MGA_DWGSYNC, 0x00007000,
				  MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
				  MGA_LEN + MGA_EXEC, 0x00000000);

			DMA_BLOCK(MGA_TEXCTL2, (MGA_DUALTEX |
						MGA_G400_TC2_MAGIC),
				  MGA_LEN + MGA_EXEC, 0x00000000,
				  MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
				  MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
293 294
		}

D
Dave Airlie 已提交
295 296 297
		DMA_BLOCK(MGA_WVRTXSZ, 0x00001807,
			  MGA_DMAPAD, 0x00000000,
			  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
298

D
Dave Airlie 已提交
299 300 301 302
		DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x00000000,
			  MGA_WACCEPTSEQ, 0x18000000);
L
Linus Torvalds 已提交
303 304
	}

D
Dave Airlie 已提交
305 306 307
	DMA_BLOCK(MGA_WFLAG, 0x00000000,
		  MGA_WFLAG1, 0x00000000,
		  MGA_WR56, MGA_G400_WR56_MAGIC, MGA_DMAPAD, 0x00000000);
L
Linus Torvalds 已提交
308

D
Dave Airlie 已提交
309 310 311 312
	DMA_BLOCK(MGA_WR49, 0x00000000,	/* tex0              */
		  MGA_WR57, 0x00000000,	/* tex0              */
		  MGA_WR53, 0x00000000,	/* tex1              */
		  MGA_WR61, 0x00000000);	/* tex1              */
L
Linus Torvalds 已提交
313

D
Dave Airlie 已提交
314 315 316 317
	DMA_BLOCK(MGA_WR54, MGA_G400_WR_MAGIC,	/* tex0 width        */
		  MGA_WR62, MGA_G400_WR_MAGIC,	/* tex0 height       */
		  MGA_WR52, MGA_G400_WR_MAGIC,	/* tex1 width        */
		  MGA_WR60, MGA_G400_WR_MAGIC);	/* tex1 height       */
L
Linus Torvalds 已提交
318

319
	/* Padding required due to hardware bug */
320 321 322 323 324
	DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
		  MGA_DMAPAD, 0xffffffff,
		  MGA_DMAPAD, 0xffffffff,
		  MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
				MGA_WMODE_START | dev_priv->wagp_enable));
L
Linus Torvalds 已提交
325 326 327 328

	ADVANCE_DMA();
}

329
static void mga_g200_emit_state(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
330 331 332 333
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	unsigned int dirty = sarea_priv->dirty;

D
Dave Airlie 已提交
334 335
	if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
		mga_g200_emit_pipe(dev_priv);
L
Linus Torvalds 已提交
336 337 338
		dev_priv->warp_pipe = sarea_priv->warp_pipe;
	}

D
Dave Airlie 已提交
339 340
	if (dirty & MGA_UPLOAD_CONTEXT) {
		mga_g200_emit_context(dev_priv);
L
Linus Torvalds 已提交
341 342 343
		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
	}

D
Dave Airlie 已提交
344 345
	if (dirty & MGA_UPLOAD_TEX0) {
		mga_g200_emit_tex0(dev_priv);
L
Linus Torvalds 已提交
346 347 348 349
		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
	}
}

350
static void mga_g400_emit_state(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
351 352 353 354 355
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	unsigned int dirty = sarea_priv->dirty;
	int multitex = sarea_priv->warp_pipe & MGA_T2;

D
Dave Airlie 已提交
356 357
	if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
		mga_g400_emit_pipe(dev_priv);
L
Linus Torvalds 已提交
358 359 360
		dev_priv->warp_pipe = sarea_priv->warp_pipe;
	}

D
Dave Airlie 已提交
361 362
	if (dirty & MGA_UPLOAD_CONTEXT) {
		mga_g400_emit_context(dev_priv);
L
Linus Torvalds 已提交
363 364 365
		sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
	}

D
Dave Airlie 已提交
366 367
	if (dirty & MGA_UPLOAD_TEX0) {
		mga_g400_emit_tex0(dev_priv);
L
Linus Torvalds 已提交
368 369 370
		sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
	}

D
Dave Airlie 已提交
371 372
	if ((dirty & MGA_UPLOAD_TEX1) && multitex) {
		mga_g400_emit_tex1(dev_priv);
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380 381 382
		sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
	}
}

/* ================================================================
 * SAREA state verification
 */

/* Disallow all write destinations except the front and backbuffer.
 */
383
static int mga_verify_context(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
384 385 386 387
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;

D
Dave Airlie 已提交
388 389 390 391 392
	if (ctx->dstorg != dev_priv->front_offset &&
	    ctx->dstorg != dev_priv->back_offset) {
		DRM_ERROR("*** bad DSTORG: %x (front %x, back %x)\n\n",
			  ctx->dstorg, dev_priv->front_offset,
			  dev_priv->back_offset);
L
Linus Torvalds 已提交
393
		ctx->dstorg = 0;
E
Eric Anholt 已提交
394
		return -EINVAL;
L
Linus Torvalds 已提交
395 396 397 398 399 400 401
	}

	return 0;
}

/* Disallow texture reads from PCI space.
 */
402
static int mga_verify_tex(drm_mga_private_t *dev_priv, int unit)
L
Linus Torvalds 已提交
403 404 405 406 407 408 409
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
	unsigned int org;

	org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK);

D
Dave Airlie 已提交
410 411
	if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
		DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
L
Linus Torvalds 已提交
412
		tex->texorg = 0;
E
Eric Anholt 已提交
413
		return -EINVAL;
L
Linus Torvalds 已提交
414 415 416 417 418
	}

	return 0;
}

419
static int mga_verify_state(drm_mga_private_t *dev_priv)
L
Linus Torvalds 已提交
420 421 422 423 424
{
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	unsigned int dirty = sarea_priv->dirty;
	int ret = 0;

D
Dave Airlie 已提交
425
	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
426 427
		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;

D
Dave Airlie 已提交
428 429
	if (dirty & MGA_UPLOAD_CONTEXT)
		ret |= mga_verify_context(dev_priv);
L
Linus Torvalds 已提交
430

D
Dave Airlie 已提交
431 432
	if (dirty & MGA_UPLOAD_TEX0)
		ret |= mga_verify_tex(dev_priv, 0);
L
Linus Torvalds 已提交
433

434 435 436
	if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
		if (dirty & MGA_UPLOAD_TEX1)
			ret |= mga_verify_tex(dev_priv, 1);
L
Linus Torvalds 已提交
437

D
Dave Airlie 已提交
438 439
		if (dirty & MGA_UPLOAD_PIPE)
			ret |= (sarea_priv->warp_pipe > MGA_MAX_G400_PIPES);
L
Linus Torvalds 已提交
440
	} else {
D
Dave Airlie 已提交
441 442
		if (dirty & MGA_UPLOAD_PIPE)
			ret |= (sarea_priv->warp_pipe > MGA_MAX_G200_PIPES);
L
Linus Torvalds 已提交
443 444
	}

D
Dave Airlie 已提交
445
	return (ret == 0);
L
Linus Torvalds 已提交
446 447
}

448
static int mga_verify_iload(drm_mga_private_t *dev_priv,
D
Dave Airlie 已提交
449
			    unsigned int dstorg, unsigned int length)
L
Linus Torvalds 已提交
450
{
D
Dave Airlie 已提交
451 452 453 454
	if (dstorg < dev_priv->texture_offset ||
	    dstorg + length > (dev_priv->texture_offset +
			       dev_priv->texture_size)) {
		DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
E
Eric Anholt 已提交
455
		return -EINVAL;
L
Linus Torvalds 已提交
456 457
	}

D
Dave Airlie 已提交
458 459 460
	if (length & MGA_ILOAD_MASK) {
		DRM_ERROR("*** bad iload length: 0x%x\n",
			  length & MGA_ILOAD_MASK);
E
Eric Anholt 已提交
461
		return -EINVAL;
L
Linus Torvalds 已提交
462 463 464 465 466
	}

	return 0;
}

467
static int mga_verify_blit(drm_mga_private_t *dev_priv,
D
Dave Airlie 已提交
468
			   unsigned int srcorg, unsigned int dstorg)
L
Linus Torvalds 已提交
469
{
D
Dave Airlie 已提交
470 471 472
	if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
	    (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
		DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
E
Eric Anholt 已提交
473
		return -EINVAL;
L
Linus Torvalds 已提交
474 475 476 477 478 479 480 481
	}
	return 0;
}

/* ================================================================
 *
 */

482
static void mga_dma_dispatch_clear(struct drm_device *dev, drm_mga_clear_t *clear)
L
Linus Torvalds 已提交
483 484 485 486
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
487
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
488 489 490
	int nbox = sarea_priv->nbox;
	int i;
	DMA_LOCALS;
D
Dave Airlie 已提交
491
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
492

D
Dave Airlie 已提交
493
	BEGIN_DMA(1);
L
Linus Torvalds 已提交
494

D
Dave Airlie 已提交
495 496 497
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
L
Linus Torvalds 已提交
498 499 500

	ADVANCE_DMA();

D
Dave Airlie 已提交
501
	for (i = 0; i < nbox; i++) {
502
		struct drm_clip_rect *box = &pbox[i];
L
Linus Torvalds 已提交
503 504
		u32 height = box->y2 - box->y1;

D
Dave Airlie 已提交
505 506
		DRM_DEBUG("   from=%d,%d to=%d,%d\n",
			  box->x1, box->y1, box->x2, box->y2);
L
Linus Torvalds 已提交
507

D
Dave Airlie 已提交
508 509
		if (clear->flags & MGA_FRONT) {
			BEGIN_DMA(2);
L
Linus Torvalds 已提交
510

D
Dave Airlie 已提交
511 512 513 514
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_PLNWT, clear->color_mask,
				  MGA_YDSTLEN, (box->y1 << 16) | height,
				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
L
Linus Torvalds 已提交
515

D
Dave Airlie 已提交
516 517 518 519
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_FCOL, clear->clear_color,
				  MGA_DSTORG, dev_priv->front_offset,
				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
L
Linus Torvalds 已提交
520 521 522 523

			ADVANCE_DMA();
		}

D
Dave Airlie 已提交
524 525
		if (clear->flags & MGA_BACK) {
			BEGIN_DMA(2);
L
Linus Torvalds 已提交
526

D
Dave Airlie 已提交
527 528 529 530
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_PLNWT, clear->color_mask,
				  MGA_YDSTLEN, (box->y1 << 16) | height,
				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
L
Linus Torvalds 已提交
531

D
Dave Airlie 已提交
532 533 534 535
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_FCOL, clear->clear_color,
				  MGA_DSTORG, dev_priv->back_offset,
				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
L
Linus Torvalds 已提交
536 537 538 539

			ADVANCE_DMA();
		}

D
Dave Airlie 已提交
540 541
		if (clear->flags & MGA_DEPTH) {
			BEGIN_DMA(2);
L
Linus Torvalds 已提交
542

D
Dave Airlie 已提交
543 544 545 546
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_PLNWT, clear->depth_mask,
				  MGA_YDSTLEN, (box->y1 << 16) | height,
				  MGA_FXBNDRY, (box->x2 << 16) | box->x1);
L
Linus Torvalds 已提交
547

D
Dave Airlie 已提交
548 549 550 551
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_FCOL, clear->clear_depth,
				  MGA_DSTORG, dev_priv->depth_offset,
				  MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
L
Linus Torvalds 已提交
552 553 554 555 556 557

			ADVANCE_DMA();
		}

	}

D
Dave Airlie 已提交
558
	BEGIN_DMA(1);
L
Linus Torvalds 已提交
559 560

	/* Force reset of DWGCTL */
D
Dave Airlie 已提交
561 562 563
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
L
Linus Torvalds 已提交
564 565 566 567 568 569

	ADVANCE_DMA();

	FLUSH_DMA();
}

570
static void mga_dma_dispatch_swap(struct drm_device *dev)
L
Linus Torvalds 已提交
571 572 573 574
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
575
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
576 577 578
	int nbox = sarea_priv->nbox;
	int i;
	DMA_LOCALS;
D
Dave Airlie 已提交
579
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
580 581 582 583

	sarea_priv->last_frame.head = dev_priv->prim.tail;
	sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;

D
Dave Airlie 已提交
584
	BEGIN_DMA(4 + nbox);
L
Linus Torvalds 已提交
585

D
Dave Airlie 已提交
586 587 588
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
L
Linus Torvalds 已提交
589

D
Dave Airlie 已提交
590 591 592 593
	DMA_BLOCK(MGA_DSTORG, dev_priv->front_offset,
		  MGA_MACCESS, dev_priv->maccess,
		  MGA_SRCORG, dev_priv->back_offset,
		  MGA_AR5, dev_priv->front_pitch);
L
Linus Torvalds 已提交
594

D
Dave Airlie 已提交
595 596 597
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_PLNWT, 0xffffffff, MGA_DWGCTL, MGA_DWGCTL_COPY);
L
Linus Torvalds 已提交
598

D
Dave Airlie 已提交
599
	for (i = 0; i < nbox; i++) {
600
		struct drm_clip_rect *box = &pbox[i];
L
Linus Torvalds 已提交
601 602 603
		u32 height = box->y2 - box->y1;
		u32 start = box->y1 * dev_priv->front_pitch;

D
Dave Airlie 已提交
604 605
		DRM_DEBUG("   from=%d,%d to=%d,%d\n",
			  box->x1, box->y1, box->x2, box->y2);
L
Linus Torvalds 已提交
606

D
Dave Airlie 已提交
607 608 609 610
		DMA_BLOCK(MGA_AR0, start + box->x2 - 1,
			  MGA_AR3, start + box->x1,
			  MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1,
			  MGA_YDSTLEN + MGA_EXEC, (box->y1 << 16) | height);
L
Linus Torvalds 已提交
611 612
	}

D
Dave Airlie 已提交
613 614 615
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_PLNWT, ctx->plnwt,
		  MGA_SRCORG, dev_priv->front_offset, MGA_DWGCTL, ctx->dwgctl);
L
Linus Torvalds 已提交
616 617 618 619 620

	ADVANCE_DMA();

	FLUSH_DMA();

621
	DRM_DEBUG("... done.\n");
L
Linus Torvalds 已提交
622 623
}

624
static void mga_dma_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf)
L
Linus Torvalds 已提交
625 626 627 628 629 630 631 632
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	u32 address = (u32) buf->bus_address;
	u32 length = (u32) buf->used;
	int i = 0;
	DMA_LOCALS;
633
	DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
L
Linus Torvalds 已提交
634

D
Dave Airlie 已提交
635
	if (buf->used) {
L
Linus Torvalds 已提交
636 637
		buf_priv->dispatched = 1;

D
Dave Airlie 已提交
638
		MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
L
Linus Torvalds 已提交
639 640

		do {
D
Dave Airlie 已提交
641 642 643
			if (i < sarea_priv->nbox) {
				mga_emit_clip_rect(dev_priv,
						   &sarea_priv->boxes[i]);
L
Linus Torvalds 已提交
644 645
			}

D
Dave Airlie 已提交
646
			BEGIN_DMA(1);
L
Linus Torvalds 已提交
647

648 649 650 651 652 653
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_DMAPAD, 0x00000000,
				  MGA_SECADDRESS, (address |
						   MGA_DMA_VERTEX),
				  MGA_SECEND, ((address + length) |
					       dev_priv->dma_access));
L
Linus Torvalds 已提交
654 655

			ADVANCE_DMA();
D
Dave Airlie 已提交
656
		} while (++i < sarea_priv->nbox);
L
Linus Torvalds 已提交
657 658
	}

D
Dave Airlie 已提交
659 660
	if (buf_priv->discard) {
		AGE_BUFFER(buf_priv);
L
Linus Torvalds 已提交
661 662 663 664
		buf->pending = 0;
		buf->used = 0;
		buf_priv->dispatched = 0;

D
Dave Airlie 已提交
665
		mga_freelist_put(dev, buf);
L
Linus Torvalds 已提交
666 667 668 669 670
	}

	FLUSH_DMA();
}

671
static void mga_dma_dispatch_indices(struct drm_device *dev, struct drm_buf *buf,
D
Dave Airlie 已提交
672
				     unsigned int start, unsigned int end)
L
Linus Torvalds 已提交
673 674 675 676 677 678 679
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	u32 address = (u32) buf->bus_address;
	int i = 0;
	DMA_LOCALS;
680
	DRM_DEBUG("buf=%d start=%d end=%d\n", buf->idx, start, end);
L
Linus Torvalds 已提交
681

D
Dave Airlie 已提交
682
	if (start != end) {
L
Linus Torvalds 已提交
683 684
		buf_priv->dispatched = 1;

D
Dave Airlie 已提交
685
		MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
L
Linus Torvalds 已提交
686 687

		do {
D
Dave Airlie 已提交
688 689 690
			if (i < sarea_priv->nbox) {
				mga_emit_clip_rect(dev_priv,
						   &sarea_priv->boxes[i]);
L
Linus Torvalds 已提交
691 692
			}

D
Dave Airlie 已提交
693
			BEGIN_DMA(1);
L
Linus Torvalds 已提交
694

695 696 697 698 699
			DMA_BLOCK(MGA_DMAPAD, 0x00000000,
				  MGA_DMAPAD, 0x00000000,
				  MGA_SETUPADDRESS, address + start,
				  MGA_SETUPEND, ((address + end) |
						 dev_priv->dma_access));
L
Linus Torvalds 已提交
700 701

			ADVANCE_DMA();
D
Dave Airlie 已提交
702
		} while (++i < sarea_priv->nbox);
L
Linus Torvalds 已提交
703 704
	}

D
Dave Airlie 已提交
705 706
	if (buf_priv->discard) {
		AGE_BUFFER(buf_priv);
L
Linus Torvalds 已提交
707 708 709 710
		buf->pending = 0;
		buf->used = 0;
		buf_priv->dispatched = 0;

D
Dave Airlie 已提交
711
		mga_freelist_put(dev, buf);
L
Linus Torvalds 已提交
712 713 714 715 716 717 718 719
	}

	FLUSH_DMA();
}

/* This copies a 64 byte aligned agp region to the frambuffer with a
 * standard blit, the ioctl needs to do checking.
 */
720
static void mga_dma_dispatch_iload(struct drm_device *dev, struct drm_buf *buf,
D
Dave Airlie 已提交
721
				   unsigned int dstorg, unsigned int length)
L
Linus Torvalds 已提交
722 723 724 725
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
	drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
D
Dave Airlie 已提交
726 727
	u32 srcorg =
	    buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
L
Linus Torvalds 已提交
728 729
	u32 y2;
	DMA_LOCALS;
D
Dave Airlie 已提交
730
	DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
L
Linus Torvalds 已提交
731 732 733

	y2 = length / 64;

D
Dave Airlie 已提交
734
	BEGIN_DMA(5);
L
Linus Torvalds 已提交
735

D
Dave Airlie 已提交
736 737 738
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
L
Linus Torvalds 已提交
739

D
Dave Airlie 已提交
740 741
	DMA_BLOCK(MGA_DSTORG, dstorg,
		  MGA_MACCESS, 0x00000000, MGA_SRCORG, srcorg, MGA_AR5, 64);
L
Linus Torvalds 已提交
742

D
Dave Airlie 已提交
743 744 745
	DMA_BLOCK(MGA_PITCH, 64,
		  MGA_PLNWT, 0xffffffff,
		  MGA_DMAPAD, 0x00000000, MGA_DWGCTL, MGA_DWGCTL_COPY);
L
Linus Torvalds 已提交
746

D
Dave Airlie 已提交
747 748 749
	DMA_BLOCK(MGA_AR0, 63,
		  MGA_AR3, 0,
		  MGA_FXBNDRY, (63 << 16) | 0, MGA_YDSTLEN + MGA_EXEC, y2);
L
Linus Torvalds 已提交
750

D
Dave Airlie 已提交
751 752 753
	DMA_BLOCK(MGA_PLNWT, ctx->plnwt,
		  MGA_SRCORG, dev_priv->front_offset,
		  MGA_PITCH, dev_priv->front_pitch, MGA_DWGSYNC, 0x00007000);
L
Linus Torvalds 已提交
754 755 756

	ADVANCE_DMA();

D
Dave Airlie 已提交
757
	AGE_BUFFER(buf_priv);
L
Linus Torvalds 已提交
758 759 760 761 762

	buf->pending = 0;
	buf->used = 0;
	buf_priv->dispatched = 0;

D
Dave Airlie 已提交
763
	mga_freelist_put(dev, buf);
L
Linus Torvalds 已提交
764 765 766 767

	FLUSH_DMA();
}

768
static void mga_dma_dispatch_blit(struct drm_device *dev, drm_mga_blit_t *blit)
L
Linus Torvalds 已提交
769 770 771 772
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
	drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
773
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
774 775 776
	int nbox = sarea_priv->nbox;
	u32 scandir = 0, i;
	DMA_LOCALS;
D
Dave Airlie 已提交
777
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
778

D
Dave Airlie 已提交
779
	BEGIN_DMA(4 + nbox);
L
Linus Torvalds 已提交
780

D
Dave Airlie 已提交
781 782 783
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
		  MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
L
Linus Torvalds 已提交
784

D
Dave Airlie 已提交
785 786 787
	DMA_BLOCK(MGA_DWGCTL, MGA_DWGCTL_COPY,
		  MGA_PLNWT, blit->planemask,
		  MGA_SRCORG, blit->srcorg, MGA_DSTORG, blit->dstorg);
L
Linus Torvalds 已提交
788

D
Dave Airlie 已提交
789 790 791 792
	DMA_BLOCK(MGA_SGN, scandir,
		  MGA_MACCESS, dev_priv->maccess,
		  MGA_AR5, blit->ydir * blit->src_pitch,
		  MGA_PITCH, blit->dst_pitch);
L
Linus Torvalds 已提交
793

D
Dave Airlie 已提交
794
	for (i = 0; i < nbox; i++) {
L
Linus Torvalds 已提交
795 796 797 798 799 800 801 802
		int srcx = pbox[i].x1 + blit->delta_sx;
		int srcy = pbox[i].y1 + blit->delta_sy;
		int dstx = pbox[i].x1 + blit->delta_dx;
		int dsty = pbox[i].y1 + blit->delta_dy;
		int h = pbox[i].y2 - pbox[i].y1;
		int w = pbox[i].x2 - pbox[i].x1 - 1;
		int start;

803
		if (blit->ydir == -1)
L
Linus Torvalds 已提交
804 805 806 807
			srcy = blit->height - srcy - 1;

		start = srcy * blit->src_pitch + srcx;

D
Dave Airlie 已提交
808 809 810 811
		DMA_BLOCK(MGA_AR0, start + w,
			  MGA_AR3, start,
			  MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff),
			  MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h);
L
Linus Torvalds 已提交
812 813 814 815 816 817
	}

	/* Do something to flush AGP?
	 */

	/* Force reset of DWGCTL */
D
Dave Airlie 已提交
818 819 820
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_PLNWT, ctx->plnwt,
		  MGA_PITCH, dev_priv->front_pitch, MGA_DWGCTL, ctx->dwgctl);
L
Linus Torvalds 已提交
821 822 823 824 825 826 827 828

	ADVANCE_DMA();
}

/* ================================================================
 *
 */

829
static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
830 831 832
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
833
	drm_mga_clear_t *clear = data;
L
Linus Torvalds 已提交
834

835
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
836

D
Dave Airlie 已提交
837
	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
838 839
		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;

D
Dave Airlie 已提交
840
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
841

842
	mga_dma_dispatch_clear(dev, clear);
L
Linus Torvalds 已提交
843 844 845 846 847 848 849 850

	/* Make sure we restore the 3D state next time.
	 */
	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;

	return 0;
}

851
static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
852 853 854 855
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;

856
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
857

D
Dave Airlie 已提交
858
	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
859 860
		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;

D
Dave Airlie 已提交
861
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
862

D
Dave Airlie 已提交
863
	mga_dma_dispatch_swap(dev);
L
Linus Torvalds 已提交
864 865 866 867 868 869 870 871

	/* Make sure we restore the 3D state next time.
	 */
	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;

	return 0;
}

872
static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
873 874
{
	drm_mga_private_t *dev_priv = dev->dev_private;
875
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
876
	struct drm_buf *buf;
L
Linus Torvalds 已提交
877
	drm_mga_buf_priv_t *buf_priv;
878
	drm_mga_vertex_t *vertex = data;
L
Linus Torvalds 已提交
879

880
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
881

882
	if (vertex->idx < 0 || vertex->idx > dma->buf_count)
E
Eric Anholt 已提交
883
		return -EINVAL;
884
	buf = dma->buflist[vertex->idx];
L
Linus Torvalds 已提交
885 886
	buf_priv = buf->dev_private;

887 888
	buf->used = vertex->used;
	buf_priv->discard = vertex->discard;
L
Linus Torvalds 已提交
889

D
Dave Airlie 已提交
890
	if (!mga_verify_state(dev_priv)) {
891
		if (vertex->discard) {
D
Dave Airlie 已提交
892 893
			if (buf_priv->dispatched == 1)
				AGE_BUFFER(buf_priv);
L
Linus Torvalds 已提交
894
			buf_priv->dispatched = 0;
D
Dave Airlie 已提交
895
			mga_freelist_put(dev, buf);
L
Linus Torvalds 已提交
896
		}
E
Eric Anholt 已提交
897
		return -EINVAL;
L
Linus Torvalds 已提交
898 899
	}

D
Dave Airlie 已提交
900
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
901

D
Dave Airlie 已提交
902
	mga_dma_dispatch_vertex(dev, buf);
L
Linus Torvalds 已提交
903 904 905 906

	return 0;
}

907
static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
908 909
{
	drm_mga_private_t *dev_priv = dev->dev_private;
910
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
911
	struct drm_buf *buf;
L
Linus Torvalds 已提交
912
	drm_mga_buf_priv_t *buf_priv;
913
	drm_mga_indices_t *indices = data;
L
Linus Torvalds 已提交
914

915
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
916

917
	if (indices->idx < 0 || indices->idx > dma->buf_count)
E
Eric Anholt 已提交
918
		return -EINVAL;
L
Linus Torvalds 已提交
919

920
	buf = dma->buflist[indices->idx];
L
Linus Torvalds 已提交
921 922
	buf_priv = buf->dev_private;

923
	buf_priv->discard = indices->discard;
L
Linus Torvalds 已提交
924

D
Dave Airlie 已提交
925
	if (!mga_verify_state(dev_priv)) {
926
		if (indices->discard) {
D
Dave Airlie 已提交
927 928
			if (buf_priv->dispatched == 1)
				AGE_BUFFER(buf_priv);
L
Linus Torvalds 已提交
929
			buf_priv->dispatched = 0;
D
Dave Airlie 已提交
930
			mga_freelist_put(dev, buf);
L
Linus Torvalds 已提交
931
		}
E
Eric Anholt 已提交
932
		return -EINVAL;
L
Linus Torvalds 已提交
933 934
	}

D
Dave Airlie 已提交
935
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
936

937
	mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
L
Linus Torvalds 已提交
938 939 940 941

	return 0;
}

942
static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
943
{
944
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
945
	drm_mga_private_t *dev_priv = dev->dev_private;
D
Dave Airlie 已提交
946
	struct drm_buf *buf;
L
Linus Torvalds 已提交
947
	drm_mga_buf_priv_t *buf_priv;
948
	drm_mga_iload_t *iload = data;
D
Dave Airlie 已提交
949
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
950

951
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
952 953

#if 0
D
Dave Airlie 已提交
954 955
	if (mga_do_wait_for_idle(dev_priv) < 0) {
		if (MGA_DMA_DEBUG)
956
			DRM_INFO("-EBUSY\n");
E
Eric Anholt 已提交
957
		return -EBUSY;
L
Linus Torvalds 已提交
958 959
	}
#endif
960
	if (iload->idx < 0 || iload->idx > dma->buf_count)
E
Eric Anholt 已提交
961
		return -EINVAL;
L
Linus Torvalds 已提交
962

963
	buf = dma->buflist[iload->idx];
L
Linus Torvalds 已提交
964 965
	buf_priv = buf->dev_private;

966
	if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
D
Dave Airlie 已提交
967
		mga_freelist_put(dev, buf);
E
Eric Anholt 已提交
968
		return -EINVAL;
L
Linus Torvalds 已提交
969 970
	}

D
Dave Airlie 已提交
971
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
972

973
	mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
L
Linus Torvalds 已提交
974 975 976 977 978 979 980 981

	/* Make sure we restore the 3D state next time.
	 */
	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;

	return 0;
}

982
static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
983 984 985
{
	drm_mga_private_t *dev_priv = dev->dev_private;
	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
986
	drm_mga_blit_t *blit = data;
D
Dave Airlie 已提交
987
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
988

989
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
990

D
Dave Airlie 已提交
991
	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
992 993
		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;

994
	if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
E
Eric Anholt 已提交
995
		return -EINVAL;
L
Linus Torvalds 已提交
996

D
Dave Airlie 已提交
997
	WRAP_TEST_WITH_RETURN(dev_priv);
L
Linus Torvalds 已提交
998

999
	mga_dma_dispatch_blit(dev, blit);
L
Linus Torvalds 已提交
1000 1001 1002 1003 1004 1005 1006 1007

	/* Make sure we restore the 3D state next time.
	 */
	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;

	return 0;
}

1008
static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1009 1010
{
	drm_mga_private_t *dev_priv = dev->dev_private;
1011
	drm_mga_getparam_t *param = data;
L
Linus Torvalds 已提交
1012 1013
	int value;

D
Dave Airlie 已提交
1014
	if (!dev_priv) {
1015
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
1016
		return -EINVAL;
L
Linus Torvalds 已提交
1017 1018
	}

D
Dave Airlie 已提交
1019
	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
L
Linus Torvalds 已提交
1020

1021
	switch (param->param) {
L
Linus Torvalds 已提交
1022
	case MGA_PARAM_IRQ_NR:
J
Jesse Barnes 已提交
1023
		value = drm_dev_to_irq(dev);
L
Linus Torvalds 已提交
1024
		break;
1025 1026 1027
	case MGA_PARAM_CARD_TYPE:
		value = dev_priv->chipset;
		break;
L
Linus Torvalds 已提交
1028
	default:
E
Eric Anholt 已提交
1029
		return -EINVAL;
L
Linus Torvalds 已提交
1030 1031
	}

1032
	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
D
Dave Airlie 已提交
1033
		DRM_ERROR("copy_to_user\n");
E
Eric Anholt 已提交
1034
		return -EFAULT;
L
Linus Torvalds 已提交
1035
	}
D
Dave Airlie 已提交
1036

L
Linus Torvalds 已提交
1037 1038 1039
	return 0;
}

1040
static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
1041 1042
{
	drm_mga_private_t *dev_priv = dev->dev_private;
1043
	u32 *fence = data;
1044 1045 1046
	DMA_LOCALS;

	if (!dev_priv) {
1047
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
1048
		return -EINVAL;
1049 1050 1051 1052
	}

	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);

1053
	/* I would normal do this assignment in the declaration of fence,
1054 1055 1056
	 * but dev_priv may be NULL.
	 */

1057
	*fence = dev_priv->next_fence_to_post;
1058 1059 1060 1061 1062
	dev_priv->next_fence_to_post++;

	BEGIN_DMA(1);
	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
		  MGA_DMAPAD, 0x00000000,
D
Dave Airlie 已提交
1063
		  MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000);
1064 1065 1066 1067 1068
	ADVANCE_DMA();

	return 0;
}

1069 1070
static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *
file_priv)
1071 1072
{
	drm_mga_private_t *dev_priv = dev->dev_private;
1073
	u32 *fence = data;
1074 1075

	if (!dev_priv) {
1076
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
1077
		return -EINVAL;
1078 1079 1080 1081
	}

	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);

1082
	mga_driver_fence_wait(dev, fence);
1083 1084 1085
	return 0;
}

R
Rob Clark 已提交
1086
const struct drm_ioctl_desc mga_ioctls[] = {
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
	DRM_IOCTL_DEF_DRV(MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF_DRV(MGA_FLUSH, mga_dma_flush, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_RESET, mga_dma_reset, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_SWAP, mga_dma_swap, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_CLEAR, mga_dma_clear, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_INDICES, mga_dma_indices, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_ILOAD, mga_dma_iload, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_BLIT, mga_dma_blit, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_GETPARAM, mga_getparam, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
	DRM_IOCTL_DEF_DRV(MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
L
Linus Torvalds 已提交
1100 1101 1102
};

int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);