Enscript Output

extractedLnx/linux-2.6.33/drivers/gpu/drm/radeon/r600_cs.c_r600_packet3_check.c

static int r600_packet3_check(struct radeon_cs_parser *p,
				struct radeon_cs_packet *pkt)
{
	struct radeon_cs_reloc *reloc;
	struct r600_cs_track *track;
	volatile u32 *ib;
	unsigned idx;
	unsigned i;
	unsigned start_reg, end_reg, reg;
	int r;
	u32 idx_value;

	track = (struct r600_cs_track *)p->track;
	ib = p->ib->ptr;
	idx = pkt->idx + 1;
	idx_value = radeon_get_ib_value(p, idx);

	switch (pkt->opcode) {
	case PACKET3_START_3D_CMDBUF:
		if (p->family >= CHIP_RV770 || pkt->count) {
			DRM_ERROR("bad START_3D\n");
			return -EINVAL;
		}
		break;
	case PACKET3_CONTEXT_CONTROL:
		if (pkt->count != 1) {
			DRM_ERROR("bad CONTEXT_CONTROL\n");
			return -EINVAL;
		}
		break;
	case PACKET3_INDEX_TYPE:
	case PACKET3_NUM_INSTANCES:
		if (pkt->count) {
			DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n");
			return -EINVAL;
		}
		break;
	case PACKET3_DRAW_INDEX:
		if (pkt->count != 3) {
			DRM_ERROR("bad DRAW_INDEX\n");
			return -EINVAL;
		}
		r = r600_cs_packet_next_reloc(p, &reloc);
		if (r) {
			DRM_ERROR("bad DRAW_INDEX\n");
			return -EINVAL;
		}
		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
		ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
		break;
	case PACKET3_DRAW_INDEX_AUTO:
		if (pkt->count != 1) {
			DRM_ERROR("bad DRAW_INDEX_AUTO\n");
			return -EINVAL;
		}
		break;
	case PACKET3_DRAW_INDEX_IMMD_BE:
	case PACKET3_DRAW_INDEX_IMMD:
		if (pkt->count < 2) {
			DRM_ERROR("bad DRAW_INDEX_IMMD\n");
			return -EINVAL;
		}
		break;
	case PACKET3_WAIT_REG_MEM:
		if (pkt->count != 5) {
			DRM_ERROR("bad WAIT_REG_MEM\n");
			return -EINVAL;
		}
		/* bit 4 is reg (0) or mem (1) */
		if (idx_value & 0x10) {
			r = r600_cs_packet_next_reloc(p, &reloc);
			if (r) {
				DRM_ERROR("bad WAIT_REG_MEM\n");
				return -EINVAL;
			}
			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
		}
		break;
	case PACKET3_SURFACE_SYNC:
		if (pkt->count != 3) {
			DRM_ERROR("bad SURFACE_SYNC\n");
			return -EINVAL;
		}
		/* 0xffffffff/0x0 is flush all cache flag */
		if (radeon_get_ib_value(p, idx + 1) != 0xffffffff ||
		    radeon_get_ib_value(p, idx + 2) != 0) {
			r = r600_cs_packet_next_reloc(p, &reloc);
			if (r) {
				DRM_ERROR("bad SURFACE_SYNC\n");
				return -EINVAL;
			}
			ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
		}
		break;
	case PACKET3_EVENT_WRITE:
		if (pkt->count != 2 && pkt->count != 0) {
			DRM_ERROR("bad EVENT_WRITE\n");
			return -EINVAL;
		}
		if (pkt->count) {
			r = r600_cs_packet_next_reloc(p, &reloc);
			if (r) {
				DRM_ERROR("bad EVENT_WRITE\n");
				return -EINVAL;
			}
			ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
			ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
		}
		break;
	case PACKET3_EVENT_WRITE_EOP:
		if (pkt->count != 4) {
			DRM_ERROR("bad EVENT_WRITE_EOP\n");
			return -EINVAL;
		}
		r = r600_cs_packet_next_reloc(p, &reloc);
		if (r) {
			DRM_ERROR("bad EVENT_WRITE\n");
			return -EINVAL;
		}
		ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
		ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
		break;
	case PACKET3_SET_CONFIG_REG:
		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_CONFIG_REG_OFFSET) ||
		    (start_reg >= PACKET3_SET_CONFIG_REG_END) ||
		    (end_reg >= PACKET3_SET_CONFIG_REG_END)) {
			DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n");
			return -EINVAL;
		}
		for (i = 0; i < pkt->count; i++) {
			reg = start_reg + (4 * i);
			switch (reg) {
			case SQ_ESGS_RING_BASE:
			case SQ_GSVS_RING_BASE:
			case SQ_ESTMP_RING_BASE:
			case SQ_GSTMP_RING_BASE:
			case SQ_VSTMP_RING_BASE:
			case SQ_PSTMP_RING_BASE:
			case SQ_FBUF_RING_BASE:
			case SQ_REDUC_RING_BASE:
			case SX_MEMORY_EXPORT_BASE:
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_CONFIG_REG "
							"0x%04X\n", reg);
					return -EINVAL;
				}
				ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				break;
			case CP_COHER_BASE:
				/* use PACKET3_SURFACE_SYNC */
				return -EINVAL;
			default:
				break;
			}
		}
		break;
	case PACKET3_SET_CONTEXT_REG:
		start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_CONTEXT_REG_OFFSET) ||
		    (start_reg >= PACKET3_SET_CONTEXT_REG_END) ||
		    (end_reg >= PACKET3_SET_CONTEXT_REG_END)) {
			DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n");
			return -EINVAL;
		}
		for (i = 0; i < pkt->count; i++) {
			reg = start_reg + (4 * i);
			switch (reg) {
			/* This register were added late, there is userspace
			 * which does provide relocation for those but set
			 * 0 offset. In order to avoid breaking old userspace
			 * we detect this and set address to point to last
			 * CB_COLOR0_BASE, note that if userspace doesn't set
			 * CB_COLOR0_BASE before this register we will report
			 * error. Old userspace always set CB_COLOR0_BASE
			 * before any of this.
			 */
			case R_0280E0_CB_COLOR0_FRAG:
			case R_0280E4_CB_COLOR1_FRAG:
			case R_0280E8_CB_COLOR2_FRAG:
			case R_0280EC_CB_COLOR3_FRAG:
			case R_0280F0_CB_COLOR4_FRAG:
			case R_0280F4_CB_COLOR5_FRAG:
			case R_0280F8_CB_COLOR6_FRAG:
			case R_0280FC_CB_COLOR7_FRAG:
			case R_0280C0_CB_COLOR0_TILE:
			case R_0280C4_CB_COLOR1_TILE:
			case R_0280C8_CB_COLOR2_TILE:
			case R_0280CC_CB_COLOR3_TILE:
			case R_0280D0_CB_COLOR4_TILE:
			case R_0280D4_CB_COLOR5_TILE:
			case R_0280D8_CB_COLOR6_TILE:
			case R_0280DC_CB_COLOR7_TILE:
				if (!r600_cs_packet_next_is_pkt3_nop(p)) {
					if (!track->cb_color0_base_last) {
						dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
						return -EINVAL;
					}
					ib[idx+1+i] = track->cb_color0_base_last;
					printk_once(KERN_WARNING "radeon: You have old & broken userspace "
						"please consider updating mesa & xf86-video-ati\n");
				} else {
					r = r600_cs_packet_next_reloc(p, &reloc);
					if (r) {
						dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
						return -EINVAL;
					}
					ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				}
				break;
			case DB_DEPTH_BASE:
			case DB_HTILE_DATA_BASE:
			case CB_COLOR0_BASE:
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_CONTEXT_REG "
							"0x%04X\n", reg);
					return -EINVAL;
				}
				ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				track->cb_color0_base_last = ib[idx+1+i];
				break;
			case CB_COLOR1_BASE:
			case CB_COLOR2_BASE:
			case CB_COLOR3_BASE:
			case CB_COLOR4_BASE:
			case CB_COLOR5_BASE:
			case CB_COLOR6_BASE:
			case CB_COLOR7_BASE:
			case SQ_PGM_START_FS:
			case SQ_PGM_START_ES:
			case SQ_PGM_START_VS:
			case SQ_PGM_START_GS:
			case SQ_PGM_START_PS:
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_CONTEXT_REG "
							"0x%04X\n", reg);
					return -EINVAL;
				}
				ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				break;
			case VGT_DMA_BASE:
			case VGT_DMA_BASE_HI:
				/* These should be handled by DRAW_INDEX packet 3 */
			case VGT_STRMOUT_BASE_OFFSET_0:
			case VGT_STRMOUT_BASE_OFFSET_1:
			case VGT_STRMOUT_BASE_OFFSET_2:
			case VGT_STRMOUT_BASE_OFFSET_3:
			case VGT_STRMOUT_BASE_OFFSET_HI_0:
			case VGT_STRMOUT_BASE_OFFSET_HI_1:
			case VGT_STRMOUT_BASE_OFFSET_HI_2:
			case VGT_STRMOUT_BASE_OFFSET_HI_3:
			case VGT_STRMOUT_BUFFER_BASE_0:
			case VGT_STRMOUT_BUFFER_BASE_1:
			case VGT_STRMOUT_BUFFER_BASE_2:
			case VGT_STRMOUT_BUFFER_BASE_3:
			case VGT_STRMOUT_BUFFER_OFFSET_0:
			case VGT_STRMOUT_BUFFER_OFFSET_1:
			case VGT_STRMOUT_BUFFER_OFFSET_2:
			case VGT_STRMOUT_BUFFER_OFFSET_3:
				/* These should be handled by STRMOUT_BUFFER packet 3 */
				DRM_ERROR("bad context reg: 0x%08x\n", reg);
				return -EINVAL;
			default:
				break;
			}
		}
		break;
	case PACKET3_SET_RESOURCE:
		if (pkt->count % 7) {
			DRM_ERROR("bad SET_RESOURCE\n");
			return -EINVAL;
		}
		start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_RESOURCE_OFFSET) ||
		    (start_reg >= PACKET3_SET_RESOURCE_END) ||
		    (end_reg >= PACKET3_SET_RESOURCE_END)) {
			DRM_ERROR("bad SET_RESOURCE\n");
			return -EINVAL;
		}
		for (i = 0; i < (pkt->count / 7); i++) {
			switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
			case SQ_TEX_VTX_VALID_TEXTURE:
				/* tex base */
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_RESOURCE\n");
					return -EINVAL;
				}
				ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				/* tex mip base */
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_RESOURCE\n");
					return -EINVAL;
				}
				ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
				break;
			case SQ_TEX_VTX_VALID_BUFFER:
				/* vtx base */
				r = r600_cs_packet_next_reloc(p, &reloc);
				if (r) {
					DRM_ERROR("bad SET_RESOURCE\n");
					return -EINVAL;
				}
				ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
				ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
				break;
			case SQ_TEX_VTX_INVALID_TEXTURE:
			case SQ_TEX_VTX_INVALID_BUFFER:
			default:
				DRM_ERROR("bad SET_RESOURCE\n");
				return -EINVAL;
			}
		}
		break;
	case PACKET3_SET_ALU_CONST:
		start_reg = (idx_value << 2) + PACKET3_SET_ALU_CONST_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_ALU_CONST_OFFSET) ||
		    (start_reg >= PACKET3_SET_ALU_CONST_END) ||
		    (end_reg >= PACKET3_SET_ALU_CONST_END)) {
			DRM_ERROR("bad SET_ALU_CONST\n");
			return -EINVAL;
		}
		break;
	case PACKET3_SET_BOOL_CONST:
		start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_BOOL_CONST_OFFSET) ||
		    (start_reg >= PACKET3_SET_BOOL_CONST_END) ||
		    (end_reg >= PACKET3_SET_BOOL_CONST_END)) {
			DRM_ERROR("bad SET_BOOL_CONST\n");
			return -EINVAL;
		}
		break;
	case PACKET3_SET_LOOP_CONST:
		start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_LOOP_CONST_OFFSET) ||
		    (start_reg >= PACKET3_SET_LOOP_CONST_END) ||
		    (end_reg >= PACKET3_SET_LOOP_CONST_END)) {
			DRM_ERROR("bad SET_LOOP_CONST\n");
			return -EINVAL;
		}
		break;
	case PACKET3_SET_CTL_CONST:
		start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_CTL_CONST_OFFSET) ||
		    (start_reg >= PACKET3_SET_CTL_CONST_END) ||
		    (end_reg >= PACKET3_SET_CTL_CONST_END)) {
			DRM_ERROR("bad SET_CTL_CONST\n");
			return -EINVAL;
		}
		break;
	case PACKET3_SET_SAMPLER:
		if (pkt->count % 3) {
			DRM_ERROR("bad SET_SAMPLER\n");
			return -EINVAL;
		}
		start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_OFFSET;
		end_reg = 4 * pkt->count + start_reg - 4;
		if ((start_reg < PACKET3_SET_SAMPLER_OFFSET) ||
		    (start_reg >= PACKET3_SET_SAMPLER_END) ||
		    (end_reg >= PACKET3_SET_SAMPLER_END)) {
			DRM_ERROR("bad SET_SAMPLER\n");
			return -EINVAL;
		}
		break;
	case PACKET3_SURFACE_BASE_UPDATE:
		if (p->family >= CHIP_RV770 || p->family == CHIP_R600) {
			DRM_ERROR("bad SURFACE_BASE_UPDATE\n");
			return -EINVAL;
		}
		if (pkt->count) {
			DRM_ERROR("bad SURFACE_BASE_UPDATE\n");
			return -EINVAL;
		}
		break;
	case PACKET3_NOP:
		break;
	default:
		DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode);
		return -EINVAL;
	}
	return 0;
}

Generated by GNU enscript 1.6.4.