1139749Simp/*- 295584Sanholt * Copyright 2000 VA Linux Systems, Inc., Fremont, California. 395584Sanholt * All Rights Reserved. 495584Sanholt * 595584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 695584Sanholt * copy of this software and associated documentation files (the "Software"), 795584Sanholt * to deal in the Software without restriction, including without limitation 895584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 995584Sanholt * and/or sell copies of the Software, and to permit persons to whom the 1095584Sanholt * Software is furnished to do so, subject to the following conditions: 1195584Sanholt * 1295584Sanholt * The above copyright notice and this permission notice (including the next 1395584Sanholt * paragraph) shall be included in all copies or substantial portions of the 1495584Sanholt * Software. 1595584Sanholt * 1695584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1795584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1895584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1995584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2095584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2195584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2295584Sanholt * DEALINGS IN THE SOFTWARE. 2395584Sanholt * 2495584Sanholt * Authors: 2595584Sanholt * Gareth Hughes <gareth@valinux.com> 2695584Sanholt * Kevin E. Martin <martin@valinux.com> 2795584Sanholt */ 2895584Sanholt 29152909Sanholt#include <sys/cdefs.h> 30152909Sanholt__FBSDID("$FreeBSD$"); 31152909Sanholt 3295584Sanholt#include "dev/drm/drmP.h" 33112015Sanholt#include "dev/drm/drm.h" 34112015Sanholt#include "dev/drm/drm_sarea.h" 3595746Sanholt#include "dev/drm/radeon_drm.h" 3695584Sanholt#include "dev/drm/radeon_drv.h" 3795584Sanholt 3895584Sanholt/* ================================================================ 39122580Sanholt * Helper functions for client state checking and fixup 40122580Sanholt */ 41122580Sanholt 42145132Sanholtstatic __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * 43145132Sanholt dev_priv, 44182080Srnoland struct drm_file *file_priv, 45189499Srnoland u32 *offset) 46145132Sanholt{ 47162132Sanholt u64 off = *offset; 48182080Srnoland u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1; 49145132Sanholt struct drm_radeon_driver_file_fields *radeon_priv; 50122580Sanholt 51157617Sanholt /* Hrm ... the story of the offset ... So this function converts 52157617Sanholt * the various ideas of what userland clients might have for an 53157617Sanholt * offset in the card address space into an offset into the card 54157617Sanholt * address space :) So with a sane client, it should just keep 55157617Sanholt * the value intact and just do some boundary checking. However, 56157617Sanholt * not all clients are sane. Some older clients pass us 0 based 57157617Sanholt * offsets relative to the start of the framebuffer and some may 58157617Sanholt * assume the AGP aperture it appended to the framebuffer, so we 59157617Sanholt * try to detect those cases and fix them up. 60157617Sanholt * 61157617Sanholt * Note: It might be a good idea here to make sure the offset lands 62157617Sanholt * in some "allowed" area to protect things like the PCIE GART... 63157617Sanholt */ 64157617Sanholt 65157617Sanholt /* First, the best case, the offset already lands in either the 66157617Sanholt * framebuffer or the GART mapped space 67157617Sanholt */ 68182080Srnoland if (radeon_check_offset(dev_priv, off)) 69122580Sanholt return 0; 70122580Sanholt 71157617Sanholt /* Ok, that didn't happen... now check if we have a zero based 72157617Sanholt * offset that fits in the framebuffer + gart space, apply the 73157617Sanholt * magic offset we get from SETPARAM or calculated from fb_location 74157617Sanholt */ 75157617Sanholt if (off < (dev_priv->fb_size + dev_priv->gart_size)) { 76182080Srnoland radeon_priv = file_priv->driver_priv; 77157617Sanholt off += radeon_priv->radeon_fb_delta; 78157617Sanholt } 79122580Sanholt 80157617Sanholt /* Finally, assume we aimed at a GART offset if beyond the fb */ 81162132Sanholt if (off > fb_end) 82182080Srnoland off = off - fb_end - 1 + dev_priv->gart_vm_start; 83122580Sanholt 84157617Sanholt /* Now recheck and fail if out of bounds */ 85182080Srnoland if (radeon_check_offset(dev_priv, off)) { 86162132Sanholt DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); 87157617Sanholt *offset = off; 88157617Sanholt return 0; 89157617Sanholt } 90182080Srnoland return -EINVAL; 91122580Sanholt} 92122580Sanholt 93145132Sanholtstatic __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * 94145132Sanholt dev_priv, 95182080Srnoland struct drm_file *file_priv, 96157617Sanholt int id, u32 *data) 97145132Sanholt{ 98145132Sanholt switch (id) { 99122580Sanholt 100130331Sanholt case RADEON_EMIT_PP_MISC: 101182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 102145132Sanholt &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) { 103145132Sanholt DRM_ERROR("Invalid depth buffer offset\n"); 104182080Srnoland return -EINVAL; 105130331Sanholt } 106130331Sanholt break; 107130331Sanholt 108130331Sanholt case RADEON_EMIT_PP_CNTL: 109182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 110145132Sanholt &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) { 111145132Sanholt DRM_ERROR("Invalid colour buffer offset\n"); 112182080Srnoland return -EINVAL; 113130331Sanholt } 114130331Sanholt break; 115130331Sanholt 116130331Sanholt case R200_EMIT_PP_TXOFFSET_0: 117130331Sanholt case R200_EMIT_PP_TXOFFSET_1: 118130331Sanholt case R200_EMIT_PP_TXOFFSET_2: 119130331Sanholt case R200_EMIT_PP_TXOFFSET_3: 120130331Sanholt case R200_EMIT_PP_TXOFFSET_4: 121130331Sanholt case R200_EMIT_PP_TXOFFSET_5: 122182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 123145132Sanholt &data[0])) { 124145132Sanholt DRM_ERROR("Invalid R200 texture offset\n"); 125182080Srnoland return -EINVAL; 126130331Sanholt } 127130331Sanholt break; 128130331Sanholt 129130331Sanholt case RADEON_EMIT_PP_TXFILTER_0: 130130331Sanholt case RADEON_EMIT_PP_TXFILTER_1: 131130331Sanholt case RADEON_EMIT_PP_TXFILTER_2: 132182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 133145132Sanholt &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) { 134145132Sanholt DRM_ERROR("Invalid R100 texture offset\n"); 135182080Srnoland return -EINVAL; 136130331Sanholt } 137130331Sanholt break; 138130331Sanholt 139130331Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_0: 140130331Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_1: 141130331Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_2: 142130331Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_3: 143130331Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_4: 144145132Sanholt case R200_EMIT_PP_CUBIC_OFFSETS_5:{ 145145132Sanholt int i; 146145132Sanholt for (i = 0; i < 5; i++) { 147145132Sanholt if (radeon_check_and_fixup_offset(dev_priv, 148182080Srnoland file_priv, 149145132Sanholt &data[i])) { 150145132Sanholt DRM_ERROR 151145132Sanholt ("Invalid R200 cubic texture offset\n"); 152182080Srnoland return -EINVAL; 153145132Sanholt } 154122580Sanholt } 155145132Sanholt break; 156122580Sanholt } 157145132Sanholt 158145132Sanholt case RADEON_EMIT_PP_CUBIC_OFFSETS_T0: 159145132Sanholt case RADEON_EMIT_PP_CUBIC_OFFSETS_T1: 160145132Sanholt case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{ 161145132Sanholt int i; 162145132Sanholt for (i = 0; i < 5; i++) { 163145132Sanholt if (radeon_check_and_fixup_offset(dev_priv, 164182080Srnoland file_priv, 165145132Sanholt &data[i])) { 166145132Sanholt DRM_ERROR 167145132Sanholt ("Invalid R100 cubic texture offset\n"); 168182080Srnoland return -EINVAL; 169145132Sanholt } 170145132Sanholt } 171145132Sanholt } 172130331Sanholt break; 173122580Sanholt 174182080Srnoland case R200_EMIT_VAP_CTL: { 175182080Srnoland RING_LOCALS; 176182080Srnoland BEGIN_RING(2); 177182080Srnoland OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 178182080Srnoland ADVANCE_RING(); 179182080Srnoland } 180182080Srnoland break; 181182080Srnoland 182130331Sanholt case RADEON_EMIT_RB3D_COLORPITCH: 183130331Sanholt case RADEON_EMIT_RE_LINE_PATTERN: 184130331Sanholt case RADEON_EMIT_SE_LINE_WIDTH: 185130331Sanholt case RADEON_EMIT_PP_LUM_MATRIX: 186130331Sanholt case RADEON_EMIT_PP_ROT_MATRIX_0: 187130331Sanholt case RADEON_EMIT_RB3D_STENCILREFMASK: 188130331Sanholt case RADEON_EMIT_SE_VPORT_XSCALE: 189130331Sanholt case RADEON_EMIT_SE_CNTL: 190130331Sanholt case RADEON_EMIT_SE_CNTL_STATUS: 191130331Sanholt case RADEON_EMIT_RE_MISC: 192130331Sanholt case RADEON_EMIT_PP_BORDER_COLOR_0: 193130331Sanholt case RADEON_EMIT_PP_BORDER_COLOR_1: 194130331Sanholt case RADEON_EMIT_PP_BORDER_COLOR_2: 195130331Sanholt case RADEON_EMIT_SE_ZBIAS_FACTOR: 196130331Sanholt case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT: 197130331Sanholt case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED: 198130331Sanholt case R200_EMIT_PP_TXCBLEND_0: 199130331Sanholt case R200_EMIT_PP_TXCBLEND_1: 200130331Sanholt case R200_EMIT_PP_TXCBLEND_2: 201130331Sanholt case R200_EMIT_PP_TXCBLEND_3: 202130331Sanholt case R200_EMIT_PP_TXCBLEND_4: 203130331Sanholt case R200_EMIT_PP_TXCBLEND_5: 204130331Sanholt case R200_EMIT_PP_TXCBLEND_6: 205130331Sanholt case R200_EMIT_PP_TXCBLEND_7: 206130331Sanholt case R200_EMIT_TCL_LIGHT_MODEL_CTL_0: 207130331Sanholt case R200_EMIT_TFACTOR_0: 208130331Sanholt case R200_EMIT_VTX_FMT_0: 209130331Sanholt case R200_EMIT_MATRIX_SELECT_0: 210130331Sanholt case R200_EMIT_TEX_PROC_CTL_2: 211130331Sanholt case R200_EMIT_TCL_UCP_VERT_BLEND_CTL: 212130331Sanholt case R200_EMIT_PP_TXFILTER_0: 213130331Sanholt case R200_EMIT_PP_TXFILTER_1: 214130331Sanholt case R200_EMIT_PP_TXFILTER_2: 215130331Sanholt case R200_EMIT_PP_TXFILTER_3: 216130331Sanholt case R200_EMIT_PP_TXFILTER_4: 217130331Sanholt case R200_EMIT_PP_TXFILTER_5: 218130331Sanholt case R200_EMIT_VTE_CNTL: 219130331Sanholt case R200_EMIT_OUTPUT_VTX_COMP_SEL: 220130331Sanholt case R200_EMIT_PP_TAM_DEBUG3: 221130331Sanholt case R200_EMIT_PP_CNTL_X: 222130331Sanholt case R200_EMIT_RB3D_DEPTHXY_OFFSET: 223130331Sanholt case R200_EMIT_RE_AUX_SCISSOR_CNTL: 224130331Sanholt case R200_EMIT_RE_SCISSOR_TL_0: 225130331Sanholt case R200_EMIT_RE_SCISSOR_TL_1: 226130331Sanholt case R200_EMIT_RE_SCISSOR_TL_2: 227130331Sanholt case R200_EMIT_SE_VAP_CNTL_STATUS: 228130331Sanholt case R200_EMIT_SE_VTX_STATE_CNTL: 229130331Sanholt case R200_EMIT_RE_POINTSIZE: 230130331Sanholt case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0: 231130331Sanholt case R200_EMIT_PP_CUBIC_FACES_0: 232130331Sanholt case R200_EMIT_PP_CUBIC_FACES_1: 233130331Sanholt case R200_EMIT_PP_CUBIC_FACES_2: 234130331Sanholt case R200_EMIT_PP_CUBIC_FACES_3: 235130331Sanholt case R200_EMIT_PP_CUBIC_FACES_4: 236130331Sanholt case R200_EMIT_PP_CUBIC_FACES_5: 237130331Sanholt case RADEON_EMIT_PP_TEX_SIZE_0: 238130331Sanholt case RADEON_EMIT_PP_TEX_SIZE_1: 239130331Sanholt case RADEON_EMIT_PP_TEX_SIZE_2: 240130331Sanholt case R200_EMIT_RB3D_BLENDCOLOR: 241145132Sanholt case R200_EMIT_TCL_POINT_SPRITE_CNTL: 242145132Sanholt case RADEON_EMIT_PP_CUBIC_FACES_0: 243145132Sanholt case RADEON_EMIT_PP_CUBIC_FACES_1: 244145132Sanholt case RADEON_EMIT_PP_CUBIC_FACES_2: 245145132Sanholt case R200_EMIT_PP_TRI_PERF_CNTL: 246152909Sanholt case R200_EMIT_PP_AFS_0: 247152909Sanholt case R200_EMIT_PP_AFS_1: 248152909Sanholt case R200_EMIT_ATF_TFACTOR: 249152909Sanholt case R200_EMIT_PP_TXCTLALL_0: 250152909Sanholt case R200_EMIT_PP_TXCTLALL_1: 251152909Sanholt case R200_EMIT_PP_TXCTLALL_2: 252152909Sanholt case R200_EMIT_PP_TXCTLALL_3: 253152909Sanholt case R200_EMIT_PP_TXCTLALL_4: 254152909Sanholt case R200_EMIT_PP_TXCTLALL_5: 255162132Sanholt case R200_EMIT_VAP_PVS_CNTL: 256130331Sanholt /* These packets don't contain memory offsets */ 257130331Sanholt break; 258130331Sanholt 259130331Sanholt default: 260145132Sanholt DRM_ERROR("Unknown state packet ID %d\n", id); 261182080Srnoland return -EINVAL; 262130331Sanholt } 263130331Sanholt 264122580Sanholt return 0; 265122580Sanholt} 266122580Sanholt 267145132Sanholtstatic __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * 268145132Sanholt dev_priv, 269182080Srnoland struct drm_file *file_priv, 270157617Sanholt drm_radeon_kcmd_buffer_t * 271145132Sanholt cmdbuf, 272145132Sanholt unsigned int *cmdsz) 273145132Sanholt{ 274145132Sanholt u32 *cmd = (u32 *) cmdbuf->buf; 275182080Srnoland u32 offset, narrays; 276182080Srnoland int count, i, k; 277122580Sanholt 278145132Sanholt *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); 279122580Sanholt 280145132Sanholt if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) { 281145132Sanholt DRM_ERROR("Not a type 3 packet\n"); 282182080Srnoland return -EINVAL; 283122580Sanholt } 284122580Sanholt 285145132Sanholt if (4 * *cmdsz > cmdbuf->bufsz) { 286145132Sanholt DRM_ERROR("Packet size larger than size of data provided\n"); 287182080Srnoland return -EINVAL; 288122580Sanholt } 289122580Sanholt 290182080Srnoland switch(cmd[0] & 0xff00) { 291182080Srnoland /* XXX Are there old drivers needing other packets? */ 292122580Sanholt 293182080Srnoland case RADEON_3D_DRAW_IMMD: 294182080Srnoland case RADEON_3D_DRAW_VBUF: 295182080Srnoland case RADEON_3D_DRAW_INDX: 296182080Srnoland case RADEON_WAIT_FOR_IDLE: 297182080Srnoland case RADEON_CP_NOP: 298182080Srnoland case RADEON_3D_CLEAR_ZMASK: 299182080Srnoland/* case RADEON_CP_NEXT_CHAR: 300182080Srnoland case RADEON_CP_PLY_NEXTSCAN: 301182080Srnoland case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ 302182080Srnoland /* these packets are safe */ 303182080Srnoland break; 304182080Srnoland 305182080Srnoland case RADEON_CP_3D_DRAW_IMMD_2: 306182080Srnoland case RADEON_CP_3D_DRAW_VBUF_2: 307182080Srnoland case RADEON_CP_3D_DRAW_INDX_2: 308182080Srnoland case RADEON_3D_CLEAR_HIZ: 309182080Srnoland /* safe but r200 only */ 310189499Srnoland if (dev_priv->microcode_version != UCODE_R200) { 311189499Srnoland DRM_ERROR("Invalid 3d packet for r100-class chip\n"); 312182080Srnoland return -EINVAL; 313182080Srnoland } 314182080Srnoland break; 315182080Srnoland 316182080Srnoland case RADEON_3D_LOAD_VBPNTR: 317182080Srnoland count = (cmd[0] >> 16) & 0x3fff; 318182080Srnoland 319182080Srnoland if (count > 18) { /* 12 arrays max */ 320182080Srnoland DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", 321182080Srnoland count); 322182080Srnoland return -EINVAL; 323182080Srnoland } 324182080Srnoland 325182080Srnoland /* carefully check packet contents */ 326182080Srnoland narrays = cmd[1] & ~0xc000; 327182080Srnoland k = 0; 328182080Srnoland i = 2; 329182080Srnoland while ((k < narrays) && (i < (count + 2))) { 330182080Srnoland i++; /* skip attribute field */ 331182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 332182080Srnoland &cmd[i])) { 333182080Srnoland DRM_ERROR 334182080Srnoland ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", 335182080Srnoland k, i); 336182080Srnoland return -EINVAL; 337182080Srnoland } 338182080Srnoland k++; 339182080Srnoland i++; 340182080Srnoland if (k == narrays) 341182080Srnoland break; 342182080Srnoland /* have one more to process, they come in pairs */ 343182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, 344182080Srnoland file_priv, &cmd[i])) 345182080Srnoland { 346182080Srnoland DRM_ERROR 347182080Srnoland ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", 348182080Srnoland k, i); 349182080Srnoland return -EINVAL; 350182080Srnoland } 351182080Srnoland k++; 352182080Srnoland i++; 353182080Srnoland } 354182080Srnoland /* do the counts match what we expect ? */ 355182080Srnoland if ((k != narrays) || (i != (count + 2))) { 356182080Srnoland DRM_ERROR 357182080Srnoland ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", 358182080Srnoland k, i, narrays, count + 1); 359182080Srnoland return -EINVAL; 360182080Srnoland } 361182080Srnoland break; 362182080Srnoland 363182080Srnoland case RADEON_3D_RNDR_GEN_INDX_PRIM: 364189499Srnoland if (dev_priv->microcode_version != UCODE_R100) { 365189499Srnoland DRM_ERROR("Invalid 3d packet for r200-class chip\n"); 366182080Srnoland return -EINVAL; 367182080Srnoland } 368182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { 369182080Srnoland DRM_ERROR("Invalid rndr_gen_indx offset\n"); 370182080Srnoland return -EINVAL; 371182080Srnoland } 372182080Srnoland break; 373182080Srnoland 374182080Srnoland case RADEON_CP_INDX_BUFFER: 375189499Srnoland if (dev_priv->microcode_version != UCODE_R200) { 376189499Srnoland DRM_ERROR("Invalid 3d packet for r100-class chip\n"); 377182080Srnoland return -EINVAL; 378182080Srnoland } 379182080Srnoland if ((cmd[1] & 0x8000ffff) != 0x80000810) { 380182080Srnoland DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); 381182080Srnoland return -EINVAL; 382182080Srnoland } 383182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) { 384182080Srnoland DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); 385182080Srnoland return -EINVAL; 386182080Srnoland } 387182080Srnoland break; 388182080Srnoland 389182080Srnoland case RADEON_CNTL_HOSTDATA_BLT: 390182080Srnoland case RADEON_CNTL_PAINT_MULTI: 391182080Srnoland case RADEON_CNTL_BITBLT_MULTI: 392182080Srnoland /* MSB of opcode: next DWORD GUI_CNTL */ 393145132Sanholt if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL 394145132Sanholt | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { 395145132Sanholt offset = cmd[2] << 10; 396145132Sanholt if (radeon_check_and_fixup_offset 397182080Srnoland (dev_priv, file_priv, &offset)) { 398145132Sanholt DRM_ERROR("Invalid first packet offset\n"); 399182080Srnoland return -EINVAL; 400122580Sanholt } 401145132Sanholt cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10; 402122580Sanholt } 403122580Sanholt 404145132Sanholt if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && 405145132Sanholt (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { 406145132Sanholt offset = cmd[3] << 10; 407145132Sanholt if (radeon_check_and_fixup_offset 408182080Srnoland (dev_priv, file_priv, &offset)) { 409145132Sanholt DRM_ERROR("Invalid second packet offset\n"); 410182080Srnoland return -EINVAL; 411122580Sanholt } 412145132Sanholt cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; 413122580Sanholt } 414182080Srnoland break; 415182080Srnoland 416182080Srnoland default: 417182080Srnoland DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); 418182080Srnoland return -EINVAL; 419122580Sanholt } 420122580Sanholt 421122580Sanholt return 0; 422122580Sanholt} 423122580Sanholt 424122580Sanholt/* ================================================================ 42595584Sanholt * CP hardware state programming functions 42695584Sanholt */ 42795584Sanholt 428145132Sanholtstatic __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv, 429182080Srnoland struct drm_clip_rect * box) 43095584Sanholt{ 43195584Sanholt RING_LOCALS; 43295584Sanholt 433145132Sanholt DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n", 434145132Sanholt box->x1, box->y1, box->x2, box->y2); 43595584Sanholt 436145132Sanholt BEGIN_RING(4); 437145132Sanholt OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0)); 438145132Sanholt OUT_RING((box->y1 << 16) | box->x1); 439145132Sanholt OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0)); 440145132Sanholt OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1)); 44195584Sanholt ADVANCE_RING(); 44295584Sanholt} 44395584Sanholt 444112015Sanholt/* Emit 1.1 state 445112015Sanholt */ 446145132Sanholtstatic int radeon_emit_state(drm_radeon_private_t * dev_priv, 447182080Srnoland struct drm_file *file_priv, 448145132Sanholt drm_radeon_context_regs_t * ctx, 449145132Sanholt drm_radeon_texture_regs_t * tex, 450145132Sanholt unsigned int dirty) 45195584Sanholt{ 45295584Sanholt RING_LOCALS; 453145132Sanholt DRM_DEBUG("dirty=0x%08x\n", dirty); 45495584Sanholt 455145132Sanholt if (dirty & RADEON_UPLOAD_CONTEXT) { 456182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 457145132Sanholt &ctx->rb3d_depthoffset)) { 458145132Sanholt DRM_ERROR("Invalid depth buffer offset\n"); 459182080Srnoland return -EINVAL; 460122580Sanholt } 461122580Sanholt 462182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 463145132Sanholt &ctx->rb3d_coloroffset)) { 464145132Sanholt DRM_ERROR("Invalid depth buffer offset\n"); 465182080Srnoland return -EINVAL; 466122580Sanholt } 467122580Sanholt 468145132Sanholt BEGIN_RING(14); 469145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6)); 470145132Sanholt OUT_RING(ctx->pp_misc); 471145132Sanholt OUT_RING(ctx->pp_fog_color); 472145132Sanholt OUT_RING(ctx->re_solid_color); 473145132Sanholt OUT_RING(ctx->rb3d_blendcntl); 474145132Sanholt OUT_RING(ctx->rb3d_depthoffset); 475145132Sanholt OUT_RING(ctx->rb3d_depthpitch); 476145132Sanholt OUT_RING(ctx->rb3d_zstencilcntl); 477145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2)); 478145132Sanholt OUT_RING(ctx->pp_cntl); 479145132Sanholt OUT_RING(ctx->rb3d_cntl); 480145132Sanholt OUT_RING(ctx->rb3d_coloroffset); 481145132Sanholt OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0)); 482145132Sanholt OUT_RING(ctx->rb3d_colorpitch); 483112015Sanholt ADVANCE_RING(); 48495584Sanholt } 48595584Sanholt 486145132Sanholt if (dirty & RADEON_UPLOAD_VERTFMT) { 487145132Sanholt BEGIN_RING(2); 488145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0)); 489145132Sanholt OUT_RING(ctx->se_coord_fmt); 490112015Sanholt ADVANCE_RING(); 49195584Sanholt } 49295584Sanholt 493145132Sanholt if (dirty & RADEON_UPLOAD_LINE) { 494145132Sanholt BEGIN_RING(5); 495145132Sanholt OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1)); 496145132Sanholt OUT_RING(ctx->re_line_pattern); 497145132Sanholt OUT_RING(ctx->re_line_state); 498145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0)); 499145132Sanholt OUT_RING(ctx->se_line_width); 500112015Sanholt ADVANCE_RING(); 50195584Sanholt } 50295584Sanholt 503145132Sanholt if (dirty & RADEON_UPLOAD_BUMPMAP) { 504145132Sanholt BEGIN_RING(5); 505145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0)); 506145132Sanholt OUT_RING(ctx->pp_lum_matrix); 507145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1)); 508145132Sanholt OUT_RING(ctx->pp_rot_matrix_0); 509145132Sanholt OUT_RING(ctx->pp_rot_matrix_1); 510112015Sanholt ADVANCE_RING(); 51195584Sanholt } 51295584Sanholt 513145132Sanholt if (dirty & RADEON_UPLOAD_MASKS) { 514145132Sanholt BEGIN_RING(4); 515145132Sanholt OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2)); 516145132Sanholt OUT_RING(ctx->rb3d_stencilrefmask); 517145132Sanholt OUT_RING(ctx->rb3d_ropcntl); 518145132Sanholt OUT_RING(ctx->rb3d_planemask); 519112015Sanholt ADVANCE_RING(); 52095584Sanholt } 52195584Sanholt 522145132Sanholt if (dirty & RADEON_UPLOAD_VIEWPORT) { 523145132Sanholt BEGIN_RING(7); 524145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5)); 525145132Sanholt OUT_RING(ctx->se_vport_xscale); 526145132Sanholt OUT_RING(ctx->se_vport_xoffset); 527145132Sanholt OUT_RING(ctx->se_vport_yscale); 528145132Sanholt OUT_RING(ctx->se_vport_yoffset); 529145132Sanholt OUT_RING(ctx->se_vport_zscale); 530145132Sanholt OUT_RING(ctx->se_vport_zoffset); 531112015Sanholt ADVANCE_RING(); 53295584Sanholt } 53395584Sanholt 534145132Sanholt if (dirty & RADEON_UPLOAD_SETUP) { 535145132Sanholt BEGIN_RING(4); 536145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0)); 537145132Sanholt OUT_RING(ctx->se_cntl); 538145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0)); 539145132Sanholt OUT_RING(ctx->se_cntl_status); 540112015Sanholt ADVANCE_RING(); 54195584Sanholt } 54295584Sanholt 543145132Sanholt if (dirty & RADEON_UPLOAD_MISC) { 544145132Sanholt BEGIN_RING(2); 545145132Sanholt OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0)); 546145132Sanholt OUT_RING(ctx->re_misc); 547112015Sanholt ADVANCE_RING(); 54895584Sanholt } 54995584Sanholt 550145132Sanholt if (dirty & RADEON_UPLOAD_TEX0) { 551182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 552145132Sanholt &tex[0].pp_txoffset)) { 553145132Sanholt DRM_ERROR("Invalid texture offset for unit 0\n"); 554182080Srnoland return -EINVAL; 555122580Sanholt } 556122580Sanholt 557145132Sanholt BEGIN_RING(9); 558145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5)); 559145132Sanholt OUT_RING(tex[0].pp_txfilter); 560145132Sanholt OUT_RING(tex[0].pp_txformat); 561145132Sanholt OUT_RING(tex[0].pp_txoffset); 562145132Sanholt OUT_RING(tex[0].pp_txcblend); 563145132Sanholt OUT_RING(tex[0].pp_txablend); 564145132Sanholt OUT_RING(tex[0].pp_tfactor); 565145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0)); 566145132Sanholt OUT_RING(tex[0].pp_border_color); 567112015Sanholt ADVANCE_RING(); 56895584Sanholt } 56995584Sanholt 570145132Sanholt if (dirty & RADEON_UPLOAD_TEX1) { 571182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 572145132Sanholt &tex[1].pp_txoffset)) { 573145132Sanholt DRM_ERROR("Invalid texture offset for unit 1\n"); 574182080Srnoland return -EINVAL; 575122580Sanholt } 576122580Sanholt 577145132Sanholt BEGIN_RING(9); 578145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5)); 579145132Sanholt OUT_RING(tex[1].pp_txfilter); 580145132Sanholt OUT_RING(tex[1].pp_txformat); 581145132Sanholt OUT_RING(tex[1].pp_txoffset); 582145132Sanholt OUT_RING(tex[1].pp_txcblend); 583145132Sanholt OUT_RING(tex[1].pp_txablend); 584145132Sanholt OUT_RING(tex[1].pp_tfactor); 585145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0)); 586145132Sanholt OUT_RING(tex[1].pp_border_color); 587112015Sanholt ADVANCE_RING(); 58895584Sanholt } 58995584Sanholt 590145132Sanholt if (dirty & RADEON_UPLOAD_TEX2) { 591182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, 592145132Sanholt &tex[2].pp_txoffset)) { 593145132Sanholt DRM_ERROR("Invalid texture offset for unit 2\n"); 594182080Srnoland return -EINVAL; 595122580Sanholt } 596122580Sanholt 597145132Sanholt BEGIN_RING(9); 598145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5)); 599145132Sanholt OUT_RING(tex[2].pp_txfilter); 600145132Sanholt OUT_RING(tex[2].pp_txformat); 601145132Sanholt OUT_RING(tex[2].pp_txoffset); 602145132Sanholt OUT_RING(tex[2].pp_txcblend); 603145132Sanholt OUT_RING(tex[2].pp_txablend); 604145132Sanholt OUT_RING(tex[2].pp_tfactor); 605145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0)); 606145132Sanholt OUT_RING(tex[2].pp_border_color); 607112015Sanholt ADVANCE_RING(); 60895584Sanholt } 609122580Sanholt 610122580Sanholt return 0; 611112015Sanholt} 61295584Sanholt 613112015Sanholt/* Emit 1.2 state 614112015Sanholt */ 615145132Sanholtstatic int radeon_emit_state2(drm_radeon_private_t * dev_priv, 616182080Srnoland struct drm_file *file_priv, 617145132Sanholt drm_radeon_state_t * state) 618112015Sanholt{ 619112015Sanholt RING_LOCALS; 620112015Sanholt 621112015Sanholt if (state->dirty & RADEON_UPLOAD_ZBIAS) { 622145132Sanholt BEGIN_RING(3); 623145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1)); 624145132Sanholt OUT_RING(state->context2.se_zbias_factor); 625145132Sanholt OUT_RING(state->context2.se_zbias_constant); 626112015Sanholt ADVANCE_RING(); 627112015Sanholt } 628112015Sanholt 629182080Srnoland return radeon_emit_state(dev_priv, file_priv, &state->context, 630145132Sanholt state->tex, state->dirty); 63195584Sanholt} 63295584Sanholt 633112015Sanholt/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in 634112015Sanholt * 1.3 cmdbuffers allow all previous state to be updated as well as 635145132Sanholt * the tcl scalar and vector areas. 636112015Sanholt */ 637145132Sanholtstatic struct { 638145132Sanholt int start; 639145132Sanholt int len; 640112015Sanholt const char *name; 641112015Sanholt} packet[RADEON_MAX_STATE_PACKETS] = { 642152909Sanholt {RADEON_PP_MISC, 7, "RADEON_PP_MISC"}, 643152909Sanholt {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"}, 644152909Sanholt {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"}, 645152909Sanholt {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"}, 646152909Sanholt {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"}, 647152909Sanholt {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"}, 648152909Sanholt {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"}, 649152909Sanholt {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"}, 650152909Sanholt {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"}, 651152909Sanholt {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"}, 652152909Sanholt {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"}, 653152909Sanholt {RADEON_RE_MISC, 1, "RADEON_RE_MISC"}, 654152909Sanholt {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"}, 655152909Sanholt {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"}, 656152909Sanholt {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"}, 657152909Sanholt {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"}, 658152909Sanholt {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"}, 659152909Sanholt {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"}, 660152909Sanholt {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"}, 661152909Sanholt {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"}, 662152909Sanholt {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17, 663157617Sanholt "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"}, 664152909Sanholt {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"}, 665152909Sanholt {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"}, 666152909Sanholt {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"}, 667152909Sanholt {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"}, 668152909Sanholt {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"}, 669152909Sanholt {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"}, 670152909Sanholt {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"}, 671152909Sanholt {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"}, 672152909Sanholt {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"}, 673152909Sanholt {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"}, 674152909Sanholt {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"}, 675152909Sanholt {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"}, 676152909Sanholt {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"}, 677152909Sanholt {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"}, 678152909Sanholt {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"}, 679152909Sanholt {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"}, 680152909Sanholt {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"}, 681152909Sanholt {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"}, 682152909Sanholt {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"}, 683152909Sanholt {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"}, 684152909Sanholt {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"}, 685152909Sanholt {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"}, 686152909Sanholt {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"}, 687152909Sanholt {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"}, 688152909Sanholt {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"}, 689152909Sanholt {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"}, 690152909Sanholt {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"}, 691152909Sanholt {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"}, 692152909Sanholt {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1, 693152909Sanholt "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"}, 694152909Sanholt {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"}, 695152909Sanholt {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"}, 696152909Sanholt {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"}, 697152909Sanholt {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"}, 698152909Sanholt {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"}, 699152909Sanholt {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"}, 700152909Sanholt {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"}, 701152909Sanholt {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"}, 702152909Sanholt {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"}, 703152909Sanholt {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"}, 704152909Sanholt {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4, 705157617Sanholt "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"}, 706152909Sanholt {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */ 707152909Sanholt {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */ 708152909Sanholt {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"}, 709152909Sanholt {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"}, 710152909Sanholt {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"}, 711152909Sanholt {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"}, 712152909Sanholt {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"}, 713152909Sanholt {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"}, 714152909Sanholt {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"}, 715152909Sanholt {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"}, 716152909Sanholt {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"}, 717152909Sanholt {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"}, 718152909Sanholt {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"}, 719152909Sanholt {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"}, 720152909Sanholt {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"}, 721152909Sanholt {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"}, 722152909Sanholt {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"}, 723152909Sanholt {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"}, 724152909Sanholt {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"}, 725152909Sanholt {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"}, 726152909Sanholt {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"}, 727152909Sanholt {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"}, 728152909Sanholt {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"}, 729152909Sanholt {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"}, 730152909Sanholt {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */ 731152909Sanholt {R200_PP_AFS_1, 32, "R200_PP_AFS_1"}, 732152909Sanholt {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"}, 733152909Sanholt {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"}, 734152909Sanholt {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"}, 735152909Sanholt {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"}, 736152909Sanholt {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"}, 737152909Sanholt {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"}, 738152909Sanholt {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"}, 739162132Sanholt {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"}, 740112015Sanholt}; 74195584Sanholt 74295584Sanholt/* ================================================================ 74395584Sanholt * Performance monitoring functions 74495584Sanholt */ 74595584Sanholt 746145132Sanholtstatic void radeon_clear_box(drm_radeon_private_t * dev_priv, 747145132Sanholt int x, int y, int w, int h, int r, int g, int b) 74895584Sanholt{ 74995584Sanholt u32 color; 75095584Sanholt RING_LOCALS; 75195584Sanholt 752112015Sanholt x += dev_priv->sarea_priv->boxes[0].x1; 753112015Sanholt y += dev_priv->sarea_priv->boxes[0].y1; 754112015Sanholt 755145132Sanholt switch (dev_priv->color_fmt) { 75695584Sanholt case RADEON_COLOR_FORMAT_RGB565: 75795584Sanholt color = (((r & 0xf8) << 8) | 758145132Sanholt ((g & 0xfc) << 3) | ((b & 0xf8) >> 3)); 75995584Sanholt break; 76095584Sanholt case RADEON_COLOR_FORMAT_ARGB8888: 76195584Sanholt default: 762145132Sanholt color = (((0xff) << 24) | (r << 16) | (g << 8) | b); 76395584Sanholt break; 76495584Sanholt } 76595584Sanholt 766145132Sanholt BEGIN_RING(4); 767145132Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 768145132Sanholt OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0)); 769145132Sanholt OUT_RING(0xffffffff); 770112015Sanholt ADVANCE_RING(); 77195584Sanholt 772145132Sanholt BEGIN_RING(6); 77395584Sanholt 774145132Sanholt OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4)); 775145132Sanholt OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 776145132Sanholt RADEON_GMC_BRUSH_SOLID_COLOR | 777145132Sanholt (dev_priv->color_fmt << 8) | 778145132Sanholt RADEON_GMC_SRC_DATATYPE_COLOR | 779145132Sanholt RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); 78095584Sanholt 781182080Srnoland if (dev_priv->sarea_priv->pfCurrentPage == 1) { 782145132Sanholt OUT_RING(dev_priv->front_pitch_offset); 783145132Sanholt } else { 784145132Sanholt OUT_RING(dev_priv->back_pitch_offset); 785145132Sanholt } 786112015Sanholt 787145132Sanholt OUT_RING(color); 78895584Sanholt 789145132Sanholt OUT_RING((x << 16) | y); 790145132Sanholt OUT_RING((w << 16) | h); 79195584Sanholt 79295584Sanholt ADVANCE_RING(); 79395584Sanholt} 79495584Sanholt 795189499Srnolandstatic void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv) 79695584Sanholt{ 797112015Sanholt /* Collapse various things into a wait flag -- trying to 798112015Sanholt * guess if userspase slept -- better just to have them tell us. 799112015Sanholt */ 800112015Sanholt if (dev_priv->stats.last_frame_reads > 1 || 801112015Sanholt dev_priv->stats.last_clear_reads > dev_priv->stats.clears) { 802112015Sanholt dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 803112015Sanholt } 804112015Sanholt 805112015Sanholt if (dev_priv->stats.freelist_loops) { 806112015Sanholt dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 807112015Sanholt } 808112015Sanholt 809112015Sanholt /* Purple box for page flipping 810112015Sanholt */ 811145132Sanholt if (dev_priv->stats.boxes & RADEON_BOX_FLIP) 812145132Sanholt radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255); 813112015Sanholt 814112015Sanholt /* Red box if we have to wait for idle at any point 815112015Sanholt */ 816145132Sanholt if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) 817145132Sanholt radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0); 818112015Sanholt 819112015Sanholt /* Blue box: lost context? 820112015Sanholt */ 821112015Sanholt 822112015Sanholt /* Yellow box for texture swaps 823112015Sanholt */ 824145132Sanholt if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) 825145132Sanholt radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0); 826112015Sanholt 827112015Sanholt /* Green box if hardware never idles (as far as we can tell) 828112015Sanholt */ 829145132Sanholt if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) 830145132Sanholt radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); 831112015Sanholt 832145132Sanholt /* Draw bars indicating number of buffers allocated 833112015Sanholt * (not a great measure, easily confused) 834112015Sanholt */ 835112015Sanholt if (dev_priv->stats.requested_bufs) { 836112015Sanholt if (dev_priv->stats.requested_bufs > 100) 837112015Sanholt dev_priv->stats.requested_bufs = 100; 838112015Sanholt 839145132Sanholt radeon_clear_box(dev_priv, 4, 16, 840145132Sanholt dev_priv->stats.requested_bufs, 4, 841145132Sanholt 196, 128, 128); 84295584Sanholt } 84395584Sanholt 844145132Sanholt memset(&dev_priv->stats, 0, sizeof(dev_priv->stats)); 84595584Sanholt 846112015Sanholt} 847145132Sanholt 84895584Sanholt/* ================================================================ 84995584Sanholt * CP command dispatch functions 85095584Sanholt */ 85195584Sanholt 852182080Srnolandstatic void radeon_cp_dispatch_clear(struct drm_device * dev, 853145132Sanholt drm_radeon_clear_t * clear, 854145132Sanholt drm_radeon_clear_rect_t * depth_boxes) 85595584Sanholt{ 85695584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 85795584Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 858112015Sanholt drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; 85995584Sanholt int nbox = sarea_priv->nbox; 860182080Srnoland struct drm_clip_rect *pbox = sarea_priv->boxes; 86195584Sanholt unsigned int flags = clear->flags; 862145132Sanholt u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0; 86395584Sanholt int i; 86495584Sanholt RING_LOCALS; 865145132Sanholt DRM_DEBUG("flags = 0x%x\n", flags); 86695584Sanholt 867112015Sanholt dev_priv->stats.clears++; 868112015Sanholt 869189499Srnoland if (sarea_priv->pfCurrentPage == 1) { 87095584Sanholt unsigned int tmp = flags; 87195584Sanholt 87295584Sanholt flags &= ~(RADEON_FRONT | RADEON_BACK); 873145132Sanholt if (tmp & RADEON_FRONT) 874145132Sanholt flags |= RADEON_BACK; 875145132Sanholt if (tmp & RADEON_BACK) 876145132Sanholt flags |= RADEON_FRONT; 87795584Sanholt } 87895584Sanholt 879145132Sanholt if (flags & (RADEON_FRONT | RADEON_BACK)) { 88095584Sanholt 881145132Sanholt BEGIN_RING(4); 88295584Sanholt 883112015Sanholt /* Ensure the 3D stream is idle before doing a 884112015Sanholt * 2D fill to clear the front or back buffer. 885112015Sanholt */ 886112015Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 88795584Sanholt 888145132Sanholt OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0)); 889145132Sanholt OUT_RING(clear->color_mask); 890145132Sanholt 891112015Sanholt ADVANCE_RING(); 89295584Sanholt 893112015Sanholt /* Make sure we restore the 3D state next time. 894112015Sanholt */ 895189499Srnoland sarea_priv->ctx_owner = 0; 89695584Sanholt 897145132Sanholt for (i = 0; i < nbox; i++) { 898112015Sanholt int x = pbox[i].x1; 899112015Sanholt int y = pbox[i].y1; 900112015Sanholt int w = pbox[i].x2 - x; 901112015Sanholt int h = pbox[i].y2 - y; 90295584Sanholt 903182080Srnoland DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n", 904145132Sanholt x, y, w, h, flags); 905112015Sanholt 906145132Sanholt if (flags & RADEON_FRONT) { 907145132Sanholt BEGIN_RING(6); 908112015Sanholt 909145132Sanholt OUT_RING(CP_PACKET3 910145132Sanholt (RADEON_CNTL_PAINT_MULTI, 4)); 911145132Sanholt OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 912145132Sanholt RADEON_GMC_BRUSH_SOLID_COLOR | 913145132Sanholt (dev_priv-> 914145132Sanholt color_fmt << 8) | 915145132Sanholt RADEON_GMC_SRC_DATATYPE_COLOR | 916145132Sanholt RADEON_ROP3_P | 917145132Sanholt RADEON_GMC_CLR_CMP_CNTL_DIS); 918145132Sanholt 919145132Sanholt OUT_RING(dev_priv->front_pitch_offset); 920145132Sanholt OUT_RING(clear->clear_color); 921145132Sanholt 922145132Sanholt OUT_RING((x << 16) | y); 923145132Sanholt OUT_RING((w << 16) | h); 924145132Sanholt 925112015Sanholt ADVANCE_RING(); 926112015Sanholt } 927112015Sanholt 928145132Sanholt if (flags & RADEON_BACK) { 929145132Sanholt BEGIN_RING(6); 930112015Sanholt 931145132Sanholt OUT_RING(CP_PACKET3 932145132Sanholt (RADEON_CNTL_PAINT_MULTI, 4)); 933145132Sanholt OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 934145132Sanholt RADEON_GMC_BRUSH_SOLID_COLOR | 935145132Sanholt (dev_priv-> 936145132Sanholt color_fmt << 8) | 937145132Sanholt RADEON_GMC_SRC_DATATYPE_COLOR | 938145132Sanholt RADEON_ROP3_P | 939145132Sanholt RADEON_GMC_CLR_CMP_CNTL_DIS); 940145132Sanholt 941145132Sanholt OUT_RING(dev_priv->back_pitch_offset); 942145132Sanholt OUT_RING(clear->clear_color); 943145132Sanholt 944145132Sanholt OUT_RING((x << 16) | y); 945145132Sanholt OUT_RING((w << 16) | h); 946145132Sanholt 947112015Sanholt ADVANCE_RING(); 948112015Sanholt } 94995584Sanholt } 950112015Sanholt } 95195584Sanholt 952145132Sanholt /* hyper z clear */ 953145132Sanholt /* no docs available, based on reverse engeneering by Stephane Marchesin */ 954157617Sanholt if ((flags & (RADEON_DEPTH | RADEON_STENCIL)) 955157617Sanholt && (flags & RADEON_CLEAR_FASTZ)) { 956145132Sanholt 957145132Sanholt int i; 958157617Sanholt int depthpixperline = 959157617Sanholt dev_priv->depth_fmt == 960157617Sanholt RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch / 961157617Sanholt 2) : (dev_priv-> 962157617Sanholt depth_pitch / 4); 963157617Sanholt 964145132Sanholt u32 clearmask; 965145132Sanholt 966145132Sanholt u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth | 967157617Sanholt ((clear->depth_mask & 0xff) << 24); 968157617Sanholt 969145132Sanholt /* Make sure we restore the 3D state next time. 970145132Sanholt * we haven't touched any "normal" state - still need this? 971145132Sanholt */ 972189499Srnoland sarea_priv->ctx_owner = 0; 973145132Sanholt 974182080Srnoland if ((dev_priv->flags & RADEON_HAS_HIERZ) 975157617Sanholt && (flags & RADEON_USE_HIERZ)) { 976157617Sanholt /* FIXME : reverse engineer that for Rx00 cards */ 977157617Sanholt /* FIXME : the mask supposedly contains low-res z values. So can't set 978157617Sanholt just to the max (0xff? or actually 0x3fff?), need to take z clear 979157617Sanholt value into account? */ 980157617Sanholt /* pattern seems to work for r100, though get slight 981157617Sanholt rendering errors with glxgears. If hierz is not enabled for r100, 982157617Sanholt only 4 bits which indicate clear (15,16,31,32, all zero) matter, the 983157617Sanholt other ones are ignored, and the same clear mask can be used. That's 984157617Sanholt very different behaviour than R200 which needs different clear mask 985157617Sanholt and different number of tiles to clear if hierz is enabled or not !?! 986157617Sanholt */ 987157617Sanholt clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f; 988157617Sanholt } else { 989157617Sanholt /* clear mask : chooses the clearing pattern. 990157617Sanholt rv250: could be used to clear only parts of macrotiles 991157617Sanholt (but that would get really complicated...)? 992157617Sanholt bit 0 and 1 (either or both of them ?!?!) are used to 993157617Sanholt not clear tile (or maybe one of the bits indicates if the tile is 994157617Sanholt compressed or not), bit 2 and 3 to not clear tile 1,...,. 995157617Sanholt Pattern is as follows: 996157617Sanholt | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29| 997157617Sanholt bits ------------------------------------------------- 998157617Sanholt | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31| 999157617Sanholt rv100: clearmask covers 2x8 4x1 tiles, but one clear still 1000157617Sanholt covers 256 pixels ?!? 1001157617Sanholt */ 1002145132Sanholt clearmask = 0x0; 1003145132Sanholt } 1004145132Sanholt 1005157617Sanholt BEGIN_RING(8); 1006145132Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 1007157617Sanholt OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE, 1008157617Sanholt tempRB3D_DEPTHCLEARVALUE); 1009145132Sanholt /* what offset is this exactly ? */ 1010157617Sanholt OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0); 1011145132Sanholt /* need ctlstat, otherwise get some strange black flickering */ 1012157617Sanholt OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT, 1013157617Sanholt RADEON_RB3D_ZC_FLUSH_ALL); 1014145132Sanholt ADVANCE_RING(); 1015145132Sanholt 1016145132Sanholt for (i = 0; i < nbox; i++) { 1017145132Sanholt int tileoffset, nrtilesx, nrtilesy, j; 1018145132Sanholt /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ 1019182080Srnoland if ((dev_priv->flags & RADEON_HAS_HIERZ) 1020189499Srnoland && !(dev_priv->microcode_version == UCODE_R200)) { 1021145132Sanholt /* FIXME : figure this out for r200 (when hierz is enabled). Or 1022145132Sanholt maybe r200 actually doesn't need to put the low-res z value into 1023145132Sanholt the tile cache like r100, but just needs to clear the hi-level z-buffer? 1024145132Sanholt Works for R100, both with hierz and without. 1025145132Sanholt R100 seems to operate on 2x1 8x8 tiles, but... 1026145132Sanholt odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially 1027145132Sanholt problematic with resolutions which are not 64 pix aligned? */ 1028157617Sanholt tileoffset = 1029157617Sanholt ((pbox[i].y1 >> 3) * depthpixperline + 1030157617Sanholt pbox[i].x1) >> 6; 1031157617Sanholt nrtilesx = 1032157617Sanholt ((pbox[i].x2 & ~63) - 1033157617Sanholt (pbox[i].x1 & ~63)) >> 4; 1034157617Sanholt nrtilesy = 1035157617Sanholt (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3); 1036145132Sanholt for (j = 0; j <= nrtilesy; j++) { 1037157617Sanholt BEGIN_RING(4); 1038157617Sanholt OUT_RING(CP_PACKET3 1039157617Sanholt (RADEON_3D_CLEAR_ZMASK, 2)); 1040145132Sanholt /* first tile */ 1041157617Sanholt OUT_RING(tileoffset * 8); 1042145132Sanholt /* the number of tiles to clear */ 1043157617Sanholt OUT_RING(nrtilesx + 4); 1044145132Sanholt /* clear mask : chooses the clearing pattern. */ 1045157617Sanholt OUT_RING(clearmask); 1046145132Sanholt ADVANCE_RING(); 1047145132Sanholt tileoffset += depthpixperline >> 6; 1048145132Sanholt } 1049189499Srnoland } else if (dev_priv->microcode_version == UCODE_R200) { 1050145132Sanholt /* works for rv250. */ 1051145132Sanholt /* find first macro tile (8x2 4x4 z-pixels on rv250) */ 1052157617Sanholt tileoffset = 1053157617Sanholt ((pbox[i].y1 >> 3) * depthpixperline + 1054157617Sanholt pbox[i].x1) >> 5; 1055157617Sanholt nrtilesx = 1056157617Sanholt (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5); 1057157617Sanholt nrtilesy = 1058157617Sanholt (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3); 1059145132Sanholt for (j = 0; j <= nrtilesy; j++) { 1060157617Sanholt BEGIN_RING(4); 1061157617Sanholt OUT_RING(CP_PACKET3 1062157617Sanholt (RADEON_3D_CLEAR_ZMASK, 2)); 1063145132Sanholt /* first tile */ 1064145132Sanholt /* judging by the first tile offset needed, could possibly 1065145132Sanholt directly address/clear 4x4 tiles instead of 8x2 * 4x4 1066145132Sanholt macro tiles, though would still need clear mask for 1067145132Sanholt right/bottom if truely 4x4 granularity is desired ? */ 1068157617Sanholt OUT_RING(tileoffset * 16); 1069145132Sanholt /* the number of tiles to clear */ 1070157617Sanholt OUT_RING(nrtilesx + 1); 1071145132Sanholt /* clear mask : chooses the clearing pattern. */ 1072157617Sanholt OUT_RING(clearmask); 1073145132Sanholt ADVANCE_RING(); 1074145132Sanholt tileoffset += depthpixperline >> 5; 1075145132Sanholt } 1076157617Sanholt } else { /* rv 100 */ 1077145132Sanholt /* rv100 might not need 64 pix alignment, who knows */ 1078145132Sanholt /* offsets are, hmm, weird */ 1079157617Sanholt tileoffset = 1080157617Sanholt ((pbox[i].y1 >> 4) * depthpixperline + 1081157617Sanholt pbox[i].x1) >> 6; 1082157617Sanholt nrtilesx = 1083157617Sanholt ((pbox[i].x2 & ~63) - 1084157617Sanholt (pbox[i].x1 & ~63)) >> 4; 1085157617Sanholt nrtilesy = 1086157617Sanholt (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4); 1087145132Sanholt for (j = 0; j <= nrtilesy; j++) { 1088157617Sanholt BEGIN_RING(4); 1089157617Sanholt OUT_RING(CP_PACKET3 1090157617Sanholt (RADEON_3D_CLEAR_ZMASK, 2)); 1091157617Sanholt OUT_RING(tileoffset * 128); 1092145132Sanholt /* the number of tiles to clear */ 1093157617Sanholt OUT_RING(nrtilesx + 4); 1094145132Sanholt /* clear mask : chooses the clearing pattern. */ 1095157617Sanholt OUT_RING(clearmask); 1096145132Sanholt ADVANCE_RING(); 1097145132Sanholt tileoffset += depthpixperline >> 6; 1098145132Sanholt } 1099145132Sanholt } 1100145132Sanholt } 1101145132Sanholt 1102145132Sanholt /* TODO don't always clear all hi-level z tiles */ 1103182080Srnoland if ((dev_priv->flags & RADEON_HAS_HIERZ) 1104189499Srnoland && (dev_priv->microcode_version == UCODE_R200) 1105157617Sanholt && (flags & RADEON_USE_HIERZ)) 1106157617Sanholt /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ 1107157617Sanholt /* FIXME : the mask supposedly contains low-res z values. So can't set 1108157617Sanholt just to the max (0xff? or actually 0x3fff?), need to take z clear 1109157617Sanholt value into account? */ 1110145132Sanholt { 1111157617Sanholt BEGIN_RING(4); 1112157617Sanholt OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2)); 1113157617Sanholt OUT_RING(0x0); /* First tile */ 1114157617Sanholt OUT_RING(0x3cc0); 1115157617Sanholt OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f); 1116145132Sanholt ADVANCE_RING(); 1117145132Sanholt } 1118145132Sanholt } 1119145132Sanholt 1120112015Sanholt /* We have to clear the depth and/or stencil buffers by 1121112015Sanholt * rendering a quad into just those buffers. Thus, we have to 1122112015Sanholt * make sure the 3D engine is configured correctly. 1123112015Sanholt */ 1124189499Srnoland else if ((dev_priv->microcode_version == UCODE_R200) && 1125189499Srnoland (flags & (RADEON_DEPTH | RADEON_STENCIL))) { 112695584Sanholt 1127112015Sanholt int tempPP_CNTL; 1128112015Sanholt int tempRE_CNTL; 1129112015Sanholt int tempRB3D_CNTL; 1130112015Sanholt int tempRB3D_ZSTENCILCNTL; 1131112015Sanholt int tempRB3D_STENCILREFMASK; 1132112015Sanholt int tempRB3D_PLANEMASK; 1133112015Sanholt int tempSE_CNTL; 1134112015Sanholt int tempSE_VTE_CNTL; 1135112015Sanholt int tempSE_VTX_FMT_0; 1136112015Sanholt int tempSE_VTX_FMT_1; 1137112015Sanholt int tempSE_VAP_CNTL; 1138112015Sanholt int tempRE_AUX_SCISSOR_CNTL; 113995584Sanholt 1140112015Sanholt tempPP_CNTL = 0; 1141112015Sanholt tempRE_CNTL = 0; 114295584Sanholt 1143112015Sanholt tempRB3D_CNTL = depth_clear->rb3d_cntl; 114495584Sanholt 1145112015Sanholt tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl; 1146112015Sanholt tempRB3D_STENCILREFMASK = 0x0; 1147112015Sanholt 1148112015Sanholt tempSE_CNTL = depth_clear->se_cntl; 1149112015Sanholt 1150112015Sanholt /* Disable TCL */ 1151112015Sanholt 1152145132Sanholt tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */ 1153145132Sanholt (0x9 << 1154145132Sanholt SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT)); 1155112015Sanholt 1156112015Sanholt tempRB3D_PLANEMASK = 0x0; 1157112015Sanholt 1158112015Sanholt tempRE_AUX_SCISSOR_CNTL = 0x0; 1159112015Sanholt 1160112015Sanholt tempSE_VTE_CNTL = 1161145132Sanholt SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK; 1162112015Sanholt 1163145132Sanholt /* Vertex format (X, Y, Z, W) */ 1164112015Sanholt tempSE_VTX_FMT_0 = 1165145132Sanholt SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK | 1166145132Sanholt SE_VTX_FMT_0__VTX_W0_PRESENT_MASK; 1167112015Sanholt tempSE_VTX_FMT_1 = 0x0; 1168112015Sanholt 1169145132Sanholt /* 1170145132Sanholt * Depth buffer specific enables 1171112015Sanholt */ 1172112015Sanholt if (flags & RADEON_DEPTH) { 1173112015Sanholt /* Enable depth buffer */ 1174112015Sanholt tempRB3D_CNTL |= RADEON_Z_ENABLE; 1175112015Sanholt } else { 1176112015Sanholt /* Disable depth buffer */ 1177112015Sanholt tempRB3D_CNTL &= ~RADEON_Z_ENABLE; 117895584Sanholt } 117995584Sanholt 1180145132Sanholt /* 1181112015Sanholt * Stencil buffer specific enables 1182112015Sanholt */ 1183145132Sanholt if (flags & RADEON_STENCIL) { 1184145132Sanholt tempRB3D_CNTL |= RADEON_STENCIL_ENABLE; 1185145132Sanholt tempRB3D_STENCILREFMASK = clear->depth_mask; 1186112015Sanholt } else { 1187112015Sanholt tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE; 1188112015Sanholt tempRB3D_STENCILREFMASK = 0x00000000; 1189112015Sanholt } 119095584Sanholt 1191145132Sanholt if (flags & RADEON_USE_COMP_ZBUF) { 1192145132Sanholt tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE | 1193157617Sanholt RADEON_Z_DECOMPRESSION_ENABLE; 1194145132Sanholt } 1195145132Sanholt if (flags & RADEON_USE_HIERZ) { 1196145132Sanholt tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE; 1197145132Sanholt } 1198145132Sanholt 1199145132Sanholt BEGIN_RING(26); 1200112015Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 120195584Sanholt 1202145132Sanholt OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL); 1203145132Sanholt OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL); 1204145132Sanholt OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL); 1205145132Sanholt OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL); 1206145132Sanholt OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, 1207145132Sanholt tempRB3D_STENCILREFMASK); 1208145132Sanholt OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK); 1209145132Sanholt OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL); 1210145132Sanholt OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL); 1211145132Sanholt OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0); 1212145132Sanholt OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1); 1213145132Sanholt OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL); 1214145132Sanholt OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL); 1215112015Sanholt ADVANCE_RING(); 121695584Sanholt 1217112015Sanholt /* Make sure we restore the 3D state next time. 1218112015Sanholt */ 1219189499Srnoland sarea_priv->ctx_owner = 0; 122095584Sanholt 1221145132Sanholt for (i = 0; i < nbox; i++) { 1222145132Sanholt 1223145132Sanholt /* Funny that this should be required -- 1224112015Sanholt * sets top-left? 1225112015Sanholt */ 1226145132Sanholt radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 1227112015Sanholt 1228145132Sanholt BEGIN_RING(14); 1229145132Sanholt OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12)); 1230145132Sanholt OUT_RING((RADEON_PRIM_TYPE_RECT_LIST | 1231145132Sanholt RADEON_PRIM_WALK_RING | 1232145132Sanholt (3 << RADEON_NUM_VERTICES_SHIFT))); 1233145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1234145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y1]); 1235145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1236145132Sanholt OUT_RING(0x3f800000); 1237145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1238145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1239145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1240145132Sanholt OUT_RING(0x3f800000); 1241145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X2]); 1242145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1243145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1244145132Sanholt OUT_RING(0x3f800000); 124595584Sanholt ADVANCE_RING(); 124695584Sanholt } 1247145132Sanholt } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) { 124895584Sanholt 1249145132Sanholt int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl; 1250157617Sanholt 1251112015Sanholt rb3d_cntl = depth_clear->rb3d_cntl; 1252112015Sanholt 1253145132Sanholt if (flags & RADEON_DEPTH) { 1254145132Sanholt rb3d_cntl |= RADEON_Z_ENABLE; 1255112015Sanholt } else { 1256112015Sanholt rb3d_cntl &= ~RADEON_Z_ENABLE; 1257112015Sanholt } 125895584Sanholt 1259145132Sanholt if (flags & RADEON_STENCIL) { 1260145132Sanholt rb3d_cntl |= RADEON_STENCIL_ENABLE; 1261145132Sanholt rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */ 1262112015Sanholt } else { 1263112015Sanholt rb3d_cntl &= ~RADEON_STENCIL_ENABLE; 1264112015Sanholt rb3d_stencilrefmask = 0x00000000; 1265112015Sanholt } 126695584Sanholt 1267145132Sanholt if (flags & RADEON_USE_COMP_ZBUF) { 1268145132Sanholt tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE | 1269157617Sanholt RADEON_Z_DECOMPRESSION_ENABLE; 1270145132Sanholt } 1271145132Sanholt if (flags & RADEON_USE_HIERZ) { 1272145132Sanholt tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE; 1273145132Sanholt } 1274145132Sanholt 1275145132Sanholt BEGIN_RING(13); 1276112015Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 1277112015Sanholt 1278145132Sanholt OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1)); 1279145132Sanholt OUT_RING(0x00000000); 1280145132Sanholt OUT_RING(rb3d_cntl); 1281145132Sanholt 1282145132Sanholt OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL); 1283145132Sanholt OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask); 1284145132Sanholt OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000); 1285145132Sanholt OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl); 1286112015Sanholt ADVANCE_RING(); 1287112015Sanholt 1288112015Sanholt /* Make sure we restore the 3D state next time. 1289112015Sanholt */ 1290189499Srnoland sarea_priv->ctx_owner = 0; 1291112015Sanholt 1292145132Sanholt for (i = 0; i < nbox; i++) { 1293145132Sanholt 1294145132Sanholt /* Funny that this should be required -- 1295112015Sanholt * sets top-left? 129695584Sanholt */ 1297145132Sanholt radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 129895584Sanholt 1299145132Sanholt BEGIN_RING(15); 130095584Sanholt 1301145132Sanholt OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13)); 1302145132Sanholt OUT_RING(RADEON_VTX_Z_PRESENT | 1303145132Sanholt RADEON_VTX_PKCOLOR_PRESENT); 1304145132Sanholt OUT_RING((RADEON_PRIM_TYPE_RECT_LIST | 1305145132Sanholt RADEON_PRIM_WALK_RING | 1306145132Sanholt RADEON_MAOS_ENABLE | 1307145132Sanholt RADEON_VTX_FMT_RADEON_MODE | 1308145132Sanholt (3 << RADEON_NUM_VERTICES_SHIFT))); 130995584Sanholt 1310145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1311145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y1]); 1312145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1313145132Sanholt OUT_RING(0x0); 1314112015Sanholt 1315145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1316145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1317145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1318145132Sanholt OUT_RING(0x0); 131995584Sanholt 1320145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_X2]); 1321145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1322145132Sanholt OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1323145132Sanholt OUT_RING(0x0); 132495584Sanholt 132595584Sanholt ADVANCE_RING(); 132695584Sanholt } 132795584Sanholt } 132895584Sanholt 132995584Sanholt /* Increment the clear counter. The client-side 3D driver must 133095584Sanholt * wait on this value before performing the clear ioctl. We 133195584Sanholt * need this because the card's so damned fast... 133295584Sanholt */ 1333189499Srnoland sarea_priv->last_clear++; 133495584Sanholt 1335145132Sanholt BEGIN_RING(4); 133695584Sanholt 1337189499Srnoland RADEON_CLEAR_AGE(sarea_priv->last_clear); 133895584Sanholt RADEON_WAIT_UNTIL_IDLE(); 133995584Sanholt 134095584Sanholt ADVANCE_RING(); 134195584Sanholt} 134295584Sanholt 1343189499Srnolandstatic void radeon_cp_dispatch_swap(struct drm_device *dev) 134495584Sanholt{ 134595584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 134695584Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 134795584Sanholt int nbox = sarea_priv->nbox; 1348182080Srnoland struct drm_clip_rect *pbox = sarea_priv->boxes; 134995584Sanholt int i; 135095584Sanholt RING_LOCALS; 1351145132Sanholt DRM_DEBUG("\n"); 135295584Sanholt 135395584Sanholt /* Do some trivial performance monitoring... 135495584Sanholt */ 1355112015Sanholt if (dev_priv->do_boxes) 1356145132Sanholt radeon_cp_performance_boxes(dev_priv); 135795584Sanholt 135895584Sanholt /* Wait for the 3D stream to idle before dispatching the bitblt. 135995584Sanholt * This will prevent data corruption between the two streams. 136095584Sanholt */ 1361145132Sanholt BEGIN_RING(2); 136295584Sanholt 136395584Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 136495584Sanholt 136595584Sanholt ADVANCE_RING(); 136695584Sanholt 1367145132Sanholt for (i = 0; i < nbox; i++) { 136895584Sanholt int x = pbox[i].x1; 136995584Sanholt int y = pbox[i].y1; 137095584Sanholt int w = pbox[i].x2 - x; 137195584Sanholt int h = pbox[i].y2 - y; 137295584Sanholt 1373182080Srnoland DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h); 137495584Sanholt 1375182080Srnoland BEGIN_RING(9); 137695584Sanholt 1377182080Srnoland OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0)); 1378145132Sanholt OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 1379145132Sanholt RADEON_GMC_DST_PITCH_OFFSET_CNTL | 1380145132Sanholt RADEON_GMC_BRUSH_NONE | 1381145132Sanholt (dev_priv->color_fmt << 8) | 1382145132Sanholt RADEON_GMC_SRC_DATATYPE_COLOR | 1383145132Sanholt RADEON_ROP3_S | 1384145132Sanholt RADEON_DP_SRC_SOURCE_MEMORY | 1385145132Sanholt RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); 1386145132Sanholt 1387112015Sanholt /* Make this work even if front & back are flipped: 1388112015Sanholt */ 1389182080Srnoland OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); 1390189499Srnoland if (sarea_priv->pfCurrentPage == 0) { 1391145132Sanholt OUT_RING(dev_priv->back_pitch_offset); 1392145132Sanholt OUT_RING(dev_priv->front_pitch_offset); 1393145132Sanholt } else { 1394145132Sanholt OUT_RING(dev_priv->front_pitch_offset); 1395145132Sanholt OUT_RING(dev_priv->back_pitch_offset); 1396112015Sanholt } 139795584Sanholt 1398182080Srnoland OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2)); 1399145132Sanholt OUT_RING((x << 16) | y); 1400145132Sanholt OUT_RING((x << 16) | y); 1401145132Sanholt OUT_RING((w << 16) | h); 140295584Sanholt 140395584Sanholt ADVANCE_RING(); 140495584Sanholt } 140595584Sanholt 140695584Sanholt /* Increment the frame counter. The client-side 3D driver must 140795584Sanholt * throttle the framerate by waiting for this value before 140895584Sanholt * performing the swapbuffer ioctl. 140995584Sanholt */ 1410189499Srnoland sarea_priv->last_frame++; 141195584Sanholt 1412145132Sanholt BEGIN_RING(4); 141395584Sanholt 1414189499Srnoland RADEON_FRAME_AGE(sarea_priv->last_frame); 141595584Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 141695584Sanholt 141795584Sanholt ADVANCE_RING(); 141895584Sanholt} 141995584Sanholt 1420189499Srnolandstatic void radeon_cp_dispatch_flip(struct drm_device *dev) 142195584Sanholt{ 142295584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 1423207066Srnoland struct drm_sarea *sarea = (struct drm_sarea *)dev_priv->sarea->virtual; 1424182080Srnoland int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) 1425145132Sanholt ? dev_priv->front_offset : dev_priv->back_offset; 142695584Sanholt RING_LOCALS; 1427182080Srnoland DRM_DEBUG("pfCurrentPage=%d\n", 1428182080Srnoland dev_priv->sarea_priv->pfCurrentPage); 142995584Sanholt 143095584Sanholt /* Do some trivial performance monitoring... 143195584Sanholt */ 1432112015Sanholt if (dev_priv->do_boxes) { 1433112015Sanholt dev_priv->stats.boxes |= RADEON_BOX_FLIP; 1434145132Sanholt radeon_cp_performance_boxes(dev_priv); 1435112015Sanholt } 143695584Sanholt 1437112015Sanholt /* Update the frame offsets for both CRTCs 1438112015Sanholt */ 1439145132Sanholt BEGIN_RING(6); 144095584Sanholt 144195584Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 1442145132Sanholt OUT_RING_REG(RADEON_CRTC_OFFSET, 1443145132Sanholt ((sarea->frame.y * dev_priv->front_pitch + 1444145132Sanholt sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) 1445145132Sanholt + offset); 1446145132Sanholt OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base 1447145132Sanholt + offset); 144895584Sanholt 144995584Sanholt ADVANCE_RING(); 145095584Sanholt 145195584Sanholt /* Increment the frame counter. The client-side 3D driver must 145295584Sanholt * throttle the framerate by waiting for this value before 145395584Sanholt * performing the swapbuffer ioctl. 145495584Sanholt */ 145595584Sanholt dev_priv->sarea_priv->last_frame++; 1456182080Srnoland dev_priv->sarea_priv->pfCurrentPage = 1457182080Srnoland 1 - dev_priv->sarea_priv->pfCurrentPage; 145895584Sanholt 1459145132Sanholt BEGIN_RING(2); 146095584Sanholt 1461145132Sanholt RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); 146295584Sanholt 146395584Sanholt ADVANCE_RING(); 146495584Sanholt} 146595584Sanholt 1466145132Sanholtstatic int bad_prim_vertex_nr(int primitive, int nr) 1467112015Sanholt{ 1468112015Sanholt switch (primitive & RADEON_PRIM_TYPE_MASK) { 1469112015Sanholt case RADEON_PRIM_TYPE_NONE: 1470112015Sanholt case RADEON_PRIM_TYPE_POINT: 1471112015Sanholt return nr < 1; 1472112015Sanholt case RADEON_PRIM_TYPE_LINE: 1473112015Sanholt return (nr & 1) || nr == 0; 1474112015Sanholt case RADEON_PRIM_TYPE_LINE_STRIP: 1475112015Sanholt return nr < 2; 1476112015Sanholt case RADEON_PRIM_TYPE_TRI_LIST: 1477112015Sanholt case RADEON_PRIM_TYPE_3VRT_POINT_LIST: 1478112015Sanholt case RADEON_PRIM_TYPE_3VRT_LINE_LIST: 1479112015Sanholt case RADEON_PRIM_TYPE_RECT_LIST: 1480112015Sanholt return nr % 3 || nr == 0; 1481112015Sanholt case RADEON_PRIM_TYPE_TRI_FAN: 1482112015Sanholt case RADEON_PRIM_TYPE_TRI_STRIP: 1483112015Sanholt return nr < 3; 1484112015Sanholt default: 1485112015Sanholt return 1; 1486145132Sanholt } 1487112015Sanholt} 1488112015Sanholt 1489112015Sanholttypedef struct { 1490112015Sanholt unsigned int start; 1491112015Sanholt unsigned int finish; 1492112015Sanholt unsigned int prim; 1493112015Sanholt unsigned int numverts; 1494145132Sanholt unsigned int offset; 1495145132Sanholt unsigned int vc_format; 1496112015Sanholt} drm_radeon_tcl_prim_t; 1497112015Sanholt 1498182080Srnolandstatic void radeon_cp_dispatch_vertex(struct drm_device * dev, 1499182080Srnoland struct drm_buf * buf, 1500145132Sanholt drm_radeon_tcl_prim_t * prim) 150195584Sanholt{ 150295584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 1503119098Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 1504119895Sanholt int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; 1505112015Sanholt int numverts = (int)prim->numverts; 1506119098Sanholt int nbox = sarea_priv->nbox; 150795584Sanholt int i = 0; 150895584Sanholt RING_LOCALS; 150995584Sanholt 1510112015Sanholt DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n", 1511112015Sanholt prim->prim, 1512145132Sanholt prim->vc_format, prim->start, prim->finish, prim->numverts); 151395584Sanholt 1514145132Sanholt if (bad_prim_vertex_nr(prim->prim, prim->numverts)) { 1515145132Sanholt DRM_ERROR("bad prim %x numverts %d\n", 1516145132Sanholt prim->prim, prim->numverts); 1517112015Sanholt return; 1518112015Sanholt } 151995584Sanholt 1520112015Sanholt do { 1521112015Sanholt /* Emit the next cliprect */ 1522145132Sanholt if (i < nbox) { 1523145132Sanholt radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 152495584Sanholt } 152595584Sanholt 1526112015Sanholt /* Emit the vertex buffer rendering commands */ 1527145132Sanholt BEGIN_RING(5); 152895584Sanholt 1529145132Sanholt OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3)); 1530145132Sanholt OUT_RING(offset); 1531145132Sanholt OUT_RING(numverts); 1532145132Sanholt OUT_RING(prim->vc_format); 1533145132Sanholt OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST | 1534145132Sanholt RADEON_COLOR_ORDER_RGBA | 1535145132Sanholt RADEON_VTX_FMT_RADEON_MODE | 1536145132Sanholt (numverts << RADEON_NUM_VERTICES_SHIFT)); 153795584Sanholt 1538112015Sanholt ADVANCE_RING(); 153995584Sanholt 1540112015Sanholt i++; 1541145132Sanholt } while (i < nbox); 1542112015Sanholt} 154395584Sanholt 1544196470Srnolandvoid radeon_cp_discard_buffer(struct drm_device *dev, struct drm_buf *buf) 1545112015Sanholt{ 1546112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 1547112015Sanholt drm_radeon_buf_priv_t *buf_priv = buf->dev_private; 1548112015Sanholt RING_LOCALS; 154995584Sanholt 1550112015Sanholt buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; 155195584Sanholt 1552112015Sanholt /* Emit the vertex buffer age */ 1553189499Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { 1554189499Srnoland BEGIN_RING(3); 1555189499Srnoland R600_DISPATCH_AGE(buf_priv->age); 1556189499Srnoland ADVANCE_RING(); 1557189499Srnoland } else { 1558189499Srnoland BEGIN_RING(2); 1559189499Srnoland RADEON_DISPATCH_AGE(buf_priv->age); 1560189499Srnoland ADVANCE_RING(); 1561189499Srnoland } 156295584Sanholt 1563112015Sanholt buf->pending = 1; 1564112015Sanholt buf->used = 0; 156595584Sanholt} 156695584Sanholt 1567182080Srnolandstatic void radeon_cp_dispatch_indirect(struct drm_device * dev, 1568182080Srnoland struct drm_buf * buf, int start, int end) 156995584Sanholt{ 157095584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 157195584Sanholt RING_LOCALS; 1572182080Srnoland DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end); 157395584Sanholt 1574145132Sanholt if (start != end) { 1575119895Sanholt int offset = (dev_priv->gart_buffers_offset 157695584Sanholt + buf->offset + start); 157795584Sanholt int dwords = (end - start + 3) / sizeof(u32); 157895584Sanholt 157995584Sanholt /* Indirect buffer data must be an even number of 158095584Sanholt * dwords, so if we've been given an odd number we must 158195584Sanholt * pad the data with a Type-2 CP packet. 158295584Sanholt */ 1583145132Sanholt if (dwords & 1) { 158495584Sanholt u32 *data = (u32 *) 1585207066Srnoland ((char *)dev->agp_buffer_map->virtual 1586145132Sanholt + buf->offset + start); 158795584Sanholt data[dwords++] = RADEON_CP_PACKET2; 158895584Sanholt } 158995584Sanholt 159095584Sanholt /* Fire off the indirect buffer */ 1591145132Sanholt BEGIN_RING(3); 159295584Sanholt 1593145132Sanholt OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); 1594145132Sanholt OUT_RING(offset); 1595145132Sanholt OUT_RING(dwords); 159695584Sanholt 159795584Sanholt ADVANCE_RING(); 159895584Sanholt } 1599112015Sanholt} 160095584Sanholt 1601189499Srnolandstatic void radeon_cp_dispatch_indices(struct drm_device *dev, 1602182080Srnoland struct drm_buf * elt_buf, 1603145132Sanholt drm_radeon_tcl_prim_t * prim) 160495584Sanholt{ 160595584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 1606119098Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 1607119895Sanholt int offset = dev_priv->gart_buffers_offset + prim->offset; 160895584Sanholt u32 *data; 160995584Sanholt int dwords; 161095584Sanholt int i = 0; 1611112015Sanholt int start = prim->start + RADEON_INDEX_PRIM_OFFSET; 1612112015Sanholt int count = (prim->finish - start) / sizeof(u16); 1613119098Sanholt int nbox = sarea_priv->nbox; 161495584Sanholt 1615112015Sanholt DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n", 1616112015Sanholt prim->prim, 1617112015Sanholt prim->vc_format, 1618145132Sanholt prim->start, prim->finish, prim->offset, prim->numverts); 161995584Sanholt 1620145132Sanholt if (bad_prim_vertex_nr(prim->prim, count)) { 1621145132Sanholt DRM_ERROR("bad prim %x count %d\n", prim->prim, count); 1622112015Sanholt return; 1623112015Sanholt } 162495584Sanholt 1625145132Sanholt if (start >= prim->finish || (prim->start & 0x7)) { 1626145132Sanholt DRM_ERROR("buffer prim %d\n", prim->prim); 1627112015Sanholt return; 1628112015Sanholt } 162995584Sanholt 1630112015Sanholt dwords = (prim->finish - prim->start + 3) / sizeof(u32); 163195584Sanholt 1632207066Srnoland data = (u32 *) ((char *)dev->agp_buffer_map->virtual + 1633145132Sanholt elt_buf->offset + prim->start); 163495584Sanholt 1635145132Sanholt data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2); 1636112015Sanholt data[1] = offset; 1637112015Sanholt data[2] = prim->numverts; 1638112015Sanholt data[3] = prim->vc_format; 1639112015Sanholt data[4] = (prim->prim | 1640112015Sanholt RADEON_PRIM_WALK_IND | 1641112015Sanholt RADEON_COLOR_ORDER_RGBA | 1642112015Sanholt RADEON_VTX_FMT_RADEON_MODE | 1643145132Sanholt (count << RADEON_NUM_VERTICES_SHIFT)); 164495584Sanholt 1645112015Sanholt do { 1646145132Sanholt if (i < nbox) 1647145132Sanholt radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 164895584Sanholt 1649145132Sanholt radeon_cp_dispatch_indirect(dev, elt_buf, 1650145132Sanholt prim->start, prim->finish); 165195584Sanholt 1652112015Sanholt i++; 1653145132Sanholt } while (i < nbox); 165495584Sanholt 165595584Sanholt} 165695584Sanholt 1657148211Sanholt#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE 165895584Sanholt 1659182080Srnolandstatic int radeon_cp_dispatch_texture(struct drm_device * dev, 1660182080Srnoland struct drm_file *file_priv, 1661145132Sanholt drm_radeon_texture_t * tex, 1662145132Sanholt drm_radeon_tex_image_t * image) 166395584Sanholt{ 166495584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 1665182080Srnoland struct drm_buf *buf; 166695584Sanholt u32 format; 166795584Sanholt u32 *buffer; 1668145132Sanholt const u8 __user *data; 1669148211Sanholt int size, dwords, tex_width, blit_width, spitch; 1670112015Sanholt u32 height; 1671112015Sanholt int i; 1672145132Sanholt u32 texpitch, microtile; 1673182080Srnoland u32 offset, byte_offset; 167495584Sanholt RING_LOCALS; 167595584Sanholt 1676182080Srnoland if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) { 1677145132Sanholt DRM_ERROR("Invalid destination offset\n"); 1678182080Srnoland return -EINVAL; 1679122580Sanholt } 1680122580Sanholt 1681112015Sanholt dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD; 1682112015Sanholt 1683112015Sanholt /* Flush the pixel cache. This ensures no pixel data gets mixed 1684112015Sanholt * up with the texture data from the host data blit, otherwise 1685112015Sanholt * part of the texture image may be corrupted. 168695584Sanholt */ 1687145132Sanholt BEGIN_RING(4); 1688112015Sanholt RADEON_FLUSH_CACHE(); 1689112015Sanholt RADEON_WAIT_UNTIL_IDLE(); 1690112015Sanholt ADVANCE_RING(); 169195584Sanholt 169295584Sanholt /* The compiler won't optimize away a division by a variable, 169395584Sanholt * even if the only legal values are powers of two. Thus, we'll 169495584Sanholt * use a shift instead. 169595584Sanholt */ 1696145132Sanholt switch (tex->format) { 169795584Sanholt case RADEON_TXFORMAT_ARGB8888: 169895584Sanholt case RADEON_TXFORMAT_RGBA8888: 169995584Sanholt format = RADEON_COLOR_FORMAT_ARGB8888; 170095584Sanholt tex_width = tex->width * 4; 170195584Sanholt blit_width = image->width * 4; 170295584Sanholt break; 170395584Sanholt case RADEON_TXFORMAT_AI88: 170495584Sanholt case RADEON_TXFORMAT_ARGB1555: 170595584Sanholt case RADEON_TXFORMAT_RGB565: 170695584Sanholt case RADEON_TXFORMAT_ARGB4444: 1707112015Sanholt case RADEON_TXFORMAT_VYUY422: 1708112015Sanholt case RADEON_TXFORMAT_YVYU422: 170995584Sanholt format = RADEON_COLOR_FORMAT_RGB565; 171095584Sanholt tex_width = tex->width * 2; 171195584Sanholt blit_width = image->width * 2; 171295584Sanholt break; 171395584Sanholt case RADEON_TXFORMAT_I8: 171495584Sanholt case RADEON_TXFORMAT_RGB332: 171595584Sanholt format = RADEON_COLOR_FORMAT_CI8; 171695584Sanholt tex_width = tex->width * 1; 171795584Sanholt blit_width = image->width * 1; 171895584Sanholt break; 171995584Sanholt default: 1720145132Sanholt DRM_ERROR("invalid texture format %d\n", tex->format); 1721182080Srnoland return -EINVAL; 172295584Sanholt } 1723148211Sanholt spitch = blit_width >> 6; 1724148211Sanholt if (spitch == 0 && image->height > 1) 1725182080Srnoland return -EINVAL; 1726148211Sanholt 1727145132Sanholt texpitch = tex->pitch; 1728145132Sanholt if ((texpitch << 22) & RADEON_DST_TILE_MICRO) { 1729145132Sanholt microtile = 1; 1730145132Sanholt if (tex_width < 64) { 1731145132Sanholt texpitch &= ~(RADEON_DST_TILE_MICRO >> 22); 1732145132Sanholt /* we got tiled coordinates, untile them */ 1733145132Sanholt image->x *= 2; 1734145132Sanholt } 1735157617Sanholt } else 1736157617Sanholt microtile = 0; 173795584Sanholt 1738182080Srnoland /* this might fail for zero-sized uploads - are those illegal? */ 1739182080Srnoland if (!radeon_check_offset(dev_priv, tex->offset + image->height * 1740182080Srnoland blit_width - 1)) { 1741182080Srnoland DRM_ERROR("Invalid final destination offset\n"); 1742182080Srnoland return -EINVAL; 1743182080Srnoland } 1744182080Srnoland 1745145132Sanholt DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width); 174695584Sanholt 1747112015Sanholt do { 1748228979Sdim DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%d y=%d w=%d h=%d\n", 1749145132Sanholt tex->offset >> 10, tex->pitch, tex->format, 1750145132Sanholt image->x, image->y, image->width, image->height); 175195584Sanholt 1752112015Sanholt /* Make a copy of some parameters in case we have to 1753112015Sanholt * update them for a multi-pass texture blit. 1754112015Sanholt */ 1755112015Sanholt height = image->height; 1756145132Sanholt data = (const u8 __user *)image->data; 1757145132Sanholt 175895584Sanholt size = height * blit_width; 175995584Sanholt 1760145132Sanholt if (size > RADEON_MAX_TEXTURE_SIZE) { 1761112015Sanholt height = RADEON_MAX_TEXTURE_SIZE / blit_width; 1762112015Sanholt size = height * blit_width; 1763145132Sanholt } else if (size < 4 && size > 0) { 1764112015Sanholt size = 4; 1765145132Sanholt } else if (size == 0) { 1766112015Sanholt return 0; 1767112015Sanholt } 176895584Sanholt 1769145132Sanholt buf = radeon_freelist_get(dev); 1770145132Sanholt if (0 && !buf) { 1771145132Sanholt radeon_do_cp_idle(dev_priv); 1772145132Sanholt buf = radeon_freelist_get(dev); 177395584Sanholt } 1774145132Sanholt if (!buf) { 1775182080Srnoland DRM_DEBUG("EAGAIN\n"); 1776145132Sanholt if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) 1777182080Srnoland return -EFAULT; 1778182080Srnoland return -EAGAIN; 1779112015Sanholt } 178095584Sanholt 1781112015Sanholt /* Dispatch the indirect buffer. 1782112015Sanholt */ 1783145132Sanholt buffer = 1784207066Srnoland (u32 *) ((char *)dev->agp_buffer_map->virtual + buf->offset); 1785112015Sanholt dwords = size / 4; 1786145132Sanholt 1787157617Sanholt#define RADEON_COPY_MT(_buf, _data, _width) \ 1788157617Sanholt do { \ 1789157617Sanholt if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\ 1790157617Sanholt DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \ 1791182080Srnoland return -EFAULT; \ 1792157617Sanholt } \ 1793157617Sanholt } while(0) 1794157617Sanholt 1795145132Sanholt if (microtile) { 1796145132Sanholt /* texture micro tiling in use, minimum texture width is thus 16 bytes. 1797145132Sanholt however, we cannot use blitter directly for texture width < 64 bytes, 1798145132Sanholt since minimum tex pitch is 64 bytes and we need this to match 1799145132Sanholt the texture width, otherwise the blitter will tile it wrong. 1800145132Sanholt Thus, tiling manually in this case. Additionally, need to special 1801145132Sanholt case tex height = 1, since our actual image will have height 2 1802145132Sanholt and we need to ensure we don't read beyond the texture size 1803145132Sanholt from user space. */ 1804145132Sanholt if (tex->height == 1) { 1805145132Sanholt if (tex_width >= 64 || tex_width <= 16) { 1806157617Sanholt RADEON_COPY_MT(buffer, data, 1807157617Sanholt (int)(tex_width * sizeof(u32))); 1808145132Sanholt } else if (tex_width == 32) { 1809157617Sanholt RADEON_COPY_MT(buffer, data, 16); 1810157617Sanholt RADEON_COPY_MT(buffer + 8, 1811157617Sanholt data + 16, 16); 1812145132Sanholt } 1813145132Sanholt } else if (tex_width >= 64 || tex_width == 16) { 1814157617Sanholt RADEON_COPY_MT(buffer, data, 1815157617Sanholt (int)(dwords * sizeof(u32))); 1816145132Sanholt } else if (tex_width < 16) { 1817145132Sanholt for (i = 0; i < tex->height; i++) { 1818157617Sanholt RADEON_COPY_MT(buffer, data, tex_width); 1819145132Sanholt buffer += 4; 1820145132Sanholt data += tex_width; 1821145132Sanholt } 1822145132Sanholt } else if (tex_width == 32) { 1823157617Sanholt /* TODO: make sure this works when not fitting in one buffer 1824157617Sanholt (i.e. 32bytes x 2048...) */ 1825145132Sanholt for (i = 0; i < tex->height; i += 2) { 1826157617Sanholt RADEON_COPY_MT(buffer, data, 16); 1827145132Sanholt data += 16; 1828157617Sanholt RADEON_COPY_MT(buffer + 8, data, 16); 1829145132Sanholt data += 16; 1830157617Sanholt RADEON_COPY_MT(buffer + 4, data, 16); 1831145132Sanholt data += 16; 1832157617Sanholt RADEON_COPY_MT(buffer + 12, data, 16); 1833145132Sanholt data += 16; 1834145132Sanholt buffer += 16; 1835145132Sanholt } 183695584Sanholt } 1837157617Sanholt } else { 1838145132Sanholt if (tex_width >= 32) { 1839145132Sanholt /* Texture image width is larger than the minimum, so we 1840145132Sanholt * can upload it directly. 1841145132Sanholt */ 1842157617Sanholt RADEON_COPY_MT(buffer, data, 1843157617Sanholt (int)(dwords * sizeof(u32))); 1844145132Sanholt } else { 1845145132Sanholt /* Texture image width is less than the minimum, so we 1846145132Sanholt * need to pad out each image scanline to the minimum 1847145132Sanholt * width. 1848145132Sanholt */ 1849145132Sanholt for (i = 0; i < tex->height; i++) { 1850157617Sanholt RADEON_COPY_MT(buffer, data, tex_width); 1851145132Sanholt buffer += 8; 1852145132Sanholt data += tex_width; 1853145132Sanholt } 1854112015Sanholt } 185595584Sanholt } 185695584Sanholt 1857157617Sanholt#undef RADEON_COPY_MT 1858182080Srnoland byte_offset = (image->y & ~2047) * blit_width; 1859182080Srnoland buf->file_priv = file_priv; 1860148211Sanholt buf->used = size; 1861148211Sanholt offset = dev_priv->gart_buffers_offset + buf->offset; 1862148211Sanholt BEGIN_RING(9); 1863148211Sanholt OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); 1864148211Sanholt OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 1865148211Sanholt RADEON_GMC_DST_PITCH_OFFSET_CNTL | 1866148211Sanholt RADEON_GMC_BRUSH_NONE | 1867148211Sanholt (format << 8) | 1868148211Sanholt RADEON_GMC_SRC_DATATYPE_COLOR | 1869148211Sanholt RADEON_ROP3_S | 1870148211Sanholt RADEON_DP_SRC_SOURCE_MEMORY | 1871157617Sanholt RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); 1872148211Sanholt OUT_RING((spitch << 22) | (offset >> 10)); 1873182080Srnoland OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10))); 1874148211Sanholt OUT_RING(0); 1875182080Srnoland OUT_RING((image->x << 16) | (image->y % 2048)); 1876148211Sanholt OUT_RING((image->width << 16) | height); 1877148211Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 1878148211Sanholt ADVANCE_RING(); 1879182080Srnoland COMMIT_RING(); 1880148211Sanholt 1881145132Sanholt radeon_cp_discard_buffer(dev, buf); 188295584Sanholt 1883112015Sanholt /* Update the input parameters for next time */ 1884112015Sanholt image->y += height; 1885112015Sanholt image->height -= height; 1886145132Sanholt image->data = (const u8 __user *)image->data + size; 1887112015Sanholt } while (image->height > 0); 188895584Sanholt 188995584Sanholt /* Flush the pixel cache after the blit completes. This ensures 189095584Sanholt * the texture data is written out to memory before rendering 189195584Sanholt * continues. 189295584Sanholt */ 1893145132Sanholt BEGIN_RING(4); 189495584Sanholt RADEON_FLUSH_CACHE(); 189595584Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 189695584Sanholt ADVANCE_RING(); 1897182080Srnoland COMMIT_RING(); 1898182080Srnoland 1899112015Sanholt return 0; 190095584Sanholt} 190195584Sanholt 1902182080Srnolandstatic void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple) 190395584Sanholt{ 190495584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 190595584Sanholt int i; 190695584Sanholt RING_LOCALS; 1907145132Sanholt DRM_DEBUG("\n"); 190895584Sanholt 1909145132Sanholt BEGIN_RING(35); 191095584Sanholt 1911145132Sanholt OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0)); 1912145132Sanholt OUT_RING(0x00000000); 191395584Sanholt 1914145132Sanholt OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31)); 1915145132Sanholt for (i = 0; i < 32; i++) { 1916145132Sanholt OUT_RING(stipple[i]); 191795584Sanholt } 191895584Sanholt 191995584Sanholt ADVANCE_RING(); 192095584Sanholt} 192195584Sanholt 1922157617Sanholtstatic void radeon_apply_surface_regs(int surf_index, 1923157617Sanholt drm_radeon_private_t *dev_priv) 1924145132Sanholt{ 1925145132Sanholt if (!dev_priv->mmio) 1926145132Sanholt return; 192795584Sanholt 1928145132Sanholt radeon_do_cp_idle(dev_priv); 1929145132Sanholt 1930157617Sanholt RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index, 1931157617Sanholt dev_priv->surfaces[surf_index].flags); 1932157617Sanholt RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index, 1933157617Sanholt dev_priv->surfaces[surf_index].lower); 1934157617Sanholt RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index, 1935157617Sanholt dev_priv->surfaces[surf_index].upper); 1936145132Sanholt} 1937145132Sanholt 1938145132Sanholt/* Allocates a virtual surface 1939157617Sanholt * doesn't always allocate a real surface, will stretch an existing 1940145132Sanholt * surface when possible. 1941145132Sanholt * 1942145132Sanholt * Note that refcount can be at most 2, since during a free refcount=3 1943145132Sanholt * might mean we have to allocate a new surface which might not always 1944145132Sanholt * be available. 1945157617Sanholt * For example : we allocate three contigous surfaces ABC. If B is 1946145132Sanholt * freed, we suddenly need two surfaces to store A and C, which might 1947145132Sanholt * not always be available. 1948145132Sanholt */ 1949157617Sanholtstatic int alloc_surface(drm_radeon_surface_alloc_t *new, 1950182080Srnoland drm_radeon_private_t *dev_priv, 1951182080Srnoland struct drm_file *file_priv) 1952145132Sanholt{ 1953145132Sanholt struct radeon_virt_surface *s; 1954145132Sanholt int i; 1955145132Sanholt int virt_surface_index; 1956145132Sanholt uint32_t new_upper, new_lower; 1957145132Sanholt 1958145132Sanholt new_lower = new->address; 1959145132Sanholt new_upper = new_lower + new->size - 1; 1960145132Sanholt 1961145132Sanholt /* sanity check */ 1962145132Sanholt if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) || 1963157617Sanholt ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) != 1964157617Sanholt RADEON_SURF_ADDRESS_FIXED_MASK) 1965157617Sanholt || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0)) 1966145132Sanholt return -1; 1967145132Sanholt 1968145132Sanholt /* make sure there is no overlap with existing surfaces */ 1969145132Sanholt for (i = 0; i < RADEON_MAX_SURFACES; i++) { 1970145132Sanholt if ((dev_priv->surfaces[i].refcount != 0) && 1971157617Sanholt (((new_lower >= dev_priv->surfaces[i].lower) && 1972157617Sanholt (new_lower < dev_priv->surfaces[i].upper)) || 1973157617Sanholt ((new_lower < dev_priv->surfaces[i].lower) && 1974157617Sanholt (new_upper > dev_priv->surfaces[i].lower)))) { 1975157617Sanholt return -1; 1976157617Sanholt } 1977145132Sanholt } 1978145132Sanholt 1979145132Sanholt /* find a virtual surface */ 1980157617Sanholt for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) 1981182080Srnoland if (dev_priv->virt_surfaces[i].file_priv == 0) 1982145132Sanholt break; 1983157617Sanholt if (i == 2 * RADEON_MAX_SURFACES) { 1984157617Sanholt return -1; 1985157617Sanholt } 1986145132Sanholt virt_surface_index = i; 1987145132Sanholt 1988145132Sanholt /* try to reuse an existing surface */ 1989145132Sanholt for (i = 0; i < RADEON_MAX_SURFACES; i++) { 1990145132Sanholt /* extend before */ 1991145132Sanholt if ((dev_priv->surfaces[i].refcount == 1) && 1992157617Sanholt (new->flags == dev_priv->surfaces[i].flags) && 1993157617Sanholt (new_upper + 1 == dev_priv->surfaces[i].lower)) { 1994145132Sanholt s = &(dev_priv->virt_surfaces[virt_surface_index]); 1995145132Sanholt s->surface_index = i; 1996145132Sanholt s->lower = new_lower; 1997145132Sanholt s->upper = new_upper; 1998145132Sanholt s->flags = new->flags; 1999182080Srnoland s->file_priv = file_priv; 2000145132Sanholt dev_priv->surfaces[i].refcount++; 2001145132Sanholt dev_priv->surfaces[i].lower = s->lower; 2002145132Sanholt radeon_apply_surface_regs(s->surface_index, dev_priv); 2003145132Sanholt return virt_surface_index; 2004145132Sanholt } 2005145132Sanholt 2006145132Sanholt /* extend after */ 2007145132Sanholt if ((dev_priv->surfaces[i].refcount == 1) && 2008157617Sanholt (new->flags == dev_priv->surfaces[i].flags) && 2009157617Sanholt (new_lower == dev_priv->surfaces[i].upper + 1)) { 2010145132Sanholt s = &(dev_priv->virt_surfaces[virt_surface_index]); 2011145132Sanholt s->surface_index = i; 2012145132Sanholt s->lower = new_lower; 2013145132Sanholt s->upper = new_upper; 2014145132Sanholt s->flags = new->flags; 2015182080Srnoland s->file_priv = file_priv; 2016145132Sanholt dev_priv->surfaces[i].refcount++; 2017145132Sanholt dev_priv->surfaces[i].upper = s->upper; 2018145132Sanholt radeon_apply_surface_regs(s->surface_index, dev_priv); 2019145132Sanholt return virt_surface_index; 2020145132Sanholt } 2021145132Sanholt } 2022145132Sanholt 2023145132Sanholt /* okay, we need a new one */ 2024145132Sanholt for (i = 0; i < RADEON_MAX_SURFACES; i++) { 2025145132Sanholt if (dev_priv->surfaces[i].refcount == 0) { 2026145132Sanholt s = &(dev_priv->virt_surfaces[virt_surface_index]); 2027145132Sanholt s->surface_index = i; 2028145132Sanholt s->lower = new_lower; 2029145132Sanholt s->upper = new_upper; 2030145132Sanholt s->flags = new->flags; 2031182080Srnoland s->file_priv = file_priv; 2032145132Sanholt dev_priv->surfaces[i].refcount = 1; 2033145132Sanholt dev_priv->surfaces[i].lower = s->lower; 2034145132Sanholt dev_priv->surfaces[i].upper = s->upper; 2035145132Sanholt dev_priv->surfaces[i].flags = s->flags; 2036145132Sanholt radeon_apply_surface_regs(s->surface_index, dev_priv); 2037145132Sanholt return virt_surface_index; 2038145132Sanholt } 2039145132Sanholt } 2040145132Sanholt 2041145132Sanholt /* we didn't find anything */ 2042145132Sanholt return -1; 2043145132Sanholt} 2044145132Sanholt 2045182080Srnolandstatic int free_surface(struct drm_file *file_priv, 2046182080Srnoland drm_radeon_private_t * dev_priv, 2047157617Sanholt int lower) 2048145132Sanholt{ 2049145132Sanholt struct radeon_virt_surface *s; 2050145132Sanholt int i; 2051145132Sanholt /* find the virtual surface */ 2052157617Sanholt for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { 2053145132Sanholt s = &(dev_priv->virt_surfaces[i]); 2054182080Srnoland if (s->file_priv) { 2055182080Srnoland if ((lower == s->lower) && (file_priv == s->file_priv)) 2056182080Srnoland { 2057157617Sanholt if (dev_priv->surfaces[s->surface_index]. 2058157617Sanholt lower == s->lower) 2059157617Sanholt dev_priv->surfaces[s->surface_index]. 2060157617Sanholt lower = s->upper; 2061145132Sanholt 2062157617Sanholt if (dev_priv->surfaces[s->surface_index]. 2063157617Sanholt upper == s->upper) 2064157617Sanholt dev_priv->surfaces[s->surface_index]. 2065157617Sanholt upper = s->lower; 2066145132Sanholt 2067145132Sanholt dev_priv->surfaces[s->surface_index].refcount--; 2068157617Sanholt if (dev_priv->surfaces[s->surface_index]. 2069157617Sanholt refcount == 0) 2070157617Sanholt dev_priv->surfaces[s->surface_index]. 2071157617Sanholt flags = 0; 2072182080Srnoland s->file_priv = NULL; 2073157617Sanholt radeon_apply_surface_regs(s->surface_index, 2074157617Sanholt dev_priv); 2075145132Sanholt return 0; 2076145132Sanholt } 2077145132Sanholt } 2078145132Sanholt } 2079145132Sanholt return 1; 2080145132Sanholt} 2081145132Sanholt 2082182080Srnolandstatic void radeon_surfaces_release(struct drm_file *file_priv, 2083157617Sanholt drm_radeon_private_t * dev_priv) 2084145132Sanholt{ 2085145132Sanholt int i; 2086157617Sanholt for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { 2087182080Srnoland if (dev_priv->virt_surfaces[i].file_priv == file_priv) 2088182080Srnoland free_surface(file_priv, dev_priv, 2089157617Sanholt dev_priv->virt_surfaces[i].lower); 2090145132Sanholt } 2091145132Sanholt} 2092145132Sanholt 209395584Sanholt/* ================================================================ 209495584Sanholt * IOCTL functions 209595584Sanholt */ 2096182080Srnolandstatic int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) 209795584Sanholt{ 209895584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2099182080Srnoland drm_radeon_surface_alloc_t *alloc = data; 2100145132Sanholt 2101182080Srnoland if (alloc_surface(alloc, dev_priv, file_priv) == -1) 2102182080Srnoland return -EINVAL; 2103145132Sanholt else 2104145132Sanholt return 0; 2105145132Sanholt} 2106145132Sanholt 2107182080Srnolandstatic int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 2108145132Sanholt{ 2109145132Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2110182080Srnoland drm_radeon_surface_free_t *memfree = data; 2111145132Sanholt 2112182080Srnoland if (free_surface(file_priv, dev_priv, memfree->address)) 2113182080Srnoland return -EINVAL; 2114145132Sanholt else 2115145132Sanholt return 0; 2116145132Sanholt} 2117145132Sanholt 2118182080Srnolandstatic int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) 2119145132Sanholt{ 2120145132Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 212195584Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 2122182080Srnoland drm_radeon_clear_t *clear = data; 212395584Sanholt drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; 2124145132Sanholt DRM_DEBUG("\n"); 212595584Sanholt 2126182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 212795584Sanholt 2128145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 212995584Sanholt 2130145132Sanholt if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 213195584Sanholt sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; 213295584Sanholt 2133182080Srnoland if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes, 2134145132Sanholt sarea_priv->nbox * sizeof(depth_boxes[0]))) 2135182080Srnoland return -EFAULT; 213695584Sanholt 2137182080Srnoland radeon_cp_dispatch_clear(dev, clear, depth_boxes); 213895584Sanholt 2139112015Sanholt COMMIT_RING(); 214095584Sanholt return 0; 214195584Sanholt} 214295584Sanholt 2143112015Sanholt/* Not sure why this isn't set all the time: 2144145132Sanholt */ 2145189499Srnolandstatic int radeon_do_init_pageflip(struct drm_device *dev) 214695584Sanholt{ 214795584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2148112015Sanholt RING_LOCALS; 2149112015Sanholt 2150145132Sanholt DRM_DEBUG("\n"); 2151112015Sanholt 2152145132Sanholt BEGIN_RING(6); 2153112015Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 2154145132Sanholt OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0)); 2155145132Sanholt OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) | 2156145132Sanholt RADEON_CRTC_OFFSET_FLIP_CNTL); 2157145132Sanholt OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0)); 2158145132Sanholt OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) | 2159145132Sanholt RADEON_CRTC_OFFSET_FLIP_CNTL); 2160112015Sanholt ADVANCE_RING(); 2161112015Sanholt 2162112015Sanholt dev_priv->page_flipping = 1; 2163112015Sanholt 2164182080Srnoland if (dev_priv->sarea_priv->pfCurrentPage != 1) 2165182080Srnoland dev_priv->sarea_priv->pfCurrentPage = 0; 2166112015Sanholt 2167112015Sanholt return 0; 2168112015Sanholt} 2169112015Sanholt 2170112015Sanholt/* Swapping and flipping are different operations, need different ioctls. 2171145132Sanholt * They can & should be intermixed to support multiple 3d windows. 2172112015Sanholt */ 2173182080Srnolandstatic int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv) 2174112015Sanholt{ 2175112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2176145132Sanholt DRM_DEBUG("\n"); 2177112015Sanholt 2178182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 2179112015Sanholt 2180145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2181112015Sanholt 2182145132Sanholt if (!dev_priv->page_flipping) 2183145132Sanholt radeon_do_init_pageflip(dev); 2184112015Sanholt 2185145132Sanholt radeon_cp_dispatch_flip(dev); 2186145132Sanholt 2187112015Sanholt COMMIT_RING(); 2188112015Sanholt return 0; 2189112015Sanholt} 2190112015Sanholt 2191182080Srnolandstatic int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) 2192112015Sanholt{ 2193112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 219495584Sanholt drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; 2195189499Srnoland 2196145132Sanholt DRM_DEBUG("\n"); 219795584Sanholt 2198182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 219995584Sanholt 2200145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 220195584Sanholt 2202145132Sanholt if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 220395584Sanholt sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; 220495584Sanholt 2205196470Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2206196470Srnoland r600_cp_dispatch_swap(dev); 2207196470Srnoland else 2208196470Srnoland radeon_cp_dispatch_swap(dev); 2209189499Srnoland sarea_priv->ctx_owner = 0; 221095584Sanholt 2211112015Sanholt COMMIT_RING(); 221295584Sanholt return 0; 221395584Sanholt} 221495584Sanholt 2215182080Srnolandstatic int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) 221695584Sanholt{ 221795584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2218157617Sanholt drm_radeon_sarea_t *sarea_priv; 2219182080Srnoland struct drm_device_dma *dma = dev->dma; 2220182080Srnoland struct drm_buf *buf; 2221182080Srnoland drm_radeon_vertex_t *vertex = data; 2222112015Sanholt drm_radeon_tcl_prim_t prim; 222395584Sanholt 2224182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 222595584Sanholt 2226157617Sanholt sarea_priv = dev_priv->sarea_priv; 2227157617Sanholt 2228145132Sanholt DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", 2229182080Srnoland DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); 223095584Sanholt 2231182080Srnoland if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { 2232145132Sanholt DRM_ERROR("buffer index %d (of %d max)\n", 2233182080Srnoland vertex->idx, dma->buf_count - 1); 2234182080Srnoland return -EINVAL; 223595584Sanholt } 2236182080Srnoland if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { 2237182080Srnoland DRM_ERROR("buffer prim %d\n", vertex->prim); 2238182080Srnoland return -EINVAL; 223995584Sanholt } 224095584Sanholt 2241145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2242145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 224395584Sanholt 2244182080Srnoland buf = dma->buflist[vertex->idx]; 224595584Sanholt 2246182080Srnoland if (buf->file_priv != file_priv) { 2247145132Sanholt DRM_ERROR("process %d using buffer owned by %p\n", 2248182080Srnoland DRM_CURRENTPID, buf->file_priv); 2249182080Srnoland return -EINVAL; 225095584Sanholt } 2251145132Sanholt if (buf->pending) { 2252182080Srnoland DRM_ERROR("sending pending buffer %d\n", vertex->idx); 2253182080Srnoland return -EINVAL; 225495584Sanholt } 225595584Sanholt 2256112015Sanholt /* Build up a prim_t record: 2257112015Sanholt */ 2258182080Srnoland if (vertex->count) { 2259182080Srnoland buf->used = vertex->count; /* not used? */ 226095584Sanholt 2261145132Sanholt if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { 2262182080Srnoland if (radeon_emit_state(dev_priv, file_priv, 2263145132Sanholt &sarea_priv->context_state, 2264145132Sanholt sarea_priv->tex_state, 2265145132Sanholt sarea_priv->dirty)) { 2266145132Sanholt DRM_ERROR("radeon_emit_state failed\n"); 2267182080Srnoland return -EINVAL; 2268122580Sanholt } 2269122580Sanholt 2270112015Sanholt sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | 2271112015Sanholt RADEON_UPLOAD_TEX1IMAGES | 2272112015Sanholt RADEON_UPLOAD_TEX2IMAGES | 2273112015Sanholt RADEON_REQUIRE_QUIESCENCE); 2274112015Sanholt } 227595584Sanholt 2276112015Sanholt prim.start = 0; 2277182080Srnoland prim.finish = vertex->count; /* unused */ 2278182080Srnoland prim.prim = vertex->prim; 2279182080Srnoland prim.numverts = vertex->count; 2280189499Srnoland prim.vc_format = sarea_priv->vc_format; 2281145132Sanholt 2282145132Sanholt radeon_cp_dispatch_vertex(dev, buf, &prim); 2283112015Sanholt } 2284112015Sanholt 2285182080Srnoland if (vertex->discard) { 2286145132Sanholt radeon_cp_discard_buffer(dev, buf); 2287112015Sanholt } 2288112015Sanholt 2289112015Sanholt COMMIT_RING(); 229095584Sanholt return 0; 229195584Sanholt} 229295584Sanholt 2293182080Srnolandstatic int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) 229495584Sanholt{ 229595584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2296157617Sanholt drm_radeon_sarea_t *sarea_priv; 2297182080Srnoland struct drm_device_dma *dma = dev->dma; 2298182080Srnoland struct drm_buf *buf; 2299182080Srnoland drm_radeon_indices_t *elts = data; 2300112015Sanholt drm_radeon_tcl_prim_t prim; 230195584Sanholt int count; 230295584Sanholt 2303182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 230495584Sanholt 2305157617Sanholt sarea_priv = dev_priv->sarea_priv; 230695584Sanholt 2307145132Sanholt DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", 2308182080Srnoland DRM_CURRENTPID, elts->idx, elts->start, elts->end, 2309182080Srnoland elts->discard); 231095584Sanholt 2311182080Srnoland if (elts->idx < 0 || elts->idx >= dma->buf_count) { 2312145132Sanholt DRM_ERROR("buffer index %d (of %d max)\n", 2313182080Srnoland elts->idx, dma->buf_count - 1); 2314182080Srnoland return -EINVAL; 231595584Sanholt } 2316182080Srnoland if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { 2317182080Srnoland DRM_ERROR("buffer prim %d\n", elts->prim); 2318182080Srnoland return -EINVAL; 231995584Sanholt } 232095584Sanholt 2321145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2322145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 232395584Sanholt 2324182080Srnoland buf = dma->buflist[elts->idx]; 232595584Sanholt 2326182080Srnoland if (buf->file_priv != file_priv) { 2327145132Sanholt DRM_ERROR("process %d using buffer owned by %p\n", 2328182080Srnoland DRM_CURRENTPID, buf->file_priv); 2329182080Srnoland return -EINVAL; 233095584Sanholt } 2331145132Sanholt if (buf->pending) { 2332182080Srnoland DRM_ERROR("sending pending buffer %d\n", elts->idx); 2333182080Srnoland return -EINVAL; 233495584Sanholt } 233595584Sanholt 2336182080Srnoland count = (elts->end - elts->start) / sizeof(u16); 2337182080Srnoland elts->start -= RADEON_INDEX_PRIM_OFFSET; 233895584Sanholt 2339182080Srnoland if (elts->start & 0x7) { 2340182080Srnoland DRM_ERROR("misaligned buffer 0x%x\n", elts->start); 2341182080Srnoland return -EINVAL; 234295584Sanholt } 2343182080Srnoland if (elts->start < buf->used) { 2344182080Srnoland DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used); 2345182080Srnoland return -EINVAL; 234695584Sanholt } 234795584Sanholt 2348182080Srnoland buf->used = elts->end; 234995584Sanholt 2350145132Sanholt if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { 2351182080Srnoland if (radeon_emit_state(dev_priv, file_priv, 2352145132Sanholt &sarea_priv->context_state, 2353145132Sanholt sarea_priv->tex_state, 2354145132Sanholt sarea_priv->dirty)) { 2355145132Sanholt DRM_ERROR("radeon_emit_state failed\n"); 2356182080Srnoland return -EINVAL; 2357122580Sanholt } 235895584Sanholt 2359112015Sanholt sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | 2360112015Sanholt RADEON_UPLOAD_TEX1IMAGES | 2361112015Sanholt RADEON_UPLOAD_TEX2IMAGES | 2362112015Sanholt RADEON_REQUIRE_QUIESCENCE); 2363112015Sanholt } 2364112015Sanholt 2365112015Sanholt /* Build up a prim_t record: 2366112015Sanholt */ 2367182080Srnoland prim.start = elts->start; 2368182080Srnoland prim.finish = elts->end; 2369182080Srnoland prim.prim = elts->prim; 2370112015Sanholt prim.offset = 0; /* offset from start of dma buffers */ 2371145132Sanholt prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ 2372189499Srnoland prim.vc_format = sarea_priv->vc_format; 2373145132Sanholt 2374145132Sanholt radeon_cp_dispatch_indices(dev, buf, &prim); 2375182080Srnoland if (elts->discard) { 2376145132Sanholt radeon_cp_discard_buffer(dev, buf); 2377112015Sanholt } 2378112015Sanholt 2379112015Sanholt COMMIT_RING(); 238095584Sanholt return 0; 238195584Sanholt} 238295584Sanholt 2383182080Srnolandstatic int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv) 238495584Sanholt{ 238595584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2386182080Srnoland drm_radeon_texture_t *tex = data; 238795584Sanholt drm_radeon_tex_image_t image; 2388112015Sanholt int ret; 238995584Sanholt 2390182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 239195584Sanholt 2392182080Srnoland if (tex->image == NULL) { 2393145132Sanholt DRM_ERROR("null texture image!\n"); 2394182080Srnoland return -EINVAL; 239595584Sanholt } 239695584Sanholt 2397145132Sanholt if (DRM_COPY_FROM_USER(&image, 2398182080Srnoland (drm_radeon_tex_image_t __user *) tex->image, 2399145132Sanholt sizeof(image))) 2400182080Srnoland return -EFAULT; 240195584Sanholt 2402145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2403145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 240495584Sanholt 2405196470Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2406196470Srnoland ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image); 2407196470Srnoland else 2408196470Srnoland ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image); 2409112015Sanholt 2410112015Sanholt return ret; 241195584Sanholt} 241295584Sanholt 2413182080Srnolandstatic int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) 241495584Sanholt{ 241595584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2416182080Srnoland drm_radeon_stipple_t *stipple = data; 241795584Sanholt u32 mask[32]; 241895584Sanholt 2419182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 242095584Sanholt 2421182080Srnoland if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) 2422182080Srnoland return -EFAULT; 242395584Sanholt 2424145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 242595584Sanholt 2426145132Sanholt radeon_cp_dispatch_stipple(dev, mask); 242795584Sanholt 2428112015Sanholt COMMIT_RING(); 242995584Sanholt return 0; 243095584Sanholt} 243195584Sanholt 2432182080Srnolandstatic int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv) 243395584Sanholt{ 243495584Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2435182080Srnoland struct drm_device_dma *dma = dev->dma; 2436182080Srnoland struct drm_buf *buf; 2437182080Srnoland drm_radeon_indirect_t *indirect = data; 243895584Sanholt RING_LOCALS; 243995584Sanholt 2440182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 244195584Sanholt 2442145132Sanholt if (!dev_priv) { 2443182080Srnoland DRM_ERROR("called with no initialization\n"); 2444182080Srnoland return -EINVAL; 244595584Sanholt } 244695584Sanholt 2447182080Srnoland DRM_DEBUG("idx=%d s=%d e=%d d=%d\n", 2448182080Srnoland indirect->idx, indirect->start, indirect->end, 2449182080Srnoland indirect->discard); 245095584Sanholt 2451182080Srnoland if (indirect->idx < 0 || indirect->idx >= dma->buf_count) { 2452145132Sanholt DRM_ERROR("buffer index %d (of %d max)\n", 2453182080Srnoland indirect->idx, dma->buf_count - 1); 2454182080Srnoland return -EINVAL; 245595584Sanholt } 245695584Sanholt 2457182080Srnoland buf = dma->buflist[indirect->idx]; 245895584Sanholt 2459182080Srnoland if (buf->file_priv != file_priv) { 2460145132Sanholt DRM_ERROR("process %d using buffer owned by %p\n", 2461182080Srnoland DRM_CURRENTPID, buf->file_priv); 2462182080Srnoland return -EINVAL; 246395584Sanholt } 2464145132Sanholt if (buf->pending) { 2465182080Srnoland DRM_ERROR("sending pending buffer %d\n", indirect->idx); 2466182080Srnoland return -EINVAL; 246795584Sanholt } 246895584Sanholt 2469182080Srnoland if (indirect->start < buf->used) { 2470145132Sanholt DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n", 2471182080Srnoland indirect->start, buf->used); 2472182080Srnoland return -EINVAL; 247395584Sanholt } 247495584Sanholt 2475145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2476145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 247795584Sanholt 2478182080Srnoland buf->used = indirect->end; 247995584Sanholt 248095584Sanholt /* Dispatch the indirect buffer full of commands from the 248195584Sanholt * X server. This is insecure and is thus only available to 248295584Sanholt * privileged clients. 248395584Sanholt */ 2484189499Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2485189499Srnoland r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); 2486189499Srnoland else { 2487189499Srnoland /* Wait for the 3D stream to idle before the indirect buffer 2488189499Srnoland * containing 2D acceleration commands is processed. 2489189499Srnoland */ 2490189499Srnoland BEGIN_RING(2); 2491189499Srnoland RADEON_WAIT_UNTIL_3D_IDLE(); 2492189499Srnoland ADVANCE_RING(); 2493189499Srnoland radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); 2494112015Sanholt } 249595584Sanholt 2496189499Srnoland if (indirect->discard) 2497189499Srnoland radeon_cp_discard_buffer(dev, buf); 2498189499Srnoland 2499112015Sanholt COMMIT_RING(); 250095584Sanholt return 0; 250195584Sanholt} 2502112015Sanholt 2503182080Srnolandstatic int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) 2504112015Sanholt{ 2505112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2506157617Sanholt drm_radeon_sarea_t *sarea_priv; 2507182080Srnoland struct drm_device_dma *dma = dev->dma; 2508182080Srnoland struct drm_buf *buf; 2509182080Srnoland drm_radeon_vertex2_t *vertex = data; 2510112015Sanholt int i; 2511112015Sanholt unsigned char laststate; 2512112015Sanholt 2513182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 2514112015Sanholt 2515157617Sanholt sarea_priv = dev_priv->sarea_priv; 2516157617Sanholt 2517145132Sanholt DRM_DEBUG("pid=%d index=%d discard=%d\n", 2518182080Srnoland DRM_CURRENTPID, vertex->idx, vertex->discard); 2519112015Sanholt 2520182080Srnoland if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { 2521145132Sanholt DRM_ERROR("buffer index %d (of %d max)\n", 2522182080Srnoland vertex->idx, dma->buf_count - 1); 2523182080Srnoland return -EINVAL; 2524112015Sanholt } 2525112015Sanholt 2526145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2527145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 2528112015Sanholt 2529182080Srnoland buf = dma->buflist[vertex->idx]; 2530112015Sanholt 2531182080Srnoland if (buf->file_priv != file_priv) { 2532145132Sanholt DRM_ERROR("process %d using buffer owned by %p\n", 2533182080Srnoland DRM_CURRENTPID, buf->file_priv); 2534182080Srnoland return -EINVAL; 2535112015Sanholt } 2536112015Sanholt 2537145132Sanholt if (buf->pending) { 2538182080Srnoland DRM_ERROR("sending pending buffer %d\n", vertex->idx); 2539182080Srnoland return -EINVAL; 2540112015Sanholt } 2541145132Sanholt 2542112015Sanholt if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 2543182080Srnoland return -EINVAL; 2544112015Sanholt 2545182080Srnoland for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) { 2546112015Sanholt drm_radeon_prim_t prim; 2547112015Sanholt drm_radeon_tcl_prim_t tclprim; 2548145132Sanholt 2549182080Srnoland if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim))) 2550182080Srnoland return -EFAULT; 2551145132Sanholt 2552145132Sanholt if (prim.stateidx != laststate) { 2553145132Sanholt drm_radeon_state_t state; 2554145132Sanholt 2555145132Sanholt if (DRM_COPY_FROM_USER(&state, 2556182080Srnoland &vertex->state[prim.stateidx], 2557145132Sanholt sizeof(state))) 2558182080Srnoland return -EFAULT; 2559112015Sanholt 2560182080Srnoland if (radeon_emit_state2(dev_priv, file_priv, &state)) { 2561145132Sanholt DRM_ERROR("radeon_emit_state2 failed\n"); 2562182080Srnoland return -EINVAL; 2563122580Sanholt } 2564112015Sanholt 2565112015Sanholt laststate = prim.stateidx; 2566112015Sanholt } 2567112015Sanholt 2568112015Sanholt tclprim.start = prim.start; 2569112015Sanholt tclprim.finish = prim.finish; 2570112015Sanholt tclprim.prim = prim.prim; 2571112015Sanholt tclprim.vc_format = prim.vc_format; 2572112015Sanholt 2573145132Sanholt if (prim.prim & RADEON_PRIM_WALK_IND) { 2574112015Sanholt tclprim.offset = prim.numverts * 64; 2575145132Sanholt tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ 2576112015Sanholt 2577145132Sanholt radeon_cp_dispatch_indices(dev, buf, &tclprim); 2578112015Sanholt } else { 2579112015Sanholt tclprim.numverts = prim.numverts; 2580145132Sanholt tclprim.offset = 0; /* not used */ 2581112015Sanholt 2582145132Sanholt radeon_cp_dispatch_vertex(dev, buf, &tclprim); 2583112015Sanholt } 2584145132Sanholt 2585112015Sanholt if (sarea_priv->nbox == 1) 2586112015Sanholt sarea_priv->nbox = 0; 2587112015Sanholt } 2588112015Sanholt 2589182080Srnoland if (vertex->discard) { 2590145132Sanholt radeon_cp_discard_buffer(dev, buf); 2591112015Sanholt } 2592112015Sanholt 2593112015Sanholt COMMIT_RING(); 2594112015Sanholt return 0; 2595112015Sanholt} 2596112015Sanholt 2597145132Sanholtstatic int radeon_emit_packets(drm_radeon_private_t * dev_priv, 2598182080Srnoland struct drm_file *file_priv, 2599145132Sanholt drm_radeon_cmd_header_t header, 2600157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2601112015Sanholt{ 2602112015Sanholt int id = (int)header.packet.packet_id; 2603112015Sanholt int sz, reg; 2604112015Sanholt int *data = (int *)cmdbuf->buf; 2605112015Sanholt RING_LOCALS; 2606145132Sanholt 2607112015Sanholt if (id >= RADEON_MAX_STATE_PACKETS) 2608182080Srnoland return -EINVAL; 2609112015Sanholt 2610112015Sanholt sz = packet[id].len; 2611112015Sanholt reg = packet[id].start; 2612112015Sanholt 2613122580Sanholt if (sz * sizeof(int) > cmdbuf->bufsz) { 2614145132Sanholt DRM_ERROR("Packet size provided larger than data provided\n"); 2615182080Srnoland return -EINVAL; 2616122580Sanholt } 2617112015Sanholt 2618182080Srnoland if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) { 2619145132Sanholt DRM_ERROR("Packet verification failed\n"); 2620182080Srnoland return -EINVAL; 2621122580Sanholt } 2622122580Sanholt 2623145132Sanholt BEGIN_RING(sz + 1); 2624145132Sanholt OUT_RING(CP_PACKET0(reg, (sz - 1))); 2625145132Sanholt OUT_RING_TABLE(data, sz); 2626112015Sanholt ADVANCE_RING(); 2627112015Sanholt 2628112015Sanholt cmdbuf->buf += sz * sizeof(int); 2629112015Sanholt cmdbuf->bufsz -= sz * sizeof(int); 2630112015Sanholt return 0; 2631112015Sanholt} 2632112015Sanholt 2633157617Sanholtstatic __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv, 2634145132Sanholt drm_radeon_cmd_header_t header, 2635157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2636112015Sanholt{ 2637112015Sanholt int sz = header.scalars.count; 2638112015Sanholt int start = header.scalars.offset; 2639112015Sanholt int stride = header.scalars.stride; 2640112015Sanholt RING_LOCALS; 2641112015Sanholt 2642145132Sanholt BEGIN_RING(3 + sz); 2643145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0)); 2644145132Sanholt OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); 2645145132Sanholt OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1)); 2646145132Sanholt OUT_RING_TABLE(cmdbuf->buf, sz); 2647112015Sanholt ADVANCE_RING(); 2648112015Sanholt cmdbuf->buf += sz * sizeof(int); 2649112015Sanholt cmdbuf->bufsz -= sz * sizeof(int); 2650112015Sanholt return 0; 2651112015Sanholt} 2652112015Sanholt 2653112015Sanholt/* God this is ugly 2654112015Sanholt */ 2655157617Sanholtstatic __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv, 2656145132Sanholt drm_radeon_cmd_header_t header, 2657157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2658112015Sanholt{ 2659112015Sanholt int sz = header.scalars.count; 2660112015Sanholt int start = ((unsigned int)header.scalars.offset) + 0x100; 2661112015Sanholt int stride = header.scalars.stride; 2662112015Sanholt RING_LOCALS; 2663112015Sanholt 2664145132Sanholt BEGIN_RING(3 + sz); 2665145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0)); 2666145132Sanholt OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); 2667145132Sanholt OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1)); 2668145132Sanholt OUT_RING_TABLE(cmdbuf->buf, sz); 2669112015Sanholt ADVANCE_RING(); 2670112015Sanholt cmdbuf->buf += sz * sizeof(int); 2671112015Sanholt cmdbuf->bufsz -= sz * sizeof(int); 2672112015Sanholt return 0; 2673112015Sanholt} 2674112015Sanholt 2675157617Sanholtstatic __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv, 2676145132Sanholt drm_radeon_cmd_header_t header, 2677157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2678112015Sanholt{ 2679112015Sanholt int sz = header.vectors.count; 2680112015Sanholt int start = header.vectors.offset; 2681112015Sanholt int stride = header.vectors.stride; 2682112015Sanholt RING_LOCALS; 2683112015Sanholt 2684162132Sanholt BEGIN_RING(5 + sz); 2685162132Sanholt OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 2686145132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); 2687145132Sanholt OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); 2688145132Sanholt OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); 2689145132Sanholt OUT_RING_TABLE(cmdbuf->buf, sz); 2690112015Sanholt ADVANCE_RING(); 2691112015Sanholt 2692112015Sanholt cmdbuf->buf += sz * sizeof(int); 2693112015Sanholt cmdbuf->bufsz -= sz * sizeof(int); 2694112015Sanholt return 0; 2695112015Sanholt} 2696112015Sanholt 2697162132Sanholtstatic __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, 2698162132Sanholt drm_radeon_cmd_header_t header, 2699162132Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2700162132Sanholt{ 2701162132Sanholt int sz = header.veclinear.count * 4; 2702162132Sanholt int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8); 2703162132Sanholt RING_LOCALS; 2704162132Sanholt 2705189499Srnoland if (!sz) 2706189499Srnoland return 0; 2707189499Srnoland if (sz * 4 > cmdbuf->bufsz) 2708189499Srnoland return -EINVAL; 2709162132Sanholt 2710162132Sanholt BEGIN_RING(5 + sz); 2711162132Sanholt OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 2712162132Sanholt OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); 2713162132Sanholt OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); 2714162132Sanholt OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); 2715162132Sanholt OUT_RING_TABLE(cmdbuf->buf, sz); 2716162132Sanholt ADVANCE_RING(); 2717162132Sanholt 2718162132Sanholt cmdbuf->buf += sz * sizeof(int); 2719162132Sanholt cmdbuf->bufsz -= sz * sizeof(int); 2720162132Sanholt return 0; 2721162132Sanholt} 2722162132Sanholt 2723182080Srnolandstatic int radeon_emit_packet3(struct drm_device * dev, 2724182080Srnoland struct drm_file *file_priv, 2725157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf) 2726112015Sanholt{ 2727112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2728122580Sanholt unsigned int cmdsz; 2729145132Sanholt int ret; 2730112015Sanholt RING_LOCALS; 2731112015Sanholt 2732112015Sanholt DRM_DEBUG("\n"); 2733112015Sanholt 2734182080Srnoland if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, 2735145132Sanholt cmdbuf, &cmdsz))) { 2736145132Sanholt DRM_ERROR("Packet verification failed\n"); 2737122580Sanholt return ret; 2738122580Sanholt } 2739112015Sanholt 2740145132Sanholt BEGIN_RING(cmdsz); 2741145132Sanholt OUT_RING_TABLE(cmdbuf->buf, cmdsz); 2742112015Sanholt ADVANCE_RING(); 2743112015Sanholt 2744112015Sanholt cmdbuf->buf += cmdsz * 4; 2745112015Sanholt cmdbuf->bufsz -= cmdsz * 4; 2746112015Sanholt return 0; 2747112015Sanholt} 2748112015Sanholt 2749182080Srnolandstatic int radeon_emit_packet3_cliprect(struct drm_device *dev, 2750182080Srnoland struct drm_file *file_priv, 2751157617Sanholt drm_radeon_kcmd_buffer_t *cmdbuf, 2752145132Sanholt int orig_nbox) 2753112015Sanholt{ 2754112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2755182080Srnoland struct drm_clip_rect box; 2756122580Sanholt unsigned int cmdsz; 2757145132Sanholt int ret; 2758182080Srnoland struct drm_clip_rect __user *boxes = cmdbuf->boxes; 2759112015Sanholt int i = 0; 2760112015Sanholt RING_LOCALS; 2761112015Sanholt 2762112015Sanholt DRM_DEBUG("\n"); 2763112015Sanholt 2764182080Srnoland if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, 2765145132Sanholt cmdbuf, &cmdsz))) { 2766145132Sanholt DRM_ERROR("Packet verification failed\n"); 2767122580Sanholt return ret; 2768122580Sanholt } 2769112015Sanholt 2770112015Sanholt if (!orig_nbox) 2771112015Sanholt goto out; 2772112015Sanholt 2773112015Sanholt do { 2774145132Sanholt if (i < cmdbuf->nbox) { 2775145132Sanholt if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box))) 2776182080Srnoland return -EFAULT; 2777112015Sanholt /* FIXME The second and subsequent times round 2778112015Sanholt * this loop, send a WAIT_UNTIL_3D_IDLE before 2779112015Sanholt * calling emit_clip_rect(). This fixes a 2780112015Sanholt * lockup on fast machines when sending 2781112015Sanholt * several cliprects with a cmdbuf, as when 2782112015Sanholt * waving a 2D window over a 3D 2783112015Sanholt * window. Something in the commands from user 2784112015Sanholt * space seems to hang the card when they're 2785112015Sanholt * sent several times in a row. That would be 2786112015Sanholt * the correct place to fix it but this works 2787112015Sanholt * around it until I can figure that out - Tim 2788112015Sanholt * Smith */ 2789145132Sanholt if (i) { 2790145132Sanholt BEGIN_RING(2); 2791112015Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 2792112015Sanholt ADVANCE_RING(); 2793112015Sanholt } 2794145132Sanholt radeon_emit_clip_rect(dev_priv, &box); 2795112015Sanholt } 2796145132Sanholt 2797145132Sanholt BEGIN_RING(cmdsz); 2798145132Sanholt OUT_RING_TABLE(cmdbuf->buf, cmdsz); 2799112015Sanholt ADVANCE_RING(); 2800112015Sanholt 2801145132Sanholt } while (++i < cmdbuf->nbox); 2802145132Sanholt if (cmdbuf->nbox == 1) 2803112015Sanholt cmdbuf->nbox = 0; 2804112015Sanholt 2805145132Sanholt out: 2806112015Sanholt cmdbuf->buf += cmdsz * 4; 2807112015Sanholt cmdbuf->bufsz -= cmdsz * 4; 2808112015Sanholt return 0; 2809112015Sanholt} 2810112015Sanholt 2811182080Srnolandstatic int radeon_emit_wait(struct drm_device * dev, int flags) 2812112015Sanholt{ 2813112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2814112015Sanholt RING_LOCALS; 2815112015Sanholt 2816182080Srnoland DRM_DEBUG("%x\n", flags); 2817112015Sanholt switch (flags) { 2818112015Sanholt case RADEON_WAIT_2D: 2819145132Sanholt BEGIN_RING(2); 2820145132Sanholt RADEON_WAIT_UNTIL_2D_IDLE(); 2821112015Sanholt ADVANCE_RING(); 2822112015Sanholt break; 2823112015Sanholt case RADEON_WAIT_3D: 2824145132Sanholt BEGIN_RING(2); 2825145132Sanholt RADEON_WAIT_UNTIL_3D_IDLE(); 2826112015Sanholt ADVANCE_RING(); 2827112015Sanholt break; 2828145132Sanholt case RADEON_WAIT_2D | RADEON_WAIT_3D: 2829145132Sanholt BEGIN_RING(2); 2830145132Sanholt RADEON_WAIT_UNTIL_IDLE(); 2831112015Sanholt ADVANCE_RING(); 2832112015Sanholt break; 2833112015Sanholt default: 2834182080Srnoland return -EINVAL; 2835112015Sanholt } 2836112015Sanholt 2837112015Sanholt return 0; 2838112015Sanholt} 2839112015Sanholt 2840182080Srnolandstatic int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv) 2841112015Sanholt{ 2842112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 2843182080Srnoland struct drm_device_dma *dma = dev->dma; 2844182080Srnoland struct drm_buf *buf = NULL; 2845112015Sanholt int idx; 2846182080Srnoland drm_radeon_kcmd_buffer_t *cmdbuf = data; 2847112015Sanholt drm_radeon_cmd_header_t header; 2848145132Sanholt int orig_nbox, orig_bufsz; 2849145132Sanholt char *kbuf = NULL; 2850112015Sanholt 2851182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 2852112015Sanholt 2853145132Sanholt RING_SPACE_TEST_WITH_RETURN(dev_priv); 2854145132Sanholt VB_AGE_TEST_WITH_RETURN(dev_priv); 2855112015Sanholt 2856182080Srnoland if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) { 2857182080Srnoland return -EINVAL; 2858145132Sanholt } 2859112015Sanholt 2860145132Sanholt /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid 2861145132Sanholt * races between checking values and using those values in other code, 2862145132Sanholt * and simply to avoid a lot of function calls to copy in data. 2863145132Sanholt */ 2864182080Srnoland orig_bufsz = cmdbuf->bufsz; 2865145132Sanholt if (orig_bufsz != 0) { 2866182080Srnoland kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER); 2867145132Sanholt if (kbuf == NULL) 2868182080Srnoland return -ENOMEM; 2869182080Srnoland if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf, 2870182080Srnoland cmdbuf->bufsz)) { 2871145132Sanholt drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); 2872182080Srnoland return -EFAULT; 2873145132Sanholt } 2874182080Srnoland cmdbuf->buf = kbuf; 2875145132Sanholt } 2876112015Sanholt 2877182080Srnoland orig_nbox = cmdbuf->nbox; 2878157617Sanholt 2879189499Srnoland if (dev_priv->microcode_version == UCODE_R300) { 2880148211Sanholt int temp; 2881182080Srnoland temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); 2882157617Sanholt 2883148211Sanholt if (orig_bufsz != 0) 2884148211Sanholt drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); 2885157617Sanholt 2886148211Sanholt return temp; 2887148211Sanholt } 2888157617Sanholt 2889148211Sanholt /* microcode_version != r300 */ 2890182080Srnoland while (cmdbuf->bufsz >= sizeof(header)) { 2891157617Sanholt 2892182080Srnoland header.i = *(int *)cmdbuf->buf; 2893182080Srnoland cmdbuf->buf += sizeof(header); 2894182080Srnoland cmdbuf->bufsz -= sizeof(header); 2895112015Sanholt 2896112015Sanholt switch (header.header.cmd_type) { 2897145132Sanholt case RADEON_CMD_PACKET: 2898112015Sanholt DRM_DEBUG("RADEON_CMD_PACKET\n"); 2899145132Sanholt if (radeon_emit_packets 2900182080Srnoland (dev_priv, file_priv, header, cmdbuf)) { 2901112015Sanholt DRM_ERROR("radeon_emit_packets failed\n"); 2902145132Sanholt goto err; 2903112015Sanholt } 2904112015Sanholt break; 2905112015Sanholt 2906112015Sanholt case RADEON_CMD_SCALARS: 2907112015Sanholt DRM_DEBUG("RADEON_CMD_SCALARS\n"); 2908182080Srnoland if (radeon_emit_scalars(dev_priv, header, cmdbuf)) { 2909112015Sanholt DRM_ERROR("radeon_emit_scalars failed\n"); 2910145132Sanholt goto err; 2911112015Sanholt } 2912112015Sanholt break; 2913112015Sanholt 2914112015Sanholt case RADEON_CMD_VECTORS: 2915112015Sanholt DRM_DEBUG("RADEON_CMD_VECTORS\n"); 2916182080Srnoland if (radeon_emit_vectors(dev_priv, header, cmdbuf)) { 2917112015Sanholt DRM_ERROR("radeon_emit_vectors failed\n"); 2918145132Sanholt goto err; 2919112015Sanholt } 2920112015Sanholt break; 2921112015Sanholt 2922112015Sanholt case RADEON_CMD_DMA_DISCARD: 2923112015Sanholt DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n"); 2924112015Sanholt idx = header.dma.buf_idx; 2925145132Sanholt if (idx < 0 || idx >= dma->buf_count) { 2926145132Sanholt DRM_ERROR("buffer index %d (of %d max)\n", 2927145132Sanholt idx, dma->buf_count - 1); 2928145132Sanholt goto err; 2929112015Sanholt } 2930112015Sanholt 2931112015Sanholt buf = dma->buflist[idx]; 2932182080Srnoland if (buf->file_priv != file_priv || buf->pending) { 2933145132Sanholt DRM_ERROR("bad buffer %p %p %d\n", 2934182080Srnoland buf->file_priv, file_priv, 2935182080Srnoland buf->pending); 2936145132Sanholt goto err; 2937112015Sanholt } 2938112015Sanholt 2939145132Sanholt radeon_cp_discard_buffer(dev, buf); 2940112015Sanholt break; 2941112015Sanholt 2942112015Sanholt case RADEON_CMD_PACKET3: 2943112015Sanholt DRM_DEBUG("RADEON_CMD_PACKET3\n"); 2944182080Srnoland if (radeon_emit_packet3(dev, file_priv, cmdbuf)) { 2945112015Sanholt DRM_ERROR("radeon_emit_packet3 failed\n"); 2946145132Sanholt goto err; 2947112015Sanholt } 2948112015Sanholt break; 2949112015Sanholt 2950112015Sanholt case RADEON_CMD_PACKET3_CLIP: 2951112015Sanholt DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); 2952145132Sanholt if (radeon_emit_packet3_cliprect 2953182080Srnoland (dev, file_priv, cmdbuf, orig_nbox)) { 2954112015Sanholt DRM_ERROR("radeon_emit_packet3_clip failed\n"); 2955145132Sanholt goto err; 2956112015Sanholt } 2957112015Sanholt break; 2958112015Sanholt 2959112015Sanholt case RADEON_CMD_SCALARS2: 2960112015Sanholt DRM_DEBUG("RADEON_CMD_SCALARS2\n"); 2961182080Srnoland if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) { 2962112015Sanholt DRM_ERROR("radeon_emit_scalars2 failed\n"); 2963145132Sanholt goto err; 2964112015Sanholt } 2965112015Sanholt break; 2966112015Sanholt 2967112015Sanholt case RADEON_CMD_WAIT: 2968112015Sanholt DRM_DEBUG("RADEON_CMD_WAIT\n"); 2969145132Sanholt if (radeon_emit_wait(dev, header.wait.flags)) { 2970112015Sanholt DRM_ERROR("radeon_emit_wait failed\n"); 2971145132Sanholt goto err; 2972112015Sanholt } 2973112015Sanholt break; 2974162132Sanholt case RADEON_CMD_VECLINEAR: 2975162132Sanholt DRM_DEBUG("RADEON_CMD_VECLINEAR\n"); 2976182080Srnoland if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) { 2977162132Sanholt DRM_ERROR("radeon_emit_veclinear failed\n"); 2978162132Sanholt goto err; 2979162132Sanholt } 2980162132Sanholt break; 2981162132Sanholt 2982112015Sanholt default: 2983145132Sanholt DRM_ERROR("bad cmd_type %d at %p\n", 2984112015Sanholt header.header.cmd_type, 2985182080Srnoland cmdbuf->buf - sizeof(header)); 2986145132Sanholt goto err; 2987112015Sanholt } 2988112015Sanholt } 2989112015Sanholt 2990145132Sanholt if (orig_bufsz != 0) 2991145132Sanholt drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); 2992157617Sanholt 2993112015Sanholt DRM_DEBUG("DONE\n"); 2994112015Sanholt COMMIT_RING(); 2995112015Sanholt return 0; 2996145132Sanholt 2997157617Sanholt err: 2998145132Sanholt if (orig_bufsz != 0) 2999145132Sanholt drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); 3000182080Srnoland return -EINVAL; 3001112015Sanholt} 3002112015Sanholt 3003182080Srnolandstatic int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) 3004112015Sanholt{ 3005112015Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 3006182080Srnoland drm_radeon_getparam_t *param = data; 3007112015Sanholt int value; 3008112015Sanholt 3009145132Sanholt DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 3010112015Sanholt 3011182080Srnoland switch (param->param) { 3012119895Sanholt case RADEON_PARAM_GART_BUFFER_OFFSET: 3013119895Sanholt value = dev_priv->gart_buffers_offset; 3014112015Sanholt break; 3015112015Sanholt case RADEON_PARAM_LAST_FRAME: 3016112015Sanholt dev_priv->stats.last_frame_reads++; 3017189499Srnoland value = GET_SCRATCH(dev_priv, 0); 3018112015Sanholt break; 3019112015Sanholt case RADEON_PARAM_LAST_DISPATCH: 3020189499Srnoland value = GET_SCRATCH(dev_priv, 1); 3021112015Sanholt break; 3022112015Sanholt case RADEON_PARAM_LAST_CLEAR: 3023112015Sanholt dev_priv->stats.last_clear_reads++; 3024189499Srnoland value = GET_SCRATCH(dev_priv, 2); 3025112015Sanholt break; 3026112015Sanholt case RADEON_PARAM_IRQ_NR: 3027197603Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 3028197603Srnoland value = 0; 3029197603Srnoland else 3030197603Srnoland value = dev->irq; 3031112015Sanholt break; 3032119895Sanholt case RADEON_PARAM_GART_BASE: 3033119895Sanholt value = dev_priv->gart_vm_start; 3034112015Sanholt break; 3035113995Sanholt case RADEON_PARAM_REGISTER_HANDLE: 3036152909Sanholt value = dev_priv->mmio->offset; 3037113995Sanholt break; 3038113995Sanholt case RADEON_PARAM_STATUS_HANDLE: 3039113995Sanholt value = dev_priv->ring_rptr_offset; 3040113995Sanholt break; 3041157719Sru#ifndef __LP64__ 3042145132Sanholt /* 3043145132Sanholt * This ioctl() doesn't work on 64-bit platforms because hw_lock is a 3044145132Sanholt * pointer which can't fit into an int-sized variable. According to 3045145132Sanholt * Michel D��nzer, the ioctl() is only used on embedded platforms, so 3046145132Sanholt * not supporting it shouldn't be a problem. If the same functionality 3047145132Sanholt * is needed on 64-bit platforms, a new ioctl() would have to be added, 3048145132Sanholt * so backwards-compatibility for the embedded platforms can be 3049145132Sanholt * maintained. --davidm 4-Feb-2004. 3050145132Sanholt */ 3051153087Sru case RADEON_PARAM_SAREA_HANDLE: 3052113995Sanholt /* The lock is the first dword in the sarea. */ 3053145132Sanholt value = (long)dev->lock.hw_lock; 3054145132Sanholt break; 3055153087Sru#endif 3056119895Sanholt case RADEON_PARAM_GART_TEX_HANDLE: 3057119895Sanholt value = dev_priv->gart_textures_offset; 3058113995Sanholt break; 3059162132Sanholt case RADEON_PARAM_SCRATCH_OFFSET: 3060162132Sanholt if (!dev_priv->writeback_works) 3061182080Srnoland return -EINVAL; 3062189499Srnoland if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 3063189499Srnoland value = R600_SCRATCH_REG_OFFSET; 3064189499Srnoland else 3065189499Srnoland value = RADEON_SCRATCH_REG_OFFSET; 3066162132Sanholt break; 3067157617Sanholt case RADEON_PARAM_CARD_TYPE: 3068182080Srnoland if (dev_priv->flags & RADEON_IS_PCIE) 3069157617Sanholt value = RADEON_CARD_PCIE; 3070182080Srnoland else if (dev_priv->flags & RADEON_IS_AGP) 3071157617Sanholt value = RADEON_CARD_AGP; 3072157617Sanholt else 3073157617Sanholt value = RADEON_CARD_PCI; 3074157617Sanholt break; 3075182080Srnoland case RADEON_PARAM_VBLANK_CRTC: 3076182080Srnoland value = radeon_vblank_crtc_get(dev); 3077182080Srnoland break; 3078182080Srnoland case RADEON_PARAM_FB_LOCATION: 3079182080Srnoland value = radeon_read_fb_location(dev_priv); 3080182080Srnoland break; 3081182080Srnoland case RADEON_PARAM_NUM_GB_PIPES: 3082182080Srnoland value = dev_priv->num_gb_pipes; 3083182080Srnoland break; 3084196471Srnoland case RADEON_PARAM_NUM_Z_PIPES: 3085196471Srnoland value = dev_priv->num_z_pipes; 3086196471Srnoland break; 3087112015Sanholt default: 3088189499Srnoland DRM_DEBUG("Invalid parameter %d\n", param->param); 3089182080Srnoland return -EINVAL; 3090112015Sanholt } 3091112015Sanholt 3092182080Srnoland if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 3093145132Sanholt DRM_ERROR("copy_to_user\n"); 3094182080Srnoland return -EFAULT; 3095112015Sanholt } 3096145132Sanholt 3097112015Sanholt return 0; 3098112015Sanholt} 3099122580Sanholt 3100182080Srnolandstatic int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) 3101145132Sanholt{ 3102122580Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 3103182080Srnoland drm_radeon_setparam_t *sp = data; 3104145132Sanholt struct drm_radeon_driver_file_fields *radeon_priv; 3105122580Sanholt 3106182080Srnoland switch (sp->param) { 3107122580Sanholt case RADEON_SETPARAM_FB_LOCATION: 3108182080Srnoland radeon_priv = file_priv->driver_priv; 3109182080Srnoland radeon_priv->radeon_fb_delta = dev_priv->fb_location - 3110182080Srnoland sp->value; 3111122580Sanholt break; 3112145132Sanholt case RADEON_SETPARAM_SWITCH_TILING: 3113182080Srnoland if (sp->value == 0) { 3114157617Sanholt DRM_DEBUG("color tiling disabled\n"); 3115145132Sanholt dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; 3116145132Sanholt dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; 3117182080Srnoland if (dev_priv->sarea_priv) 3118182080Srnoland dev_priv->sarea_priv->tiling_enabled = 0; 3119182080Srnoland } else if (sp->value == 1) { 3120157617Sanholt DRM_DEBUG("color tiling enabled\n"); 3121145132Sanholt dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; 3122145132Sanholt dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; 3123182080Srnoland if (dev_priv->sarea_priv) 3124182080Srnoland dev_priv->sarea_priv->tiling_enabled = 1; 3125145132Sanholt } 3126145132Sanholt break; 3127152909Sanholt case RADEON_SETPARAM_PCIGART_LOCATION: 3128182080Srnoland dev_priv->pcigart_offset = sp->value; 3129182080Srnoland dev_priv->pcigart_offset_set = 1; 3130152909Sanholt break; 3131157617Sanholt case RADEON_SETPARAM_NEW_MEMMAP: 3132182080Srnoland dev_priv->new_memmap = sp->value; 3133157617Sanholt break; 3134182080Srnoland case RADEON_SETPARAM_PCIGART_TABLE_SIZE: 3135182080Srnoland dev_priv->gart_info.table_size = sp->value; 3136182080Srnoland if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) 3137182080Srnoland dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; 3138182080Srnoland break; 3139182080Srnoland case RADEON_SETPARAM_VBLANK_CRTC: 3140182080Srnoland return radeon_vblank_crtc_set(dev, sp->value); 3141182080Srnoland break; 3142122580Sanholt default: 3143182080Srnoland DRM_DEBUG("Invalid parameter %d\n", sp->param); 3144182080Srnoland return -EINVAL; 3145122580Sanholt } 3146122580Sanholt 3147122580Sanholt return 0; 3148122580Sanholt} 3149145132Sanholt 3150145132Sanholt/* When a client dies: 3151145132Sanholt * - Check for and clean up flipped page state 3152145132Sanholt * - Free any alloced GART memory. 3153145132Sanholt * - Free any alloced radeon surfaces. 3154145132Sanholt * 3155145132Sanholt * DRM infrastructure takes care of reclaiming dma buffers. 3156145132Sanholt */ 3157189499Srnolandvoid radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) 3158145132Sanholt{ 3159145132Sanholt if (dev->dev_private) { 3160145132Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 3161182080Srnoland dev_priv->page_flipping = 0; 3162182080Srnoland radeon_mem_release(file_priv, dev_priv->gart_heap); 3163182080Srnoland radeon_mem_release(file_priv, dev_priv->fb_heap); 3164182080Srnoland radeon_surfaces_release(file_priv, dev_priv); 3165145132Sanholt } 3166145132Sanholt} 3167145132Sanholt 3168182080Srnolandvoid radeon_driver_lastclose(struct drm_device *dev) 3169145132Sanholt{ 3170189499Srnoland radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private); 3171196470Srnoland if (dev->dev_private) { 3172196470Srnoland drm_radeon_private_t *dev_priv = dev->dev_private; 3173196470Srnoland 3174196470Srnoland if (dev_priv->sarea_priv && 3175196470Srnoland dev_priv->sarea_priv->pfCurrentPage != 0) 3176196470Srnoland radeon_cp_dispatch_flip(dev); 3177196470Srnoland } 3178196470Srnoland 3179145132Sanholt radeon_do_release(dev); 3180145132Sanholt} 3181145132Sanholt 3182182080Srnolandint radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) 3183145132Sanholt{ 3184145132Sanholt drm_radeon_private_t *dev_priv = dev->dev_private; 3185145132Sanholt struct drm_radeon_driver_file_fields *radeon_priv; 3186145132Sanholt 3187145132Sanholt DRM_DEBUG("\n"); 3188145132Sanholt radeon_priv = 3189145132Sanholt (struct drm_radeon_driver_file_fields *) 3190145132Sanholt drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES); 3191145132Sanholt 3192145132Sanholt if (!radeon_priv) 3193145132Sanholt return -ENOMEM; 3194145132Sanholt 3195182080Srnoland file_priv->driver_priv = radeon_priv; 3196145132Sanholt 3197145132Sanholt if (dev_priv) 3198145132Sanholt radeon_priv->radeon_fb_delta = dev_priv->fb_location; 3199145132Sanholt else 3200145132Sanholt radeon_priv->radeon_fb_delta = 0; 3201145132Sanholt return 0; 3202145132Sanholt} 3203145132Sanholt 3204182080Srnolandvoid radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) 3205145132Sanholt{ 3206145132Sanholt struct drm_radeon_driver_file_fields *radeon_priv = 3207182080Srnoland file_priv->driver_priv; 3208145132Sanholt 3209145132Sanholt drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); 3210145132Sanholt} 3211145132Sanholt 3212182080Srnolandstruct drm_ioctl_desc radeon_ioctls[] = { 3213182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3214182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3215182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3216182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3217182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), 3218182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), 3219182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH), 3220182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), 3221182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH), 3222182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), 3223182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), 3224182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH), 3225182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), 3226182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), 3227189499Srnoland DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_ROOT_ONLY), 3228182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), 3229182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), 3230182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), 3231182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH), 3232182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), 3233182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH), 3234182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3235182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), 3236182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), 3237182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), 3238182080Srnoland DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), 3239196470Srnoland DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), 3240196470Srnoland DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH) 3241145132Sanholt}; 3242145132Sanholt 3243145132Sanholtint radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); 3244