summaryrefslogtreecommitdiff
path: root/shared-core/r128_cce.c
blob: 64c9b8be7b1dd4f46fc1f174593159422d1a7709 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
 * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
 *
 * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Gareth Hughes <gareth@valinux.com>
 */

#include "r128.h"
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
#include "r128_drv.h"

#define R128_FIFO_DEBUG		0

/* CCE microcode (from ATI) */
static u32 r128_cce_microcode[] = {
	0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0,
	1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0,
	599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1,
	11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11,
	262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28,
	1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9,
	30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656,
	1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1,
	15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071,
	12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2,
	46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1,
	459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1,
	18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1,
	15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2,
	268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1,
	15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82,
	1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729,
	3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008,
	1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0,
	15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1,
	180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1,
	114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0,
	33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370,
	1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1,
	14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793,
	1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1,
	198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1,
	114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1,
	1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1,
	1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894,
	16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14,
	174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1,
	33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1,
	33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1,
	409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

int R128_READ_PLL(drm_device_t *dev, int addr)
{
	drm_r128_private_t *dev_priv = dev->dev_private;

	R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
	return R128_READ(R128_CLOCK_CNTL_DATA);
}

#if R128_FIFO_DEBUG
static void r128_status( drm_r128_private_t *dev_priv )
{
	printk( "GUI_STAT           = 0x%08x\n",
		(unsigned int)R128_READ( R128_GUI_STAT ) );
	printk( "PM4_STAT           = 0x%08x\n",
		(unsigned int)R128_READ( R128_PM4_STAT ) );
	printk( "PM4_BUFFER_DL_WPTR = 0x%08x\n",
		(unsigned int)R128_READ( R128_PM4_BUFFER_DL_WPTR ) );
	printk( "PM4_BUFFER_DL_RPTR = 0x%08x\n",
		(unsigned int)R128_READ( R128_PM4_BUFFER_DL_RPTR ) );
	printk( "PM4_MICRO_CNTL     = 0x%08x\n",
		(unsigned int)R128_READ( R128_PM4_MICRO_CNTL ) );
	printk( "PM4_BUFFER_CNTL    = 0x%08x\n",
		(unsigned int)R128_READ( R128_PM4_BUFFER_CNTL ) );
}
#endif


/* ================================================================
 * Engine, FIFO control
 */

static int r128_do_pixcache_flush( drm_r128_private_t *dev_priv )
{
	u32 tmp;
	int i;

	tmp = R128_READ( R128_PC_NGUI_CTLSTAT ) | R128_PC_FLUSH_ALL;
	R128_WRITE( R128_PC_NGUI_CTLSTAT, tmp );

	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
		if ( !(R128_READ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY) ) {
			return 0;
		}
		DRM_UDELAY( 1 );
	}

#if R128_FIFO_DEBUG
	DRM_ERROR( "failed!\n" );
#endif
	return DRM_ERR(EBUSY);
}

static int r128_do_wait_for_fifo( drm_r128_private_t *dev_priv, int entries )
{
	int i;

	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
		int slots = R128_READ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK;
		if ( slots >= entries ) return 0;
		DRM_UDELAY( 1 );
	}

#if R128_FIFO_DEBUG
	DRM_ERROR( "failed!\n" );
#endif
	return DRM_ERR(EBUSY);
}

static int r128_do_wait_for_idle( drm_r128_private_t *dev_priv )
{
	int i, ret;

	ret = r128_do_wait_for_fifo( dev_priv, 64 );
	if ( ret ) return ret;

	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
		if ( !(R128_READ( R128_GUI_STAT ) & R128_GUI_ACTIVE) ) {
			r128_do_pixcache_flush( dev_priv );
			return 0;
		}
		DRM_UDELAY( 1 );
	}

#if R128_FIFO_DEBUG
	DRM_ERROR( "failed!\n" );
#endif
	return DRM_ERR(EBUSY);
}


/* ================================================================
 * CCE control, initialization
 */

/* Load the microcode for the CCE */
static void r128_cce_load_microcode( drm_r128_private_t *dev_priv )
{
	int i;

	DRM_DEBUG( "\n" );

	r128_do_wait_for_idle( dev_priv );

	R128_WRITE( R128_PM4_MICROCODE_ADDR, 0 );
	for ( i = 0 ; i < 256 ; i++ ) {
		R128_WRITE( R128_PM4_MICROCODE_DATAH,
			    r128_cce_microcode[i * 2] );
		R128_WRITE( R128_PM4_MICROCODE_DATAL,
			    r128_cce_microcode[i * 2 + 1] );
	}
}

/* Flush any pending commands to the CCE.  This should only be used just
 * prior to a wait for idle, as it informs the engine that the command
 * stream is ending.
 */
static void r128_do_cce_flush( drm_r128_private_t *dev_priv )
{
	u32 tmp;

	tmp = R128_READ( R128_PM4_BUFFER_DL_WPTR ) | R128_PM4_BUFFER_DL_DONE;
	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, tmp );
}

/* Wait for the CCE to go idle.
 */
int r128_do_cce_idle( drm_r128_private_t *dev_priv )
{
	int i;

	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
		if ( GET_RING_HEAD( dev_priv ) == dev_priv->ring.tail ) {
			int pm4stat = R128_READ( R128_PM4_STAT );
			if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >=
			       dev_priv->cce_fifo_size ) &&
			     !(pm4stat & (R128_PM4_BUSY |
					  R128_PM4_GUI_ACTIVE)) ) {
				return r128_do_pixcache_flush( dev_priv );
			}
		}
		DRM_UDELAY( 1 );
	}

#if R128_FIFO_DEBUG
	DRM_ERROR( "failed!\n" );
	r128_status( dev_priv );
#endif
	return DRM_ERR(EBUSY);
}

/* Start the Concurrent Command Engine.
 */
static void r128_do_cce_start( drm_r128_private_t *dev_priv )
{
	r128_do_wait_for_idle( dev_priv );

	R128_WRITE( R128_PM4_BUFFER_CNTL,
		    dev_priv->cce_mode | dev_priv->ring.size_l2qw
		    | R128_PM4_BUFFER_CNTL_NOUPDATE );
	R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */
	R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN );

	dev_priv->cce_running = 1;
}

/* Reset the Concurrent Command Engine.  This will not flush any pending
 * commands, so you must wait for the CCE command stream to complete
 * before calling this routine.
 */
static void r128_do_cce_reset( drm_r128_private_t *dev_priv )
{
	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );
	dev_priv->ring.tail = 0;
}

/* Stop the Concurrent Command Engine.  This will not flush any pending
 * commands, so you must flush the command stream and wait for the CCE
 * to go idle before calling this routine.
 */
static void r128_do_cce_stop( drm_r128_private_t *dev_priv )
{
	R128_WRITE( R128_PM4_MICRO_CNTL, 0 );
	R128_WRITE( R128_PM4_BUFFER_CNTL,
		    R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE );

	dev_priv->cce_running = 0;
}

/* Reset the engine.  This will stop the CCE if it is running.
 */
static int r128_do_engine_reset( drm_device_t *dev )
{
	drm_r128_private_t *dev_priv = dev->dev_private;
	u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;

	r128_do_pixcache_flush( dev_priv );

	clock_cntl_index = R128_READ( R128_CLOCK_CNTL_INDEX );
	mclk_cntl = R128_READ_PLL( dev, R128_MCLK_CNTL );

	R128_WRITE_PLL( R128_MCLK_CNTL,
			mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP );

	gen_reset_cntl = R128_READ( R128_GEN_RESET_CNTL );

	/* Taken from the sample code - do not change */
	R128_WRITE( R128_GEN_RESET_CNTL,
		    gen_reset_cntl | R128_SOFT_RESET_GUI );
	R128_READ( R128_GEN_RESET_CNTL );
	R128_WRITE( R128_GEN_RESET_CNTL,
		    gen_reset_cntl & ~R128_SOFT_RESET_GUI );
	R128_READ( R128_GEN_RESET_CNTL );

	R128_WRITE_PLL( R128_MCLK_CNTL, mclk_cntl );
	R128_WRITE( R128_CLOCK_CNTL_INDEX, clock_cntl_index );
	R128_WRITE( R128_GEN_RESET_CNTL, gen_reset_cntl );

	/* Reset the CCE ring */
	r128_do_cce_reset( dev_priv );

	/* The CCE is no longer running after an engine reset */
	dev_priv->cce_running = 0;

	/* Reset any pending vertex, indirect buffers */
	r128_freelist_reset( dev );

	return 0;
}

static void r128_cce_init_ring_buffer( drm_device_t *dev,
				       drm_r128_private_t *dev_priv )
{
	u32 ring_start;
	u32 tmp;

	DRM_DEBUG( "\n" );

	/* The manual (p. 2) says this address is in "VM space".  This
	 * means it's an offset from the start of AGP space.
	 */
#if __OS_HAS_AGP
	if ( !dev_priv->is_pci )
		ring_start = dev_priv->cce_ring->offset - dev->agp->base;
	else
#endif
		ring_start = dev_priv->cce_ring->offset - dev->sg->handle;

	R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET );

	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 );
	R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 );

	/* Set watermark control */
	R128_WRITE( R128_PM4_BUFFER_WM_CNTL,
		    ((R128_WATERMARK_L/4) << R128_WMA_SHIFT)
		    | ((R128_WATERMARK_M/4) << R128_WMB_SHIFT)
		    | ((R128_WATERMARK_N/4) << R128_WMC_SHIFT)
		    | ((R128_WATERMARK_K/64) << R128_WB_WM_SHIFT) );

	/* Force read.  Why?  Because it's in the examples... */
	R128_READ( R128_PM4_BUFFER_ADDR );

	/* Turn on bus mastering */
	tmp = R128_READ( R128_BUS_CNTL ) & ~R128_BUS_MASTER_DIS;
	R128_WRITE( R128_BUS_CNTL, tmp );
}

static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
{
	drm_r128_private_t *dev_priv;

	DRM_DEBUG( "\n" );

	dev_priv = DRM(alloc)( sizeof(drm_r128_private_t), DRM_MEM_DRIVER );
	if ( dev_priv == NULL )
		return DRM_ERR(ENOMEM);

	memset( dev_priv, 0, sizeof(drm_r128_private_t) );

	dev_priv->is_pci = init->is_pci;

	if ( dev_priv->is_pci && !dev->sg ) {
		DRM_ERROR( "PCI GART memory not allocated!\n" );
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}

	dev_priv->usec_timeout = init->usec_timeout;
	if ( dev_priv->usec_timeout < 1 ||
	     dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT ) {
		DRM_DEBUG( "TIMEOUT problem!\n" );
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}

	dev_priv->cce_mode = init->cce_mode;

	/* GH: Simple idle check.
	 */
	atomic_set( &dev_priv->idle_count, 0 );

	/* We don't support anything other than bus-mastering ring mode,
	 * but the ring can be in either AGP or PCI space for the ring
	 * read pointer.
	 */
	if ( ( init->cce_mode != R128_PM4_192BM ) &&
	     ( init->cce_mode != R128_PM4_128BM_64INDBM ) &&
	     ( init->cce_mode != R128_PM4_64BM_128INDBM ) &&
	     ( init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM ) ) {
		DRM_DEBUG( "Bad cce_mode!\n" );
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}

	switch ( init->cce_mode ) {
	case R128_PM4_NONPM4:
		dev_priv->cce_fifo_size = 0;
		break;
	case R128_PM4_192PIO:
	case R128_PM4_192BM:
		dev_priv->cce_fifo_size = 192;
		break;
	case R128_PM4_128PIO_64INDBM:
	case R128_PM4_128BM_64INDBM:
		dev_priv->cce_fifo_size = 128;
		break;
	case R128_PM4_64PIO_128INDBM:
	case R128_PM4_64BM_128INDBM:
	case R128_PM4_64PIO_64VCBM_64INDBM:
	case R128_PM4_64BM_64VCBM_64INDBM:
	case R128_PM4_64PIO_64VCPIO_64INDPIO:
		dev_priv->cce_fifo_size = 64;
		break;
	}

	switch ( init->fb_bpp ) {
	case 16:
		dev_priv->color_fmt = R128_DATATYPE_RGB565;
		break;
	case 32:
	default:
		dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
		break;
	}
	dev_priv->front_offset	= init->front_offset;
	dev_priv->front_pitch	= init->front_pitch;
	dev_priv->back_offset	= init->back_offset;
	dev_priv->back_pitch	= init->back_pitch;

	switch ( init->depth_bpp ) {
	case 16:
		dev_priv->depth_fmt = R128_DATATYPE_RGB565;
		break;
	case 24:
	case 32:
	default:
		dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
		break;
	}
	dev_priv->depth_offset	= init->depth_offset;
	dev_priv->depth_pitch	= init->depth_pitch;
	dev_priv->span_offset	= init->span_offset;

	dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch/8) << 21) |
					  (dev_priv->front_offset >> 5));
	dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch/8) << 21) |
					 (dev_priv->back_offset >> 5));
	dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch/8) << 21) |
					  (dev_priv->depth_offset >> 5) |
					  R128_DST_TILE);
	dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch/8) << 21) |
					 (dev_priv->span_offset >> 5));

	DRM_GETSAREA();
	
	if(!dev_priv->sarea) {
		DRM_ERROR("could not find sarea!\n");
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}

	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
	if(!dev_priv->mmio) {
		DRM_ERROR("could not find mmio region!\n");
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}
	dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
	if(!dev_priv->cce_ring) {
		DRM_ERROR("could not find cce ring region!\n");
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}
	dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
	if(!dev_priv->ring_rptr) {
		DRM_ERROR("could not find ring read pointer!\n");
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}
	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
	if(!dev->agp_buffer_map) {
		DRM_ERROR("could not find dma buffer region!\n");
		dev->dev_private = (void *)dev_priv;
		r128_do_cleanup_cce( dev );
		return DRM_ERR(EINVAL);
	}

	if ( !dev_priv->is_pci ) {
		dev_priv->agp_textures = drm_core_findmap(dev, init->agp_textures_offset);
		if(!dev_priv->agp_textures) {
			DRM_ERROR("could not find agp texture region!\n");
			dev->dev_private = (void *)dev_priv;
			r128_do_cleanup_cce( dev );
			return DRM_ERR(EINVAL);
		}
	}

	dev_priv->sarea_priv =
		(drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle +
				     init->sarea_priv_offset);

