1203288Srnoland/*- 2203288Srnoland * Copyright 2004 The Unichrome Project. All Rights Reserved. 3203288Srnoland * Copyright 2005 Thomas Hellstrom. All Rights Reserved. 4203288Srnoland * 5203288Srnoland * Permission is hereby granted, free of charge, to any person obtaining a 6203288Srnoland * copy of this software and associated documentation files (the "Software"), 7203288Srnoland * to deal in the Software without restriction, including without limitation 8203288Srnoland * the rights to use, copy, modify, merge, publish, distribute, sub license, 9203288Srnoland * and/or sell copies of the Software, and to permit persons to whom the 10203288Srnoland * Software is furnished to do so, subject to the following conditions: 11203288Srnoland * 12203288Srnoland * The above copyright notice and this permission notice (including the 13203288Srnoland * next paragraph) shall be included in all copies or substantial portions 14203288Srnoland * of the Software. 15203288Srnoland * 16203288Srnoland * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17203288Srnoland * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18203288Srnoland * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19203288Srnoland * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20203288Srnoland * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21203288Srnoland * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22203288Srnoland * DEALINGS IN THE SOFTWARE. 23203288Srnoland * 24203288Srnoland * Author: Thomas Hellstrom 2004, 2005. 25203288Srnoland * This code was written using docs obtained under NDA from VIA Inc. 26203288Srnoland * 27203288Srnoland * Don't run this code directly on an AGP buffer. Due to cache problems it will 28203288Srnoland * be very slow. 29203288Srnoland */ 30203288Srnoland 31203288Srnoland#include <sys/cdefs.h> 32203288Srnoland__FBSDID("$FreeBSD$"); 33203288Srnoland 34203288Srnoland#include "dev/drm/via_3d_reg.h" 35203288Srnoland#include "dev/drm/drmP.h" 36203288Srnoland#include "dev/drm/drm.h" 37203288Srnoland#include "dev/drm/via_drm.h" 38203288Srnoland#include "dev/drm/via_verifier.h" 39203288Srnoland#include "dev/drm/via_drv.h" 40203288Srnoland 41203288Srnolandtypedef enum { 42203288Srnoland state_command, 43203288Srnoland state_header2, 44203288Srnoland state_header1, 45203288Srnoland state_vheader5, 46203288Srnoland state_vheader6, 47203288Srnoland state_error 48203288Srnoland} verifier_state_t; 49203288Srnoland 50203288Srnolandtypedef enum { 51203288Srnoland no_check = 0, 52203288Srnoland check_for_header2, 53203288Srnoland check_for_header1, 54203288Srnoland check_for_header2_err, 55203288Srnoland check_for_header1_err, 56203288Srnoland check_for_fire, 57203288Srnoland check_z_buffer_addr0, 58203288Srnoland check_z_buffer_addr1, 59203288Srnoland check_z_buffer_addr_mode, 60203288Srnoland check_destination_addr0, 61203288Srnoland check_destination_addr1, 62203288Srnoland check_destination_addr_mode, 63203288Srnoland check_for_dummy, 64203288Srnoland check_for_dd, 65203288Srnoland check_texture_addr0, 66203288Srnoland check_texture_addr1, 67203288Srnoland check_texture_addr2, 68203288Srnoland check_texture_addr3, 69203288Srnoland check_texture_addr4, 70203288Srnoland check_texture_addr5, 71203288Srnoland check_texture_addr6, 72203288Srnoland check_texture_addr7, 73203288Srnoland check_texture_addr8, 74203288Srnoland check_texture_addr_mode, 75203288Srnoland check_for_vertex_count, 76203288Srnoland check_number_texunits, 77203288Srnoland forbidden_command 78203288Srnoland} hazard_t; 79203288Srnoland 80203288Srnoland/* 81203288Srnoland * Associates each hazard above with a possible multi-command 82203288Srnoland * sequence. For example an address that is split over multiple 83203288Srnoland * commands and that needs to be checked at the first command 84203288Srnoland * that does not include any part of the address. 85203288Srnoland */ 86203288Srnoland 87203288Srnolandstatic drm_via_sequence_t seqs[] = { 88203288Srnoland no_sequence, 89203288Srnoland no_sequence, 90203288Srnoland no_sequence, 91203288Srnoland no_sequence, 92203288Srnoland no_sequence, 93203288Srnoland no_sequence, 94203288Srnoland z_address, 95203288Srnoland z_address, 96203288Srnoland z_address, 97203288Srnoland dest_address, 98203288Srnoland dest_address, 99203288Srnoland dest_address, 100203288Srnoland no_sequence, 101203288Srnoland no_sequence, 102203288Srnoland tex_address, 103203288Srnoland tex_address, 104203288Srnoland tex_address, 105203288Srnoland tex_address, 106203288Srnoland tex_address, 107203288Srnoland tex_address, 108203288Srnoland tex_address, 109203288Srnoland tex_address, 110203288Srnoland tex_address, 111203288Srnoland tex_address, 112203288Srnoland no_sequence 113203288Srnoland}; 114203288Srnoland 115203288Srnolandtypedef struct { 116203288Srnoland unsigned int code; 117203288Srnoland hazard_t hz; 118203288Srnoland} hz_init_t; 119203288Srnoland 120203288Srnolandstatic hz_init_t init_table1[] = { 121203288Srnoland {0xf2, check_for_header2_err}, 122203288Srnoland {0xf0, check_for_header1_err}, 123203288Srnoland {0xee, check_for_fire}, 124203288Srnoland {0xcc, check_for_dummy}, 125203288Srnoland {0xdd, check_for_dd}, 126203288Srnoland {0x00, no_check}, 127203288Srnoland {0x10, check_z_buffer_addr0}, 128203288Srnoland {0x11, check_z_buffer_addr1}, 129203288Srnoland {0x12, check_z_buffer_addr_mode}, 130203288Srnoland {0x13, no_check}, 131203288Srnoland {0x14, no_check}, 132203288Srnoland {0x15, no_check}, 133203288Srnoland {0x23, no_check}, 134203288Srnoland {0x24, no_check}, 135203288Srnoland {0x33, no_check}, 136203288Srnoland {0x34, no_check}, 137203288Srnoland {0x35, no_check}, 138203288Srnoland {0x36, no_check}, 139203288Srnoland {0x37, no_check}, 140203288Srnoland {0x38, no_check}, 141203288Srnoland {0x39, no_check}, 142203288Srnoland {0x3A, no_check}, 143203288Srnoland {0x3B, no_check}, 144203288Srnoland {0x3C, no_check}, 145203288Srnoland {0x3D, no_check}, 146203288Srnoland {0x3E, no_check}, 147203288Srnoland {0x40, check_destination_addr0}, 148203288Srnoland {0x41, check_destination_addr1}, 149203288Srnoland {0x42, check_destination_addr_mode}, 150203288Srnoland {0x43, no_check}, 151203288Srnoland {0x44, no_check}, 152203288Srnoland {0x50, no_check}, 153203288Srnoland {0x51, no_check}, 154203288Srnoland {0x52, no_check}, 155203288Srnoland {0x53, no_check}, 156203288Srnoland {0x54, no_check}, 157203288Srnoland {0x55, no_check}, 158203288Srnoland {0x56, no_check}, 159203288Srnoland {0x57, no_check}, 160203288Srnoland {0x58, no_check}, 161203288Srnoland {0x70, no_check}, 162203288Srnoland {0x71, no_check}, 163203288Srnoland {0x78, no_check}, 164203288Srnoland {0x79, no_check}, 165203288Srnoland {0x7A, no_check}, 166203288Srnoland {0x7B, no_check}, 167203288Srnoland {0x7C, no_check}, 168203288Srnoland {0x7D, check_for_vertex_count} 169203288Srnoland}; 170203288Srnoland 171203288Srnolandstatic hz_init_t init_table2[] = { 172203288Srnoland {0xf2, check_for_header2_err}, 173203288Srnoland {0xf0, check_for_header1_err}, 174203288Srnoland {0xee, check_for_fire}, 175203288Srnoland {0xcc, check_for_dummy}, 176203288Srnoland {0x00, check_texture_addr0}, 177203288Srnoland {0x01, check_texture_addr0}, 178203288Srnoland {0x02, check_texture_addr0}, 179203288Srnoland {0x03, check_texture_addr0}, 180203288Srnoland {0x04, check_texture_addr0}, 181203288Srnoland {0x05, check_texture_addr0}, 182203288Srnoland {0x06, check_texture_addr0}, 183203288Srnoland {0x07, check_texture_addr0}, 184203288Srnoland {0x08, check_texture_addr0}, 185203288Srnoland {0x09, check_texture_addr0}, 186203288Srnoland {0x20, check_texture_addr1}, 187203288Srnoland {0x21, check_texture_addr1}, 188203288Srnoland {0x22, check_texture_addr1}, 189203288Srnoland {0x23, check_texture_addr4}, 190203288Srnoland {0x2B, check_texture_addr3}, 191203288Srnoland {0x2C, check_texture_addr3}, 192203288Srnoland {0x2D, check_texture_addr3}, 193203288Srnoland {0x2E, check_texture_addr3}, 194203288Srnoland {0x2F, check_texture_addr3}, 195203288Srnoland {0x30, check_texture_addr3}, 196203288Srnoland {0x31, check_texture_addr3}, 197203288Srnoland {0x32, check_texture_addr3}, 198203288Srnoland {0x33, check_texture_addr3}, 199203288Srnoland {0x34, check_texture_addr3}, 200203288Srnoland {0x4B, check_texture_addr5}, 201203288Srnoland {0x4C, check_texture_addr6}, 202203288Srnoland {0x51, check_texture_addr7}, 203203288Srnoland {0x52, check_texture_addr8}, 204203288Srnoland {0x77, check_texture_addr2}, 205203288Srnoland {0x78, no_check}, 206203288Srnoland {0x79, no_check}, 207203288Srnoland {0x7A, no_check}, 208203288Srnoland {0x7B, check_texture_addr_mode}, 209203288Srnoland {0x7C, no_check}, 210203288Srnoland {0x7D, no_check}, 211203288Srnoland {0x7E, no_check}, 212203288Srnoland {0x7F, no_check}, 213203288Srnoland {0x80, no_check}, 214203288Srnoland {0x81, no_check}, 215203288Srnoland {0x82, no_check}, 216203288Srnoland {0x83, no_check}, 217203288Srnoland {0x85, no_check}, 218203288Srnoland {0x86, no_check}, 219203288Srnoland {0x87, no_check}, 220203288Srnoland {0x88, no_check}, 221203288Srnoland {0x89, no_check}, 222203288Srnoland {0x8A, no_check}, 223203288Srnoland {0x90, no_check}, 224203288Srnoland {0x91, no_check}, 225203288Srnoland {0x92, no_check}, 226203288Srnoland {0x93, no_check} 227203288Srnoland}; 228203288Srnoland 229203288Srnolandstatic hz_init_t init_table3[] = { 230203288Srnoland {0xf2, check_for_header2_err}, 231203288Srnoland {0xf0, check_for_header1_err}, 232203288Srnoland {0xcc, check_for_dummy}, 233203288Srnoland {0x00, check_number_texunits} 234203288Srnoland}; 235203288Srnoland 236203288Srnolandstatic hazard_t table1[256]; 237203288Srnolandstatic hazard_t table2[256]; 238203288Srnolandstatic hazard_t table3[256]; 239203288Srnoland 240203288Srnolandstatic __inline__ int 241203288Srnolandeat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words) 242203288Srnoland{ 243203288Srnoland if ((buf_end - *buf) >= num_words) { 244203288Srnoland *buf += num_words; 245203288Srnoland return 0; 246203288Srnoland } 247203288Srnoland DRM_ERROR("Illegal termination of DMA command buffer\n"); 248203288Srnoland return 1; 249203288Srnoland} 250203288Srnoland 251203288Srnoland/* 252203288Srnoland * Partially stolen from drm_memory.h 253203288Srnoland */ 254203288Srnoland 255203288Srnolandstatic __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, 256203288Srnoland unsigned long offset, 257203288Srnoland unsigned long size, 258203288Srnoland struct drm_device * dev) 259203288Srnoland{ 260203288Srnoland drm_local_map_t *map = seq->map_cache; 261203288Srnoland 262203288Srnoland if (map && map->offset <= offset 263203288Srnoland && (offset + size) <= (map->offset + map->size)) { 264203288Srnoland return map; 265203288Srnoland } 266203288Srnoland 267203288Srnoland TAILQ_FOREACH(map, &dev->maplist, link) { 268203288Srnoland if (map->offset <= offset 269203288Srnoland && (offset + size) <= (map->offset + map->size) 270203288Srnoland && !(map->flags & _DRM_RESTRICTED) 271203288Srnoland && (map->type == _DRM_AGP)) { 272203288Srnoland seq->map_cache = map; 273203288Srnoland return map; 274203288Srnoland } 275203288Srnoland } 276203288Srnoland return NULL; 277203288Srnoland} 278203288Srnoland 279203288Srnoland/* 280203288Srnoland * Require that all AGP texture levels reside in the same AGP map which should 281203288Srnoland * be mappable by the client. This is not a big restriction. 282203288Srnoland * FIXME: To actually enforce this security policy strictly, drm_rmmap 283203288Srnoland * would have to wait for dma quiescent before removing an AGP map. 284203288Srnoland * The via_drm_lookup_agp_map call in reality seems to take 285203288Srnoland * very little CPU time. 286203288Srnoland */ 287203288Srnoland 288203288Srnolandstatic __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) 289203288Srnoland{ 290203288Srnoland switch (cur_seq->unfinished) { 291203288Srnoland case z_address: 292203288Srnoland DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr); 293203288Srnoland break; 294203288Srnoland case dest_address: 295203288Srnoland DRM_DEBUG("Destination start address is 0x%x\n", 296203288Srnoland cur_seq->d_addr); 297203288Srnoland break; 298203288Srnoland case tex_address: 299203288Srnoland if (cur_seq->agp_texture) { 300203288Srnoland unsigned start = 301203288Srnoland cur_seq->tex_level_lo[cur_seq->texture]; 302203288Srnoland unsigned end = cur_seq->tex_level_hi[cur_seq->texture]; 303203288Srnoland unsigned long lo = ~0, hi = 0, tmp; 304203288Srnoland uint32_t *addr, *pitch, *height, tex; 305203288Srnoland unsigned i; 306203288Srnoland int npot; 307203288Srnoland 308203288Srnoland if (end > 9) 309203288Srnoland end = 9; 310203288Srnoland if (start > 9) 311203288Srnoland start = 9; 312203288Srnoland 313203288Srnoland addr = 314203288Srnoland &(cur_seq->t_addr[tex = cur_seq->texture][start]); 315203288Srnoland pitch = &(cur_seq->pitch[tex][start]); 316203288Srnoland height = &(cur_seq->height[tex][start]); 317203288Srnoland npot = cur_seq->tex_npot[tex]; 318203288Srnoland for (i = start; i <= end; ++i) { 319203288Srnoland tmp = *addr++; 320203288Srnoland if (tmp < lo) 321203288Srnoland lo = tmp; 322203288Srnoland if (i == 0 && npot) 323203288Srnoland tmp += (*height++ * *pitch++); 324203288Srnoland else 325203288Srnoland tmp += (*height++ << *pitch++); 326203288Srnoland if (tmp > hi) 327203288Srnoland hi = tmp; 328203288Srnoland } 329203288Srnoland 330203288Srnoland if (!via_drm_lookup_agp_map 331203288Srnoland (cur_seq, lo, hi - lo, cur_seq->dev)) { 332203288Srnoland DRM_ERROR 333203288Srnoland ("AGP texture is not in allowed map\n"); 334203288Srnoland return 2; 335203288Srnoland } 336203288Srnoland } 337203288Srnoland break; 338203288Srnoland default: 339203288Srnoland break; 340203288Srnoland } 341203288Srnoland cur_seq->unfinished = no_sequence; 342203288Srnoland return 0; 343203288Srnoland} 344203288Srnoland 345203288Srnolandstatic __inline__ int 346203288Srnolandinvestigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq) 347203288Srnoland{ 348203288Srnoland register uint32_t tmp, *tmp_addr; 349203288Srnoland 350203288Srnoland if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { 351203288Srnoland int ret; 352203288Srnoland if ((ret = finish_current_sequence(cur_seq))) 353203288Srnoland return ret; 354203288Srnoland } 355203288Srnoland 356203288Srnoland switch (hz) { 357203288Srnoland case check_for_header2: 358203288Srnoland if (cmd == HALCYON_HEADER2) 359203288Srnoland return 1; 360203288Srnoland return 0; 361203288Srnoland case check_for_header1: 362203288Srnoland if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 363203288Srnoland return 1; 364203288Srnoland return 0; 365203288Srnoland case check_for_header2_err: 366203288Srnoland if (cmd == HALCYON_HEADER2) 367203288Srnoland return 1; 368203288Srnoland DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n"); 369203288Srnoland break; 370203288Srnoland case check_for_header1_err: 371203288Srnoland if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 372203288Srnoland return 1; 373203288Srnoland DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n"); 374203288Srnoland break; 375203288Srnoland case check_for_fire: 376203288Srnoland if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) 377203288Srnoland return 1; 378203288Srnoland DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n"); 379203288Srnoland break; 380203288Srnoland case check_for_dummy: 381203288Srnoland if (HC_DUMMY == cmd) 382203288Srnoland return 0; 383203288Srnoland DRM_ERROR("Illegal DMA HC_DUMMY command\n"); 384203288Srnoland break; 385203288Srnoland case check_for_dd: 386203288Srnoland if (0xdddddddd == cmd) 387203288Srnoland return 0; 388203288Srnoland DRM_ERROR("Illegal DMA 0xdddddddd command\n"); 389203288Srnoland break; 390203288Srnoland case check_z_buffer_addr0: 391203288Srnoland cur_seq->unfinished = z_address; 392203288Srnoland cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) | 393203288Srnoland (cmd & 0x00FFFFFF); 394203288Srnoland return 0; 395203288Srnoland case check_z_buffer_addr1: 396203288Srnoland cur_seq->unfinished = z_address; 397203288Srnoland cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) | 398203288Srnoland ((cmd & 0xFF) << 24); 399203288Srnoland return 0; 400203288Srnoland case check_z_buffer_addr_mode: 401203288Srnoland cur_seq->unfinished = z_address; 402203288Srnoland if ((cmd & 0x0000C000) == 0) 403203288Srnoland return 0; 404203288Srnoland DRM_ERROR("Attempt to place Z buffer in system memory\n"); 405203288Srnoland return 2; 406203288Srnoland case check_destination_addr0: 407203288Srnoland cur_seq->unfinished = dest_address; 408203288Srnoland cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) | 409203288Srnoland (cmd & 0x00FFFFFF); 410203288Srnoland return 0; 411203288Srnoland case check_destination_addr1: 412203288Srnoland cur_seq->unfinished = dest_address; 413203288Srnoland cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) | 414203288Srnoland ((cmd & 0xFF) << 24); 415203288Srnoland return 0; 416203288Srnoland case check_destination_addr_mode: 417203288Srnoland cur_seq->unfinished = dest_address; 418203288Srnoland if ((cmd & 0x0000C000) == 0) 419203288Srnoland return 0; 420203288Srnoland DRM_ERROR 421203288Srnoland ("Attempt to place 3D drawing buffer in system memory\n"); 422203288Srnoland return 2; 423203288Srnoland case check_texture_addr0: 424203288Srnoland cur_seq->unfinished = tex_address; 425203288Srnoland tmp = (cmd >> 24); 426203288Srnoland tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; 427203288Srnoland *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF); 428203288Srnoland return 0; 429203288Srnoland case check_texture_addr1: 430203288Srnoland cur_seq->unfinished = tex_address; 431203288Srnoland tmp = ((cmd >> 24) - 0x20); 432203288Srnoland tmp += tmp << 1; 433203288Srnoland tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; 434203288Srnoland *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); 435203288Srnoland tmp_addr++; 436203288Srnoland *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16); 437203288Srnoland tmp_addr++; 438203288Srnoland *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8); 439203288Srnoland return 0; 440203288Srnoland case check_texture_addr2: 441203288Srnoland cur_seq->unfinished = tex_address; 442203288Srnoland cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F; 443203288Srnoland cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6; 444203288Srnoland return 0; 445203288Srnoland case check_texture_addr3: 446203288Srnoland cur_seq->unfinished = tex_address; 447203288Srnoland tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); 448203288Srnoland if (tmp == 0 && 449203288Srnoland (cmd & HC_HTXnEnPit_MASK)) { 450203288Srnoland cur_seq->pitch[cur_seq->texture][tmp] = 451203288Srnoland (cmd & HC_HTXnLnPit_MASK); 452203288Srnoland cur_seq->tex_npot[cur_seq->texture] = 1; 453203288Srnoland } else { 454203288Srnoland cur_seq->pitch[cur_seq->texture][tmp] = 455203288Srnoland (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; 456203288Srnoland cur_seq->tex_npot[cur_seq->texture] = 0; 457203288Srnoland if (cmd & 0x000FFFFF) { 458203288Srnoland DRM_ERROR 459203288Srnoland ("Unimplemented texture level 0 pitch mode.\n"); 460203288Srnoland return 2; 461203288Srnoland } 462203288Srnoland } 463203288Srnoland return 0; 464203288Srnoland case check_texture_addr4: 465203288Srnoland cur_seq->unfinished = tex_address; 466203288Srnoland tmp_addr = &cur_seq->t_addr[cur_seq->texture][9]; 467203288Srnoland *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); 468203288Srnoland return 0; 469203288Srnoland case check_texture_addr5: 470203288Srnoland case check_texture_addr6: 471203288Srnoland cur_seq->unfinished = tex_address; 472203288Srnoland /* 473203288Srnoland * Texture width. We don't care since we have the pitch. 474203288Srnoland */ 475203288Srnoland return 0; 476203288Srnoland case check_texture_addr7: 477203288Srnoland cur_seq->unfinished = tex_address; 478203288Srnoland tmp_addr = &(cur_seq->height[cur_seq->texture][0]); 479203288Srnoland tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20); 480203288Srnoland tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16); 481203288Srnoland tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12); 482203288Srnoland tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8); 483203288Srnoland tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4); 484203288Srnoland tmp_addr[0] = 1 << (cmd & 0x0000000F); 485203288Srnoland return 0; 486203288Srnoland case check_texture_addr8: 487203288Srnoland cur_seq->unfinished = tex_address; 488203288Srnoland tmp_addr = &(cur_seq->height[cur_seq->texture][0]); 489203288Srnoland tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12); 490203288Srnoland tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8); 491203288Srnoland tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4); 492203288Srnoland tmp_addr[6] = 1 << (cmd & 0x0000000F); 493203288Srnoland return 0; 494203288Srnoland case check_texture_addr_mode: 495203288Srnoland cur_seq->unfinished = tex_address; 496203288Srnoland if (2 == (tmp = cmd & 0x00000003)) { 497203288Srnoland DRM_ERROR 498203288Srnoland ("Attempt to fetch texture from system memory.\n"); 499203288Srnoland return 2; 500203288Srnoland } 501203288Srnoland cur_seq->agp_texture = (tmp == 3); 502203288Srnoland cur_seq->tex_palette_size[cur_seq->texture] = 503203288Srnoland (cmd >> 16) & 0x000000007; 504203288Srnoland return 0; 505203288Srnoland case check_for_vertex_count: 506203288Srnoland cur_seq->vertex_count = cmd & 0x0000FFFF; 507203288Srnoland return 0; 508203288Srnoland case check_number_texunits: 509203288Srnoland cur_seq->multitex = (cmd >> 3) & 1; 510203288Srnoland return 0; 511203288Srnoland default: 512203288Srnoland DRM_ERROR("Illegal DMA data: 0x%x\n", cmd); 513203288Srnoland return 2; 514203288Srnoland } 515203288Srnoland return 2; 516203288Srnoland} 517203288Srnoland 518203288Srnolandstatic __inline__ int 519203288Srnolandvia_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, 520203288Srnoland drm_via_state_t * cur_seq) 521203288Srnoland{ 522203288Srnoland drm_via_private_t *dev_priv = 523203288Srnoland (drm_via_private_t *) cur_seq->dev->dev_private; 524203288Srnoland uint32_t a_fire, bcmd, dw_count; 525203288Srnoland int ret = 0; 526203288Srnoland int have_fire; 527203288Srnoland const uint32_t *buf = *buffer; 528203288Srnoland 529203288Srnoland while (buf < buf_end) { 530203288Srnoland have_fire = 0; 531203288Srnoland if ((buf_end - buf) < 2) { 532203288Srnoland DRM_ERROR 533203288Srnoland ("Unexpected termination of primitive list.\n"); 534203288Srnoland ret = 1; 535203288Srnoland break; 536203288Srnoland } 537203288Srnoland if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) 538203288Srnoland break; 539203288Srnoland bcmd = *buf++; 540203288Srnoland if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) { 541203288Srnoland DRM_ERROR("Expected Vertex List A command, got 0x%x\n", 542203288Srnoland *buf); 543203288Srnoland ret = 1; 544203288Srnoland break; 545203288Srnoland } 546203288Srnoland a_fire = 547203288Srnoland *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | 548203288Srnoland HC_HE3Fire_MASK; 549203288Srnoland 550203288Srnoland /* 551203288Srnoland * How many dwords per vertex ? 552203288Srnoland */ 553203288Srnoland 554203288Srnoland if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) { 555203288Srnoland DRM_ERROR("Illegal B command vertex data for AGP.\n"); 556203288Srnoland ret = 1; 557203288Srnoland break; 558203288Srnoland } 559203288Srnoland 560203288Srnoland dw_count = 0; 561203288Srnoland if (bcmd & (1 << 7)) 562203288Srnoland dw_count += (cur_seq->multitex) ? 2 : 1; 563203288Srnoland if (bcmd & (1 << 8)) 564203288Srnoland dw_count += (cur_seq->multitex) ? 2 : 1; 565203288Srnoland if (bcmd & (1 << 9)) 566203288Srnoland dw_count++; 567203288Srnoland if (bcmd & (1 << 10)) 568203288Srnoland dw_count++; 569203288Srnoland if (bcmd & (1 << 11)) 570203288Srnoland dw_count++; 571203288Srnoland if (bcmd & (1 << 12)) 572203288Srnoland dw_count++; 573203288Srnoland if (bcmd & (1 << 13)) 574203288Srnoland dw_count++; 575203288Srnoland if (bcmd & (1 << 14)) 576203288Srnoland dw_count++; 577203288Srnoland 578203288Srnoland while (buf < buf_end) { 579203288Srnoland if (*buf == a_fire) { 580203288Srnoland if (dev_priv->num_fire_offsets >= 581203288Srnoland VIA_FIRE_BUF_SIZE) { 582203288Srnoland DRM_ERROR("Fire offset buffer full.\n"); 583203288Srnoland ret = 1; 584203288Srnoland break; 585203288Srnoland } 586203288Srnoland dev_priv->fire_offsets[dev_priv-> 587203288Srnoland num_fire_offsets++] = 588203288Srnoland buf; 589203288Srnoland have_fire = 1; 590203288Srnoland buf++; 591203288Srnoland if (buf < buf_end && *buf == a_fire) 592203288Srnoland buf++; 593203288Srnoland break; 594203288Srnoland } 595203288Srnoland if ((*buf == HALCYON_HEADER2) || 596203288Srnoland ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) { 597203288Srnoland DRM_ERROR("Missing Vertex Fire command, " 598203288Srnoland "Stray Vertex Fire command or verifier " 599203288Srnoland "lost sync.\n"); 600203288Srnoland ret = 1; 601203288Srnoland break; 602203288Srnoland } 603203288Srnoland if ((ret = eat_words(&buf, buf_end, dw_count))) 604203288Srnoland break; 605203288Srnoland } 606203288Srnoland if (buf >= buf_end && !have_fire) { 607203288Srnoland DRM_ERROR("Missing Vertex Fire command or verifier " 608203288Srnoland "lost sync.\n"); 609203288Srnoland ret = 1; 610203288Srnoland break; 611203288Srnoland } 612203288Srnoland if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) { 613203288Srnoland DRM_ERROR("AGP Primitive list end misaligned.\n"); 614203288Srnoland ret = 1; 615203288Srnoland break; 616203288Srnoland } 617203288Srnoland } 618203288Srnoland *buffer = buf; 619203288Srnoland return ret; 620203288Srnoland} 621203288Srnoland 622203288Srnolandstatic __inline__ verifier_state_t 623203288Srnolandvia_check_header2(uint32_t const **buffer, const uint32_t * buf_end, 624203288Srnoland drm_via_state_t * hc_state) 625203288Srnoland{ 626203288Srnoland uint32_t cmd; 627203288Srnoland int hz_mode; 628203288Srnoland hazard_t hz; 629203288Srnoland const uint32_t *buf = *buffer; 630203288Srnoland const hazard_t *hz_table; 631203288Srnoland 632203288Srnoland if ((buf_end - buf) < 2) { 633203288Srnoland DRM_ERROR 634203288Srnoland ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); 635203288Srnoland return state_error; 636203288Srnoland } 637203288Srnoland buf++; 638203288Srnoland cmd = (*buf++ & 0xFFFF0000) >> 16; 639203288Srnoland 640203288Srnoland switch (cmd) { 641203288Srnoland case HC_ParaType_CmdVdata: 642203288Srnoland if (via_check_prim_list(&buf, buf_end, hc_state)) 643203288Srnoland return state_error; 644203288Srnoland *buffer = buf; 645203288Srnoland return state_command; 646203288Srnoland case HC_ParaType_NotTex: 647203288Srnoland hz_table = table1; 648203288Srnoland break; 649203288Srnoland case HC_ParaType_Tex: 650203288Srnoland hc_state->texture = 0; 651203288Srnoland hz_table = table2; 652203288Srnoland break; 653203288Srnoland case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)): 654203288Srnoland hc_state->texture = 1; 655203288Srnoland hz_table = table2; 656203288Srnoland break; 657203288Srnoland case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)): 658203288Srnoland hz_table = table3; 659203288Srnoland break; 660203288Srnoland case HC_ParaType_Auto: 661203288Srnoland if (eat_words(&buf, buf_end, 2)) 662203288Srnoland return state_error; 663203288Srnoland *buffer = buf; 664203288Srnoland return state_command; 665203288Srnoland case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)): 666203288Srnoland if (eat_words(&buf, buf_end, 32)) 667203288Srnoland return state_error; 668203288Srnoland *buffer = buf; 669203288Srnoland return state_command; 670203288Srnoland case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)): 671203288Srnoland case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)): 672203288Srnoland DRM_ERROR("Texture palettes are rejected because of " 673203288Srnoland "lack of info how to determine their size.\n"); 674203288Srnoland return state_error; 675203288Srnoland case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)): 676203288Srnoland DRM_ERROR("Fog factor palettes are rejected because of " 677203288Srnoland "lack of info how to determine their size.\n"); 678203288Srnoland return state_error; 679203288Srnoland default: 680203288Srnoland 681203288Srnoland /* 682203288Srnoland * There are some unimplemented HC_ParaTypes here, that 683203288Srnoland * need to be implemented if the Mesa driver is extended. 684203288Srnoland */ 685203288Srnoland 686203288Srnoland DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 " 687203288Srnoland "DMA subcommand: 0x%x. Previous dword: 0x%x\n", 688203288Srnoland cmd, *(buf - 2)); 689203288Srnoland *buffer = buf; 690203288Srnoland return state_error; 691203288Srnoland } 692203288Srnoland 693203288Srnoland while (buf < buf_end) { 694203288Srnoland cmd = *buf++; 695203288Srnoland if ((hz = hz_table[cmd >> 24])) { 696203288Srnoland if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) { 697203288Srnoland if (hz_mode == 1) { 698203288Srnoland buf--; 699203288Srnoland break; 700203288Srnoland } 701203288Srnoland return state_error; 702203288Srnoland } 703203288Srnoland } else if (hc_state->unfinished && 704203288Srnoland finish_current_sequence(hc_state)) { 705203288Srnoland return state_error; 706203288Srnoland } 707203288Srnoland } 708203288Srnoland if (hc_state->unfinished && finish_current_sequence(hc_state)) { 709203288Srnoland return state_error; 710203288Srnoland } 711203288Srnoland *buffer = buf; 712203288Srnoland return state_command; 713203288Srnoland} 714203288Srnoland 715203288Srnolandstatic __inline__ verifier_state_t 716203288Srnolandvia_parse_header2(drm_via_private_t * dev_priv, uint32_t const **buffer, 717203288Srnoland const uint32_t * buf_end, int *fire_count) 718203288Srnoland{ 719203288Srnoland uint32_t cmd; 720203288Srnoland const uint32_t *buf = *buffer; 721203288Srnoland const uint32_t *next_fire; 722203288Srnoland int burst = 0; 723203288Srnoland 724203288Srnoland next_fire = dev_priv->fire_offsets[*fire_count]; 725203288Srnoland buf++; 726203288Srnoland cmd = (*buf & 0xFFFF0000) >> 16; 727203288Srnoland VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++); 728203288Srnoland switch (cmd) { 729203288Srnoland case HC_ParaType_CmdVdata: 730203288Srnoland while ((buf < buf_end) && 731203288Srnoland (*fire_count < dev_priv->num_fire_offsets) && 732203288Srnoland (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) { 733203288Srnoland while (buf <= next_fire) { 734203288Srnoland VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + 735203288Srnoland (burst & 63), *buf++); 736203288Srnoland burst += 4; 737203288Srnoland } 738203288Srnoland if ((buf < buf_end) 739203288Srnoland && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) 740203288Srnoland buf++; 741203288Srnoland 742203288Srnoland if (++(*fire_count) < dev_priv->num_fire_offsets) 743203288Srnoland next_fire = dev_priv->fire_offsets[*fire_count]; 744203288Srnoland } 745203288Srnoland break; 746203288Srnoland default: 747203288Srnoland while (buf < buf_end) { 748203288Srnoland 749203288Srnoland if (*buf == HC_HEADER2 || 750203288Srnoland (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || 751203288Srnoland (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || 752203288Srnoland (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 753203288Srnoland break; 754203288Srnoland 755203288Srnoland VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + 756203288Srnoland (burst & 63), *buf++); 757203288Srnoland burst += 4; 758203288Srnoland } 759203288Srnoland } 760203288Srnoland *buffer = buf; 761203288Srnoland return state_command; 762203288Srnoland} 763203288Srnoland 764203288Srnolandstatic __inline__ int verify_mmio_address(uint32_t address) 765203288Srnoland{ 766203288Srnoland if ((address > 0x3FF) && (address < 0xC00)) { 767203288Srnoland DRM_ERROR("Invalid VIDEO DMA command. " 768203288Srnoland "Attempt to access 3D- or command burst area.\n"); 769203288Srnoland return 1; 770203288Srnoland } else if ((address > 0xCFF) && (address < 0x1300)) { 771203288Srnoland DRM_ERROR("Invalid VIDEO DMA command. " 772203288Srnoland "Attempt to access PCI DMA area.\n"); 773203288Srnoland return 1; 774203288Srnoland } else if (address > 0x13FF) { 775203288Srnoland DRM_ERROR("Invalid VIDEO DMA command. " 776203288Srnoland "Attempt to access VGA registers.\n"); 777203288Srnoland return 1; 778203288Srnoland } 779203288Srnoland return 0; 780203288Srnoland} 781203288Srnoland 782203288Srnolandstatic __inline__ int 783203288Srnolandverify_video_tail(uint32_t const **buffer, const uint32_t * buf_end, 784203288Srnoland uint32_t dwords) 785203288Srnoland{ 786203288Srnoland const uint32_t *buf = *buffer; 787203288Srnoland 788203288Srnoland if (buf_end - buf < dwords) { 789203288Srnoland DRM_ERROR("Illegal termination of video command.\n"); 790203288Srnoland return 1; 791203288Srnoland } 792203288Srnoland while (dwords--) { 793203288Srnoland if (*buf++) { 794203288Srnoland DRM_ERROR("Illegal video command tail.\n"); 795203288Srnoland return 1; 796203288Srnoland } 797203288Srnoland } 798203288Srnoland *buffer = buf; 799203288Srnoland return 0; 800203288Srnoland} 801203288Srnoland 802203288Srnolandstatic __inline__ verifier_state_t 803203288Srnolandvia_check_header1(uint32_t const **buffer, const uint32_t * buf_end) 804203288Srnoland{ 805203288Srnoland uint32_t cmd; 806203288Srnoland const uint32_t *buf = *buffer; 807203288Srnoland verifier_state_t ret = state_command; 808203288Srnoland 809203288Srnoland while (buf < buf_end) { 810203288Srnoland cmd = *buf; 811203288Srnoland if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) && 812203288Srnoland (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { 813203288Srnoland if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 814203288Srnoland break; 815203288Srnoland DRM_ERROR("Invalid HALCYON_HEADER1 command. " 816203288Srnoland "Attempt to access 3D- or command burst area.\n"); 817203288Srnoland ret = state_error; 818203288Srnoland break; 819203288Srnoland } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) { 820203288Srnoland if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 821203288Srnoland break; 822203288Srnoland DRM_ERROR("Invalid HALCYON_HEADER1 command. " 823203288Srnoland "Attempt to access VGA registers.\n"); 824203288Srnoland ret = state_error; 825203288Srnoland break; 826203288Srnoland } else { 827203288Srnoland buf += 2; 828203288Srnoland } 829203288Srnoland } 830203288Srnoland *buffer = buf; 831203288Srnoland return ret; 832203288Srnoland} 833203288Srnoland 834203288Srnolandstatic __inline__ verifier_state_t 835203288Srnolandvia_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer, 836203288Srnoland const uint32_t * buf_end) 837203288Srnoland{ 838203288Srnoland register uint32_t cmd; 839203288Srnoland const uint32_t *buf = *buffer; 840203288Srnoland 841203288Srnoland while (buf < buf_end) { 842203288Srnoland cmd = *buf; 843203288Srnoland if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 844203288Srnoland break; 845203288Srnoland VIA_WRITE((cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); 846203288Srnoland buf++; 847203288Srnoland } 848203288Srnoland *buffer = buf; 849203288Srnoland return state_command; 850203288Srnoland} 851203288Srnoland 852203288Srnolandstatic __inline__ verifier_state_t 853203288Srnolandvia_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end) 854203288Srnoland{ 855203288Srnoland uint32_t data; 856203288Srnoland const uint32_t *buf = *buffer; 857203288Srnoland 858203288Srnoland if (buf_end - buf < 4) { 859203288Srnoland DRM_ERROR("Illegal termination of video header5 command\n"); 860203288Srnoland return state_error; 861203288Srnoland } 862203288Srnoland 863203288Srnoland data = *buf++ & ~VIA_VIDEOMASK; 864203288Srnoland if (verify_mmio_address(data)) 865203288Srnoland return state_error; 866203288Srnoland 867203288Srnoland data = *buf++; 868203288Srnoland if (*buf++ != 0x00F50000) { 869203288Srnoland DRM_ERROR("Illegal header5 header data\n"); 870203288Srnoland return state_error; 871203288Srnoland } 872203288Srnoland if (*buf++ != 0x00000000) { 873203288Srnoland DRM_ERROR("Illegal header5 header data\n"); 874203288Srnoland return state_error; 875203288Srnoland } 876203288Srnoland if (eat_words(&buf, buf_end, data)) 877203288Srnoland return state_error; 878203288Srnoland if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 879203288Srnoland return state_error; 880203288Srnoland *buffer = buf; 881203288Srnoland return state_command; 882203288Srnoland 883203288Srnoland} 884203288Srnoland 885203288Srnolandstatic __inline__ verifier_state_t 886203288Srnolandvia_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer, 887203288Srnoland const uint32_t * buf_end) 888203288Srnoland{ 889203288Srnoland uint32_t addr, count, i; 890203288Srnoland const uint32_t *buf = *buffer; 891203288Srnoland 892203288Srnoland addr = *buf++ & ~VIA_VIDEOMASK; 893203288Srnoland i = count = *buf; 894203288Srnoland buf += 3; 895203288Srnoland while (i--) { 896203288Srnoland VIA_WRITE(addr, *buf++); 897203288Srnoland } 898203288Srnoland if (count & 3) 899203288Srnoland buf += 4 - (count & 3); 900203288Srnoland *buffer = buf; 901203288Srnoland return state_command; 902203288Srnoland} 903203288Srnoland 904203288Srnolandstatic __inline__ verifier_state_t 905203288Srnolandvia_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end) 906203288Srnoland{ 907203288Srnoland uint32_t data; 908203288Srnoland const uint32_t *buf = *buffer; 909203288Srnoland uint32_t i; 910203288Srnoland 911203288Srnoland if (buf_end - buf < 4) { 912203288Srnoland DRM_ERROR("Illegal termination of video header6 command\n"); 913203288Srnoland return state_error; 914203288Srnoland } 915203288Srnoland buf++; 916203288Srnoland data = *buf++; 917203288Srnoland if (*buf++ != 0x00F60000) { 918203288Srnoland DRM_ERROR("Illegal header6 header data\n"); 919203288Srnoland return state_error; 920203288Srnoland } 921203288Srnoland if (*buf++ != 0x00000000) { 922203288Srnoland DRM_ERROR("Illegal header6 header data\n"); 923203288Srnoland return state_error; 924203288Srnoland } 925203288Srnoland if ((buf_end - buf) < (data << 1)) { 926203288Srnoland DRM_ERROR("Illegal termination of video header6 command\n"); 927203288Srnoland return state_error; 928203288Srnoland } 929203288Srnoland for (i = 0; i < data; ++i) { 930203288Srnoland if (verify_mmio_address(*buf++)) 931203288Srnoland return state_error; 932203288Srnoland buf++; 933203288Srnoland } 934203288Srnoland data <<= 1; 935203288Srnoland if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 936203288Srnoland return state_error; 937203288Srnoland *buffer = buf; 938203288Srnoland return state_command; 939203288Srnoland} 940203288Srnoland 941203288Srnolandstatic __inline__ verifier_state_t 942203288Srnolandvia_parse_vheader6(drm_via_private_t * dev_priv, uint32_t const **buffer, 943203288Srnoland const uint32_t * buf_end) 944203288Srnoland{ 945203288Srnoland 946203288Srnoland uint32_t addr, count, i; 947203288Srnoland const uint32_t *buf = *buffer; 948203288Srnoland 949203288Srnoland i = count = *++buf; 950203288Srnoland buf += 3; 951203288Srnoland while (i--) { 952203288Srnoland addr = *buf++; 953203288Srnoland VIA_WRITE(addr, *buf++); 954203288Srnoland } 955203288Srnoland count <<= 1; 956203288Srnoland if (count & 3) 957203288Srnoland buf += 4 - (count & 3); 958203288Srnoland *buffer = buf; 959203288Srnoland return state_command; 960203288Srnoland} 961203288Srnoland 962203288Srnolandint 963203288Srnolandvia_verify_command_stream(const uint32_t * buf, unsigned int size, 964203288Srnoland struct drm_device * dev, int agp) 965203288Srnoland{ 966203288Srnoland 967203288Srnoland drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 968203288Srnoland drm_via_state_t *hc_state = &dev_priv->hc_state; 969203288Srnoland drm_via_state_t saved_state = *hc_state; 970203288Srnoland uint32_t cmd; 971203288Srnoland const uint32_t *buf_end = buf + (size >> 2); 972203288Srnoland verifier_state_t state = state_command; 973203288Srnoland int cme_video; 974203288Srnoland int supported_3d; 975203288Srnoland 976203288Srnoland cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || 977203288Srnoland dev_priv->chipset == VIA_DX9_0); 978203288Srnoland 979203288Srnoland supported_3d = dev_priv->chipset != VIA_DX9_0; 980203288Srnoland 981203288Srnoland hc_state->dev = dev; 982203288Srnoland hc_state->unfinished = no_sequence; 983203288Srnoland hc_state->map_cache = NULL; 984203288Srnoland hc_state->agp = agp; 985203288Srnoland hc_state->buf_start = buf; 986203288Srnoland dev_priv->num_fire_offsets = 0; 987203288Srnoland 988203288Srnoland while (buf < buf_end) { 989203288Srnoland 990203288Srnoland switch (state) { 991203288Srnoland case state_header2: 992203288Srnoland state = via_check_header2(&buf, buf_end, hc_state); 993203288Srnoland break; 994203288Srnoland case state_header1: 995203288Srnoland state = via_check_header1(&buf, buf_end); 996203288Srnoland break; 997203288Srnoland case state_vheader5: 998203288Srnoland state = via_check_vheader5(&buf, buf_end); 999203288Srnoland break; 1000203288Srnoland case state_vheader6: 1001203288Srnoland state = via_check_vheader6(&buf, buf_end); 1002203288Srnoland break; 1003203288Srnoland case state_command: 1004203288Srnoland if ((HALCYON_HEADER2 == (cmd = *buf)) && 1005203288Srnoland supported_3d) 1006203288Srnoland state = state_header2; 1007203288Srnoland else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 1008203288Srnoland state = state_header1; 1009203288Srnoland else if (cme_video 1010203288Srnoland && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) 1011203288Srnoland state = state_vheader5; 1012203288Srnoland else if (cme_video 1013203288Srnoland && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 1014203288Srnoland state = state_vheader6; 1015203288Srnoland else if ((cmd == HALCYON_HEADER2) && !supported_3d) { 1016203288Srnoland DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); 1017203288Srnoland state = state_error; 1018203288Srnoland } else { 1019203288Srnoland DRM_ERROR 1020203288Srnoland ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", 1021203288Srnoland cmd); 1022203288Srnoland state = state_error; 1023203288Srnoland } 1024203288Srnoland break; 1025203288Srnoland case state_error: 1026203288Srnoland default: 1027203288Srnoland *hc_state = saved_state; 1028203288Srnoland return -EINVAL; 1029203288Srnoland } 1030203288Srnoland } 1031203288Srnoland if (state == state_error) { 1032203288Srnoland *hc_state = saved_state; 1033203288Srnoland return -EINVAL; 1034203288Srnoland } 1035203288Srnoland return 0; 1036203288Srnoland} 1037203288Srnoland 1038203288Srnolandint 1039203288Srnolandvia_parse_command_stream(struct drm_device * dev, const uint32_t * buf, 1040203288Srnoland unsigned int size) 1041203288Srnoland{ 1042203288Srnoland 1043203288Srnoland drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 1044203288Srnoland uint32_t cmd; 1045203288Srnoland const uint32_t *buf_end = buf + (size >> 2); 1046203288Srnoland verifier_state_t state = state_command; 1047203288Srnoland int fire_count = 0; 1048203288Srnoland 1049203288Srnoland while (buf < buf_end) { 1050203288Srnoland 1051203288Srnoland switch (state) { 1052203288Srnoland case state_header2: 1053203288Srnoland state = 1054203288Srnoland via_parse_header2(dev_priv, &buf, buf_end, 1055203288Srnoland &fire_count); 1056203288Srnoland break; 1057203288Srnoland case state_header1: 1058203288Srnoland state = via_parse_header1(dev_priv, &buf, buf_end); 1059203288Srnoland break; 1060203288Srnoland case state_vheader5: 1061203288Srnoland state = via_parse_vheader5(dev_priv, &buf, buf_end); 1062203288Srnoland break; 1063203288Srnoland case state_vheader6: 1064203288Srnoland state = via_parse_vheader6(dev_priv, &buf, buf_end); 1065203288Srnoland break; 1066203288Srnoland case state_command: 1067203288Srnoland if (HALCYON_HEADER2 == (cmd = *buf)) 1068203288Srnoland state = state_header2; 1069203288Srnoland else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 1070203288Srnoland state = state_header1; 1071203288Srnoland else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) 1072203288Srnoland state = state_vheader5; 1073203288Srnoland else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 1074203288Srnoland state = state_vheader6; 1075203288Srnoland else { 1076203288Srnoland DRM_ERROR 1077203288Srnoland ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", 1078203288Srnoland cmd); 1079203288Srnoland state = state_error; 1080203288Srnoland } 1081203288Srnoland break; 1082203288Srnoland case state_error: 1083203288Srnoland default: 1084203288Srnoland return -EINVAL; 1085203288Srnoland } 1086203288Srnoland } 1087203288Srnoland if (state == state_error) { 1088203288Srnoland return -EINVAL; 1089203288Srnoland } 1090203288Srnoland return 0; 1091203288Srnoland} 1092203288Srnoland 1093203288Srnolandstatic void 1094203288Srnolandsetup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) 1095203288Srnoland{ 1096203288Srnoland int i; 1097203288Srnoland 1098203288Srnoland for (i = 0; i < 256; ++i) { 1099203288Srnoland table[i] = forbidden_command; 1100203288Srnoland } 1101203288Srnoland 1102203288Srnoland for (i = 0; i < size; ++i) { 1103203288Srnoland table[init_table[i].code] = init_table[i].hz; 1104203288Srnoland } 1105203288Srnoland} 1106203288Srnoland 1107203288Srnolandvoid via_init_command_verifier(void) 1108203288Srnoland{ 1109203288Srnoland setup_hazard_table(init_table1, table1, 1110203288Srnoland sizeof(init_table1) / sizeof(hz_init_t)); 1111203288Srnoland setup_hazard_table(init_table2, table2, 1112203288Srnoland sizeof(init_table2) / sizeof(hz_init_t)); 1113203288Srnoland setup_hazard_table(init_table3, table3, 1114203288Srnoland sizeof(init_table3) / sizeof(hz_init_t)); 1115203288Srnoland} 1116