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