#if __OS_HAS_AGP
	if ( !dev_priv->is_pci ) {
		drm_core_ioremap( dev_priv->cce_ring, dev );
		drm_core_ioremap( dev_priv->ring_rptr, dev );
		drm_core_ioremap( dev->agp_buffer_map, dev );
		if(!dev_priv->cce_ring->handle ||
		   !dev_priv->ring_rptr->handle ||
		   !dev->agp_buffer_map->handle) {
			DRM_ERROR("Could not ioremap agp regions!\n");
			dev->dev_private = (void *)dev_priv;
			r128_do_cleanup_cce( dev );
			return DRM_ERR(ENOMEM);
		}
	} else
#endif
	{
		dev_priv->cce_ring->handle =
			(void *)dev_priv->cce_ring->offset;
		dev_priv->ring_rptr->handle =
			(void *)dev_priv->ring_rptr->offset;
		dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset;
	}

#if __OS_HAS_AGP
	if ( !dev_priv->is_pci )
		dev_priv->cce_buffers_offset = dev->agp->base;
	else
#endif
		dev_priv->cce_buffers_offset = dev->sg->handle;

	dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle;
	dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle
			      + init->ring_size / sizeof(u32));
	dev_priv->ring.size = init->ring_size;
	dev_priv->ring.size_l2qw = DRM(order)( init->ring_size / 8 );

	dev_priv->ring.tail_mask =
		(dev_priv->ring.size / sizeof(u32)) - 1;

	dev_priv->ring.high_mark = 128;

	dev_priv->sarea_priv->last_frame = 0;
	R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame );

	dev_priv->sarea_priv->last_dispatch = 0;
	R128_WRITE( R128_LAST_DISPATCH_REG,
		    dev_priv->sarea_priv->last_dispatch );

#if __OS_HAS_AGP
	if ( dev_priv->is_pci ) {
#endif
		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
     					    &dev_priv->bus_pci_gart) ) {
			DRM_ERROR( "failed to init PCI GART!\n" );
			dev->dev_private = (void *)dev_priv;
			r128_do_cleanup_cce( dev );
			return DRM_ERR(ENOMEM);
		}
		R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart );
#if __OS_HAS_AGP
	}
#endif

	r128_cce_init_ring_buffer( dev, dev_priv );
	r128_cce_load_microcode( dev_priv );

	dev->dev_private = (void *)dev_priv;

	r128_do_engine_reset( dev );

	return 0;
}

int r128_do_cleanup_cce( drm_device_t *dev )
{

	/* Make sure interrupts are disabled here because the uninstall ioctl
	 * may not have been called from userspace and after dev_private
	 * is freed, it's too late.
	 */
	if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);

	if ( dev->dev_private ) {
		drm_r128_private_t *dev_priv = dev->dev_private;

#if __OS_HAS_AGP
		if ( !dev_priv->is_pci ) {
			if ( dev_priv->cce_ring != NULL )
				drm_core_ioremapfree( dev_priv->cce_ring, dev );
			if ( dev_priv->ring_rptr != NULL )
				drm_core_ioremapfree( dev_priv->ring_rptr, dev );
			if ( dev->agp_buffer_map != NULL ) {
				drm_core_ioremapfree( dev->agp_buffer_map, dev );
				dev->agp_buffer_map = NULL;
			}
		} else
#endif
		{
			if (!DRM(ati_pcigart_cleanup)( dev,
						dev_priv->phys_pci_gart,
						dev_priv->bus_pci_gart ))
				DRM_ERROR( "failed to cleanup PCI GART!\n" );
		}

		DRM(free)( dev->dev_private, sizeof(drm_r128_private_t),
			   DRM_MEM_DRIVER );
		dev->dev_private = NULL;
	}

	return 0;
}

int r128_cce_init( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_r128_init_t init;

	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	DRM_COPY_FROM_USER_IOCTL( init, (drm_r128_init_t __user *)data, sizeof(init) );

	switch ( init.func ) {
	case R128_INIT_CCE:
		return r128_do_init_cce( dev, &init );
	case R128_CLEANUP_CCE:
		return r128_do_cleanup_cce( dev );
	}

	return DRM_ERR(EINVAL);
}

int r128_cce_start( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_r128_private_t *dev_priv = dev->dev_private;
	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) {
		DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ );
		return 0;
	}

	r128_do_cce_start( dev_priv );

	return 0;
}

/* Stop the CCE.  The engine must have been idled before calling this
 * routine.
 */
int r128_cce_stop( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_r128_private_t *dev_priv = dev->dev_private;
	drm_r128_cce_stop_t stop;
	int ret;
	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *)data, sizeof(stop) );

	/* Flush any pending CCE commands.  This ensures any outstanding
	 * commands are exectuted by the engine before we turn it off.
	 */
	if ( stop.flush ) {
		r128_do_cce_flush( dev_priv );
	}

	/* If we fail to make the engine go idle, we return an error
	 * code so that the DRM ioctl wrapper can try again.
	 */
	if ( stop.idle ) {
		ret = r128_do_cce_idle( dev_priv );
		if ( ret ) return ret;
	}

	/* Finally, we can turn off the CCE.  If the engine isn't idle,
	 * we will get some dropped triangles as they won't be fully
	 * rendered before the CCE is shut down.
	 */
	r128_do_cce_stop( dev_priv );

	/* Reset the engine */
	r128_do_engine_reset( dev );

	return 0;
}

/* Just reset the CCE ring.  Called as part of an X Server engine reset.
 */
int r128_cce_reset( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_r128_private_t *dev_priv = dev->dev_private;
	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	if ( !dev_priv ) {
		DRM_DEBUG( "%s called before init done\n", __FUNCTION__ );
		return DRM_ERR(EINVAL);
	}

	r128_do_cce_reset( dev_priv );

	/* The CCE is no longer running after an engine reset */
	dev_priv->cce_running = 0;

	return 0;
}

int r128_cce_idle( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_r128_private_t *dev_priv = dev->dev_private;
	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	if ( dev_priv->cce_running ) {
		r128_do_cce_flush( dev_priv );
	}

	return r128_do_cce_idle( dev_priv );
}

int r128_engine_reset( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	DRM_DEBUG( "\n" );

	LOCK_TEST_WITH_RETURN( dev, filp );

	return r128_do_engine_reset( dev );
}

int r128_fullscreen( DRM_IOCTL_ARGS )
{
	return DRM_ERR(EINVAL);
}


/* ================================================================
 * Freelist management
 */
#define R128_BUFFER_USED	0xffffffff
#define R128_BUFFER_FREE	0

#if 0
static int r128_freelist_init( drm_device_t *dev )
{
	drm_device_dma_t *dma = dev->dma;
	drm_r128_private_t *dev_priv = dev->dev_private;
	drm_buf_t *buf;
	drm_r128_buf_priv_t *buf_priv;
	drm_r128_freelist_t *entry;
	int i;

	dev_priv->head = DRM(alloc)( sizeof(drm_r128_freelist_t),
				     DRM_MEM_DRIVER );
	if ( dev_priv->head == NULL )
		return DRM_ERR(ENOMEM);

	memset( dev_priv->head, 0, sizeof(drm_r128_freelist_t) );
	dev_priv->head->age = R128_BUFFER_USED;

	for ( i = 0 ; i < dma->buf_count ; i++ ) {
		buf = dma->buflist[i];
		buf_priv = buf->dev_private;

		entry = DRM(alloc)( sizeof(drm_r128_freelist_t),
				    DRM_MEM_DRIVER );
		if ( !entry ) return DRM_ERR(ENOMEM);

		entry->age = R128_BUFFER_FREE;
		entry->buf = buf;
		entry->prev = dev_priv->head;
		entry->next = dev_priv->head->next;
		if ( !entry->next )
			dev_priv->tail = entry;

		buf_priv->discard = 0;
		buf_priv->dispatched = 0;
		buf_priv->list_entry = entry;

		dev_priv->head->next = entry;

		if ( dev_priv->head->next )
			dev_priv->head->next->prev = entry;
	}

	return 0;

}
#endif

drm_buf_t *r128_freelist_get( drm_device_t *dev )
{
	drm_device_dma_t *dma = dev->dma;
	drm_r128_private_t *dev_priv = dev->dev_private;
	drm_r128_buf_priv_t *buf_priv;
	drm_buf_t *buf;
	int i, t;

	/* FIXME: Optimize -- use freelist code */

	for ( i = 0 ; i < dma->buf_count ; i++ ) {
		buf = dma->buflist[i];
		buf_priv = buf->dev_private;
		if ( buf->filp == 0 )
			return buf;
	}

	for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) {
		u32 done_age = R128_READ( R128_LAST_DISPATCH_REG );

		for ( i = 0 ; i < dma->buf_count ; i++ ) {
			buf = dma->buflist[i];
			buf_priv = buf->dev_private;
			if ( buf->pending && buf_priv->age <= done_age ) {
				/* The buffer has been processed, so it
				 * can now be used.
				 */
				buf->pending = 0;
				return buf;
			}
		}
		DRM_UDELAY( 1 );
	}

	DRM_DEBUG( "returning NULL!\n" );
	return NULL;
}

void r128_freelist_reset( drm_device_t *dev )
{
	drm_device_dma_t *dma = dev->dma;
	int i;

	for ( i = 0 ; i < dma->buf_count ; i++ ) {
		drm_buf_t *buf = dma->buflist[i];
		drm_r128_buf_priv_t *buf_priv = buf->dev_private;
		buf_priv->age = 0;
	}
}


/* ================================================================
 * CCE command submission
 */

int r128_wait_ring( drm_r128_private_t *dev_priv, int n )
{
	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
	int i;

	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
		r128_update_ring_snapshot( dev_priv );
		if ( ring->space >= n )
			return 0;
		DRM_UDELAY( 1 );
	}

	/* FIXME: This is being ignored... */
	DRM_ERROR( "failed!\n" );
	return DRM_ERR(EBUSY);
}

static int r128_cce_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d )
{
	int i;
	drm_buf_t *buf;

	for ( i = d->granted_count ; i < d->request_count ; i++ ) {
		buf = r128_freelist_get( dev );
		if ( !buf ) return DRM_ERR(EAGAIN);

		buf->filp = filp;

		if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx,
				   sizeof(buf->idx) ) )
			return DRM_ERR(EFAULT);
		if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total,
				   sizeof(buf->total) ) )
			return DRM_ERR(EFAULT);

		d->granted_count++;
	}
	return 0;
}

