diff options
author | Jerome Glisse <glisse@freedesktop.org> | 2008-08-12 19:46:31 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2008-08-24 16:34:58 -0400 |
commit | 54f961a628b737f66710eca0b0d95346645dd33e (patch) | |
tree | 9ba62d7e8d5818155330ef79cbf2d8b7302042a1 /drivers/gpu/drm/radeon/r300_cmdbuf.c | |
parent | 94ad374a0751f40d25e22e036c37f7263569d24c (diff) |
radeon: fix some hard lockups on r3/4/500s
This patch should fix hard lockup and convert them in
softlockup (ie you can ssh the box but the gpu is busted
and we are waiting in loop for it to come back to reason).
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r300_cmdbuf.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r300_cmdbuf.c | 117 |
1 files changed, 97 insertions, 20 deletions
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 702df45320f7..4b3bd6303daf 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c | |||
@@ -136,6 +136,18 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv, | |||
136 | ADVANCE_RING(); | 136 | ADVANCE_RING(); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* flus cache and wait idle clean after cliprect change */ | ||
140 | BEGIN_RING(2); | ||
141 | OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); | ||
142 | OUT_RING(R300_RB3D_DC_FLUSH); | ||
143 | ADVANCE_RING(); | ||
144 | BEGIN_RING(2); | ||
145 | OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); | ||
146 | OUT_RING(RADEON_WAIT_3D_IDLECLEAN); | ||
147 | ADVANCE_RING(); | ||
148 | /* set flush flag */ | ||
149 | dev_priv->track_flush |= RADEON_FLUSH_EMITED; | ||
150 | |||
139 | return 0; | 151 | return 0; |
140 | } | 152 | } |
141 | 153 | ||
@@ -166,13 +178,13 @@ void r300_init_reg_flags(struct drm_device *dev) | |||
166 | ADD_RANGE(0x21DC, 1); | 178 | ADD_RANGE(0x21DC, 1); |
167 | ADD_RANGE(R300_VAP_UNKNOWN_221C, 1); | 179 | ADD_RANGE(R300_VAP_UNKNOWN_221C, 1); |
168 | ADD_RANGE(R300_VAP_CLIP_X_0, 4); | 180 | ADD_RANGE(R300_VAP_CLIP_X_0, 4); |
169 | ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1); | 181 | ADD_RANGE(R300_VAP_PVS_STATE_FLUSH_REG, 1); |
170 | ADD_RANGE(R300_VAP_UNKNOWN_2288, 1); | 182 | ADD_RANGE(R300_VAP_UNKNOWN_2288, 1); |
171 | ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2); | 183 | ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2); |
172 | ADD_RANGE(R300_VAP_PVS_CNTL_1, 3); | 184 | ADD_RANGE(R300_VAP_PVS_CNTL_1, 3); |
173 | ADD_RANGE(R300_GB_ENABLE, 1); | 185 | ADD_RANGE(R300_GB_ENABLE, 1); |
174 | ADD_RANGE(R300_GB_MSPOS0, 5); | 186 | ADD_RANGE(R300_GB_MSPOS0, 5); |
175 | ADD_RANGE(R300_TX_CNTL, 1); | 187 | ADD_RANGE(R300_TX_INVALTAGS, 1); |
176 | ADD_RANGE(R300_TX_ENABLE, 1); | 188 | ADD_RANGE(R300_TX_ENABLE, 1); |
177 | ADD_RANGE(0x4200, 4); | 189 | ADD_RANGE(0x4200, 4); |
178 | ADD_RANGE(0x4214, 1); | 190 | ADD_RANGE(0x4214, 1); |
@@ -388,15 +400,28 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv, | |||
388 | if (sz * 16 > cmdbuf->bufsz) | 400 | if (sz * 16 > cmdbuf->bufsz) |
389 | return -EINVAL; | 401 | return -EINVAL; |
390 | 402 | ||
391 | BEGIN_RING(5 + sz * 4); | 403 | /* VAP is very sensitive so we purge cache before we program it |
392 | /* Wait for VAP to come to senses.. */ | 404 | * and we also flush its state before & after */ |
393 | /* there is no need to emit it multiple times, (only once before VAP is programmed, | 405 | BEGIN_RING(6); |
394 | but this optimization is for later */ | 406 | OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); |
395 | OUT_RING_REG(R300_VAP_PVS_WAITIDLE, 0); | 407 | OUT_RING(R300_RB3D_DC_FLUSH); |
408 | OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); | ||
409 | OUT_RING(RADEON_WAIT_3D_IDLECLEAN); | ||
410 | OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0)); | ||
411 | OUT_RING(0); | ||
412 | ADVANCE_RING(); | ||
413 | /* set flush flag */ | ||
414 | dev_priv->track_flush |= RADEON_FLUSH_EMITED; | ||
415 | |||
416 | BEGIN_RING(3 + sz * 4); | ||
396 | OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr); | 417 | OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr); |
397 | OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1)); | 418 | OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1)); |
398 | OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4); | 419 | OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4); |
420 | ADVANCE_RING(); | ||
399 | 421 | ||
422 | BEGIN_RING(2); | ||
423 | OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0)); | ||
424 | OUT_RING(0); | ||
400 | ADVANCE_RING(); | 425 | ADVANCE_RING(); |
401 | 426 | ||
402 | cmdbuf->buf += sz * 16; | 427 | cmdbuf->buf += sz * 16; |
@@ -424,6 +449,15 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv, | |||
424 | OUT_RING_TABLE((int *)cmdbuf->buf, 8); | 449 | OUT_RING_TABLE((int *)cmdbuf->buf, 8); |
425 | ADVANCE_RING(); | 450 | ADVANCE_RING(); |
426 | 451 | ||
452 | BEGIN_RING(4); | ||
453 | OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); | ||
454 | OUT_RING(R300_RB3D_DC_FLUSH); | ||
455 | OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); | ||
456 | OUT_RING(RADEON_WAIT_3D_IDLECLEAN); | ||
457 | ADVANCE_RING(); | ||
458 | /* set flush flag */ | ||
459 | dev_priv->track_flush |= RADEON_FLUSH_EMITED; | ||
460 | |||
427 | cmdbuf->buf += 8 * 4; | 461 | cmdbuf->buf += 8 * 4; |
428 | cmdbuf->bufsz -= 8 * 4; | 462 | cmdbuf->bufsz -= 8 * 4; |
429 | 463 | ||
@@ -613,11 +647,19 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, | |||
613 | case RADEON_CNTL_BITBLT_MULTI: | 647 | case RADEON_CNTL_BITBLT_MULTI: |
614 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); | 648 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); |
615 | 649 | ||
616 | case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ | 650 | case RADEON_CP_INDX_BUFFER: |
651 | /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ | ||
617 | return r300_emit_indx_buffer(dev_priv, cmdbuf); | 652 | return r300_emit_indx_buffer(dev_priv, cmdbuf); |
618 | case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ | 653 | case RADEON_CP_3D_DRAW_IMMD_2: |
619 | case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ | 654 | /* triggers drawing using in-packet vertex data */ |
620 | case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ | 655 | case RADEON_CP_3D_DRAW_VBUF_2: |
656 | /* triggers drawing of vertex buffers setup elsewhere */ | ||
657 | case RADEON_CP_3D_DRAW_INDX_2: | ||
658 | /* triggers drawing using indices to vertex buffer */ | ||
659 | /* whenever we send vertex we clear flush & purge */ | ||
660 | dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | | ||
661 | RADEON_PURGE_EMITED); | ||
662 | break; | ||
621 | case RADEON_WAIT_FOR_IDLE: | 663 | case RADEON_WAIT_FOR_IDLE: |
622 | case RADEON_CP_NOP: | 664 | case RADEON_CP_NOP: |
623 | /* these packets are safe */ | 665 | /* these packets are safe */ |
@@ -713,17 +755,53 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, | |||
713 | */ | 755 | */ |
714 | static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) | 756 | static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) |
715 | { | 757 | { |
758 | uint32_t cache_z, cache_3d, cache_2d; | ||
716 | RING_LOCALS; | 759 | RING_LOCALS; |
760 | |||
761 | cache_z = R300_ZC_FLUSH; | ||
762 | cache_2d = R300_RB2D_DC_FLUSH; | ||
763 | cache_3d = R300_RB3D_DC_FLUSH; | ||
764 | if (!(dev_priv->track_flush & RADEON_PURGE_EMITED)) { | ||
765 | /* we can purge, primitive where draw since last purge */ | ||
766 | cache_z |= R300_ZC_FREE; | ||
767 | cache_2d |= R300_RB2D_DC_FREE; | ||
768 | cache_3d |= R300_RB3D_DC_FREE; | ||
769 | } | ||
717 | 770 | ||
718 | BEGIN_RING(6); | 771 | /* flush & purge zbuffer */ |
719 | OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); | 772 | BEGIN_RING(2); |
720 | OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A); | ||
721 | OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); | 773 | OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); |
722 | OUT_RING(R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE| | 774 | OUT_RING(cache_z); |
723 | R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE); | 775 | ADVANCE_RING(); |
724 | OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0)); | 776 | /* flush & purge 3d */ |
725 | OUT_RING(0x0); | 777 | BEGIN_RING(2); |
778 | OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); | ||
779 | OUT_RING(cache_3d); | ||
780 | ADVANCE_RING(); | ||
781 | /* flush & purge texture */ | ||
782 | BEGIN_RING(2); | ||
783 | OUT_RING(CP_PACKET0(R300_TX_INVALTAGS, 0)); | ||
784 | OUT_RING(0); | ||
785 | ADVANCE_RING(); | ||
786 | /* FIXME: is this one really needed ? */ | ||
787 | BEGIN_RING(2); | ||
788 | OUT_RING(CP_PACKET0(R300_RB3D_AARESOLVE_CTL, 0)); | ||
789 | OUT_RING(0); | ||
790 | ADVANCE_RING(); | ||
791 | BEGIN_RING(2); | ||
792 | OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); | ||
793 | OUT_RING(RADEON_WAIT_3D_IDLECLEAN); | ||
794 | ADVANCE_RING(); | ||
795 | /* flush & purge 2d through E2 as RB2D will trigger lockup */ | ||
796 | BEGIN_RING(4); | ||
797 | OUT_RING(CP_PACKET0(R300_DSTCACHE_CTLSTAT, 0)); | ||
798 | OUT_RING(cache_2d); | ||
799 | OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); | ||
800 | OUT_RING(RADEON_WAIT_2D_IDLECLEAN | | ||
801 | RADEON_WAIT_HOST_IDLECLEAN); | ||
726 | ADVANCE_RING(); | 802 | ADVANCE_RING(); |
803 | /* set flush & purge flags */ | ||
804 | dev_priv->track_flush |= RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED; | ||
727 | } | 805 | } |
728 | 806 | ||
729 | /** | 807 | /** |
@@ -905,8 +983,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, | |||
905 | 983 | ||
906 | DRM_DEBUG("\n"); | 984 | DRM_DEBUG("\n"); |
907 | 985 | ||
908 | /* See the comment above r300_emit_begin3d for why this call must be here, | 986 | /* pacify */ |
909 | * and what the cleanup gotos are for. */ | ||
910 | r300_pacify(dev_priv); | 987 | r300_pacify(dev_priv); |
911 | 988 | ||
912 | if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) { | 989 | if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) { |