Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/r300: fix bug in r300 userspace hardware wait emission

This interface was originally designed wrong, confusing bit-fields and
integers, major brown paper bag going back many years...

But userspace only ever used 4 values so fix the interface for new
users and fix the implementation to deal with the 4 values userspace
has ever emitted (0x1, 0x2, 0x3, 0x6).

Signed-off-by: Dave Airlie <airlied@redhat.com>

+54 -12
+42 -12
drivers/char/drm/r300_cmdbuf.c
··· 729 729 buf->used = 0; 730 730 } 731 731 732 + static void r300_cmd_wait(drm_radeon_private_t * dev_priv, 733 + drm_r300_cmd_header_t header) 734 + { 735 + u32 wait_until; 736 + RING_LOCALS; 737 + 738 + if (!header.wait.flags) 739 + return; 740 + 741 + wait_until = 0; 742 + 743 + switch(header.wait.flags) { 744 + case R300_WAIT_2D: 745 + wait_until = RADEON_WAIT_2D_IDLE; 746 + break; 747 + case R300_WAIT_3D: 748 + wait_until = RADEON_WAIT_3D_IDLE; 749 + break; 750 + case R300_NEW_WAIT_2D_3D: 751 + wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_3D_IDLE; 752 + break; 753 + case R300_NEW_WAIT_2D_2D_CLEAN: 754 + wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_2D_IDLECLEAN; 755 + break; 756 + case R300_NEW_WAIT_3D_3D_CLEAN: 757 + wait_until = RADEON_WAIT_3D_IDLE|RADEON_WAIT_3D_IDLECLEAN; 758 + break; 759 + case R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN: 760 + wait_until = RADEON_WAIT_2D_IDLE|RADEON_WAIT_2D_IDLECLEAN; 761 + wait_until |= RADEON_WAIT_3D_IDLE|RADEON_WAIT_3D_IDLECLEAN; 762 + break; 763 + default: 764 + return; 765 + } 766 + 767 + BEGIN_RING(2); 768 + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); 769 + OUT_RING(wait_until); 770 + ADVANCE_RING(); 771 + } 772 + 732 773 static int r300_scratch(drm_radeon_private_t *dev_priv, 733 774 drm_radeon_kcmd_buffer_t *cmdbuf, 734 775 drm_r300_cmd_header_t header) ··· 950 909 break; 951 910 952 911 case R300_CMD_WAIT: 953 - /* simple enough, we can do it here */ 954 912 DRM_DEBUG("R300_CMD_WAIT\n"); 955 - if (header.wait.flags == 0) 956 - break; /* nothing to do */ 957 - 958 - { 959 - RING_LOCALS; 960 - 961 - BEGIN_RING(2); 962 - OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); 963 - OUT_RING((header.wait.flags & 0xf) << 14); 964 - ADVANCE_RING(); 965 - } 913 + r300_cmd_wait(dev_priv, header); 966 914 break; 967 915 968 916 case R300_CMD_SCRATCH:
+12
drivers/char/drm/radeon_drm.h
··· 225 225 #define R300_CMD_WAIT 7 226 226 # define R300_WAIT_2D 0x1 227 227 # define R300_WAIT_3D 0x2 228 + /* these two defines are DOING IT WRONG - however 229 + * we have userspace which relies on using these. 230 + * The wait interface is backwards compat new 231 + * code should use the NEW_WAIT defines below 232 + * THESE ARE NOT BIT FIELDS 233 + */ 228 234 # define R300_WAIT_2D_CLEAN 0x3 229 235 # define R300_WAIT_3D_CLEAN 0x4 236 + 237 + # define R300_NEW_WAIT_2D_3D 0x3 238 + # define R300_NEW_WAIT_2D_2D_CLEAN 0x4 239 + # define R300_NEW_WAIT_3D_3D_CLEAN 0x6 240 + # define R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN 0x8 241 + 230 242 #define R300_CMD_SCRATCH 8 231 243 232 244 typedef union {