1 /* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*- 2 * Created: Sun Dec 03 19:20:26 2000 by gareth (at) valinux.com 3 */ 4 /* 5 * Copyright 2000 Gareth Hughes 6 * Copyright 2002-2003 Leif Delgass 7 * All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Authors: 28 * Gareth Hughes <gareth (at) valinux.com> 29 * Leif Delgass <ldelgass (at) retinalburn.net> 30 * Jos Fonseca <j_r_fonseca (at) yahoo.co.uk> 31 */ 32 33 #include "drmP.h" 34 #include "drm.h" 35 #include "mach64_drm.h" 36 #include "mach64_drv.h" 37 38 /* Interface history: 39 * 40 * 1.0 - Initial mach64 DRM 41 * 42 */ 43 struct drm_ioctl_desc mach64_ioctls[] = { 44 DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 45 DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH), 46 DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH), 47 DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH), 48 DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH), 49 DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH), 50 DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH), 51 DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH), 52 DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH), 53 }; 54 55 int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); 56 57 /* ================================================================ 58 * DMA hardware state programming functions 59 */ 60 61 static void mach64_print_dirty(const char *msg, unsigned int flags) 62 { 63 DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n", 64 msg, 65 flags, 66 (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " : 67 "", 68 (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "", 69 (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " : 70 "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "", 71 (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " : 72 "", 73 (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "", 74 (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "", 75 (flags & MACH64_UPLOAD_MISC) ? "misc, " : "", 76 (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "", 77 (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "", 78 (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "", 79 (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : ""); 80 } 81 82 /* Mach64 doesn't have hardware cliprects, just one hardware scissor, 83 * so the GL scissor is intersected with each cliprect here 84 */ 85 /* This function returns 0 on success, 1 for no intersection, and 86 * negative for an error 87 */ 88 static int mach64_emit_cliprect(struct drm_file *file_priv, 89 drm_mach64_private_t * dev_priv, 90 struct drm_clip_rect * box) 91 { 92 u32 sc_left_right, sc_top_bottom; 93 struct drm_clip_rect scissor; 94 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 95 drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 96 DMALOCALS; 97 98 DRM_DEBUG("box=%p\n", box); 99 100 /* Get GL scissor */ 101 /* FIXME: store scissor in SAREA as a cliprect instead of in 102 * hardware format, or do intersection client-side 103 */ 104 scissor.x1 = regs->sc_left_right & 0xffff; 105 scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16; 106 scissor.y1 = regs->sc_top_bottom & 0xffff; 107 scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16; 108 109 /* Intersect GL scissor with cliprect */ 110 if (box->x1 > scissor.x1) 111 scissor.x1 = box->x1; 112 if (box->y1 > scissor.y1) 113 scissor.y1 = box->y1; 114 if (box->x2 < scissor.x2) 115 scissor.x2 = box->x2; 116 if (box->y2 < scissor.y2) 117 scissor.y2 = box->y2; 118 /* positive return means skip */ 119 if (scissor.x1 >= scissor.x2) 120 return 1; 121 if (scissor.y1 >= scissor.y2) 122 return 1; 123 124 DMAGETPTR(file_priv, dev_priv, 2); /* returns on failure to get buffer */ 125 126 sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16)); 127 sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16)); 128 129 DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right); 130 DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom); 131 132 DMAADVANCE(dev_priv, 1); 133 134 return 0; 135 } 136 137 static __inline__ int mach64_emit_state(struct drm_file *file_priv, 138 drm_mach64_private_t * dev_priv) 139 { 140 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 141 drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 142 unsigned int dirty = sarea_priv->dirty; 143 u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); 144 DMALOCALS; 145 146 if (MACH64_VERBOSE) { 147 mach64_print_dirty(__FUNCTION__, dirty); 148 } else { 149 DRM_DEBUG("dirty=0x%08x\n", dirty); 150 } 151 152 DMAGETPTR(file_priv, dev_priv, 17); /* returns on failure to get buffer */ 153 154 if (dirty & MACH64_UPLOAD_MISC) { 155 DMAOUTREG(MACH64_DP_MIX, regs->dp_mix); 156 DMAOUTREG(MACH64_DP_SRC, regs->dp_src); 157 DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl); 158 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl); 159 sarea_priv->dirty &= ~MACH64_UPLOAD_MISC; 160 } 161 162 if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) { 163 DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch); 164 sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; 165 } 166 if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) { 167 DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch); 168 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; 169 } 170 if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) { 171 DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl); 172 DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl); 173 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; 174 } 175 if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) { 176 DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl); 177 sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; 178 } 179 if (dirty & MACH64_UPLOAD_DP_FOG_CLR) { 180 DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr); 181 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; 182 } 183 if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) { 184 DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask); 185 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; 186 } 187 if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) { 188 DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width); 189 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; 190 } 191 if (dirty & MACH64_UPLOAD_SETUP_CNTL) { 192 DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl); 193 sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; 194 } 195 196 if (dirty & MACH64_UPLOAD_TEXTURE) { 197 DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch); 198 DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl); 199 DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off); 200 DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset); 201 sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE; 202 } 203 204 DMAADVANCE(dev_priv, 1); 205 206 sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS; 207 208 return 0; 209 210 } 211 212 /* ================================================================ 213 * DMA command dispatch functions 214 */ 215 216 static int mach64_dma_dispatch_clear(struct drm_device * dev, 217 struct drm_file *file_priv, 218 unsigned int flags, 219 int cx, int cy, int cw, int ch, 220 unsigned int clear_color, 221 unsigned int clear_depth) 222 { 223 drm_mach64_private_t *dev_priv = dev->dev_private; 224 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 225 drm_mach64_context_regs_t *ctx = &sarea_priv->context_state; 226 int nbox = sarea_priv->nbox; 227 struct drm_clip_rect *pbox = sarea_priv->boxes; 228 u32 fb_bpp, depth_bpp; 229 int i; 230 DMALOCALS; 231 232 DRM_DEBUG("\n"); 233 234 switch (dev_priv->fb_bpp) { 235 case 16: 236 fb_bpp = MACH64_DATATYPE_RGB565; 237 break; 238 case 32: 239 fb_bpp = MACH64_DATATYPE_ARGB8888; 240 break; 241 default: 242 return -EINVAL; 243 } 244 switch (dev_priv->depth_bpp) { 245 case 16: 246 depth_bpp = MACH64_DATATYPE_RGB565; 247 break; 248 case 24: 249 case 32: 250 depth_bpp = MACH64_DATATYPE_ARGB8888; 251 break; 252 default: 253 return -EINVAL; 254 } 255 256 if (!nbox) 257 return 0; 258 259 DMAGETPTR(file_priv, dev_priv, nbox * 31); /* returns on failure to get buffer */ 260 261 for (i = 0; i < nbox; i++) { 262 int x = pbox[i].x1; 263 int y = pbox[i].y1; 264 int w = pbox[i].x2 - x; 265 int h = pbox[i].y2 - y; 266 267 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n", 268 pbox[i].x1, pbox[i].y1, 269 pbox[i].x2, pbox[i].y2, flags); 270 271 if (flags & (MACH64_FRONT | MACH64_BACK)) { 272 /* Setup for color buffer clears 273 */ 274 275 DMAOUTREG(MACH64_Z_CNTL, 0); 276 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 277 278 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 279 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 280 281 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 282 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 283 (MACH64_DST_X_LEFT_TO_RIGHT | 284 MACH64_DST_Y_TOP_TO_BOTTOM)); 285 286 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 287 (fb_bpp << 4) | 288 (fb_bpp << 8) | 289 (fb_bpp << 16) | 290 (fb_bpp << 28))); 291 292 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color); 293 DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask); 294 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 295 MACH64_FRGD_MIX_S)); 296 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 297 MACH64_FRGD_SRC_FRGD_CLR | 298 MACH64_MONO_SRC_ONE)); 299 300 } 301 302 if (flags & MACH64_FRONT) { 303 304 DMAOUTREG(MACH64_DST_OFF_PITCH, 305 dev_priv->front_offset_pitch); 306 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 307 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 308 309 } 310 311 if (flags & MACH64_BACK) { 312 313 DMAOUTREG(MACH64_DST_OFF_PITCH, 314 dev_priv->back_offset_pitch); 315 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 316 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 317 318 } 319 320 if (flags & MACH64_DEPTH) { 321 /* Setup for depth buffer clear 322 */ 323 DMAOUTREG(MACH64_Z_CNTL, 0); 324 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 325 326 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 327 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 328 329 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 330 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 331 (MACH64_DST_X_LEFT_TO_RIGHT | 332 MACH64_DST_Y_TOP_TO_BOTTOM)); 333 334 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) | 335 (depth_bpp << 4) | 336 (depth_bpp << 8) | 337 (depth_bpp << 16) | 338 (depth_bpp << 28))); 339 340 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth); 341 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 342 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 343 MACH64_FRGD_MIX_S)); 344 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 345 MACH64_FRGD_SRC_FRGD_CLR | 346 MACH64_MONO_SRC_ONE)); 347 348 DMAOUTREG(MACH64_DST_OFF_PITCH, 349 dev_priv->depth_offset_pitch); 350 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 351 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 352 } 353 } 354 355 DMAADVANCE(dev_priv, 1); 356 357 return 0; 358 } 359 360 static int mach64_dma_dispatch_swap(struct drm_device * dev, 361 struct drm_file *file_priv) 362 { 363 drm_mach64_private_t *dev_priv = dev->dev_private; 364 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 365 int nbox = sarea_priv->nbox; 366 struct drm_clip_rect *pbox = sarea_priv->boxes; 367 u32 fb_bpp; 368 int i; 369 DMALOCALS; 370 371 DRM_DEBUG("\n"); 372 373 switch (dev_priv->fb_bpp) { 374 case 16: 375 fb_bpp = MACH64_DATATYPE_RGB565; 376 break; 377 case 32: 378 default: 379 fb_bpp = MACH64_DATATYPE_ARGB8888; 380 break; 381 } 382 383 if (!nbox) 384 return 0; 385 386 DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */ 387 388 DMAOUTREG(MACH64_Z_CNTL, 0); 389 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 390 391 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 392 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 393 394 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 395 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT | 396 MACH64_DST_Y_TOP_TO_BOTTOM)); 397 398 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 399 (fb_bpp << 4) | 400 (fb_bpp << 8) | 401 (fb_bpp << 16) | (fb_bpp << 28))); 402 403 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 404 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S)); 405 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR | 406 MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE)); 407 408 DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch); 409 DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch); 410 411 for (i = 0; i < nbox; i++) { 412 int x = pbox[i].x1; 413 int y = pbox[i].y1; 414 int w = pbox[i].x2 - x; 415 int h = pbox[i].y2 - y; 416 417 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", 418 pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); 419 420 DMAOUTREG(MACH64_SRC_WIDTH1, w); 421 DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y); 422 DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y); 423 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 424 425 } 426 427 DMAADVANCE(dev_priv, 1); 428 429 if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) { 430 for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) { 431 dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1]; 432 } 433 dev_priv->frame_ofs[i] = GETRINGOFFSET(); 434 435 dev_priv->sarea_priv->frames_queued++; 436 } 437 438 return 0; 439 } 440 441 static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv) 442 { 443 drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 444 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 445 int i, start; 446 u32 head, tail, ofs; 447 448 DRM_DEBUG("\n"); 449 450 if (sarea_priv->frames_queued == 0) 451 return 0; 452 453 tail = ring->tail; 454 mach64_ring_tick(dev_priv, ring); 455 head = ring->head; 456 457 start = (MACH64_MAX_QUEUED_FRAMES - 458 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); 459 460 if (head == tail) { 461 sarea_priv->frames_queued = 0; 462 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 463 dev_priv->frame_ofs[i] = ~0; 464 } 465 return 0; 466 } 467 468 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 469 ofs = dev_priv->frame_ofs[i]; 470 DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs); 471 if (ofs == ~0 || 472 (head < tail && (ofs < head || ofs >= tail)) || 473 (head > tail && (ofs < head && ofs >= tail))) { 474 sarea_priv->frames_queued = 475 (MACH64_MAX_QUEUED_FRAMES - 1) - i; 476 dev_priv->frame_ofs[i] = ~0; 477 } 478 } 479 480 return sarea_priv->frames_queued; 481 } 482 483 /* Copy and verify a client submited buffer. 484 * FIXME: Make an assembly optimized version 485 */ 486 static __inline__ int copy_from_user_vertex(u32 *to, 487 const u32 __user *ufrom, 488 unsigned long bytes) 489 { 490 unsigned long n = bytes; /* dwords remaining in buffer */ 491 u32 *from, *orig_from; 492 493 from = drm_alloc(bytes, DRM_MEM_DRIVER); 494 if (from == NULL) 495 return -ENOMEM; 496 497 if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { 498 drm_free(from, bytes, DRM_MEM_DRIVER); 499 return -EFAULT; 500 } 501 orig_from = from; /* we'll be modifying the "from" ptr, so save it */ 502 503 n >>= 2; 504 505 while (n > 1) { 506 u32 data, reg, count; 507 508 data = *from++; 509 510 n--; 511 512 reg = le32_to_cpu(data); 513 count = (reg >> 16) + 1; 514 if (count <= n) { 515 n -= count; 516 reg &= 0xffff; 517 518 /* This is an exact match of Mach64's Setup Engine registers, 519 * excluding SETUP_CNTL (1_C1). 520 */ 521 if ((reg >= 0x0190 && reg < 0x01c1) || 522 (reg >= 0x01ca && reg <= 0x01cf)) { 523 *to++ = data; 524 memcpy(to, from, count << 2); 525 from += count; 526 to += count; 527 } else { 528 DRM_ERROR("Got bad command: 0x%04x\n", reg); 529 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 530 return -EACCES; 531 } 532 } else { 533 DRM_ERROR 534 ("Got bad command count(=%u) dwords remaining=%lu\n", 535 count, n); 536 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 537 return -EINVAL; 538 } 539 } 540 541 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 542 if (n == 0) 543 return 0; 544 else { 545 DRM_ERROR("Bad buf->used(=%lu)\n", bytes); 546 return -EINVAL; 547 } 548 } 549 550 static int mach64_dma_dispatch_vertex(struct drm_device * dev, 551 struct drm_file *file_priv, 552 drm_mach64_vertex_t * vertex) 553 { 554 drm_mach64_private_t *dev_priv = dev->dev_private; 555 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 556 struct drm_buf *copy_buf; 557 void *buf = vertex->buf; 558 unsigned long used = vertex->used; 559 int ret = 0; 560 int i = 0; 561 int done = 0; 562 int verify_ret = 0; 563 DMALOCALS_NOOUT; 564 565 DRM_DEBUG("buf=%p used=%lu nbox=%d\n", 566 buf, used, sarea_priv->nbox); 567 568 if (!used) 569 goto _vertex_done; 570 571 copy_buf = mach64_freelist_get(dev_priv); 572 if (copy_buf == NULL) { 573 DRM_ERROR("couldn't get buffer\n"); 574 return -EAGAIN; 575 } 576 577 /* Mach64's vertex data is actually register writes. To avoid security 578 * compromises these register writes have to be verified and copied from 579 * user space into a private DMA buffer. 580 */ 581 verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used); 582 583 if (verify_ret != 0) { 584 mach64_freelist_put(dev_priv, copy_buf); 585 goto _vertex_done; 586 } 587 588 copy_buf->used = used; 589 590 DMASETPTR_NOOUT(copy_buf); 591 592 if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { 593 ret = mach64_emit_state(file_priv, dev_priv); 594 if (ret < 0) 595 return ret; 596 } 597 598 do { 599 /* Emit the next cliprect */ 600 if (i < sarea_priv->nbox) { 601 ret = mach64_emit_cliprect(file_priv, dev_priv, 602 &sarea_priv->boxes[i]); 603 if (ret < 0) { 604 /* failed to get buffer */ 605 return ret; 606 } else if (ret != 0) { 607 /* null intersection with scissor */ 608 continue; 609 } 610 } 611 if ((i >= sarea_priv->nbox - 1)) 612 done = 1; 613 614 /* Add the buffer to the DMA queue */ 615 DMAADVANCE(dev_priv, done); 616 617 } while (++i < sarea_priv->nbox); 618 619 if (!done) { 620 if (copy_buf->pending) { 621 DMADISCARDBUF(); 622 } else { 623 /* This buffer wasn't used (no cliprects), so place it 624 * back on the free list 625 */ 626 mach64_freelist_put(dev_priv, copy_buf); 627 } 628 } 629 630 _vertex_done: 631 sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; 632 sarea_priv->nbox = 0; 633 634 return verify_ret; 635 } 636 637 static __inline__ int copy_from_user_blit(u32 *to, 638 const u32 __user *ufrom, 639 unsigned long bytes) 640 { 641 to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); 642 643 if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { 644 return -EFAULT; 645 } 646 647 return 0; 648 } 649 650 static int mach64_dma_dispatch_blit(struct drm_device * dev, 651 struct drm_file *file_priv, 652 drm_mach64_blit_t * blit) 653 { 654 drm_mach64_private_t *dev_priv = dev->dev_private; 655 int dword_shift, dwords; 656 unsigned long used; 657 struct drm_buf *copy_buf; 658 int verify_ret = 0; 659 DMALOCALS; 660 661 /* The compiler won't optimize away a division by a variable, 662 * even if the only legal values are powers of two. Thus, we'll 663 * use a shift instead. 664 */ 665 switch (blit->format) { 666 case MACH64_DATATYPE_ARGB8888: 667 dword_shift = 0; 668 break; 669 case MACH64_DATATYPE_ARGB1555: 670 case MACH64_DATATYPE_RGB565: 671 case MACH64_DATATYPE_VYUY422: 672 case MACH64_DATATYPE_YVYU422: 673 case MACH64_DATATYPE_ARGB4444: 674 dword_shift = 1; 675 break; 676 case MACH64_DATATYPE_CI8: 677 case MACH64_DATATYPE_RGB8: 678 dword_shift = 2; 679 break; 680 default: 681 DRM_ERROR("invalid blit format %d\n", blit->format); 682 return -EINVAL; 683 } 684 685 /* Set buf->used to the bytes of blit data based on the blit dimensions 686 * and verify the size. When the setup is emitted to the buffer with 687 * the DMA* macros below, buf->used is incremented to include the bytes 688 * used for setup as well as the blit data. 689 */ 690 dwords = (blit->width * blit->height) >> dword_shift; 691 used = dwords << 2; 692 if (used <= 0 || 693 used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { 694 DRM_ERROR("Invalid blit size: %lu bytes\n", used); 695 return -EINVAL; 696 } 697 698 copy_buf = mach64_freelist_get(dev_priv); 699 if (copy_buf == NULL) { 700 DRM_ERROR("couldn't get buffer\n"); 701 return -EAGAIN; 702 } 703 704 /* Copy the blit data from userspace. 705 * 706 * XXX: This is overkill. The most efficient solution would be having 707 * two sets of buffers (one set private for vertex data, the other set 708 * client-writable for blits). However that would bring more complexity 709 * and would break backward compatability. The solution currently 710 * implemented is keeping all buffers private, allowing to secure the 711 * driver, without increasing complexity at the expense of some speed 712 * transfering data. 713 */ 714 verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used); 715 716 if (verify_ret != 0) { 717 mach64_freelist_put(dev_priv, copy_buf); 718 goto _blit_done; 719 } 720 721 copy_buf->used = used; 722 723 /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, 724 * continuation buffers? 725 */ 726 727 /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require 728 * a register command every 16 dwords. State setup is added at the start of the 729 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET 730 */ 731 DMASETPTR(copy_buf); 732 733 DMAOUTREG(MACH64_Z_CNTL, 0); 734 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 735 736 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 737 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 738 739 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */ 740 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 741 MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM); 742 743 DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */ 744 |(blit->format << 4) /* composite pix width */ 745 |(blit->format << 8) /* src pix width */ 746 |(blit->format << 16) /* host data pix width */ 747 |(blit->format << 28) /* scaler/3D pix width */ 748 ); 749 750 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */ 751 DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S); 752 DMAOUTREG(MACH64_DP_SRC, 753 MACH64_BKGD_SRC_BKGD_CLR 754 | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE); 755 756 DMAOUTREG(MACH64_DST_OFF_PITCH, 757 (blit->pitch << 22) | (blit->offset >> 3)); 758 DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); 759 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); 760 761 DRM_DEBUG("%lu bytes\n", used); 762 763 /* Add the buffer to the queue */ 764 DMAADVANCEHOSTDATA(dev_priv); 765 766 _blit_done: 767 return verify_ret; 768 } 769 770 /* ================================================================ 771 * IOCTL functions 772 */ 773 774 int mach64_dma_clear(struct drm_device *dev, void *data, 775 struct drm_file *file_priv) 776 { 777 drm_mach64_private_t *dev_priv = dev->dev_private; 778 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 779 drm_mach64_clear_t *clear = data; 780 int ret; 781 782 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 783 784 LOCK_TEST_WITH_RETURN(dev, file_priv); 785 786 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 787 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 788 789 ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags, 790 clear->x, clear->y, clear->w, clear->h, 791 clear->clear_color, 792 clear->clear_depth); 793 794 /* Make sure we restore the 3D state next time. 795 */ 796 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 797 return ret; 798 } 799 800 int mach64_dma_swap(struct drm_device *dev, void *data, 801 struct drm_file *file_priv) 802 { 803 drm_mach64_private_t *dev_priv = dev->dev_private; 804 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 805 int ret; 806 807 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 808 809 LOCK_TEST_WITH_RETURN(dev, file_priv); 810 811 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 812 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 813 814 ret = mach64_dma_dispatch_swap(dev, file_priv); 815 816 /* Make sure we restore the 3D state next time. 817 */ 818 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 819 return ret; 820 } 821 822 int mach64_dma_vertex(struct drm_device *dev, void *data, 823 struct drm_file *file_priv) 824 { 825 drm_mach64_private_t *dev_priv = dev->dev_private; 826 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 827 drm_mach64_vertex_t *vertex = data; 828 829 LOCK_TEST_WITH_RETURN(dev, file_priv); 830 831 if (!dev_priv) { 832 DRM_ERROR("called with no initialization\n"); 833 return -EINVAL; 834 } 835 836 DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n", 837 DRM_CURRENTPID, 838 vertex->buf, vertex->used, vertex->discard); 839 840 if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) { 841 DRM_ERROR("buffer prim %d\n", vertex->prim); 842 return -EINVAL; 843 } 844 845 if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) { 846 DRM_ERROR("Invalid vertex buffer size: %lu bytes\n", 847 vertex->used); 848 return -EINVAL; 849 } 850 851 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 852 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 853 854 return mach64_dma_dispatch_vertex(dev, file_priv, vertex); 855 } 856 857 int mach64_dma_blit(struct drm_device *dev, void *data, 858 struct drm_file *file_priv) 859 { 860 drm_mach64_private_t *dev_priv = dev->dev_private; 861 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 862 drm_mach64_blit_t *blit = data; 863 int ret; 864 865 LOCK_TEST_WITH_RETURN(dev, file_priv); 866 867 ret = mach64_dma_dispatch_blit(dev, file_priv, blit); 868 869 /* Make sure we restore the 3D state next time. 870 */ 871 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | 872 MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS); 873 874 return ret; 875 } 876 877 int mach64_get_param(struct drm_device *dev, void *data, 878 struct drm_file *file_priv) 879 { 880 drm_mach64_private_t *dev_priv = dev->dev_private; 881 drm_mach64_getparam_t *param = data; 882 int value; 883 884 DRM_DEBUG("\n"); 885 886 if (!dev_priv) { 887 DRM_ERROR("called with no initialization\n"); 888 return -EINVAL; 889 } 890 891 switch (param->param) { 892 case MACH64_PARAM_FRAMES_QUEUED: 893 /* Needs lock since it calls mach64_ring_tick() */ 894 LOCK_TEST_WITH_RETURN(dev, file_priv); 895 value = mach64_do_get_frames_queued(dev_priv); 896 break; 897 case MACH64_PARAM_IRQ_NR: 898 value = dev->irq; 899 break; 900 default: 901 return -EINVAL; 902 } 903 904 if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 905 DRM_ERROR("copy_to_user\n"); 906 return -EFAULT; 907 } 908 909 return 0; 910 } 911