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