18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2004 The Unichrome Project. All Rights Reserved.
38c2ecf20Sopenharmony_ci * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license,
98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
138c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
148c2ecf20Sopenharmony_ci * of the Software.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
198c2ecf20Sopenharmony_ci * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
228c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Author: Thomas Hellstrom 2004, 2005.
258c2ecf20Sopenharmony_ci * This code was written using docs obtained under NDA from VIA Inc.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * Don't run this code directly on an AGP buffer. Due to cache problems it will
288c2ecf20Sopenharmony_ci * be very slow.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <drm/drm_device.h>
328c2ecf20Sopenharmony_ci#include <drm/drm_legacy.h>
338c2ecf20Sopenharmony_ci#include <drm/via_drm.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "via_3d_reg.h"
368c2ecf20Sopenharmony_ci#include "via_drv.h"
378c2ecf20Sopenharmony_ci#include "via_verifier.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_citypedef enum {
408c2ecf20Sopenharmony_ci	state_command,
418c2ecf20Sopenharmony_ci	state_header2,
428c2ecf20Sopenharmony_ci	state_header1,
438c2ecf20Sopenharmony_ci	state_vheader5,
448c2ecf20Sopenharmony_ci	state_vheader6,
458c2ecf20Sopenharmony_ci	state_error
468c2ecf20Sopenharmony_ci} verifier_state_t;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_citypedef enum {
498c2ecf20Sopenharmony_ci	no_check = 0,
508c2ecf20Sopenharmony_ci	check_for_header2,
518c2ecf20Sopenharmony_ci	check_for_header1,
528c2ecf20Sopenharmony_ci	check_for_header2_err,
538c2ecf20Sopenharmony_ci	check_for_header1_err,
548c2ecf20Sopenharmony_ci	check_for_fire,
558c2ecf20Sopenharmony_ci	check_z_buffer_addr0,
568c2ecf20Sopenharmony_ci	check_z_buffer_addr1,
578c2ecf20Sopenharmony_ci	check_z_buffer_addr_mode,
588c2ecf20Sopenharmony_ci	check_destination_addr0,
598c2ecf20Sopenharmony_ci	check_destination_addr1,
608c2ecf20Sopenharmony_ci	check_destination_addr_mode,
618c2ecf20Sopenharmony_ci	check_for_dummy,
628c2ecf20Sopenharmony_ci	check_for_dd,
638c2ecf20Sopenharmony_ci	check_texture_addr0,
648c2ecf20Sopenharmony_ci	check_texture_addr1,
658c2ecf20Sopenharmony_ci	check_texture_addr2,
668c2ecf20Sopenharmony_ci	check_texture_addr3,
678c2ecf20Sopenharmony_ci	check_texture_addr4,
688c2ecf20Sopenharmony_ci	check_texture_addr5,
698c2ecf20Sopenharmony_ci	check_texture_addr6,
708c2ecf20Sopenharmony_ci	check_texture_addr7,
718c2ecf20Sopenharmony_ci	check_texture_addr8,
728c2ecf20Sopenharmony_ci	check_texture_addr_mode,
738c2ecf20Sopenharmony_ci	check_for_vertex_count,
748c2ecf20Sopenharmony_ci	check_number_texunits,
758c2ecf20Sopenharmony_ci	forbidden_command
768c2ecf20Sopenharmony_ci} hazard_t;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/*
798c2ecf20Sopenharmony_ci * Associates each hazard above with a possible multi-command
808c2ecf20Sopenharmony_ci * sequence. For example an address that is split over multiple
818c2ecf20Sopenharmony_ci * commands and that needs to be checked at the first command
828c2ecf20Sopenharmony_ci * that does not include any part of the address.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic drm_via_sequence_t seqs[] = {
868c2ecf20Sopenharmony_ci	no_sequence,
878c2ecf20Sopenharmony_ci	no_sequence,
888c2ecf20Sopenharmony_ci	no_sequence,
898c2ecf20Sopenharmony_ci	no_sequence,
908c2ecf20Sopenharmony_ci	no_sequence,
918c2ecf20Sopenharmony_ci	no_sequence,
928c2ecf20Sopenharmony_ci	z_address,
938c2ecf20Sopenharmony_ci	z_address,
948c2ecf20Sopenharmony_ci	z_address,
958c2ecf20Sopenharmony_ci	dest_address,
968c2ecf20Sopenharmony_ci	dest_address,
978c2ecf20Sopenharmony_ci	dest_address,
988c2ecf20Sopenharmony_ci	no_sequence,
998c2ecf20Sopenharmony_ci	no_sequence,
1008c2ecf20Sopenharmony_ci	tex_address,
1018c2ecf20Sopenharmony_ci	tex_address,
1028c2ecf20Sopenharmony_ci	tex_address,
1038c2ecf20Sopenharmony_ci	tex_address,
1048c2ecf20Sopenharmony_ci	tex_address,
1058c2ecf20Sopenharmony_ci	tex_address,
1068c2ecf20Sopenharmony_ci	tex_address,
1078c2ecf20Sopenharmony_ci	tex_address,
1088c2ecf20Sopenharmony_ci	tex_address,
1098c2ecf20Sopenharmony_ci	tex_address,
1108c2ecf20Sopenharmony_ci	no_sequence
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_citypedef struct {
1148c2ecf20Sopenharmony_ci	unsigned int code;
1158c2ecf20Sopenharmony_ci	hazard_t hz;
1168c2ecf20Sopenharmony_ci} hz_init_t;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic hz_init_t init_table1[] = {
1198c2ecf20Sopenharmony_ci	{0xf2, check_for_header2_err},
1208c2ecf20Sopenharmony_ci	{0xf0, check_for_header1_err},
1218c2ecf20Sopenharmony_ci	{0xee, check_for_fire},
1228c2ecf20Sopenharmony_ci	{0xcc, check_for_dummy},
1238c2ecf20Sopenharmony_ci	{0xdd, check_for_dd},
1248c2ecf20Sopenharmony_ci	{0x00, no_check},
1258c2ecf20Sopenharmony_ci	{0x10, check_z_buffer_addr0},
1268c2ecf20Sopenharmony_ci	{0x11, check_z_buffer_addr1},
1278c2ecf20Sopenharmony_ci	{0x12, check_z_buffer_addr_mode},
1288c2ecf20Sopenharmony_ci	{0x13, no_check},
1298c2ecf20Sopenharmony_ci	{0x14, no_check},
1308c2ecf20Sopenharmony_ci	{0x15, no_check},
1318c2ecf20Sopenharmony_ci	{0x23, no_check},
1328c2ecf20Sopenharmony_ci	{0x24, no_check},
1338c2ecf20Sopenharmony_ci	{0x33, no_check},
1348c2ecf20Sopenharmony_ci	{0x34, no_check},
1358c2ecf20Sopenharmony_ci	{0x35, no_check},
1368c2ecf20Sopenharmony_ci	{0x36, no_check},
1378c2ecf20Sopenharmony_ci	{0x37, no_check},
1388c2ecf20Sopenharmony_ci	{0x38, no_check},
1398c2ecf20Sopenharmony_ci	{0x39, no_check},
1408c2ecf20Sopenharmony_ci	{0x3A, no_check},
1418c2ecf20Sopenharmony_ci	{0x3B, no_check},
1428c2ecf20Sopenharmony_ci	{0x3C, no_check},
1438c2ecf20Sopenharmony_ci	{0x3D, no_check},
1448c2ecf20Sopenharmony_ci	{0x3E, no_check},
1458c2ecf20Sopenharmony_ci	{0x40, check_destination_addr0},
1468c2ecf20Sopenharmony_ci	{0x41, check_destination_addr1},
1478c2ecf20Sopenharmony_ci	{0x42, check_destination_addr_mode},
1488c2ecf20Sopenharmony_ci	{0x43, no_check},
1498c2ecf20Sopenharmony_ci	{0x44, no_check},
1508c2ecf20Sopenharmony_ci	{0x50, no_check},
1518c2ecf20Sopenharmony_ci	{0x51, no_check},
1528c2ecf20Sopenharmony_ci	{0x52, no_check},
1538c2ecf20Sopenharmony_ci	{0x53, no_check},
1548c2ecf20Sopenharmony_ci	{0x54, no_check},
1558c2ecf20Sopenharmony_ci	{0x55, no_check},
1568c2ecf20Sopenharmony_ci	{0x56, no_check},
1578c2ecf20Sopenharmony_ci	{0x57, no_check},
1588c2ecf20Sopenharmony_ci	{0x58, no_check},
1598c2ecf20Sopenharmony_ci	{0x70, no_check},
1608c2ecf20Sopenharmony_ci	{0x71, no_check},
1618c2ecf20Sopenharmony_ci	{0x78, no_check},
1628c2ecf20Sopenharmony_ci	{0x79, no_check},
1638c2ecf20Sopenharmony_ci	{0x7A, no_check},
1648c2ecf20Sopenharmony_ci	{0x7B, no_check},
1658c2ecf20Sopenharmony_ci	{0x7C, no_check},
1668c2ecf20Sopenharmony_ci	{0x7D, check_for_vertex_count}
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic hz_init_t init_table2[] = {
1708c2ecf20Sopenharmony_ci	{0xf2, check_for_header2_err},
1718c2ecf20Sopenharmony_ci	{0xf0, check_for_header1_err},
1728c2ecf20Sopenharmony_ci	{0xee, check_for_fire},
1738c2ecf20Sopenharmony_ci	{0xcc, check_for_dummy},
1748c2ecf20Sopenharmony_ci	{0x00, check_texture_addr0},
1758c2ecf20Sopenharmony_ci	{0x01, check_texture_addr0},
1768c2ecf20Sopenharmony_ci	{0x02, check_texture_addr0},
1778c2ecf20Sopenharmony_ci	{0x03, check_texture_addr0},
1788c2ecf20Sopenharmony_ci	{0x04, check_texture_addr0},
1798c2ecf20Sopenharmony_ci	{0x05, check_texture_addr0},
1808c2ecf20Sopenharmony_ci	{0x06, check_texture_addr0},
1818c2ecf20Sopenharmony_ci	{0x07, check_texture_addr0},
1828c2ecf20Sopenharmony_ci	{0x08, check_texture_addr0},
1838c2ecf20Sopenharmony_ci	{0x09, check_texture_addr0},
1848c2ecf20Sopenharmony_ci	{0x20, check_texture_addr1},
1858c2ecf20Sopenharmony_ci	{0x21, check_texture_addr1},
1868c2ecf20Sopenharmony_ci	{0x22, check_texture_addr1},
1878c2ecf20Sopenharmony_ci	{0x23, check_texture_addr4},
1888c2ecf20Sopenharmony_ci	{0x2B, check_texture_addr3},
1898c2ecf20Sopenharmony_ci	{0x2C, check_texture_addr3},
1908c2ecf20Sopenharmony_ci	{0x2D, check_texture_addr3},
1918c2ecf20Sopenharmony_ci	{0x2E, check_texture_addr3},
1928c2ecf20Sopenharmony_ci	{0x2F, check_texture_addr3},
1938c2ecf20Sopenharmony_ci	{0x30, check_texture_addr3},
1948c2ecf20Sopenharmony_ci	{0x31, check_texture_addr3},
1958c2ecf20Sopenharmony_ci	{0x32, check_texture_addr3},
1968c2ecf20Sopenharmony_ci	{0x33, check_texture_addr3},
1978c2ecf20Sopenharmony_ci	{0x34, check_texture_addr3},
1988c2ecf20Sopenharmony_ci	{0x4B, check_texture_addr5},
1998c2ecf20Sopenharmony_ci	{0x4C, check_texture_addr6},
2008c2ecf20Sopenharmony_ci	{0x51, check_texture_addr7},
2018c2ecf20Sopenharmony_ci	{0x52, check_texture_addr8},
2028c2ecf20Sopenharmony_ci	{0x77, check_texture_addr2},
2038c2ecf20Sopenharmony_ci	{0x78, no_check},
2048c2ecf20Sopenharmony_ci	{0x79, no_check},
2058c2ecf20Sopenharmony_ci	{0x7A, no_check},
2068c2ecf20Sopenharmony_ci	{0x7B, check_texture_addr_mode},
2078c2ecf20Sopenharmony_ci	{0x7C, no_check},
2088c2ecf20Sopenharmony_ci	{0x7D, no_check},
2098c2ecf20Sopenharmony_ci	{0x7E, no_check},
2108c2ecf20Sopenharmony_ci	{0x7F, no_check},
2118c2ecf20Sopenharmony_ci	{0x80, no_check},
2128c2ecf20Sopenharmony_ci	{0x81, no_check},
2138c2ecf20Sopenharmony_ci	{0x82, no_check},
2148c2ecf20Sopenharmony_ci	{0x83, no_check},
2158c2ecf20Sopenharmony_ci	{0x85, no_check},
2168c2ecf20Sopenharmony_ci	{0x86, no_check},
2178c2ecf20Sopenharmony_ci	{0x87, no_check},
2188c2ecf20Sopenharmony_ci	{0x88, no_check},
2198c2ecf20Sopenharmony_ci	{0x89, no_check},
2208c2ecf20Sopenharmony_ci	{0x8A, no_check},
2218c2ecf20Sopenharmony_ci	{0x90, no_check},
2228c2ecf20Sopenharmony_ci	{0x91, no_check},
2238c2ecf20Sopenharmony_ci	{0x92, no_check},
2248c2ecf20Sopenharmony_ci	{0x93, no_check}
2258c2ecf20Sopenharmony_ci};
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic hz_init_t init_table3[] = {
2288c2ecf20Sopenharmony_ci	{0xf2, check_for_header2_err},
2298c2ecf20Sopenharmony_ci	{0xf0, check_for_header1_err},
2308c2ecf20Sopenharmony_ci	{0xcc, check_for_dummy},
2318c2ecf20Sopenharmony_ci	{0x00, check_number_texunits}
2328c2ecf20Sopenharmony_ci};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic hazard_t table1[256];
2358c2ecf20Sopenharmony_cistatic hazard_t table2[256];
2368c2ecf20Sopenharmony_cistatic hazard_t table3[256];
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic __inline__ int
2398c2ecf20Sopenharmony_cieat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	if ((buf_end - *buf) >= num_words) {
2428c2ecf20Sopenharmony_ci		*buf += num_words;
2438c2ecf20Sopenharmony_ci		return 0;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	DRM_ERROR("Illegal termination of DMA command buffer\n");
2468c2ecf20Sopenharmony_ci	return 1;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/*
2508c2ecf20Sopenharmony_ci * Partially stolen from drm_memory.h
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
2548c2ecf20Sopenharmony_ci						    unsigned long offset,
2558c2ecf20Sopenharmony_ci						    unsigned long size,
2568c2ecf20Sopenharmony_ci						    struct drm_device *dev)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct drm_map_list *r_list;
2598c2ecf20Sopenharmony_ci	drm_local_map_t *map = seq->map_cache;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (map && map->offset <= offset
2628c2ecf20Sopenharmony_ci	    && (offset + size) <= (map->offset + map->size)) {
2638c2ecf20Sopenharmony_ci		return map;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	list_for_each_entry(r_list, &dev->maplist, head) {
2678c2ecf20Sopenharmony_ci		map = r_list->map;
2688c2ecf20Sopenharmony_ci		if (!map)
2698c2ecf20Sopenharmony_ci			continue;
2708c2ecf20Sopenharmony_ci		if (map->offset <= offset
2718c2ecf20Sopenharmony_ci		    && (offset + size) <= (map->offset + map->size)
2728c2ecf20Sopenharmony_ci		    && !(map->flags & _DRM_RESTRICTED)
2738c2ecf20Sopenharmony_ci		    && (map->type == _DRM_AGP)) {
2748c2ecf20Sopenharmony_ci			seq->map_cache = map;
2758c2ecf20Sopenharmony_ci			return map;
2768c2ecf20Sopenharmony_ci		}
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci	return NULL;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/*
2828c2ecf20Sopenharmony_ci * Require that all AGP texture levels reside in the same AGP map which should
2838c2ecf20Sopenharmony_ci * be mappable by the client. This is not a big restriction.
2848c2ecf20Sopenharmony_ci * FIXME: To actually enforce this security policy strictly, drm_rmmap
2858c2ecf20Sopenharmony_ci * would have to wait for dma quiescent before removing an AGP map.
2868c2ecf20Sopenharmony_ci * The via_drm_lookup_agp_map call in reality seems to take
2878c2ecf20Sopenharmony_ci * very little CPU time.
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	switch (cur_seq->unfinished) {
2938c2ecf20Sopenharmony_ci	case z_address:
2948c2ecf20Sopenharmony_ci		DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
2958c2ecf20Sopenharmony_ci		break;
2968c2ecf20Sopenharmony_ci	case dest_address:
2978c2ecf20Sopenharmony_ci		DRM_DEBUG("Destination start address is 0x%x\n",
2988c2ecf20Sopenharmony_ci			  cur_seq->d_addr);
2998c2ecf20Sopenharmony_ci		break;
3008c2ecf20Sopenharmony_ci	case tex_address:
3018c2ecf20Sopenharmony_ci		if (cur_seq->agp_texture) {
3028c2ecf20Sopenharmony_ci			unsigned start =
3038c2ecf20Sopenharmony_ci			    cur_seq->tex_level_lo[cur_seq->texture];
3048c2ecf20Sopenharmony_ci			unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
3058c2ecf20Sopenharmony_ci			unsigned long lo = ~0, hi = 0, tmp;
3068c2ecf20Sopenharmony_ci			uint32_t *addr, *pitch, *height, tex;
3078c2ecf20Sopenharmony_ci			unsigned i;
3088c2ecf20Sopenharmony_ci			int npot;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci			if (end > 9)
3118c2ecf20Sopenharmony_ci				end = 9;
3128c2ecf20Sopenharmony_ci			if (start > 9)
3138c2ecf20Sopenharmony_ci				start = 9;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci			addr =
3168c2ecf20Sopenharmony_ci			    &(cur_seq->t_addr[tex = cur_seq->texture][start]);
3178c2ecf20Sopenharmony_ci			pitch = &(cur_seq->pitch[tex][start]);
3188c2ecf20Sopenharmony_ci			height = &(cur_seq->height[tex][start]);
3198c2ecf20Sopenharmony_ci			npot = cur_seq->tex_npot[tex];
3208c2ecf20Sopenharmony_ci			for (i = start; i <= end; ++i) {
3218c2ecf20Sopenharmony_ci				tmp = *addr++;
3228c2ecf20Sopenharmony_ci				if (tmp < lo)
3238c2ecf20Sopenharmony_ci					lo = tmp;
3248c2ecf20Sopenharmony_ci				if (i == 0 && npot)
3258c2ecf20Sopenharmony_ci					tmp += (*height++ * *pitch++);
3268c2ecf20Sopenharmony_ci				else
3278c2ecf20Sopenharmony_ci					tmp += (*height++ << *pitch++);
3288c2ecf20Sopenharmony_ci				if (tmp > hi)
3298c2ecf20Sopenharmony_ci					hi = tmp;
3308c2ecf20Sopenharmony_ci			}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci			if (!via_drm_lookup_agp_map
3338c2ecf20Sopenharmony_ci			    (cur_seq, lo, hi - lo, cur_seq->dev)) {
3348c2ecf20Sopenharmony_ci				DRM_ERROR
3358c2ecf20Sopenharmony_ci				    ("AGP texture is not in allowed map\n");
3368c2ecf20Sopenharmony_ci				return 2;
3378c2ecf20Sopenharmony_ci			}
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		break;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci	cur_seq->unfinished = no_sequence;
3448c2ecf20Sopenharmony_ci	return 0;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic __inline__ int
3488c2ecf20Sopenharmony_ciinvestigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	register uint32_t tmp, *tmp_addr;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
3538c2ecf20Sopenharmony_ci		int ret;
3548c2ecf20Sopenharmony_ci		if ((ret = finish_current_sequence(cur_seq)))
3558c2ecf20Sopenharmony_ci			return ret;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	switch (hz) {
3598c2ecf20Sopenharmony_ci	case check_for_header2:
3608c2ecf20Sopenharmony_ci		if (cmd == HALCYON_HEADER2)
3618c2ecf20Sopenharmony_ci			return 1;
3628c2ecf20Sopenharmony_ci		return 0;
3638c2ecf20Sopenharmony_ci	case check_for_header1:
3648c2ecf20Sopenharmony_ci		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
3658c2ecf20Sopenharmony_ci			return 1;
3668c2ecf20Sopenharmony_ci		return 0;
3678c2ecf20Sopenharmony_ci	case check_for_header2_err:
3688c2ecf20Sopenharmony_ci		if (cmd == HALCYON_HEADER2)
3698c2ecf20Sopenharmony_ci			return 1;
3708c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	case check_for_header1_err:
3738c2ecf20Sopenharmony_ci		if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
3748c2ecf20Sopenharmony_ci			return 1;
3758c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case check_for_fire:
3788c2ecf20Sopenharmony_ci		if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD)
3798c2ecf20Sopenharmony_ci			return 1;
3808c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	case check_for_dummy:
3838c2ecf20Sopenharmony_ci		if (HC_DUMMY == cmd)
3848c2ecf20Sopenharmony_ci			return 0;
3858c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA HC_DUMMY command\n");
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	case check_for_dd:
3888c2ecf20Sopenharmony_ci		if (0xdddddddd == cmd)
3898c2ecf20Sopenharmony_ci			return 0;
3908c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA 0xdddddddd command\n");
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	case check_z_buffer_addr0:
3938c2ecf20Sopenharmony_ci		cur_seq->unfinished = z_address;
3948c2ecf20Sopenharmony_ci		cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
3958c2ecf20Sopenharmony_ci		    (cmd & 0x00FFFFFF);
3968c2ecf20Sopenharmony_ci		return 0;
3978c2ecf20Sopenharmony_ci	case check_z_buffer_addr1:
3988c2ecf20Sopenharmony_ci		cur_seq->unfinished = z_address;
3998c2ecf20Sopenharmony_ci		cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
4008c2ecf20Sopenharmony_ci		    ((cmd & 0xFF) << 24);
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci	case check_z_buffer_addr_mode:
4038c2ecf20Sopenharmony_ci		cur_seq->unfinished = z_address;
4048c2ecf20Sopenharmony_ci		if ((cmd & 0x0000C000) == 0)
4058c2ecf20Sopenharmony_ci			return 0;
4068c2ecf20Sopenharmony_ci		DRM_ERROR("Attempt to place Z buffer in system memory\n");
4078c2ecf20Sopenharmony_ci		return 2;
4088c2ecf20Sopenharmony_ci	case check_destination_addr0:
4098c2ecf20Sopenharmony_ci		cur_seq->unfinished = dest_address;
4108c2ecf20Sopenharmony_ci		cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
4118c2ecf20Sopenharmony_ci		    (cmd & 0x00FFFFFF);
4128c2ecf20Sopenharmony_ci		return 0;
4138c2ecf20Sopenharmony_ci	case check_destination_addr1:
4148c2ecf20Sopenharmony_ci		cur_seq->unfinished = dest_address;
4158c2ecf20Sopenharmony_ci		cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
4168c2ecf20Sopenharmony_ci		    ((cmd & 0xFF) << 24);
4178c2ecf20Sopenharmony_ci		return 0;
4188c2ecf20Sopenharmony_ci	case check_destination_addr_mode:
4198c2ecf20Sopenharmony_ci		cur_seq->unfinished = dest_address;
4208c2ecf20Sopenharmony_ci		if ((cmd & 0x0000C000) == 0)
4218c2ecf20Sopenharmony_ci			return 0;
4228c2ecf20Sopenharmony_ci		DRM_ERROR
4238c2ecf20Sopenharmony_ci		    ("Attempt to place 3D drawing buffer in system memory\n");
4248c2ecf20Sopenharmony_ci		return 2;
4258c2ecf20Sopenharmony_ci	case check_texture_addr0:
4268c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4278c2ecf20Sopenharmony_ci		tmp = (cmd >> 24);
4288c2ecf20Sopenharmony_ci		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
4298c2ecf20Sopenharmony_ci		*tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
4308c2ecf20Sopenharmony_ci		return 0;
4318c2ecf20Sopenharmony_ci	case check_texture_addr1:
4328c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4338c2ecf20Sopenharmony_ci		tmp = ((cmd >> 24) - 0x20);
4348c2ecf20Sopenharmony_ci		tmp += tmp << 1;
4358c2ecf20Sopenharmony_ci		tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
4368c2ecf20Sopenharmony_ci		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
4378c2ecf20Sopenharmony_ci		tmp_addr++;
4388c2ecf20Sopenharmony_ci		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
4398c2ecf20Sopenharmony_ci		tmp_addr++;
4408c2ecf20Sopenharmony_ci		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
4418c2ecf20Sopenharmony_ci		return 0;
4428c2ecf20Sopenharmony_ci	case check_texture_addr2:
4438c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4448c2ecf20Sopenharmony_ci		cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
4458c2ecf20Sopenharmony_ci		cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
4468c2ecf20Sopenharmony_ci		return 0;
4478c2ecf20Sopenharmony_ci	case check_texture_addr3:
4488c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4498c2ecf20Sopenharmony_ci		tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
4508c2ecf20Sopenharmony_ci		if (tmp == 0 &&
4518c2ecf20Sopenharmony_ci		    (cmd & HC_HTXnEnPit_MASK)) {
4528c2ecf20Sopenharmony_ci			cur_seq->pitch[cur_seq->texture][tmp] =
4538c2ecf20Sopenharmony_ci				(cmd & HC_HTXnLnPit_MASK);
4548c2ecf20Sopenharmony_ci			cur_seq->tex_npot[cur_seq->texture] = 1;
4558c2ecf20Sopenharmony_ci		} else {
4568c2ecf20Sopenharmony_ci			cur_seq->pitch[cur_seq->texture][tmp] =
4578c2ecf20Sopenharmony_ci				(cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
4588c2ecf20Sopenharmony_ci			cur_seq->tex_npot[cur_seq->texture] = 0;
4598c2ecf20Sopenharmony_ci			if (cmd & 0x000FFFFF) {
4608c2ecf20Sopenharmony_ci				DRM_ERROR
4618c2ecf20Sopenharmony_ci					("Unimplemented texture level 0 pitch mode.\n");
4628c2ecf20Sopenharmony_ci				return 2;
4638c2ecf20Sopenharmony_ci			}
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci		return 0;
4668c2ecf20Sopenharmony_ci	case check_texture_addr4:
4678c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4688c2ecf20Sopenharmony_ci		tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
4698c2ecf20Sopenharmony_ci		*tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
4708c2ecf20Sopenharmony_ci		return 0;
4718c2ecf20Sopenharmony_ci	case check_texture_addr5:
4728c2ecf20Sopenharmony_ci	case check_texture_addr6:
4738c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4748c2ecf20Sopenharmony_ci		/*
4758c2ecf20Sopenharmony_ci		 * Texture width. We don't care since we have the pitch.
4768c2ecf20Sopenharmony_ci		 */
4778c2ecf20Sopenharmony_ci		return 0;
4788c2ecf20Sopenharmony_ci	case check_texture_addr7:
4798c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4808c2ecf20Sopenharmony_ci		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
4818c2ecf20Sopenharmony_ci		tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
4828c2ecf20Sopenharmony_ci		tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
4838c2ecf20Sopenharmony_ci		tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
4848c2ecf20Sopenharmony_ci		tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
4858c2ecf20Sopenharmony_ci		tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
4868c2ecf20Sopenharmony_ci		tmp_addr[0] = 1 << (cmd & 0x0000000F);
4878c2ecf20Sopenharmony_ci		return 0;
4888c2ecf20Sopenharmony_ci	case check_texture_addr8:
4898c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4908c2ecf20Sopenharmony_ci		tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
4918c2ecf20Sopenharmony_ci		tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
4928c2ecf20Sopenharmony_ci		tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
4938c2ecf20Sopenharmony_ci		tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
4948c2ecf20Sopenharmony_ci		tmp_addr[6] = 1 << (cmd & 0x0000000F);
4958c2ecf20Sopenharmony_ci		return 0;
4968c2ecf20Sopenharmony_ci	case check_texture_addr_mode:
4978c2ecf20Sopenharmony_ci		cur_seq->unfinished = tex_address;
4988c2ecf20Sopenharmony_ci		if (2 == (tmp = cmd & 0x00000003)) {
4998c2ecf20Sopenharmony_ci			DRM_ERROR
5008c2ecf20Sopenharmony_ci			    ("Attempt to fetch texture from system memory.\n");
5018c2ecf20Sopenharmony_ci			return 2;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci		cur_seq->agp_texture = (tmp == 3);
5048c2ecf20Sopenharmony_ci		cur_seq->tex_palette_size[cur_seq->texture] =
5058c2ecf20Sopenharmony_ci		    (cmd >> 16) & 0x000000007;
5068c2ecf20Sopenharmony_ci		return 0;
5078c2ecf20Sopenharmony_ci	case check_for_vertex_count:
5088c2ecf20Sopenharmony_ci		cur_seq->vertex_count = cmd & 0x0000FFFF;
5098c2ecf20Sopenharmony_ci		return 0;
5108c2ecf20Sopenharmony_ci	case check_number_texunits:
5118c2ecf20Sopenharmony_ci		cur_seq->multitex = (cmd >> 3) & 1;
5128c2ecf20Sopenharmony_ci		return 0;
5138c2ecf20Sopenharmony_ci	default:
5148c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
5158c2ecf20Sopenharmony_ci		return 2;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	return 2;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic __inline__ int
5218c2ecf20Sopenharmony_civia_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
5228c2ecf20Sopenharmony_ci		    drm_via_state_t *cur_seq)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	drm_via_private_t *dev_priv =
5258c2ecf20Sopenharmony_ci	    (drm_via_private_t *) cur_seq->dev->dev_private;
5268c2ecf20Sopenharmony_ci	uint32_t a_fire, bcmd, dw_count;
5278c2ecf20Sopenharmony_ci	int ret = 0;
5288c2ecf20Sopenharmony_ci	int have_fire;
5298c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	while (buf < buf_end) {
5328c2ecf20Sopenharmony_ci		have_fire = 0;
5338c2ecf20Sopenharmony_ci		if ((buf_end - buf) < 2) {
5348c2ecf20Sopenharmony_ci			DRM_ERROR
5358c2ecf20Sopenharmony_ci			    ("Unexpected termination of primitive list.\n");
5368c2ecf20Sopenharmony_ci			ret = 1;
5378c2ecf20Sopenharmony_ci			break;
5388c2ecf20Sopenharmony_ci		}
5398c2ecf20Sopenharmony_ci		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB)
5408c2ecf20Sopenharmony_ci			break;
5418c2ecf20Sopenharmony_ci		bcmd = *buf++;
5428c2ecf20Sopenharmony_ci		if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
5438c2ecf20Sopenharmony_ci			DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
5448c2ecf20Sopenharmony_ci				  *buf);
5458c2ecf20Sopenharmony_ci			ret = 1;
5468c2ecf20Sopenharmony_ci			break;
5478c2ecf20Sopenharmony_ci		}
5488c2ecf20Sopenharmony_ci		a_fire =
5498c2ecf20Sopenharmony_ci		    *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK |
5508c2ecf20Sopenharmony_ci		    HC_HE3Fire_MASK;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		/*
5538c2ecf20Sopenharmony_ci		 * How many dwords per vertex ?
5548c2ecf20Sopenharmony_ci		 */
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
5578c2ecf20Sopenharmony_ci			DRM_ERROR("Illegal B command vertex data for AGP.\n");
5588c2ecf20Sopenharmony_ci			ret = 1;
5598c2ecf20Sopenharmony_ci			break;
5608c2ecf20Sopenharmony_ci		}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		dw_count = 0;
5638c2ecf20Sopenharmony_ci		if (bcmd & (1 << 7))
5648c2ecf20Sopenharmony_ci			dw_count += (cur_seq->multitex) ? 2 : 1;
5658c2ecf20Sopenharmony_ci		if (bcmd & (1 << 8))
5668c2ecf20Sopenharmony_ci			dw_count += (cur_seq->multitex) ? 2 : 1;
5678c2ecf20Sopenharmony_ci		if (bcmd & (1 << 9))
5688c2ecf20Sopenharmony_ci			dw_count++;
5698c2ecf20Sopenharmony_ci		if (bcmd & (1 << 10))
5708c2ecf20Sopenharmony_ci			dw_count++;
5718c2ecf20Sopenharmony_ci		if (bcmd & (1 << 11))
5728c2ecf20Sopenharmony_ci			dw_count++;
5738c2ecf20Sopenharmony_ci		if (bcmd & (1 << 12))
5748c2ecf20Sopenharmony_ci			dw_count++;
5758c2ecf20Sopenharmony_ci		if (bcmd & (1 << 13))
5768c2ecf20Sopenharmony_ci			dw_count++;
5778c2ecf20Sopenharmony_ci		if (bcmd & (1 << 14))
5788c2ecf20Sopenharmony_ci			dw_count++;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		while (buf < buf_end) {
5818c2ecf20Sopenharmony_ci			if (*buf == a_fire) {
5828c2ecf20Sopenharmony_ci				if (dev_priv->num_fire_offsets >=
5838c2ecf20Sopenharmony_ci				    VIA_FIRE_BUF_SIZE) {
5848c2ecf20Sopenharmony_ci					DRM_ERROR("Fire offset buffer full.\n");
5858c2ecf20Sopenharmony_ci					ret = 1;
5868c2ecf20Sopenharmony_ci					break;
5878c2ecf20Sopenharmony_ci				}
5888c2ecf20Sopenharmony_ci				dev_priv->fire_offsets[dev_priv->
5898c2ecf20Sopenharmony_ci						       num_fire_offsets++] =
5908c2ecf20Sopenharmony_ci				    buf;
5918c2ecf20Sopenharmony_ci				have_fire = 1;
5928c2ecf20Sopenharmony_ci				buf++;
5938c2ecf20Sopenharmony_ci				if (buf < buf_end && *buf == a_fire)
5948c2ecf20Sopenharmony_ci					buf++;
5958c2ecf20Sopenharmony_ci				break;
5968c2ecf20Sopenharmony_ci			}
5978c2ecf20Sopenharmony_ci			if ((*buf == HALCYON_HEADER2) ||
5988c2ecf20Sopenharmony_ci			    ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
5998c2ecf20Sopenharmony_ci				DRM_ERROR("Missing Vertex Fire command, "
6008c2ecf20Sopenharmony_ci					  "Stray Vertex Fire command  or verifier "
6018c2ecf20Sopenharmony_ci					  "lost sync.\n");
6028c2ecf20Sopenharmony_ci				ret = 1;
6038c2ecf20Sopenharmony_ci				break;
6048c2ecf20Sopenharmony_ci			}
6058c2ecf20Sopenharmony_ci			if ((ret = eat_words(&buf, buf_end, dw_count)))
6068c2ecf20Sopenharmony_ci				break;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci		if (buf >= buf_end && !have_fire) {
6098c2ecf20Sopenharmony_ci			DRM_ERROR("Missing Vertex Fire command or verifier "
6108c2ecf20Sopenharmony_ci				  "lost sync.\n");
6118c2ecf20Sopenharmony_ci			ret = 1;
6128c2ecf20Sopenharmony_ci			break;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci		if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
6158c2ecf20Sopenharmony_ci			DRM_ERROR("AGP Primitive list end misaligned.\n");
6168c2ecf20Sopenharmony_ci			ret = 1;
6178c2ecf20Sopenharmony_ci			break;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci	*buffer = buf;
6218c2ecf20Sopenharmony_ci	return ret;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
6258c2ecf20Sopenharmony_civia_check_header2(uint32_t const **buffer, const uint32_t *buf_end,
6268c2ecf20Sopenharmony_ci		  drm_via_state_t *hc_state)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	uint32_t cmd;
6298c2ecf20Sopenharmony_ci	int hz_mode;
6308c2ecf20Sopenharmony_ci	hazard_t hz;
6318c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
6328c2ecf20Sopenharmony_ci	const hazard_t *hz_table;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if ((buf_end - buf) < 2) {
6358c2ecf20Sopenharmony_ci		DRM_ERROR
6368c2ecf20Sopenharmony_ci		    ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
6378c2ecf20Sopenharmony_ci		return state_error;
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci	buf++;
6408c2ecf20Sopenharmony_ci	cmd = (*buf++ & 0xFFFF0000) >> 16;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	switch (cmd) {
6438c2ecf20Sopenharmony_ci	case HC_ParaType_CmdVdata:
6448c2ecf20Sopenharmony_ci		if (via_check_prim_list(&buf, buf_end, hc_state))
6458c2ecf20Sopenharmony_ci			return state_error;
6468c2ecf20Sopenharmony_ci		*buffer = buf;
6478c2ecf20Sopenharmony_ci		return state_command;
6488c2ecf20Sopenharmony_ci	case HC_ParaType_NotTex:
6498c2ecf20Sopenharmony_ci		hz_table = table1;
6508c2ecf20Sopenharmony_ci		break;
6518c2ecf20Sopenharmony_ci	case HC_ParaType_Tex:
6528c2ecf20Sopenharmony_ci		hc_state->texture = 0;
6538c2ecf20Sopenharmony_ci		hz_table = table2;
6548c2ecf20Sopenharmony_ci		break;
6558c2ecf20Sopenharmony_ci	case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
6568c2ecf20Sopenharmony_ci		hc_state->texture = 1;
6578c2ecf20Sopenharmony_ci		hz_table = table2;
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
6608c2ecf20Sopenharmony_ci		hz_table = table3;
6618c2ecf20Sopenharmony_ci		break;
6628c2ecf20Sopenharmony_ci	case HC_ParaType_Auto:
6638c2ecf20Sopenharmony_ci		if (eat_words(&buf, buf_end, 2))
6648c2ecf20Sopenharmony_ci			return state_error;
6658c2ecf20Sopenharmony_ci		*buffer = buf;
6668c2ecf20Sopenharmony_ci		return state_command;
6678c2ecf20Sopenharmony_ci	case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
6688c2ecf20Sopenharmony_ci		if (eat_words(&buf, buf_end, 32))
6698c2ecf20Sopenharmony_ci			return state_error;
6708c2ecf20Sopenharmony_ci		*buffer = buf;
6718c2ecf20Sopenharmony_ci		return state_command;
6728c2ecf20Sopenharmony_ci	case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
6738c2ecf20Sopenharmony_ci	case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
6748c2ecf20Sopenharmony_ci		DRM_ERROR("Texture palettes are rejected because of "
6758c2ecf20Sopenharmony_ci			  "lack of info how to determine their size.\n");
6768c2ecf20Sopenharmony_ci		return state_error;
6778c2ecf20Sopenharmony_ci	case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
6788c2ecf20Sopenharmony_ci		DRM_ERROR("Fog factor palettes are rejected because of "
6798c2ecf20Sopenharmony_ci			  "lack of info how to determine their size.\n");
6808c2ecf20Sopenharmony_ci		return state_error;
6818c2ecf20Sopenharmony_ci	default:
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci		/*
6848c2ecf20Sopenharmony_ci		 * There are some unimplemented HC_ParaTypes here, that
6858c2ecf20Sopenharmony_ci		 * need to be implemented if the Mesa driver is extended.
6868c2ecf20Sopenharmony_ci		 */
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
6898c2ecf20Sopenharmony_ci			  "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
6908c2ecf20Sopenharmony_ci			  cmd, *(buf - 2));
6918c2ecf20Sopenharmony_ci		*buffer = buf;
6928c2ecf20Sopenharmony_ci		return state_error;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	while (buf < buf_end) {
6968c2ecf20Sopenharmony_ci		cmd = *buf++;
6978c2ecf20Sopenharmony_ci		if ((hz = hz_table[cmd >> 24])) {
6988c2ecf20Sopenharmony_ci			if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
6998c2ecf20Sopenharmony_ci				if (hz_mode == 1) {
7008c2ecf20Sopenharmony_ci					buf--;
7018c2ecf20Sopenharmony_ci					break;
7028c2ecf20Sopenharmony_ci				}
7038c2ecf20Sopenharmony_ci				return state_error;
7048c2ecf20Sopenharmony_ci			}
7058c2ecf20Sopenharmony_ci		} else if (hc_state->unfinished &&
7068c2ecf20Sopenharmony_ci			   finish_current_sequence(hc_state)) {
7078c2ecf20Sopenharmony_ci			return state_error;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	if (hc_state->unfinished && finish_current_sequence(hc_state))
7118c2ecf20Sopenharmony_ci		return state_error;
7128c2ecf20Sopenharmony_ci	*buffer = buf;
7138c2ecf20Sopenharmony_ci	return state_command;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
7178c2ecf20Sopenharmony_civia_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer,
7188c2ecf20Sopenharmony_ci		  const uint32_t *buf_end, int *fire_count)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	uint32_t cmd;
7218c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
7228c2ecf20Sopenharmony_ci	const uint32_t *next_fire;
7238c2ecf20Sopenharmony_ci	int burst = 0;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	next_fire = dev_priv->fire_offsets[*fire_count];
7268c2ecf20Sopenharmony_ci	buf++;
7278c2ecf20Sopenharmony_ci	cmd = (*buf & 0xFFFF0000) >> 16;
7288c2ecf20Sopenharmony_ci	via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
7298c2ecf20Sopenharmony_ci	switch (cmd) {
7308c2ecf20Sopenharmony_ci	case HC_ParaType_CmdVdata:
7318c2ecf20Sopenharmony_ci		while ((buf < buf_end) &&
7328c2ecf20Sopenharmony_ci		       (*fire_count < dev_priv->num_fire_offsets) &&
7338c2ecf20Sopenharmony_ci		       (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) {
7348c2ecf20Sopenharmony_ci			while (buf <= next_fire) {
7358c2ecf20Sopenharmony_ci				via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
7368c2ecf20Sopenharmony_ci					  (burst & 63), *buf++);
7378c2ecf20Sopenharmony_ci				burst += 4;
7388c2ecf20Sopenharmony_ci			}
7398c2ecf20Sopenharmony_ci			if ((buf < buf_end)
7408c2ecf20Sopenharmony_ci			    && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
7418c2ecf20Sopenharmony_ci				buf++;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci			if (++(*fire_count) < dev_priv->num_fire_offsets)
7448c2ecf20Sopenharmony_ci				next_fire = dev_priv->fire_offsets[*fire_count];
7458c2ecf20Sopenharmony_ci		}
7468c2ecf20Sopenharmony_ci		break;
7478c2ecf20Sopenharmony_ci	default:
7488c2ecf20Sopenharmony_ci		while (buf < buf_end) {
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci			if (*buf == HC_HEADER2 ||
7518c2ecf20Sopenharmony_ci			    (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
7528c2ecf20Sopenharmony_ci			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
7538c2ecf20Sopenharmony_ci			    (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
7548c2ecf20Sopenharmony_ci				break;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci			via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
7578c2ecf20Sopenharmony_ci				  (burst & 63), *buf++);
7588c2ecf20Sopenharmony_ci			burst += 4;
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci	*buffer = buf;
7628c2ecf20Sopenharmony_ci	return state_command;
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic __inline__ int verify_mmio_address(uint32_t address)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	if ((address > 0x3FF) && (address < 0xC00)) {
7688c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid VIDEO DMA command. "
7698c2ecf20Sopenharmony_ci			  "Attempt to access 3D- or command burst area.\n");
7708c2ecf20Sopenharmony_ci		return 1;
7718c2ecf20Sopenharmony_ci	} else if ((address > 0xCFF) && (address < 0x1300)) {
7728c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid VIDEO DMA command. "
7738c2ecf20Sopenharmony_ci			  "Attempt to access PCI DMA area.\n");
7748c2ecf20Sopenharmony_ci		return 1;
7758c2ecf20Sopenharmony_ci	} else if (address > 0x13FF) {
7768c2ecf20Sopenharmony_ci		DRM_ERROR("Invalid VIDEO DMA command. "
7778c2ecf20Sopenharmony_ci			  "Attempt to access VGA registers.\n");
7788c2ecf20Sopenharmony_ci		return 1;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci	return 0;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic __inline__ int
7848c2ecf20Sopenharmony_civerify_video_tail(uint32_t const **buffer, const uint32_t * buf_end,
7858c2ecf20Sopenharmony_ci		  uint32_t dwords)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (buf_end - buf < dwords) {
7908c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal termination of video command.\n");
7918c2ecf20Sopenharmony_ci		return 1;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci	while (dwords--) {
7948c2ecf20Sopenharmony_ci		if (*buf++) {
7958c2ecf20Sopenharmony_ci			DRM_ERROR("Illegal video command tail.\n");
7968c2ecf20Sopenharmony_ci			return 1;
7978c2ecf20Sopenharmony_ci		}
7988c2ecf20Sopenharmony_ci	}
7998c2ecf20Sopenharmony_ci	*buffer = buf;
8008c2ecf20Sopenharmony_ci	return 0;
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
8048c2ecf20Sopenharmony_civia_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	uint32_t cmd;
8078c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
8088c2ecf20Sopenharmony_ci	verifier_state_t ret = state_command;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	while (buf < buf_end) {
8118c2ecf20Sopenharmony_ci		cmd = *buf;
8128c2ecf20Sopenharmony_ci		if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
8138c2ecf20Sopenharmony_ci		    (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
8148c2ecf20Sopenharmony_ci			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
8158c2ecf20Sopenharmony_ci				break;
8168c2ecf20Sopenharmony_ci			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
8178c2ecf20Sopenharmony_ci				  "Attempt to access 3D- or command burst area.\n");
8188c2ecf20Sopenharmony_ci			ret = state_error;
8198c2ecf20Sopenharmony_ci			break;
8208c2ecf20Sopenharmony_ci		} else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
8218c2ecf20Sopenharmony_ci			if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
8228c2ecf20Sopenharmony_ci				break;
8238c2ecf20Sopenharmony_ci			DRM_ERROR("Invalid HALCYON_HEADER1 command. "
8248c2ecf20Sopenharmony_ci				  "Attempt to access VGA registers.\n");
8258c2ecf20Sopenharmony_ci			ret = state_error;
8268c2ecf20Sopenharmony_ci			break;
8278c2ecf20Sopenharmony_ci		} else {
8288c2ecf20Sopenharmony_ci			buf += 2;
8298c2ecf20Sopenharmony_ci		}
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci	*buffer = buf;
8328c2ecf20Sopenharmony_ci	return ret;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
8368c2ecf20Sopenharmony_civia_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer,
8378c2ecf20Sopenharmony_ci		  const uint32_t *buf_end)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	register uint32_t cmd;
8408c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	while (buf < buf_end) {
8438c2ecf20Sopenharmony_ci		cmd = *buf;
8448c2ecf20Sopenharmony_ci		if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
8458c2ecf20Sopenharmony_ci			break;
8468c2ecf20Sopenharmony_ci		via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
8478c2ecf20Sopenharmony_ci		buf++;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci	*buffer = buf;
8508c2ecf20Sopenharmony_ci	return state_command;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
8548c2ecf20Sopenharmony_civia_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	uint32_t data;
8578c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (buf_end - buf < 4) {
8608c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal termination of video header5 command\n");
8618c2ecf20Sopenharmony_ci		return state_error;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	data = *buf++ & ~VIA_VIDEOMASK;
8658c2ecf20Sopenharmony_ci	if (verify_mmio_address(data))
8668c2ecf20Sopenharmony_ci		return state_error;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	data = *buf++;
8698c2ecf20Sopenharmony_ci	if (*buf++ != 0x00F50000) {
8708c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal header5 header data\n");
8718c2ecf20Sopenharmony_ci		return state_error;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci	if (*buf++ != 0x00000000) {
8748c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal header5 header data\n");
8758c2ecf20Sopenharmony_ci		return state_error;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci	if (eat_words(&buf, buf_end, data))
8788c2ecf20Sopenharmony_ci		return state_error;
8798c2ecf20Sopenharmony_ci	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
8808c2ecf20Sopenharmony_ci		return state_error;
8818c2ecf20Sopenharmony_ci	*buffer = buf;
8828c2ecf20Sopenharmony_ci	return state_command;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
8878c2ecf20Sopenharmony_civia_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer,
8888c2ecf20Sopenharmony_ci		   const uint32_t *buf_end)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	uint32_t addr, count, i;
8918c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	addr = *buf++ & ~VIA_VIDEOMASK;
8948c2ecf20Sopenharmony_ci	i = count = *buf;
8958c2ecf20Sopenharmony_ci	buf += 3;
8968c2ecf20Sopenharmony_ci	while (i--)
8978c2ecf20Sopenharmony_ci		via_write(dev_priv, addr, *buf++);
8988c2ecf20Sopenharmony_ci	if (count & 3)
8998c2ecf20Sopenharmony_ci		buf += 4 - (count & 3);
9008c2ecf20Sopenharmony_ci	*buffer = buf;
9018c2ecf20Sopenharmony_ci	return state_command;
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
9058c2ecf20Sopenharmony_civia_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	uint32_t data;
9088c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
9098c2ecf20Sopenharmony_ci	uint32_t i;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	if (buf_end - buf < 4) {
9128c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal termination of video header6 command\n");
9138c2ecf20Sopenharmony_ci		return state_error;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci	buf++;
9168c2ecf20Sopenharmony_ci	data = *buf++;
9178c2ecf20Sopenharmony_ci	if (*buf++ != 0x00F60000) {
9188c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal header6 header data\n");
9198c2ecf20Sopenharmony_ci		return state_error;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci	if (*buf++ != 0x00000000) {
9228c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal header6 header data\n");
9238c2ecf20Sopenharmony_ci		return state_error;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci	if ((buf_end - buf) < (data << 1)) {
9268c2ecf20Sopenharmony_ci		DRM_ERROR("Illegal termination of video header6 command\n");
9278c2ecf20Sopenharmony_ci		return state_error;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci	for (i = 0; i < data; ++i) {
9308c2ecf20Sopenharmony_ci		if (verify_mmio_address(*buf++))
9318c2ecf20Sopenharmony_ci			return state_error;
9328c2ecf20Sopenharmony_ci		buf++;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci	data <<= 1;
9358c2ecf20Sopenharmony_ci	if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
9368c2ecf20Sopenharmony_ci		return state_error;
9378c2ecf20Sopenharmony_ci	*buffer = buf;
9388c2ecf20Sopenharmony_ci	return state_command;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic __inline__ verifier_state_t
9428c2ecf20Sopenharmony_civia_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer,
9438c2ecf20Sopenharmony_ci		   const uint32_t *buf_end)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	uint32_t addr, count, i;
9478c2ecf20Sopenharmony_ci	const uint32_t *buf = *buffer;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	i = count = *++buf;
9508c2ecf20Sopenharmony_ci	buf += 3;
9518c2ecf20Sopenharmony_ci	while (i--) {
9528c2ecf20Sopenharmony_ci		addr = *buf++;
9538c2ecf20Sopenharmony_ci		via_write(dev_priv, addr, *buf++);
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci	count <<= 1;
9568c2ecf20Sopenharmony_ci	if (count & 3)
9578c2ecf20Sopenharmony_ci		buf += 4 - (count & 3);
9588c2ecf20Sopenharmony_ci	*buffer = buf;
9598c2ecf20Sopenharmony_ci	return state_command;
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ciint
9638c2ecf20Sopenharmony_civia_verify_command_stream(const uint32_t * buf, unsigned int size,
9648c2ecf20Sopenharmony_ci			  struct drm_device * dev, int agp)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
9688c2ecf20Sopenharmony_ci	drm_via_state_t *hc_state = &dev_priv->hc_state;
9698c2ecf20Sopenharmony_ci	drm_via_state_t saved_state = *hc_state;
9708c2ecf20Sopenharmony_ci	uint32_t cmd;
9718c2ecf20Sopenharmony_ci	const uint32_t *buf_end = buf + (size >> 2);
9728c2ecf20Sopenharmony_ci	verifier_state_t state = state_command;
9738c2ecf20Sopenharmony_ci	int cme_video;
9748c2ecf20Sopenharmony_ci	int supported_3d;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
9778c2ecf20Sopenharmony_ci		     dev_priv->chipset == VIA_DX9_0);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	supported_3d = dev_priv->chipset != VIA_DX9_0;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	hc_state->dev = dev;
9828c2ecf20Sopenharmony_ci	hc_state->unfinished = no_sequence;
9838c2ecf20Sopenharmony_ci	hc_state->map_cache = NULL;
9848c2ecf20Sopenharmony_ci	hc_state->agp = agp;
9858c2ecf20Sopenharmony_ci	hc_state->buf_start = buf;
9868c2ecf20Sopenharmony_ci	dev_priv->num_fire_offsets = 0;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	while (buf < buf_end) {
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		switch (state) {
9918c2ecf20Sopenharmony_ci		case state_header2:
9928c2ecf20Sopenharmony_ci			state = via_check_header2(&buf, buf_end, hc_state);
9938c2ecf20Sopenharmony_ci			break;
9948c2ecf20Sopenharmony_ci		case state_header1:
9958c2ecf20Sopenharmony_ci			state = via_check_header1(&buf, buf_end);
9968c2ecf20Sopenharmony_ci			break;
9978c2ecf20Sopenharmony_ci		case state_vheader5:
9988c2ecf20Sopenharmony_ci			state = via_check_vheader5(&buf, buf_end);
9998c2ecf20Sopenharmony_ci			break;
10008c2ecf20Sopenharmony_ci		case state_vheader6:
10018c2ecf20Sopenharmony_ci			state = via_check_vheader6(&buf, buf_end);
10028c2ecf20Sopenharmony_ci			break;
10038c2ecf20Sopenharmony_ci		case state_command:
10048c2ecf20Sopenharmony_ci			if ((HALCYON_HEADER2 == (cmd = *buf)) &&
10058c2ecf20Sopenharmony_ci			    supported_3d)
10068c2ecf20Sopenharmony_ci				state = state_header2;
10078c2ecf20Sopenharmony_ci			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
10088c2ecf20Sopenharmony_ci				state = state_header1;
10098c2ecf20Sopenharmony_ci			else if (cme_video
10108c2ecf20Sopenharmony_ci				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
10118c2ecf20Sopenharmony_ci				state = state_vheader5;
10128c2ecf20Sopenharmony_ci			else if (cme_video
10138c2ecf20Sopenharmony_ci				 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
10148c2ecf20Sopenharmony_ci				state = state_vheader6;
10158c2ecf20Sopenharmony_ci			else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
10168c2ecf20Sopenharmony_ci				DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
10178c2ecf20Sopenharmony_ci				state = state_error;
10188c2ecf20Sopenharmony_ci			} else {
10198c2ecf20Sopenharmony_ci				DRM_ERROR
10208c2ecf20Sopenharmony_ci				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
10218c2ecf20Sopenharmony_ci				     cmd);
10228c2ecf20Sopenharmony_ci				state = state_error;
10238c2ecf20Sopenharmony_ci			}
10248c2ecf20Sopenharmony_ci			break;
10258c2ecf20Sopenharmony_ci		case state_error:
10268c2ecf20Sopenharmony_ci		default:
10278c2ecf20Sopenharmony_ci			*hc_state = saved_state;
10288c2ecf20Sopenharmony_ci			return -EINVAL;
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci	if (state == state_error) {
10328c2ecf20Sopenharmony_ci		*hc_state = saved_state;
10338c2ecf20Sopenharmony_ci		return -EINVAL;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci	return 0;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ciint
10398c2ecf20Sopenharmony_civia_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
10408c2ecf20Sopenharmony_ci			 unsigned int size)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
10448c2ecf20Sopenharmony_ci	uint32_t cmd;
10458c2ecf20Sopenharmony_ci	const uint32_t *buf_end = buf + (size >> 2);
10468c2ecf20Sopenharmony_ci	verifier_state_t state = state_command;
10478c2ecf20Sopenharmony_ci	int fire_count = 0;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	while (buf < buf_end) {
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		switch (state) {
10528c2ecf20Sopenharmony_ci		case state_header2:
10538c2ecf20Sopenharmony_ci			state =
10548c2ecf20Sopenharmony_ci			    via_parse_header2(dev_priv, &buf, buf_end,
10558c2ecf20Sopenharmony_ci					      &fire_count);
10568c2ecf20Sopenharmony_ci			break;
10578c2ecf20Sopenharmony_ci		case state_header1:
10588c2ecf20Sopenharmony_ci			state = via_parse_header1(dev_priv, &buf, buf_end);
10598c2ecf20Sopenharmony_ci			break;
10608c2ecf20Sopenharmony_ci		case state_vheader5:
10618c2ecf20Sopenharmony_ci			state = via_parse_vheader5(dev_priv, &buf, buf_end);
10628c2ecf20Sopenharmony_ci			break;
10638c2ecf20Sopenharmony_ci		case state_vheader6:
10648c2ecf20Sopenharmony_ci			state = via_parse_vheader6(dev_priv, &buf, buf_end);
10658c2ecf20Sopenharmony_ci			break;
10668c2ecf20Sopenharmony_ci		case state_command:
10678c2ecf20Sopenharmony_ci			if (HALCYON_HEADER2 == (cmd = *buf))
10688c2ecf20Sopenharmony_ci				state = state_header2;
10698c2ecf20Sopenharmony_ci			else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
10708c2ecf20Sopenharmony_ci				state = state_header1;
10718c2ecf20Sopenharmony_ci			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
10728c2ecf20Sopenharmony_ci				state = state_vheader5;
10738c2ecf20Sopenharmony_ci			else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
10748c2ecf20Sopenharmony_ci				state = state_vheader6;
10758c2ecf20Sopenharmony_ci			else {
10768c2ecf20Sopenharmony_ci				DRM_ERROR
10778c2ecf20Sopenharmony_ci				    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
10788c2ecf20Sopenharmony_ci				     cmd);
10798c2ecf20Sopenharmony_ci				state = state_error;
10808c2ecf20Sopenharmony_ci			}
10818c2ecf20Sopenharmony_ci			break;
10828c2ecf20Sopenharmony_ci		case state_error:
10838c2ecf20Sopenharmony_ci		default:
10848c2ecf20Sopenharmony_ci			return -EINVAL;
10858c2ecf20Sopenharmony_ci		}
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	if (state == state_error)
10888c2ecf20Sopenharmony_ci		return -EINVAL;
10898c2ecf20Sopenharmony_ci	return 0;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic void
10938c2ecf20Sopenharmony_cisetup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	int i;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	for (i = 0; i < 256; ++i)
10988c2ecf20Sopenharmony_ci		table[i] = forbidden_command;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	for (i = 0; i < size; ++i)
11018c2ecf20Sopenharmony_ci		table[init_table[i].code] = init_table[i].hz;
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_civoid via_init_command_verifier(void)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1));
11078c2ecf20Sopenharmony_ci	setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2));
11088c2ecf20Sopenharmony_ci	setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3));
11098c2ecf20Sopenharmony_ci}
1110