int r128_cce_buffers( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	int ret = 0;
	drm_dma_t __user *argp = (void __user *)data;
	drm_dma_t d;

	LOCK_TEST_WITH_RETURN( dev, filp );

	DRM_COPY_FROM_USER_IOCTL( d, argp, sizeof(d) );

	/* Please don't send us buffers.
	 */
	if ( d.send_count != 0 ) {
		DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n",
			   DRM_CURRENTPID, d.send_count );
		return DRM_ERR(EINVAL);
	}

	/* We'll send you buffers.
	 */
	if ( d.request_count < 0 || d.request_count > dma->buf_count ) {
		DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n",
			   DRM_CURRENTPID, d.request_count, dma->buf_count );
		return DRM_ERR(EINVAL);
	}

	d.granted_count = 0;

	if ( d.request_count ) {
		ret = r128_cce_get_buffers( filp, dev, &d );
	}

	DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d) );

	return ret;
}
pt">); va_end(va); } static int decode_MI_SET_CONTEXT(struct drm_intel_decode *ctx) { uint32_t data = ctx->data[1]; if (ctx->gen > 7) return 1; instr_out(ctx, 0, "MI_SET_CONTEXT\n"); instr_out(ctx, 1, "gtt offset = 0x%x%s%s\n", data & ~0xfff, data & (1<<1)? ", Force Restore": "", data & (1<<0)? ", Restore Inhibit": ""); return 2; } static int decode_MI_WAIT_FOR_EVENT(struct drm_intel_decode *ctx) { const char *cc_wait; int cc_shift = 0; uint32_t data = ctx->data[0]; if (ctx->gen <= 5) cc_shift = 9; else cc_shift = 16; switch ((data >> cc_shift) & 0x1f) { case 1: cc_wait = ", cc wait 1"; break; case 2: cc_wait = ", cc wait 2"; break; case 3: cc_wait = ", cc wait 3"; break; case 4: cc_wait = ", cc wait 4"; break; case 5: cc_wait = ", cc wait 4"; break; default: cc_wait = ""; break; } if (ctx->gen <= 5) { instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", data & (1<<18)? ", pipe B start vblank wait": "", data & (1<<17)? ", pipe A start vblank wait": "", data & (1<<16)? ", overlay flip pending wait": "", data & (1<<14)? ", pipe B hblank wait": "", data & (1<<13)? ", pipe A hblank wait": "", cc_wait, data & (1<<8)? ", plane C pending flip wait": "", data & (1<<7)? ", pipe B vblank wait": "", data & (1<<6)? ", plane B pending flip wait": "", data & (1<<5)? ", pipe B scan line wait": "", data & (1<<4)? ", fbc idle wait": "", data & (1<<3)? ", pipe A vblank wait": "", data & (1<<2)? ", plane A pending flip wait": "", data & (1<<1)? ", plane A scan line wait": ""); } else { instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s\n", data & (1<<20)? ", sprite C pending flip wait": "", /* ivb */ cc_wait, data & (1<<13)? ", pipe B hblank wait": "", data & (1<<11)? ", pipe B vblank wait": "", data & (1<<10)? ", sprite B pending flip wait": "", data & (1<<9)? ", plane B pending flip wait": "", data & (1<<8)? ", plane B scan line wait": "", data & (1<<5)? ", pipe A hblank wait": "", data & (1<<3)? ", pipe A vblank wait": "", data & (1<<2)? ", sprite A pending flip wait": "", data & (1<<1)? ", plane A pending flip wait": "", data & (1<<0)? ", plane A scan line wait": ""); } return 1; } static int decode_mi(struct drm_intel_decode *ctx) { unsigned int opcode, len = -1; const char *post_sync_op = ""; uint32_t *data = ctx->data; struct { uint32_t opcode; int len_mask; unsigned int min_len; unsigned int max_len; const char *name; int (*func)(struct drm_intel_decode *ctx); } opcodes_mi[] = { { 0x08, 0, 1, 1, "MI_ARB_ON_OFF" }, { 0x0a, 0, 1, 1, "MI_BATCH_BUFFER_END" }, { 0x30, 0x3f, 3, 3, "MI_BATCH_BUFFER" }, { 0x31, 0x3f, 2, 2, "MI_BATCH_BUFFER_START" }, { 0x14, 0x3f, 3, 3, "MI_DISPLAY_BUFFER_INFO" }, { 0x04, 0, 1, 1, "MI_FLUSH" }, { 0x22, 0x1f, 3, 3, "MI_LOAD_REGISTER_IMM" }, { 0x13, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_EXCL" }, { 0x12, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_INCL" }, { 0x00, 0, 1, 1, "MI_NOOP" }, { 0x11, 0x3f, 2, 2, "MI_OVERLAY_FLIP" }, { 0x07, 0, 1, 1, "MI_REPORT_HEAD" }, { 0x18, 0x3f, 2, 2, "MI_SET_CONTEXT", decode_MI_SET_CONTEXT }, { 0x20, 0x3f, 3, 4, "MI_STORE_DATA_IMM" }, { 0x21, 0x3f, 3, 4, "MI_STORE_DATA_INDEX" }, { 0x24, 0x3f, 3, 3, "MI_STORE_REGISTER_MEM" }, { 0x02, 0, 1, 1, "MI_USER_INTERRUPT" }, { 0x03, 0, 1, 1, "MI_WAIT_FOR_EVENT", decode_MI_WAIT_FOR_EVENT }, { 0x16, 0x7f, 3, 3, "MI_SEMAPHORE_MBOX" }, { 0x26, 0x1f, 3, 4, "MI_FLUSH_DW" }, { 0x0b, 0, 1, 1, "MI_SUSPEND_FLUSH"}, }, *opcode_mi = NULL; /* check instruction length */ for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); opcode++) { if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { len = 1; if (opcodes_mi[opcode].max_len > 1) { len = (data[0] & opcodes_mi[opcode].len_mask) + 2; if (len < opcodes_mi[opcode].min_len || len > opcodes_mi[opcode].max_len) { fprintf(out, "Bad length (%d) in %s, [%d, %d]\n", len, opcodes_mi[opcode].name, opcodes_mi[opcode].min_len, opcodes_mi[opcode].max_len); } } opcode_mi = &opcodes_mi[opcode]; break; } } if (opcode_mi && opcode_mi->func) return opcode_mi->func(ctx); switch ((data[0] & 0x1f800000) >> 23) { case 0x0a: instr_out(ctx, 0, "MI_BATCH_BUFFER_END\n"); return -1; case 0x16: instr_out(ctx, 0, "MI_SEMAPHORE_MBOX%s%s%s%s %u\n", data[0] & (1 << 22) ? " global gtt," : "", data[0] & (1 << 21) ? " update semaphore," : "", data[0] & (1 << 20) ? " compare semaphore," : "", data[0] & (1 << 18) ? " use compare reg" : "", (data[0] & (0x3 << 16)) >> 16); instr_out(ctx, 1, "value\n"); instr_out(ctx, 2, "address\n"); return len; case 0x21: instr_out(ctx, 0, "MI_STORE_DATA_INDEX%s\n", data[0] & (1 << 21) ? " use per-process HWS," : ""); instr_out(ctx, 1, "index\n"); instr_out(ctx, 2, "dword\n"); if (len == 4) instr_out(ctx, 3, "upper dword\n"); return len; case 0x00: if (data[0] & (1 << 22)) instr_out(ctx, 0, "MI_NOOP write NOPID reg, val=0x%x\n", data[0] & ((1 << 22) - 1)); else instr_out(ctx, 0, "MI_NOOP\n"); return len; case 0x26: switch (data[0] & (0x3 << 14)) { case (0 << 14): post_sync_op = "no write"; break; case (1 << 14): post_sync_op = "write data"; break; case (2 << 14): post_sync_op = "reserved"; break; case (3 << 14): post_sync_op = "write TIMESTAMP"; break; } instr_out(ctx, 0, "MI_FLUSH_DW%s%s%s%s post_sync_op='%s' %s%s\n", data[0] & (1 << 22) ? " enable protected mem (BCS-only)," : "", data[0] & (1 << 21) ? " store in hws," : "", data[0] & (1 << 18) ? " invalidate tlb," : "", data[0] & (1 << 17) ? " flush gfdt," : "", post_sync_op, data[0] & (1 << 8) ? " enable notify interrupt," : "", data[0] & (1 << 7) ? " invalidate video state (BCS-only)," : ""); if (data[0] & (1 << 21)) instr_out(ctx, 1, "hws index\n"); else instr_out(ctx, 1, "address\n"); instr_out(ctx, 2, "dword\n"); if (len == 4) instr_out(ctx, 3, "upper dword\n"); return len; } for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); opcode++) { if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { unsigned int i; instr_out(ctx, 0, "%s\n", opcodes_mi[opcode].name); for (i = 1; i < len; i++) { instr_out(ctx, i, "dword %d\n", i); } return len; } } instr_out(ctx, 0, "MI UNKNOWN\n"); return 1; } static void decode_2d_br00(struct drm_intel_decode *ctx, const char *cmd) { instr_out(ctx, 0, "%s (rgb %sabled, alpha %sabled, src tile %d, dst tile %d)\n", cmd, (ctx->data[0] & (1 << 20)) ? "en" : "dis", (ctx->data[0] & (1 << 21)) ? "en" : "dis", (ctx->data[0] >> 15) & 1, (ctx->data[0] >> 11) & 1); } static void decode_2d_br01(struct drm_intel_decode *ctx) { const char *format; switch ((ctx->data[1] >> 24) & 0x3) { case 0: format = "8"; break; case 1: format = "565"; break; case 2: format = "1555"; break; case 3: format = "8888"; break; } instr_out(ctx, 1, "format %s, pitch %d, rop 0x%02x, " "clipping %sabled, %s%s \n", format, (short)(ctx->data[1] & 0xffff), (ctx->data[1] >> 16) & 0xff, ctx->data[1] & (1 << 30) ? "en" : "dis", ctx->data[1] & (1 << 31) ? "solid pattern enabled, " : "", ctx->data[1] & (1 << 31) ? "mono pattern transparency enabled, " : ""); } static int decode_2d(struct drm_intel_decode *ctx) { unsigned int opcode, len; uint32_t *data = ctx->data; struct { uint32_t opcode; unsigned int min_len; unsigned int max_len; const char *name; } opcodes_2d[] = { { 0x40, 5, 5, "COLOR_BLT" }, { 0x43, 6, 6, "SRC_COPY_BLT" }, { 0x01, 8, 8, "XY_SETUP_BLT" }, { 0x11, 9, 9, "XY_SETUP_MONO_PATTERN_SL_BLT" }, { 0x03, 3, 3, "XY_SETUP_CLIP_BLT" }, { 0x24, 2, 2, "XY_PIXEL_BLT" }, { 0x25, 3, 3, "XY_SCANLINES_BLT" }, { 0x26, 4, 4, "Y_TEXT_BLT" }, { 0x31, 5, 134, "XY_TEXT_IMMEDIATE_BLT" }, { 0x50, 6, 6, "XY_COLOR_BLT" }, { 0x51, 6, 6, "XY_PAT_BLT" }, { 0x76, 8, 8, "XY_PAT_CHROMA_BLT" }, { 0x72, 7, 135, "XY_PAT_BLT_IMMEDIATE" }, { 0x77, 9, 137, "XY_PAT_CHROMA_BLT_IMMEDIATE" }, { 0x52, 9, 9, "XY_MONO_PAT_BLT" }, { 0x59, 7, 7, "XY_MONO_PAT_FIXED_BLT" }, { 0x53, 8, 8, "XY_SRC_COPY_BLT" }, { 0x54, 8, 8, "XY_MONO_SRC_COPY_BLT" }, { 0x71, 9, 137, "XY_MONO_SRC_COPY_IMMEDIATE_BLT" }, { 0x55, 9, 9, "XY_FULL_BLT" }, { 0x55, 9, 137, "XY_FULL_IMMEDIATE_PATTERN_BLT" }, { 0x56, 9, 9, "XY_FULL_MONO_SRC_BLT" }, { 0x75, 10, 138, "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT" }, { 0x57, 12, 12, "XY_FULL_MONO_PATTERN_BLT" }, { 0x58, 12, 12, "XY_FULL_MONO_PATTERN_MONO_SRC_BLT"}, }; switch ((data[0] & 0x1fc00000) >> 22) { case 0x25: instr_out(ctx, 0, "XY_SCANLINES_BLT (pattern seed (%d, %d), dst tile %d)\n", (data[0] >> 12) & 0x8, (data[0] >> 8) & 0x8, (data[0] >> 11) & 1); len = (data[0] & 0x000000ff) + 2; if (len != 3) fprintf(out, "Bad count in XY_SCANLINES_BLT\n"); instr_out(ctx, 1, "dest (%d,%d)\n", data[1] & 0xffff, data[1] >> 16); instr_out(ctx, 2, "dest (%d,%d)\n", data[2] & 0xffff, data[2] >> 16); return len; case 0x01: decode_2d_br00(ctx, "XY_SETUP_BLT"); len = (data[0] & 0x000000ff) + 2; if (len != 8) fprintf(out, "Bad count in XY_SETUP_BLT\n"); decode_2d_br01(ctx); instr_out(ctx, 2, "cliprect (%d,%d)\n", data[2] & 0xffff, data[2] >> 16); instr_out(ctx, 3, "cliprect (%d,%d)\n", data[3] & 0xffff, data[3] >> 16); instr_out(ctx, 4, "setup dst offset 0x%08x\n", data[4]); instr_out(ctx, 5, "setup background color\n"); instr_out(ctx, 6, "setup foreground color\n"); instr_out(ctx, 7, "color pattern offset\n"); return len; case 0x03: decode_2d_br00(ctx, "XY_SETUP_CLIP_BLT"); len = (data[0] & 0x000000ff) + 2; if (len != 3) fprintf(out, "Bad count in XY_SETUP_CLIP_BLT\n"); instr_out(ctx, 1, "cliprect (%d,%d)\n", data[1] & 0xffff, data[2] >> 16); instr_out(ctx, 2, "cliprect (%d,%d)\n", data[2] & 0xffff, data[3] >> 16); return len; case 0x11: decode_2d_br00(ctx, "XY_SETUP_MONO_PATTERN_SL_BLT"); len = (data[0] & 0x000000ff) + 2; if (len != 9) fprintf(out, "Bad count in XY_SETUP_MONO_PATTERN_SL_BLT\n"); decode_2d_br01(ctx); instr_out(ctx, 2, "cliprect (%d,%d)\n", data[2] & 0xffff, data[2] >> 16); instr_out(ctx, 3, "cliprect (%d,%d)\n", data[3] & 0xffff, data[3] >> 16); instr_out(ctx, 4, "setup dst offset 0x%08x\n", data[4]); instr_out(ctx, 5, "setup background color\n"); instr_out(ctx, 6, "setup foreground color\n"); instr_out(ctx, 7, "mono pattern dw0\n"); instr_out(ctx, 8, "mono pattern dw1\n"); return len; case 0x50: decode_2d_br00(ctx, "XY_COLOR_BLT"); len = (data[0] & 0x000000ff) + 2; if (len != 6) fprintf(out, "Bad count in XY_COLOR_BLT\n"); decode_2d_br01(ctx); instr_out(ctx, 2, "(%d,%d)\n", data[2] & 0xffff, data[2] >> 16); instr_out(ctx, 3, "(%d,%d)\n", data[3] & 0xffff, data[3] >> 16); instr_out(ctx, 4, "offset 0x%08x\n", data[4]); instr_out(ctx, 5, "color\n"); return len; case 0x53: decode_2d_br00(ctx, "XY_SRC_COPY_BLT"); len = (data[0] & 0x000000ff) + 2; if (len != 8) fprintf(out, "Bad count in XY_SRC_COPY_BLT\n"); decode_2d_br01(ctx); instr_out(ctx, 2, "dst (%d,%d)\n", data[2] & 0xffff, data[2] >> 16); instr_out(ctx, 3, "dst (%d,%d)\n", data[3] & 0xffff, data[3] >> 16); instr_out(ctx, 4, "dst offset 0x%08x\n", data[4]); instr_out(ctx, 5, "src (%d,%d)\n", data[5] & 0xffff, data[5] >> 16); instr_out(ctx, 6, "src pitch %d\n", (short)(data[6] & 0xffff)); instr_out(ctx, 7, "src offset 0x%08x\n", data[7]); return len; } for (opcode = 0; opcode < sizeof(opcodes_2d) / sizeof(opcodes_2d[0]); opcode++) { if ((data[0] & 0x1fc00000) >> 22 == opcodes_2d[opcode].opcode) { unsigned int i; len = 1; instr_out(ctx, 0, "%s\n", opcodes_2d[opcode].name); if (opcodes_2d[opcode].max_len > 1) { len = (data[0] & 0x000000ff) + 2; if (len < opcodes_2d[opcode].min_len || len > opcodes_2d[opcode].max_len) { fprintf(out, "Bad count in %s\n", opcodes_2d[opcode].name); } } for (i = 1; i < len; i++) { instr_out(ctx, i, "dword %d\n", i); } return len; } } instr_out(ctx, 0, "2D UNKNOWN\n"); return 1; } static int decode_3d_1c(struct drm_intel_decode *ctx) { uint32_t *data = ctx->data; uint32_t opcode; opcode = (data[0] & 0x00f80000) >> 19; switch (opcode) { case 0x11: instr_out(ctx, 0, "3DSTATE_DEPTH_SUBRECTANGLE_DISABLE\n"); return 1; case 0x10: instr_out(ctx, 0, "3DSTATE_SCISSOR_ENABLE %s\n", data[0] & 1 ? "enabled" : "disabled"); return 1; case 0x01: instr_out(ctx, 0, "3DSTATE_MAP_COORD_SET_I830\n"); return 1; case 0x0a: instr_out(ctx, 0, "3DSTATE_MAP_CUBE_I830\n"); return 1; case 0x05: instr_out(ctx, 0, "3DSTATE_MAP_TEX_STREAM_I830\n"); return 1; } instr_out(ctx, 0, "3D UNKNOWN: 3d_1c opcode = 0x%x\n", opcode); return 1; } /** Sets the string dstname to describe the destination of the PS instruction */ static void i915_get_instruction_dst(uint32_t *data, int i, char *dstname, int do_mask) { uint32_t a0 = data[i]; int dst_nr = (a0 >> 14) & 0xf; char dstmask[8]; const char *sat; if (do_mask) { if (((a0 >> 10) & 0xf) == 0xf) { dstmask[0] = 0; } else { int dstmask_index = 0; dstmask[dstmask_index++] = '.'; if (a0 & (1 << 10)) dstmask[dstmask_index++] = 'x'; if (a0 & (1 << 11)) dstmask[dstmask_index++] = 'y'; if (a0 & (1 << 12)) dstmask[dstmask_index++] = 'z'; if (a0 & (1 << 13)) dstmask[dstmask_index++] = 'w'; dstmask[dstmask_index++] = 0; } if (a0 & (1 << 22)) sat = ".sat"; else sat = ""; } else { dstmask[0] = 0; sat = ""; } switch ((a0 >> 19) & 0x7) { case 0: if (dst_nr > 15) fprintf(out, "bad destination reg R%d\n", dst_nr); sprintf(dstname, "R%d%s%s", dst_nr, dstmask, sat); break; case 4: if (dst_nr > 0) fprintf(out, "bad destination reg oC%d\n", dst_nr); sprintf(dstname, "oC%s%s", dstmask, sat); break; case 5: if (dst_nr > 0) fprintf(out, "bad destination reg oD%d\n", dst_nr); sprintf(dstname, "oD%s%s", dstmask, sat); break; case 6: if (dst_nr > 3) fprintf(out, "bad destination reg U%d\n", dst_nr); sprintf(dstname, "U%d%s%s", dst_nr, dstmask, sat); break; default: sprintf(dstname, "RESERVED"); break; } } static const char * i915_get_channel_swizzle(uint32_t select) { switch (select & 0x7) { case 0: return (select & 8) ? "-x" : "x"; case 1: return (select & 8) ? "-y" : "y"; case 2: return (select & 8) ? "-z" : "z"; case 3: return (select & 8) ? "-w" : "w"; case 4: return (select & 8) ? "-0" : "0"; case 5: return (select & 8) ? "-1" : "1"; default: return (select & 8) ? "-bad" : "bad"; } } static void i915_get_instruction_src_name(uint32_t src_type, uint32_t src_nr, char *name) { switch (src_type) { case 0: sprintf(name, "R%d", src_nr); if (src_nr > 15) fprintf(out, "bad src reg %s\n", name); break; case 1: if (src_nr < 8) sprintf(name, "T%d", src_nr); else if (src_nr == 8) sprintf(name, "DIFFUSE"); else if (src_nr == 9) sprintf(name, "SPECULAR"); else if (src_nr == 10) sprintf(name, "FOG"); else { fprintf(out, "bad src reg T%d\n", src_nr); sprintf(name, "RESERVED"); } break; case 2: sprintf(name, "C%d", src_nr); if (src_nr > 31) fprintf(out, "bad src reg %s\n", name); break; case 4: sprintf(name, "oC"); if (src_nr > 0) fprintf(out, "bad src reg oC%d\n", src_nr); break; case 5: sprintf(name, "oD"); if (src_nr > 0) fprintf(out, "bad src reg oD%d\n", src_nr); break; case 6: sprintf(name, "U%d", src_nr); if (src_nr > 3) fprintf(out, "bad src reg %s\n", name); break; default: fprintf(out, "bad src reg type %d\n", src_type); sprintf(name, "RESERVED"); break; } } static void i915_get_instruction_src0(uint32_t *data, int i, char *srcname) { uint32_t a0 = data[i]; uint32_t a1 = data[i + 1]; int src_nr = (a0 >> 2) & 0x1f; const char *swizzle_x = i915_get_channel_swizzle((a1 >> 28) & 0xf); const char *swizzle_y = i915_get_channel_swizzle((a1 >> 24) & 0xf); const char *swizzle_z = i915_get_channel_swizzle((a1 >> 20) & 0xf); const char *swizzle_w = i915_get_channel_swizzle((a1 >> 16) & 0xf); char swizzle[100]; i915_get_instruction_src_name((a0 >> 7) & 0x7, src_nr, srcname); sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, swizzle_w); if (strcmp(swizzle, ".xyzw") != 0) strcat(srcname, swizzle); } static void i915_get_instruction_src1(uint32_t *data, int i, char *srcname) { uint32_t a1 = data[i + 1]; uint32_t a2 = data[i + 2]; int src_nr = (a1 >> 8) & 0x1f; const char *swizzle_x = i915_get_channel_swizzle((a1 >> 4) & 0xf); const char *swizzle_y = i915_get_channel_swizzle((a1 >> 0) & 0xf); const char *swizzle_z = i915_get_channel_swizzle((a2 >> 28) & 0xf); const char *swizzle_w = i915_get_channel_swizzle((a2 >> 24) & 0xf); char swizzle[100]; i915_get_instruction_src_name((a1 >> 13) & 0x7, src_nr, srcname); sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, swizzle_w); if (strcmp(swizzle, ".xyzw") != 0) strcat(srcname, swizzle); } static void i915_get_instruction_src2(uint32_t *data, int i, char *srcname) { uint32_t a2 = data[i + 2]; int src_nr = (a2 >> 16) & 0x1f; const char *swizzle_x = i915_get_channel_swizzle((a2 >> 12) & 0xf); const char *swizzle_y = i915_get_channel_swizzle((a2 >> 8) & 0xf); const char *swizzle_z = i915_get_channel_swizzle((a2 >> 4) & 0xf); const char *swizzle_w = i915_get_channel_swizzle((a2 >> 0) & 0xf); char swizzle[100]; i915_get_instruction_src_name((a2 >> 21) & 0x7, src_nr, srcname); sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, swizzle_w); if (strcmp(swizzle, ".xyzw") != 0) strcat(srcname, swizzle); } static void i915_get_instruction_addr(uint32_t src_type, uint32_t src_nr, char *name) { switch (src_type) { case 0: sprintf(name, "R%d", src_nr); if (src_nr > 15) fprintf(out, "bad src reg %s\n", name); break; case 1: if (src_nr < 8) sprintf(name, "T%d", src_nr); else if (src_nr == 8) sprintf(name, "DIFFUSE"); else if (src_nr == 9) sprintf(name, "SPECULAR"); else if (src_nr == 10) sprintf(name, "FOG"); else { fprintf(out, "bad src reg T%d\n", src_nr); sprintf(name, "RESERVED"); } break; case 4: sprintf(name, "oC"); if (src_nr > 0) fprintf(out, "bad src reg oC%d\n", src_nr); break; case 5: sprintf(name, "oD"); if (src_nr > 0) fprintf(out, "bad src reg oD%d\n", src_nr); break; default: fprintf(out, "bad src reg type %d\n", src_type); sprintf(name, "RESERVED"); break; } } static void i915_decode_alu1(struct drm_intel_decode *ctx, int i, char *instr_prefix, const char *op_name) { char dst[100], src0[100]; i915_get_instruction_dst(ctx->data, i, dst, 1); i915_get_instruction_src0(ctx->data, i, src0); instr_out(ctx, i++, "%s: %s %s, %s\n", instr_prefix, op_name, dst, src0); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); } static void i915_decode_alu2(struct drm_intel_decode *ctx, int i, char *instr_prefix, const char *op_name) { char dst[100], src0[100], src1[100]; i915_get_instruction_dst(ctx->data, i, dst, 1); i915_get_instruction_src0(ctx->data, i, src0); i915_get_instruction_src1(ctx->data, i, src1); instr_out(ctx, i++, "%s: %s %s, %s, %s\n", instr_prefix, op_name, dst, src0, src1); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); } static void i915_decode_alu3(struct drm_intel_decode *ctx, int i, char *instr_prefix, const char *op_name) { char dst[100], src0[100], src1[100], src2[100]; i915_get_instruction_dst(ctx->data, i, dst, 1); i915_get_instruction_src0(ctx->data, i, src0); i915_get_instruction_src1(ctx->data, i, src1); i915_get_instruction_src2(ctx->data, i, src2); instr_out(ctx, i++, "%s: %s %s, %s, %s, %s\n", instr_prefix, op_name, dst, src0, src1, src2); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); } static void i915_decode_tex(struct drm_intel_decode *ctx, int i, const char *instr_prefix, const char *tex_name) { uint32_t t0 = ctx->data[i]; uint32_t t1 = ctx->data[i + 1]; char dst_name[100]; char addr_name[100]; int sampler_nr; i915_get_instruction_dst(ctx->data, i, dst_name, 0); i915_get_instruction_addr((t1 >> 24) & 0x7, (t1 >> 17) & 0xf, addr_name); sampler_nr = t0 & 0xf; instr_out(ctx, i++, "%s: %s %s, S%d, %s\n", instr_prefix, tex_name, dst_name, sampler_nr, addr_name); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); } static void i915_decode_dcl(struct drm_intel_decode *ctx, int i, char *instr_prefix) { uint32_t d0 = ctx->data[i]; const char *sampletype; int dcl_nr = (d0 >> 14) & 0xf; const char *dcl_x = d0 & (1 << 10) ? "x" : ""; const char *dcl_y = d0 & (1 << 11) ? "y" : ""; const char *dcl_z = d0 & (1 << 12) ? "z" : ""; const char *dcl_w = d0 & (1 << 13) ? "w" : ""; char dcl_mask[10]; switch ((d0 >> 19) & 0x3) { case 1: sprintf(dcl_mask, ".%s%s%s%s", dcl_x, dcl_y, dcl_z, dcl_w); if (strcmp(dcl_mask, ".") == 0) fprintf(out, "bad (empty) dcl mask\n"); if (dcl_nr > 10) fprintf(out, "bad T%d dcl register number\n", dcl_nr); if (dcl_nr < 8) { if (strcmp(dcl_mask, ".x") != 0 && strcmp(dcl_mask, ".xy") != 0 && strcmp(dcl_mask, ".xz") != 0 && strcmp(dcl_mask, ".w") != 0 && strcmp(dcl_mask, ".xyzw") != 0) { fprintf(out, "bad T%d.%s dcl mask\n", dcl_nr, dcl_mask); } instr_out(ctx, i++, "%s: DCL T%d%s\n", instr_prefix, dcl_nr, dcl_mask); } else { if (strcmp(dcl_mask, ".xz") == 0) fprintf(out, "errataed bad dcl mask %s\n", dcl_mask); else if (strcmp(dcl_mask, ".xw") == 0) fprintf(out, "errataed bad dcl mask %s\n", dcl_mask); else if (strcmp(dcl_mask, ".xzw") == 0) fprintf(out, "errataed bad dcl mask %s\n", dcl_mask); if (dcl_nr == 8) { instr_out(ctx, i++, "%s: DCL DIFFUSE%s\n", instr_prefix, dcl_mask); } else if (dcl_nr == 9) { instr_out(ctx, i++, "%s: DCL SPECULAR%s\n", instr_prefix, dcl_mask); } else if (dcl_nr == 10) { instr_out(ctx, i++, "%s: DCL FOG%s\n", instr_prefix, dcl_mask); } } instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); break; case 3: switch ((d0 >> 22) & 0x3) { case 0: sampletype = "2D"; break; case 1: sampletype = "CUBE"; break; case 2: sampletype = "3D"; break; default: sampletype = "RESERVED"; break; } if (dcl_nr > 15) fprintf(out, "bad S%d dcl register number\n", dcl_nr); instr_out(ctx, i++, "%s: DCL S%d %s\n", instr_prefix, dcl_nr, sampletype); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); break; default: instr_out(ctx, i++, "%s: DCL RESERVED%d\n", instr_prefix, dcl_nr); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); } } static void i915_decode_instruction(struct drm_intel_decode *ctx, int i, char *instr_prefix) { switch ((ctx->data[i] >> 24) & 0x1f) { case 0x0: instr_out(ctx, i++, "%s: NOP\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); break; case 0x01: i915_decode_alu2(ctx, i, instr_prefix, "ADD"); break; case 0x02: i915_decode_alu1(ctx, i, instr_prefix, "MOV"); break; case 0x03: i915_decode_alu2(ctx, i, instr_prefix, "MUL"); break; case 0x04: i915_decode_alu3(ctx, i, instr_prefix, "MAD"); break; case 0x05: i915_decode_alu3(ctx, i, instr_prefix, "DP2ADD"); break; case 0x06: i915_decode_alu2(ctx, i, instr_prefix, "DP3"); break; case 0x07: i915_decode_alu2(ctx, i, instr_prefix, "DP4"); break; case 0x08: i915_decode_alu1(ctx, i, instr_prefix, "FRC"); break; case 0x09: i915_decode_alu1(ctx, i, instr_prefix, "RCP"); break; case 0x0a: i915_decode_alu1(ctx, i, instr_prefix, "RSQ"); break; case 0x0b: i915_decode_alu1(ctx, i, instr_prefix, "EXP"); break; case 0x0c: i915_decode_alu1(ctx, i, instr_prefix, "LOG"); break; case 0x0d: i915_decode_alu2(ctx, i, instr_prefix, "CMP"); break; case 0x0e: i915_decode_alu2(ctx, i, instr_prefix, "MIN"); break; case 0x0f: i915_decode_alu2(ctx, i, instr_prefix, "MAX"); break; case 0x10: i915_decode_alu1(ctx, i, instr_prefix, "FLR"); break; case 0x11: i915_decode_alu1(ctx, i, instr_prefix, "MOD"); break; case 0x12: i915_decode_alu1(ctx, i, instr_prefix, "TRC"); break; case 0x13: i915_decode_alu2(ctx, i, instr_prefix, "SGE"); break; case 0x14: i915_decode_alu2(ctx, i, instr_prefix, "SLT"); break; case 0x15: i915_decode_tex(ctx, i, instr_prefix, "TEXLD"); break; case 0x16: i915_decode_tex(ctx, i, instr_prefix, "TEXLDP"); break; case 0x17: i915_decode_tex(ctx, i, instr_prefix, "TEXLDB"); break; case 0x19: i915_decode_dcl(ctx, i, instr_prefix); break; default: instr_out(ctx, i++, "%s: unknown\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); instr_out(ctx, i++, "%s\n", instr_prefix); break; } } static const char * decode_compare_func(uint32_t op) { switch (op & 0x7) { case 0: return "always"; case 1: return "never"; case 2: return "less"; case 3: return "equal"; case 4: return "lequal"; case 5: return "greater"; case 6: return "notequal"; case 7: return "gequal"; } return ""; } static const char * decode_stencil_op(uint32_t op) { switch (op & 0x7) { case 0: return "keep"; case 1: return "zero"; case 2: return "replace"; case 3: return "incr_sat"; case 4: return "decr_sat"; case 5: return "greater"; case 6: return "incr"; case 7: return "decr"; } return ""; } #if 0 static const char * decode_logic_op(uint32_t op) { switch (op & 0xf) { case 0: return "clear"; case 1: return "nor"; case 2: return "and_inv"; case 3: return "copy_inv"; case 4: return "and_rvrse"; case 5: return "inv"; case 6: return "xor"; case 7: return "nand"; case 8: return "and"; case 9: return "equiv"; case 10: return "noop"; case 11: return "or_inv"; case 12: return "copy"; case 13: return "or_rvrse"; case 14: return "or"; case 15: return "set"; } return ""; } #endif static const char * decode_blend_fact(uint32_t op) { switch (op & 0xf) { case 1: return "zero"; case 2: return "one"; case 3: return "src_colr"; case 4: return "inv_src_colr"; case 5: return "src_alpha"; case 6: return "inv_src_alpha"; case 7: return "dst_alpha"; case 8: return "inv_dst_alpha"; case 9: return "dst_colr"; case 10: return "inv_dst_colr"; case 11: return "src_alpha_sat"; case 12: return "cnst_colr"; case 13: return "inv_cnst_colr"; case 14: return "cnst_alpha"; case 15: return "inv_const_alpha"; } return ""; } static const char * decode_tex_coord_mode(uint32_t mode) { switch (mode & 0x7) { case 0: return "wrap"; case 1: return "mirror"; case 2: return "clamp_edge"; case 3: return "cube"; case 4: return "clamp_border"; case 5: return "mirror_once"; } return ""; } static const char * decode_sample_filter(uint32_t mode) { switch (mode & 0x7) { case 0: return "nearest"; case 1: return "linear"; case 2: return "anisotropic"; case 3: return "4x4_1"; case 4: return "4x4_2"; case 5: return "4x4_flat"; case 6: return "6x5_mono"; } return ""; } static int decode_3d_1d(struct drm_intel_decode *ctx) { unsigned int len, i, c, idx, word, map, sampler, instr; const char *format, *zformat, *type; uint32_t opcode; uint32_t *data = ctx->data; uint32_t devid = ctx->devid; struct { uint32_t opcode; int i830_only; unsigned int min_len; unsigned int max_len; const char *name; } opcodes_3d_1d[] = { { 0x86, 0, 4, 4, "3DSTATE_CHROMA_KEY" }, { 0x88, 0, 2, 2, "3DSTATE_CONSTANT_BLEND_COLOR" }, { 0x99, 0, 2, 2, "3DSTATE_DEFAULT_DIFFUSE" }, { 0x9a, 0, 2, 2, "3DSTATE_DEFAULT_SPECULAR" }, { 0x98, 0, 2, 2, "3DSTATE_DEFAULT_Z" }, { 0x97, 0, 2, 2, "3DSTATE_DEPTH_OFFSET_SCALE" }, { 0x9d, 0, 65, 65, "3DSTATE_FILTER_COEFFICIENTS_4X4" }, { 0x9e, 0, 4, 4, "3DSTATE_MONO_FILTER" }, { 0x89, 0, 4, 4, "3DSTATE_FOG_MODE" }, { 0x8f, 0, 2, 16, "3DSTATE_MAP_PALLETE_LOAD_32" }, { 0x83, 0, 2, 2, "3DSTATE_SPAN_STIPPLE" }, { 0x8c, 1, 2, 2, "3DSTATE_MAP_COORD_TRANSFORM_I830" }, { 0x8b, 1, 2, 2, "3DSTATE_MAP_VERTEX_TRANSFORM_I830" }, { 0x8d, 1, 3, 3, "3DSTATE_W_STATE_I830" }, { 0x01, 1, 2, 2, "3DSTATE_COLOR_FACTOR_I830" }, { 0x02, 1, 2, 2, "3DSTATE_MAP_COORD_SETBIND_I830"}, }, *opcode_3d_1d; opcode = (data[0] & 0x00ff0000) >> 16; switch (opcode) { case 0x07: /* This instruction is unusual. A 0 length means just * 1 DWORD instead of 2. The 0 length is specified in * one place to be unsupported, but stated to be * required in another, and 0 length LOAD_INDIRECTs * appear to cause no harm at least. */ instr_out(ctx, 0, "3DSTATE_LOAD_INDIRECT\n"); len = (data[0] & 0x000000ff) + 1; i = 1; if (data[0] & (0x01 << 8)) { instr_out(ctx, i++, "SIS.0\n"); instr_out(ctx, i++, "SIS.1\n"); } if (data[0] & (0x02 << 8)) { instr_out(ctx, i++, "DIS.0\n"); } if (data[0] & (0x04 << 8)) { instr_out(ctx, i++, "SSB.0\n"); instr_out(ctx, i++, "SSB.1\n"); } if (data[0] & (0x08 << 8)) { instr_out(ctx, i++, "MSB.0\n"); instr_out(ctx, i++, "MSB.1\n"); } if (data[0] & (0x10 << 8)) { instr_out(ctx, i++, "PSP.0\n"); instr_out(ctx, i++, "PSP.1\n"); } if (data[0] & (0x20 << 8)) { instr_out(ctx, i++, "PSC.0\n"); instr_out(ctx, i++, "PSC.1\n"); } if (len != i) { fprintf(out, "Bad count in 3DSTATE_LOAD_INDIRECT\n"); return len; } return len; case 0x04: instr_out(ctx, 0, "3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); len = (data[0] & 0x0000000f) + 2; i = 1; for (word = 0; word <= 8; word++) { if (data[0] & (1 << (4 + word))) { /* save vertex state for decode */ if (!IS_GEN2(devid)) { int tex_num; if (word == 2) { saved_s2_set = 1; saved_s2 = data[i]; } if (word == 4) { saved_s4_set = 1; saved_s4 = data[i]; } switch (word) { case 0: instr_out(ctx, i, "S0: vbo offset: 0x%08x%s\n", data[i] & (~1), data[i] & 1 ? ", auto cache invalidate disabled" : ""); break; case 1: instr_out(ctx, i, "S1: vertex width: %i, vertex pitch: %i\n", (data[i] >> 24) & 0x3f, (data[i] >> 16) & 0x3f); break; case 2: instr_out(ctx, i, "S2: texcoord formats: "); for (tex_num = 0; tex_num < 8; tex_num++) { switch ((data[i] >> tex_num * 4) & 0xf) { case 0: fprintf(out, "%i=2D ", tex_num); break; case 1: fprintf(out, "%i=3D ", tex_num); break; case 2: fprintf(out, "%i=4D ", tex_num); break; case 3: fprintf(out, "%i=1D ", tex_num); break; case 4: fprintf(out, "%i=2D_16 ", tex_num); break; case 5: fprintf(out, "%i=4D_16 ", tex_num); break; case 0xf: fprintf(out, "%i=NP ", tex_num); break; } } fprintf(out, "\n"); break; case 3: instr_out(ctx, i, "S3: not documented\n"); break; case 4: { const char *cullmode = ""; const char *vfmt_xyzw = ""; switch ((data[i] >> 13) & 0x3) { case 0: cullmode = "both"; break; case 1: cullmode = "none"; break; case 2: cullmode = "cw"; break; case 3: cullmode = "ccw"; break; } switch (data[i] & (7 << 6 | 1 << 2)) { case 1 << 6: vfmt_xyzw = "XYZ,"; break; case 2 << 6: vfmt_xyzw = "XYZW,"; break; case 3 << 6: vfmt_xyzw = "XY,"; break; case 4 << 6: vfmt_xyzw = "XYW,"; break; case 1 << 6 | 1 << 2: vfmt_xyzw = "XYZF,"; break; case 2 << 6 | 1 << 2: vfmt_xyzw = "XYZWF,"; break; case 3 << 6 | 1 << 2: vfmt_xyzw = "XYF,"; break; case 4 << 6 | 1 << 2: vfmt_xyzw = "XYWF,"; break; } instr_out(ctx, i, "S4: point_width=%i, line_width=%.1f," "%s%s%s%s%s cullmode=%s, vfmt=%s%s%s%s%s%s " "%s%s%s%s%s\n", (data[i] >> 23) & 0x1ff, ((data[i] >> 19) & 0xf) / 2.0, data[i] & (0xf << 15) ? " flatshade=" : "", data[i] & (1 << 18) ? "Alpha," : "", data[i] & (1 << 17) ? "Fog," : "", data[i] & (1 << 16) ? "Specular," : "", data[i] & (1 << 15) ? "Color," : "", cullmode, data[i] & (1 << 12) ? "PointWidth," : "", data[i] & (1 << 11) ? "SpecFog," : "", data[i] & (1 << 10) ? "Color," : "", data[i] & (1 << 9) ? "DepthOfs," : "", vfmt_xyzw, data[i] & (1 << 9) ? "FogParam," : "", data[i] & (1 << 5) ? "force default diffuse, " : "", data[i] & (1 << 4) ? "force default specular, " : "", data[i] & (1 << 3) ? "local depth ofs enable, " : "", data[i] & (1 << 1) ? "point sprite enable, " : "", data[i] & (1 << 0) ? "line AA enable, " : ""); break; } case 5: { instr_out(ctx, i, "S5:%s%s%s%s%s" "%s%s%s%s stencil_ref=0x%x, stencil_test=%s, " "stencil_fail=%s, stencil_pass_z_fail=%s, " "stencil_pass_z_pass=%s, %s%s%s%s\n", data[i] & (0xf << 28) ? " write_disable=" : "", data[i] & (1 << 31) ? "Alpha," : "", data[i] & (1 << 30) ? "Red," : "", data[i] & (1 << 29) ? "Green," : "", data[i] & (1 << 28) ? "Blue," : "", data[i] & (1 << 27) ? " force default point size," : "", data[i] & (1 << 26) ? " last pixel enable," : "", data[i] & (1 << 25) ? " global depth ofs enable," : "", data[i] & (1 << 24) ? " fog enable," : "", (data[i] >> 16) & 0xff, decode_compare_func (data[i] >> 13), decode_stencil_op (data[i] >> 10), decode_stencil_op (data[i] >> 7), decode_stencil_op (data[i] >> 4), data[i] & (1 << 3) ? "stencil write enable, " : "", data[i] & (1 << 2) ? "stencil test enable, " : "", data[i] & (1 << 1) ? "color dither enable, " : "", data[i] & (1 << 0) ? "logicop enable, " : ""); } break; case 6: instr_out(ctx, i, "S6: %salpha_test=%s, alpha_ref=0x%x, " "depth_test=%s, %ssrc_blnd_fct=%s, dst_blnd_fct=%s, " "%s%stristrip_provoking_vertex=%i\n", data[i] & (1 << 31) ? "alpha test enable, " : "", decode_compare_func (data[i] >> 28), data[i] & (0xff << 20), decode_compare_func (data[i] >> 16), data[i] & (1 << 15) ? "cbuf blend enable, " : "", decode_blend_fact(data [i] >> 8), decode_blend_fact(data [i] >> 4), data[i] & (1 << 3) ? "depth write enable, " : "", data[i] & (1 << 2) ? "cbuf write enable, " : "", data[i] & (0x3)); break; case 7: instr_out(ctx, i, "S7: depth offset constant: 0x%08x\n", data[i]); break; } } else { instr_out(ctx, i, "S%d: 0x%08x\n", word, data[i]); } i++; } } if (len != i) { fprintf(out, "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); } return len; case 0x03: instr_out(ctx, 0, "3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); len = (data[0] & 0x0000000f) + 2; i = 1; for (word = 6; word <= 14; word++) { if (data[0] & (1 << word)) { if (word == 6) instr_out(ctx, i++, "TBCF\n"); else if (word >= 7 && word <= 10) { instr_out(ctx, i++, "TB%dC\n", word - 7); instr_out(ctx, i++, "TB%dA\n", word - 7); } else if (word >= 11 && word <= 14) { instr_out(ctx, i, "TM%dS0: offset=0x%08x, %s\n", word - 11, data[i] & 0xfffffffe, data[i] & 1 ? "use fence" : ""); i++; instr_out(ctx, i, "TM%dS1: height=%i, width=%i, %s\n", word - 11, data[i] >> 21, (data[i] >> 10) & 0x3ff, data[i] & 2 ? (data[i] & 1 ? "y-tiled" : "x-tiled") : ""); i++; instr_out(ctx, i, "TM%dS2: pitch=%i, \n", word - 11, ((data[i] >> 21) + 1) * 4); i++; instr_out(ctx, i++, "TM%dS3\n", word - 11); instr_out(ctx, i++, "TM%dS4: dflt color\n", word - 11); } } } if (len != i) { fprintf(out, "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); } return len; case 0x00: instr_out(ctx, 0, "3DSTATE_MAP_STATE\n"); len = (data[0] & 0x0000003f) + 2; instr_out(ctx, 1, "mask\n"); i = 2; for (map = 0; map <= 15; map++) { if (data[1] & (1 << map)) { int width, height, pitch, dword; const char *tiling; dword = data[i]; instr_out(ctx, i++, "map %d MS2 %s%s%s\n", map, dword & (1 << 31) ? "untrusted surface, " : "", dword & (1 << 1) ? "vertical line stride enable, " : "", dword & (1 << 0) ? "vertical ofs enable, " : ""); dword = data[i]; width = ((dword >> 10) & ((1 << 11) - 1)) + 1; height = ((dword >> 21) & ((1 << 11) - 1)) + 1; tiling = "none"; if (dword & (1 << 2)) tiling = "fenced"; else if (dword & (1 << 1)) tiling = dword & (1 << 0) ? "Y" : "X"; type = " BAD"; format = "BAD"; switch ((dword >> 7) & 0x7) { case 1: type = "8b"; switch ((dword >> 3) & 0xf) { case 0: format = "I"; break; case 1: format = "L"; break; case 4: format = "A"; break; case 5: format = " mono"; break; } break; case 2: type = "16b"; switch ((dword >> 3) & 0xf) { case 0: format = " rgb565"; break; case 1: format = " argb1555"; break; case 2: format = " argb4444"; break; case 5: format = " ay88"; break; case 6: format = " bump655"; break; case 7: format = "I"; break; case 8: format = "L"; break; case 9: format = "A"; break; } break; case 3: type = "32b"; switch ((dword >> 3) & 0xf) { case 0: format = " argb8888"; break; case 1: format = " abgr8888"; break; case 2: format = " xrgb8888"; break; case 3: format = " xbgr8888"; break; case 4: format = " qwvu8888"; break; case 5: format = " axvu8888"; break; case 6: format = " lxvu8888"; break; case 7: format = " xlvu8888"; break; case 8: format = " argb2101010"; break; case 9: format = " abgr2101010"; break; case 10: format = " awvu2101010"; break; case 11: format = " gr1616"; break; case 12: format = " vu1616"; break; case 13: format = " xI824"; break; case 14: format = " xA824"; break; case 15: format = " xL824"; break; } break; case 5: type = "422"; switch ((dword >> 3) & 0xf) { case 0: format = " yuv_swapy"; break; case 1: format = " yuv"; break; case 2: format = " yuv_swapuv"; break; case 3: format = " yuv_swapuvy"; break; } break; case 6: type = "compressed"; switch ((dword >> 3) & 0x7) { case 0: format = " dxt1"; break; case 1: format = " dxt2_3"; break; case 2: format = " dxt4_5"; break; case 3: format = " fxt1"; break; case 4: format = " dxt1_rb"; break; } break; case 7: type = "4b indexed"; switch ((dword >> 3) & 0xf) { case 7: format = " argb8888"; break; } break; } dword = data[i]; instr_out(ctx, i++, "map %d MS3 [width=%d, height=%d, format=%s%s, tiling=%s%s]\n", map, width, height, type, format, tiling, dword & (1 << 9) ? " palette select" : ""); dword = data[i]; pitch = 4 * (((dword >> 21) & ((1 << 11) - 1)) + 1); instr_out(ctx, i++, "map %d MS4 [pitch=%d, max_lod=%i, vol_depth=%i, cube_face_ena=%x, %s]\n", map, pitch, (dword >> 9) & 0x3f, dword & 0xff, (dword >> 15) & 0x3f, dword & (1 << 8) ? "miplayout legacy" : "miplayout right"); } } if (len != i) { fprintf(out, "Bad count in 3DSTATE_MAP_STATE\n"); return len; } return len; case 0x06: instr_out(ctx, 0, "3DSTATE_PIXEL_SHADER_CONSTANTS\n"); len = (data[0] & 0x000000ff) + 2; i = 2; for (c = 0; c <= 31; c++) { if (data[1] & (1 << c)) { instr_out(ctx, i, "C%d.X = %f\n", c, int_as_float(data[i])); i++; instr_out(ctx, i, "C%d.Y = %f\n", c, int_as_float(data[i])); i++; instr_out(ctx, i, "C%d.Z = %f\n", c, int_as_float(data[i])); i++; instr_out(ctx, i, "C%d.W = %f\n", c, int_as_float(data[i])); i++; } } if (len != i) { fprintf(out, "Bad count in 3DSTATE_PIXEL_SHADER_CONSTANTS\n"); } return len; case 0x05: instr_out(ctx, 0, "3DSTATE_PIXEL_SHADER_PROGRAM\n"); len = (data[0] & 0x000000ff) + 2; if ((len - 1) % 3 != 0 || len > 370) { fprintf(out, "Bad count in 3DSTATE_PIXEL_SHADER_PROGRAM\n"); } i = 1; for (instr = 0; instr < (len - 1) / 3; instr++) { char instr_prefix[10]; sprintf(instr_prefix, "PS%03d", instr); i915_decode_instruction(ctx, i, instr_prefix); i += 3; } return len; case 0x01: if (IS_GEN2(devid)) break; instr_out(ctx, 0, "3DSTATE_SAMPLER_STATE\n"); instr_out(ctx, 1, "mask\n"); len = (data[0] & 0x0000003f) + 2; i = 2; for (sampler = 0; sampler <= 15; sampler++) { if (data[1] & (1 << sampler)) { uint32_t dword; const char *mip_filter = ""; dword = data[i]; switch ((dword >> 20) & 0x3) { case 0: mip_filter = "none"; break; case 1: mip_filter = "nearest"; break; case 3: mip_filter = "linear"; break; } instr_out(ctx, i++, "sampler %d SS2:%s%s%s " "base_mip_level=%i, mip_filter=%s, mag_filter=%s, min_filter=%s " "lod_bias=%.2f,%s max_aniso=%i, shadow_func=%s\n", sampler, dword & (1 << 31) ? " reverse gamma," : "", dword & (1 << 30) ? " packed2planar," : "", dword & (1 << 29) ? " colorspace conversion," : "", (dword >> 22) & 0x1f, mip_filter, decode_sample_filter(dword >> 17), decode_sample_filter(dword >> 14), ((dword >> 5) & 0x1ff) / (0x10 * 1.0), dword & (1 << 4) ? " shadow," : "", dword & (1 << 3) ? 4 : 2, decode_compare_func(dword)); dword = data[i]; instr_out(ctx, i++, "sampler %d SS3: min_lod=%.2f,%s " "tcmode_x=%s, tcmode_y=%s, tcmode_z=%s,%s texmap_idx=%i,%s\n", sampler, ((dword >> 24) & 0xff) / (0x10 * 1.0), dword & (1 << 17) ? " kill pixel enable," : "", decode_tex_coord_mode(dword >> 12), decode_tex_coord_mode(dword >> 9), decode_tex_coord_mode(dword >> 6), dword & (1 << 5) ? " normalized coords," : "", (dword >> 1) & 0xf, dword & (1 << 0) ? " deinterlacer," : ""); dword = data[i]; instr_out(ctx, i++, "sampler %d SS4: border color\n", sampler); } } if (len != i) { fprintf(out, "Bad count in 3DSTATE_SAMPLER_STATE\n"); } return len; case 0x85: len = (data[0] & 0x0000000f) + 2; if (len != 2) fprintf(out, "Bad count in 3DSTATE_DEST_BUFFER_VARIABLES\n"); instr_out(ctx, 0, "3DSTATE_DEST_BUFFER_VARIABLES\n"); switch ((data[1] >> 8) & 0xf) { case 0x0: format = "g8"; break; case 0x1: format = "x1r5g5b5"; break; case 0x2: format = "r5g6b5"; break; case 0x3: format = "a8r8g8b8"; break; case 0x4: format = "ycrcb_swapy"; break; case 0x5: format = "ycrcb_normal"; break; case 0x6: format = "ycrcb_swapuv"; break; case 0x7: format = "ycrcb_swapuvy"; break; case 0x8: format = "a4r4g4b4"; break; case 0x9: format = "a1r5g5b5"; break; case 0xa: format = "a2r10g10b10"; break; default: format = "BAD"; break; } switch ((data[1] >> 2) & 0x3) { case 0x0: zformat = "u16"; break; case 0x1: zformat = "f16"; break; case 0x2: zformat = "u24x8"; break; default: zformat = "BAD"; break; } instr_out(ctx, 1, "%s format, %s depth format, early Z %sabled\n", format, zformat, (data[1] & (1 << 31)) ? "en" : "dis"); return len; case 0x8e: { const char *name, *tiling; len = (data[0] & 0x0000000f) + 2; if (len != 3) fprintf(out, "Bad count in 3DSTATE_BUFFER_INFO\n"); switch ((data[1] >> 24) & 0x7) { case 0x3: name = "color"; break; case 0x7: name = "depth"; break; default: name = "unknown"; break; } tiling = "none"; if (data[1] & (1 << 23)) tiling = "fenced"; else if (data[1] & (1 << 22)) tiling = data[1] & (1 << 21) ? "Y" : "X"; instr_out(ctx, 0, "3DSTATE_BUFFER_INFO\n"); instr_out(ctx, 1, "%s, tiling = %s, pitch=%d\n", name, tiling, data[1] & 0xffff); instr_out(ctx, 2, "address\n"); return len; } case 0x81: len = (data[0] & 0x0000000f) + 2; if (len != 3) fprintf(out, "Bad count in 3DSTATE_SCISSOR_RECTANGLE\n"); instr_out(ctx, 0, "3DSTATE_SCISSOR_RECTANGLE\n"); instr_out(ctx, 1, "(%d,%d)\n", data[1] & 0xffff, data[1] >> 16); instr_out(ctx, 2, "(%d,%d)\n", data[2] & 0xffff, data[2] >> 16); return len; case 0x80: len = (data[0] & 0x0000000f) + 2; if (len != 5) fprintf(out, "Bad count in 3DSTATE_DRAWING_RECTANGLE\n"); instr_out(ctx, 0, "3DSTATE_DRAWING_RECTANGLE\n"); instr_out(ctx, 1, "%s\n", data[1] & (1 << 30) ? "depth ofs disabled " : ""); instr_out(ctx, 2, "(%d,%d)\n", data[2] & 0xffff, data[2] >> 16); instr_out(ctx, 3, "(%d,%d)\n", data[3] & 0xffff, data[3] >> 16); instr_out(ctx, 4, "(%d,%d)\n", data[4] & 0xffff, data[4] >> 16); return len; case 0x9c: len = (data[0] & 0x0000000f) + 2; if (len != 7) fprintf(out, "Bad count in 3DSTATE_CLEAR_PARAMETERS\n"); instr_out(ctx, 0, "3DSTATE_CLEAR_PARAMETERS\n"); instr_out(ctx, 1, "prim_type=%s, clear=%s%s%s\n", data[1] & (1 << 16) ? "CLEAR_RECT" : "ZONE_INIT", data[1] & (1 << 2) ? "color," : "", data[1] & (1 << 1) ? "depth," : "", data[1] & (1 << 0) ? "stencil," : ""); instr_out(ctx, 2, "clear color\n"); instr_out(ctx, 3, "clear depth/stencil\n"); instr_out(ctx, 4, "color value (rgba8888)\n"); instr_out(ctx, 5, "depth value %f\n", int_as_float(data[5])); instr_out(ctx, 6, "clear stencil\n"); return len; } for (idx = 0; idx < ARRAY_SIZE(opcodes_3d_1d); idx++) { opcode_3d_1d = &opcodes_3d_1d[idx]; if (opcode_3d_1d->i830_only && !IS_GEN2(devid)) continue; if (((data[0] & 0x00ff0000) >> 16) == opcode_3d_1d->opcode) { len = 1; instr_out(ctx, 0, "%s\n", opcode_3d_1d->name); if (opcode_3d_1d->max_len > 1) { len = (data[0] & 0x0000ffff) + 2; if (len < opcode_3d_1d->min_len || len > opcode_3d_1d->max_len) { fprintf(out, "Bad count in %s\n", opcode_3d_1d->name); } } for (i = 1; i < len; i++) { instr_out(ctx, i, "dword %d\n", i); } return len; } } instr_out(ctx, 0, "3D UNKNOWN: 3d_1d opcode = 0x%x\n", opcode); return 1; } static int decode_3d_primitive(struct drm_intel_decode *ctx) { uint32_t *data = ctx->data; uint32_t count = ctx->count; char immediate = (data[0] & (1 << 23)) == 0; unsigned int len, i, j, ret; const char *primtype; int original_s2 = saved_s2; int original_s4 = saved_s4; switch ((data[0] >> 18) & 0xf) { case 0x0: primtype = "TRILIST"; break; case 0x1: primtype = "TRISTRIP"; break; case 0x2: primtype = "TRISTRIP_REVERSE"; break; case 0x3: primtype = "TRIFAN"; break; case 0x4: primtype = "POLYGON"; break; case 0x5: primtype = "LINELIST"; break; case 0x6: primtype = "LINESTRIP"; break; case 0x7: primtype = "RECTLIST"; break; case 0x8: primtype = "POINTLIST"; break; case 0x9: primtype = "DIB"; break; case 0xa: primtype = "CLEAR_RECT"; saved_s4 = 3 << 6; saved_s2 = ~0; break; default: primtype = "unknown"; break; } /* XXX: 3DPRIM_DIB not supported */ if (immediate) { len = (data[0] & 0x0003ffff) + 2; instr_out(ctx, 0, "3DPRIMITIVE inline %s\n", primtype); if (count < len) BUFFER_FAIL(count, len, "3DPRIMITIVE inline"); if (!saved_s2_set || !saved_s4_set) { fprintf(out, "unknown vertex format\n"); for (i = 1; i < len; i++) { instr_out(ctx, i, " vertex data (%f float)\n", int_as_float(data[i])); } } else { unsigned int vertex = 0; for (i = 1; i < len;) { unsigned int tc; #define VERTEX_OUT(fmt, ...) do { \ if (i < len) \ instr_out(ctx, i, " V%d."fmt"\n", vertex, __VA_ARGS__); \ else \ fprintf(out, " missing data in V%d\n", vertex); \ i++; \ } while (0) VERTEX_OUT("X = %f", int_as_float(data[i])); VERTEX_OUT("Y = %f", int_as_float(data[i])); switch (saved_s4 >> 6 & 0x7) { case 0x1: VERTEX_OUT("Z = %f", int_as_float(data[i])); break; case 0x2: VERTEX_OUT("Z = %f", int_as_float(data[i])); VERTEX_OUT("W = %f", int_as_float(data[i])); break; case 0x3: break; case 0x4: VERTEX_OUT("W = %f", int_as_float(data[i])); break; default: fprintf(out, "bad S4 position mask\n"); } if (saved_s4 & (1 << 10)) { VERTEX_OUT ("color = (A=0x%02x, R=0x%02x, G=0x%02x, " "B=0x%02x)", data[i] >> 24, (data[i] >> 16) & 0xff, (data[i] >> 8) & 0xff, data[i] & 0xff); } if (saved_s4 & (1 << 11)) { VERTEX_OUT ("spec = (A=0x%02x, R=0x%02x, G=0x%02x, " "B=0x%02x)", data[i] >> 24, (data[i] >> 16) & 0xff, (data[i] >> 8) & 0xff, data[i] & 0xff); } if (saved_s4 & (1 << 12)) VERTEX_OUT("width = 0x%08x)", data[i]); for (tc = 0; tc <= 7; tc++) { switch ((saved_s2 >> (tc * 4)) & 0xf) { case 0x0: VERTEX_OUT("T%d.X = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.Y = %f", tc, int_as_float(data [i])); break; case 0x1: VERTEX_OUT("T%d.X = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.Y = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.Z = %f", tc, int_as_float(data [i])); break; case 0x2: VERTEX_OUT("T%d.X = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.Y = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.Z = %f", tc, int_as_float(data [i])); VERTEX_OUT("T%d.W = %f", tc, int_as_float(data [i])); break; case 0x3: VERTEX_OUT("T%d.X = %f", tc, int_as_float(data [i])); break; case 0x4: VERTEX_OUT ("T%d.XY = 0x%08x half-float", tc, data[i]); break; case 0x5: VERTEX_OUT ("T%d.XY = 0x%08x half-float", tc, data[i]); VERTEX_OUT ("T%d.ZW = 0x%08x half-float", tc, data[i]); break; case 0xf: break; default: fprintf(out, "bad S2.T%d format\n", tc); } } vertex++; } } ret = len; } else { /* indirect vertices */ len = data[0] & 0x0000ffff; /* index count */ if (data[0] & (1 << 17)) { /* random vertex access */ if (count < (len + 1) / 2 + 1) { BUFFER_FAIL(count, (len + 1) / 2 + 1, "3DPRIMITIVE random indirect"); } instr_out(ctx, 0, "3DPRIMITIVE random indirect %s (%d)\n", primtype, len); if (len == 0) { /* vertex indices continue until 0xffff is * found */ for (i = 1; i < count; i++) { if ((data[i] & 0xffff) == 0xffff) { instr_out(ctx, i, " indices: (terminator)\n"); ret = i; goto out; } else if ((data[i] >> 16) == 0xffff) { instr_out(ctx, i, " indices: 0x%04x, (terminator)\n", data[i] & 0xffff); ret = i; goto out; } else { instr_out(ctx, i, " indices: 0x%04x, 0x%04x\n", data[i] & 0xffff, data[i] >> 16); } } fprintf(out, "3DPRIMITIVE: no terminator found in index buffer\n"); ret = count; goto out; } else { /* fixed size vertex index buffer */ for (j = 1, i = 0; i < len; i += 2, j++) { if (i * 2 == len - 1) { instr_out(ctx, j, " indices: 0x%04x\n", data[j] & 0xffff); } else { instr_out(ctx, j, " indices: 0x%04x, 0x%04x\n", data[j] & 0xffff, data[j] >> 16); } } } ret = (len + 1) / 2 + 1; goto out; } else { /* sequential vertex access */ instr_out(ctx, 0, "3DPRIMITIVE sequential indirect %s, %d starting from " "%d\n", primtype, len, data[1] & 0xffff); instr_out(ctx, 1, " start\n"); ret = 2; goto out; } } out: saved_s2 = original_s2; saved_s4 = original_s4; return ret; } static int decode_3d(struct drm_intel_decode *ctx) { uint32_t opcode; unsigned int idx; uint32_t *data = ctx->data; struct { uint32_t opcode; unsigned int min_len; unsigned int max_len; const char *name; } opcodes_3d[] = { { 0x06, 1, 1, "3DSTATE_ANTI_ALIASING" }, { 0x08, 1, 1, "3DSTATE_BACKFACE_STENCIL_OPS" }, { 0x09, 1, 1, "3DSTATE_BACKFACE_STENCIL_MASKS" }, { 0x16, 1, 1, "3DSTATE_COORD_SET_BINDINGS" }, { 0x15, 1, 1, "3DSTATE_FOG_COLOR" }, { 0x0b, 1, 1, "3DSTATE_INDEPENDENT_ALPHA_BLEND" }, { 0x0d, 1, 1, "3DSTATE_MODES_4" }, { 0x0c, 1, 1, "3DSTATE_MODES_5" }, { 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES"}, }, *opcode_3d; opcode = (data[0] & 0x1f000000) >> 24; switch (opcode) { case 0x1f: return decode_3d_primitive(ctx); case 0x1d: return decode_3d_1d(ctx); case 0x1c: return decode_3d_1c(ctx); } for (idx = 0; idx < ARRAY_SIZE(opcodes_3d); idx++) { opcode_3d = &opcodes_3d[idx]; if (opcode == opcode_3d->opcode) { unsigned int len = 1, i; instr_out(ctx, 0, "%s\n", opcode_3d->name); if (opcode_3d->max_len > 1) { len = (data[0] & 0xff) + 2; if (len < opcode_3d->min_len || len > opcode_3d->max_len) { fprintf(out, "Bad count in %s\n", opcode_3d->name); } } for (i = 1; i < len; i++) { instr_out(ctx, i, "dword %d\n", i); } return len; } } instr_out(ctx, 0, "3D UNKNOWN: 3d opcode = 0x%x\n", opcode); return 1; } static const char *get_965_surfacetype(unsigned int surfacetype) { switch (surfacetype) { case 0: return "1D"; case 1: return "2D"; case 2: return "3D"; case 3: return "CUBE"; case 4: return "BUFFER"; case 7: return "NULL"; default: return "unknown"; } } static const char *get_965_depthformat(unsigned int depthformat) { switch (depthformat) { case 0: return "s8_z24float"; case 1: return "z32float"; case 2: return "z24s8"; case 5: return "z16"; default: return "unknown"; } } static const char *get_965_element_component(uint32_t data, int component) { uint32_t component_control = (data >> (16 + (3 - component) * 4)) & 0x7; switch (component_control) { case 0: return "nostore"; case 1: switch (component) { case 0: return "X"; case 1: return "Y"; case 2: return "Z"; case 3: return "W"; default: return "fail"; } case 2: return "0.0"; case 3: return "1.0"; case 4: return "0x1"; case 5: return "VID"; default: return "fail"; } } static const char *get_965_prim_type(uint32_t primtype) { switch (primtype) { case 0x01: return "point list"; case 0x02: return "line list"; case 0x03: return "line strip"; case 0x04: return "tri list"; case 0x05: return "tri strip"; case 0x06: return "tri fan"; case 0x07: return "quad list"; case 0x08: return "quad strip"; case 0x09: return "line list adj"; case 0x0a: return "line strip adj"; case 0x0b: return "tri list adj"; case 0x0c: return "tri strip adj"; case 0x0d: return "tri strip reverse"; case 0x0e: return "polygon"; case 0x0f: return "rect list"; case 0x10: return "line loop"; case 0x11: return "point list bf"; case 0x12: return "line strip cont"; case 0x13: return "line strip bf"; case 0x14: return "line strip cont bf"; case 0x15: return "tri fan no stipple"; default: return "fail"; } } static int i965_decode_urb_fence(struct drm_intel_decode *ctx, int len) { uint32_t vs_fence, clip_fence, gs_fence, sf_fence, vfe_fence, cs_fence; uint32_t *data = ctx->data; if (len != 3) fprintf(out, "Bad count in URB_FENCE\n"); vs_fence = data[1] & 0x3ff; gs_fence = (data[1] >> 10) & 0x3ff; clip_fence = (data[1] >> 20) & 0x3ff; sf_fence = data[2] & 0x3ff; vfe_fence = (data[2] >> 10) & 0x3ff; cs_fence = (data[2] >> 20) & 0x7ff; instr_out(ctx, 0, "URB_FENCE: %s%s%s%s%s%s\n", (data[0] >> 13) & 1 ? "cs " : "", (data[0] >> 12) & 1 ? "vfe " : "", (data[0] >> 11) & 1 ? "sf " : "", (data[0] >> 10) & 1 ? "clip " : "", (data[0] >> 9) & 1 ? "gs " : "", (data[0] >> 8) & 1 ? "vs " : ""); instr_out(ctx, 1, "vs fence: %d, clip_fence: %d, gs_fence: %d\n", vs_fence, clip_fence, gs_fence); instr_out(ctx, 2, "sf fence: %d, vfe_fence: %d, cs_fence: %d\n", sf_fence, vfe_fence, cs_fence); if (gs_fence < vs_fence) fprintf(out, "gs fence < vs fence!\n"); if (clip_fence < gs_fence) fprintf(out, "clip fence < gs fence!\n"); if (sf_fence < clip_fence) fprintf(out, "sf fence < clip fence!\n"); if (cs_fence < sf_fence) fprintf(out, "cs fence < sf fence!\n"); return len; } static void state_base_out(struct drm_intel_decode *ctx, unsigned int index, const char *name) { if (ctx->data[index] & 1) { instr_out(ctx, index, "%s state base address 0x%08x\n", name, ctx->data[index] & ~1); } else { instr_out(ctx, index, "%s state base not updated\n", name); } } static void state_max_out(struct drm_intel_decode *ctx, unsigned int index, const char *name) { if (ctx->data[index] & 1) { if (ctx->data[index] == 1) { instr_out(ctx, index, "%s state upper bound disabled\n", name); } else { instr_out(ctx, index, "%s state upper bound 0x%08x\n", name, ctx->data[index] & ~1); } } else { instr_out(ctx, index, "%s state upper bound not updated\n", name); } } static int gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_CC\n"); instr_out(ctx, 1, "pointer to CC viewport\n"); return 2; } static int gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP\n"); instr_out(ctx, 1, "pointer to SF_CLIP viewport\n"); return 2; } static int gen7_3DSTATE_BLEND_STATE_POINTERS(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_BLEND_STATE_POINTERS\n"); instr_out(ctx, 1, "pointer to BLEND_STATE at 0x%08x (%s)\n", ctx->data[1] & ~1, (ctx->data[1] & 1) ? "changed" : "unchanged"); return 2; } static int gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_DEPTH_STENCIL_STATE_POINTERS\n"); instr_out(ctx, 1, "pointer to DEPTH_STENCIL_STATE at 0x%08x (%s)\n", ctx->data[1] & ~1, (ctx->data[1] & 1) ? "changed" : "unchanged"); return 2; } static int gen7_3DSTATE_HIER_DEPTH_BUFFER(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_HIER_DEPTH_BUFFER\n"); instr_out(ctx, 1, "pitch %db\n", (ctx->data[1] & 0x1ffff) + 1); instr_out(ctx, 2, "pointer to HiZ buffer\n"); return 3; } static int gen6_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); instr_out(ctx, 1, "blend change %d\n", ctx->data[1] & 1); instr_out(ctx, 2, "depth stencil change %d\n", ctx->data[2] & 1); instr_out(ctx, 3, "cc change %d\n", ctx->data[3] & 1); return 4; } static int gen7_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); instr_out(ctx, 1, "pointer to COLOR_CALC_STATE at 0x%08x " "(%s)\n", ctx->data[1] & ~1, (ctx->data[1] & 1) ? "changed" : "unchanged"); return 2; } static int gen7_3DSTATE_URB_unit(struct drm_intel_decode *ctx, const char *unit) { int start_kb = ((ctx->data[1] >> 25) & 0x3f) * 8; /* the field is # of 512-bit rows - 1, we print bytes */ int entry_size = (((ctx->data[1] >> 16) & 0x1ff) + 1); int nr_entries = ctx->data[1] & 0xffff; instr_out(ctx, 0, "3DSTATE_URB_%s\n", unit); instr_out(ctx, 1, "%dKB start, size=%d 64B rows, nr_entries=%d, total size %dB\n", start_kb, entry_size, nr_entries, nr_entries * 64 * entry_size); return 2; } static int gen7_3DSTATE_URB_VS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_URB_unit(ctx, "VS"); } static int gen7_3DSTATE_URB_HS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_URB_unit(ctx, "HS"); } static int gen7_3DSTATE_URB_DS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_URB_unit(ctx, "DS"); } static int gen7_3DSTATE_URB_GS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_URB_unit(ctx, "GS"); } static int gen7_3DSTATE_CONSTANT(struct drm_intel_decode *ctx, const char *unit) { int rlen[4]; rlen[0] = (ctx->data[1] >> 0) & 0xffff; rlen[1] = (ctx->data[1] >> 16) & 0xffff; rlen[2] = (ctx->data[2] >> 0) & 0xffff; rlen[3] = (ctx->data[2] >> 16) & 0xffff; instr_out(ctx, 0, "3DSTATE_CONSTANT_%s\n", unit); instr_out(ctx, 1, "len 0 = %d, len 1 = %d\n", rlen[0], rlen[1]); instr_out(ctx, 2, "len 2 = %d, len 3 = %d\n", rlen[2], rlen[3]); instr_out(ctx, 3, "pointer to constbuf 0\n"); instr_out(ctx, 4, "pointer to constbuf 1\n"); instr_out(ctx, 5, "pointer to constbuf 2\n"); instr_out(ctx, 6, "pointer to constbuf 3\n"); return 7; } static int gen7_3DSTATE_CONSTANT_VS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_CONSTANT(ctx, "VS"); } static int gen7_3DSTATE_CONSTANT_GS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_CONSTANT(ctx, "GS"); } static int gen7_3DSTATE_CONSTANT_PS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_CONSTANT(ctx, "PS"); } static int gen7_3DSTATE_CONSTANT_DS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_CONSTANT(ctx, "DS"); } static int gen7_3DSTATE_CONSTANT_HS(struct drm_intel_decode *ctx) { return gen7_3DSTATE_CONSTANT(ctx, "HS"); } static int gen6_3DSTATE_WM(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DSTATE_WM\n"); instr_out(ctx, 1, "kernel start pointer 0\n"); instr_out(ctx, 2, "SPF=%d, VME=%d, Sampler Count %d, " "Binding table count %d\n", (ctx->data[2] >> 31) & 1, (ctx->data[2] >> 30) & 1, (ctx->data[2] >> 27) & 7, (ctx->data[2] >> 18) & 0xff); instr_out(ctx, 3, "scratch offset\n"); instr_out(ctx, 4, "Depth Clear %d, Depth Resolve %d, HiZ Resolve %d, " "Dispatch GRF start[0] %d, start[1] %d, start[2] %d\n", (ctx->data[4] & (1 << 30)) != 0, (ctx->data[4] & (1 << 28)) != 0, (ctx->data[4] & (1 << 27)) != 0, (ctx->data[4] >> 16) & 0x7f, (ctx->data[4] >> 8) & 0x7f, (ctx->data[4] & 0x7f)); instr_out(ctx, 5, "MaxThreads %d, PS KillPixel %d, PS computed Z %d, " "PS use sourceZ %d, Thread Dispatch %d, PS use sourceW %d, " "Dispatch32 %d, Dispatch16 %d, Dispatch8 %d\n", ((ctx->data[5] >> 25) & 0x7f) + 1, (ctx->data[5] & (1 << 22)) != 0, (ctx->data[5] & (1 << 21)) != 0, (ctx->data[5] & (1 << 20)) != 0, (ctx->data[5] & (1 << 19)) != 0, (ctx->data[5] & (1 << 8)) != 0, (ctx->data[5] & (1 << 2)) != 0, (ctx->data[5] & (1 << 1)) != 0, (ctx->data[5] & (1 << 0)) != 0); instr_out(ctx, 6, "Num SF output %d, Pos XY offset %d, ZW interp mode %d , " "Barycentric interp mode 0x%x, Point raster rule %d, " "Multisample mode %d, " "Multisample Dispatch mode %d\n", (ctx->data[6] >> 20) & 0x3f, (ctx->data[6] >> 18) & 3, (ctx->data[6] >> 16) & 3, (ctx->data[6] >> 10) & 0x3f, (ctx->data[6] & (1 << 9)) != 0, (ctx->data[6] >> 1) & 3, (ctx->data[6] & 1)); instr_out(ctx, 7, "kernel start pointer 1\n"); instr_out(ctx, 8, "kernel start pointer 2\n"); return 9; } static int gen7_3DSTATE_WM(struct drm_intel_decode *ctx) { const char *computed_depth = ""; const char *early_depth = ""; const char *zw_interp = ""; switch ((ctx->data[1] >> 23) & 0x3) { case 0: computed_depth = ""; break; case 1: computed_depth = "computed depth"; break; case 2: computed_depth = "computed depth >="; break; case 3: computed_depth = "computed depth <="; break; } switch ((ctx->data[1] >> 21) & 0x3) { case 0: early_depth = ""; break; case 1: early_depth = ", EDSC_PSEXEC"; break; case 2: early_depth = ", EDSC_PREPS"; break; case 3: early_depth = ", BAD EDSC"; break; } switch ((ctx->data[1] >> 17) & 0x3) { case 0: early_depth = ""; break; case 1: early_depth = ", BAD ZW interp"; break; case 2: early_depth = ", ZW centroid"; break; case 3: early_depth = ", ZW sample"; break; } instr_out(ctx, 0, "3DSTATE_WM\n"); instr_out(ctx, 1, "(%s%s%s%s%s%s)%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", (ctx->data[1] & (1 << 11)) ? "PP " : "", (ctx->data[1] & (1 << 12)) ? "PC " : "", (ctx->data[1] & (1 << 13)) ? "PS " : "", (ctx->data[1] & (1 << 14)) ? "NPP " : "", (ctx->data[1] & (1 << 15)) ? "NPC " : "", (ctx->data[1] & (1 << 16)) ? "NPS " : "", (ctx->data[1] & (1 << 30)) ? ", depth clear" : "", (ctx->data[1] & (1 << 29)) ? "" : ", disabled", (ctx->data[1] & (1 << 28)) ? ", depth resolve" : "", (ctx->data[1] & (1 << 27)) ? ", hiz resolve" : "", (ctx->data[1] & (1 << 25)) ? ", kill" : "", computed_depth, early_depth, zw_interp, (ctx->data[1] & (1 << 20)) ? ", source depth" : "", (ctx->data[1] & (1 << 19)) ? ", source W" : "", (ctx->data[1] & (1 << 10)) ? ", coverage" : "", (ctx->data[1] & (1 << 4)) ? ", poly stipple" : "", (ctx->data[1] & (1 << 3)) ? ", line stipple" : "", (ctx->data[1] & (1 << 2)) ? ", point UL" : ", point UR" ); instr_out(ctx, 2, "MS\n"); return 3; } static int gen4_3DPRIMITIVE(struct drm_intel_decode *ctx) { instr_out(ctx, 0, "3DPRIMITIVE: %s %s\n", get_965_prim_type((ctx->data[0] >> 10) & 0x1f), (ctx->data[0] & (1 << 15)) ? "random" : "sequential"); instr_out(ctx, 1, "vertex count\n"); instr_out(ctx, 2, "start vertex\n"); instr_out(ctx, 3, "instance count\n"); instr_out(ctx, 4, "start instance\n"); instr_out(ctx, 5, "index bias\n"); return 6; } static int gen7_3DPRIMITIVE(struct drm_intel_decode *ctx) { bool indirect = !!(ctx->data[0] & (1 << 10)); instr_out(ctx, 0, "3DPRIMITIVE: %s%s\n", indirect ? " indirect" : "", (ctx->data[0] & (1 << 8)) ? " predicated" : ""); instr_out(ctx, 1, "%s %s\n", get_965_prim_type(ctx->data[1] & 0x3f), (ctx->data[1] & (1 << 8)) ? "random" : "sequential"); instr_out(ctx, 2, indirect ? "ignored" : "vertex count\n"); instr_out(ctx, 3, indirect ? "ignored" : "start vertex\n"); instr_out(ctx, 4, indirect ? "ignored" : "instance count\n"); instr_out(ctx, 5, indirect ? "ignored" : "start instance\n"); instr_out(ctx, 6, indirect ? "ignored" : "index bias\n"); return 7; } static int decode_3d_965(struct drm_intel_decode *ctx) { uint32_t opcode; unsigned int len; unsigned int i, j, sba_len; const char *desc1 = NULL; uint32_t *data = ctx->data; uint32_t devid = ctx->devid; struct { uint32_t opcode; uint32_t len_mask; int unsigned min_len; int unsigned max_len; const char *name; int gen; int (*func)(struct drm_intel_decode *ctx); } opcodes_3d[] = { { 0x6000, 0x00ff, 3, 3, "URB_FENCE" }, { 0x6001, 0xffff, 2, 2, "CS_URB_STATE" }, { 0x6002, 0x00ff, 2, 2, "CONSTANT_BUFFER" }, { 0x6101, 0xffff, 6, 10, "STATE_BASE_ADDRESS" }, { 0x6102, 0xffff, 2, 2, "STATE_SIP" }, { 0x6104, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, { 0x680b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, { 0x6904, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, { 0x7800, 0xffff, 7, 7, "3DSTATE_PIPELINED_POINTERS" }, { 0x7801, 0x00ff, 4, 6, "3DSTATE_BINDING_TABLE_POINTERS" }, { 0x7802, 0x00ff, 4, 4, "3DSTATE_SAMPLER_STATE_POINTERS" }, { 0x7805, 0x00ff, 7, 7, "3DSTATE_DEPTH_BUFFER", 7 }, { 0x7805, 0x00ff, 3, 3, "3DSTATE_URB" }, { 0x7804, 0x00ff, 3, 3, "3DSTATE_CLEAR_PARAMS" }, { 0x7806, 0x00ff, 3, 3, "3DSTATE_STENCIL_BUFFER" }, { 0x790f, 0x00ff, 3, 3, "3DSTATE_HIER_DEPTH_BUFFER", 6 }, { 0x7807, 0x00ff, 3, 3, "3DSTATE_HIER_DEPTH_BUFFER", 7, gen7_3DSTATE_HIER_DEPTH_BUFFER }, { 0x7808, 0x00ff, 5, 257, "3DSTATE_VERTEX_BUFFERS" }, { 0x7809, 0x00ff, 3, 256, "3DSTATE_VERTEX_ELEMENTS" }, { 0x780a, 0x00ff, 3, 3, "3DSTATE_INDEX_BUFFER" }, { 0x780b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, { 0x780d, 0x00ff, 4, 4, "3DSTATE_VIEWPORT_STATE_POINTERS" }, { 0x780e, 0xffff, 4, 4, NULL, 6, gen6_3DSTATE_CC_STATE_POINTERS }, { 0x780e, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_CC_STATE_POINTERS }, { 0x780f, 0x00ff, 2, 2, "3DSTATE_SCISSOR_POINTERS" }, { 0x7810, 0x00ff, 6, 6, "3DSTATE_VS" }, { 0x7811, 0x00ff, 7, 7, "3DSTATE_GS" }, { 0x7812, 0x00ff, 4, 4, "3DSTATE_CLIP" }, { 0x7813, 0x00ff, 20, 20, "3DSTATE_SF", 6 }, { 0x7813, 0x00ff, 7, 7, "3DSTATE_SF", 7 }, { 0x7814, 0x00ff, 3, 3, "3DSTATE_WM", 7, gen7_3DSTATE_WM }, { 0x7814, 0x00ff, 9, 9, "3DSTATE_WM", 6, gen6_3DSTATE_WM }, { 0x7815, 0x00ff, 5, 5, "3DSTATE_CONSTANT_VS_STATE", 6 }, { 0x7815, 0x00ff, 7, 7, "3DSTATE_CONSTANT_VS", 7, gen7_3DSTATE_CONSTANT_VS }, { 0x7816, 0x00ff, 5, 5, "3DSTATE_CONSTANT_GS_STATE", 6 }, { 0x7816, 0x00ff, 7, 7, "3DSTATE_CONSTANT_GS", 7, gen7_3DSTATE_CONSTANT_GS }, { 0x7817, 0x00ff, 5, 5, "3DSTATE_CONSTANT_PS_STATE", 6 }, { 0x7817, 0x00ff, 7, 7, "3DSTATE_CONSTANT_PS", 7, gen7_3DSTATE_CONSTANT_PS }, { 0x7818, 0xffff, 2, 2, "3DSTATE_SAMPLE_MASK" }, { 0x7819, 0x00ff, 7, 7, "3DSTATE_CONSTANT_HS", 7, gen7_3DSTATE_CONSTANT_HS }, { 0x781a, 0x00ff, 7, 7, "3DSTATE_CONSTANT_DS", 7, gen7_3DSTATE_CONSTANT_DS }, { 0x781b, 0x00ff, 7, 7, "3DSTATE_HS" }, { 0x781c, 0x00ff, 4, 4, "3DSTATE_TE" }, { 0x781d, 0x00ff, 6, 6, "3DSTATE_DS" }, { 0x781e, 0x00ff, 3, 3, "3DSTATE_STREAMOUT" }, { 0x781f, 0x00ff, 14, 14, "3DSTATE_SBE" }, { 0x7820, 0x00ff, 8, 8, "3DSTATE_PS" }, { 0x7821, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP }, { 0x7823, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC }, { 0x7824, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_BLEND_STATE_POINTERS }, { 0x7825, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS }, { 0x7826, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_VS" }, { 0x7827, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_HS" }, { 0x7828, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_DS" }, { 0x7829, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_GS" }, { 0x782a, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_PS" }, { 0x782b, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_VS" }, { 0x782c, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_HS" }, { 0x782d, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_DS" }, { 0x782e, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_GS" }, { 0x782f, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_PS" }, { 0x7830, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_VS }, { 0x7831, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_HS }, { 0x7832, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_DS }, { 0x7833, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_GS }, { 0x7900, 0xffff, 4, 4, "3DSTATE_DRAWING_RECTANGLE" }, { 0x7901, 0xffff, 5, 5, "3DSTATE_CONSTANT_COLOR" }, { 0x7905, 0xffff, 5, 7, "3DSTATE_DEPTH_BUFFER" }, { 0x7906, 0xffff, 2, 2, "3DSTATE_POLY_STIPPLE_OFFSET" }, { 0x7907, 0xffff, 33, 33, "3DSTATE_POLY_STIPPLE_PATTERN" }, { 0x7908, 0xffff, 3, 3, "3DSTATE_LINE_STIPPLE" }, { 0x7909, 0xffff, 2, 2, "3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP" }, { 0x7909, 0xffff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, { 0x790a, 0xffff, 3, 3, "3DSTATE_AA_LINE_PARAMETERS" }, { 0x790b, 0xffff, 4, 4, "3DSTATE_GS_SVB_INDEX" }, { 0x790d, 0xffff, 3, 3, "3DSTATE_MULTISAMPLE", 6 }, { 0x790d, 0xffff, 4, 4, "3DSTATE_MULTISAMPLE", 7 }, { 0x7910, 0x00ff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, { 0x7912, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_VS" }, { 0x7913, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_HS" }, { 0x7914, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_DS" }, { 0x7915, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_GS" }, { 0x7916, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_PS" }, { 0x7917, 0x00ff, 2, 2+128*2, "3DSTATE_SO_DECL_LIST" }, { 0x7918, 0x00ff, 4, 4, "3DSTATE_SO_BUFFER" }, { 0x7a00, 0x00ff, 4, 6, "PIPE_CONTROL" }, { 0x7b00, 0x00ff, 7, 7, NULL, 7, gen7_3DPRIMITIVE }, { 0x7b00, 0x00ff, 6, 6, NULL, 0, gen4_3DPRIMITIVE }, }, *opcode_3d = NULL; opcode = (data[0] & 0xffff0000) >> 16; for (i = 0; i < ARRAY_SIZE(opcodes_3d); i++) { if (opcode != opcodes_3d[i].opcode) continue; /* If it's marked as not our gen, skip. */