1 1.2 riastrad /* $NetBSD: via_verifier.c,v 1.3 2021/12/18 23:45:44 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2004 The Unichrome Project. All Rights Reserved. 5 1.1 riastrad * Copyright 2005 Thomas Hellstrom. All Rights Reserved. 6 1.1 riastrad * 7 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 8 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 9 1.1 riastrad * to deal in the Software without restriction, including without limitation 10 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sub license, 11 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 12 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 13 1.1 riastrad * 14 1.1 riastrad * The above copyright notice and this permission notice (including the 15 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 16 1.1 riastrad * of the Software. 17 1.1 riastrad * 18 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 1.1 riastrad * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 1.1 riastrad * DEALINGS IN THE SOFTWARE. 25 1.1 riastrad * 26 1.1 riastrad * Author: Thomas Hellstrom 2004, 2005. 27 1.1 riastrad * This code was written using docs obtained under NDA from VIA Inc. 28 1.1 riastrad * 29 1.1 riastrad * Don't run this code directly on an AGP buffer. Due to cache problems it will 30 1.1 riastrad * be very slow. 31 1.1 riastrad */ 32 1.1 riastrad 33 1.2 riastrad #include <sys/cdefs.h> 34 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: via_verifier.c,v 1.3 2021/12/18 23:45:44 riastradh Exp $"); 35 1.2 riastrad 36 1.3 riastrad #include <drm/drm_device.h> 37 1.3 riastrad #include <drm/drm_legacy.h> 38 1.3 riastrad #include <drm/via_drm.h> 39 1.3 riastrad 40 1.1 riastrad #include "via_3d_reg.h" 41 1.3 riastrad #include "via_drv.h" 42 1.1 riastrad #include "via_verifier.h" 43 1.1 riastrad 44 1.1 riastrad typedef enum { 45 1.1 riastrad state_command, 46 1.1 riastrad state_header2, 47 1.1 riastrad state_header1, 48 1.1 riastrad state_vheader5, 49 1.1 riastrad state_vheader6, 50 1.1 riastrad state_error 51 1.1 riastrad } verifier_state_t; 52 1.1 riastrad 53 1.1 riastrad typedef enum { 54 1.1 riastrad no_check = 0, 55 1.1 riastrad check_for_header2, 56 1.1 riastrad check_for_header1, 57 1.1 riastrad check_for_header2_err, 58 1.1 riastrad check_for_header1_err, 59 1.1 riastrad check_for_fire, 60 1.1 riastrad check_z_buffer_addr0, 61 1.1 riastrad check_z_buffer_addr1, 62 1.1 riastrad check_z_buffer_addr_mode, 63 1.1 riastrad check_destination_addr0, 64 1.1 riastrad check_destination_addr1, 65 1.1 riastrad check_destination_addr_mode, 66 1.1 riastrad check_for_dummy, 67 1.1 riastrad check_for_dd, 68 1.1 riastrad check_texture_addr0, 69 1.1 riastrad check_texture_addr1, 70 1.1 riastrad check_texture_addr2, 71 1.1 riastrad check_texture_addr3, 72 1.1 riastrad check_texture_addr4, 73 1.1 riastrad check_texture_addr5, 74 1.1 riastrad check_texture_addr6, 75 1.1 riastrad check_texture_addr7, 76 1.1 riastrad check_texture_addr8, 77 1.1 riastrad check_texture_addr_mode, 78 1.1 riastrad check_for_vertex_count, 79 1.1 riastrad check_number_texunits, 80 1.1 riastrad forbidden_command 81 1.1 riastrad } hazard_t; 82 1.1 riastrad 83 1.1 riastrad /* 84 1.1 riastrad * Associates each hazard above with a possible multi-command 85 1.1 riastrad * sequence. For example an address that is split over multiple 86 1.1 riastrad * commands and that needs to be checked at the first command 87 1.1 riastrad * that does not include any part of the address. 88 1.1 riastrad */ 89 1.1 riastrad 90 1.1 riastrad static drm_via_sequence_t seqs[] = { 91 1.1 riastrad no_sequence, 92 1.1 riastrad no_sequence, 93 1.1 riastrad no_sequence, 94 1.1 riastrad no_sequence, 95 1.1 riastrad no_sequence, 96 1.1 riastrad no_sequence, 97 1.1 riastrad z_address, 98 1.1 riastrad z_address, 99 1.1 riastrad z_address, 100 1.1 riastrad dest_address, 101 1.1 riastrad dest_address, 102 1.1 riastrad dest_address, 103 1.1 riastrad no_sequence, 104 1.1 riastrad no_sequence, 105 1.1 riastrad tex_address, 106 1.1 riastrad tex_address, 107 1.1 riastrad tex_address, 108 1.1 riastrad tex_address, 109 1.1 riastrad tex_address, 110 1.1 riastrad tex_address, 111 1.1 riastrad tex_address, 112 1.1 riastrad tex_address, 113 1.1 riastrad tex_address, 114 1.1 riastrad tex_address, 115 1.1 riastrad no_sequence 116 1.1 riastrad }; 117 1.1 riastrad 118 1.1 riastrad typedef struct { 119 1.1 riastrad unsigned int code; 120 1.1 riastrad hazard_t hz; 121 1.1 riastrad } hz_init_t; 122 1.1 riastrad 123 1.1 riastrad static hz_init_t init_table1[] = { 124 1.1 riastrad {0xf2, check_for_header2_err}, 125 1.1 riastrad {0xf0, check_for_header1_err}, 126 1.1 riastrad {0xee, check_for_fire}, 127 1.1 riastrad {0xcc, check_for_dummy}, 128 1.1 riastrad {0xdd, check_for_dd}, 129 1.1 riastrad {0x00, no_check}, 130 1.1 riastrad {0x10, check_z_buffer_addr0}, 131 1.1 riastrad {0x11, check_z_buffer_addr1}, 132 1.1 riastrad {0x12, check_z_buffer_addr_mode}, 133 1.1 riastrad {0x13, no_check}, 134 1.1 riastrad {0x14, no_check}, 135 1.1 riastrad {0x15, no_check}, 136 1.1 riastrad {0x23, no_check}, 137 1.1 riastrad {0x24, no_check}, 138 1.1 riastrad {0x33, no_check}, 139 1.1 riastrad {0x34, no_check}, 140 1.1 riastrad {0x35, no_check}, 141 1.1 riastrad {0x36, no_check}, 142 1.1 riastrad {0x37, no_check}, 143 1.1 riastrad {0x38, no_check}, 144 1.1 riastrad {0x39, no_check}, 145 1.1 riastrad {0x3A, no_check}, 146 1.1 riastrad {0x3B, no_check}, 147 1.1 riastrad {0x3C, no_check}, 148 1.1 riastrad {0x3D, no_check}, 149 1.1 riastrad {0x3E, no_check}, 150 1.1 riastrad {0x40, check_destination_addr0}, 151 1.1 riastrad {0x41, check_destination_addr1}, 152 1.1 riastrad {0x42, check_destination_addr_mode}, 153 1.1 riastrad {0x43, no_check}, 154 1.1 riastrad {0x44, no_check}, 155 1.1 riastrad {0x50, no_check}, 156 1.1 riastrad {0x51, no_check}, 157 1.1 riastrad {0x52, no_check}, 158 1.1 riastrad {0x53, no_check}, 159 1.1 riastrad {0x54, no_check}, 160 1.1 riastrad {0x55, no_check}, 161 1.1 riastrad {0x56, no_check}, 162 1.1 riastrad {0x57, no_check}, 163 1.1 riastrad {0x58, no_check}, 164 1.1 riastrad {0x70, no_check}, 165 1.1 riastrad {0x71, no_check}, 166 1.1 riastrad {0x78, no_check}, 167 1.1 riastrad {0x79, no_check}, 168 1.1 riastrad {0x7A, no_check}, 169 1.1 riastrad {0x7B, no_check}, 170 1.1 riastrad {0x7C, no_check}, 171 1.1 riastrad {0x7D, check_for_vertex_count} 172 1.1 riastrad }; 173 1.1 riastrad 174 1.1 riastrad static hz_init_t init_table2[] = { 175 1.1 riastrad {0xf2, check_for_header2_err}, 176 1.1 riastrad {0xf0, check_for_header1_err}, 177 1.1 riastrad {0xee, check_for_fire}, 178 1.1 riastrad {0xcc, check_for_dummy}, 179 1.1 riastrad {0x00, check_texture_addr0}, 180 1.1 riastrad {0x01, check_texture_addr0}, 181 1.1 riastrad {0x02, check_texture_addr0}, 182 1.1 riastrad {0x03, check_texture_addr0}, 183 1.1 riastrad {0x04, check_texture_addr0}, 184 1.1 riastrad {0x05, check_texture_addr0}, 185 1.1 riastrad {0x06, check_texture_addr0}, 186 1.1 riastrad {0x07, check_texture_addr0}, 187 1.1 riastrad {0x08, check_texture_addr0}, 188 1.1 riastrad {0x09, check_texture_addr0}, 189 1.1 riastrad {0x20, check_texture_addr1}, 190 1.1 riastrad {0x21, check_texture_addr1}, 191 1.1 riastrad {0x22, check_texture_addr1}, 192 1.1 riastrad {0x23, check_texture_addr4}, 193 1.1 riastrad {0x2B, check_texture_addr3}, 194 1.1 riastrad {0x2C, check_texture_addr3}, 195 1.1 riastrad {0x2D, check_texture_addr3}, 196 1.1 riastrad {0x2E, check_texture_addr3}, 197 1.1 riastrad {0x2F, check_texture_addr3}, 198 1.1 riastrad {0x30, check_texture_addr3}, 199 1.1 riastrad {0x31, check_texture_addr3}, 200 1.1 riastrad {0x32, check_texture_addr3}, 201 1.1 riastrad {0x33, check_texture_addr3}, 202 1.1 riastrad {0x34, check_texture_addr3}, 203 1.1 riastrad {0x4B, check_texture_addr5}, 204 1.1 riastrad {0x4C, check_texture_addr6}, 205 1.1 riastrad {0x51, check_texture_addr7}, 206 1.1 riastrad {0x52, check_texture_addr8}, 207 1.1 riastrad {0x77, check_texture_addr2}, 208 1.1 riastrad {0x78, no_check}, 209 1.1 riastrad {0x79, no_check}, 210 1.1 riastrad {0x7A, no_check}, 211 1.1 riastrad {0x7B, check_texture_addr_mode}, 212 1.1 riastrad {0x7C, no_check}, 213 1.1 riastrad {0x7D, no_check}, 214 1.1 riastrad {0x7E, no_check}, 215 1.1 riastrad {0x7F, no_check}, 216 1.1 riastrad {0x80, no_check}, 217 1.1 riastrad {0x81, no_check}, 218 1.1 riastrad {0x82, no_check}, 219 1.1 riastrad {0x83, no_check}, 220 1.1 riastrad {0x85, no_check}, 221 1.1 riastrad {0x86, no_check}, 222 1.1 riastrad {0x87, no_check}, 223 1.1 riastrad {0x88, no_check}, 224 1.1 riastrad {0x89, no_check}, 225 1.1 riastrad {0x8A, no_check}, 226 1.1 riastrad {0x90, no_check}, 227 1.1 riastrad {0x91, no_check}, 228 1.1 riastrad {0x92, no_check}, 229 1.1 riastrad {0x93, no_check} 230 1.1 riastrad }; 231 1.1 riastrad 232 1.1 riastrad static hz_init_t init_table3[] = { 233 1.1 riastrad {0xf2, check_for_header2_err}, 234 1.1 riastrad {0xf0, check_for_header1_err}, 235 1.1 riastrad {0xcc, check_for_dummy}, 236 1.1 riastrad {0x00, check_number_texunits} 237 1.1 riastrad }; 238 1.1 riastrad 239 1.1 riastrad static hazard_t table1[256]; 240 1.1 riastrad static hazard_t table2[256]; 241 1.1 riastrad static hazard_t table3[256]; 242 1.1 riastrad 243 1.1 riastrad static __inline__ int 244 1.1 riastrad eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words) 245 1.1 riastrad { 246 1.1 riastrad if ((buf_end - *buf) >= num_words) { 247 1.1 riastrad *buf += num_words; 248 1.1 riastrad return 0; 249 1.1 riastrad } 250 1.1 riastrad DRM_ERROR("Illegal termination of DMA command buffer\n"); 251 1.1 riastrad return 1; 252 1.1 riastrad } 253 1.1 riastrad 254 1.1 riastrad /* 255 1.1 riastrad * Partially stolen from drm_memory.h 256 1.1 riastrad */ 257 1.1 riastrad 258 1.1 riastrad static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, 259 1.1 riastrad unsigned long offset, 260 1.1 riastrad unsigned long size, 261 1.1 riastrad struct drm_device *dev) 262 1.1 riastrad { 263 1.1 riastrad struct drm_map_list *r_list; 264 1.1 riastrad drm_local_map_t *map = seq->map_cache; 265 1.1 riastrad 266 1.1 riastrad if (map && map->offset <= offset 267 1.1 riastrad && (offset + size) <= (map->offset + map->size)) { 268 1.1 riastrad return map; 269 1.1 riastrad } 270 1.1 riastrad 271 1.1 riastrad list_for_each_entry(r_list, &dev->maplist, head) { 272 1.1 riastrad map = r_list->map; 273 1.1 riastrad if (!map) 274 1.1 riastrad continue; 275 1.1 riastrad if (map->offset <= offset 276 1.1 riastrad && (offset + size) <= (map->offset + map->size) 277 1.1 riastrad && !(map->flags & _DRM_RESTRICTED) 278 1.1 riastrad && (map->type == _DRM_AGP)) { 279 1.1 riastrad seq->map_cache = map; 280 1.1 riastrad return map; 281 1.1 riastrad } 282 1.1 riastrad } 283 1.1 riastrad return NULL; 284 1.1 riastrad } 285 1.1 riastrad 286 1.1 riastrad /* 287 1.1 riastrad * Require that all AGP texture levels reside in the same AGP map which should 288 1.1 riastrad * be mappable by the client. This is not a big restriction. 289 1.1 riastrad * FIXME: To actually enforce this security policy strictly, drm_rmmap 290 1.1 riastrad * would have to wait for dma quiescent before removing an AGP map. 291 1.1 riastrad * The via_drm_lookup_agp_map call in reality seems to take 292 1.1 riastrad * very little CPU time. 293 1.1 riastrad */ 294 1.1 riastrad 295 1.1 riastrad static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) 296 1.1 riastrad { 297 1.1 riastrad switch (cur_seq->unfinished) { 298 1.1 riastrad case z_address: 299 1.1 riastrad DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr); 300 1.1 riastrad break; 301 1.1 riastrad case dest_address: 302 1.1 riastrad DRM_DEBUG("Destination start address is 0x%x\n", 303 1.1 riastrad cur_seq->d_addr); 304 1.1 riastrad break; 305 1.1 riastrad case tex_address: 306 1.1 riastrad if (cur_seq->agp_texture) { 307 1.1 riastrad unsigned start = 308 1.1 riastrad cur_seq->tex_level_lo[cur_seq->texture]; 309 1.1 riastrad unsigned end = cur_seq->tex_level_hi[cur_seq->texture]; 310 1.1 riastrad unsigned long lo = ~0, hi = 0, tmp; 311 1.1 riastrad uint32_t *addr, *pitch, *height, tex; 312 1.1 riastrad unsigned i; 313 1.1 riastrad int npot; 314 1.1 riastrad 315 1.1 riastrad if (end > 9) 316 1.1 riastrad end = 9; 317 1.1 riastrad if (start > 9) 318 1.1 riastrad start = 9; 319 1.1 riastrad 320 1.1 riastrad addr = 321 1.1 riastrad &(cur_seq->t_addr[tex = cur_seq->texture][start]); 322 1.1 riastrad pitch = &(cur_seq->pitch[tex][start]); 323 1.1 riastrad height = &(cur_seq->height[tex][start]); 324 1.1 riastrad npot = cur_seq->tex_npot[tex]; 325 1.1 riastrad for (i = start; i <= end; ++i) { 326 1.1 riastrad tmp = *addr++; 327 1.1 riastrad if (tmp < lo) 328 1.1 riastrad lo = tmp; 329 1.1 riastrad if (i == 0 && npot) 330 1.1 riastrad tmp += (*height++ * *pitch++); 331 1.1 riastrad else 332 1.1 riastrad tmp += (*height++ << *pitch++); 333 1.1 riastrad if (tmp > hi) 334 1.1 riastrad hi = tmp; 335 1.1 riastrad } 336 1.1 riastrad 337 1.1 riastrad if (!via_drm_lookup_agp_map 338 1.1 riastrad (cur_seq, lo, hi - lo, cur_seq->dev)) { 339 1.1 riastrad DRM_ERROR 340 1.1 riastrad ("AGP texture is not in allowed map\n"); 341 1.1 riastrad return 2; 342 1.1 riastrad } 343 1.1 riastrad } 344 1.1 riastrad break; 345 1.1 riastrad default: 346 1.1 riastrad break; 347 1.1 riastrad } 348 1.1 riastrad cur_seq->unfinished = no_sequence; 349 1.1 riastrad return 0; 350 1.1 riastrad } 351 1.1 riastrad 352 1.1 riastrad static __inline__ int 353 1.1 riastrad investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq) 354 1.1 riastrad { 355 1.1 riastrad register uint32_t tmp, *tmp_addr; 356 1.1 riastrad 357 1.1 riastrad if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { 358 1.1 riastrad int ret; 359 1.1 riastrad if ((ret = finish_current_sequence(cur_seq))) 360 1.1 riastrad return ret; 361 1.1 riastrad } 362 1.1 riastrad 363 1.1 riastrad switch (hz) { 364 1.1 riastrad case check_for_header2: 365 1.1 riastrad if (cmd == HALCYON_HEADER2) 366 1.1 riastrad return 1; 367 1.1 riastrad return 0; 368 1.1 riastrad case check_for_header1: 369 1.1 riastrad if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 370 1.1 riastrad return 1; 371 1.1 riastrad return 0; 372 1.1 riastrad case check_for_header2_err: 373 1.1 riastrad if (cmd == HALCYON_HEADER2) 374 1.1 riastrad return 1; 375 1.1 riastrad DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n"); 376 1.1 riastrad break; 377 1.1 riastrad case check_for_header1_err: 378 1.1 riastrad if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 379 1.1 riastrad return 1; 380 1.1 riastrad DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n"); 381 1.1 riastrad break; 382 1.1 riastrad case check_for_fire: 383 1.1 riastrad if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) 384 1.1 riastrad return 1; 385 1.1 riastrad DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n"); 386 1.1 riastrad break; 387 1.1 riastrad case check_for_dummy: 388 1.1 riastrad if (HC_DUMMY == cmd) 389 1.1 riastrad return 0; 390 1.1 riastrad DRM_ERROR("Illegal DMA HC_DUMMY command\n"); 391 1.1 riastrad break; 392 1.1 riastrad case check_for_dd: 393 1.1 riastrad if (0xdddddddd == cmd) 394 1.1 riastrad return 0; 395 1.1 riastrad DRM_ERROR("Illegal DMA 0xdddddddd command\n"); 396 1.1 riastrad break; 397 1.1 riastrad case check_z_buffer_addr0: 398 1.1 riastrad cur_seq->unfinished = z_address; 399 1.1 riastrad cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) | 400 1.1 riastrad (cmd & 0x00FFFFFF); 401 1.1 riastrad return 0; 402 1.1 riastrad case check_z_buffer_addr1: 403 1.1 riastrad cur_seq->unfinished = z_address; 404 1.1 riastrad cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) | 405 1.1 riastrad ((cmd & 0xFF) << 24); 406 1.1 riastrad return 0; 407 1.1 riastrad case check_z_buffer_addr_mode: 408 1.1 riastrad cur_seq->unfinished = z_address; 409 1.1 riastrad if ((cmd & 0x0000C000) == 0) 410 1.1 riastrad return 0; 411 1.1 riastrad DRM_ERROR("Attempt to place Z buffer in system memory\n"); 412 1.1 riastrad return 2; 413 1.1 riastrad case check_destination_addr0: 414 1.1 riastrad cur_seq->unfinished = dest_address; 415 1.1 riastrad cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) | 416 1.1 riastrad (cmd & 0x00FFFFFF); 417 1.1 riastrad return 0; 418 1.1 riastrad case check_destination_addr1: 419 1.1 riastrad cur_seq->unfinished = dest_address; 420 1.1 riastrad cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) | 421 1.1 riastrad ((cmd & 0xFF) << 24); 422 1.1 riastrad return 0; 423 1.1 riastrad case check_destination_addr_mode: 424 1.1 riastrad cur_seq->unfinished = dest_address; 425 1.1 riastrad if ((cmd & 0x0000C000) == 0) 426 1.1 riastrad return 0; 427 1.1 riastrad DRM_ERROR 428 1.1 riastrad ("Attempt to place 3D drawing buffer in system memory\n"); 429 1.1 riastrad return 2; 430 1.1 riastrad case check_texture_addr0: 431 1.1 riastrad cur_seq->unfinished = tex_address; 432 1.1 riastrad tmp = (cmd >> 24); 433 1.1 riastrad tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; 434 1.1 riastrad *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF); 435 1.1 riastrad return 0; 436 1.1 riastrad case check_texture_addr1: 437 1.1 riastrad cur_seq->unfinished = tex_address; 438 1.1 riastrad tmp = ((cmd >> 24) - 0x20); 439 1.1 riastrad tmp += tmp << 1; 440 1.1 riastrad tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; 441 1.1 riastrad *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); 442 1.1 riastrad tmp_addr++; 443 1.1 riastrad *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16); 444 1.1 riastrad tmp_addr++; 445 1.1 riastrad *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8); 446 1.1 riastrad return 0; 447 1.1 riastrad case check_texture_addr2: 448 1.1 riastrad cur_seq->unfinished = tex_address; 449 1.1 riastrad cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F; 450 1.1 riastrad cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6; 451 1.1 riastrad return 0; 452 1.1 riastrad case check_texture_addr3: 453 1.1 riastrad cur_seq->unfinished = tex_address; 454 1.1 riastrad tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); 455 1.1 riastrad if (tmp == 0 && 456 1.1 riastrad (cmd & HC_HTXnEnPit_MASK)) { 457 1.1 riastrad cur_seq->pitch[cur_seq->texture][tmp] = 458 1.1 riastrad (cmd & HC_HTXnLnPit_MASK); 459 1.1 riastrad cur_seq->tex_npot[cur_seq->texture] = 1; 460 1.1 riastrad } else { 461 1.1 riastrad cur_seq->pitch[cur_seq->texture][tmp] = 462 1.1 riastrad (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; 463 1.1 riastrad cur_seq->tex_npot[cur_seq->texture] = 0; 464 1.1 riastrad if (cmd & 0x000FFFFF) { 465 1.1 riastrad DRM_ERROR 466 1.1 riastrad ("Unimplemented texture level 0 pitch mode.\n"); 467 1.1 riastrad return 2; 468 1.1 riastrad } 469 1.1 riastrad } 470 1.1 riastrad return 0; 471 1.1 riastrad case check_texture_addr4: 472 1.1 riastrad cur_seq->unfinished = tex_address; 473 1.1 riastrad tmp_addr = &cur_seq->t_addr[cur_seq->texture][9]; 474 1.1 riastrad *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); 475 1.1 riastrad return 0; 476 1.1 riastrad case check_texture_addr5: 477 1.1 riastrad case check_texture_addr6: 478 1.1 riastrad cur_seq->unfinished = tex_address; 479 1.1 riastrad /* 480 1.1 riastrad * Texture width. We don't care since we have the pitch. 481 1.1 riastrad */ 482 1.1 riastrad return 0; 483 1.1 riastrad case check_texture_addr7: 484 1.1 riastrad cur_seq->unfinished = tex_address; 485 1.1 riastrad tmp_addr = &(cur_seq->height[cur_seq->texture][0]); 486 1.1 riastrad tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20); 487 1.1 riastrad tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16); 488 1.1 riastrad tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12); 489 1.1 riastrad tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8); 490 1.1 riastrad tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4); 491 1.1 riastrad tmp_addr[0] = 1 << (cmd & 0x0000000F); 492 1.1 riastrad return 0; 493 1.1 riastrad case check_texture_addr8: 494 1.1 riastrad cur_seq->unfinished = tex_address; 495 1.1 riastrad tmp_addr = &(cur_seq->height[cur_seq->texture][0]); 496 1.1 riastrad tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12); 497 1.1 riastrad tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8); 498 1.1 riastrad tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4); 499 1.1 riastrad tmp_addr[6] = 1 << (cmd & 0x0000000F); 500 1.1 riastrad return 0; 501 1.1 riastrad case check_texture_addr_mode: 502 1.1 riastrad cur_seq->unfinished = tex_address; 503 1.1 riastrad if (2 == (tmp = cmd & 0x00000003)) { 504 1.1 riastrad DRM_ERROR 505 1.1 riastrad ("Attempt to fetch texture from system memory.\n"); 506 1.1 riastrad return 2; 507 1.1 riastrad } 508 1.1 riastrad cur_seq->agp_texture = (tmp == 3); 509 1.1 riastrad cur_seq->tex_palette_size[cur_seq->texture] = 510 1.1 riastrad (cmd >> 16) & 0x000000007; 511 1.1 riastrad return 0; 512 1.1 riastrad case check_for_vertex_count: 513 1.1 riastrad cur_seq->vertex_count = cmd & 0x0000FFFF; 514 1.1 riastrad return 0; 515 1.1 riastrad case check_number_texunits: 516 1.1 riastrad cur_seq->multitex = (cmd >> 3) & 1; 517 1.1 riastrad return 0; 518 1.1 riastrad default: 519 1.1 riastrad DRM_ERROR("Illegal DMA data: 0x%x\n", cmd); 520 1.1 riastrad return 2; 521 1.1 riastrad } 522 1.1 riastrad return 2; 523 1.1 riastrad } 524 1.1 riastrad 525 1.1 riastrad static __inline__ int 526 1.1 riastrad via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, 527 1.1 riastrad drm_via_state_t *cur_seq) 528 1.1 riastrad { 529 1.1 riastrad drm_via_private_t *dev_priv = 530 1.1 riastrad (drm_via_private_t *) cur_seq->dev->dev_private; 531 1.1 riastrad uint32_t a_fire, bcmd, dw_count; 532 1.1 riastrad int ret = 0; 533 1.1 riastrad int have_fire; 534 1.1 riastrad const uint32_t *buf = *buffer; 535 1.1 riastrad 536 1.1 riastrad while (buf < buf_end) { 537 1.1 riastrad have_fire = 0; 538 1.1 riastrad if ((buf_end - buf) < 2) { 539 1.1 riastrad DRM_ERROR 540 1.1 riastrad ("Unexpected termination of primitive list.\n"); 541 1.1 riastrad ret = 1; 542 1.1 riastrad break; 543 1.1 riastrad } 544 1.1 riastrad if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) 545 1.1 riastrad break; 546 1.1 riastrad bcmd = *buf++; 547 1.1 riastrad if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) { 548 1.1 riastrad DRM_ERROR("Expected Vertex List A command, got 0x%x\n", 549 1.1 riastrad *buf); 550 1.1 riastrad ret = 1; 551 1.1 riastrad break; 552 1.1 riastrad } 553 1.1 riastrad a_fire = 554 1.1 riastrad *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | 555 1.1 riastrad HC_HE3Fire_MASK; 556 1.1 riastrad 557 1.1 riastrad /* 558 1.1 riastrad * How many dwords per vertex ? 559 1.1 riastrad */ 560 1.1 riastrad 561 1.1 riastrad if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) { 562 1.1 riastrad DRM_ERROR("Illegal B command vertex data for AGP.\n"); 563 1.1 riastrad ret = 1; 564 1.1 riastrad break; 565 1.1 riastrad } 566 1.1 riastrad 567 1.1 riastrad dw_count = 0; 568 1.1 riastrad if (bcmd & (1 << 7)) 569 1.1 riastrad dw_count += (cur_seq->multitex) ? 2 : 1; 570 1.1 riastrad if (bcmd & (1 << 8)) 571 1.1 riastrad dw_count += (cur_seq->multitex) ? 2 : 1; 572 1.1 riastrad if (bcmd & (1 << 9)) 573 1.1 riastrad dw_count++; 574 1.1 riastrad if (bcmd & (1 << 10)) 575 1.1 riastrad dw_count++; 576 1.1 riastrad if (bcmd & (1 << 11)) 577 1.1 riastrad dw_count++; 578 1.1 riastrad if (bcmd & (1 << 12)) 579 1.1 riastrad dw_count++; 580 1.1 riastrad if (bcmd & (1 << 13)) 581 1.1 riastrad dw_count++; 582 1.1 riastrad if (bcmd & (1 << 14)) 583 1.1 riastrad dw_count++; 584 1.1 riastrad 585 1.1 riastrad while (buf < buf_end) { 586 1.1 riastrad if (*buf == a_fire) { 587 1.1 riastrad if (dev_priv->num_fire_offsets >= 588 1.1 riastrad VIA_FIRE_BUF_SIZE) { 589 1.1 riastrad DRM_ERROR("Fire offset buffer full.\n"); 590 1.1 riastrad ret = 1; 591 1.1 riastrad break; 592 1.1 riastrad } 593 1.1 riastrad dev_priv->fire_offsets[dev_priv-> 594 1.1 riastrad num_fire_offsets++] = 595 1.1 riastrad buf; 596 1.1 riastrad have_fire = 1; 597 1.1 riastrad buf++; 598 1.1 riastrad if (buf < buf_end && *buf == a_fire) 599 1.1 riastrad buf++; 600 1.1 riastrad break; 601 1.1 riastrad } 602 1.1 riastrad if ((*buf == HALCYON_HEADER2) || 603 1.1 riastrad ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) { 604 1.1 riastrad DRM_ERROR("Missing Vertex Fire command, " 605 1.1 riastrad "Stray Vertex Fire command or verifier " 606 1.1 riastrad "lost sync.\n"); 607 1.1 riastrad ret = 1; 608 1.1 riastrad break; 609 1.1 riastrad } 610 1.1 riastrad if ((ret = eat_words(&buf, buf_end, dw_count))) 611 1.1 riastrad break; 612 1.1 riastrad } 613 1.1 riastrad if (buf >= buf_end && !have_fire) { 614 1.1 riastrad DRM_ERROR("Missing Vertex Fire command or verifier " 615 1.1 riastrad "lost sync.\n"); 616 1.1 riastrad ret = 1; 617 1.1 riastrad break; 618 1.1 riastrad } 619 1.1 riastrad if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) { 620 1.1 riastrad DRM_ERROR("AGP Primitive list end misaligned.\n"); 621 1.1 riastrad ret = 1; 622 1.1 riastrad break; 623 1.1 riastrad } 624 1.1 riastrad } 625 1.1 riastrad *buffer = buf; 626 1.1 riastrad return ret; 627 1.1 riastrad } 628 1.1 riastrad 629 1.1 riastrad static __inline__ verifier_state_t 630 1.1 riastrad via_check_header2(uint32_t const **buffer, const uint32_t *buf_end, 631 1.1 riastrad drm_via_state_t *hc_state) 632 1.1 riastrad { 633 1.1 riastrad uint32_t cmd; 634 1.1 riastrad int hz_mode; 635 1.1 riastrad hazard_t hz; 636 1.1 riastrad const uint32_t *buf = *buffer; 637 1.1 riastrad const hazard_t *hz_table; 638 1.1 riastrad 639 1.1 riastrad if ((buf_end - buf) < 2) { 640 1.1 riastrad DRM_ERROR 641 1.1 riastrad ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); 642 1.1 riastrad return state_error; 643 1.1 riastrad } 644 1.1 riastrad buf++; 645 1.1 riastrad cmd = (*buf++ & 0xFFFF0000) >> 16; 646 1.1 riastrad 647 1.1 riastrad switch (cmd) { 648 1.1 riastrad case HC_ParaType_CmdVdata: 649 1.1 riastrad if (via_check_prim_list(&buf, buf_end, hc_state)) 650 1.1 riastrad return state_error; 651 1.1 riastrad *buffer = buf; 652 1.1 riastrad return state_command; 653 1.1 riastrad case HC_ParaType_NotTex: 654 1.1 riastrad hz_table = table1; 655 1.1 riastrad break; 656 1.1 riastrad case HC_ParaType_Tex: 657 1.1 riastrad hc_state->texture = 0; 658 1.1 riastrad hz_table = table2; 659 1.1 riastrad break; 660 1.1 riastrad case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)): 661 1.1 riastrad hc_state->texture = 1; 662 1.1 riastrad hz_table = table2; 663 1.1 riastrad break; 664 1.1 riastrad case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)): 665 1.1 riastrad hz_table = table3; 666 1.1 riastrad break; 667 1.1 riastrad case HC_ParaType_Auto: 668 1.1 riastrad if (eat_words(&buf, buf_end, 2)) 669 1.1 riastrad return state_error; 670 1.1 riastrad *buffer = buf; 671 1.1 riastrad return state_command; 672 1.1 riastrad case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)): 673 1.1 riastrad if (eat_words(&buf, buf_end, 32)) 674 1.1 riastrad return state_error; 675 1.1 riastrad *buffer = buf; 676 1.1 riastrad return state_command; 677 1.1 riastrad case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)): 678 1.1 riastrad case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)): 679 1.1 riastrad DRM_ERROR("Texture palettes are rejected because of " 680 1.1 riastrad "lack of info how to determine their size.\n"); 681 1.1 riastrad return state_error; 682 1.1 riastrad case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)): 683 1.1 riastrad DRM_ERROR("Fog factor palettes are rejected because of " 684 1.1 riastrad "lack of info how to determine their size.\n"); 685 1.1 riastrad return state_error; 686 1.1 riastrad default: 687 1.1 riastrad 688 1.1 riastrad /* 689 1.1 riastrad * There are some unimplemented HC_ParaTypes here, that 690 1.1 riastrad * need to be implemented if the Mesa driver is extended. 691 1.1 riastrad */ 692 1.1 riastrad 693 1.1 riastrad DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 " 694 1.1 riastrad "DMA subcommand: 0x%x. Previous dword: 0x%x\n", 695 1.1 riastrad cmd, *(buf - 2)); 696 1.1 riastrad *buffer = buf; 697 1.1 riastrad return state_error; 698 1.1 riastrad } 699 1.1 riastrad 700 1.1 riastrad while (buf < buf_end) { 701 1.1 riastrad cmd = *buf++; 702 1.1 riastrad if ((hz = hz_table[cmd >> 24])) { 703 1.1 riastrad if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) { 704 1.1 riastrad if (hz_mode == 1) { 705 1.1 riastrad buf--; 706 1.1 riastrad break; 707 1.1 riastrad } 708 1.1 riastrad return state_error; 709 1.1 riastrad } 710 1.1 riastrad } else if (hc_state->unfinished && 711 1.1 riastrad finish_current_sequence(hc_state)) { 712 1.1 riastrad return state_error; 713 1.1 riastrad } 714 1.1 riastrad } 715 1.1 riastrad if (hc_state->unfinished && finish_current_sequence(hc_state)) 716 1.1 riastrad return state_error; 717 1.1 riastrad *buffer = buf; 718 1.1 riastrad return state_command; 719 1.1 riastrad } 720 1.1 riastrad 721 1.1 riastrad static __inline__ verifier_state_t 722 1.1 riastrad via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer, 723 1.1 riastrad const uint32_t *buf_end, int *fire_count) 724 1.1 riastrad { 725 1.1 riastrad uint32_t cmd; 726 1.1 riastrad const uint32_t *buf = *buffer; 727 1.1 riastrad const uint32_t *next_fire; 728 1.1 riastrad int burst = 0; 729 1.1 riastrad 730 1.1 riastrad next_fire = dev_priv->fire_offsets[*fire_count]; 731 1.1 riastrad buf++; 732 1.1 riastrad cmd = (*buf & 0xFFFF0000) >> 16; 733 1.3 riastrad via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++); 734 1.1 riastrad switch (cmd) { 735 1.1 riastrad case HC_ParaType_CmdVdata: 736 1.1 riastrad while ((buf < buf_end) && 737 1.1 riastrad (*fire_count < dev_priv->num_fire_offsets) && 738 1.1 riastrad (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) { 739 1.1 riastrad while (buf <= next_fire) { 740 1.3 riastrad via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + 741 1.1 riastrad (burst & 63), *buf++); 742 1.1 riastrad burst += 4; 743 1.1 riastrad } 744 1.1 riastrad if ((buf < buf_end) 745 1.1 riastrad && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) 746 1.1 riastrad buf++; 747 1.1 riastrad 748 1.1 riastrad if (++(*fire_count) < dev_priv->num_fire_offsets) 749 1.1 riastrad next_fire = dev_priv->fire_offsets[*fire_count]; 750 1.1 riastrad } 751 1.1 riastrad break; 752 1.1 riastrad default: 753 1.1 riastrad while (buf < buf_end) { 754 1.1 riastrad 755 1.1 riastrad if (*buf == HC_HEADER2 || 756 1.1 riastrad (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || 757 1.1 riastrad (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || 758 1.1 riastrad (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 759 1.1 riastrad break; 760 1.1 riastrad 761 1.3 riastrad via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + 762 1.1 riastrad (burst & 63), *buf++); 763 1.1 riastrad burst += 4; 764 1.1 riastrad } 765 1.1 riastrad } 766 1.1 riastrad *buffer = buf; 767 1.1 riastrad return state_command; 768 1.1 riastrad } 769 1.1 riastrad 770 1.1 riastrad static __inline__ int verify_mmio_address(uint32_t address) 771 1.1 riastrad { 772 1.1 riastrad if ((address > 0x3FF) && (address < 0xC00)) { 773 1.1 riastrad DRM_ERROR("Invalid VIDEO DMA command. " 774 1.1 riastrad "Attempt to access 3D- or command burst area.\n"); 775 1.1 riastrad return 1; 776 1.1 riastrad } else if ((address > 0xCFF) && (address < 0x1300)) { 777 1.1 riastrad DRM_ERROR("Invalid VIDEO DMA command. " 778 1.1 riastrad "Attempt to access PCI DMA area.\n"); 779 1.1 riastrad return 1; 780 1.1 riastrad } else if (address > 0x13FF) { 781 1.1 riastrad DRM_ERROR("Invalid VIDEO DMA command. " 782 1.1 riastrad "Attempt to access VGA registers.\n"); 783 1.1 riastrad return 1; 784 1.1 riastrad } 785 1.1 riastrad return 0; 786 1.1 riastrad } 787 1.1 riastrad 788 1.1 riastrad static __inline__ int 789 1.1 riastrad verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end, 790 1.1 riastrad uint32_t dwords) 791 1.1 riastrad { 792 1.1 riastrad const uint32_t *buf = *buffer; 793 1.1 riastrad 794 1.1 riastrad if (buf_end - buf < dwords) { 795 1.1 riastrad DRM_ERROR("Illegal termination of video command.\n"); 796 1.1 riastrad return 1; 797 1.1 riastrad } 798 1.1 riastrad while (dwords--) { 799 1.1 riastrad if (*buf++) { 800 1.1 riastrad DRM_ERROR("Illegal video command tail.\n"); 801 1.1 riastrad return 1; 802 1.1 riastrad } 803 1.1 riastrad } 804 1.1 riastrad *buffer = buf; 805 1.1 riastrad return 0; 806 1.1 riastrad } 807 1.1 riastrad 808 1.1 riastrad static __inline__ verifier_state_t 809 1.1 riastrad via_check_header1(uint32_t const **buffer, const uint32_t * buf_end) 810 1.1 riastrad { 811 1.1 riastrad uint32_t cmd; 812 1.1 riastrad const uint32_t *buf = *buffer; 813 1.1 riastrad verifier_state_t ret = state_command; 814 1.1 riastrad 815 1.1 riastrad while (buf < buf_end) { 816 1.1 riastrad cmd = *buf; 817 1.1 riastrad if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) && 818 1.1 riastrad (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { 819 1.1 riastrad if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 820 1.1 riastrad break; 821 1.1 riastrad DRM_ERROR("Invalid HALCYON_HEADER1 command. " 822 1.1 riastrad "Attempt to access 3D- or command burst area.\n"); 823 1.1 riastrad ret = state_error; 824 1.1 riastrad break; 825 1.1 riastrad } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) { 826 1.1 riastrad if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 827 1.1 riastrad break; 828 1.1 riastrad DRM_ERROR("Invalid HALCYON_HEADER1 command. " 829 1.1 riastrad "Attempt to access VGA registers.\n"); 830 1.1 riastrad ret = state_error; 831 1.1 riastrad break; 832 1.1 riastrad } else { 833 1.1 riastrad buf += 2; 834 1.1 riastrad } 835 1.1 riastrad } 836 1.1 riastrad *buffer = buf; 837 1.1 riastrad return ret; 838 1.1 riastrad } 839 1.1 riastrad 840 1.1 riastrad static __inline__ verifier_state_t 841 1.1 riastrad via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer, 842 1.1 riastrad const uint32_t *buf_end) 843 1.1 riastrad { 844 1.1 riastrad register uint32_t cmd; 845 1.1 riastrad const uint32_t *buf = *buffer; 846 1.1 riastrad 847 1.1 riastrad while (buf < buf_end) { 848 1.1 riastrad cmd = *buf; 849 1.1 riastrad if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) 850 1.1 riastrad break; 851 1.3 riastrad via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); 852 1.1 riastrad buf++; 853 1.1 riastrad } 854 1.1 riastrad *buffer = buf; 855 1.1 riastrad return state_command; 856 1.1 riastrad } 857 1.1 riastrad 858 1.1 riastrad static __inline__ verifier_state_t 859 1.1 riastrad via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end) 860 1.1 riastrad { 861 1.1 riastrad uint32_t data; 862 1.1 riastrad const uint32_t *buf = *buffer; 863 1.1 riastrad 864 1.1 riastrad if (buf_end - buf < 4) { 865 1.1 riastrad DRM_ERROR("Illegal termination of video header5 command\n"); 866 1.1 riastrad return state_error; 867 1.1 riastrad } 868 1.1 riastrad 869 1.1 riastrad data = *buf++ & ~VIA_VIDEOMASK; 870 1.1 riastrad if (verify_mmio_address(data)) 871 1.1 riastrad return state_error; 872 1.1 riastrad 873 1.1 riastrad data = *buf++; 874 1.1 riastrad if (*buf++ != 0x00F50000) { 875 1.1 riastrad DRM_ERROR("Illegal header5 header data\n"); 876 1.1 riastrad return state_error; 877 1.1 riastrad } 878 1.1 riastrad if (*buf++ != 0x00000000) { 879 1.1 riastrad DRM_ERROR("Illegal header5 header data\n"); 880 1.1 riastrad return state_error; 881 1.1 riastrad } 882 1.1 riastrad if (eat_words(&buf, buf_end, data)) 883 1.1 riastrad return state_error; 884 1.1 riastrad if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 885 1.1 riastrad return state_error; 886 1.1 riastrad *buffer = buf; 887 1.1 riastrad return state_command; 888 1.1 riastrad 889 1.1 riastrad } 890 1.1 riastrad 891 1.1 riastrad static __inline__ verifier_state_t 892 1.1 riastrad via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer, 893 1.1 riastrad const uint32_t *buf_end) 894 1.1 riastrad { 895 1.1 riastrad uint32_t addr, count, i; 896 1.1 riastrad const uint32_t *buf = *buffer; 897 1.1 riastrad 898 1.1 riastrad addr = *buf++ & ~VIA_VIDEOMASK; 899 1.1 riastrad i = count = *buf; 900 1.1 riastrad buf += 3; 901 1.1 riastrad while (i--) 902 1.3 riastrad via_write(dev_priv, addr, *buf++); 903 1.1 riastrad if (count & 3) 904 1.1 riastrad buf += 4 - (count & 3); 905 1.1 riastrad *buffer = buf; 906 1.1 riastrad return state_command; 907 1.1 riastrad } 908 1.1 riastrad 909 1.1 riastrad static __inline__ verifier_state_t 910 1.1 riastrad via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end) 911 1.1 riastrad { 912 1.1 riastrad uint32_t data; 913 1.1 riastrad const uint32_t *buf = *buffer; 914 1.1 riastrad uint32_t i; 915 1.1 riastrad 916 1.1 riastrad if (buf_end - buf < 4) { 917 1.1 riastrad DRM_ERROR("Illegal termination of video header6 command\n"); 918 1.1 riastrad return state_error; 919 1.1 riastrad } 920 1.1 riastrad buf++; 921 1.1 riastrad data = *buf++; 922 1.1 riastrad if (*buf++ != 0x00F60000) { 923 1.1 riastrad DRM_ERROR("Illegal header6 header data\n"); 924 1.1 riastrad return state_error; 925 1.1 riastrad } 926 1.1 riastrad if (*buf++ != 0x00000000) { 927 1.1 riastrad DRM_ERROR("Illegal header6 header data\n"); 928 1.1 riastrad return state_error; 929 1.1 riastrad } 930 1.1 riastrad if ((buf_end - buf) < (data << 1)) { 931 1.1 riastrad DRM_ERROR("Illegal termination of video header6 command\n"); 932 1.1 riastrad return state_error; 933 1.1 riastrad } 934 1.1 riastrad for (i = 0; i < data; ++i) { 935 1.1 riastrad if (verify_mmio_address(*buf++)) 936 1.1 riastrad return state_error; 937 1.1 riastrad buf++; 938 1.1 riastrad } 939 1.1 riastrad data <<= 1; 940 1.1 riastrad if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) 941 1.1 riastrad return state_error; 942 1.1 riastrad *buffer = buf; 943 1.1 riastrad return state_command; 944 1.1 riastrad } 945 1.1 riastrad 946 1.1 riastrad static __inline__ verifier_state_t 947 1.1 riastrad via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer, 948 1.1 riastrad const uint32_t *buf_end) 949 1.1 riastrad { 950 1.1 riastrad 951 1.1 riastrad uint32_t addr, count, i; 952 1.1 riastrad const uint32_t *buf = *buffer; 953 1.1 riastrad 954 1.1 riastrad i = count = *++buf; 955 1.1 riastrad buf += 3; 956 1.1 riastrad while (i--) { 957 1.1 riastrad addr = *buf++; 958 1.3 riastrad via_write(dev_priv, addr, *buf++); 959 1.1 riastrad } 960 1.1 riastrad count <<= 1; 961 1.1 riastrad if (count & 3) 962 1.1 riastrad buf += 4 - (count & 3); 963 1.1 riastrad *buffer = buf; 964 1.1 riastrad return state_command; 965 1.1 riastrad } 966 1.1 riastrad 967 1.1 riastrad int 968 1.1 riastrad via_verify_command_stream(const uint32_t * buf, unsigned int size, 969 1.1 riastrad struct drm_device * dev, int agp) 970 1.1 riastrad { 971 1.1 riastrad 972 1.1 riastrad drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 973 1.1 riastrad drm_via_state_t *hc_state = &dev_priv->hc_state; 974 1.1 riastrad drm_via_state_t saved_state = *hc_state; 975 1.1 riastrad uint32_t cmd; 976 1.1 riastrad const uint32_t *buf_end = buf + (size >> 2); 977 1.1 riastrad verifier_state_t state = state_command; 978 1.1 riastrad int cme_video; 979 1.1 riastrad int supported_3d; 980 1.1 riastrad 981 1.1 riastrad cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || 982 1.1 riastrad dev_priv->chipset == VIA_DX9_0); 983 1.1 riastrad 984 1.1 riastrad supported_3d = dev_priv->chipset != VIA_DX9_0; 985 1.1 riastrad 986 1.1 riastrad hc_state->dev = dev; 987 1.1 riastrad hc_state->unfinished = no_sequence; 988 1.1 riastrad hc_state->map_cache = NULL; 989 1.1 riastrad hc_state->agp = agp; 990 1.1 riastrad hc_state->buf_start = buf; 991 1.1 riastrad dev_priv->num_fire_offsets = 0; 992 1.1 riastrad 993 1.1 riastrad while (buf < buf_end) { 994 1.1 riastrad 995 1.1 riastrad switch (state) { 996 1.1 riastrad case state_header2: 997 1.1 riastrad state = via_check_header2(&buf, buf_end, hc_state); 998 1.1 riastrad break; 999 1.1 riastrad case state_header1: 1000 1.1 riastrad state = via_check_header1(&buf, buf_end); 1001 1.1 riastrad break; 1002 1.1 riastrad case state_vheader5: 1003 1.1 riastrad state = via_check_vheader5(&buf, buf_end); 1004 1.1 riastrad break; 1005 1.1 riastrad case state_vheader6: 1006 1.1 riastrad state = via_check_vheader6(&buf, buf_end); 1007 1.1 riastrad break; 1008 1.1 riastrad case state_command: 1009 1.1 riastrad if ((HALCYON_HEADER2 == (cmd = *buf)) && 1010 1.1 riastrad supported_3d) 1011 1.1 riastrad state = state_header2; 1012 1.1 riastrad else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 1013 1.1 riastrad state = state_header1; 1014 1.1 riastrad else if (cme_video 1015 1.1 riastrad && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) 1016 1.1 riastrad state = state_vheader5; 1017 1.1 riastrad else if (cme_video 1018 1.1 riastrad && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 1019 1.1 riastrad state = state_vheader6; 1020 1.1 riastrad else if ((cmd == HALCYON_HEADER2) && !supported_3d) { 1021 1.1 riastrad DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); 1022 1.1 riastrad state = state_error; 1023 1.1 riastrad } else { 1024 1.1 riastrad DRM_ERROR 1025 1.1 riastrad ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", 1026 1.1 riastrad cmd); 1027 1.1 riastrad state = state_error; 1028 1.1 riastrad } 1029 1.1 riastrad break; 1030 1.1 riastrad case state_error: 1031 1.1 riastrad default: 1032 1.1 riastrad *hc_state = saved_state; 1033 1.1 riastrad return -EINVAL; 1034 1.1 riastrad } 1035 1.1 riastrad } 1036 1.1 riastrad if (state == state_error) { 1037 1.1 riastrad *hc_state = saved_state; 1038 1.1 riastrad return -EINVAL; 1039 1.1 riastrad } 1040 1.1 riastrad return 0; 1041 1.1 riastrad } 1042 1.1 riastrad 1043 1.1 riastrad int 1044 1.1 riastrad via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, 1045 1.1 riastrad unsigned int size) 1046 1.1 riastrad { 1047 1.1 riastrad 1048 1.1 riastrad drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 1049 1.1 riastrad uint32_t cmd; 1050 1.1 riastrad const uint32_t *buf_end = buf + (size >> 2); 1051 1.1 riastrad verifier_state_t state = state_command; 1052 1.1 riastrad int fire_count = 0; 1053 1.1 riastrad 1054 1.1 riastrad while (buf < buf_end) { 1055 1.1 riastrad 1056 1.1 riastrad switch (state) { 1057 1.1 riastrad case state_header2: 1058 1.1 riastrad state = 1059 1.1 riastrad via_parse_header2(dev_priv, &buf, buf_end, 1060 1.1 riastrad &fire_count); 1061 1.1 riastrad break; 1062 1.1 riastrad case state_header1: 1063 1.1 riastrad state = via_parse_header1(dev_priv, &buf, buf_end); 1064 1.1 riastrad break; 1065 1.1 riastrad case state_vheader5: 1066 1.1 riastrad state = via_parse_vheader5(dev_priv, &buf, buf_end); 1067 1.1 riastrad break; 1068 1.1 riastrad case state_vheader6: 1069 1.1 riastrad state = via_parse_vheader6(dev_priv, &buf, buf_end); 1070 1.1 riastrad break; 1071 1.1 riastrad case state_command: 1072 1.1 riastrad if (HALCYON_HEADER2 == (cmd = *buf)) 1073 1.1 riastrad state = state_header2; 1074 1.1 riastrad else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) 1075 1.1 riastrad state = state_header1; 1076 1.1 riastrad else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) 1077 1.1 riastrad state = state_vheader5; 1078 1.1 riastrad else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) 1079 1.1 riastrad state = state_vheader6; 1080 1.1 riastrad else { 1081 1.1 riastrad DRM_ERROR 1082 1.1 riastrad ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", 1083 1.1 riastrad cmd); 1084 1.1 riastrad state = state_error; 1085 1.1 riastrad } 1086 1.1 riastrad break; 1087 1.1 riastrad case state_error: 1088 1.1 riastrad default: 1089 1.1 riastrad return -EINVAL; 1090 1.1 riastrad } 1091 1.1 riastrad } 1092 1.1 riastrad if (state == state_error) 1093 1.1 riastrad return -EINVAL; 1094 1.1 riastrad return 0; 1095 1.1 riastrad } 1096 1.1 riastrad 1097 1.1 riastrad static void 1098 1.1 riastrad setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) 1099 1.1 riastrad { 1100 1.1 riastrad int i; 1101 1.1 riastrad 1102 1.1 riastrad for (i = 0; i < 256; ++i) 1103 1.1 riastrad table[i] = forbidden_command; 1104 1.1 riastrad 1105 1.1 riastrad for (i = 0; i < size; ++i) 1106 1.1 riastrad table[init_table[i].code] = init_table[i].hz; 1107 1.1 riastrad } 1108 1.1 riastrad 1109 1.1 riastrad void via_init_command_verifier(void) 1110 1.1 riastrad { 1111 1.3 riastrad setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1)); 1112 1.3 riastrad setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2)); 1113 1.3 riastrad setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3)); 1114 1.1 riastrad } 1115