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 * VA LINUX SYSTEMS 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 25 * OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Authors: 28 * Jeff Hartmann <jhartmann@valinux.com> 29 * Keith Whitwell <keith@tungstengraphics.com> 30 * 31 * Rewritten by: 32 * Gareth Hughes <gareth@valinux.com> 33 */ 34 35#include "drmP.h" 36#include "drm.h" 37#include "mga_drm.h" 38#include "mga_drv.h" 39 40/* ================================================================ 41 * DMA hardware state programming functions 42 */ 43 44static void mga_emit_clip_rect(drm_mga_private_t * dev_priv, 45 drm_clip_rect_t * box) 46{ 47 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 48 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 49 unsigned int pitch = dev_priv->front_pitch; 50 DMA_LOCALS; 51 52 BEGIN_DMA(2); 53 54 /* Force reset of DWGCTL on G400 (eliminates clip disable bit). 55 */ 56 if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { 57 DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl, 58 MGA_LEN + MGA_EXEC, 0x80000000, 59 MGA_DWGCTL, ctx->dwgctl, 60 MGA_LEN + MGA_EXEC, 0x80000000); 61 } 62 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 63 MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1, 64 MGA_YTOP, box->y1 * pitch, MGA_YBOT, (box->y2 - 1) * pitch); 65 66 ADVANCE_DMA(); 67} 68 69static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv) 70{ 71 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 72 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 73 DMA_LOCALS; 74 75 BEGIN_DMA(3); 76 77 DMA_BLOCK(MGA_DSTORG, ctx->dstorg, 78 MGA_MACCESS, ctx->maccess, 79 MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl); 80 81 DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl, 82 MGA_FOGCOL, ctx->fogcolor, 83 MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset); 84 85 DMA_BLOCK(MGA_FCOL, ctx->fcol, 86 MGA_DMAPAD, 0x00000000, 87 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 88 89 ADVANCE_DMA(); 90} 91 92static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv) 93{ 94 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 95 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 96 DMA_LOCALS; 97 98 BEGIN_DMA(4); 99 100 DMA_BLOCK(MGA_DSTORG, ctx->dstorg, 101 MGA_MACCESS, ctx->maccess, 102 MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl); 103 104 DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl, 105 MGA_FOGCOL, ctx->fogcolor, 106 MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset); 107 108 DMA_BLOCK(MGA_WFLAG1, ctx->wflag, 109 MGA_TDUALSTAGE0, ctx->tdualstage0, 110 MGA_TDUALSTAGE1, ctx->tdualstage1, MGA_FCOL, ctx->fcol); 111 112 DMA_BLOCK(MGA_STENCIL, ctx->stencil, 113 MGA_STENCILCTL, ctx->stencilctl, 114 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 115 116 ADVANCE_DMA(); 117} 118 119static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv) 120{ 121 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 122 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; 123 DMA_LOCALS; 124 125 BEGIN_DMA(4); 126 127 DMA_BLOCK(MGA_TEXCTL2, tex->texctl2, 128 MGA_TEXCTL, tex->texctl, 129 MGA_TEXFILTER, tex->texfilter, 130 MGA_TEXBORDERCOL, tex->texbordercol); 131 132 DMA_BLOCK(MGA_TEXORG, tex->texorg, 133 MGA_TEXORG1, tex->texorg1, 134 MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3); 135 136 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 137 MGA_TEXWIDTH, tex->texwidth, 138 MGA_TEXHEIGHT, tex->texheight, MGA_WR24, tex->texwidth); 139 140 DMA_BLOCK(MGA_WR34, tex->texheight, 141 MGA_TEXTRANS, 0x0000ffff, 142 MGA_TEXTRANSHIGH, 0x0000ffff, MGA_DMAPAD, 0x00000000); 143 144 ADVANCE_DMA(); 145} 146 147static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv) 148{ 149 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 150 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; 151 DMA_LOCALS; 152 153/* printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */ 154/* tex->texctl, tex->texctl2); */ 155 156 BEGIN_DMA(6); 157 158 DMA_BLOCK(MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC, 159 MGA_TEXCTL, tex->texctl, 160 MGA_TEXFILTER, tex->texfilter, 161 MGA_TEXBORDERCOL, tex->texbordercol); 162 163 DMA_BLOCK(MGA_TEXORG, tex->texorg, 164 MGA_TEXORG1, tex->texorg1, 165 MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3); 166 167 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 168 MGA_TEXWIDTH, tex->texwidth, 169 MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000); 170 171 DMA_BLOCK(MGA_WR57, 0x00000000, 172 MGA_WR53, 0x00000000, 173 MGA_WR61, 0x00000000, MGA_WR52, MGA_G400_WR_MAGIC); 174 175 DMA_BLOCK(MGA_WR60, MGA_G400_WR_MAGIC, 176 MGA_WR54, tex->texwidth | MGA_G400_WR_MAGIC, 177 MGA_WR62, tex->texheight | MGA_G400_WR_MAGIC, 178 MGA_DMAPAD, 0x00000000); 179 180 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 181 MGA_DMAPAD, 0x00000000, 182 MGA_TEXTRANS, 0x0000ffff, MGA_TEXTRANSHIGH, 0x0000ffff); 183 184 ADVANCE_DMA(); 185} 186 187static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv) 188{ 189 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 190 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1]; 191 DMA_LOCALS; 192 193/* printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg, */ 194/* tex->texctl, tex->texctl2); */ 195 196 BEGIN_DMA(5); 197 198 DMA_BLOCK(MGA_TEXCTL2, (tex->texctl2 | 199 MGA_MAP1_ENABLE | 200 MGA_G400_TC2_MAGIC), 201 MGA_TEXCTL, tex->texctl, 202 MGA_TEXFILTER, tex->texfilter, 203 MGA_TEXBORDERCOL, tex->texbordercol); 204 205 DMA_BLOCK(MGA_TEXORG, tex->texorg, 206 MGA_TEXORG1, tex->texorg1, 207 MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3); 208 209 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 210 MGA_TEXWIDTH, tex->texwidth, 211 MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000); 212 213 DMA_BLOCK(MGA_WR57, 0x00000000, 214 MGA_WR53, 0x00000000, 215 MGA_WR61, 0x00000000, 216 MGA_WR52, tex->texwidth | MGA_G400_WR_MAGIC); 217 218 DMA_BLOCK(MGA_WR60, tex->texheight | MGA_G400_WR_MAGIC, 219 MGA_TEXTRANS, 0x0000ffff, 220 MGA_TEXTRANSHIGH, 0x0000ffff, 221 MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC); 222 223 ADVANCE_DMA(); 224} 225 226static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv) 227{ 228 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 229 unsigned int pipe = sarea_priv->warp_pipe; 230 DMA_LOCALS; 231 232 BEGIN_DMA(3); 233 234 DMA_BLOCK(MGA_WIADDR, MGA_WMODE_SUSPEND, 235 MGA_WVRTXSZ, 0x00000007, 236 MGA_WFLAG, 0x00000000, MGA_WR24, 0x00000000); 237 238 DMA_BLOCK(MGA_WR25, 0x00000100, 239 MGA_WR34, 0x00000000, 240 MGA_WR42, 0x0000ffff, MGA_WR60, 0x0000ffff); 241 242 /* Padding required to to hardware bug. 243 */ 244 DMA_BLOCK(MGA_DMAPAD, 0xffffffff, 245 MGA_DMAPAD, 0xffffffff, 246 MGA_DMAPAD, 0xffffffff, 247 MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | 248 MGA_WMODE_START | dev_priv->wagp_enable)); 249 250 ADVANCE_DMA(); 251} 252 253static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv) 254{ 255 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 256 unsigned int pipe = sarea_priv->warp_pipe; 257 DMA_LOCALS; 258 259/* printk("mga_g400_emit_pipe %x\n", pipe); */ 260 261 BEGIN_DMA(10); 262 263 DMA_BLOCK(MGA_WIADDR2, MGA_WMODE_SUSPEND, 264 MGA_DMAPAD, 0x00000000, 265 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 266 267 if (pipe & MGA_T2) { 268 DMA_BLOCK(MGA_WVRTXSZ, 0x00001e09, 269 MGA_DMAPAD, 0x00000000, 270 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 271 272 DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000, 273 MGA_WACCEPTSEQ, 0x00000000, 274 MGA_WACCEPTSEQ, 0x00000000, 275 MGA_WACCEPTSEQ, 0x1e000000); 276 } else { 277 if (dev_priv->warp_pipe & MGA_T2) { 278 /* Flush the WARP pipe */ 279 DMA_BLOCK(MGA_YDST, 0x00000000, 280 MGA_FXLEFT, 0x00000000, 281 MGA_FXRIGHT, 0x00000001, 282 MGA_DWGCTL, MGA_DWGCTL_FLUSH); 283 284 DMA_BLOCK(MGA_LEN + MGA_EXEC, 0x00000001, 285 MGA_DWGSYNC, 0x00007000, 286 MGA_TEXCTL2, MGA_G400_TC2_MAGIC, 287 MGA_LEN + MGA_EXEC, 0x00000000); 288 289 DMA_BLOCK(MGA_TEXCTL2, (MGA_DUALTEX | 290 MGA_G400_TC2_MAGIC), 291 MGA_LEN + MGA_EXEC, 0x00000000, 292 MGA_TEXCTL2, MGA_G400_TC2_MAGIC, 293 MGA_DMAPAD, 0x00000000); 294 } 295 296 DMA_BLOCK(MGA_WVRTXSZ, 0x00001807, 297 MGA_DMAPAD, 0x00000000, 298 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 299 300 DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000, 301 MGA_WACCEPTSEQ, 0x00000000, 302 MGA_WACCEPTSEQ, 0x00000000, 303 MGA_WACCEPTSEQ, 0x18000000); 304 } 305 306 DMA_BLOCK(MGA_WFLAG, 0x00000000, 307 MGA_WFLAG1, 0x00000000, 308 MGA_WR56, MGA_G400_WR56_MAGIC, MGA_DMAPAD, 0x00000000); 309 310 DMA_BLOCK(MGA_WR49, 0x00000000, /* tex0 */ 311 MGA_WR57, 0x00000000, /* tex0 */ 312 MGA_WR53, 0x00000000, /* tex1 */ 313 MGA_WR61, 0x00000000); /* tex1 */ 314 315 DMA_BLOCK(MGA_WR54, MGA_G400_WR_MAGIC, /* tex0 width */ 316 MGA_WR62, MGA_G400_WR_MAGIC, /* tex0 height */ 317 MGA_WR52, MGA_G400_WR_MAGIC, /* tex1 width */ 318 MGA_WR60, MGA_G400_WR_MAGIC); /* tex1 height */ 319 320 /* Padding required to to hardware bug */ 321 DMA_BLOCK(MGA_DMAPAD, 0xffffffff, 322 MGA_DMAPAD, 0xffffffff, 323 MGA_DMAPAD, 0xffffffff, 324 MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | 325 MGA_WMODE_START | dev_priv->wagp_enable)); 326 327 ADVANCE_DMA(); 328} 329 330static void mga_g200_emit_state(drm_mga_private_t * dev_priv) 331{ 332 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 333 unsigned int dirty = sarea_priv->dirty; 334 335 if (sarea_priv->warp_pipe != dev_priv->warp_pipe) { 336 mga_g200_emit_pipe(dev_priv); 337 dev_priv->warp_pipe = sarea_priv->warp_pipe; 338 } 339 340 if (dirty & MGA_UPLOAD_CONTEXT) { 341 mga_g200_emit_context(dev_priv); 342 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT; 343 } 344 345 if (dirty & MGA_UPLOAD_TEX0) { 346 mga_g200_emit_tex0(dev_priv); 347 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; 348 } 349} 350 351static void mga_g400_emit_state(drm_mga_private_t * dev_priv) 352{ 353 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 354 unsigned int dirty = sarea_priv->dirty; 355 int multitex = sarea_priv->warp_pipe & MGA_T2; 356 357 if (sarea_priv->warp_pipe != dev_priv->warp_pipe) { 358 mga_g400_emit_pipe(dev_priv); 359 dev_priv->warp_pipe = sarea_priv->warp_pipe; 360 } 361 362 if (dirty & MGA_UPLOAD_CONTEXT) { 363 mga_g400_emit_context(dev_priv); 364 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT; 365 } 366 367 if (dirty & MGA_UPLOAD_TEX0) { 368 mga_g400_emit_tex0(dev_priv); 369 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; 370 } 371 372 if ((dirty & MGA_UPLOAD_TEX1) && multitex) { 373 mga_g400_emit_tex1(dev_priv); 374 sarea_priv->dirty &= ~MGA_UPLOAD_TEX1; 375 } 376} 377 378/* ================================================================ 379 * SAREA state verification 380 */ 381 382/* Disallow all write destinations except the front and backbuffer. 383 */ 384static int mga_verify_context(drm_mga_private_t * dev_priv) 385{ 386 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 387 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 388 389 if (ctx->dstorg != dev_priv->front_offset && 390 ctx->dstorg != dev_priv->back_offset) { 391 DRM_ERROR("*** bad DSTORG: %x (front %x, back %x)\n\n", 392 ctx->dstorg, dev_priv->front_offset, 393 dev_priv->back_offset); 394 ctx->dstorg = 0; 395 return DRM_ERR(EINVAL); 396 } 397 398 return 0; 399} 400 401/* Disallow texture reads from PCI space. 402 */ 403static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit) 404{ 405 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 406 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit]; 407 unsigned int org; 408 409 org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK); 410 411 if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) { 412 DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit); 413 tex->texorg = 0; 414 return DRM_ERR(EINVAL); 415 } 416 417 return 0; 418} 419 420static int mga_verify_state(drm_mga_private_t * dev_priv) 421{ 422 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 423 unsigned int dirty = sarea_priv->dirty; 424 int ret = 0; 425 426 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 427 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 428 429 if (dirty & MGA_UPLOAD_CONTEXT) 430 ret |= mga_verify_context(dev_priv); 431 432 if (dirty & MGA_UPLOAD_TEX0) 433 ret |= mga_verify_tex(dev_priv, 0); 434 435 if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { 436 if (dirty & MGA_UPLOAD_TEX1) 437 ret |= mga_verify_tex(dev_priv, 1); 438 439 if (dirty & MGA_UPLOAD_PIPE) 440 ret |= (sarea_priv->warp_pipe > MGA_MAX_G400_PIPES); 441 } else { 442 if (dirty & MGA_UPLOAD_PIPE) 443 ret |= (sarea_priv->warp_pipe > MGA_MAX_G200_PIPES); 444 } 445 446 return (ret == 0); 447} 448 449static int mga_verify_iload(drm_mga_private_t * dev_priv, 450 unsigned int dstorg, unsigned int length) 451{ 452 if (dstorg < dev_priv->texture_offset || 453 dstorg + length > (dev_priv->texture_offset + 454 dev_priv->texture_size)) { 455 DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg); 456 return DRM_ERR(EINVAL); 457 } 458 459 if (length & MGA_ILOAD_MASK) { 460 DRM_ERROR("*** bad iload length: 0x%x\n", 461 length & MGA_ILOAD_MASK); 462 return DRM_ERR(EINVAL); 463 } 464 465 return 0; 466} 467 468static int mga_verify_blit(drm_mga_private_t * dev_priv, 469 unsigned int srcorg, unsigned int dstorg) 470{ 471 if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) || 472 (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) { 473 DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg); 474 return DRM_ERR(EINVAL); 475 } 476 return 0; 477} 478 479/* ================================================================ 480 * 481 */ 482 483static void mga_dma_dispatch_clear(drm_device_t * dev, drm_mga_clear_t * clear) 484{ 485 drm_mga_private_t *dev_priv = dev->dev_private; 486 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 487 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 488 drm_clip_rect_t *pbox = sarea_priv->boxes; 489 int nbox = sarea_priv->nbox; 490 int i; 491 DMA_LOCALS; 492 DRM_DEBUG("\n"); 493 494 BEGIN_DMA(1); 495 496 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 497 MGA_DMAPAD, 0x00000000, 498 MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000); 499 500 ADVANCE_DMA(); 501 502 for (i = 0; i < nbox; i++) { 503 drm_clip_rect_t *box = &pbox[i]; 504 u32 height = box->y2 - box->y1; 505 506 DRM_DEBUG(" from=%d,%d to=%d,%d\n", 507 box->x1, box->y1, box->x2, box->y2); 508 509 if (clear->flags & MGA_FRONT) { 510 BEGIN_DMA(2); 511 512 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 513 MGA_PLNWT, clear->color_mask, 514 MGA_YDSTLEN, (box->y1 << 16) | height, 515 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 516 517 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 518 MGA_FCOL, clear->clear_color, 519 MGA_DSTORG, dev_priv->front_offset, 520 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 521 522 ADVANCE_DMA(); 523 } 524 525 if (clear->flags & MGA_BACK) { 526 BEGIN_DMA(2); 527 528 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 529 MGA_PLNWT, clear->color_mask, 530 MGA_YDSTLEN, (box->y1 << 16) | height, 531 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 532 533 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 534 MGA_FCOL, clear->clear_color, 535 MGA_DSTORG, dev_priv->back_offset, 536 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 537 538 ADVANCE_DMA(); 539 } 540 541 if (clear->flags & MGA_DEPTH) { 542 BEGIN_DMA(2); 543 544 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 545 MGA_PLNWT, clear->depth_mask, 546 MGA_YDSTLEN, (box->y1 << 16) | height, 547 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 548 549 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 550 MGA_FCOL, clear->clear_depth, 551 MGA_DSTORG, dev_priv->depth_offset, 552 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 553 554 ADVANCE_DMA(); 555 } 556 557 } 558 559 BEGIN_DMA(1); 560 561 /* Force reset of DWGCTL */ 562 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 563 MGA_DMAPAD, 0x00000000, 564 MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl); 565 566 ADVANCE_DMA(); 567 568 FLUSH_DMA(); 569} 570 571static void mga_dma_dispatch_swap(drm_device_t * dev) 572{ 573 drm_mga_private_t *dev_priv = dev->dev_private; 574 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 575 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 576 drm_clip_rect_t *pbox = sarea_priv->boxes; 577 int nbox = sarea_priv->nbox; 578 int i; 579 DMA_LOCALS; 580 DRM_DEBUG("\n"); 581 582 sarea_priv->last_frame.head = dev_priv->prim.tail; 583 sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap; 584 585 BEGIN_DMA(4 + nbox); 586 587 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 588 MGA_DMAPAD, 0x00000000, 589 MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000); 590 591 DMA_BLOCK(MGA_DSTORG, dev_priv->front_offset, 592 MGA_MACCESS, dev_priv->maccess, 593 MGA_SRCORG, dev_priv->back_offset, 594 MGA_AR5, dev_priv->front_pitch); 595 596 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 597 MGA_DMAPAD, 0x00000000, 598 MGA_PLNWT, 0xffffffff, MGA_DWGCTL, MGA_DWGCTL_COPY); 599 600 for (i = 0; i < nbox; i++) { 601 drm_clip_rect_t *box = &pbox[i]; 602 u32 height = box->y2 - box->y1; 603 u32 start = box->y1 * dev_priv->front_pitch; 604 605 DRM_DEBUG(" from=%d,%d to=%d,%d\n", 606 box->x1, box->y1, box->x2, box->y2); 607 608 DMA_BLOCK(MGA_AR0, start + box->x2 - 1, 609 MGA_AR3, start + box->x1, 610 MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1, 611 MGA_YDSTLEN + MGA_EXEC, (box->y1 << 16) | height); 612 } 613 614 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 615 MGA_PLNWT, ctx->plnwt, 616 MGA_SRCORG, dev_priv->front_offset, MGA_DWGCTL, ctx->dwgctl); 617 618 ADVANCE_DMA(); 619 620 FLUSH_DMA(); 621 622 DRM_DEBUG("%s... done.\n", __FUNCTION__); 623} 624 625static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf) 626{ 627 drm_mga_private_t *dev_priv = dev->dev_private; 628 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 629 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 630 u32 address = (u32) buf->bus_address; 631 u32 length = (u32) buf->used; 632 int i = 0; 633 DMA_LOCALS; 634 DRM_DEBUG("vertex: buf=%d used=%d\n", buf->idx, buf->used); 635 636 if (buf->used) { 637 buf_priv->dispatched = 1; 638 639 MGA_EMIT_STATE(dev_priv, sarea_priv->dirty); 640 641 do { 642 if (i < sarea_priv->nbox) { 643 mga_emit_clip_rect(dev_priv, 644 &sarea_priv->boxes[i]); 645 } 646 647 BEGIN_DMA(1); 648 649 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 650 MGA_DMAPAD, 0x00000000, 651 MGA_SECADDRESS, (address | 652 MGA_DMA_VERTEX), 653 MGA_SECEND, ((address + length) | 654 dev_priv->dma_access)); 655 656 ADVANCE_DMA(); 657 } while (++i < sarea_priv->nbox); 658 } 659 660 if (buf_priv->discard) { 661 AGE_BUFFER(buf_priv); 662 buf->pending = 0; 663 buf->used = 0; 664 buf_priv->dispatched = 0; 665 666 mga_freelist_put(dev, buf); 667 } 668 669 FLUSH_DMA(); 670} 671 672static void mga_dma_dispatch_indices(drm_device_t * dev, drm_buf_t * buf, 673 unsigned int start, unsigned int end) 674{ 675 drm_mga_private_t *dev_priv = dev->dev_private; 676 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 677 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 678 u32 address = (u32) buf->bus_address; 679 int i = 0; 680 DMA_LOCALS; 681 DRM_DEBUG("indices: buf=%d start=%d end=%d\n", buf->idx, start, end); 682 683 if (start != end) { 684 buf_priv->dispatched = 1; 685 686 MGA_EMIT_STATE(dev_priv, sarea_priv->dirty); 687 688 do { 689 if (i < sarea_priv->nbox) { 690 mga_emit_clip_rect(dev_priv, 691 &sarea_priv->boxes[i]); 692 } 693 694 BEGIN_DMA(1); 695 696 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 697 MGA_DMAPAD, 0x00000000, 698 MGA_SETUPADDRESS, address + start, 699 MGA_SETUPEND, ((address + end) | 700 dev_priv->dma_access)); 701 702 ADVANCE_DMA(); 703 } while (++i < sarea_priv->nbox); 704 } 705 706 if (buf_priv->discard) { 707 AGE_BUFFER(buf_priv); 708 buf->pending = 0; 709 buf->used = 0; 710 buf_priv->dispatched = 0; 711 712 mga_freelist_put(dev, buf); 713 } 714 715 FLUSH_DMA(); 716} 717 718/* This copies a 64 byte aligned agp region to the frambuffer with a 719 * standard blit, the ioctl needs to do checking. 720 */ 721static void mga_dma_dispatch_iload(drm_device_t * dev, drm_buf_t * buf, 722 unsigned int dstorg, unsigned int length) 723{ 724 drm_mga_private_t *dev_priv = dev->dev_private; 725 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 726 drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; 727 u32 srcorg = 728 buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM; 729 u32 y2; 730 DMA_LOCALS; 731 DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used); 732 733 y2 = length / 64; 734 735 BEGIN_DMA(5); 736 737 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 738 MGA_DMAPAD, 0x00000000, 739 MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000); 740 741 DMA_BLOCK(MGA_DSTORG, dstorg, 742 MGA_MACCESS, 0x00000000, MGA_SRCORG, srcorg, MGA_AR5, 64); 743 744 DMA_BLOCK(MGA_PITCH, 64, 745 MGA_PLNWT, 0xffffffff, 746 MGA_DMAPAD, 0x00000000, MGA_DWGCTL, MGA_DWGCTL_COPY); 747 748 DMA_BLOCK(MGA_AR0, 63, 749 MGA_AR3, 0, 750 MGA_FXBNDRY, (63 << 16) | 0, MGA_YDSTLEN + MGA_EXEC, y2); 751 752 DMA_BLOCK(MGA_PLNWT, ctx->plnwt, 753 MGA_SRCORG, dev_priv->front_offset, 754 MGA_PITCH, dev_priv->front_pitch, MGA_DWGSYNC, 0x00007000); 755 756 ADVANCE_DMA(); 757 758 AGE_BUFFER(buf_priv); 759 760 buf->pending = 0; 761 buf->used = 0; 762 buf_priv->dispatched = 0; 763 764 mga_freelist_put(dev, buf); 765 766 FLUSH_DMA(); 767} 768 769static void mga_dma_dispatch_blit(drm_device_t * dev, drm_mga_blit_t * blit) 770{ 771 drm_mga_private_t *dev_priv = dev->dev_private; 772 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 773 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 774 drm_clip_rect_t *pbox = sarea_priv->boxes; 775 int nbox = sarea_priv->nbox; 776 u32 scandir = 0, i; 777 DMA_LOCALS; 778 DRM_DEBUG("\n"); 779 780 BEGIN_DMA(4 + nbox); 781 782 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 783 MGA_DMAPAD, 0x00000000, 784 MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000); 785 786 DMA_BLOCK(MGA_DWGCTL, MGA_DWGCTL_COPY, 787 MGA_PLNWT, blit->planemask, 788 MGA_SRCORG, blit->srcorg, MGA_DSTORG, blit->dstorg); 789 790 DMA_BLOCK(MGA_SGN, scandir, 791 MGA_MACCESS, dev_priv->maccess, 792 MGA_AR5, blit->ydir * blit->src_pitch, 793 MGA_PITCH, blit->dst_pitch); 794 795 for (i = 0; i < nbox; i++) { 796 int srcx = pbox[i].x1 + blit->delta_sx; 797 int srcy = pbox[i].y1 + blit->delta_sy; 798 int dstx = pbox[i].x1 + blit->delta_dx; 799 int dsty = pbox[i].y1 + blit->delta_dy; 800 int h = pbox[i].y2 - pbox[i].y1; 801 int w = pbox[i].x2 - pbox[i].x1 - 1; 802 int start; 803 804 if (blit->ydir == -1) { 805 srcy = blit->height - srcy - 1; 806 } 807 808 start = srcy * blit->src_pitch + srcx; 809 810 DMA_BLOCK(MGA_AR0, start + w, 811 MGA_AR3, start, 812 MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff), 813 MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h); 814 } 815 816 /* Do something to flush AGP? 817 */ 818 819 /* Force reset of DWGCTL */ 820 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 821 MGA_PLNWT, ctx->plnwt, 822 MGA_PITCH, dev_priv->front_pitch, MGA_DWGCTL, ctx->dwgctl); 823 824 ADVANCE_DMA(); 825} 826 827/* ================================================================ 828 * 829 */ 830 831static int mga_dma_clear(DRM_IOCTL_ARGS) 832{ 833 DRM_DEVICE; 834 drm_mga_private_t *dev_priv = dev->dev_private; 835 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 836 drm_mga_clear_t clear; 837 838 LOCK_TEST_WITH_RETURN(dev, filp); 839 840 DRM_COPY_FROM_USER_IOCTL(clear, (drm_mga_clear_t __user *) data, 841 sizeof(clear)); 842 843 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 844 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 845 846 WRAP_TEST_WITH_RETURN(dev_priv); 847 848 mga_dma_dispatch_clear(dev, &clear); 849 850 /* Make sure we restore the 3D state next time. 851 */ 852 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 853 854 return 0; 855} 856 857static int mga_dma_swap(DRM_IOCTL_ARGS) 858{ 859 DRM_DEVICE; 860 drm_mga_private_t *dev_priv = dev->dev_private; 861 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 862 863 LOCK_TEST_WITH_RETURN(dev, filp); 864 865 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 866 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 867 868 WRAP_TEST_WITH_RETURN(dev_priv); 869 870 mga_dma_dispatch_swap(dev); 871 872 /* Make sure we restore the 3D state next time. 873 */ 874 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 875 876 return 0; 877} 878 879static int mga_dma_vertex(DRM_IOCTL_ARGS) 880{ 881 DRM_DEVICE; 882 drm_mga_private_t *dev_priv = dev->dev_private; 883 drm_device_dma_t *dma = dev->dma; 884 drm_buf_t *buf; 885 drm_mga_buf_priv_t *buf_priv; 886 drm_mga_vertex_t vertex; 887 888 LOCK_TEST_WITH_RETURN(dev, filp); 889 890 DRM_COPY_FROM_USER_IOCTL(vertex, 891 (drm_mga_vertex_t __user *) data, 892 sizeof(vertex)); 893 894 if (vertex.idx < 0 || vertex.idx > dma->buf_count) 895 return DRM_ERR(EINVAL); 896 buf = dma->buflist[vertex.idx]; 897 buf_priv = buf->dev_private; 898 899 buf->used = vertex.used; 900 buf_priv->discard = vertex.discard; 901 902 if (!mga_verify_state(dev_priv)) { 903 if (vertex.discard) { 904 if (buf_priv->dispatched == 1) 905 AGE_BUFFER(buf_priv); 906 buf_priv->dispatched = 0; 907 mga_freelist_put(dev, buf); 908 } 909 return DRM_ERR(EINVAL); 910 } 911 912 WRAP_TEST_WITH_RETURN(dev_priv); 913 914 mga_dma_dispatch_vertex(dev, buf); 915 916 return 0; 917} 918 919static int mga_dma_indices(DRM_IOCTL_ARGS) 920{ 921 DRM_DEVICE; 922 drm_mga_private_t *dev_priv = dev->dev_private; 923 drm_device_dma_t *dma = dev->dma; 924 drm_buf_t *buf; 925 drm_mga_buf_priv_t *buf_priv; 926 drm_mga_indices_t indices; 927 928 LOCK_TEST_WITH_RETURN(dev, filp); 929 930 DRM_COPY_FROM_USER_IOCTL(indices, 931 (drm_mga_indices_t __user *) data, 932 sizeof(indices)); 933 934 if (indices.idx < 0 || indices.idx > dma->buf_count) 935 return DRM_ERR(EINVAL); 936 937 buf = dma->buflist[indices.idx]; 938 buf_priv = buf->dev_private; 939 940 buf_priv->discard = indices.discard; 941 942 if (!mga_verify_state(dev_priv)) { 943 if (indices.discard) { 944 if (buf_priv->dispatched == 1) 945 AGE_BUFFER(buf_priv); 946 buf_priv->dispatched = 0; 947 mga_freelist_put(dev, buf); 948 } 949 return DRM_ERR(EINVAL); 950 } 951 952 WRAP_TEST_WITH_RETURN(dev_priv); 953 954 mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); 955 956 return 0; 957} 958 959static int mga_dma_iload(DRM_IOCTL_ARGS) 960{ 961 DRM_DEVICE; 962 drm_device_dma_t *dma = dev->dma; 963 drm_mga_private_t *dev_priv = dev->dev_private; 964 drm_buf_t *buf; 965 drm_mga_buf_priv_t *buf_priv; 966 drm_mga_iload_t iload; 967 DRM_DEBUG("\n"); 968 969 LOCK_TEST_WITH_RETURN(dev, filp); 970 971 DRM_COPY_FROM_USER_IOCTL(iload, (drm_mga_iload_t __user *) data, 972 sizeof(iload)); 973 974 if (iload.idx < 0 || iload.idx > dma->buf_count) 975 return DRM_ERR(EINVAL); 976 977 buf = dma->buflist[iload.idx]; 978 buf_priv = buf->dev_private; 979 980 if (mga_verify_iload(dev_priv, iload.dstorg, iload.length)) { 981 mga_freelist_put(dev, buf); 982 return DRM_ERR(EINVAL); 983 } 984 985 WRAP_TEST_WITH_RETURN(dev_priv); 986 987 mga_dma_dispatch_iload(dev, buf, iload.dstorg, iload.length); 988 989 /* Make sure we restore the 3D state next time. 990 */ 991 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 992 993 return 0; 994} 995 996static int mga_dma_blit(DRM_IOCTL_ARGS) 997{ 998 DRM_DEVICE; 999 drm_mga_private_t *dev_priv = dev->dev_private; 1000 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 1001 drm_mga_blit_t blit; 1002 DRM_DEBUG("\n"); 1003 1004 LOCK_TEST_WITH_RETURN(dev, filp); 1005 1006 DRM_COPY_FROM_USER_IOCTL(blit, (drm_mga_blit_t __user *) data, 1007 sizeof(blit)); 1008 1009 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 1010 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 1011 1012 if (mga_verify_blit(dev_priv, blit.srcorg, blit.dstorg)) 1013 return DRM_ERR(EINVAL); 1014 1015 WRAP_TEST_WITH_RETURN(dev_priv); 1016 1017 mga_dma_dispatch_blit(dev, &blit); 1018 1019 /* Make sure we restore the 3D state next time. 1020 */ 1021 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 1022 1023 return 0; 1024} 1025 1026static int mga_getparam(DRM_IOCTL_ARGS) 1027{ 1028 DRM_DEVICE; 1029 drm_mga_private_t *dev_priv = dev->dev_private; 1030 drm_mga_getparam_t param; 1031 int value; 1032 1033 if (!dev_priv) { 1034 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 1035 return DRM_ERR(EINVAL); 1036 } 1037 1038 DRM_COPY_FROM_USER_IOCTL(param, (drm_mga_getparam_t __user *) data, 1039 sizeof(param)); 1040 1041 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1042 1043 switch (param.param) { 1044 case MGA_PARAM_IRQ_NR: 1045 value = dev->irq; 1046 break; 1047 case MGA_PARAM_CARD_TYPE: 1048 value = dev_priv->chipset; 1049 break; 1050 default: 1051 return DRM_ERR(EINVAL); 1052 } 1053 1054 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { 1055 DRM_ERROR("copy_to_user\n"); 1056 return DRM_ERR(EFAULT); 1057 } 1058 1059 return 0; 1060} 1061 1062static int mga_set_fence(DRM_IOCTL_ARGS) 1063{ 1064 DRM_DEVICE; 1065 drm_mga_private_t *dev_priv = dev->dev_private; 1066 u32 temp; 1067 DMA_LOCALS; 1068 1069 if (!dev_priv) { 1070 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 1071 return DRM_ERR(EINVAL); 1072 } 1073 1074 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1075 1076 /* I would normal do this assignment in the declaration of temp, 1077 * but dev_priv may be NULL. 1078 */ 1079 1080 temp = dev_priv->next_fence_to_post; 1081 dev_priv->next_fence_to_post++; 1082 1083 BEGIN_DMA(1); 1084 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 1085 MGA_DMAPAD, 0x00000000, 1086 MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000); 1087 ADVANCE_DMA(); 1088 1089 if (DRM_COPY_TO_USER((u32 __user *) data, &temp, sizeof(u32))) { 1090 DRM_ERROR("copy_to_user\n"); 1091 return DRM_ERR(EFAULT); 1092 } 1093 1094 return 0; 1095} 1096 1097static int mga_wait_fence(DRM_IOCTL_ARGS) 1098{ 1099 DRM_DEVICE; 1100 drm_mga_private_t *dev_priv = dev->dev_private; 1101 u32 fence; 1102 1103 if (!dev_priv) { 1104 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 1105 return DRM_ERR(EINVAL); 1106 } 1107 1108 DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32)); 1109 1110 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1111 1112 mga_driver_fence_wait(dev, &fence); 1113 1114 if (DRM_COPY_TO_USER((u32 __user *) data, &fence, sizeof(u32))) { 1115 DRM_ERROR("copy_to_user\n"); 1116 return DRM_ERR(EFAULT); 1117 } 1118 1119 return 0; 1120} 1121 1122drm_ioctl_desc_t mga_ioctls[] = { 1123 [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, 1124 [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH}, 1125 [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH}, 1126 [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH}, 1127 [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH}, 1128 [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH}, 1129 [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH}, 1130 [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH}, 1131 [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH}, 1132 [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH}, 1133 [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH}, 1134 [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH}, 1135 [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, 1136}; 1137 1138int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); 1139