1 /* mga_state.c -- State support for mga g200/g400 -*- linux-c -*-
2 * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors: Jeff Hartmann <jhartmann@valinux.com>
28 * Keith Whitwell <keithw@valinux.com>
29 *
30 */
31
32 #define __NO_VERSION__
33 #include "drmP.h"
34 #include "mga_drv.h"
35 #include "drm.h"
36
37 /* If you change the functions to set state, PLEASE
38 * change these values
39 */
40
41 #define MGAEMITCLIP_SIZE 10
42 #define MGAEMITCTX_SIZE 20
43 #define MGAG200EMITTEX_SIZE 20
44 #define MGAG400EMITTEX0_SIZE 30
45 #define MGAG400EMITTEX1_SIZE 25
46 #define MGAG400EMITPIPE_SIZE 50
47 #define MGAG200EMITPIPE_SIZE 15
48
49 #define MAX_STATE_SIZE ((MGAEMITCLIP_SIZE * MGA_NR_SAREA_CLIPRECTS) + \
50 MGAEMITCTX_SIZE + MGAG400EMITTEX0_SIZE + \
51 MGAG400EMITTEX1_SIZE + MGAG400EMITPIPE_SIZE)
52
mgaEmitClipRect(drm_mga_private_t * dev_priv,drm_clip_rect_t * box)53 static void mgaEmitClipRect(drm_mga_private_t * dev_priv,
54 drm_clip_rect_t * box)
55 {
56 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
57 unsigned int *regs = sarea_priv->ContextState;
58 PRIMLOCALS;
59
60 /* This takes 10 dwords */
61 PRIMGETPTR(dev_priv);
62
63 /* Force reset of dwgctl on G400 (eliminates clip disable bit) */
64 if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
65 #if 0
66 PRIMOUTREG(MGAREG_DMAPAD, 0);
67 PRIMOUTREG(MGAREG_DWGSYNC, 0);
68 PRIMOUTREG(MGAREG_DWGSYNC, 0);
69 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
70 #else
71 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
72 PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
73 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
74 PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
75 #endif
76 }
77 PRIMOUTREG(MGAREG_DMAPAD, 0);
78 PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1));
79 PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / dev_priv->cpp);
80 PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / dev_priv->cpp);
81
82 PRIMADVANCE(dev_priv);
83 }
84
mgaEmitContext(drm_mga_private_t * dev_priv)85 static void mgaEmitContext(drm_mga_private_t * dev_priv)
86 {
87 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
88 unsigned int *regs = sarea_priv->ContextState;
89 PRIMLOCALS;
90
91 /* This takes a max of 20 dwords */
92 PRIMGETPTR(dev_priv);
93
94 PRIMOUTREG(MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG]);
95 PRIMOUTREG(MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS]);
96 PRIMOUTREG(MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT]);
97 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
98
99 PRIMOUTREG(MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL]);
100 PRIMOUTREG(MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR]);
101 PRIMOUTREG(MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG]);
102 PRIMOUTREG(MGAREG_ZORG, dev_priv->depthOffset); /* invarient */
103
104 if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
105 PRIMOUTREG(MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG]);
106 PRIMOUTREG(MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0]);
107 PRIMOUTREG(MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1]);
108 PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
109
110 PRIMOUTREG(MGAREG_STENCIL, regs[MGA_CTXREG_STENCIL]);
111 PRIMOUTREG(MGAREG_STENCILCTL, regs[MGA_CTXREG_STENCILCTL]);
112 PRIMOUTREG(MGAREG_DMAPAD, 0);
113 PRIMOUTREG(MGAREG_DMAPAD, 0);
114 } else {
115 PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
116 PRIMOUTREG(MGAREG_DMAPAD, 0);
117 PRIMOUTREG(MGAREG_DMAPAD, 0);
118 PRIMOUTREG(MGAREG_DMAPAD, 0);
119 }
120
121 PRIMADVANCE(dev_priv);
122 }
123
mgaG200EmitTex(drm_mga_private_t * dev_priv)124 static void mgaG200EmitTex(drm_mga_private_t * dev_priv)
125 {
126 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
127 unsigned int *regs = sarea_priv->TexState[0];
128 PRIMLOCALS;
129
130 PRIMGETPTR(dev_priv);
131
132 /* This takes 20 dwords */
133
134 PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2]);
135 PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
136 PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
137 PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
138
139 PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
140 PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
141 PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
142 PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
143
144 PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
145 PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
146 PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
147 PRIMOUTREG(MGAREG_WR24, regs[MGA_TEXREG_WIDTH]);
148
149 PRIMOUTREG(MGAREG_WR34, regs[MGA_TEXREG_HEIGHT]);
150 PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
151 PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
152 PRIMOUTREG(MGAREG_DMAPAD, 0);
153
154 PRIMADVANCE(dev_priv);
155 }
156
157 #define TMC_dualtex_enable 0x80
158
mgaG400EmitTex0(drm_mga_private_t * dev_priv)159 static void mgaG400EmitTex0(drm_mga_private_t * dev_priv)
160 {
161 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
162 unsigned int *regs = sarea_priv->TexState[0];
163 PRIMLOCALS;
164
165 PRIMGETPTR(dev_priv);
166
167 /* This takes 30 dwords */
168
169 PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
170 PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
171 PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
172 PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
173
174 PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
175 PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
176 PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
177 PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
178
179 PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
180 PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
181 PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
182 PRIMOUTREG(MGAREG_WR49, 0);
183
184 PRIMOUTREG(MGAREG_WR57, 0);
185 PRIMOUTREG(MGAREG_WR53, 0);
186 PRIMOUTREG(MGAREG_WR61, 0);
187 PRIMOUTREG(MGAREG_WR52, 0x40);
188
189 PRIMOUTREG(MGAREG_WR60, 0x40);
190 PRIMOUTREG(MGAREG_WR54, regs[MGA_TEXREG_WIDTH] | 0x40);
191 PRIMOUTREG(MGAREG_WR62, regs[MGA_TEXREG_HEIGHT] | 0x40);
192 PRIMOUTREG(MGAREG_DMAPAD, 0);
193
194 PRIMOUTREG(MGAREG_DMAPAD, 0);
195 PRIMOUTREG(MGAREG_DMAPAD, 0);
196 PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
197 PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
198
199 PRIMADVANCE(dev_priv);
200 }
201
202 #define TMC_map1_enable 0x80000000
203
mgaG400EmitTex1(drm_mga_private_t * dev_priv)204 static void mgaG400EmitTex1(drm_mga_private_t * dev_priv)
205 {
206 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
207 unsigned int *regs = sarea_priv->TexState[1];
208 PRIMLOCALS;
209
210 PRIMGETPTR(dev_priv);
211
212 /* This takes 25 dwords */
213
214 PRIMOUTREG(MGAREG_TEXCTL2,
215 regs[MGA_TEXREG_CTL2] | TMC_map1_enable | 0x00008000);
216 PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
217 PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
218 PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
219
220 PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
221 PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
222 PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
223 PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
224
225 PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
226 PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
227 PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
228 PRIMOUTREG(MGAREG_WR49, 0);
229
230 PRIMOUTREG(MGAREG_WR57, 0);
231 PRIMOUTREG(MGAREG_WR53, 0);
232 PRIMOUTREG(MGAREG_WR61, 0);
233 PRIMOUTREG(MGAREG_WR52, regs[MGA_TEXREG_WIDTH] | 0x40);
234
235 PRIMOUTREG(MGAREG_WR60, regs[MGA_TEXREG_HEIGHT] | 0x40);
236 PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
237 PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
238 PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
239
240 PRIMADVANCE(dev_priv);
241 }
242
243 #define MAGIC_FPARAM_HEX_VALUE 0x46480000
244 /* This is the hex value of 12800.0f which is a magic value we must
245 * set in wr56.
246 */
247
mgaG400EmitPipe(drm_mga_private_t * dev_priv)248 static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
249 {
250 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
251 unsigned int pipe = sarea_priv->WarpPipe;
252 PRIMLOCALS;
253
254 PRIMGETPTR(dev_priv);
255
256 /* This takes 50 dwords */
257
258 /* Establish vertex size.
259 */
260 PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend);
261 PRIMOUTREG(MGAREG_DMAPAD, 0);
262 PRIMOUTREG(MGAREG_DMAPAD, 0);
263 PRIMOUTREG(MGAREG_DMAPAD, 0);
264
265 if (pipe & MGA_T2) {
266 PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001e09);
267 PRIMOUTREG(MGAREG_DMAPAD, 0);
268 PRIMOUTREG(MGAREG_DMAPAD, 0);
269 PRIMOUTREG(MGAREG_DMAPAD, 0);
270
271 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
272 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
273 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
274 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000);
275 } else {
276 if (dev_priv->WarpPipe & MGA_T2) {
277 /* Flush the WARP pipe */
278 PRIMOUTREG(MGAREG_YDST, 0);
279 PRIMOUTREG(MGAREG_FXLEFT, 0);
280 PRIMOUTREG(MGAREG_FXRIGHT, 1);
281 PRIMOUTREG(MGAREG_DWGCTL, MGA_FLUSH_CMD);
282
283 PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 1);
284 PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
285 PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000);
286 PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
287
288 PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000);
289 PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
290 PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000);
291 PRIMOUTREG(MGAREG_DMAPAD, 0);
292 }
293
294 PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807);
295 PRIMOUTREG(MGAREG_DMAPAD, 0);
296 PRIMOUTREG(MGAREG_DMAPAD, 0);
297 PRIMOUTREG(MGAREG_DMAPAD, 0);
298
299 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
300 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
301 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
302 PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x18000000);
303 }
304
305 PRIMOUTREG(MGAREG_WFLAG, 0);
306 PRIMOUTREG(MGAREG_WFLAG1, 0);
307 PRIMOUTREG(MGAREG_WR56, MAGIC_FPARAM_HEX_VALUE);
308 PRIMOUTREG(MGAREG_DMAPAD, 0);
309
310 PRIMOUTREG(MGAREG_WR49, 0); /* Tex stage 0 */
311 PRIMOUTREG(MGAREG_WR57, 0); /* Tex stage 0 */
312 PRIMOUTREG(MGAREG_WR53, 0); /* Tex stage 1 */
313 PRIMOUTREG(MGAREG_WR61, 0); /* Tex stage 1 */
314
315 PRIMOUTREG(MGAREG_WR54, 0x40); /* Tex stage 0 : w */
316 PRIMOUTREG(MGAREG_WR62, 0x40); /* Tex stage 0 : h */
317 PRIMOUTREG(MGAREG_WR52, 0x40); /* Tex stage 1 : w */
318 PRIMOUTREG(MGAREG_WR60, 0x40); /* Tex stage 1 : h */
319
320 /* Dma pading required due to hw bug */
321 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
322 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
323 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
324 PRIMOUTREG(MGAREG_WIADDR2,
325 (u32) (dev_priv->WarpIndex[pipe].
326 phys_addr | WIA_wmode_start | WIA_wagp_agp));
327 PRIMADVANCE(dev_priv);
328 }
329
mgaG200EmitPipe(drm_mga_private_t * dev_priv)330 static void mgaG200EmitPipe(drm_mga_private_t * dev_priv)
331 {
332 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
333 unsigned int pipe = sarea_priv->WarpPipe;
334 PRIMLOCALS;
335
336 PRIMGETPTR(dev_priv);
337
338 /* This takes 15 dwords */
339
340 PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend);
341 PRIMOUTREG(MGAREG_WVRTXSZ, 7);
342 PRIMOUTREG(MGAREG_WFLAG, 0);
343 PRIMOUTREG(MGAREG_WR24, 0); /* tex w/h */
344
345 PRIMOUTREG(MGAREG_WR25, 0x100);
346 PRIMOUTREG(MGAREG_WR34, 0); /* tex w/h */
347 PRIMOUTREG(MGAREG_WR42, 0xFFFF);
348 PRIMOUTREG(MGAREG_WR60, 0xFFFF);
349
350 /* Dma pading required due to hw bug */
351 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
352 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
353 PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
354 PRIMOUTREG(MGAREG_WIADDR,
355 (u32) (dev_priv->WarpIndex[pipe].
356 phys_addr | WIA_wmode_start | WIA_wagp_agp));
357
358 PRIMADVANCE( dev_priv );
359 }
360
mgaEmitState(drm_mga_private_t * dev_priv)361 static void mgaEmitState(drm_mga_private_t * dev_priv)
362 {
363 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
364 unsigned int dirty = sarea_priv->dirty;
365
366 if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
367 int multitex = sarea_priv->WarpPipe & MGA_T2;
368
369 if (sarea_priv->WarpPipe != dev_priv->WarpPipe) {
370 mgaG400EmitPipe(dev_priv);
371 dev_priv->WarpPipe = sarea_priv->WarpPipe;
372 }
373
374 if (dirty & MGA_UPLOAD_CTX) {
375 mgaEmitContext(dev_priv);
376 sarea_priv->dirty &= ~MGA_UPLOAD_CTX;
377 }
378
379 if (dirty & MGA_UPLOAD_TEX0) {
380 mgaG400EmitTex0(dev_priv);
381 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
382 }
383
384 if ((dirty & MGA_UPLOAD_TEX1) && multitex) {
385 mgaG400EmitTex1(dev_priv);
386 sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
387 }
388 } else {
389 if (sarea_priv->WarpPipe != dev_priv->WarpPipe) {
390 mgaG200EmitPipe(dev_priv);
391 dev_priv->WarpPipe = sarea_priv->WarpPipe;
392 }
393
394 if (dirty & MGA_UPLOAD_CTX) {
395 mgaEmitContext(dev_priv);
396 sarea_priv->dirty &= ~MGA_UPLOAD_CTX;
397 }
398
399 if (dirty & MGA_UPLOAD_TEX0) {
400 mgaG200EmitTex(dev_priv);
401 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
402 }
403 }
404 }
405
406 /* Disallow all write destinations except the front and backbuffer.
407 */
mgaVerifyContext(drm_mga_private_t * dev_priv)408 static int mgaVerifyContext(drm_mga_private_t * dev_priv)
409 {
410 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
411 unsigned int *regs = sarea_priv->ContextState;
412
413 if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset &&
414 regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) {
415 DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n",
416 regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset,
417 dev_priv->backOffset);
418 regs[MGA_CTXREG_DSTORG] = 0;
419 return -1;
420 }
421
422 return 0;
423 }
424
425 /* Disallow texture reads from PCI space.
426 */
mgaVerifyTex(drm_mga_private_t * dev_priv,int unit)427 static int mgaVerifyTex(drm_mga_private_t * dev_priv, int unit)
428 {
429 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
430
431 if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) {
432 DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n",
433 sarea_priv->TexState[unit][MGA_TEXREG_ORG],
434 unit);
435 sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0;
436 return -1;
437 }
438
439 return 0;
440 }
441
mgaVerifyState(drm_mga_private_t * dev_priv)442 static int mgaVerifyState(drm_mga_private_t * dev_priv)
443 {
444 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
445 unsigned int dirty = sarea_priv->dirty;
446 int rv = 0;
447
448 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
449 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
450
451 if (dirty & MGA_UPLOAD_CTX)
452 rv |= mgaVerifyContext(dev_priv);
453
454 if (dirty & MGA_UPLOAD_TEX0)
455 rv |= mgaVerifyTex(dev_priv, 0);
456
457 if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
458 if (dirty & MGA_UPLOAD_TEX1)
459 rv |= mgaVerifyTex(dev_priv, 1);
460
461 if (dirty & MGA_UPLOAD_PIPE)
462 rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES);
463 } else {
464 if (dirty & MGA_UPLOAD_PIPE)
465 rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES);
466 }
467
468 return rv == 0;
469 }
470
mgaVerifyIload(drm_mga_private_t * dev_priv,unsigned long bus_address,unsigned int dstOrg,int length)471 static int mgaVerifyIload(drm_mga_private_t * dev_priv,
472 unsigned long bus_address,
473 unsigned int dstOrg, int length)
474 {
475 if (dstOrg < dev_priv->textureOffset ||
476 dstOrg + length >
477 (dev_priv->textureOffset + dev_priv->textureSize)) {
478 return -EINVAL;
479 }
480 if (length % 64) {
481 return -EINVAL;
482 }
483 return 0;
484 }
485
486 /* This copies a 64 byte aligned agp region to the frambuffer
487 * with a standard blit, the ioctl needs to do checking */
488
mga_dma_dispatch_tex_blit(drm_device_t * dev,unsigned long bus_address,int length,unsigned int destOrg)489 static void mga_dma_dispatch_tex_blit(drm_device_t * dev,
490 unsigned long bus_address,
491 int length, unsigned int destOrg)
492 {
493 drm_mga_private_t *dev_priv = dev->dev_private;
494 int use_agp = PDEA_pagpxfer_enable | 0x00000001;
495 u16 y2;
496 PRIMLOCALS;
497
498 y2 = length / 64;
499
500 PRIM_OVERFLOW(dev, dev_priv, 30);
501
502 PRIMOUTREG(MGAREG_DSTORG, destOrg);
503 PRIMOUTREG(MGAREG_MACCESS, 0x00000000);
504 PRIMOUTREG(MGAREG_SRCORG, (u32) bus_address | use_agp);
505 PRIMOUTREG(MGAREG_AR5, 64);
506
507 PRIMOUTREG(MGAREG_PITCH, 64);
508 PRIMOUTREG(MGAREG_DMAPAD, 0);
509 PRIMOUTREG(MGAREG_DMAPAD, 0);
510 PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD);
511
512 PRIMOUTREG(MGAREG_AR0, 63);
513 PRIMOUTREG(MGAREG_AR3, 0);
514 PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16));
515 PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, y2);
516
517 PRIMOUTREG(MGAREG_DMAPAD, 0);
518 PRIMOUTREG(MGAREG_SRCORG, 0);
519 PRIMOUTREG(MGAREG_PITCH, dev_priv->stride / dev_priv->cpp);
520 PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
521 PRIMADVANCE(dev_priv);
522 }
523
mga_dma_dispatch_vertex(drm_device_t * dev,drm_buf_t * buf)524 static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
525 {
526 drm_mga_private_t *dev_priv = dev->dev_private;
527 drm_mga_buf_priv_t *buf_priv = buf->dev_private;
528 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
529 unsigned long address = (unsigned long) buf->bus_address;
530 int length = buf->used;
531 int use_agp = PDEA_pagpxfer_enable;
532 int i = 0;
533 PRIMLOCALS;
534
535 if (buf->used) {
536 /* WARNING: if you change any of the state functions verify
537 * these numbers (Overestimating this doesn't hurt).
538 */
539 buf_priv->dispatched = 1;
540 PRIM_OVERFLOW(dev, dev_priv,
541 (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS)));
542 mgaEmitState(dev_priv);
543
544 #if 0
545 length = dev_priv->vertexsize * 3 * 4;
546 #endif
547
548 do {
549 if (i < sarea_priv->nbox) {
550 mgaEmitClipRect(dev_priv,
551 &sarea_priv->boxes[i]);
552 }
553
554 PRIMGETPTR(dev_priv);
555 PRIMOUTREG(MGAREG_DMAPAD, 0);
556 PRIMOUTREG(MGAREG_DMAPAD, 0);
557 PRIMOUTREG(MGAREG_SECADDRESS,
558 ((u32) address) | TT_VERTEX);
559 PRIMOUTREG(MGAREG_SECEND,
560 (((u32) (address + length)) | use_agp));
561 PRIMADVANCE(dev_priv);
562 } while (++i < sarea_priv->nbox);
563 }
564 if (buf_priv->discard) {
565 if (buf_priv->dispatched == 1)
566 AGEBUF(dev_priv, buf_priv);
567 buf_priv->dispatched = 0;
568 mga_freelist_put(dev, buf);
569 }
570
571
572 }
573
574
mga_dma_dispatch_indices(drm_device_t * dev,drm_buf_t * buf,unsigned int start,unsigned int end)575 static void mga_dma_dispatch_indices(drm_device_t * dev,
576 drm_buf_t * buf,
577 unsigned int start, unsigned int end)
578 {
579 drm_mga_private_t *dev_priv = dev->dev_private;
580 drm_mga_buf_priv_t *buf_priv = buf->dev_private;
581 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
582 unsigned int address = (unsigned int) buf->bus_address;
583 int use_agp = PDEA_pagpxfer_enable;
584 int i = 0;
585 PRIMLOCALS;
586
587 if (start != end) {
588 /* WARNING: if you change any of the state functions verify
589 * these numbers (Overestimating this doesn't hurt).
590 */
591 buf_priv->dispatched = 1;
592 PRIM_OVERFLOW(dev, dev_priv,
593 (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS)));
594 mgaEmitState(dev_priv);
595
596 do {
597 if (i < sarea_priv->nbox) {
598 mgaEmitClipRect(dev_priv,
599 &sarea_priv->boxes[i]);
600 }
601
602 PRIMGETPTR(dev_priv);
603 PRIMOUTREG(MGAREG_DMAPAD, 0);
604 PRIMOUTREG(MGAREG_DMAPAD, 0);
605 PRIMOUTREG(MGAREG_SETUPADDRESS,
606 ((address + start) |
607 SETADD_mode_vertlist));
608 PRIMOUTREG(MGAREG_SETUPEND,
609 ((address + end) | use_agp));
610 /* ((address + start + 12) | use_agp)); */
611 PRIMADVANCE(dev_priv);
612 } while (++i < sarea_priv->nbox);
613 }
614 if (buf_priv->discard) {
615 if (buf_priv->dispatched == 1)
616 AGEBUF(dev_priv, buf_priv);
617 buf_priv->dispatched = 0;
618 mga_freelist_put(dev, buf);
619 }
620 }
621
622
mga_dma_dispatch_clear(drm_device_t * dev,int flags,unsigned int clear_color,unsigned int clear_zval,unsigned int clear_colormask,unsigned int clear_depthmask)623 static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
624 unsigned int clear_color,
625 unsigned int clear_zval,
626 unsigned int clear_colormask,
627 unsigned int clear_depthmask)
628 {
629 drm_mga_private_t *dev_priv = dev->dev_private;
630 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
631 unsigned int *regs = sarea_priv->ContextState;
632 int nbox = sarea_priv->nbox;
633 drm_clip_rect_t *pbox = sarea_priv->boxes;
634 unsigned int cmd;
635 int i;
636 PRIMLOCALS;
637
638 if (dev_priv->sgram)
639 cmd = MGA_CLEAR_CMD | DC_atype_blk;
640 else
641 cmd = MGA_CLEAR_CMD | DC_atype_rstr;
642
643 PRIM_OVERFLOW(dev, dev_priv, 35 * MGA_NR_SAREA_CLIPRECTS);
644
645 for (i = 0; i < nbox; i++) {
646 unsigned int height = pbox[i].y2 - pbox[i].y1;
647
648 if (flags & MGA_FRONT) {
649 PRIMOUTREG(MGAREG_DMAPAD, 0);
650 PRIMOUTREG(MGAREG_PLNWT, clear_colormask);
651 PRIMOUTREG(MGAREG_YDSTLEN,
652 (pbox[i].y1 << 16) | height);
653 PRIMOUTREG(MGAREG_FXBNDRY,
654 (pbox[i].x2 << 16) | pbox[i].x1);
655
656 PRIMOUTREG(MGAREG_DMAPAD, 0);
657 PRIMOUTREG(MGAREG_FCOL, clear_color);
658 PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset);
659 PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
660 }
661
662 if (flags & MGA_BACK) {
663 PRIMOUTREG(MGAREG_DMAPAD, 0);
664 PRIMOUTREG(MGAREG_PLNWT, clear_colormask);
665 PRIMOUTREG(MGAREG_YDSTLEN,
666 (pbox[i].y1 << 16) | height);
667 PRIMOUTREG(MGAREG_FXBNDRY,
668 (pbox[i].x2 << 16) | pbox[i].x1);
669
670 PRIMOUTREG(MGAREG_DMAPAD, 0);
671 PRIMOUTREG(MGAREG_FCOL, clear_color);
672 PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset);
673 PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
674 }
675
676 if (flags & MGA_DEPTH) {
677 PRIMOUTREG(MGAREG_DMAPAD, 0);
678 PRIMOUTREG(MGAREG_PLNWT, clear_depthmask);
679 PRIMOUTREG(MGAREG_YDSTLEN,
680 (pbox[i].y1 << 16) | height);
681 PRIMOUTREG(MGAREG_FXBNDRY,
682 (pbox[i].x2 << 16) | pbox[i].x1);
683
684 PRIMOUTREG(MGAREG_DMAPAD, 0);
685 PRIMOUTREG(MGAREG_FCOL, clear_zval);
686 PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset);
687 PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
688 }
689 }
690
691 /* Force reset of DWGCTL */
692 PRIMOUTREG(MGAREG_DMAPAD, 0);
693 PRIMOUTREG(MGAREG_DMAPAD, 0);
694 PRIMOUTREG(MGAREG_DMAPAD, 0);
695 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
696 PRIMADVANCE(dev_priv);
697 }
698
mga_dma_dispatch_swap(drm_device_t * dev)699 static void mga_dma_dispatch_swap(drm_device_t * dev)
700 {
701 drm_mga_private_t *dev_priv = dev->dev_private;
702 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
703 unsigned int *regs = sarea_priv->ContextState;
704 int nbox = sarea_priv->nbox;
705 drm_clip_rect_t *pbox = sarea_priv->boxes;
706 int i;
707 int pixel_stride = dev_priv->stride / dev_priv->cpp;
708
709 PRIMLOCALS;
710
711 PRIM_OVERFLOW(dev, dev_priv, (MGA_NR_SAREA_CLIPRECTS * 5) + 20);
712
713 PRIMOUTREG(MGAREG_DMAPAD, 0);
714 PRIMOUTREG(MGAREG_DMAPAD, 0);
715 PRIMOUTREG(MGAREG_DWGSYNC, 0x7100);
716 PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
717
718 PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset);
719 PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess);
720 PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset);
721 PRIMOUTREG(MGAREG_AR5, pixel_stride);
722
723 PRIMOUTREG(MGAREG_DMAPAD, 0);
724 PRIMOUTREG(MGAREG_DMAPAD, 0);
725 PRIMOUTREG(MGAREG_DMAPAD, 0);
726 PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD);
727
728 for (i = 0; i < nbox; i++) {
729 unsigned int h = pbox[i].y2 - pbox[i].y1;
730 unsigned int start = pbox[i].y1 * pixel_stride;
731
732 PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1);
733 PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1);
734 PRIMOUTREG(MGAREG_FXBNDRY,
735 pbox[i].x1 | ((pbox[i].x2 - 1) << 16));
736 PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC,
737 (pbox[i].y1 << 16) | h);
738 }
739
740 /* Force reset of DWGCTL */
741 PRIMOUTREG(MGAREG_DMAPAD, 0);
742 PRIMOUTREG(MGAREG_DMAPAD, 0);
743 PRIMOUTREG(MGAREG_SRCORG, 0);
744 PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
745
746 PRIMADVANCE(dev_priv);
747 }
748
mga_clear_bufs(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)749 int mga_clear_bufs(struct inode *inode, struct file *filp,
750 unsigned int cmd, unsigned long arg)
751 {
752 drm_file_t *priv = filp->private_data;
753 drm_device_t *dev = priv->dev;
754 drm_mga_private_t *dev_priv =
755 (drm_mga_private_t *) dev->dev_private;
756 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
757 drm_mga_clear_t clear;
758
759 if (copy_from_user(&clear, (drm_mga_clear_t *) arg, sizeof(clear)))
760 return -EFAULT;
761
762 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
763 DRM_ERROR("mga_clear_bufs called without lock held\n");
764 return -EINVAL;
765 }
766
767 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
768 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
769
770 /* Make sure we restore the 3D state next time.
771 */
772 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX;
773 mga_dma_dispatch_clear(dev, clear.flags,
774 clear.clear_color,
775 clear.clear_depth,
776 clear.clear_color_mask,
777 clear.clear_depth_mask);
778 PRIMUPDATE(dev_priv);
779 mga_flush_write_combine();
780 mga_dma_schedule(dev, 1);
781 return 0;
782 }
783
mga_swap_bufs(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)784 int mga_swap_bufs(struct inode *inode, struct file *filp,
785 unsigned int cmd, unsigned long arg)
786 {
787 drm_file_t *priv = filp->private_data;
788 drm_device_t *dev = priv->dev;
789 drm_mga_private_t *dev_priv =
790 (drm_mga_private_t *) dev->dev_private;
791 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
792
793 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
794 DRM_ERROR("mga_swap_bufs called without lock held\n");
795 return -EINVAL;
796 }
797
798 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
799 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
800
801 /* Make sure we restore the 3D state next time.
802 */
803 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX;
804 mga_dma_dispatch_swap(dev);
805 PRIMUPDATE(dev_priv);
806 set_bit(MGA_BUF_SWAP_PENDING,
807 &dev_priv->current_prim->buffer_status);
808 mga_flush_write_combine();
809 mga_dma_schedule(dev, 1);
810 return 0;
811 }
812
mga_iload(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)813 int mga_iload(struct inode *inode, struct file *filp,
814 unsigned int cmd, unsigned long arg)
815 {
816 drm_file_t *priv = filp->private_data;
817 drm_device_t *dev = priv->dev;
818 drm_device_dma_t *dma = dev->dma;
819 drm_mga_private_t *dev_priv =
820 (drm_mga_private_t *) dev->dev_private;
821 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
822 drm_buf_t *buf;
823 drm_mga_buf_priv_t *buf_priv;
824 drm_mga_iload_t iload;
825 unsigned long bus_address;
826
827 if (copy_from_user(&iload, (drm_mga_iload_t *) arg, sizeof(iload)))
828 return -EFAULT;
829
830 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
831 DRM_ERROR("mga_iload called without lock held\n");
832 return -EINVAL;
833 }
834
835 if(iload.idx < 0 || iload.idx > dma->buf_count) return -EINVAL;
836 buf = dma->buflist[iload.idx];
837 buf_priv = buf->dev_private;
838 bus_address = buf->bus_address;
839
840 if (mgaVerifyIload(dev_priv,
841 bus_address, iload.destOrg, iload.length)) {
842 mga_freelist_put(dev, buf);
843 return -EINVAL;
844 }
845
846 sarea_priv->dirty |= MGA_UPLOAD_CTX;
847
848 mga_dma_dispatch_tex_blit(dev, bus_address, iload.length,
849 iload.destOrg);
850 AGEBUF(dev_priv, buf_priv);
851 buf_priv->discard = 1;
852 mga_freelist_put(dev, buf);
853 mga_flush_write_combine();
854 mga_dma_schedule(dev, 1);
855 return 0;
856 }
857
mga_vertex(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)858 int mga_vertex(struct inode *inode, struct file *filp,
859 unsigned int cmd, unsigned long arg)
860 {
861 drm_file_t *priv = filp->private_data;
862 drm_device_t *dev = priv->dev;
863 drm_mga_private_t *dev_priv =
864 (drm_mga_private_t *) dev->dev_private;
865 drm_device_dma_t *dma = dev->dma;
866 drm_buf_t *buf;
867 drm_mga_buf_priv_t *buf_priv;
868 drm_mga_vertex_t vertex;
869
870 if (copy_from_user(&vertex, (drm_mga_vertex_t *) arg, sizeof(vertex)))
871 return -EFAULT;
872
873 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
874 DRM_ERROR("mga_vertex called without lock held\n");
875 return -EINVAL;
876 }
877
878 if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
879
880 buf = dma->buflist[vertex.idx];
881 buf_priv = buf->dev_private;
882
883 buf->used = vertex.used;
884 buf_priv->discard = vertex.discard;
885
886 if (!mgaVerifyState(dev_priv)) {
887 if (vertex.discard) {
888 if (buf_priv->dispatched == 1)
889 AGEBUF(dev_priv, buf_priv);
890 buf_priv->dispatched = 0;
891 mga_freelist_put(dev, buf);
892 }
893 return -EINVAL;
894 }
895
896 mga_dma_dispatch_vertex(dev, buf);
897
898 PRIMUPDATE(dev_priv);
899 mga_flush_write_combine();
900 mga_dma_schedule(dev, 1);
901 return 0;
902 }
903
904
mga_indices(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)905 int mga_indices(struct inode *inode, struct file *filp,
906 unsigned int cmd, unsigned long arg)
907 {
908 drm_file_t *priv = filp->private_data;
909 drm_device_t *dev = priv->dev;
910 drm_mga_private_t *dev_priv =
911 (drm_mga_private_t *) dev->dev_private;
912 drm_device_dma_t *dma = dev->dma;
913 drm_buf_t *buf;
914 drm_mga_buf_priv_t *buf_priv;
915 drm_mga_indices_t indices;
916
917 if (copy_from_user(&indices,
918 (drm_mga_indices_t *)arg, sizeof(indices)))
919 return -EFAULT;
920
921 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
922 DRM_ERROR("mga_indices called without lock held\n");
923 return -EINVAL;
924 }
925
926 if(indices.idx < 0 || indices.idx > dma->buf_count) return -EINVAL;
927 buf = dma->buflist[indices.idx];
928 buf_priv = buf->dev_private;
929
930 buf_priv->discard = indices.discard;
931
932 if (!mgaVerifyState(dev_priv)) {
933 if (indices.discard) {
934 if (buf_priv->dispatched == 1)
935 AGEBUF(dev_priv, buf_priv);
936 buf_priv->dispatched = 0;
937 mga_freelist_put(dev, buf);
938 }
939 return -EINVAL;
940 }
941
942 mga_dma_dispatch_indices(dev, buf, indices.start, indices.end);
943
944 PRIMUPDATE(dev_priv);
945 mga_flush_write_combine();
946 mga_dma_schedule(dev, 1);
947 return 0;
948 }
949
950
951
mga_dma_get_buffers(drm_device_t * dev,drm_dma_t * d)952 static int mga_dma_get_buffers(drm_device_t * dev, drm_dma_t * d)
953 {
954 int i;
955 drm_buf_t *buf;
956
957 for (i = d->granted_count; i < d->request_count; i++) {
958 buf = mga_freelist_get(dev);
959 if (!buf)
960 break;
961 buf->pid = current->pid;
962 if (copy_to_user(&d->request_indices[i],
963 &buf->idx, sizeof(buf->idx)))
964 return -EFAULT;
965 if (copy_to_user(&d->request_sizes[i],
966 &buf->total, sizeof(buf->total)))
967 return -EFAULT;
968 ++d->granted_count;
969 }
970 return 0;
971 }
972
mga_dma(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)973 int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd,
974 unsigned long arg)
975 {
976 drm_file_t *priv = filp->private_data;
977 drm_device_t *dev = priv->dev;
978 drm_device_dma_t *dma = dev->dma;
979 int retcode = 0;
980 drm_dma_t d;
981
982 if (copy_from_user(&d, (drm_dma_t *) arg, sizeof(d)))
983 return -EFAULT;
984
985 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
986 DRM_ERROR("mga_dma called without lock held\n");
987 return -EINVAL;
988 }
989
990 /* Please don't send us buffers.
991 */
992 if (d.send_count != 0) {
993 DRM_ERROR
994 ("Process %d trying to send %d buffers via drmDMA\n",
995 current->pid, d.send_count);
996 return -EINVAL;
997 }
998
999 /* We'll send you buffers.
1000 */
1001 if (d.request_count < 0 || d.request_count > dma->buf_count) {
1002 DRM_ERROR
1003 ("Process %d trying to get %d buffers (of %d max)\n",
1004 current->pid, d.request_count, dma->buf_count);
1005 return -EINVAL;
1006 }
1007
1008 d.granted_count = 0;
1009
1010 if (d.request_count) {
1011 retcode = mga_dma_get_buffers(dev, &d);
1012 }
1013
1014 if (copy_to_user((drm_dma_t *) arg, &d, sizeof(d)))
1015 return -EFAULT;
1016 return retcode;
1017 }
1018