1254885Sdumbbell/* radeon_state.c -- State support for Radeon -*- linux-c -*- */ 2254885Sdumbbell/* 3254885Sdumbbell * Copyright 2000 VA Linux Systems, Inc., Fremont, California. 4254885Sdumbbell * All Rights Reserved. 5254885Sdumbbell * 6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 7254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 8254885Sdumbbell * to deal in the Software without restriction, including without limitation 9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 11254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 12254885Sdumbbell * 13254885Sdumbbell * The above copyright notice and this permission notice (including the next 14254885Sdumbbell * paragraph) shall be included in all copies or substantial portions of the 15254885Sdumbbell * Software. 16254885Sdumbbell * 17254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20254885Sdumbbell * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23254885Sdumbbell * DEALINGS IN THE SOFTWARE. 24254885Sdumbbell * 25254885Sdumbbell * Authors: 26254885Sdumbbell * Gareth Hughes <gareth@valinux.com> 27254885Sdumbbell * Kevin E. Martin <martin@valinux.com> 28254885Sdumbbell */ 29254885Sdumbbell 30254885Sdumbbell#include <sys/cdefs.h> 31254885Sdumbbell__FBSDID("$FreeBSD$"); 32254885Sdumbbell 33254885Sdumbbell#include <dev/drm2/drmP.h> 34254885Sdumbbell#include <dev/drm2/drm_buffer.h> 35254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 36254885Sdumbbell#include "radeon_drv.h" 37254885Sdumbbell 38254885Sdumbbell/* ================================================================ 39254885Sdumbbell * Helper functions for client state checking and fixup 40254885Sdumbbell */ 41254885Sdumbbell 42254885Sdumbbellstatic __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * 43254885Sdumbbell dev_priv, 44254885Sdumbbell struct drm_file * file_priv, 45254885Sdumbbell u32 *offset) 46254885Sdumbbell{ 47254885Sdumbbell u64 off = *offset; 48254885Sdumbbell u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1; 49254885Sdumbbell struct drm_radeon_driver_file_fields *radeon_priv; 50254885Sdumbbell 51254885Sdumbbell /* Hrm ... the story of the offset ... So this function converts 52254885Sdumbbell * the various ideas of what userland clients might have for an 53254885Sdumbbell * offset in the card address space into an offset into the card 54254885Sdumbbell * address space :) So with a sane client, it should just keep 55254885Sdumbbell * the value intact and just do some boundary checking. However, 56254885Sdumbbell * not all clients are sane. Some older clients pass us 0 based 57254885Sdumbbell * offsets relative to the start of the framebuffer and some may 58254885Sdumbbell * assume the AGP aperture it appended to the framebuffer, so we 59254885Sdumbbell * try to detect those cases and fix them up. 60254885Sdumbbell * 61254885Sdumbbell * Note: It might be a good idea here to make sure the offset lands 62254885Sdumbbell * in some "allowed" area to protect things like the PCIE GART... 63254885Sdumbbell */ 64254885Sdumbbell 65254885Sdumbbell /* First, the best case, the offset already lands in either the 66254885Sdumbbell * framebuffer or the GART mapped space 67254885Sdumbbell */ 68254885Sdumbbell if (radeon_check_offset(dev_priv, off)) 69254885Sdumbbell return 0; 70254885Sdumbbell 71254885Sdumbbell /* Ok, that didn't happen... now check if we have a zero based 72254885Sdumbbell * offset that fits in the framebuffer + gart space, apply the 73254885Sdumbbell * magic offset we get from SETPARAM or calculated from fb_location 74254885Sdumbbell */ 75254885Sdumbbell if (off < (dev_priv->fb_size + dev_priv->gart_size)) { 76254885Sdumbbell radeon_priv = file_priv->driver_priv; 77254885Sdumbbell off += radeon_priv->radeon_fb_delta; 78254885Sdumbbell } 79254885Sdumbbell 80254885Sdumbbell /* Finally, assume we aimed at a GART offset if beyond the fb */ 81254885Sdumbbell if (off > fb_end) 82254885Sdumbbell off = off - fb_end - 1 + dev_priv->gart_vm_start; 83254885Sdumbbell 84254885Sdumbbell /* Now recheck and fail if out of bounds */ 85254885Sdumbbell if (radeon_check_offset(dev_priv, off)) { 86254885Sdumbbell DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); 87254885Sdumbbell *offset = off; 88254885Sdumbbell return 0; 89254885Sdumbbell } 90254885Sdumbbell return -EINVAL; 91254885Sdumbbell} 92254885Sdumbbell 93254885Sdumbbellstatic __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * 94254885Sdumbbell dev_priv, 95254885Sdumbbell struct drm_file *file_priv, 96254885Sdumbbell int id, struct drm_buffer *buf) 97254885Sdumbbell{ 98254885Sdumbbell u32 *data; 99254885Sdumbbell switch (id) { 100254885Sdumbbell 101254885Sdumbbell case RADEON_EMIT_PP_MISC: 102254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, 103254885Sdumbbell (RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4); 104254885Sdumbbell 105254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) { 106254885Sdumbbell DRM_ERROR("Invalid depth buffer offset\n"); 107254885Sdumbbell return -EINVAL; 108254885Sdumbbell } 109254885Sdumbbell dev_priv->have_z_offset = 1; 110254885Sdumbbell break; 111254885Sdumbbell 112254885Sdumbbell case RADEON_EMIT_PP_CNTL: 113254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, 114254885Sdumbbell (RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4); 115254885Sdumbbell 116254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) { 117254885Sdumbbell DRM_ERROR("Invalid colour buffer offset\n"); 118254885Sdumbbell return -EINVAL; 119254885Sdumbbell } 120254885Sdumbbell break; 121254885Sdumbbell 122254885Sdumbbell case R200_EMIT_PP_TXOFFSET_0: 123254885Sdumbbell case R200_EMIT_PP_TXOFFSET_1: 124254885Sdumbbell case R200_EMIT_PP_TXOFFSET_2: 125254885Sdumbbell case R200_EMIT_PP_TXOFFSET_3: 126254885Sdumbbell case R200_EMIT_PP_TXOFFSET_4: 127254885Sdumbbell case R200_EMIT_PP_TXOFFSET_5: 128254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, 0); 129254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) { 130254885Sdumbbell DRM_ERROR("Invalid R200 texture offset\n"); 131254885Sdumbbell return -EINVAL; 132254885Sdumbbell } 133254885Sdumbbell break; 134254885Sdumbbell 135254885Sdumbbell case RADEON_EMIT_PP_TXFILTER_0: 136254885Sdumbbell case RADEON_EMIT_PP_TXFILTER_1: 137254885Sdumbbell case RADEON_EMIT_PP_TXFILTER_2: 138254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, 139254885Sdumbbell (RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4); 140254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) { 141254885Sdumbbell DRM_ERROR("Invalid R100 texture offset\n"); 142254885Sdumbbell return -EINVAL; 143254885Sdumbbell } 144254885Sdumbbell break; 145254885Sdumbbell 146254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_0: 147254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_1: 148254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_2: 149254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_3: 150254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_4: 151254885Sdumbbell case R200_EMIT_PP_CUBIC_OFFSETS_5:{ 152254885Sdumbbell int i; 153254885Sdumbbell for (i = 0; i < 5; i++) { 154254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, i); 155254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, 156254885Sdumbbell file_priv, 157254885Sdumbbell data)) { 158254885Sdumbbell DRM_ERROR 159254885Sdumbbell ("Invalid R200 cubic texture offset\n"); 160254885Sdumbbell return -EINVAL; 161254885Sdumbbell } 162254885Sdumbbell } 163254885Sdumbbell break; 164254885Sdumbbell } 165254885Sdumbbell 166254885Sdumbbell case RADEON_EMIT_PP_CUBIC_OFFSETS_T0: 167254885Sdumbbell case RADEON_EMIT_PP_CUBIC_OFFSETS_T1: 168254885Sdumbbell case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{ 169254885Sdumbbell int i; 170254885Sdumbbell for (i = 0; i < 5; i++) { 171254885Sdumbbell data = drm_buffer_pointer_to_dword(buf, i); 172254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, 173254885Sdumbbell file_priv, 174254885Sdumbbell data)) { 175254885Sdumbbell DRM_ERROR 176254885Sdumbbell ("Invalid R100 cubic texture offset\n"); 177254885Sdumbbell return -EINVAL; 178254885Sdumbbell } 179254885Sdumbbell } 180254885Sdumbbell } 181254885Sdumbbell break; 182254885Sdumbbell 183254885Sdumbbell case R200_EMIT_VAP_CTL:{ 184254885Sdumbbell RING_LOCALS; 185254885Sdumbbell BEGIN_RING(2); 186254885Sdumbbell OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 187254885Sdumbbell ADVANCE_RING(); 188254885Sdumbbell } 189254885Sdumbbell break; 190254885Sdumbbell 191254885Sdumbbell case RADEON_EMIT_RB3D_COLORPITCH: 192254885Sdumbbell case RADEON_EMIT_RE_LINE_PATTERN: 193254885Sdumbbell case RADEON_EMIT_SE_LINE_WIDTH: 194254885Sdumbbell case RADEON_EMIT_PP_LUM_MATRIX: 195254885Sdumbbell case RADEON_EMIT_PP_ROT_MATRIX_0: 196254885Sdumbbell case RADEON_EMIT_RB3D_STENCILREFMASK: 197254885Sdumbbell case RADEON_EMIT_SE_VPORT_XSCALE: 198254885Sdumbbell case RADEON_EMIT_SE_CNTL: 199254885Sdumbbell case RADEON_EMIT_SE_CNTL_STATUS: 200254885Sdumbbell case RADEON_EMIT_RE_MISC: 201254885Sdumbbell case RADEON_EMIT_PP_BORDER_COLOR_0: 202254885Sdumbbell case RADEON_EMIT_PP_BORDER_COLOR_1: 203254885Sdumbbell case RADEON_EMIT_PP_BORDER_COLOR_2: 204254885Sdumbbell case RADEON_EMIT_SE_ZBIAS_FACTOR: 205254885Sdumbbell case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT: 206254885Sdumbbell case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED: 207254885Sdumbbell case R200_EMIT_PP_TXCBLEND_0: 208254885Sdumbbell case R200_EMIT_PP_TXCBLEND_1: 209254885Sdumbbell case R200_EMIT_PP_TXCBLEND_2: 210254885Sdumbbell case R200_EMIT_PP_TXCBLEND_3: 211254885Sdumbbell case R200_EMIT_PP_TXCBLEND_4: 212254885Sdumbbell case R200_EMIT_PP_TXCBLEND_5: 213254885Sdumbbell case R200_EMIT_PP_TXCBLEND_6: 214254885Sdumbbell case R200_EMIT_PP_TXCBLEND_7: 215254885Sdumbbell case R200_EMIT_TCL_LIGHT_MODEL_CTL_0: 216254885Sdumbbell case R200_EMIT_TFACTOR_0: 217254885Sdumbbell case R200_EMIT_VTX_FMT_0: 218254885Sdumbbell case R200_EMIT_MATRIX_SELECT_0: 219254885Sdumbbell case R200_EMIT_TEX_PROC_CTL_2: 220254885Sdumbbell case R200_EMIT_TCL_UCP_VERT_BLEND_CTL: 221254885Sdumbbell case R200_EMIT_PP_TXFILTER_0: 222254885Sdumbbell case R200_EMIT_PP_TXFILTER_1: 223254885Sdumbbell case R200_EMIT_PP_TXFILTER_2: 224254885Sdumbbell case R200_EMIT_PP_TXFILTER_3: 225254885Sdumbbell case R200_EMIT_PP_TXFILTER_4: 226254885Sdumbbell case R200_EMIT_PP_TXFILTER_5: 227254885Sdumbbell case R200_EMIT_VTE_CNTL: 228254885Sdumbbell case R200_EMIT_OUTPUT_VTX_COMP_SEL: 229254885Sdumbbell case R200_EMIT_PP_TAM_DEBUG3: 230254885Sdumbbell case R200_EMIT_PP_CNTL_X: 231254885Sdumbbell case R200_EMIT_RB3D_DEPTHXY_OFFSET: 232254885Sdumbbell case R200_EMIT_RE_AUX_SCISSOR_CNTL: 233254885Sdumbbell case R200_EMIT_RE_SCISSOR_TL_0: 234254885Sdumbbell case R200_EMIT_RE_SCISSOR_TL_1: 235254885Sdumbbell case R200_EMIT_RE_SCISSOR_TL_2: 236254885Sdumbbell case R200_EMIT_SE_VAP_CNTL_STATUS: 237254885Sdumbbell case R200_EMIT_SE_VTX_STATE_CNTL: 238254885Sdumbbell case R200_EMIT_RE_POINTSIZE: 239254885Sdumbbell case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0: 240254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_0: 241254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_1: 242254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_2: 243254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_3: 244254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_4: 245254885Sdumbbell case R200_EMIT_PP_CUBIC_FACES_5: 246254885Sdumbbell case RADEON_EMIT_PP_TEX_SIZE_0: 247254885Sdumbbell case RADEON_EMIT_PP_TEX_SIZE_1: 248254885Sdumbbell case RADEON_EMIT_PP_TEX_SIZE_2: 249254885Sdumbbell case R200_EMIT_RB3D_BLENDCOLOR: 250254885Sdumbbell case R200_EMIT_TCL_POINT_SPRITE_CNTL: 251254885Sdumbbell case RADEON_EMIT_PP_CUBIC_FACES_0: 252254885Sdumbbell case RADEON_EMIT_PP_CUBIC_FACES_1: 253254885Sdumbbell case RADEON_EMIT_PP_CUBIC_FACES_2: 254254885Sdumbbell case R200_EMIT_PP_TRI_PERF_CNTL: 255254885Sdumbbell case R200_EMIT_PP_AFS_0: 256254885Sdumbbell case R200_EMIT_PP_AFS_1: 257254885Sdumbbell case R200_EMIT_ATF_TFACTOR: 258254885Sdumbbell case R200_EMIT_PP_TXCTLALL_0: 259254885Sdumbbell case R200_EMIT_PP_TXCTLALL_1: 260254885Sdumbbell case R200_EMIT_PP_TXCTLALL_2: 261254885Sdumbbell case R200_EMIT_PP_TXCTLALL_3: 262254885Sdumbbell case R200_EMIT_PP_TXCTLALL_4: 263254885Sdumbbell case R200_EMIT_PP_TXCTLALL_5: 264254885Sdumbbell case R200_EMIT_VAP_PVS_CNTL: 265254885Sdumbbell /* These packets don't contain memory offsets */ 266254885Sdumbbell break; 267254885Sdumbbell 268254885Sdumbbell default: 269254885Sdumbbell DRM_ERROR("Unknown state packet ID %d\n", id); 270254885Sdumbbell return -EINVAL; 271254885Sdumbbell } 272254885Sdumbbell 273254885Sdumbbell return 0; 274254885Sdumbbell} 275254885Sdumbbell 276254885Sdumbbellstatic int radeon_check_and_fixup_packet3(drm_radeon_private_t * 277254885Sdumbbell dev_priv, 278254885Sdumbbell struct drm_file *file_priv, 279254885Sdumbbell drm_radeon_kcmd_buffer_t * 280254885Sdumbbell cmdbuf, 281254885Sdumbbell unsigned int *cmdsz) 282254885Sdumbbell{ 283254885Sdumbbell u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0); 284254885Sdumbbell u32 offset, narrays; 285254885Sdumbbell int count, i, k; 286254885Sdumbbell 287254885Sdumbbell count = ((*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16); 288254885Sdumbbell *cmdsz = 2 + count; 289254885Sdumbbell 290254885Sdumbbell if ((*cmd & 0xc0000000) != RADEON_CP_PACKET3) { 291254885Sdumbbell DRM_ERROR("Not a type 3 packet\n"); 292254885Sdumbbell return -EINVAL; 293254885Sdumbbell } 294254885Sdumbbell 295254885Sdumbbell if (4 * *cmdsz > drm_buffer_unprocessed(cmdbuf->buffer)) { 296254885Sdumbbell DRM_ERROR("Packet size larger than size of data provided\n"); 297254885Sdumbbell return -EINVAL; 298254885Sdumbbell } 299254885Sdumbbell 300254885Sdumbbell switch (*cmd & 0xff00) { 301254885Sdumbbell /* XXX Are there old drivers needing other packets? */ 302254885Sdumbbell 303254885Sdumbbell case RADEON_3D_DRAW_IMMD: 304254885Sdumbbell case RADEON_3D_DRAW_VBUF: 305254885Sdumbbell case RADEON_3D_DRAW_INDX: 306254885Sdumbbell case RADEON_WAIT_FOR_IDLE: 307254885Sdumbbell case RADEON_CP_NOP: 308254885Sdumbbell case RADEON_3D_CLEAR_ZMASK: 309254885Sdumbbell/* case RADEON_CP_NEXT_CHAR: 310254885Sdumbbell case RADEON_CP_PLY_NEXTSCAN: 311254885Sdumbbell case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ 312254885Sdumbbell /* these packets are safe */ 313254885Sdumbbell break; 314254885Sdumbbell 315254885Sdumbbell case RADEON_CP_3D_DRAW_IMMD_2: 316254885Sdumbbell case RADEON_CP_3D_DRAW_VBUF_2: 317254885Sdumbbell case RADEON_CP_3D_DRAW_INDX_2: 318254885Sdumbbell case RADEON_3D_CLEAR_HIZ: 319254885Sdumbbell /* safe but r200 only */ 320254885Sdumbbell if (dev_priv->microcode_version != UCODE_R200) { 321254885Sdumbbell DRM_ERROR("Invalid 3d packet for r100-class chip\n"); 322254885Sdumbbell return -EINVAL; 323254885Sdumbbell } 324254885Sdumbbell break; 325254885Sdumbbell 326254885Sdumbbell case RADEON_3D_LOAD_VBPNTR: 327254885Sdumbbell 328254885Sdumbbell if (count > 18) { /* 12 arrays max */ 329254885Sdumbbell DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", 330254885Sdumbbell count); 331254885Sdumbbell return -EINVAL; 332254885Sdumbbell } 333254885Sdumbbell 334254885Sdumbbell /* carefully check packet contents */ 335254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1); 336254885Sdumbbell 337254885Sdumbbell narrays = *cmd & ~0xc000; 338254885Sdumbbell k = 0; 339254885Sdumbbell i = 2; 340254885Sdumbbell while ((k < narrays) && (i < (count + 2))) { 341254885Sdumbbell i++; /* skip attribute field */ 342254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i); 343254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 344254885Sdumbbell cmd)) { 345254885Sdumbbell DRM_ERROR 346254885Sdumbbell ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", 347254885Sdumbbell k, i); 348254885Sdumbbell return -EINVAL; 349254885Sdumbbell } 350254885Sdumbbell k++; 351254885Sdumbbell i++; 352254885Sdumbbell if (k == narrays) 353254885Sdumbbell break; 354254885Sdumbbell /* have one more to process, they come in pairs */ 355254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i); 356254885Sdumbbell 357254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, 358254885Sdumbbell file_priv, cmd)) 359254885Sdumbbell { 360254885Sdumbbell DRM_ERROR 361254885Sdumbbell ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", 362254885Sdumbbell k, i); 363254885Sdumbbell return -EINVAL; 364254885Sdumbbell } 365254885Sdumbbell k++; 366254885Sdumbbell i++; 367254885Sdumbbell } 368254885Sdumbbell /* do the counts match what we expect ? */ 369254885Sdumbbell if ((k != narrays) || (i != (count + 2))) { 370254885Sdumbbell DRM_ERROR 371254885Sdumbbell ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", 372254885Sdumbbell k, i, narrays, count + 1); 373254885Sdumbbell return -EINVAL; 374254885Sdumbbell } 375254885Sdumbbell break; 376254885Sdumbbell 377254885Sdumbbell case RADEON_3D_RNDR_GEN_INDX_PRIM: 378254885Sdumbbell if (dev_priv->microcode_version != UCODE_R100) { 379254885Sdumbbell DRM_ERROR("Invalid 3d packet for r200-class chip\n"); 380254885Sdumbbell return -EINVAL; 381254885Sdumbbell } 382254885Sdumbbell 383254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1); 384254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) { 385254885Sdumbbell DRM_ERROR("Invalid rndr_gen_indx offset\n"); 386254885Sdumbbell return -EINVAL; 387254885Sdumbbell } 388254885Sdumbbell break; 389254885Sdumbbell 390254885Sdumbbell case RADEON_CP_INDX_BUFFER: 391254885Sdumbbell if (dev_priv->microcode_version != UCODE_R200) { 392254885Sdumbbell DRM_ERROR("Invalid 3d packet for r100-class chip\n"); 393254885Sdumbbell return -EINVAL; 394254885Sdumbbell } 395254885Sdumbbell 396254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1); 397254885Sdumbbell if ((*cmd & 0x8000ffff) != 0x80000810) { 398254885Sdumbbell DRM_ERROR("Invalid indx_buffer reg address %08X\n", *cmd); 399254885Sdumbbell return -EINVAL; 400254885Sdumbbell } 401254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2); 402254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) { 403254885Sdumbbell DRM_ERROR("Invalid indx_buffer offset is %08X\n", *cmd); 404254885Sdumbbell return -EINVAL; 405254885Sdumbbell } 406254885Sdumbbell break; 407254885Sdumbbell 408254885Sdumbbell case RADEON_CNTL_HOSTDATA_BLT: 409254885Sdumbbell case RADEON_CNTL_PAINT_MULTI: 410254885Sdumbbell case RADEON_CNTL_BITBLT_MULTI: 411254885Sdumbbell /* MSB of opcode: next DWORD GUI_CNTL */ 412254885Sdumbbell cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1); 413254885Sdumbbell if (*cmd & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL 414254885Sdumbbell | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { 415254885Sdumbbell u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2); 416254885Sdumbbell offset = *cmd2 << 10; 417254885Sdumbbell if (radeon_check_and_fixup_offset 418254885Sdumbbell (dev_priv, file_priv, &offset)) { 419254885Sdumbbell DRM_ERROR("Invalid first packet offset\n"); 420254885Sdumbbell return -EINVAL; 421254885Sdumbbell } 422254885Sdumbbell *cmd2 = (*cmd2 & 0xffc00000) | offset >> 10; 423254885Sdumbbell } 424254885Sdumbbell 425254885Sdumbbell if ((*cmd & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && 426254885Sdumbbell (*cmd & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { 427254885Sdumbbell u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3); 428254885Sdumbbell offset = *cmd3 << 10; 429254885Sdumbbell if (radeon_check_and_fixup_offset 430254885Sdumbbell (dev_priv, file_priv, &offset)) { 431254885Sdumbbell DRM_ERROR("Invalid second packet offset\n"); 432254885Sdumbbell return -EINVAL; 433254885Sdumbbell } 434254885Sdumbbell *cmd3 = (*cmd3 & 0xffc00000) | offset >> 10; 435254885Sdumbbell } 436254885Sdumbbell break; 437254885Sdumbbell 438254885Sdumbbell default: 439254885Sdumbbell DRM_ERROR("Invalid packet type %x\n", *cmd & 0xff00); 440254885Sdumbbell return -EINVAL; 441254885Sdumbbell } 442254885Sdumbbell 443254885Sdumbbell return 0; 444254885Sdumbbell} 445254885Sdumbbell 446254885Sdumbbell/* ================================================================ 447254885Sdumbbell * CP hardware state programming functions 448254885Sdumbbell */ 449254885Sdumbbell 450254885Sdumbbellstatic void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv, 451254885Sdumbbell struct drm_clip_rect * box) 452254885Sdumbbell{ 453254885Sdumbbell RING_LOCALS; 454254885Sdumbbell 455254885Sdumbbell DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n", 456254885Sdumbbell box->x1, box->y1, box->x2, box->y2); 457254885Sdumbbell 458254885Sdumbbell BEGIN_RING(4); 459254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0)); 460254885Sdumbbell OUT_RING((box->y1 << 16) | box->x1); 461254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0)); 462254885Sdumbbell OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1)); 463254885Sdumbbell ADVANCE_RING(); 464254885Sdumbbell} 465254885Sdumbbell 466254885Sdumbbell/* Emit 1.1 state 467254885Sdumbbell */ 468254885Sdumbbellstatic int radeon_emit_state(drm_radeon_private_t * dev_priv, 469254885Sdumbbell struct drm_file *file_priv, 470254885Sdumbbell drm_radeon_context_regs_t * ctx, 471254885Sdumbbell drm_radeon_texture_regs_t * tex, 472254885Sdumbbell unsigned int dirty) 473254885Sdumbbell{ 474254885Sdumbbell RING_LOCALS; 475254885Sdumbbell DRM_DEBUG("dirty=0x%08x\n", dirty); 476254885Sdumbbell 477254885Sdumbbell if (dirty & RADEON_UPLOAD_CONTEXT) { 478254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 479254885Sdumbbell &ctx->rb3d_depthoffset)) { 480254885Sdumbbell DRM_ERROR("Invalid depth buffer offset\n"); 481254885Sdumbbell return -EINVAL; 482254885Sdumbbell } 483254885Sdumbbell 484254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 485254885Sdumbbell &ctx->rb3d_coloroffset)) { 486254885Sdumbbell DRM_ERROR("Invalid depth buffer offset\n"); 487254885Sdumbbell return -EINVAL; 488254885Sdumbbell } 489254885Sdumbbell 490254885Sdumbbell BEGIN_RING(14); 491254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6)); 492254885Sdumbbell OUT_RING(ctx->pp_misc); 493254885Sdumbbell OUT_RING(ctx->pp_fog_color); 494254885Sdumbbell OUT_RING(ctx->re_solid_color); 495254885Sdumbbell OUT_RING(ctx->rb3d_blendcntl); 496254885Sdumbbell OUT_RING(ctx->rb3d_depthoffset); 497254885Sdumbbell OUT_RING(ctx->rb3d_depthpitch); 498254885Sdumbbell OUT_RING(ctx->rb3d_zstencilcntl); 499254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2)); 500254885Sdumbbell OUT_RING(ctx->pp_cntl); 501254885Sdumbbell OUT_RING(ctx->rb3d_cntl); 502254885Sdumbbell OUT_RING(ctx->rb3d_coloroffset); 503254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0)); 504254885Sdumbbell OUT_RING(ctx->rb3d_colorpitch); 505254885Sdumbbell ADVANCE_RING(); 506254885Sdumbbell } 507254885Sdumbbell 508254885Sdumbbell if (dirty & RADEON_UPLOAD_VERTFMT) { 509254885Sdumbbell BEGIN_RING(2); 510254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0)); 511254885Sdumbbell OUT_RING(ctx->se_coord_fmt); 512254885Sdumbbell ADVANCE_RING(); 513254885Sdumbbell } 514254885Sdumbbell 515254885Sdumbbell if (dirty & RADEON_UPLOAD_LINE) { 516254885Sdumbbell BEGIN_RING(5); 517254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1)); 518254885Sdumbbell OUT_RING(ctx->re_line_pattern); 519254885Sdumbbell OUT_RING(ctx->re_line_state); 520254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0)); 521254885Sdumbbell OUT_RING(ctx->se_line_width); 522254885Sdumbbell ADVANCE_RING(); 523254885Sdumbbell } 524254885Sdumbbell 525254885Sdumbbell if (dirty & RADEON_UPLOAD_BUMPMAP) { 526254885Sdumbbell BEGIN_RING(5); 527254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0)); 528254885Sdumbbell OUT_RING(ctx->pp_lum_matrix); 529254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1)); 530254885Sdumbbell OUT_RING(ctx->pp_rot_matrix_0); 531254885Sdumbbell OUT_RING(ctx->pp_rot_matrix_1); 532254885Sdumbbell ADVANCE_RING(); 533254885Sdumbbell } 534254885Sdumbbell 535254885Sdumbbell if (dirty & RADEON_UPLOAD_MASKS) { 536254885Sdumbbell BEGIN_RING(4); 537254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2)); 538254885Sdumbbell OUT_RING(ctx->rb3d_stencilrefmask); 539254885Sdumbbell OUT_RING(ctx->rb3d_ropcntl); 540254885Sdumbbell OUT_RING(ctx->rb3d_planemask); 541254885Sdumbbell ADVANCE_RING(); 542254885Sdumbbell } 543254885Sdumbbell 544254885Sdumbbell if (dirty & RADEON_UPLOAD_VIEWPORT) { 545254885Sdumbbell BEGIN_RING(7); 546254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5)); 547254885Sdumbbell OUT_RING(ctx->se_vport_xscale); 548254885Sdumbbell OUT_RING(ctx->se_vport_xoffset); 549254885Sdumbbell OUT_RING(ctx->se_vport_yscale); 550254885Sdumbbell OUT_RING(ctx->se_vport_yoffset); 551254885Sdumbbell OUT_RING(ctx->se_vport_zscale); 552254885Sdumbbell OUT_RING(ctx->se_vport_zoffset); 553254885Sdumbbell ADVANCE_RING(); 554254885Sdumbbell } 555254885Sdumbbell 556254885Sdumbbell if (dirty & RADEON_UPLOAD_SETUP) { 557254885Sdumbbell BEGIN_RING(4); 558254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0)); 559254885Sdumbbell OUT_RING(ctx->se_cntl); 560254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0)); 561254885Sdumbbell OUT_RING(ctx->se_cntl_status); 562254885Sdumbbell ADVANCE_RING(); 563254885Sdumbbell } 564254885Sdumbbell 565254885Sdumbbell if (dirty & RADEON_UPLOAD_MISC) { 566254885Sdumbbell BEGIN_RING(2); 567254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0)); 568254885Sdumbbell OUT_RING(ctx->re_misc); 569254885Sdumbbell ADVANCE_RING(); 570254885Sdumbbell } 571254885Sdumbbell 572254885Sdumbbell if (dirty & RADEON_UPLOAD_TEX0) { 573254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 574254885Sdumbbell &tex[0].pp_txoffset)) { 575254885Sdumbbell DRM_ERROR("Invalid texture offset for unit 0\n"); 576254885Sdumbbell return -EINVAL; 577254885Sdumbbell } 578254885Sdumbbell 579254885Sdumbbell BEGIN_RING(9); 580254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5)); 581254885Sdumbbell OUT_RING(tex[0].pp_txfilter); 582254885Sdumbbell OUT_RING(tex[0].pp_txformat); 583254885Sdumbbell OUT_RING(tex[0].pp_txoffset); 584254885Sdumbbell OUT_RING(tex[0].pp_txcblend); 585254885Sdumbbell OUT_RING(tex[0].pp_txablend); 586254885Sdumbbell OUT_RING(tex[0].pp_tfactor); 587254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0)); 588254885Sdumbbell OUT_RING(tex[0].pp_border_color); 589254885Sdumbbell ADVANCE_RING(); 590254885Sdumbbell } 591254885Sdumbbell 592254885Sdumbbell if (dirty & RADEON_UPLOAD_TEX1) { 593254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 594254885Sdumbbell &tex[1].pp_txoffset)) { 595254885Sdumbbell DRM_ERROR("Invalid texture offset for unit 1\n"); 596254885Sdumbbell return -EINVAL; 597254885Sdumbbell } 598254885Sdumbbell 599254885Sdumbbell BEGIN_RING(9); 600254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5)); 601254885Sdumbbell OUT_RING(tex[1].pp_txfilter); 602254885Sdumbbell OUT_RING(tex[1].pp_txformat); 603254885Sdumbbell OUT_RING(tex[1].pp_txoffset); 604254885Sdumbbell OUT_RING(tex[1].pp_txcblend); 605254885Sdumbbell OUT_RING(tex[1].pp_txablend); 606254885Sdumbbell OUT_RING(tex[1].pp_tfactor); 607254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0)); 608254885Sdumbbell OUT_RING(tex[1].pp_border_color); 609254885Sdumbbell ADVANCE_RING(); 610254885Sdumbbell } 611254885Sdumbbell 612254885Sdumbbell if (dirty & RADEON_UPLOAD_TEX2) { 613254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, 614254885Sdumbbell &tex[2].pp_txoffset)) { 615254885Sdumbbell DRM_ERROR("Invalid texture offset for unit 2\n"); 616254885Sdumbbell return -EINVAL; 617254885Sdumbbell } 618254885Sdumbbell 619254885Sdumbbell BEGIN_RING(9); 620254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5)); 621254885Sdumbbell OUT_RING(tex[2].pp_txfilter); 622254885Sdumbbell OUT_RING(tex[2].pp_txformat); 623254885Sdumbbell OUT_RING(tex[2].pp_txoffset); 624254885Sdumbbell OUT_RING(tex[2].pp_txcblend); 625254885Sdumbbell OUT_RING(tex[2].pp_txablend); 626254885Sdumbbell OUT_RING(tex[2].pp_tfactor); 627254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0)); 628254885Sdumbbell OUT_RING(tex[2].pp_border_color); 629254885Sdumbbell ADVANCE_RING(); 630254885Sdumbbell } 631254885Sdumbbell 632254885Sdumbbell return 0; 633254885Sdumbbell} 634254885Sdumbbell 635254885Sdumbbell/* Emit 1.2 state 636254885Sdumbbell */ 637254885Sdumbbellstatic int radeon_emit_state2(drm_radeon_private_t * dev_priv, 638254885Sdumbbell struct drm_file *file_priv, 639254885Sdumbbell drm_radeon_state_t * state) 640254885Sdumbbell{ 641254885Sdumbbell RING_LOCALS; 642254885Sdumbbell 643254885Sdumbbell if (state->dirty & RADEON_UPLOAD_ZBIAS) { 644254885Sdumbbell BEGIN_RING(3); 645254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1)); 646254885Sdumbbell OUT_RING(state->context2.se_zbias_factor); 647254885Sdumbbell OUT_RING(state->context2.se_zbias_constant); 648254885Sdumbbell ADVANCE_RING(); 649254885Sdumbbell } 650254885Sdumbbell 651254885Sdumbbell return radeon_emit_state(dev_priv, file_priv, &state->context, 652254885Sdumbbell state->tex, state->dirty); 653254885Sdumbbell} 654254885Sdumbbell 655254885Sdumbbell/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in 656254885Sdumbbell * 1.3 cmdbuffers allow all previous state to be updated as well as 657254885Sdumbbell * the tcl scalar and vector areas. 658254885Sdumbbell */ 659254885Sdumbbellstatic struct { 660254885Sdumbbell int start; 661254885Sdumbbell int len; 662254885Sdumbbell const char *name; 663254885Sdumbbell} packet[RADEON_MAX_STATE_PACKETS] = { 664254885Sdumbbell {RADEON_PP_MISC, 7, "RADEON_PP_MISC"}, 665254885Sdumbbell {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"}, 666254885Sdumbbell {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"}, 667254885Sdumbbell {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"}, 668254885Sdumbbell {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"}, 669254885Sdumbbell {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"}, 670254885Sdumbbell {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"}, 671254885Sdumbbell {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"}, 672254885Sdumbbell {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"}, 673254885Sdumbbell {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"}, 674254885Sdumbbell {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"}, 675254885Sdumbbell {RADEON_RE_MISC, 1, "RADEON_RE_MISC"}, 676254885Sdumbbell {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"}, 677254885Sdumbbell {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"}, 678254885Sdumbbell {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"}, 679254885Sdumbbell {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"}, 680254885Sdumbbell {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"}, 681254885Sdumbbell {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"}, 682254885Sdumbbell {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"}, 683254885Sdumbbell {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"}, 684254885Sdumbbell {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17, 685254885Sdumbbell "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"}, 686254885Sdumbbell {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"}, 687254885Sdumbbell {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"}, 688254885Sdumbbell {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"}, 689254885Sdumbbell {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"}, 690254885Sdumbbell {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"}, 691254885Sdumbbell {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"}, 692254885Sdumbbell {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"}, 693254885Sdumbbell {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"}, 694254885Sdumbbell {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"}, 695254885Sdumbbell {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"}, 696254885Sdumbbell {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"}, 697254885Sdumbbell {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"}, 698254885Sdumbbell {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"}, 699254885Sdumbbell {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"}, 700254885Sdumbbell {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"}, 701254885Sdumbbell {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"}, 702254885Sdumbbell {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"}, 703254885Sdumbbell {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"}, 704254885Sdumbbell {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"}, 705254885Sdumbbell {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"}, 706254885Sdumbbell {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"}, 707254885Sdumbbell {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"}, 708254885Sdumbbell {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"}, 709254885Sdumbbell {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"}, 710254885Sdumbbell {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"}, 711254885Sdumbbell {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"}, 712254885Sdumbbell {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"}, 713254885Sdumbbell {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"}, 714254885Sdumbbell {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1, 715254885Sdumbbell "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"}, 716254885Sdumbbell {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"}, 717254885Sdumbbell {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"}, 718254885Sdumbbell {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"}, 719254885Sdumbbell {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"}, 720254885Sdumbbell {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"}, 721254885Sdumbbell {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"}, 722254885Sdumbbell {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"}, 723254885Sdumbbell {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"}, 724254885Sdumbbell {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"}, 725254885Sdumbbell {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"}, 726254885Sdumbbell {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4, 727254885Sdumbbell "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"}, 728254885Sdumbbell {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */ 729254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */ 730254885Sdumbbell {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"}, 731254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"}, 732254885Sdumbbell {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"}, 733254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"}, 734254885Sdumbbell {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"}, 735254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"}, 736254885Sdumbbell {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"}, 737254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"}, 738254885Sdumbbell {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"}, 739254885Sdumbbell {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"}, 740254885Sdumbbell {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"}, 741254885Sdumbbell {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"}, 742254885Sdumbbell {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"}, 743254885Sdumbbell {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"}, 744254885Sdumbbell {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"}, 745254885Sdumbbell {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"}, 746254885Sdumbbell {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"}, 747254885Sdumbbell {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"}, 748254885Sdumbbell {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"}, 749254885Sdumbbell {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"}, 750254885Sdumbbell {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"}, 751254885Sdumbbell {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"}, 752254885Sdumbbell {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */ 753254885Sdumbbell {R200_PP_AFS_1, 32, "R200_PP_AFS_1"}, 754254885Sdumbbell {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"}, 755254885Sdumbbell {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"}, 756254885Sdumbbell {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"}, 757254885Sdumbbell {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"}, 758254885Sdumbbell {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"}, 759254885Sdumbbell {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"}, 760254885Sdumbbell {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"}, 761254885Sdumbbell {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"}, 762254885Sdumbbell}; 763254885Sdumbbell 764254885Sdumbbell/* ================================================================ 765254885Sdumbbell * Performance monitoring functions 766254885Sdumbbell */ 767254885Sdumbbell 768254885Sdumbbellstatic void radeon_clear_box(drm_radeon_private_t * dev_priv, 769254885Sdumbbell struct drm_radeon_master_private *master_priv, 770254885Sdumbbell int x, int y, int w, int h, int r, int g, int b) 771254885Sdumbbell{ 772254885Sdumbbell u32 color; 773254885Sdumbbell RING_LOCALS; 774254885Sdumbbell 775254885Sdumbbell x += master_priv->sarea_priv->boxes[0].x1; 776254885Sdumbbell y += master_priv->sarea_priv->boxes[0].y1; 777254885Sdumbbell 778254885Sdumbbell switch (dev_priv->color_fmt) { 779254885Sdumbbell case RADEON_COLOR_FORMAT_RGB565: 780254885Sdumbbell color = (((r & 0xf8) << 8) | 781254885Sdumbbell ((g & 0xfc) << 3) | ((b & 0xf8) >> 3)); 782254885Sdumbbell break; 783254885Sdumbbell case RADEON_COLOR_FORMAT_ARGB8888: 784254885Sdumbbell default: 785254885Sdumbbell color = (((0xff) << 24) | (r << 16) | (g << 8) | b); 786254885Sdumbbell break; 787254885Sdumbbell } 788254885Sdumbbell 789254885Sdumbbell BEGIN_RING(4); 790254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 791254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0)); 792254885Sdumbbell OUT_RING(0xffffffff); 793254885Sdumbbell ADVANCE_RING(); 794254885Sdumbbell 795254885Sdumbbell BEGIN_RING(6); 796254885Sdumbbell 797254885Sdumbbell OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4)); 798254885Sdumbbell OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 799254885Sdumbbell RADEON_GMC_BRUSH_SOLID_COLOR | 800254885Sdumbbell (dev_priv->color_fmt << 8) | 801254885Sdumbbell RADEON_GMC_SRC_DATATYPE_COLOR | 802254885Sdumbbell RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); 803254885Sdumbbell 804254885Sdumbbell if (master_priv->sarea_priv->pfCurrentPage == 1) { 805254885Sdumbbell OUT_RING(dev_priv->front_pitch_offset); 806254885Sdumbbell } else { 807254885Sdumbbell OUT_RING(dev_priv->back_pitch_offset); 808254885Sdumbbell } 809254885Sdumbbell 810254885Sdumbbell OUT_RING(color); 811254885Sdumbbell 812254885Sdumbbell OUT_RING((x << 16) | y); 813254885Sdumbbell OUT_RING((w << 16) | h); 814254885Sdumbbell 815254885Sdumbbell ADVANCE_RING(); 816254885Sdumbbell} 817254885Sdumbbell 818254885Sdumbbellstatic void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv, struct drm_radeon_master_private *master_priv) 819254885Sdumbbell{ 820254885Sdumbbell /* Collapse various things into a wait flag -- trying to 821254885Sdumbbell * guess if userspase slept -- better just to have them tell us. 822254885Sdumbbell */ 823254885Sdumbbell if (dev_priv->stats.last_frame_reads > 1 || 824254885Sdumbbell dev_priv->stats.last_clear_reads > dev_priv->stats.clears) { 825254885Sdumbbell dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 826254885Sdumbbell } 827254885Sdumbbell 828254885Sdumbbell if (dev_priv->stats.freelist_loops) { 829254885Sdumbbell dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 830254885Sdumbbell } 831254885Sdumbbell 832254885Sdumbbell /* Purple box for page flipping 833254885Sdumbbell */ 834254885Sdumbbell if (dev_priv->stats.boxes & RADEON_BOX_FLIP) 835254885Sdumbbell radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255); 836254885Sdumbbell 837254885Sdumbbell /* Red box if we have to wait for idle at any point 838254885Sdumbbell */ 839254885Sdumbbell if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) 840254885Sdumbbell radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0); 841254885Sdumbbell 842254885Sdumbbell /* Blue box: lost context? 843254885Sdumbbell */ 844254885Sdumbbell 845254885Sdumbbell /* Yellow box for texture swaps 846254885Sdumbbell */ 847254885Sdumbbell if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) 848254885Sdumbbell radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0); 849254885Sdumbbell 850254885Sdumbbell /* Green box if hardware never idles (as far as we can tell) 851254885Sdumbbell */ 852254885Sdumbbell if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) 853254885Sdumbbell radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0); 854254885Sdumbbell 855254885Sdumbbell /* Draw bars indicating number of buffers allocated 856254885Sdumbbell * (not a great measure, easily confused) 857254885Sdumbbell */ 858254885Sdumbbell if (dev_priv->stats.requested_bufs) { 859254885Sdumbbell if (dev_priv->stats.requested_bufs > 100) 860254885Sdumbbell dev_priv->stats.requested_bufs = 100; 861254885Sdumbbell 862254885Sdumbbell radeon_clear_box(dev_priv, master_priv, 4, 16, 863254885Sdumbbell dev_priv->stats.requested_bufs, 4, 864254885Sdumbbell 196, 128, 128); 865254885Sdumbbell } 866254885Sdumbbell 867254885Sdumbbell memset(&dev_priv->stats, 0, sizeof(dev_priv->stats)); 868254885Sdumbbell 869254885Sdumbbell} 870254885Sdumbbell 871254885Sdumbbell/* ================================================================ 872254885Sdumbbell * CP command dispatch functions 873254885Sdumbbell */ 874254885Sdumbbell 875254885Sdumbbellstatic void radeon_cp_dispatch_clear(struct drm_device * dev, 876254885Sdumbbell struct drm_master *master, 877254885Sdumbbell drm_radeon_clear_t * clear, 878254885Sdumbbell drm_radeon_clear_rect_t * depth_boxes) 879254885Sdumbbell{ 880254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 881254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 882254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 883254885Sdumbbell drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; 884254885Sdumbbell int nbox = sarea_priv->nbox; 885254885Sdumbbell struct drm_clip_rect *pbox = sarea_priv->boxes; 886254885Sdumbbell unsigned int flags = clear->flags; 887254885Sdumbbell u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0; 888254885Sdumbbell int i; 889254885Sdumbbell RING_LOCALS; 890254885Sdumbbell DRM_DEBUG("flags = 0x%x\n", flags); 891254885Sdumbbell 892254885Sdumbbell dev_priv->stats.clears++; 893254885Sdumbbell 894254885Sdumbbell if (sarea_priv->pfCurrentPage == 1) { 895254885Sdumbbell unsigned int tmp = flags; 896254885Sdumbbell 897254885Sdumbbell flags &= ~(RADEON_FRONT | RADEON_BACK); 898254885Sdumbbell if (tmp & RADEON_FRONT) 899254885Sdumbbell flags |= RADEON_BACK; 900254885Sdumbbell if (tmp & RADEON_BACK) 901254885Sdumbbell flags |= RADEON_FRONT; 902254885Sdumbbell } 903254885Sdumbbell if (flags & (RADEON_DEPTH|RADEON_STENCIL)) { 904254885Sdumbbell if (!dev_priv->have_z_offset) { 905254885Sdumbbell DRM_ERROR("radeon: illegal depth clear request. Buggy mesa detected - please update.\n"); 906254885Sdumbbell flags &= ~(RADEON_DEPTH | RADEON_STENCIL); 907254885Sdumbbell } 908254885Sdumbbell } 909254885Sdumbbell 910254885Sdumbbell if (flags & (RADEON_FRONT | RADEON_BACK)) { 911254885Sdumbbell 912254885Sdumbbell BEGIN_RING(4); 913254885Sdumbbell 914254885Sdumbbell /* Ensure the 3D stream is idle before doing a 915254885Sdumbbell * 2D fill to clear the front or back buffer. 916254885Sdumbbell */ 917254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 918254885Sdumbbell 919254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0)); 920254885Sdumbbell OUT_RING(clear->color_mask); 921254885Sdumbbell 922254885Sdumbbell ADVANCE_RING(); 923254885Sdumbbell 924254885Sdumbbell /* Make sure we restore the 3D state next time. 925254885Sdumbbell */ 926254885Sdumbbell sarea_priv->ctx_owner = 0; 927254885Sdumbbell 928254885Sdumbbell for (i = 0; i < nbox; i++) { 929254885Sdumbbell int x = pbox[i].x1; 930254885Sdumbbell int y = pbox[i].y1; 931254885Sdumbbell int w = pbox[i].x2 - x; 932254885Sdumbbell int h = pbox[i].y2 - y; 933254885Sdumbbell 934254885Sdumbbell DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n", 935254885Sdumbbell x, y, w, h, flags); 936254885Sdumbbell 937254885Sdumbbell if (flags & RADEON_FRONT) { 938254885Sdumbbell BEGIN_RING(6); 939254885Sdumbbell 940254885Sdumbbell OUT_RING(CP_PACKET3 941254885Sdumbbell (RADEON_CNTL_PAINT_MULTI, 4)); 942254885Sdumbbell OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 943254885Sdumbbell RADEON_GMC_BRUSH_SOLID_COLOR | 944254885Sdumbbell (dev_priv-> 945254885Sdumbbell color_fmt << 8) | 946254885Sdumbbell RADEON_GMC_SRC_DATATYPE_COLOR | 947254885Sdumbbell RADEON_ROP3_P | 948254885Sdumbbell RADEON_GMC_CLR_CMP_CNTL_DIS); 949254885Sdumbbell 950254885Sdumbbell OUT_RING(dev_priv->front_pitch_offset); 951254885Sdumbbell OUT_RING(clear->clear_color); 952254885Sdumbbell 953254885Sdumbbell OUT_RING((x << 16) | y); 954254885Sdumbbell OUT_RING((w << 16) | h); 955254885Sdumbbell 956254885Sdumbbell ADVANCE_RING(); 957254885Sdumbbell } 958254885Sdumbbell 959254885Sdumbbell if (flags & RADEON_BACK) { 960254885Sdumbbell BEGIN_RING(6); 961254885Sdumbbell 962254885Sdumbbell OUT_RING(CP_PACKET3 963254885Sdumbbell (RADEON_CNTL_PAINT_MULTI, 4)); 964254885Sdumbbell OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | 965254885Sdumbbell RADEON_GMC_BRUSH_SOLID_COLOR | 966254885Sdumbbell (dev_priv-> 967254885Sdumbbell color_fmt << 8) | 968254885Sdumbbell RADEON_GMC_SRC_DATATYPE_COLOR | 969254885Sdumbbell RADEON_ROP3_P | 970254885Sdumbbell RADEON_GMC_CLR_CMP_CNTL_DIS); 971254885Sdumbbell 972254885Sdumbbell OUT_RING(dev_priv->back_pitch_offset); 973254885Sdumbbell OUT_RING(clear->clear_color); 974254885Sdumbbell 975254885Sdumbbell OUT_RING((x << 16) | y); 976254885Sdumbbell OUT_RING((w << 16) | h); 977254885Sdumbbell 978254885Sdumbbell ADVANCE_RING(); 979254885Sdumbbell } 980254885Sdumbbell } 981254885Sdumbbell } 982254885Sdumbbell 983254885Sdumbbell /* hyper z clear */ 984254885Sdumbbell /* no docs available, based on reverse engineering by Stephane Marchesin */ 985254885Sdumbbell if ((flags & (RADEON_DEPTH | RADEON_STENCIL)) 986254885Sdumbbell && (flags & RADEON_CLEAR_FASTZ)) { 987254885Sdumbbell 988254885Sdumbbell int i; 989254885Sdumbbell int depthpixperline = 990254885Sdumbbell dev_priv->depth_fmt == 991254885Sdumbbell RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch / 992254885Sdumbbell 2) : (dev_priv-> 993254885Sdumbbell depth_pitch / 4); 994254885Sdumbbell 995254885Sdumbbell u32 clearmask; 996254885Sdumbbell 997254885Sdumbbell u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth | 998254885Sdumbbell ((clear->depth_mask & 0xff) << 24); 999254885Sdumbbell 1000254885Sdumbbell /* Make sure we restore the 3D state next time. 1001254885Sdumbbell * we haven't touched any "normal" state - still need this? 1002254885Sdumbbell */ 1003254885Sdumbbell sarea_priv->ctx_owner = 0; 1004254885Sdumbbell 1005254885Sdumbbell if ((dev_priv->flags & RADEON_HAS_HIERZ) 1006254885Sdumbbell && (flags & RADEON_USE_HIERZ)) { 1007254885Sdumbbell /* FIXME : reverse engineer that for Rx00 cards */ 1008254885Sdumbbell /* FIXME : the mask supposedly contains low-res z values. So can't set 1009254885Sdumbbell just to the max (0xff? or actually 0x3fff?), need to take z clear 1010254885Sdumbbell value into account? */ 1011254885Sdumbbell /* pattern seems to work for r100, though get slight 1012254885Sdumbbell rendering errors with glxgears. If hierz is not enabled for r100, 1013254885Sdumbbell only 4 bits which indicate clear (15,16,31,32, all zero) matter, the 1014254885Sdumbbell other ones are ignored, and the same clear mask can be used. That's 1015254885Sdumbbell very different behaviour than R200 which needs different clear mask 1016254885Sdumbbell and different number of tiles to clear if hierz is enabled or not !?! 1017254885Sdumbbell */ 1018254885Sdumbbell clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f; 1019254885Sdumbbell } else { 1020254885Sdumbbell /* clear mask : chooses the clearing pattern. 1021254885Sdumbbell rv250: could be used to clear only parts of macrotiles 1022254885Sdumbbell (but that would get really complicated...)? 1023254885Sdumbbell bit 0 and 1 (either or both of them ?!?!) are used to 1024254885Sdumbbell not clear tile (or maybe one of the bits indicates if the tile is 1025254885Sdumbbell compressed or not), bit 2 and 3 to not clear tile 1,...,. 1026254885Sdumbbell Pattern is as follows: 1027254885Sdumbbell | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29| 1028254885Sdumbbell bits ------------------------------------------------- 1029254885Sdumbbell | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31| 1030254885Sdumbbell rv100: clearmask covers 2x8 4x1 tiles, but one clear still 1031254885Sdumbbell covers 256 pixels ?!? 1032254885Sdumbbell */ 1033254885Sdumbbell clearmask = 0x0; 1034254885Sdumbbell } 1035254885Sdumbbell 1036254885Sdumbbell BEGIN_RING(8); 1037254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1038254885Sdumbbell OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE, 1039254885Sdumbbell tempRB3D_DEPTHCLEARVALUE); 1040254885Sdumbbell /* what offset is this exactly ? */ 1041254885Sdumbbell OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0); 1042254885Sdumbbell /* need ctlstat, otherwise get some strange black flickering */ 1043254885Sdumbbell OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT, 1044254885Sdumbbell RADEON_RB3D_ZC_FLUSH_ALL); 1045254885Sdumbbell ADVANCE_RING(); 1046254885Sdumbbell 1047254885Sdumbbell for (i = 0; i < nbox; i++) { 1048254885Sdumbbell int tileoffset, nrtilesx, nrtilesy, j; 1049254885Sdumbbell /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ 1050254885Sdumbbell if ((dev_priv->flags & RADEON_HAS_HIERZ) 1051254885Sdumbbell && !(dev_priv->microcode_version == UCODE_R200)) { 1052254885Sdumbbell /* FIXME : figure this out for r200 (when hierz is enabled). Or 1053254885Sdumbbell maybe r200 actually doesn't need to put the low-res z value into 1054254885Sdumbbell the tile cache like r100, but just needs to clear the hi-level z-buffer? 1055254885Sdumbbell Works for R100, both with hierz and without. 1056254885Sdumbbell R100 seems to operate on 2x1 8x8 tiles, but... 1057254885Sdumbbell odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially 1058254885Sdumbbell problematic with resolutions which are not 64 pix aligned? */ 1059254885Sdumbbell tileoffset = 1060254885Sdumbbell ((pbox[i].y1 >> 3) * depthpixperline + 1061254885Sdumbbell pbox[i].x1) >> 6; 1062254885Sdumbbell nrtilesx = 1063254885Sdumbbell ((pbox[i].x2 & ~63) - 1064254885Sdumbbell (pbox[i].x1 & ~63)) >> 4; 1065254885Sdumbbell nrtilesy = 1066254885Sdumbbell (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3); 1067254885Sdumbbell for (j = 0; j <= nrtilesy; j++) { 1068254885Sdumbbell BEGIN_RING(4); 1069254885Sdumbbell OUT_RING(CP_PACKET3 1070254885Sdumbbell (RADEON_3D_CLEAR_ZMASK, 2)); 1071254885Sdumbbell /* first tile */ 1072254885Sdumbbell OUT_RING(tileoffset * 8); 1073254885Sdumbbell /* the number of tiles to clear */ 1074254885Sdumbbell OUT_RING(nrtilesx + 4); 1075254885Sdumbbell /* clear mask : chooses the clearing pattern. */ 1076254885Sdumbbell OUT_RING(clearmask); 1077254885Sdumbbell ADVANCE_RING(); 1078254885Sdumbbell tileoffset += depthpixperline >> 6; 1079254885Sdumbbell } 1080254885Sdumbbell } else if (dev_priv->microcode_version == UCODE_R200) { 1081254885Sdumbbell /* works for rv250. */ 1082254885Sdumbbell /* find first macro tile (8x2 4x4 z-pixels on rv250) */ 1083254885Sdumbbell tileoffset = 1084254885Sdumbbell ((pbox[i].y1 >> 3) * depthpixperline + 1085254885Sdumbbell pbox[i].x1) >> 5; 1086254885Sdumbbell nrtilesx = 1087254885Sdumbbell (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5); 1088254885Sdumbbell nrtilesy = 1089254885Sdumbbell (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3); 1090254885Sdumbbell for (j = 0; j <= nrtilesy; j++) { 1091254885Sdumbbell BEGIN_RING(4); 1092254885Sdumbbell OUT_RING(CP_PACKET3 1093254885Sdumbbell (RADEON_3D_CLEAR_ZMASK, 2)); 1094254885Sdumbbell /* first tile */ 1095254885Sdumbbell /* judging by the first tile offset needed, could possibly 1096254885Sdumbbell directly address/clear 4x4 tiles instead of 8x2 * 4x4 1097254885Sdumbbell macro tiles, though would still need clear mask for 1098254885Sdumbbell right/bottom if truly 4x4 granularity is desired ? */ 1099254885Sdumbbell OUT_RING(tileoffset * 16); 1100254885Sdumbbell /* the number of tiles to clear */ 1101254885Sdumbbell OUT_RING(nrtilesx + 1); 1102254885Sdumbbell /* clear mask : chooses the clearing pattern. */ 1103254885Sdumbbell OUT_RING(clearmask); 1104254885Sdumbbell ADVANCE_RING(); 1105254885Sdumbbell tileoffset += depthpixperline >> 5; 1106254885Sdumbbell } 1107254885Sdumbbell } else { /* rv 100 */ 1108254885Sdumbbell /* rv100 might not need 64 pix alignment, who knows */ 1109254885Sdumbbell /* offsets are, hmm, weird */ 1110254885Sdumbbell tileoffset = 1111254885Sdumbbell ((pbox[i].y1 >> 4) * depthpixperline + 1112254885Sdumbbell pbox[i].x1) >> 6; 1113254885Sdumbbell nrtilesx = 1114254885Sdumbbell ((pbox[i].x2 & ~63) - 1115254885Sdumbbell (pbox[i].x1 & ~63)) >> 4; 1116254885Sdumbbell nrtilesy = 1117254885Sdumbbell (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4); 1118254885Sdumbbell for (j = 0; j <= nrtilesy; j++) { 1119254885Sdumbbell BEGIN_RING(4); 1120254885Sdumbbell OUT_RING(CP_PACKET3 1121254885Sdumbbell (RADEON_3D_CLEAR_ZMASK, 2)); 1122254885Sdumbbell OUT_RING(tileoffset * 128); 1123254885Sdumbbell /* the number of tiles to clear */ 1124254885Sdumbbell OUT_RING(nrtilesx + 4); 1125254885Sdumbbell /* clear mask : chooses the clearing pattern. */ 1126254885Sdumbbell OUT_RING(clearmask); 1127254885Sdumbbell ADVANCE_RING(); 1128254885Sdumbbell tileoffset += depthpixperline >> 6; 1129254885Sdumbbell } 1130254885Sdumbbell } 1131254885Sdumbbell } 1132254885Sdumbbell 1133254885Sdumbbell /* TODO don't always clear all hi-level z tiles */ 1134254885Sdumbbell if ((dev_priv->flags & RADEON_HAS_HIERZ) 1135254885Sdumbbell && (dev_priv->microcode_version == UCODE_R200) 1136254885Sdumbbell && (flags & RADEON_USE_HIERZ)) 1137254885Sdumbbell /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ 1138254885Sdumbbell /* FIXME : the mask supposedly contains low-res z values. So can't set 1139254885Sdumbbell just to the max (0xff? or actually 0x3fff?), need to take z clear 1140254885Sdumbbell value into account? */ 1141254885Sdumbbell { 1142254885Sdumbbell BEGIN_RING(4); 1143254885Sdumbbell OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2)); 1144254885Sdumbbell OUT_RING(0x0); /* First tile */ 1145254885Sdumbbell OUT_RING(0x3cc0); 1146254885Sdumbbell OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f); 1147254885Sdumbbell ADVANCE_RING(); 1148254885Sdumbbell } 1149254885Sdumbbell } 1150254885Sdumbbell 1151254885Sdumbbell /* We have to clear the depth and/or stencil buffers by 1152254885Sdumbbell * rendering a quad into just those buffers. Thus, we have to 1153254885Sdumbbell * make sure the 3D engine is configured correctly. 1154254885Sdumbbell */ 1155254885Sdumbbell else if ((dev_priv->microcode_version == UCODE_R200) && 1156254885Sdumbbell (flags & (RADEON_DEPTH | RADEON_STENCIL))) { 1157254885Sdumbbell 1158254885Sdumbbell int tempPP_CNTL; 1159254885Sdumbbell int tempRE_CNTL; 1160254885Sdumbbell int tempRB3D_CNTL; 1161254885Sdumbbell int tempRB3D_ZSTENCILCNTL; 1162254885Sdumbbell int tempRB3D_STENCILREFMASK; 1163254885Sdumbbell int tempRB3D_PLANEMASK; 1164254885Sdumbbell int tempSE_CNTL; 1165254885Sdumbbell int tempSE_VTE_CNTL; 1166254885Sdumbbell int tempSE_VTX_FMT_0; 1167254885Sdumbbell int tempSE_VTX_FMT_1; 1168254885Sdumbbell int tempSE_VAP_CNTL; 1169254885Sdumbbell int tempRE_AUX_SCISSOR_CNTL; 1170254885Sdumbbell 1171254885Sdumbbell tempPP_CNTL = 0; 1172254885Sdumbbell tempRE_CNTL = 0; 1173254885Sdumbbell 1174254885Sdumbbell tempRB3D_CNTL = depth_clear->rb3d_cntl; 1175254885Sdumbbell 1176254885Sdumbbell tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl; 1177254885Sdumbbell tempRB3D_STENCILREFMASK = 0x0; 1178254885Sdumbbell 1179254885Sdumbbell tempSE_CNTL = depth_clear->se_cntl; 1180254885Sdumbbell 1181254885Sdumbbell /* Disable TCL */ 1182254885Sdumbbell 1183254885Sdumbbell tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */ 1184254885Sdumbbell (0x9 << 1185254885Sdumbbell SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT)); 1186254885Sdumbbell 1187254885Sdumbbell tempRB3D_PLANEMASK = 0x0; 1188254885Sdumbbell 1189254885Sdumbbell tempRE_AUX_SCISSOR_CNTL = 0x0; 1190254885Sdumbbell 1191254885Sdumbbell tempSE_VTE_CNTL = 1192254885Sdumbbell SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK; 1193254885Sdumbbell 1194254885Sdumbbell /* Vertex format (X, Y, Z, W) */ 1195254885Sdumbbell tempSE_VTX_FMT_0 = 1196254885Sdumbbell SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK | 1197254885Sdumbbell SE_VTX_FMT_0__VTX_W0_PRESENT_MASK; 1198254885Sdumbbell tempSE_VTX_FMT_1 = 0x0; 1199254885Sdumbbell 1200254885Sdumbbell /* 1201254885Sdumbbell * Depth buffer specific enables 1202254885Sdumbbell */ 1203254885Sdumbbell if (flags & RADEON_DEPTH) { 1204254885Sdumbbell /* Enable depth buffer */ 1205254885Sdumbbell tempRB3D_CNTL |= RADEON_Z_ENABLE; 1206254885Sdumbbell } else { 1207254885Sdumbbell /* Disable depth buffer */ 1208254885Sdumbbell tempRB3D_CNTL &= ~RADEON_Z_ENABLE; 1209254885Sdumbbell } 1210254885Sdumbbell 1211254885Sdumbbell /* 1212254885Sdumbbell * Stencil buffer specific enables 1213254885Sdumbbell */ 1214254885Sdumbbell if (flags & RADEON_STENCIL) { 1215254885Sdumbbell tempRB3D_CNTL |= RADEON_STENCIL_ENABLE; 1216254885Sdumbbell tempRB3D_STENCILREFMASK = clear->depth_mask; 1217254885Sdumbbell } else { 1218254885Sdumbbell tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE; 1219254885Sdumbbell tempRB3D_STENCILREFMASK = 0x00000000; 1220254885Sdumbbell } 1221254885Sdumbbell 1222254885Sdumbbell if (flags & RADEON_USE_COMP_ZBUF) { 1223254885Sdumbbell tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE | 1224254885Sdumbbell RADEON_Z_DECOMPRESSION_ENABLE; 1225254885Sdumbbell } 1226254885Sdumbbell if (flags & RADEON_USE_HIERZ) { 1227254885Sdumbbell tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE; 1228254885Sdumbbell } 1229254885Sdumbbell 1230254885Sdumbbell BEGIN_RING(26); 1231254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1232254885Sdumbbell 1233254885Sdumbbell OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL); 1234254885Sdumbbell OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL); 1235254885Sdumbbell OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL); 1236254885Sdumbbell OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL); 1237254885Sdumbbell OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, 1238254885Sdumbbell tempRB3D_STENCILREFMASK); 1239254885Sdumbbell OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK); 1240254885Sdumbbell OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL); 1241254885Sdumbbell OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL); 1242254885Sdumbbell OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0); 1243254885Sdumbbell OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1); 1244254885Sdumbbell OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL); 1245254885Sdumbbell OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL); 1246254885Sdumbbell ADVANCE_RING(); 1247254885Sdumbbell 1248254885Sdumbbell /* Make sure we restore the 3D state next time. 1249254885Sdumbbell */ 1250254885Sdumbbell sarea_priv->ctx_owner = 0; 1251254885Sdumbbell 1252254885Sdumbbell for (i = 0; i < nbox; i++) { 1253254885Sdumbbell 1254254885Sdumbbell /* Funny that this should be required -- 1255254885Sdumbbell * sets top-left? 1256254885Sdumbbell */ 1257254885Sdumbbell radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 1258254885Sdumbbell 1259254885Sdumbbell BEGIN_RING(14); 1260254885Sdumbbell OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12)); 1261254885Sdumbbell OUT_RING((RADEON_PRIM_TYPE_RECT_LIST | 1262254885Sdumbbell RADEON_PRIM_WALK_RING | 1263254885Sdumbbell (3 << RADEON_NUM_VERTICES_SHIFT))); 1264254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1265254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y1]); 1266254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1267254885Sdumbbell OUT_RING(0x3f800000); 1268254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1269254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1270254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1271254885Sdumbbell OUT_RING(0x3f800000); 1272254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X2]); 1273254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1274254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1275254885Sdumbbell OUT_RING(0x3f800000); 1276254885Sdumbbell ADVANCE_RING(); 1277254885Sdumbbell } 1278254885Sdumbbell } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) { 1279254885Sdumbbell 1280254885Sdumbbell int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl; 1281254885Sdumbbell 1282254885Sdumbbell rb3d_cntl = depth_clear->rb3d_cntl; 1283254885Sdumbbell 1284254885Sdumbbell if (flags & RADEON_DEPTH) { 1285254885Sdumbbell rb3d_cntl |= RADEON_Z_ENABLE; 1286254885Sdumbbell } else { 1287254885Sdumbbell rb3d_cntl &= ~RADEON_Z_ENABLE; 1288254885Sdumbbell } 1289254885Sdumbbell 1290254885Sdumbbell if (flags & RADEON_STENCIL) { 1291254885Sdumbbell rb3d_cntl |= RADEON_STENCIL_ENABLE; 1292254885Sdumbbell rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */ 1293254885Sdumbbell } else { 1294254885Sdumbbell rb3d_cntl &= ~RADEON_STENCIL_ENABLE; 1295254885Sdumbbell rb3d_stencilrefmask = 0x00000000; 1296254885Sdumbbell } 1297254885Sdumbbell 1298254885Sdumbbell if (flags & RADEON_USE_COMP_ZBUF) { 1299254885Sdumbbell tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE | 1300254885Sdumbbell RADEON_Z_DECOMPRESSION_ENABLE; 1301254885Sdumbbell } 1302254885Sdumbbell if (flags & RADEON_USE_HIERZ) { 1303254885Sdumbbell tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE; 1304254885Sdumbbell } 1305254885Sdumbbell 1306254885Sdumbbell BEGIN_RING(13); 1307254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1308254885Sdumbbell 1309254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1)); 1310254885Sdumbbell OUT_RING(0x00000000); 1311254885Sdumbbell OUT_RING(rb3d_cntl); 1312254885Sdumbbell 1313254885Sdumbbell OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL); 1314254885Sdumbbell OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask); 1315254885Sdumbbell OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000); 1316254885Sdumbbell OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl); 1317254885Sdumbbell ADVANCE_RING(); 1318254885Sdumbbell 1319254885Sdumbbell /* Make sure we restore the 3D state next time. 1320254885Sdumbbell */ 1321254885Sdumbbell sarea_priv->ctx_owner = 0; 1322254885Sdumbbell 1323254885Sdumbbell for (i = 0; i < nbox; i++) { 1324254885Sdumbbell 1325254885Sdumbbell /* Funny that this should be required -- 1326254885Sdumbbell * sets top-left? 1327254885Sdumbbell */ 1328254885Sdumbbell radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 1329254885Sdumbbell 1330254885Sdumbbell BEGIN_RING(15); 1331254885Sdumbbell 1332254885Sdumbbell OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13)); 1333254885Sdumbbell OUT_RING(RADEON_VTX_Z_PRESENT | 1334254885Sdumbbell RADEON_VTX_PKCOLOR_PRESENT); 1335254885Sdumbbell OUT_RING((RADEON_PRIM_TYPE_RECT_LIST | 1336254885Sdumbbell RADEON_PRIM_WALK_RING | 1337254885Sdumbbell RADEON_MAOS_ENABLE | 1338254885Sdumbbell RADEON_VTX_FMT_RADEON_MODE | 1339254885Sdumbbell (3 << RADEON_NUM_VERTICES_SHIFT))); 1340254885Sdumbbell 1341254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1342254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y1]); 1343254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1344254885Sdumbbell OUT_RING(0x0); 1345254885Sdumbbell 1346254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X1]); 1347254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1348254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1349254885Sdumbbell OUT_RING(0x0); 1350254885Sdumbbell 1351254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_X2]); 1352254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_Y2]); 1353254885Sdumbbell OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]); 1354254885Sdumbbell OUT_RING(0x0); 1355254885Sdumbbell 1356254885Sdumbbell ADVANCE_RING(); 1357254885Sdumbbell } 1358254885Sdumbbell } 1359254885Sdumbbell 1360254885Sdumbbell /* Increment the clear counter. The client-side 3D driver must 1361254885Sdumbbell * wait on this value before performing the clear ioctl. We 1362254885Sdumbbell * need this because the card's so damned fast... 1363254885Sdumbbell */ 1364254885Sdumbbell sarea_priv->last_clear++; 1365254885Sdumbbell 1366254885Sdumbbell BEGIN_RING(4); 1367254885Sdumbbell 1368254885Sdumbbell RADEON_CLEAR_AGE(sarea_priv->last_clear); 1369254885Sdumbbell RADEON_WAIT_UNTIL_IDLE(); 1370254885Sdumbbell 1371254885Sdumbbell ADVANCE_RING(); 1372254885Sdumbbell} 1373254885Sdumbbell 1374254885Sdumbbellstatic void radeon_cp_dispatch_swap(struct drm_device *dev, struct drm_master *master) 1375254885Sdumbbell{ 1376254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1377254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 1378254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 1379254885Sdumbbell int nbox = sarea_priv->nbox; 1380254885Sdumbbell struct drm_clip_rect *pbox = sarea_priv->boxes; 1381254885Sdumbbell int i; 1382254885Sdumbbell RING_LOCALS; 1383254885Sdumbbell DRM_DEBUG("\n"); 1384254885Sdumbbell 1385254885Sdumbbell /* Do some trivial performance monitoring... 1386254885Sdumbbell */ 1387254885Sdumbbell if (dev_priv->do_boxes) 1388254885Sdumbbell radeon_cp_performance_boxes(dev_priv, master_priv); 1389254885Sdumbbell 1390254885Sdumbbell /* Wait for the 3D stream to idle before dispatching the bitblt. 1391254885Sdumbbell * This will prevent data corruption between the two streams. 1392254885Sdumbbell */ 1393254885Sdumbbell BEGIN_RING(2); 1394254885Sdumbbell 1395254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 1396254885Sdumbbell 1397254885Sdumbbell ADVANCE_RING(); 1398254885Sdumbbell 1399254885Sdumbbell for (i = 0; i < nbox; i++) { 1400254885Sdumbbell int x = pbox[i].x1; 1401254885Sdumbbell int y = pbox[i].y1; 1402254885Sdumbbell int w = pbox[i].x2 - x; 1403254885Sdumbbell int h = pbox[i].y2 - y; 1404254885Sdumbbell 1405254885Sdumbbell DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h); 1406254885Sdumbbell 1407254885Sdumbbell BEGIN_RING(9); 1408254885Sdumbbell 1409254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0)); 1410254885Sdumbbell OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 1411254885Sdumbbell RADEON_GMC_DST_PITCH_OFFSET_CNTL | 1412254885Sdumbbell RADEON_GMC_BRUSH_NONE | 1413254885Sdumbbell (dev_priv->color_fmt << 8) | 1414254885Sdumbbell RADEON_GMC_SRC_DATATYPE_COLOR | 1415254885Sdumbbell RADEON_ROP3_S | 1416254885Sdumbbell RADEON_DP_SRC_SOURCE_MEMORY | 1417254885Sdumbbell RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); 1418254885Sdumbbell 1419254885Sdumbbell /* Make this work even if front & back are flipped: 1420254885Sdumbbell */ 1421254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); 1422254885Sdumbbell if (sarea_priv->pfCurrentPage == 0) { 1423254885Sdumbbell OUT_RING(dev_priv->back_pitch_offset); 1424254885Sdumbbell OUT_RING(dev_priv->front_pitch_offset); 1425254885Sdumbbell } else { 1426254885Sdumbbell OUT_RING(dev_priv->front_pitch_offset); 1427254885Sdumbbell OUT_RING(dev_priv->back_pitch_offset); 1428254885Sdumbbell } 1429254885Sdumbbell 1430254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2)); 1431254885Sdumbbell OUT_RING((x << 16) | y); 1432254885Sdumbbell OUT_RING((x << 16) | y); 1433254885Sdumbbell OUT_RING((w << 16) | h); 1434254885Sdumbbell 1435254885Sdumbbell ADVANCE_RING(); 1436254885Sdumbbell } 1437254885Sdumbbell 1438254885Sdumbbell /* Increment the frame counter. The client-side 3D driver must 1439254885Sdumbbell * throttle the framerate by waiting for this value before 1440254885Sdumbbell * performing the swapbuffer ioctl. 1441254885Sdumbbell */ 1442254885Sdumbbell sarea_priv->last_frame++; 1443254885Sdumbbell 1444254885Sdumbbell BEGIN_RING(4); 1445254885Sdumbbell 1446254885Sdumbbell RADEON_FRAME_AGE(sarea_priv->last_frame); 1447254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1448254885Sdumbbell 1449254885Sdumbbell ADVANCE_RING(); 1450254885Sdumbbell} 1451254885Sdumbbell 1452254885Sdumbbellvoid radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master) 1453254885Sdumbbell{ 1454254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1455254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 1456254885Sdumbbell struct drm_sarea *sarea = (struct drm_sarea *)master_priv->sarea->handle; 1457254885Sdumbbell int offset = (master_priv->sarea_priv->pfCurrentPage == 1) 1458254885Sdumbbell ? dev_priv->front_offset : dev_priv->back_offset; 1459254885Sdumbbell RING_LOCALS; 1460254885Sdumbbell DRM_DEBUG("pfCurrentPage=%d\n", 1461254885Sdumbbell master_priv->sarea_priv->pfCurrentPage); 1462254885Sdumbbell 1463254885Sdumbbell /* Do some trivial performance monitoring... 1464254885Sdumbbell */ 1465254885Sdumbbell if (dev_priv->do_boxes) { 1466254885Sdumbbell dev_priv->stats.boxes |= RADEON_BOX_FLIP; 1467254885Sdumbbell radeon_cp_performance_boxes(dev_priv, master_priv); 1468254885Sdumbbell } 1469254885Sdumbbell 1470254885Sdumbbell /* Update the frame offsets for both CRTCs 1471254885Sdumbbell */ 1472254885Sdumbbell BEGIN_RING(6); 1473254885Sdumbbell 1474254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 1475254885Sdumbbell OUT_RING_REG(RADEON_CRTC_OFFSET, 1476254885Sdumbbell ((sarea->frame.y * dev_priv->front_pitch + 1477254885Sdumbbell sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) 1478254885Sdumbbell + offset); 1479254885Sdumbbell OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base 1480254885Sdumbbell + offset); 1481254885Sdumbbell 1482254885Sdumbbell ADVANCE_RING(); 1483254885Sdumbbell 1484254885Sdumbbell /* Increment the frame counter. The client-side 3D driver must 1485254885Sdumbbell * throttle the framerate by waiting for this value before 1486254885Sdumbbell * performing the swapbuffer ioctl. 1487254885Sdumbbell */ 1488254885Sdumbbell master_priv->sarea_priv->last_frame++; 1489254885Sdumbbell master_priv->sarea_priv->pfCurrentPage = 1490254885Sdumbbell 1 - master_priv->sarea_priv->pfCurrentPage; 1491254885Sdumbbell 1492254885Sdumbbell BEGIN_RING(2); 1493254885Sdumbbell 1494254885Sdumbbell RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame); 1495254885Sdumbbell 1496254885Sdumbbell ADVANCE_RING(); 1497254885Sdumbbell} 1498254885Sdumbbell 1499254885Sdumbbellstatic int bad_prim_vertex_nr(int primitive, int nr) 1500254885Sdumbbell{ 1501254885Sdumbbell switch (primitive & RADEON_PRIM_TYPE_MASK) { 1502254885Sdumbbell case RADEON_PRIM_TYPE_NONE: 1503254885Sdumbbell case RADEON_PRIM_TYPE_POINT: 1504254885Sdumbbell return nr < 1; 1505254885Sdumbbell case RADEON_PRIM_TYPE_LINE: 1506254885Sdumbbell return (nr & 1) || nr == 0; 1507254885Sdumbbell case RADEON_PRIM_TYPE_LINE_STRIP: 1508254885Sdumbbell return nr < 2; 1509254885Sdumbbell case RADEON_PRIM_TYPE_TRI_LIST: 1510254885Sdumbbell case RADEON_PRIM_TYPE_3VRT_POINT_LIST: 1511254885Sdumbbell case RADEON_PRIM_TYPE_3VRT_LINE_LIST: 1512254885Sdumbbell case RADEON_PRIM_TYPE_RECT_LIST: 1513254885Sdumbbell return nr % 3 || nr == 0; 1514254885Sdumbbell case RADEON_PRIM_TYPE_TRI_FAN: 1515254885Sdumbbell case RADEON_PRIM_TYPE_TRI_STRIP: 1516254885Sdumbbell return nr < 3; 1517254885Sdumbbell default: 1518254885Sdumbbell return 1; 1519254885Sdumbbell } 1520254885Sdumbbell} 1521254885Sdumbbell 1522254885Sdumbbelltypedef struct { 1523254885Sdumbbell unsigned int start; 1524254885Sdumbbell unsigned int finish; 1525254885Sdumbbell unsigned int prim; 1526254885Sdumbbell unsigned int numverts; 1527254885Sdumbbell unsigned int offset; 1528254885Sdumbbell unsigned int vc_format; 1529254885Sdumbbell} drm_radeon_tcl_prim_t; 1530254885Sdumbbell 1531254885Sdumbbellstatic void radeon_cp_dispatch_vertex(struct drm_device * dev, 1532254885Sdumbbell struct drm_file *file_priv, 1533254885Sdumbbell struct drm_buf * buf, 1534254885Sdumbbell drm_radeon_tcl_prim_t * prim) 1535254885Sdumbbell{ 1536254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1537254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 1538254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 1539254885Sdumbbell int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; 1540254885Sdumbbell int numverts = (int)prim->numverts; 1541254885Sdumbbell int nbox = sarea_priv->nbox; 1542254885Sdumbbell int i = 0; 1543254885Sdumbbell RING_LOCALS; 1544254885Sdumbbell 1545254885Sdumbbell DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n", 1546254885Sdumbbell prim->prim, 1547254885Sdumbbell prim->vc_format, prim->start, prim->finish, prim->numverts); 1548254885Sdumbbell 1549254885Sdumbbell if (bad_prim_vertex_nr(prim->prim, prim->numverts)) { 1550254885Sdumbbell DRM_ERROR("bad prim %x numverts %d\n", 1551254885Sdumbbell prim->prim, prim->numverts); 1552254885Sdumbbell return; 1553254885Sdumbbell } 1554254885Sdumbbell 1555254885Sdumbbell do { 1556254885Sdumbbell /* Emit the next cliprect */ 1557254885Sdumbbell if (i < nbox) { 1558254885Sdumbbell radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 1559254885Sdumbbell } 1560254885Sdumbbell 1561254885Sdumbbell /* Emit the vertex buffer rendering commands */ 1562254885Sdumbbell BEGIN_RING(5); 1563254885Sdumbbell 1564254885Sdumbbell OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3)); 1565254885Sdumbbell OUT_RING(offset); 1566254885Sdumbbell OUT_RING(numverts); 1567254885Sdumbbell OUT_RING(prim->vc_format); 1568254885Sdumbbell OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST | 1569254885Sdumbbell RADEON_COLOR_ORDER_RGBA | 1570254885Sdumbbell RADEON_VTX_FMT_RADEON_MODE | 1571254885Sdumbbell (numverts << RADEON_NUM_VERTICES_SHIFT)); 1572254885Sdumbbell 1573254885Sdumbbell ADVANCE_RING(); 1574254885Sdumbbell 1575254885Sdumbbell i++; 1576254885Sdumbbell } while (i < nbox); 1577254885Sdumbbell} 1578254885Sdumbbell 1579254885Sdumbbellvoid radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf) 1580254885Sdumbbell{ 1581254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1582254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 1583254885Sdumbbell drm_radeon_buf_priv_t *buf_priv = buf->dev_private; 1584254885Sdumbbell RING_LOCALS; 1585254885Sdumbbell 1586254885Sdumbbell buf_priv->age = ++master_priv->sarea_priv->last_dispatch; 1587254885Sdumbbell 1588254885Sdumbbell /* Emit the vertex buffer age */ 1589254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { 1590254885Sdumbbell BEGIN_RING(3); 1591254885Sdumbbell R600_DISPATCH_AGE(buf_priv->age); 1592254885Sdumbbell ADVANCE_RING(); 1593254885Sdumbbell } else { 1594254885Sdumbbell BEGIN_RING(2); 1595254885Sdumbbell RADEON_DISPATCH_AGE(buf_priv->age); 1596254885Sdumbbell ADVANCE_RING(); 1597254885Sdumbbell } 1598254885Sdumbbell 1599254885Sdumbbell buf->pending = 1; 1600254885Sdumbbell buf->used = 0; 1601254885Sdumbbell} 1602254885Sdumbbell 1603254885Sdumbbellstatic void radeon_cp_dispatch_indirect(struct drm_device * dev, 1604254885Sdumbbell struct drm_buf * buf, int start, int end) 1605254885Sdumbbell{ 1606254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1607254885Sdumbbell RING_LOCALS; 1608254885Sdumbbell DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end); 1609254885Sdumbbell 1610254885Sdumbbell if (start != end) { 1611254885Sdumbbell int offset = (dev_priv->gart_buffers_offset 1612254885Sdumbbell + buf->offset + start); 1613254885Sdumbbell int dwords = (end - start + 3) / sizeof(u32); 1614254885Sdumbbell 1615254885Sdumbbell /* Indirect buffer data must be an even number of 1616254885Sdumbbell * dwords, so if we've been given an odd number we must 1617254885Sdumbbell * pad the data with a Type-2 CP packet. 1618254885Sdumbbell */ 1619254885Sdumbbell if (dwords & 1) { 1620254885Sdumbbell u32 *data = (u32 *) 1621254885Sdumbbell ((char *)dev->agp_buffer_map->handle 1622254885Sdumbbell + buf->offset + start); 1623254885Sdumbbell data[dwords++] = RADEON_CP_PACKET2; 1624254885Sdumbbell } 1625254885Sdumbbell 1626254885Sdumbbell /* Fire off the indirect buffer */ 1627254885Sdumbbell BEGIN_RING(3); 1628254885Sdumbbell 1629254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); 1630254885Sdumbbell OUT_RING(offset); 1631254885Sdumbbell OUT_RING(dwords); 1632254885Sdumbbell 1633254885Sdumbbell ADVANCE_RING(); 1634254885Sdumbbell } 1635254885Sdumbbell} 1636254885Sdumbbell 1637254885Sdumbbellstatic void radeon_cp_dispatch_indices(struct drm_device *dev, 1638254885Sdumbbell struct drm_master *master, 1639254885Sdumbbell struct drm_buf * elt_buf, 1640254885Sdumbbell drm_radeon_tcl_prim_t * prim) 1641254885Sdumbbell{ 1642254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1643254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 1644254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 1645254885Sdumbbell int offset = dev_priv->gart_buffers_offset + prim->offset; 1646254885Sdumbbell u32 *data; 1647254885Sdumbbell int dwords; 1648254885Sdumbbell int i = 0; 1649254885Sdumbbell int start = prim->start + RADEON_INDEX_PRIM_OFFSET; 1650254885Sdumbbell int count = (prim->finish - start) / sizeof(u16); 1651254885Sdumbbell int nbox = sarea_priv->nbox; 1652254885Sdumbbell 1653254885Sdumbbell DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n", 1654254885Sdumbbell prim->prim, 1655254885Sdumbbell prim->vc_format, 1656254885Sdumbbell prim->start, prim->finish, prim->offset, prim->numverts); 1657254885Sdumbbell 1658254885Sdumbbell if (bad_prim_vertex_nr(prim->prim, count)) { 1659254885Sdumbbell DRM_ERROR("bad prim %x count %d\n", prim->prim, count); 1660254885Sdumbbell return; 1661254885Sdumbbell } 1662254885Sdumbbell 1663254885Sdumbbell if (start >= prim->finish || (prim->start & 0x7)) { 1664254885Sdumbbell DRM_ERROR("buffer prim %d\n", prim->prim); 1665254885Sdumbbell return; 1666254885Sdumbbell } 1667254885Sdumbbell 1668254885Sdumbbell dwords = (prim->finish - prim->start + 3) / sizeof(u32); 1669254885Sdumbbell 1670254885Sdumbbell data = (u32 *) ((char *)dev->agp_buffer_map->handle + 1671254885Sdumbbell elt_buf->offset + prim->start); 1672254885Sdumbbell 1673254885Sdumbbell data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2); 1674254885Sdumbbell data[1] = offset; 1675254885Sdumbbell data[2] = prim->numverts; 1676254885Sdumbbell data[3] = prim->vc_format; 1677254885Sdumbbell data[4] = (prim->prim | 1678254885Sdumbbell RADEON_PRIM_WALK_IND | 1679254885Sdumbbell RADEON_COLOR_ORDER_RGBA | 1680254885Sdumbbell RADEON_VTX_FMT_RADEON_MODE | 1681254885Sdumbbell (count << RADEON_NUM_VERTICES_SHIFT)); 1682254885Sdumbbell 1683254885Sdumbbell do { 1684254885Sdumbbell if (i < nbox) 1685254885Sdumbbell radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]); 1686254885Sdumbbell 1687254885Sdumbbell radeon_cp_dispatch_indirect(dev, elt_buf, 1688254885Sdumbbell prim->start, prim->finish); 1689254885Sdumbbell 1690254885Sdumbbell i++; 1691254885Sdumbbell } while (i < nbox); 1692254885Sdumbbell 1693254885Sdumbbell} 1694254885Sdumbbell 1695254885Sdumbbell#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE 1696254885Sdumbbell 1697254885Sdumbbellstatic int radeon_cp_dispatch_texture(struct drm_device * dev, 1698254885Sdumbbell struct drm_file *file_priv, 1699254885Sdumbbell drm_radeon_texture_t * tex, 1700254885Sdumbbell drm_radeon_tex_image_t * image) 1701254885Sdumbbell{ 1702254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1703254885Sdumbbell struct drm_buf *buf; 1704254885Sdumbbell u32 format; 1705254885Sdumbbell u32 *buffer; 1706254885Sdumbbell const u8 __user *data; 1707254885Sdumbbell int size, dwords, tex_width, blit_width, spitch; 1708254885Sdumbbell u32 height; 1709254885Sdumbbell int i; 1710254885Sdumbbell u32 texpitch, microtile; 1711254885Sdumbbell u32 offset, byte_offset; 1712254885Sdumbbell RING_LOCALS; 1713254885Sdumbbell 1714254885Sdumbbell if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) { 1715254885Sdumbbell DRM_ERROR("Invalid destination offset\n"); 1716254885Sdumbbell return -EINVAL; 1717254885Sdumbbell } 1718254885Sdumbbell 1719254885Sdumbbell dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD; 1720254885Sdumbbell 1721254885Sdumbbell /* Flush the pixel cache. This ensures no pixel data gets mixed 1722254885Sdumbbell * up with the texture data from the host data blit, otherwise 1723254885Sdumbbell * part of the texture image may be corrupted. 1724254885Sdumbbell */ 1725254885Sdumbbell BEGIN_RING(4); 1726254885Sdumbbell RADEON_FLUSH_CACHE(); 1727254885Sdumbbell RADEON_WAIT_UNTIL_IDLE(); 1728254885Sdumbbell ADVANCE_RING(); 1729254885Sdumbbell 1730254885Sdumbbell /* The compiler won't optimize away a division by a variable, 1731254885Sdumbbell * even if the only legal values are powers of two. Thus, we'll 1732254885Sdumbbell * use a shift instead. 1733254885Sdumbbell */ 1734254885Sdumbbell switch (tex->format) { 1735254885Sdumbbell case RADEON_TXFORMAT_ARGB8888: 1736254885Sdumbbell case RADEON_TXFORMAT_RGBA8888: 1737254885Sdumbbell format = RADEON_COLOR_FORMAT_ARGB8888; 1738254885Sdumbbell tex_width = tex->width * 4; 1739254885Sdumbbell blit_width = image->width * 4; 1740254885Sdumbbell break; 1741254885Sdumbbell case RADEON_TXFORMAT_AI88: 1742254885Sdumbbell case RADEON_TXFORMAT_ARGB1555: 1743254885Sdumbbell case RADEON_TXFORMAT_RGB565: 1744254885Sdumbbell case RADEON_TXFORMAT_ARGB4444: 1745254885Sdumbbell case RADEON_TXFORMAT_VYUY422: 1746254885Sdumbbell case RADEON_TXFORMAT_YVYU422: 1747254885Sdumbbell format = RADEON_COLOR_FORMAT_RGB565; 1748254885Sdumbbell tex_width = tex->width * 2; 1749254885Sdumbbell blit_width = image->width * 2; 1750254885Sdumbbell break; 1751254885Sdumbbell case RADEON_TXFORMAT_I8: 1752254885Sdumbbell case RADEON_TXFORMAT_RGB332: 1753254885Sdumbbell format = RADEON_COLOR_FORMAT_CI8; 1754254885Sdumbbell tex_width = tex->width * 1; 1755254885Sdumbbell blit_width = image->width * 1; 1756254885Sdumbbell break; 1757254885Sdumbbell default: 1758254885Sdumbbell DRM_ERROR("invalid texture format %d\n", tex->format); 1759254885Sdumbbell return -EINVAL; 1760254885Sdumbbell } 1761254885Sdumbbell spitch = blit_width >> 6; 1762254885Sdumbbell if (spitch == 0 && image->height > 1) 1763254885Sdumbbell return -EINVAL; 1764254885Sdumbbell 1765254885Sdumbbell texpitch = tex->pitch; 1766254885Sdumbbell if ((texpitch << 22) & RADEON_DST_TILE_MICRO) { 1767254885Sdumbbell microtile = 1; 1768254885Sdumbbell if (tex_width < 64) { 1769254885Sdumbbell texpitch &= ~(RADEON_DST_TILE_MICRO >> 22); 1770254885Sdumbbell /* we got tiled coordinates, untile them */ 1771254885Sdumbbell image->x *= 2; 1772254885Sdumbbell } 1773254885Sdumbbell } else 1774254885Sdumbbell microtile = 0; 1775254885Sdumbbell 1776254885Sdumbbell /* this might fail for zero-sized uploads - are those illegal? */ 1777254885Sdumbbell if (!radeon_check_offset(dev_priv, tex->offset + image->height * 1778254885Sdumbbell blit_width - 1)) { 1779254885Sdumbbell DRM_ERROR("Invalid final destination offset\n"); 1780254885Sdumbbell return -EINVAL; 1781254885Sdumbbell } 1782254885Sdumbbell 1783254885Sdumbbell DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width); 1784254885Sdumbbell 1785254885Sdumbbell do { 1786254885Sdumbbell DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%u y=%u w=%u h=%u\n", 1787254885Sdumbbell tex->offset >> 10, tex->pitch, tex->format, 1788254885Sdumbbell image->x, image->y, image->width, image->height); 1789254885Sdumbbell 1790254885Sdumbbell /* Make a copy of some parameters in case we have to 1791254885Sdumbbell * update them for a multi-pass texture blit. 1792254885Sdumbbell */ 1793254885Sdumbbell height = image->height; 1794254885Sdumbbell data = (const u8 __user *)image->data; 1795254885Sdumbbell 1796254885Sdumbbell size = height * blit_width; 1797254885Sdumbbell 1798254885Sdumbbell if (size > RADEON_MAX_TEXTURE_SIZE) { 1799254885Sdumbbell height = RADEON_MAX_TEXTURE_SIZE / blit_width; 1800254885Sdumbbell size = height * blit_width; 1801254885Sdumbbell } else if (size < 4 && size > 0) { 1802254885Sdumbbell size = 4; 1803254885Sdumbbell } else if (size == 0) { 1804254885Sdumbbell return 0; 1805254885Sdumbbell } 1806254885Sdumbbell 1807254885Sdumbbell buf = radeon_freelist_get(dev); 1808254885Sdumbbell if (0 && !buf) { 1809254885Sdumbbell radeon_do_cp_idle(dev_priv); 1810254885Sdumbbell buf = radeon_freelist_get(dev); 1811254885Sdumbbell } 1812254885Sdumbbell if (!buf) { 1813254885Sdumbbell DRM_DEBUG("EAGAIN\n"); 1814254885Sdumbbell if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image))) 1815254885Sdumbbell return -EFAULT; 1816254885Sdumbbell return -EAGAIN; 1817254885Sdumbbell } 1818254885Sdumbbell 1819254885Sdumbbell /* Dispatch the indirect buffer. 1820254885Sdumbbell */ 1821254885Sdumbbell buffer = 1822254885Sdumbbell (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset); 1823254885Sdumbbell dwords = size / 4; 1824254885Sdumbbell 1825254885Sdumbbell#define RADEON_COPY_MT(_buf, _data, _width) \ 1826254885Sdumbbell do { \ 1827254885Sdumbbell if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\ 1828254885Sdumbbell DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \ 1829254885Sdumbbell return -EFAULT; \ 1830254885Sdumbbell } \ 1831254885Sdumbbell } while(0) 1832254885Sdumbbell 1833254885Sdumbbell if (microtile) { 1834254885Sdumbbell /* texture micro tiling in use, minimum texture width is thus 16 bytes. 1835254885Sdumbbell however, we cannot use blitter directly for texture width < 64 bytes, 1836254885Sdumbbell since minimum tex pitch is 64 bytes and we need this to match 1837254885Sdumbbell the texture width, otherwise the blitter will tile it wrong. 1838254885Sdumbbell Thus, tiling manually in this case. Additionally, need to special 1839254885Sdumbbell case tex height = 1, since our actual image will have height 2 1840254885Sdumbbell and we need to ensure we don't read beyond the texture size 1841254885Sdumbbell from user space. */ 1842254885Sdumbbell if (tex->height == 1) { 1843254885Sdumbbell if (tex_width >= 64 || tex_width <= 16) { 1844254885Sdumbbell RADEON_COPY_MT(buffer, data, 1845254885Sdumbbell (int)(tex_width * sizeof(u32))); 1846254885Sdumbbell } else if (tex_width == 32) { 1847254885Sdumbbell RADEON_COPY_MT(buffer, data, 16); 1848254885Sdumbbell RADEON_COPY_MT(buffer + 8, 1849254885Sdumbbell data + 16, 16); 1850254885Sdumbbell } 1851254885Sdumbbell } else if (tex_width >= 64 || tex_width == 16) { 1852254885Sdumbbell RADEON_COPY_MT(buffer, data, 1853254885Sdumbbell (int)(dwords * sizeof(u32))); 1854254885Sdumbbell } else if (tex_width < 16) { 1855254885Sdumbbell for (i = 0; i < tex->height; i++) { 1856254885Sdumbbell RADEON_COPY_MT(buffer, data, tex_width); 1857254885Sdumbbell buffer += 4; 1858254885Sdumbbell data += tex_width; 1859254885Sdumbbell } 1860254885Sdumbbell } else if (tex_width == 32) { 1861254885Sdumbbell /* TODO: make sure this works when not fitting in one buffer 1862254885Sdumbbell (i.e. 32bytes x 2048...) */ 1863254885Sdumbbell for (i = 0; i < tex->height; i += 2) { 1864254885Sdumbbell RADEON_COPY_MT(buffer, data, 16); 1865254885Sdumbbell data += 16; 1866254885Sdumbbell RADEON_COPY_MT(buffer + 8, data, 16); 1867254885Sdumbbell data += 16; 1868254885Sdumbbell RADEON_COPY_MT(buffer + 4, data, 16); 1869254885Sdumbbell data += 16; 1870254885Sdumbbell RADEON_COPY_MT(buffer + 12, data, 16); 1871254885Sdumbbell data += 16; 1872254885Sdumbbell buffer += 16; 1873254885Sdumbbell } 1874254885Sdumbbell } 1875254885Sdumbbell } else { 1876254885Sdumbbell if (tex_width >= 32) { 1877254885Sdumbbell /* Texture image width is larger than the minimum, so we 1878254885Sdumbbell * can upload it directly. 1879254885Sdumbbell */ 1880254885Sdumbbell RADEON_COPY_MT(buffer, data, 1881254885Sdumbbell (int)(dwords * sizeof(u32))); 1882254885Sdumbbell } else { 1883254885Sdumbbell /* Texture image width is less than the minimum, so we 1884254885Sdumbbell * need to pad out each image scanline to the minimum 1885254885Sdumbbell * width. 1886254885Sdumbbell */ 1887254885Sdumbbell for (i = 0; i < tex->height; i++) { 1888254885Sdumbbell RADEON_COPY_MT(buffer, data, tex_width); 1889254885Sdumbbell buffer += 8; 1890254885Sdumbbell data += tex_width; 1891254885Sdumbbell } 1892254885Sdumbbell } 1893254885Sdumbbell } 1894254885Sdumbbell 1895254885Sdumbbell#undef RADEON_COPY_MT 1896254885Sdumbbell byte_offset = (image->y & ~2047) * blit_width; 1897254885Sdumbbell buf->file_priv = file_priv; 1898254885Sdumbbell buf->used = size; 1899254885Sdumbbell offset = dev_priv->gart_buffers_offset + buf->offset; 1900254885Sdumbbell BEGIN_RING(9); 1901254885Sdumbbell OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); 1902254885Sdumbbell OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 1903254885Sdumbbell RADEON_GMC_DST_PITCH_OFFSET_CNTL | 1904254885Sdumbbell RADEON_GMC_BRUSH_NONE | 1905254885Sdumbbell (format << 8) | 1906254885Sdumbbell RADEON_GMC_SRC_DATATYPE_COLOR | 1907254885Sdumbbell RADEON_ROP3_S | 1908254885Sdumbbell RADEON_DP_SRC_SOURCE_MEMORY | 1909254885Sdumbbell RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); 1910254885Sdumbbell OUT_RING((spitch << 22) | (offset >> 10)); 1911254885Sdumbbell OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10))); 1912254885Sdumbbell OUT_RING(0); 1913254885Sdumbbell OUT_RING((image->x << 16) | (image->y % 2048)); 1914254885Sdumbbell OUT_RING((image->width << 16) | height); 1915254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1916254885Sdumbbell ADVANCE_RING(); 1917254885Sdumbbell COMMIT_RING(); 1918254885Sdumbbell 1919254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 1920254885Sdumbbell 1921254885Sdumbbell /* Update the input parameters for next time */ 1922254885Sdumbbell image->y += height; 1923254885Sdumbbell image->height -= height; 1924254885Sdumbbell image->data = (const u8 __user *)image->data + size; 1925254885Sdumbbell } while (image->height > 0); 1926254885Sdumbbell 1927254885Sdumbbell /* Flush the pixel cache after the blit completes. This ensures 1928254885Sdumbbell * the texture data is written out to memory before rendering 1929254885Sdumbbell * continues. 1930254885Sdumbbell */ 1931254885Sdumbbell BEGIN_RING(4); 1932254885Sdumbbell RADEON_FLUSH_CACHE(); 1933254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 1934254885Sdumbbell ADVANCE_RING(); 1935254885Sdumbbell COMMIT_RING(); 1936254885Sdumbbell 1937254885Sdumbbell return 0; 1938254885Sdumbbell} 1939254885Sdumbbell 1940254885Sdumbbellstatic void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple) 1941254885Sdumbbell{ 1942254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 1943254885Sdumbbell int i; 1944254885Sdumbbell RING_LOCALS; 1945254885Sdumbbell DRM_DEBUG("\n"); 1946254885Sdumbbell 1947254885Sdumbbell BEGIN_RING(35); 1948254885Sdumbbell 1949254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0)); 1950254885Sdumbbell OUT_RING(0x00000000); 1951254885Sdumbbell 1952254885Sdumbbell OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31)); 1953254885Sdumbbell for (i = 0; i < 32; i++) { 1954254885Sdumbbell OUT_RING(stipple[i]); 1955254885Sdumbbell } 1956254885Sdumbbell 1957254885Sdumbbell ADVANCE_RING(); 1958254885Sdumbbell} 1959254885Sdumbbell 1960254885Sdumbbellstatic void radeon_apply_surface_regs(int surf_index, 1961254885Sdumbbell drm_radeon_private_t *dev_priv) 1962254885Sdumbbell{ 1963254885Sdumbbell if (!dev_priv->mmio) 1964254885Sdumbbell return; 1965254885Sdumbbell 1966254885Sdumbbell radeon_do_cp_idle(dev_priv); 1967254885Sdumbbell 1968254885Sdumbbell RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index, 1969254885Sdumbbell dev_priv->surfaces[surf_index].flags); 1970254885Sdumbbell RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index, 1971254885Sdumbbell dev_priv->surfaces[surf_index].lower); 1972254885Sdumbbell RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index, 1973254885Sdumbbell dev_priv->surfaces[surf_index].upper); 1974254885Sdumbbell} 1975254885Sdumbbell 1976254885Sdumbbell/* Allocates a virtual surface 1977254885Sdumbbell * doesn't always allocate a real surface, will stretch an existing 1978254885Sdumbbell * surface when possible. 1979254885Sdumbbell * 1980254885Sdumbbell * Note that refcount can be at most 2, since during a free refcount=3 1981254885Sdumbbell * might mean we have to allocate a new surface which might not always 1982254885Sdumbbell * be available. 1983254885Sdumbbell * For example : we allocate three contiguous surfaces ABC. If B is 1984254885Sdumbbell * freed, we suddenly need two surfaces to store A and C, which might 1985254885Sdumbbell * not always be available. 1986254885Sdumbbell */ 1987254885Sdumbbellstatic int alloc_surface(drm_radeon_surface_alloc_t *new, 1988254885Sdumbbell drm_radeon_private_t *dev_priv, 1989254885Sdumbbell struct drm_file *file_priv) 1990254885Sdumbbell{ 1991254885Sdumbbell struct radeon_virt_surface *s; 1992254885Sdumbbell int i; 1993254885Sdumbbell int virt_surface_index; 1994254885Sdumbbell uint32_t new_upper, new_lower; 1995254885Sdumbbell 1996254885Sdumbbell new_lower = new->address; 1997254885Sdumbbell new_upper = new_lower + new->size - 1; 1998254885Sdumbbell 1999254885Sdumbbell /* sanity check */ 2000254885Sdumbbell if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) || 2001254885Sdumbbell ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) != 2002254885Sdumbbell RADEON_SURF_ADDRESS_FIXED_MASK) 2003254885Sdumbbell || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0)) 2004254885Sdumbbell return -1; 2005254885Sdumbbell 2006254885Sdumbbell /* make sure there is no overlap with existing surfaces */ 2007254885Sdumbbell for (i = 0; i < RADEON_MAX_SURFACES; i++) { 2008254885Sdumbbell if ((dev_priv->surfaces[i].refcount != 0) && 2009254885Sdumbbell (((new_lower >= dev_priv->surfaces[i].lower) && 2010254885Sdumbbell (new_lower < dev_priv->surfaces[i].upper)) || 2011254885Sdumbbell ((new_lower < dev_priv->surfaces[i].lower) && 2012254885Sdumbbell (new_upper > dev_priv->surfaces[i].lower)))) { 2013254885Sdumbbell return -1; 2014254885Sdumbbell } 2015254885Sdumbbell } 2016254885Sdumbbell 2017254885Sdumbbell /* find a virtual surface */ 2018254885Sdumbbell for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) 2019254885Sdumbbell if (dev_priv->virt_surfaces[i].file_priv == NULL) 2020254885Sdumbbell break; 2021254885Sdumbbell if (i == 2 * RADEON_MAX_SURFACES) { 2022254885Sdumbbell return -1; 2023254885Sdumbbell } 2024254885Sdumbbell virt_surface_index = i; 2025254885Sdumbbell 2026254885Sdumbbell /* try to reuse an existing surface */ 2027254885Sdumbbell for (i = 0; i < RADEON_MAX_SURFACES; i++) { 2028254885Sdumbbell /* extend before */ 2029254885Sdumbbell if ((dev_priv->surfaces[i].refcount == 1) && 2030254885Sdumbbell (new->flags == dev_priv->surfaces[i].flags) && 2031254885Sdumbbell (new_upper + 1 == dev_priv->surfaces[i].lower)) { 2032254885Sdumbbell s = &(dev_priv->virt_surfaces[virt_surface_index]); 2033254885Sdumbbell s->surface_index = i; 2034254885Sdumbbell s->lower = new_lower; 2035254885Sdumbbell s->upper = new_upper; 2036254885Sdumbbell s->flags = new->flags; 2037254885Sdumbbell s->file_priv = file_priv; 2038254885Sdumbbell dev_priv->surfaces[i].refcount++; 2039254885Sdumbbell dev_priv->surfaces[i].lower = s->lower; 2040254885Sdumbbell radeon_apply_surface_regs(s->surface_index, dev_priv); 2041254885Sdumbbell return virt_surface_index; 2042254885Sdumbbell } 2043254885Sdumbbell 2044254885Sdumbbell /* extend after */ 2045254885Sdumbbell if ((dev_priv->surfaces[i].refcount == 1) && 2046254885Sdumbbell (new->flags == dev_priv->surfaces[i].flags) && 2047254885Sdumbbell (new_lower == dev_priv->surfaces[i].upper + 1)) { 2048254885Sdumbbell s = &(dev_priv->virt_surfaces[virt_surface_index]); 2049254885Sdumbbell s->surface_index = i; 2050254885Sdumbbell s->lower = new_lower; 2051254885Sdumbbell s->upper = new_upper; 2052254885Sdumbbell s->flags = new->flags; 2053254885Sdumbbell s->file_priv = file_priv; 2054254885Sdumbbell dev_priv->surfaces[i].refcount++; 2055254885Sdumbbell dev_priv->surfaces[i].upper = s->upper; 2056254885Sdumbbell radeon_apply_surface_regs(s->surface_index, dev_priv); 2057254885Sdumbbell return virt_surface_index; 2058254885Sdumbbell } 2059254885Sdumbbell } 2060254885Sdumbbell 2061254885Sdumbbell /* okay, we need a new one */ 2062254885Sdumbbell for (i = 0; i < RADEON_MAX_SURFACES; i++) { 2063254885Sdumbbell if (dev_priv->surfaces[i].refcount == 0) { 2064254885Sdumbbell s = &(dev_priv->virt_surfaces[virt_surface_index]); 2065254885Sdumbbell s->surface_index = i; 2066254885Sdumbbell s->lower = new_lower; 2067254885Sdumbbell s->upper = new_upper; 2068254885Sdumbbell s->flags = new->flags; 2069254885Sdumbbell s->file_priv = file_priv; 2070254885Sdumbbell dev_priv->surfaces[i].refcount = 1; 2071254885Sdumbbell dev_priv->surfaces[i].lower = s->lower; 2072254885Sdumbbell dev_priv->surfaces[i].upper = s->upper; 2073254885Sdumbbell dev_priv->surfaces[i].flags = s->flags; 2074254885Sdumbbell radeon_apply_surface_regs(s->surface_index, dev_priv); 2075254885Sdumbbell return virt_surface_index; 2076254885Sdumbbell } 2077254885Sdumbbell } 2078254885Sdumbbell 2079254885Sdumbbell /* we didn't find anything */ 2080254885Sdumbbell return -1; 2081254885Sdumbbell} 2082254885Sdumbbell 2083254885Sdumbbellstatic int free_surface(struct drm_file *file_priv, 2084254885Sdumbbell drm_radeon_private_t * dev_priv, 2085254885Sdumbbell int lower) 2086254885Sdumbbell{ 2087254885Sdumbbell struct radeon_virt_surface *s; 2088254885Sdumbbell int i; 2089254885Sdumbbell /* find the virtual surface */ 2090254885Sdumbbell for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { 2091254885Sdumbbell s = &(dev_priv->virt_surfaces[i]); 2092254885Sdumbbell if (s->file_priv) { 2093254885Sdumbbell if ((lower == s->lower) && (file_priv == s->file_priv)) 2094254885Sdumbbell { 2095254885Sdumbbell if (dev_priv->surfaces[s->surface_index]. 2096254885Sdumbbell lower == s->lower) 2097254885Sdumbbell dev_priv->surfaces[s->surface_index]. 2098254885Sdumbbell lower = s->upper; 2099254885Sdumbbell 2100254885Sdumbbell if (dev_priv->surfaces[s->surface_index]. 2101254885Sdumbbell upper == s->upper) 2102254885Sdumbbell dev_priv->surfaces[s->surface_index]. 2103254885Sdumbbell upper = s->lower; 2104254885Sdumbbell 2105254885Sdumbbell dev_priv->surfaces[s->surface_index].refcount--; 2106254885Sdumbbell if (dev_priv->surfaces[s->surface_index]. 2107254885Sdumbbell refcount == 0) 2108254885Sdumbbell dev_priv->surfaces[s->surface_index]. 2109254885Sdumbbell flags = 0; 2110254885Sdumbbell s->file_priv = NULL; 2111254885Sdumbbell radeon_apply_surface_regs(s->surface_index, 2112254885Sdumbbell dev_priv); 2113254885Sdumbbell return 0; 2114254885Sdumbbell } 2115254885Sdumbbell } 2116254885Sdumbbell } 2117254885Sdumbbell return 1; 2118254885Sdumbbell} 2119254885Sdumbbell 2120254885Sdumbbellstatic void radeon_surfaces_release(struct drm_file *file_priv, 2121254885Sdumbbell drm_radeon_private_t * dev_priv) 2122254885Sdumbbell{ 2123254885Sdumbbell int i; 2124254885Sdumbbell for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) { 2125254885Sdumbbell if (dev_priv->virt_surfaces[i].file_priv == file_priv) 2126254885Sdumbbell free_surface(file_priv, dev_priv, 2127254885Sdumbbell dev_priv->virt_surfaces[i].lower); 2128254885Sdumbbell } 2129254885Sdumbbell} 2130254885Sdumbbell 2131254885Sdumbbell/* ================================================================ 2132254885Sdumbbell * IOCTL functions 2133254885Sdumbbell */ 2134254885Sdumbbellstatic int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) 2135254885Sdumbbell{ 2136254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2137254885Sdumbbell drm_radeon_surface_alloc_t *alloc = data; 2138254885Sdumbbell 2139254885Sdumbbell if (alloc_surface(alloc, dev_priv, file_priv) == -1) 2140254885Sdumbbell return -EINVAL; 2141254885Sdumbbell else 2142254885Sdumbbell return 0; 2143254885Sdumbbell} 2144254885Sdumbbell 2145254885Sdumbbellstatic int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 2146254885Sdumbbell{ 2147254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2148254885Sdumbbell drm_radeon_surface_free_t *memfree = data; 2149254885Sdumbbell 2150254885Sdumbbell if (free_surface(file_priv, dev_priv, memfree->address)) 2151254885Sdumbbell return -EINVAL; 2152254885Sdumbbell else 2153254885Sdumbbell return 0; 2154254885Sdumbbell} 2155254885Sdumbbell 2156254885Sdumbbellstatic int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) 2157254885Sdumbbell{ 2158254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2159254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 2160254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 2161254885Sdumbbell drm_radeon_clear_t *clear = data; 2162254885Sdumbbell drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; 2163254885Sdumbbell DRM_DEBUG("\n"); 2164254885Sdumbbell 2165254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2166254885Sdumbbell 2167254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2168254885Sdumbbell 2169254885Sdumbbell if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 2170254885Sdumbbell sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; 2171254885Sdumbbell 2172254885Sdumbbell if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes, 2173254885Sdumbbell sarea_priv->nbox * sizeof(depth_boxes[0]))) 2174254885Sdumbbell return -EFAULT; 2175254885Sdumbbell 2176254885Sdumbbell radeon_cp_dispatch_clear(dev, file_priv->masterp, clear, depth_boxes); 2177254885Sdumbbell 2178254885Sdumbbell COMMIT_RING(); 2179254885Sdumbbell return 0; 2180254885Sdumbbell} 2181254885Sdumbbell 2182254885Sdumbbell/* Not sure why this isn't set all the time: 2183254885Sdumbbell */ 2184254885Sdumbbellstatic int radeon_do_init_pageflip(struct drm_device *dev, struct drm_master *master) 2185254885Sdumbbell{ 2186254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2187254885Sdumbbell struct drm_radeon_master_private *master_priv = master->driver_priv; 2188254885Sdumbbell RING_LOCALS; 2189254885Sdumbbell 2190254885Sdumbbell DRM_DEBUG("\n"); 2191254885Sdumbbell 2192254885Sdumbbell BEGIN_RING(6); 2193254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 2194254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0)); 2195254885Sdumbbell OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) | 2196254885Sdumbbell RADEON_CRTC_OFFSET_FLIP_CNTL); 2197254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0)); 2198254885Sdumbbell OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) | 2199254885Sdumbbell RADEON_CRTC_OFFSET_FLIP_CNTL); 2200254885Sdumbbell ADVANCE_RING(); 2201254885Sdumbbell 2202254885Sdumbbell dev_priv->page_flipping = 1; 2203254885Sdumbbell 2204254885Sdumbbell if (master_priv->sarea_priv->pfCurrentPage != 1) 2205254885Sdumbbell master_priv->sarea_priv->pfCurrentPage = 0; 2206254885Sdumbbell 2207254885Sdumbbell return 0; 2208254885Sdumbbell} 2209254885Sdumbbell 2210254885Sdumbbell/* Swapping and flipping are different operations, need different ioctls. 2211254885Sdumbbell * They can & should be intermixed to support multiple 3d windows. 2212254885Sdumbbell */ 2213254885Sdumbbellstatic int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv) 2214254885Sdumbbell{ 2215254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2216254885Sdumbbell DRM_DEBUG("\n"); 2217254885Sdumbbell 2218254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2219254885Sdumbbell 2220254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2221254885Sdumbbell 2222254885Sdumbbell if (!dev_priv->page_flipping) 2223254885Sdumbbell radeon_do_init_pageflip(dev, file_priv->masterp); 2224254885Sdumbbell 2225254885Sdumbbell radeon_cp_dispatch_flip(dev, file_priv->masterp); 2226254885Sdumbbell 2227254885Sdumbbell COMMIT_RING(); 2228254885Sdumbbell return 0; 2229254885Sdumbbell} 2230254885Sdumbbell 2231254885Sdumbbellstatic int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) 2232254885Sdumbbell{ 2233254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2234254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 2235254885Sdumbbell drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; 2236254885Sdumbbell 2237254885Sdumbbell DRM_DEBUG("\n"); 2238254885Sdumbbell 2239254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2240254885Sdumbbell 2241254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2242254885Sdumbbell 2243254885Sdumbbell if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 2244254885Sdumbbell sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; 2245254885Sdumbbell 2246254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2247254885Sdumbbell r600_cp_dispatch_swap(dev, file_priv); 2248254885Sdumbbell else 2249254885Sdumbbell radeon_cp_dispatch_swap(dev, file_priv->masterp); 2250254885Sdumbbell sarea_priv->ctx_owner = 0; 2251254885Sdumbbell 2252254885Sdumbbell COMMIT_RING(); 2253254885Sdumbbell return 0; 2254254885Sdumbbell} 2255254885Sdumbbell 2256254885Sdumbbellstatic int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) 2257254885Sdumbbell{ 2258254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2259254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 2260254885Sdumbbell drm_radeon_sarea_t *sarea_priv; 2261254885Sdumbbell struct drm_device_dma *dma = dev->dma; 2262254885Sdumbbell struct drm_buf *buf; 2263254885Sdumbbell drm_radeon_vertex_t *vertex = data; 2264254885Sdumbbell drm_radeon_tcl_prim_t prim; 2265254885Sdumbbell 2266254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2267254885Sdumbbell 2268254885Sdumbbell sarea_priv = master_priv->sarea_priv; 2269254885Sdumbbell 2270254885Sdumbbell DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", 2271254885Sdumbbell DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); 2272254885Sdumbbell 2273254885Sdumbbell if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { 2274254885Sdumbbell DRM_ERROR("buffer index %d (of %d max)\n", 2275254885Sdumbbell vertex->idx, dma->buf_count - 1); 2276254885Sdumbbell return -EINVAL; 2277254885Sdumbbell } 2278254885Sdumbbell if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { 2279254885Sdumbbell DRM_ERROR("buffer prim %d\n", vertex->prim); 2280254885Sdumbbell return -EINVAL; 2281254885Sdumbbell } 2282254885Sdumbbell 2283254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2284254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2285254885Sdumbbell 2286254885Sdumbbell buf = dma->buflist[vertex->idx]; 2287254885Sdumbbell 2288254885Sdumbbell if (buf->file_priv != file_priv) { 2289254885Sdumbbell DRM_ERROR("process %d using buffer owned by %p\n", 2290254885Sdumbbell DRM_CURRENTPID, buf->file_priv); 2291254885Sdumbbell return -EINVAL; 2292254885Sdumbbell } 2293254885Sdumbbell if (buf->pending) { 2294254885Sdumbbell DRM_ERROR("sending pending buffer %d\n", vertex->idx); 2295254885Sdumbbell return -EINVAL; 2296254885Sdumbbell } 2297254885Sdumbbell 2298254885Sdumbbell /* Build up a prim_t record: 2299254885Sdumbbell */ 2300254885Sdumbbell if (vertex->count) { 2301254885Sdumbbell buf->used = vertex->count; /* not used? */ 2302254885Sdumbbell 2303254885Sdumbbell if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { 2304254885Sdumbbell if (radeon_emit_state(dev_priv, file_priv, 2305254885Sdumbbell &sarea_priv->context_state, 2306254885Sdumbbell sarea_priv->tex_state, 2307254885Sdumbbell sarea_priv->dirty)) { 2308254885Sdumbbell DRM_ERROR("radeon_emit_state failed\n"); 2309254885Sdumbbell return -EINVAL; 2310254885Sdumbbell } 2311254885Sdumbbell 2312254885Sdumbbell sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | 2313254885Sdumbbell RADEON_UPLOAD_TEX1IMAGES | 2314254885Sdumbbell RADEON_UPLOAD_TEX2IMAGES | 2315254885Sdumbbell RADEON_REQUIRE_QUIESCENCE); 2316254885Sdumbbell } 2317254885Sdumbbell 2318254885Sdumbbell prim.start = 0; 2319254885Sdumbbell prim.finish = vertex->count; /* unused */ 2320254885Sdumbbell prim.prim = vertex->prim; 2321254885Sdumbbell prim.numverts = vertex->count; 2322254885Sdumbbell prim.vc_format = sarea_priv->vc_format; 2323254885Sdumbbell 2324254885Sdumbbell radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim); 2325254885Sdumbbell } 2326254885Sdumbbell 2327254885Sdumbbell if (vertex->discard) { 2328254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 2329254885Sdumbbell } 2330254885Sdumbbell 2331254885Sdumbbell COMMIT_RING(); 2332254885Sdumbbell return 0; 2333254885Sdumbbell} 2334254885Sdumbbell 2335254885Sdumbbellstatic int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) 2336254885Sdumbbell{ 2337254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2338254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 2339254885Sdumbbell drm_radeon_sarea_t *sarea_priv; 2340254885Sdumbbell struct drm_device_dma *dma = dev->dma; 2341254885Sdumbbell struct drm_buf *buf; 2342254885Sdumbbell drm_radeon_indices_t *elts = data; 2343254885Sdumbbell drm_radeon_tcl_prim_t prim; 2344254885Sdumbbell int count; 2345254885Sdumbbell 2346254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2347254885Sdumbbell 2348254885Sdumbbell sarea_priv = master_priv->sarea_priv; 2349254885Sdumbbell 2350254885Sdumbbell DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", 2351254885Sdumbbell DRM_CURRENTPID, elts->idx, elts->start, elts->end, 2352254885Sdumbbell elts->discard); 2353254885Sdumbbell 2354254885Sdumbbell if (elts->idx < 0 || elts->idx >= dma->buf_count) { 2355254885Sdumbbell DRM_ERROR("buffer index %d (of %d max)\n", 2356254885Sdumbbell elts->idx, dma->buf_count - 1); 2357254885Sdumbbell return -EINVAL; 2358254885Sdumbbell } 2359254885Sdumbbell if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) { 2360254885Sdumbbell DRM_ERROR("buffer prim %d\n", elts->prim); 2361254885Sdumbbell return -EINVAL; 2362254885Sdumbbell } 2363254885Sdumbbell 2364254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2365254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2366254885Sdumbbell 2367254885Sdumbbell buf = dma->buflist[elts->idx]; 2368254885Sdumbbell 2369254885Sdumbbell if (buf->file_priv != file_priv) { 2370254885Sdumbbell DRM_ERROR("process %d using buffer owned by %p\n", 2371254885Sdumbbell DRM_CURRENTPID, buf->file_priv); 2372254885Sdumbbell return -EINVAL; 2373254885Sdumbbell } 2374254885Sdumbbell if (buf->pending) { 2375254885Sdumbbell DRM_ERROR("sending pending buffer %d\n", elts->idx); 2376254885Sdumbbell return -EINVAL; 2377254885Sdumbbell } 2378254885Sdumbbell 2379254885Sdumbbell count = (elts->end - elts->start) / sizeof(u16); 2380254885Sdumbbell elts->start -= RADEON_INDEX_PRIM_OFFSET; 2381254885Sdumbbell 2382254885Sdumbbell if (elts->start & 0x7) { 2383254885Sdumbbell DRM_ERROR("misaligned buffer 0x%x\n", elts->start); 2384254885Sdumbbell return -EINVAL; 2385254885Sdumbbell } 2386254885Sdumbbell if (elts->start < buf->used) { 2387254885Sdumbbell DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used); 2388254885Sdumbbell return -EINVAL; 2389254885Sdumbbell } 2390254885Sdumbbell 2391254885Sdumbbell buf->used = elts->end; 2392254885Sdumbbell 2393254885Sdumbbell if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) { 2394254885Sdumbbell if (radeon_emit_state(dev_priv, file_priv, 2395254885Sdumbbell &sarea_priv->context_state, 2396254885Sdumbbell sarea_priv->tex_state, 2397254885Sdumbbell sarea_priv->dirty)) { 2398254885Sdumbbell DRM_ERROR("radeon_emit_state failed\n"); 2399254885Sdumbbell return -EINVAL; 2400254885Sdumbbell } 2401254885Sdumbbell 2402254885Sdumbbell sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | 2403254885Sdumbbell RADEON_UPLOAD_TEX1IMAGES | 2404254885Sdumbbell RADEON_UPLOAD_TEX2IMAGES | 2405254885Sdumbbell RADEON_REQUIRE_QUIESCENCE); 2406254885Sdumbbell } 2407254885Sdumbbell 2408254885Sdumbbell /* Build up a prim_t record: 2409254885Sdumbbell */ 2410254885Sdumbbell prim.start = elts->start; 2411254885Sdumbbell prim.finish = elts->end; 2412254885Sdumbbell prim.prim = elts->prim; 2413254885Sdumbbell prim.offset = 0; /* offset from start of dma buffers */ 2414254885Sdumbbell prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ 2415254885Sdumbbell prim.vc_format = sarea_priv->vc_format; 2416254885Sdumbbell 2417254885Sdumbbell radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &prim); 2418254885Sdumbbell if (elts->discard) { 2419254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 2420254885Sdumbbell } 2421254885Sdumbbell 2422254885Sdumbbell COMMIT_RING(); 2423254885Sdumbbell return 0; 2424254885Sdumbbell} 2425254885Sdumbbell 2426254885Sdumbbellstatic int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv) 2427254885Sdumbbell{ 2428254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2429254885Sdumbbell drm_radeon_texture_t *tex = data; 2430254885Sdumbbell drm_radeon_tex_image_t image; 2431254885Sdumbbell int ret; 2432254885Sdumbbell 2433254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2434254885Sdumbbell 2435254885Sdumbbell if (tex->image == NULL) { 2436254885Sdumbbell DRM_ERROR("null texture image!\n"); 2437254885Sdumbbell return -EINVAL; 2438254885Sdumbbell } 2439254885Sdumbbell 2440254885Sdumbbell if (DRM_COPY_FROM_USER(&image, 2441254885Sdumbbell (drm_radeon_tex_image_t __user *) tex->image, 2442254885Sdumbbell sizeof(image))) 2443254885Sdumbbell return -EFAULT; 2444254885Sdumbbell 2445254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2446254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2447254885Sdumbbell 2448254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2449254885Sdumbbell ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image); 2450254885Sdumbbell else 2451254885Sdumbbell ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image); 2452254885Sdumbbell 2453254885Sdumbbell return ret; 2454254885Sdumbbell} 2455254885Sdumbbell 2456254885Sdumbbellstatic int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) 2457254885Sdumbbell{ 2458254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2459254885Sdumbbell drm_radeon_stipple_t *stipple = data; 2460254885Sdumbbell u32 mask[32]; 2461254885Sdumbbell 2462254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2463254885Sdumbbell 2464254885Sdumbbell if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) 2465254885Sdumbbell return -EFAULT; 2466254885Sdumbbell 2467254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2468254885Sdumbbell 2469254885Sdumbbell radeon_cp_dispatch_stipple(dev, mask); 2470254885Sdumbbell 2471254885Sdumbbell COMMIT_RING(); 2472254885Sdumbbell return 0; 2473254885Sdumbbell} 2474254885Sdumbbell 2475254885Sdumbbellstatic int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv) 2476254885Sdumbbell{ 2477254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2478254885Sdumbbell struct drm_device_dma *dma = dev->dma; 2479254885Sdumbbell struct drm_buf *buf; 2480254885Sdumbbell drm_radeon_indirect_t *indirect = data; 2481254885Sdumbbell RING_LOCALS; 2482254885Sdumbbell 2483254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2484254885Sdumbbell 2485254885Sdumbbell DRM_DEBUG("idx=%d s=%d e=%d d=%d\n", 2486254885Sdumbbell indirect->idx, indirect->start, indirect->end, 2487254885Sdumbbell indirect->discard); 2488254885Sdumbbell 2489254885Sdumbbell if (indirect->idx < 0 || indirect->idx >= dma->buf_count) { 2490254885Sdumbbell DRM_ERROR("buffer index %d (of %d max)\n", 2491254885Sdumbbell indirect->idx, dma->buf_count - 1); 2492254885Sdumbbell return -EINVAL; 2493254885Sdumbbell } 2494254885Sdumbbell 2495254885Sdumbbell buf = dma->buflist[indirect->idx]; 2496254885Sdumbbell 2497254885Sdumbbell if (buf->file_priv != file_priv) { 2498254885Sdumbbell DRM_ERROR("process %d using buffer owned by %p\n", 2499254885Sdumbbell DRM_CURRENTPID, buf->file_priv); 2500254885Sdumbbell return -EINVAL; 2501254885Sdumbbell } 2502254885Sdumbbell if (buf->pending) { 2503254885Sdumbbell DRM_ERROR("sending pending buffer %d\n", indirect->idx); 2504254885Sdumbbell return -EINVAL; 2505254885Sdumbbell } 2506254885Sdumbbell 2507254885Sdumbbell if (indirect->start < buf->used) { 2508254885Sdumbbell DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n", 2509254885Sdumbbell indirect->start, buf->used); 2510254885Sdumbbell return -EINVAL; 2511254885Sdumbbell } 2512254885Sdumbbell 2513254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2514254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2515254885Sdumbbell 2516254885Sdumbbell buf->used = indirect->end; 2517254885Sdumbbell 2518254885Sdumbbell /* Dispatch the indirect buffer full of commands from the 2519254885Sdumbbell * X server. This is insecure and is thus only available to 2520254885Sdumbbell * privileged clients. 2521254885Sdumbbell */ 2522254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 2523254885Sdumbbell r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); 2524254885Sdumbbell else { 2525254885Sdumbbell /* Wait for the 3D stream to idle before the indirect buffer 2526254885Sdumbbell * containing 2D acceleration commands is processed. 2527254885Sdumbbell */ 2528254885Sdumbbell BEGIN_RING(2); 2529254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 2530254885Sdumbbell ADVANCE_RING(); 2531254885Sdumbbell radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); 2532254885Sdumbbell } 2533254885Sdumbbell 2534254885Sdumbbell if (indirect->discard) { 2535254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 2536254885Sdumbbell } 2537254885Sdumbbell 2538254885Sdumbbell COMMIT_RING(); 2539254885Sdumbbell return 0; 2540254885Sdumbbell} 2541254885Sdumbbell 2542254885Sdumbbellstatic int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) 2543254885Sdumbbell{ 2544254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2545254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 2546254885Sdumbbell drm_radeon_sarea_t *sarea_priv; 2547254885Sdumbbell struct drm_device_dma *dma = dev->dma; 2548254885Sdumbbell struct drm_buf *buf; 2549254885Sdumbbell drm_radeon_vertex2_t *vertex = data; 2550254885Sdumbbell int i; 2551254885Sdumbbell unsigned char laststate; 2552254885Sdumbbell 2553254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2554254885Sdumbbell 2555254885Sdumbbell sarea_priv = master_priv->sarea_priv; 2556254885Sdumbbell 2557254885Sdumbbell DRM_DEBUG("pid=%d index=%d discard=%d\n", 2558254885Sdumbbell DRM_CURRENTPID, vertex->idx, vertex->discard); 2559254885Sdumbbell 2560254885Sdumbbell if (vertex->idx < 0 || vertex->idx >= dma->buf_count) { 2561254885Sdumbbell DRM_ERROR("buffer index %d (of %d max)\n", 2562254885Sdumbbell vertex->idx, dma->buf_count - 1); 2563254885Sdumbbell return -EINVAL; 2564254885Sdumbbell } 2565254885Sdumbbell 2566254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2567254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2568254885Sdumbbell 2569254885Sdumbbell buf = dma->buflist[vertex->idx]; 2570254885Sdumbbell 2571254885Sdumbbell if (buf->file_priv != file_priv) { 2572254885Sdumbbell DRM_ERROR("process %d using buffer owned by %p\n", 2573254885Sdumbbell DRM_CURRENTPID, buf->file_priv); 2574254885Sdumbbell return -EINVAL; 2575254885Sdumbbell } 2576254885Sdumbbell 2577254885Sdumbbell if (buf->pending) { 2578254885Sdumbbell DRM_ERROR("sending pending buffer %d\n", vertex->idx); 2579254885Sdumbbell return -EINVAL; 2580254885Sdumbbell } 2581254885Sdumbbell 2582254885Sdumbbell if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) 2583254885Sdumbbell return -EINVAL; 2584254885Sdumbbell 2585254885Sdumbbell for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) { 2586254885Sdumbbell drm_radeon_prim_t prim; 2587254885Sdumbbell drm_radeon_tcl_prim_t tclprim; 2588254885Sdumbbell 2589254885Sdumbbell if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim))) 2590254885Sdumbbell return -EFAULT; 2591254885Sdumbbell 2592254885Sdumbbell if (prim.stateidx != laststate) { 2593254885Sdumbbell drm_radeon_state_t state; 2594254885Sdumbbell 2595254885Sdumbbell if (DRM_COPY_FROM_USER(&state, 2596254885Sdumbbell &vertex->state[prim.stateidx], 2597254885Sdumbbell sizeof(state))) 2598254885Sdumbbell return -EFAULT; 2599254885Sdumbbell 2600254885Sdumbbell if (radeon_emit_state2(dev_priv, file_priv, &state)) { 2601254885Sdumbbell DRM_ERROR("radeon_emit_state2 failed\n"); 2602254885Sdumbbell return -EINVAL; 2603254885Sdumbbell } 2604254885Sdumbbell 2605254885Sdumbbell laststate = prim.stateidx; 2606254885Sdumbbell } 2607254885Sdumbbell 2608254885Sdumbbell tclprim.start = prim.start; 2609254885Sdumbbell tclprim.finish = prim.finish; 2610254885Sdumbbell tclprim.prim = prim.prim; 2611254885Sdumbbell tclprim.vc_format = prim.vc_format; 2612254885Sdumbbell 2613254885Sdumbbell if (prim.prim & RADEON_PRIM_WALK_IND) { 2614254885Sdumbbell tclprim.offset = prim.numverts * 64; 2615254885Sdumbbell tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ 2616254885Sdumbbell 2617254885Sdumbbell radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &tclprim); 2618254885Sdumbbell } else { 2619254885Sdumbbell tclprim.numverts = prim.numverts; 2620254885Sdumbbell tclprim.offset = 0; /* not used */ 2621254885Sdumbbell 2622254885Sdumbbell radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim); 2623254885Sdumbbell } 2624254885Sdumbbell 2625254885Sdumbbell if (sarea_priv->nbox == 1) 2626254885Sdumbbell sarea_priv->nbox = 0; 2627254885Sdumbbell } 2628254885Sdumbbell 2629254885Sdumbbell if (vertex->discard) { 2630254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 2631254885Sdumbbell } 2632254885Sdumbbell 2633254885Sdumbbell COMMIT_RING(); 2634254885Sdumbbell return 0; 2635254885Sdumbbell} 2636254885Sdumbbell 2637254885Sdumbbellstatic int radeon_emit_packets(drm_radeon_private_t * dev_priv, 2638254885Sdumbbell struct drm_file *file_priv, 2639254885Sdumbbell drm_radeon_cmd_header_t header, 2640254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2641254885Sdumbbell{ 2642254885Sdumbbell int id = (int)header.packet.packet_id; 2643254885Sdumbbell int sz, reg; 2644254885Sdumbbell RING_LOCALS; 2645254885Sdumbbell 2646254885Sdumbbell if (id >= RADEON_MAX_STATE_PACKETS) 2647254885Sdumbbell return -EINVAL; 2648254885Sdumbbell 2649254885Sdumbbell sz = packet[id].len; 2650254885Sdumbbell reg = packet[id].start; 2651254885Sdumbbell 2652254885Sdumbbell if (sz * sizeof(u32) > drm_buffer_unprocessed(cmdbuf->buffer)) { 2653254885Sdumbbell DRM_ERROR("Packet size provided larger than data provided\n"); 2654254885Sdumbbell return -EINVAL; 2655254885Sdumbbell } 2656254885Sdumbbell 2657254885Sdumbbell if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, 2658254885Sdumbbell cmdbuf->buffer)) { 2659254885Sdumbbell DRM_ERROR("Packet verification failed\n"); 2660254885Sdumbbell return -EINVAL; 2661254885Sdumbbell } 2662254885Sdumbbell 2663254885Sdumbbell BEGIN_RING(sz + 1); 2664254885Sdumbbell OUT_RING(CP_PACKET0(reg, (sz - 1))); 2665254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz); 2666254885Sdumbbell ADVANCE_RING(); 2667254885Sdumbbell 2668254885Sdumbbell return 0; 2669254885Sdumbbell} 2670254885Sdumbbell 2671254885Sdumbbellstatic __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv, 2672254885Sdumbbell drm_radeon_cmd_header_t header, 2673254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2674254885Sdumbbell{ 2675254885Sdumbbell int sz = header.scalars.count; 2676254885Sdumbbell int start = header.scalars.offset; 2677254885Sdumbbell int stride = header.scalars.stride; 2678254885Sdumbbell RING_LOCALS; 2679254885Sdumbbell 2680254885Sdumbbell BEGIN_RING(3 + sz); 2681254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0)); 2682254885Sdumbbell OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); 2683254885Sdumbbell OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1)); 2684254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz); 2685254885Sdumbbell ADVANCE_RING(); 2686254885Sdumbbell return 0; 2687254885Sdumbbell} 2688254885Sdumbbell 2689254885Sdumbbell/* God this is ugly 2690254885Sdumbbell */ 2691254885Sdumbbellstatic __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv, 2692254885Sdumbbell drm_radeon_cmd_header_t header, 2693254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2694254885Sdumbbell{ 2695254885Sdumbbell int sz = header.scalars.count; 2696254885Sdumbbell int start = ((unsigned int)header.scalars.offset) + 0x100; 2697254885Sdumbbell int stride = header.scalars.stride; 2698254885Sdumbbell RING_LOCALS; 2699254885Sdumbbell 2700254885Sdumbbell BEGIN_RING(3 + sz); 2701254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0)); 2702254885Sdumbbell OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT)); 2703254885Sdumbbell OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1)); 2704254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz); 2705254885Sdumbbell ADVANCE_RING(); 2706254885Sdumbbell return 0; 2707254885Sdumbbell} 2708254885Sdumbbell 2709254885Sdumbbellstatic __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv, 2710254885Sdumbbell drm_radeon_cmd_header_t header, 2711254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2712254885Sdumbbell{ 2713254885Sdumbbell int sz = header.vectors.count; 2714254885Sdumbbell int start = header.vectors.offset; 2715254885Sdumbbell int stride = header.vectors.stride; 2716254885Sdumbbell RING_LOCALS; 2717254885Sdumbbell 2718254885Sdumbbell BEGIN_RING(5 + sz); 2719254885Sdumbbell OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 2720254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); 2721254885Sdumbbell OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); 2722254885Sdumbbell OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); 2723254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz); 2724254885Sdumbbell ADVANCE_RING(); 2725254885Sdumbbell 2726254885Sdumbbell return 0; 2727254885Sdumbbell} 2728254885Sdumbbell 2729254885Sdumbbellstatic __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, 2730254885Sdumbbell drm_radeon_cmd_header_t header, 2731254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2732254885Sdumbbell{ 2733254885Sdumbbell int sz = header.veclinear.count * 4; 2734254885Sdumbbell int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8); 2735254885Sdumbbell RING_LOCALS; 2736254885Sdumbbell 2737254885Sdumbbell if (!sz) 2738254885Sdumbbell return 0; 2739254885Sdumbbell if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer)) 2740254885Sdumbbell return -EINVAL; 2741254885Sdumbbell 2742254885Sdumbbell BEGIN_RING(5 + sz); 2743254885Sdumbbell OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); 2744254885Sdumbbell OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0)); 2745254885Sdumbbell OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT)); 2746254885Sdumbbell OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1))); 2747254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz); 2748254885Sdumbbell ADVANCE_RING(); 2749254885Sdumbbell 2750254885Sdumbbell return 0; 2751254885Sdumbbell} 2752254885Sdumbbell 2753254885Sdumbbellstatic int radeon_emit_packet3(struct drm_device * dev, 2754254885Sdumbbell struct drm_file *file_priv, 2755254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf) 2756254885Sdumbbell{ 2757254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2758254885Sdumbbell unsigned int cmdsz; 2759254885Sdumbbell int ret; 2760254885Sdumbbell RING_LOCALS; 2761254885Sdumbbell 2762254885Sdumbbell DRM_DEBUG("\n"); 2763254885Sdumbbell 2764254885Sdumbbell if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, 2765254885Sdumbbell cmdbuf, &cmdsz))) { 2766254885Sdumbbell DRM_ERROR("Packet verification failed\n"); 2767254885Sdumbbell return ret; 2768254885Sdumbbell } 2769254885Sdumbbell 2770254885Sdumbbell BEGIN_RING(cmdsz); 2771254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz); 2772254885Sdumbbell ADVANCE_RING(); 2773254885Sdumbbell 2774254885Sdumbbell return 0; 2775254885Sdumbbell} 2776254885Sdumbbell 2777254885Sdumbbellstatic int radeon_emit_packet3_cliprect(struct drm_device *dev, 2778254885Sdumbbell struct drm_file *file_priv, 2779254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf, 2780254885Sdumbbell int orig_nbox) 2781254885Sdumbbell{ 2782254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2783254885Sdumbbell struct drm_clip_rect box; 2784254885Sdumbbell unsigned int cmdsz; 2785254885Sdumbbell int ret; 2786254885Sdumbbell struct drm_clip_rect __user *boxes = cmdbuf->boxes; 2787254885Sdumbbell int i = 0; 2788254885Sdumbbell RING_LOCALS; 2789254885Sdumbbell 2790254885Sdumbbell DRM_DEBUG("\n"); 2791254885Sdumbbell 2792254885Sdumbbell if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv, 2793254885Sdumbbell cmdbuf, &cmdsz))) { 2794254885Sdumbbell DRM_ERROR("Packet verification failed\n"); 2795254885Sdumbbell return ret; 2796254885Sdumbbell } 2797254885Sdumbbell 2798254885Sdumbbell if (!orig_nbox) 2799254885Sdumbbell goto out; 2800254885Sdumbbell 2801254885Sdumbbell do { 2802254885Sdumbbell if (i < cmdbuf->nbox) { 2803254885Sdumbbell if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box))) 2804254885Sdumbbell return -EFAULT; 2805254885Sdumbbell /* FIXME The second and subsequent times round 2806254885Sdumbbell * this loop, send a WAIT_UNTIL_3D_IDLE before 2807254885Sdumbbell * calling emit_clip_rect(). This fixes a 2808254885Sdumbbell * lockup on fast machines when sending 2809254885Sdumbbell * several cliprects with a cmdbuf, as when 2810254885Sdumbbell * waving a 2D window over a 3D 2811254885Sdumbbell * window. Something in the commands from user 2812254885Sdumbbell * space seems to hang the card when they're 2813254885Sdumbbell * sent several times in a row. That would be 2814254885Sdumbbell * the correct place to fix it but this works 2815254885Sdumbbell * around it until I can figure that out - Tim 2816254885Sdumbbell * Smith */ 2817254885Sdumbbell if (i) { 2818254885Sdumbbell BEGIN_RING(2); 2819254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 2820254885Sdumbbell ADVANCE_RING(); 2821254885Sdumbbell } 2822254885Sdumbbell radeon_emit_clip_rect(dev_priv, &box); 2823254885Sdumbbell } 2824254885Sdumbbell 2825254885Sdumbbell BEGIN_RING(cmdsz); 2826254885Sdumbbell OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz); 2827254885Sdumbbell ADVANCE_RING(); 2828254885Sdumbbell 2829254885Sdumbbell } while (++i < cmdbuf->nbox); 2830254885Sdumbbell if (cmdbuf->nbox == 1) 2831254885Sdumbbell cmdbuf->nbox = 0; 2832254885Sdumbbell 2833254885Sdumbbell return 0; 2834254885Sdumbbell out: 2835254885Sdumbbell drm_buffer_advance(cmdbuf->buffer, cmdsz * 4); 2836254885Sdumbbell return 0; 2837254885Sdumbbell} 2838254885Sdumbbell 2839254885Sdumbbellstatic int radeon_emit_wait(struct drm_device * dev, int flags) 2840254885Sdumbbell{ 2841254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2842254885Sdumbbell RING_LOCALS; 2843254885Sdumbbell 2844254885Sdumbbell DRM_DEBUG("%x\n", flags); 2845254885Sdumbbell switch (flags) { 2846254885Sdumbbell case RADEON_WAIT_2D: 2847254885Sdumbbell BEGIN_RING(2); 2848254885Sdumbbell RADEON_WAIT_UNTIL_2D_IDLE(); 2849254885Sdumbbell ADVANCE_RING(); 2850254885Sdumbbell break; 2851254885Sdumbbell case RADEON_WAIT_3D: 2852254885Sdumbbell BEGIN_RING(2); 2853254885Sdumbbell RADEON_WAIT_UNTIL_3D_IDLE(); 2854254885Sdumbbell ADVANCE_RING(); 2855254885Sdumbbell break; 2856254885Sdumbbell case RADEON_WAIT_2D | RADEON_WAIT_3D: 2857254885Sdumbbell BEGIN_RING(2); 2858254885Sdumbbell RADEON_WAIT_UNTIL_IDLE(); 2859254885Sdumbbell ADVANCE_RING(); 2860254885Sdumbbell break; 2861254885Sdumbbell default: 2862254885Sdumbbell return -EINVAL; 2863254885Sdumbbell } 2864254885Sdumbbell 2865254885Sdumbbell return 0; 2866254885Sdumbbell} 2867254885Sdumbbell 2868254885Sdumbbellstatic int radeon_cp_cmdbuf(struct drm_device *dev, void *data, 2869254885Sdumbbell struct drm_file *file_priv) 2870254885Sdumbbell{ 2871254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 2872254885Sdumbbell struct drm_device_dma *dma = dev->dma; 2873254885Sdumbbell struct drm_buf *buf = NULL; 2874254885Sdumbbell drm_radeon_cmd_header_t stack_header; 2875254885Sdumbbell int idx; 2876254885Sdumbbell drm_radeon_kcmd_buffer_t *cmdbuf = data; 2877254885Sdumbbell int orig_nbox; 2878254885Sdumbbell 2879254885Sdumbbell LOCK_TEST_WITH_RETURN(dev, file_priv); 2880254885Sdumbbell 2881254885Sdumbbell RING_SPACE_TEST_WITH_RETURN(dev_priv); 2882254885Sdumbbell VB_AGE_TEST_WITH_RETURN(dev_priv); 2883254885Sdumbbell 2884254885Sdumbbell if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) { 2885254885Sdumbbell return -EINVAL; 2886254885Sdumbbell } 2887254885Sdumbbell 2888254885Sdumbbell /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid 2889254885Sdumbbell * races between checking values and using those values in other code, 2890254885Sdumbbell * and simply to avoid a lot of function calls to copy in data. 2891254885Sdumbbell */ 2892254885Sdumbbell if (cmdbuf->bufsz != 0) { 2893254885Sdumbbell int rv; 2894254885Sdumbbell void __user *buffer = cmdbuf->buffer; 2895254885Sdumbbell rv = drm_buffer_alloc(&cmdbuf->buffer, cmdbuf->bufsz); 2896254885Sdumbbell if (rv) 2897254885Sdumbbell return rv; 2898254885Sdumbbell rv = drm_buffer_copy_from_user(cmdbuf->buffer, buffer, 2899254885Sdumbbell cmdbuf->bufsz); 2900254885Sdumbbell if (rv) { 2901254885Sdumbbell drm_buffer_free(cmdbuf->buffer); 2902254885Sdumbbell return rv; 2903254885Sdumbbell } 2904254885Sdumbbell } else 2905254885Sdumbbell goto done; 2906254885Sdumbbell 2907254885Sdumbbell orig_nbox = cmdbuf->nbox; 2908254885Sdumbbell 2909254885Sdumbbell if (dev_priv->microcode_version == UCODE_R300) { 2910254885Sdumbbell int temp; 2911254885Sdumbbell temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); 2912254885Sdumbbell 2913254885Sdumbbell drm_buffer_free(cmdbuf->buffer); 2914254885Sdumbbell 2915254885Sdumbbell return temp; 2916254885Sdumbbell } 2917254885Sdumbbell 2918254885Sdumbbell /* microcode_version != r300 */ 2919254885Sdumbbell while (drm_buffer_unprocessed(cmdbuf->buffer) >= sizeof(stack_header)) { 2920254885Sdumbbell 2921254885Sdumbbell drm_radeon_cmd_header_t *header; 2922254885Sdumbbell header = drm_buffer_read_object(cmdbuf->buffer, 2923254885Sdumbbell sizeof(stack_header), &stack_header); 2924254885Sdumbbell 2925254885Sdumbbell switch (header->header.cmd_type) { 2926254885Sdumbbell case RADEON_CMD_PACKET: 2927254885Sdumbbell DRM_DEBUG("RADEON_CMD_PACKET\n"); 2928254885Sdumbbell if (radeon_emit_packets 2929254885Sdumbbell (dev_priv, file_priv, *header, cmdbuf)) { 2930254885Sdumbbell DRM_ERROR("radeon_emit_packets failed\n"); 2931254885Sdumbbell goto err; 2932254885Sdumbbell } 2933254885Sdumbbell break; 2934254885Sdumbbell 2935254885Sdumbbell case RADEON_CMD_SCALARS: 2936254885Sdumbbell DRM_DEBUG("RADEON_CMD_SCALARS\n"); 2937254885Sdumbbell if (radeon_emit_scalars(dev_priv, *header, cmdbuf)) { 2938254885Sdumbbell DRM_ERROR("radeon_emit_scalars failed\n"); 2939254885Sdumbbell goto err; 2940254885Sdumbbell } 2941254885Sdumbbell break; 2942254885Sdumbbell 2943254885Sdumbbell case RADEON_CMD_VECTORS: 2944254885Sdumbbell DRM_DEBUG("RADEON_CMD_VECTORS\n"); 2945254885Sdumbbell if (radeon_emit_vectors(dev_priv, *header, cmdbuf)) { 2946254885Sdumbbell DRM_ERROR("radeon_emit_vectors failed\n"); 2947254885Sdumbbell goto err; 2948254885Sdumbbell } 2949254885Sdumbbell break; 2950254885Sdumbbell 2951254885Sdumbbell case RADEON_CMD_DMA_DISCARD: 2952254885Sdumbbell DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n"); 2953254885Sdumbbell idx = header->dma.buf_idx; 2954254885Sdumbbell if (idx < 0 || idx >= dma->buf_count) { 2955254885Sdumbbell DRM_ERROR("buffer index %d (of %d max)\n", 2956254885Sdumbbell idx, dma->buf_count - 1); 2957254885Sdumbbell goto err; 2958254885Sdumbbell } 2959254885Sdumbbell 2960254885Sdumbbell buf = dma->buflist[idx]; 2961254885Sdumbbell if (buf->file_priv != file_priv || buf->pending) { 2962254885Sdumbbell DRM_ERROR("bad buffer %p %p %d\n", 2963254885Sdumbbell buf->file_priv, file_priv, 2964254885Sdumbbell buf->pending); 2965254885Sdumbbell goto err; 2966254885Sdumbbell } 2967254885Sdumbbell 2968254885Sdumbbell radeon_cp_discard_buffer(dev, file_priv->masterp, buf); 2969254885Sdumbbell break; 2970254885Sdumbbell 2971254885Sdumbbell case RADEON_CMD_PACKET3: 2972254885Sdumbbell DRM_DEBUG("RADEON_CMD_PACKET3\n"); 2973254885Sdumbbell if (radeon_emit_packet3(dev, file_priv, cmdbuf)) { 2974254885Sdumbbell DRM_ERROR("radeon_emit_packet3 failed\n"); 2975254885Sdumbbell goto err; 2976254885Sdumbbell } 2977254885Sdumbbell break; 2978254885Sdumbbell 2979254885Sdumbbell case RADEON_CMD_PACKET3_CLIP: 2980254885Sdumbbell DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); 2981254885Sdumbbell if (radeon_emit_packet3_cliprect 2982254885Sdumbbell (dev, file_priv, cmdbuf, orig_nbox)) { 2983254885Sdumbbell DRM_ERROR("radeon_emit_packet3_clip failed\n"); 2984254885Sdumbbell goto err; 2985254885Sdumbbell } 2986254885Sdumbbell break; 2987254885Sdumbbell 2988254885Sdumbbell case RADEON_CMD_SCALARS2: 2989254885Sdumbbell DRM_DEBUG("RADEON_CMD_SCALARS2\n"); 2990254885Sdumbbell if (radeon_emit_scalars2(dev_priv, *header, cmdbuf)) { 2991254885Sdumbbell DRM_ERROR("radeon_emit_scalars2 failed\n"); 2992254885Sdumbbell goto err; 2993254885Sdumbbell } 2994254885Sdumbbell break; 2995254885Sdumbbell 2996254885Sdumbbell case RADEON_CMD_WAIT: 2997254885Sdumbbell DRM_DEBUG("RADEON_CMD_WAIT\n"); 2998254885Sdumbbell if (radeon_emit_wait(dev, header->wait.flags)) { 2999254885Sdumbbell DRM_ERROR("radeon_emit_wait failed\n"); 3000254885Sdumbbell goto err; 3001254885Sdumbbell } 3002254885Sdumbbell break; 3003254885Sdumbbell case RADEON_CMD_VECLINEAR: 3004254885Sdumbbell DRM_DEBUG("RADEON_CMD_VECLINEAR\n"); 3005254885Sdumbbell if (radeon_emit_veclinear(dev_priv, *header, cmdbuf)) { 3006254885Sdumbbell DRM_ERROR("radeon_emit_veclinear failed\n"); 3007254885Sdumbbell goto err; 3008254885Sdumbbell } 3009254885Sdumbbell break; 3010254885Sdumbbell 3011254885Sdumbbell default: 3012254885Sdumbbell DRM_ERROR("bad cmd_type %d at byte %d\n", 3013254885Sdumbbell header->header.cmd_type, 3014254885Sdumbbell cmdbuf->buffer->iterator); 3015254885Sdumbbell goto err; 3016254885Sdumbbell } 3017254885Sdumbbell } 3018254885Sdumbbell 3019254885Sdumbbell drm_buffer_free(cmdbuf->buffer); 3020254885Sdumbbell 3021254885Sdumbbell done: 3022254885Sdumbbell DRM_DEBUG("DONE\n"); 3023254885Sdumbbell COMMIT_RING(); 3024254885Sdumbbell return 0; 3025254885Sdumbbell 3026254885Sdumbbell err: 3027254885Sdumbbell drm_buffer_free(cmdbuf->buffer); 3028254885Sdumbbell return -EINVAL; 3029254885Sdumbbell} 3030254885Sdumbbell 3031254885Sdumbbellstatic int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) 3032254885Sdumbbell{ 3033254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 3034254885Sdumbbell drm_radeon_getparam_t *param = data; 3035254885Sdumbbell int value; 3036254885Sdumbbell 3037254885Sdumbbell DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 3038254885Sdumbbell 3039254885Sdumbbell switch (param->param) { 3040254885Sdumbbell case RADEON_PARAM_GART_BUFFER_OFFSET: 3041254885Sdumbbell value = dev_priv->gart_buffers_offset; 3042254885Sdumbbell break; 3043254885Sdumbbell case RADEON_PARAM_LAST_FRAME: 3044254885Sdumbbell dev_priv->stats.last_frame_reads++; 3045254885Sdumbbell value = GET_SCRATCH(dev_priv, 0); 3046254885Sdumbbell break; 3047254885Sdumbbell case RADEON_PARAM_LAST_DISPATCH: 3048254885Sdumbbell value = GET_SCRATCH(dev_priv, 1); 3049254885Sdumbbell break; 3050254885Sdumbbell case RADEON_PARAM_LAST_CLEAR: 3051254885Sdumbbell dev_priv->stats.last_clear_reads++; 3052254885Sdumbbell value = GET_SCRATCH(dev_priv, 2); 3053254885Sdumbbell break; 3054254885Sdumbbell case RADEON_PARAM_IRQ_NR: 3055254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 3056254885Sdumbbell value = 0; 3057254885Sdumbbell else 3058254885Sdumbbell value = dev->irq; 3059254885Sdumbbell break; 3060254885Sdumbbell case RADEON_PARAM_GART_BASE: 3061254885Sdumbbell value = dev_priv->gart_vm_start; 3062254885Sdumbbell break; 3063254885Sdumbbell case RADEON_PARAM_REGISTER_HANDLE: 3064254885Sdumbbell value = dev_priv->mmio->offset; 3065254885Sdumbbell break; 3066254885Sdumbbell case RADEON_PARAM_STATUS_HANDLE: 3067254885Sdumbbell value = dev_priv->ring_rptr_offset; 3068254885Sdumbbell break; 3069254885Sdumbbell#ifndef __LP64__ 3070254885Sdumbbell /* 3071254885Sdumbbell * This ioctl() doesn't work on 64-bit platforms because hw_lock is a 3072254885Sdumbbell * pointer which can't fit into an int-sized variable. According to 3073254885Sdumbbell * Michel D��nzer, the ioctl() is only used on embedded platforms, so 3074254885Sdumbbell * not supporting it shouldn't be a problem. If the same functionality 3075254885Sdumbbell * is needed on 64-bit platforms, a new ioctl() would have to be added, 3076254885Sdumbbell * so backwards-compatibility for the embedded platforms can be 3077254885Sdumbbell * maintained. --davidm 4-Feb-2004. 3078254885Sdumbbell */ 3079254885Sdumbbell case RADEON_PARAM_SAREA_HANDLE: 3080254885Sdumbbell /* The lock is the first dword in the sarea. */ 3081254885Sdumbbell /* no users of this parameter */ 3082254885Sdumbbell break; 3083254885Sdumbbell#endif 3084254885Sdumbbell case RADEON_PARAM_GART_TEX_HANDLE: 3085254885Sdumbbell value = dev_priv->gart_textures_offset; 3086254885Sdumbbell break; 3087254885Sdumbbell case RADEON_PARAM_SCRATCH_OFFSET: 3088254885Sdumbbell if (!dev_priv->writeback_works) 3089254885Sdumbbell return -EINVAL; 3090254885Sdumbbell if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) 3091254885Sdumbbell value = R600_SCRATCH_REG_OFFSET; 3092254885Sdumbbell else 3093254885Sdumbbell value = RADEON_SCRATCH_REG_OFFSET; 3094254885Sdumbbell break; 3095254885Sdumbbell case RADEON_PARAM_CARD_TYPE: 3096254885Sdumbbell if (dev_priv->flags & RADEON_IS_PCIE) 3097254885Sdumbbell value = RADEON_CARD_PCIE; 3098254885Sdumbbell else if (dev_priv->flags & RADEON_IS_AGP) 3099254885Sdumbbell value = RADEON_CARD_AGP; 3100254885Sdumbbell else 3101254885Sdumbbell value = RADEON_CARD_PCI; 3102254885Sdumbbell break; 3103254885Sdumbbell case RADEON_PARAM_VBLANK_CRTC: 3104254885Sdumbbell value = radeon_vblank_crtc_get(dev); 3105254885Sdumbbell break; 3106254885Sdumbbell case RADEON_PARAM_FB_LOCATION: 3107254885Sdumbbell value = radeon_read_fb_location(dev_priv); 3108254885Sdumbbell break; 3109254885Sdumbbell case RADEON_PARAM_NUM_GB_PIPES: 3110254885Sdumbbell value = dev_priv->num_gb_pipes; 3111254885Sdumbbell break; 3112254885Sdumbbell case RADEON_PARAM_NUM_Z_PIPES: 3113254885Sdumbbell value = dev_priv->num_z_pipes; 3114254885Sdumbbell break; 3115254885Sdumbbell default: 3116254885Sdumbbell DRM_DEBUG("Invalid parameter %d\n", param->param); 3117254885Sdumbbell return -EINVAL; 3118254885Sdumbbell } 3119254885Sdumbbell 3120254885Sdumbbell if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 3121254885Sdumbbell DRM_ERROR("copy_to_user\n"); 3122254885Sdumbbell return -EFAULT; 3123254885Sdumbbell } 3124254885Sdumbbell 3125254885Sdumbbell return 0; 3126254885Sdumbbell} 3127254885Sdumbbell 3128254885Sdumbbellstatic int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) 3129254885Sdumbbell{ 3130254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 3131254885Sdumbbell struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; 3132254885Sdumbbell drm_radeon_setparam_t *sp = data; 3133254885Sdumbbell struct drm_radeon_driver_file_fields *radeon_priv; 3134254885Sdumbbell 3135254885Sdumbbell switch (sp->param) { 3136254885Sdumbbell case RADEON_SETPARAM_FB_LOCATION: 3137254885Sdumbbell radeon_priv = file_priv->driver_priv; 3138254885Sdumbbell radeon_priv->radeon_fb_delta = dev_priv->fb_location - 3139254885Sdumbbell sp->value; 3140254885Sdumbbell break; 3141254885Sdumbbell case RADEON_SETPARAM_SWITCH_TILING: 3142254885Sdumbbell if (sp->value == 0) { 3143254885Sdumbbell DRM_DEBUG("color tiling disabled\n"); 3144254885Sdumbbell dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; 3145254885Sdumbbell dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; 3146254885Sdumbbell if (master_priv->sarea_priv) 3147254885Sdumbbell master_priv->sarea_priv->tiling_enabled = 0; 3148254885Sdumbbell } else if (sp->value == 1) { 3149254885Sdumbbell DRM_DEBUG("color tiling enabled\n"); 3150254885Sdumbbell dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; 3151254885Sdumbbell dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; 3152254885Sdumbbell if (master_priv->sarea_priv) 3153254885Sdumbbell master_priv->sarea_priv->tiling_enabled = 1; 3154254885Sdumbbell } 3155254885Sdumbbell break; 3156254885Sdumbbell case RADEON_SETPARAM_PCIGART_LOCATION: 3157254885Sdumbbell dev_priv->pcigart_offset = sp->value; 3158254885Sdumbbell dev_priv->pcigart_offset_set = 1; 3159254885Sdumbbell break; 3160254885Sdumbbell case RADEON_SETPARAM_NEW_MEMMAP: 3161254885Sdumbbell dev_priv->new_memmap = sp->value; 3162254885Sdumbbell break; 3163254885Sdumbbell case RADEON_SETPARAM_PCIGART_TABLE_SIZE: 3164254885Sdumbbell dev_priv->gart_info.table_size = sp->value; 3165254885Sdumbbell if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) 3166254885Sdumbbell dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; 3167254885Sdumbbell break; 3168254885Sdumbbell case RADEON_SETPARAM_VBLANK_CRTC: 3169254885Sdumbbell return radeon_vblank_crtc_set(dev, sp->value); 3170254885Sdumbbell break; 3171254885Sdumbbell default: 3172254885Sdumbbell DRM_DEBUG("Invalid parameter %d\n", sp->param); 3173254885Sdumbbell return -EINVAL; 3174254885Sdumbbell } 3175254885Sdumbbell 3176254885Sdumbbell return 0; 3177254885Sdumbbell} 3178254885Sdumbbell 3179254885Sdumbbell/* When a client dies: 3180254885Sdumbbell * - Check for and clean up flipped page state 3181254885Sdumbbell * - Free any alloced GART memory. 3182254885Sdumbbell * - Free any alloced radeon surfaces. 3183254885Sdumbbell * 3184254885Sdumbbell * DRM infrastructure takes care of reclaiming dma buffers. 3185254885Sdumbbell */ 3186254885Sdumbbellvoid radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) 3187254885Sdumbbell{ 3188254885Sdumbbell if (dev->dev_private) { 3189254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 3190254885Sdumbbell dev_priv->page_flipping = 0; 3191254885Sdumbbell radeon_mem_release(file_priv, dev_priv->gart_heap); 3192254885Sdumbbell radeon_mem_release(file_priv, dev_priv->fb_heap); 3193254885Sdumbbell radeon_surfaces_release(file_priv, dev_priv); 3194254885Sdumbbell } 3195254885Sdumbbell} 3196254885Sdumbbell 3197254885Sdumbbellvoid radeon_driver_lastclose(struct drm_device *dev) 3198254885Sdumbbell{ 3199254885Sdumbbell radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private); 3200254885Sdumbbell radeon_do_release(dev); 3201254885Sdumbbell} 3202254885Sdumbbell 3203254885Sdumbbellint radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) 3204254885Sdumbbell{ 3205254885Sdumbbell drm_radeon_private_t *dev_priv = dev->dev_private; 3206254885Sdumbbell struct drm_radeon_driver_file_fields *radeon_priv; 3207254885Sdumbbell 3208254885Sdumbbell DRM_DEBUG("\n"); 3209254885Sdumbbell radeon_priv = malloc(sizeof(*radeon_priv), DRM_MEM_DRIVER, M_WAITOK); 3210254885Sdumbbell 3211254885Sdumbbell if (!radeon_priv) 3212254885Sdumbbell return -ENOMEM; 3213254885Sdumbbell 3214254885Sdumbbell file_priv->driver_priv = radeon_priv; 3215254885Sdumbbell 3216254885Sdumbbell if (dev_priv) 3217254885Sdumbbell radeon_priv->radeon_fb_delta = dev_priv->fb_location; 3218254885Sdumbbell else 3219254885Sdumbbell radeon_priv->radeon_fb_delta = 0; 3220254885Sdumbbell return 0; 3221254885Sdumbbell} 3222254885Sdumbbell 3223254885Sdumbbellvoid radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) 3224254885Sdumbbell{ 3225254885Sdumbbell struct drm_radeon_driver_file_fields *radeon_priv = 3226254885Sdumbbell file_priv->driver_priv; 3227254885Sdumbbell 3228254885Sdumbbell free(radeon_priv, DRM_MEM_DRIVER); 3229254885Sdumbbell} 3230254885Sdumbbell 3231254885Sdumbbellstruct drm_ioctl_desc radeon_ioctls[] = { 3232254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3233254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3234254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3235254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3236254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), 3237254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), 3238254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset, DRM_AUTH), 3239254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), 3240254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap, DRM_AUTH), 3241254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), 3242254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), 3243254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices, DRM_AUTH), 3244254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), 3245254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), 3246254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3247254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), 3248254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), 3249254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), 3250254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip, DRM_AUTH), 3251254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), 3252254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free, DRM_AUTH), 3253254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 3254254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), 3255254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), 3256254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), 3257254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), 3258254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), 3259254885Sdumbbell DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) 3260254885Sdumbbell}; 3261254885Sdumbbell 3262254885Sdumbbellint radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); 3263