radeon_state.c
来自「linux 内核源代码」· C语言 代码 · 共 2,223 行 · 第 1/5 页
C
2,223 行
/* radeon_state.c -- State support for Radeon -*- linux-c -*- *//* * Copyright 2000 VA Linux Systems, Inc., Fremont, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Gareth Hughes <gareth@valinux.com> * Kevin E. Martin <martin@valinux.com> */#include "drmP.h"#include "drm.h"#include "drm_sarea.h"#include "radeon_drm.h"#include "radeon_drv.h"/* ================================================================ * Helper functions for client state checking and fixup */static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * dev_priv, struct drm_file * file_priv, u32 *offset){ u64 off = *offset; u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1; struct drm_radeon_driver_file_fields *radeon_priv; /* Hrm ... the story of the offset ... So this function converts * the various ideas of what userland clients might have for an * offset in the card address space into an offset into the card * address space :) So with a sane client, it should just keep * the value intact and just do some boundary checking. However, * not all clients are sane. Some older clients pass us 0 based * offsets relative to the start of the framebuffer and some may * assume the AGP aperture it appended to the framebuffer, so we * try to detect those cases and fix them up. * * Note: It might be a good idea here to make sure the offset lands * in some "allowed" area to protect things like the PCIE GART... */ /* First, the best case, the offset already lands in either the * framebuffer or the GART mapped space */ if (radeon_check_offset(dev_priv, off)) return 0; /* Ok, that didn't happen... now check if we have a zero based * offset that fits in the framebuffer + gart space, apply the * magic offset we get from SETPARAM or calculated from fb_location */ if (off < (dev_priv->fb_size + dev_priv->gart_size)) { radeon_priv = file_priv->driver_priv; off += radeon_priv->radeon_fb_delta; } /* Finally, assume we aimed at a GART offset if beyond the fb */ if (off > fb_end) off = off - fb_end - 1 + dev_priv->gart_vm_start; /* Now recheck and fail if out of bounds */ if (radeon_check_offset(dev_priv, off)) { DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); *offset = off; return 0; } return -EINVAL;}static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * dev_priv, struct drm_file *file_priv, int id, u32 *data){ switch (id) { case RADEON_EMIT_PP_MISC: if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) { DRM_ERROR("Invalid depth buffer offset\n"); return -EINVAL; } break; case RADEON_EMIT_PP_CNTL: if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) { DRM_ERROR("Invalid colour buffer offset\n"); return -EINVAL; } break; case R200_EMIT_PP_TXOFFSET_0: case R200_EMIT_PP_TXOFFSET_1: case R200_EMIT_PP_TXOFFSET_2: case R200_EMIT_PP_TXOFFSET_3: case R200_EMIT_PP_TXOFFSET_4: case R200_EMIT_PP_TXOFFSET_5: if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[0])) { DRM_ERROR("Invalid R200 texture offset\n"); return -EINVAL; } break; case RADEON_EMIT_PP_TXFILTER_0: case RADEON_EMIT_PP_TXFILTER_1: case RADEON_EMIT_PP_TXFILTER_2: if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) { DRM_ERROR("Invalid R100 texture offset\n"); return -EINVAL; } break; case R200_EMIT_PP_CUBIC_OFFSETS_0: case R200_EMIT_PP_CUBIC_OFFSETS_1: case R200_EMIT_PP_CUBIC_OFFSETS_2: case R200_EMIT_PP_CUBIC_OFFSETS_3: case R200_EMIT_PP_CUBIC_OFFSETS_4: case R200_EMIT_PP_CUBIC_OFFSETS_5:{ int i; for (i = 0; i < 5; i++) { if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[i])) { DRM_ERROR ("Invalid R200 cubic texture offset\n"); return -EINVAL; } } break; } case RADEON_EMIT_PP_CUBIC_OFFSETS_T0: case RADEON_EMIT_PP_CUBIC_OFFSETS_T1: case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{ int i; for (i = 0; i < 5; i++) { if (radeon_check_and_fixup_offset(dev_priv, file_priv, &data[i])) { DRM_ERROR ("Invalid R100 cubic texture offset\n"); return -EINVAL; } } } break; case R200_EMIT_VAP_CTL:{ RING_LOCALS; BEGIN_RING(2); OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); ADVANCE_RING(); } break; case RADEON_EMIT_RB3D_COLORPITCH: case RADEON_EMIT_RE_LINE_PATTERN: case RADEON_EMIT_SE_LINE_WIDTH: case RADEON_EMIT_PP_LUM_MATRIX: case RADEON_EMIT_PP_ROT_MATRIX_0: case RADEON_EMIT_RB3D_STENCILREFMASK: case RADEON_EMIT_SE_VPORT_XSCALE: case RADEON_EMIT_SE_CNTL: case RADEON_EMIT_SE_CNTL_STATUS: case RADEON_EMIT_RE_MISC: case RADEON_EMIT_PP_BORDER_COLOR_0: case RADEON_EMIT_PP_BORDER_COLOR_1: case RADEON_EMIT_PP_BORDER_COLOR_2: case RADEON_EMIT_SE_ZBIAS_FACTOR: case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT: case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED: case R200_EMIT_PP_TXCBLEND_0: case R200_EMIT_PP_TXCBLEND_1: case R200_EMIT_PP_TXCBLEND_2: case R200_EMIT_PP_TXCBLEND_3: case R200_EMIT_PP_TXCBLEND_4: case R200_EMIT_PP_TXCBLEND_5: case R200_EMIT_PP_TXCBLEND_6: case R200_EMIT_PP_TXCBLEND_7: case R200_EMIT_TCL_LIGHT_MODEL_CTL_0: case R200_EMIT_TFACTOR_0: case R200_EMIT_VTX_FMT_0: case R200_EMIT_MATRIX_SELECT_0: case R200_EMIT_TEX_PROC_CTL_2: case R200_EMIT_TCL_UCP_VERT_BLEND_CTL: case R200_EMIT_PP_TXFILTER_0: case R200_EMIT_PP_TXFILTER_1: case R200_EMIT_PP_TXFILTER_2: case R200_EMIT_PP_TXFILTER_3: case R200_EMIT_PP_TXFILTER_4: case R200_EMIT_PP_TXFILTER_5: case R200_EMIT_VTE_CNTL: case R200_EMIT_OUTPUT_VTX_COMP_SEL: case R200_EMIT_PP_TAM_DEBUG3: case R200_EMIT_PP_CNTL_X: case R200_EMIT_RB3D_DEPTHXY_OFFSET: case R200_EMIT_RE_AUX_SCISSOR_CNTL: case R200_EMIT_RE_SCISSOR_TL_0: case R200_EMIT_RE_SCISSOR_TL_1: case R200_EMIT_RE_SCISSOR_TL_2: case R200_EMIT_SE_VAP_CNTL_STATUS: case R200_EMIT_SE_VTX_STATE_CNTL: case R200_EMIT_RE_POINTSIZE: case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0: case R200_EMIT_PP_CUBIC_FACES_0: case R200_EMIT_PP_CUBIC_FACES_1: case R200_EMIT_PP_CUBIC_FACES_2: case R200_EMIT_PP_CUBIC_FACES_3: case R200_EMIT_PP_CUBIC_FACES_4: case R200_EMIT_PP_CUBIC_FACES_5: case RADEON_EMIT_PP_TEX_SIZE_0: case RADEON_EMIT_PP_TEX_SIZE_1: case RADEON_EMIT_PP_TEX_SIZE_2: case R200_EMIT_RB3D_BLENDCOLOR: case R200_EMIT_TCL_POINT_SPRITE_CNTL: case RADEON_EMIT_PP_CUBIC_FACES_0: case RADEON_EMIT_PP_CUBIC_FACES_1: case RADEON_EMIT_PP_CUBIC_FACES_2: case R200_EMIT_PP_TRI_PERF_CNTL: case R200_EMIT_PP_AFS_0: case R200_EMIT_PP_AFS_1: case R200_EMIT_ATF_TFACTOR: case R200_EMIT_PP_TXCTLALL_0: case R200_EMIT_PP_TXCTLALL_1: case R200_EMIT_PP_TXCTLALL_2: case R200_EMIT_PP_TXCTLALL_3: case R200_EMIT_PP_TXCTLALL_4: case R200_EMIT_PP_TXCTLALL_5: case R200_EMIT_VAP_PVS_CNTL: /* These packets don't contain memory offsets */ break; default: DRM_ERROR("Unknown state packet ID %d\n", id); return -EINVAL; } return 0;}static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * dev_priv, struct drm_file *file_priv, drm_radeon_kcmd_buffer_t * cmdbuf, unsigned int *cmdsz){ u32 *cmd = (u32 *) cmdbuf->buf; u32 offset, narrays; int count, i, k; *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) { DRM_ERROR("Not a type 3 packet\n"); return -EINVAL; } if (4 * *cmdsz > cmdbuf->bufsz) { DRM_ERROR("Packet size larger than size of data provided\n"); return -EINVAL; } switch(cmd[0] & 0xff00) { /* XXX Are there old drivers needing other packets? */ case RADEON_3D_DRAW_IMMD: case RADEON_3D_DRAW_VBUF: case RADEON_3D_DRAW_INDX: case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: case RADEON_3D_CLEAR_ZMASK:/* case RADEON_CP_NEXT_CHAR: case RADEON_CP_PLY_NEXTSCAN: case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ /* these packets are safe */ break; case RADEON_CP_3D_DRAW_IMMD_2: case RADEON_CP_3D_DRAW_VBUF_2: case RADEON_CP_3D_DRAW_INDX_2: case RADEON_3D_CLEAR_HIZ: /* safe but r200 only */ if (dev_priv->microcode_version != UCODE_R200) { DRM_ERROR("Invalid 3d packet for r100-class chip\n"); return -EINVAL; } break; case RADEON_3D_LOAD_VBPNTR: count = (cmd[0] >> 16) & 0x3fff; if (count > 18) { /* 12 arrays max */ DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", count); return -EINVAL; } /* carefully check packet contents */ narrays = cmd[1] & ~0xc000; k = 0; i = 2; while ((k < narrays) && (i < (count + 2))) { i++; /* skip attribute field */ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[i])) { DRM_ERROR ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", k, i); return -EINVAL; } k++; i++; if (k == narrays) break; /* have one more to process, they come in pairs */ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[i])) { DRM_ERROR ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", k, i); return -EINVAL; } k++; i++; } /* do the counts match what we expect ? */ if ((k != narrays) || (i != (count + 2))) { DRM_ERROR ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", k, i, narrays, count + 1); return -EINVAL; } break; case RADEON_3D_RNDR_GEN_INDX_PRIM: if (dev_priv->microcode_version != UCODE_R100) { DRM_ERROR("Invalid 3d packet for r200-class chip\n"); return -EINVAL; } if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { DRM_ERROR("Invalid rndr_gen_indx offset\n"); return -EINVAL; } break; case RADEON_CP_INDX_BUFFER: if (dev_priv->microcode_version != UCODE_R200) { DRM_ERROR("Invalid 3d packet for r100-class chip\n"); return -EINVAL; } if ((cmd[1] & 0x8000ffff) != 0x80000810) { DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); return -EINVAL; } if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) { DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); return -EINVAL; } break; case RADEON_CNTL_HOSTDATA_BLT: case RADEON_CNTL_PAINT_MULTI: case RADEON_CNTL_BITBLT_MULTI: /* MSB of opcode: next DWORD GUI_CNTL */ if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; if (radeon_check_and_fixup_offset (dev_priv, file_priv, &offset)) { DRM_ERROR("Invalid first packet offset\n"); return -EINVAL; } cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10; } if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[3] << 10; if (radeon_check_and_fixup_offset (dev_priv, file_priv, &offset)) { DRM_ERROR("Invalid second packet offset\n"); return -EINVAL; } cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; } break; default: DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); return -EINVAL; } return 0;}/* ================================================================ * CP hardware state programming functions */static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv, struct drm_clip_rect * box){ RING_LOCALS; DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n", box->x1, box->y1, box->x2, box->y2); BEGIN_RING(4); OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0)); OUT_RING((box->y1 << 16) | box->x1); OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0)); OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1)); ADVANCE_RING();}/* Emit 1.1 state */static int radeon_emit_state(drm_radeon_private_t * dev_priv, struct drm_file *file_priv,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?