diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/r300_cmdbuf.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r300_cmdbuf.c | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 4b3bd6303daf..b1fdfc61f27d 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c | |||
@@ -577,22 +577,23 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, | |||
577 | return 0; | 577 | return 0; |
578 | } | 578 | } |
579 | 579 | ||
580 | static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, | 580 | static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv, |
581 | drm_radeon_kcmd_buffer_t *cmdbuf) | 581 | drm_radeon_kcmd_buffer_t *cmdbuf) |
582 | { | 582 | { |
583 | u32 *cmd = (u32 *) cmdbuf->buf; | 583 | u32 *cmd; |
584 | int count, ret; | 584 | int count; |
585 | int expected_count; | ||
585 | RING_LOCALS; | 586 | RING_LOCALS; |
586 | 587 | ||
587 | count=(cmd[0]>>16) & 0x3fff; | 588 | cmd = (u32 *) cmdbuf->buf; |
589 | count = (cmd[0]>>16) & 0x3fff; | ||
590 | expected_count = cmd[1] >> 16; | ||
591 | if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit)) | ||
592 | expected_count = (expected_count+1)/2; | ||
588 | 593 | ||
589 | if ((cmd[1] & 0x8000ffff) != 0x80000810) { | 594 | if (count && count != expected_count) { |
590 | DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); | 595 | DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n", |
591 | return -EINVAL; | 596 | count, expected_count); |
592 | } | ||
593 | ret = !radeon_check_offset(dev_priv, cmd[2]); | ||
594 | if (ret) { | ||
595 | DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); | ||
596 | return -EINVAL; | 597 | return -EINVAL; |
597 | } | 598 | } |
598 | 599 | ||
@@ -604,6 +605,50 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, | |||
604 | cmdbuf->buf += (count+2)*4; | 605 | cmdbuf->buf += (count+2)*4; |
605 | cmdbuf->bufsz -= (count+2)*4; | 606 | cmdbuf->bufsz -= (count+2)*4; |
606 | 607 | ||
608 | if (!count) { | ||
609 | drm_r300_cmd_header_t header; | ||
610 | |||
611 | if (cmdbuf->bufsz < 4*4 + sizeof(header)) { | ||
612 | DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n"); | ||
613 | return -EINVAL; | ||
614 | } | ||
615 | |||
616 | header.u = *(unsigned int *)cmdbuf->buf; | ||
617 | |||
618 | cmdbuf->buf += sizeof(header); | ||
619 | cmdbuf->bufsz -= sizeof(header); | ||
620 | cmd = (u32 *) cmdbuf->buf; | ||
621 | |||
622 | if (header.header.cmd_type != R300_CMD_PACKET3 || | ||
623 | header.packet3.packet != R300_CMD_PACKET3_RAW || | ||
624 | cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) { | ||
625 | DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | if ((cmd[1] & 0x8000ffff) != 0x80000810) { | ||
630 | DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | if (!radeon_check_offset(dev_priv, cmd[2])) { | ||
634 | DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); | ||
635 | return -EINVAL; | ||
636 | } | ||
637 | if (cmd[3] != expected_count) { | ||
638 | DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n", | ||
639 | cmd[3], expected_count); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | |||
643 | BEGIN_RING(4); | ||
644 | OUT_RING(cmd[0]); | ||
645 | OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3); | ||
646 | ADVANCE_RING(); | ||
647 | |||
648 | cmdbuf->buf += 4*4; | ||
649 | cmdbuf->bufsz -= 4*4; | ||
650 | } | ||
651 | |||
607 | return 0; | 652 | return 0; |
608 | } | 653 | } |
609 | 654 | ||
@@ -648,18 +693,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, | |||
648 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); | 693 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); |
649 | 694 | ||
650 | case RADEON_CP_INDX_BUFFER: | 695 | case RADEON_CP_INDX_BUFFER: |
651 | /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ | 696 | DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n"); |
652 | return r300_emit_indx_buffer(dev_priv, cmdbuf); | 697 | return -EINVAL; |
653 | case RADEON_CP_3D_DRAW_IMMD_2: | 698 | case RADEON_CP_3D_DRAW_IMMD_2: |
654 | /* triggers drawing using in-packet vertex data */ | 699 | /* triggers drawing using in-packet vertex data */ |
655 | case RADEON_CP_3D_DRAW_VBUF_2: | 700 | case RADEON_CP_3D_DRAW_VBUF_2: |
656 | /* triggers drawing of vertex buffers setup elsewhere */ | 701 | /* triggers drawing of vertex buffers setup elsewhere */ |
702 | dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | | ||
703 | RADEON_PURGE_EMITED); | ||
704 | break; | ||
657 | case RADEON_CP_3D_DRAW_INDX_2: | 705 | case RADEON_CP_3D_DRAW_INDX_2: |
658 | /* triggers drawing using indices to vertex buffer */ | 706 | /* triggers drawing using indices to vertex buffer */ |
659 | /* whenever we send vertex we clear flush & purge */ | 707 | /* whenever we send vertex we clear flush & purge */ |
660 | dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | | 708 | dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | |
661 | RADEON_PURGE_EMITED); | 709 | RADEON_PURGE_EMITED); |
662 | break; | 710 | return r300_emit_draw_indx_2(dev_priv, cmdbuf); |
663 | case RADEON_WAIT_FOR_IDLE: | 711 | case RADEON_WAIT_FOR_IDLE: |
664 | case RADEON_CP_NOP: | 712 | case RADEON_CP_NOP: |
665 | /* these packets are safe */ | 713 | /* these packets are safe */ |
@@ -757,7 +805,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) | |||
757 | { | 805 | { |
758 | uint32_t cache_z, cache_3d, cache_2d; | 806 | uint32_t cache_z, cache_3d, cache_2d; |
759 | RING_LOCALS; | 807 | RING_LOCALS; |
760 | 808 | ||
761 | cache_z = R300_ZC_FLUSH; | 809 | cache_z = R300_ZC_FLUSH; |
762 | cache_2d = R300_RB2D_DC_FLUSH; | 810 | cache_2d = R300_RB2D_DC_FLUSH; |
763 | cache_3d = R300_RB3D_DC_FLUSH; | 811 | cache_3d = R300_RB3D_DC_FLUSH; |