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 + -
显示快捷键?