diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2012-12-13 09:55:45 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2012-12-14 10:45:25 -0500 |
commit | d2ead3eaf8a4bf92129eda69189ce18a6c1cc8bd (patch) | |
tree | 61502ccac6c09b16184b617bfdcb309d19114ccf /drivers/gpu/drm/radeon | |
parent | cf4ccd016bae1a03bb38170eb54b5db4b04e0545 (diff) |
drm/radeon/kms: add evergreen/cayman CS parser for async DMA (v2)
Allows us to use the DMA ring from userspace.
DMA doesn't have a good NOP packet in which to embed the
reloc idx, so userspace has to add a reloc for each
buffer used and order them to match the command stream.
v2: fix address bounds checking
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen_cs.c | 451 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 1 |
3 files changed, 459 insertions, 7 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index fc7e613124d..0a1ec4e6f15 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #define MAX(a,b) (((a)>(b))?(a):(b)) | 34 | #define MAX(a,b) (((a)>(b))?(a):(b)) |
35 | #define MIN(a,b) (((a)<(b))?(a):(b)) | 35 | #define MIN(a,b) (((a)<(b))?(a):(b)) |
36 | 36 | ||
37 | int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, | ||
38 | struct radeon_cs_reloc **cs_reloc); | ||
37 | static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, | 39 | static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, |
38 | struct radeon_cs_reloc **cs_reloc); | 40 | struct radeon_cs_reloc **cs_reloc); |
39 | 41 | ||
@@ -2815,6 +2817,455 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) | |||
2815 | return 0; | 2817 | return 0; |
2816 | } | 2818 | } |
2817 | 2819 | ||
2820 | /* | ||
2821 | * DMA | ||
2822 | */ | ||
2823 | |||
2824 | #define GET_DMA_CMD(h) (((h) & 0xf0000000) >> 28) | ||
2825 | #define GET_DMA_COUNT(h) ((h) & 0x000fffff) | ||
2826 | #define GET_DMA_T(h) (((h) & 0x00800000) >> 23) | ||
2827 | #define GET_DMA_NEW(h) (((h) & 0x04000000) >> 26) | ||
2828 | #define GET_DMA_MISC(h) (((h) & 0x0700000) >> 20) | ||
2829 | |||
2830 | /** | ||
2831 | * evergreen_dma_cs_parse() - parse the DMA IB | ||
2832 | * @p: parser structure holding parsing context. | ||
2833 | * | ||
2834 | * Parses the DMA IB from the CS ioctl and updates | ||
2835 | * the GPU addresses based on the reloc information and | ||
2836 | * checks for errors. (Evergreen-Cayman) | ||
2837 | * Returns 0 for success and an error on failure. | ||
2838 | **/ | ||
2839 | int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | ||
2840 | { | ||
2841 | struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; | ||
2842 | struct radeon_cs_reloc *src_reloc, *dst_reloc, *dst2_reloc; | ||
2843 | u32 header, cmd, count, tiled, new_cmd, misc; | ||
2844 | volatile u32 *ib = p->ib.ptr; | ||
2845 | u32 idx, idx_value; | ||
2846 | u64 src_offset, dst_offset, dst2_offset; | ||
2847 | int r; | ||
2848 | |||
2849 | do { | ||
2850 | if (p->idx >= ib_chunk->length_dw) { | ||
2851 | DRM_ERROR("Can not parse packet at %d after CS end %d !\n", | ||
2852 | p->idx, ib_chunk->length_dw); | ||
2853 | return -EINVAL; | ||
2854 | } | ||
2855 | idx = p->idx; | ||
2856 | header = radeon_get_ib_value(p, idx); | ||
2857 | cmd = GET_DMA_CMD(header); | ||
2858 | count = GET_DMA_COUNT(header); | ||
2859 | tiled = GET_DMA_T(header); | ||
2860 | new_cmd = GET_DMA_NEW(header); | ||
2861 | misc = GET_DMA_MISC(header); | ||
2862 | |||
2863 | switch (cmd) { | ||
2864 | case DMA_PACKET_WRITE: | ||
2865 | r = r600_dma_cs_next_reloc(p, &dst_reloc); | ||
2866 | if (r) { | ||
2867 | DRM_ERROR("bad DMA_PACKET_WRITE\n"); | ||
2868 | return -EINVAL; | ||
2869 | } | ||
2870 | if (tiled) { | ||
2871 | dst_offset = ib[idx+1]; | ||
2872 | dst_offset <<= 8; | ||
2873 | |||
2874 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
2875 | p->idx += count + 7; | ||
2876 | } else { | ||
2877 | dst_offset = ib[idx+1]; | ||
2878 | dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; | ||
2879 | |||
2880 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
2881 | ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
2882 | p->idx += count + 3; | ||
2883 | } | ||
2884 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
2885 | dev_warn(p->dev, "DMA write buffer too small (%llu %lu)\n", | ||
2886 | dst_offset, radeon_bo_size(dst_reloc->robj)); | ||
2887 | return -EINVAL; | ||
2888 | } | ||
2889 | break; | ||
2890 | case DMA_PACKET_COPY: | ||
2891 | r = r600_dma_cs_next_reloc(p, &src_reloc); | ||
2892 | if (r) { | ||
2893 | DRM_ERROR("bad DMA_PACKET_COPY\n"); | ||
2894 | return -EINVAL; | ||
2895 | } | ||
2896 | r = r600_dma_cs_next_reloc(p, &dst_reloc); | ||
2897 | if (r) { | ||
2898 | DRM_ERROR("bad DMA_PACKET_COPY\n"); | ||
2899 | return -EINVAL; | ||
2900 | } | ||
2901 | if (tiled) { | ||
2902 | idx_value = radeon_get_ib_value(p, idx + 2); | ||
2903 | if (new_cmd) { | ||
2904 | switch (misc) { | ||
2905 | case 0: | ||
2906 | /* L2T, frame to fields */ | ||
2907 | if (idx_value & (1 << 31)) { | ||
2908 | DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); | ||
2909 | return -EINVAL; | ||
2910 | } | ||
2911 | r = r600_dma_cs_next_reloc(p, &dst2_reloc); | ||
2912 | if (r) { | ||
2913 | DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); | ||
2914 | return -EINVAL; | ||
2915 | } | ||
2916 | dst_offset = ib[idx+1]; | ||
2917 | dst_offset <<= 8; | ||
2918 | dst2_offset = ib[idx+2]; | ||
2919 | dst2_offset <<= 8; | ||
2920 | src_offset = ib[idx+8]; | ||
2921 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | ||
2922 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
2923 | dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n", | ||
2924 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
2925 | return -EINVAL; | ||
2926 | } | ||
2927 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
2928 | dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%llu %lu)\n", | ||
2929 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
2930 | return -EINVAL; | ||
2931 | } | ||
2932 | if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { | ||
2933 | dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%llu %lu)\n", | ||
2934 | dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); | ||
2935 | return -EINVAL; | ||
2936 | } | ||
2937 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
2938 | ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); | ||
2939 | ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
2940 | ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
2941 | p->idx += 10; | ||
2942 | break; | ||
2943 | case 1: | ||
2944 | /* L2T, T2L partial */ | ||
2945 | if (p->family < CHIP_CAYMAN) { | ||
2946 | DRM_ERROR("L2T, T2L Partial is cayman only !\n"); | ||
2947 | return -EINVAL; | ||
2948 | } | ||
2949 | /* detile bit */ | ||
2950 | if (idx_value & (1 << 31)) { | ||
2951 | /* tiled src, linear dst */ | ||
2952 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | ||
2953 | |||
2954 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
2955 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
2956 | } else { | ||
2957 | /* linear src, tiled dst */ | ||
2958 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
2959 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
2960 | |||
2961 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
2962 | } | ||
2963 | p->idx += 12; | ||
2964 | break; | ||
2965 | case 3: | ||
2966 | /* L2T, broadcast */ | ||
2967 | if (idx_value & (1 << 31)) { | ||
2968 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | ||
2969 | return -EINVAL; | ||
2970 | } | ||
2971 | r = r600_dma_cs_next_reloc(p, &dst2_reloc); | ||
2972 | if (r) { | ||
2973 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | ||
2974 | return -EINVAL; | ||
2975 | } | ||
2976 | dst_offset = ib[idx+1]; | ||
2977 | dst_offset <<= 8; | ||
2978 | dst2_offset = ib[idx+2]; | ||
2979 | dst2_offset <<= 8; | ||
2980 | src_offset = ib[idx+8]; | ||
2981 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | ||
2982 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
2983 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", | ||
2984 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
2985 | return -EINVAL; | ||
2986 | } | ||
2987 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
2988 | dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%llu %lu)\n", | ||
2989 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
2990 | return -EINVAL; | ||
2991 | } | ||
2992 | if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { | ||
2993 | dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%llu %lu)\n", | ||
2994 | dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); | ||
2995 | return -EINVAL; | ||
2996 | } | ||
2997 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
2998 | ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); | ||
2999 | ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3000 | ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3001 | p->idx += 10; | ||
3002 | break; | ||
3003 | case 4: | ||
3004 | /* L2T, T2L */ | ||
3005 | /* detile bit */ | ||
3006 | if (idx_value & (1 << 31)) { | ||
3007 | /* tiled src, linear dst */ | ||
3008 | src_offset = ib[idx+1]; | ||
3009 | src_offset <<= 8; | ||
3010 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | ||
3011 | |||
3012 | dst_offset = ib[idx+7]; | ||
3013 | dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | ||
3014 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3015 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3016 | } else { | ||
3017 | /* linear src, tiled dst */ | ||
3018 | src_offset = ib[idx+7]; | ||
3019 | src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | ||
3020 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3021 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3022 | |||
3023 | dst_offset = ib[idx+1]; | ||
3024 | dst_offset <<= 8; | ||
3025 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
3026 | } | ||
3027 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
3028 | dev_warn(p->dev, "DMA L2T, T2L src buffer too small (%llu %lu)\n", | ||
3029 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
3030 | return -EINVAL; | ||
3031 | } | ||
3032 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3033 | dev_warn(p->dev, "DMA L2T, T2L dst buffer too small (%llu %lu)\n", | ||
3034 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
3035 | return -EINVAL; | ||
3036 | } | ||
3037 | p->idx += 9; | ||
3038 | break; | ||
3039 | case 5: | ||
3040 | /* T2T partial */ | ||
3041 | if (p->family < CHIP_CAYMAN) { | ||
3042 | DRM_ERROR("L2T, T2L Partial is cayman only !\n"); | ||
3043 | return -EINVAL; | ||
3044 | } | ||
3045 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | ||
3046 | ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
3047 | p->idx += 13; | ||
3048 | break; | ||
3049 | case 7: | ||
3050 | /* L2T, broadcast */ | ||
3051 | if (idx_value & (1 << 31)) { | ||
3052 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | ||
3053 | return -EINVAL; | ||
3054 | } | ||
3055 | r = r600_dma_cs_next_reloc(p, &dst2_reloc); | ||
3056 | if (r) { | ||
3057 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | ||
3058 | return -EINVAL; | ||
3059 | } | ||
3060 | dst_offset = ib[idx+1]; | ||
3061 | dst_offset <<= 8; | ||
3062 | dst2_offset = ib[idx+2]; | ||
3063 | dst2_offset <<= 8; | ||
3064 | src_offset = ib[idx+8]; | ||
3065 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | ||
3066 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
3067 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", | ||
3068 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
3069 | return -EINVAL; | ||
3070 | } | ||
3071 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3072 | dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%llu %lu)\n", | ||
3073 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
3074 | return -EINVAL; | ||
3075 | } | ||
3076 | if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { | ||
3077 | dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%llu %lu)\n", | ||
3078 | dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); | ||
3079 | return -EINVAL; | ||
3080 | } | ||
3081 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
3082 | ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8); | ||
3083 | ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3084 | ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3085 | p->idx += 10; | ||
3086 | break; | ||
3087 | default: | ||
3088 | DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc); | ||
3089 | return -EINVAL; | ||
3090 | } | ||
3091 | } else { | ||
3092 | switch (misc) { | ||
3093 | case 0: | ||
3094 | /* detile bit */ | ||
3095 | if (idx_value & (1 << 31)) { | ||
3096 | /* tiled src, linear dst */ | ||
3097 | src_offset = ib[idx+1]; | ||
3098 | src_offset <<= 8; | ||
3099 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | ||
3100 | |||
3101 | dst_offset = ib[idx+7]; | ||
3102 | dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | ||
3103 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3104 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3105 | } else { | ||
3106 | /* linear src, tiled dst */ | ||
3107 | src_offset = ib[idx+7]; | ||
3108 | src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | ||
3109 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3110 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3111 | |||
3112 | dst_offset = ib[idx+1]; | ||
3113 | dst_offset <<= 8; | ||
3114 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | ||
3115 | } | ||
3116 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
3117 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", | ||
3118 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
3119 | return -EINVAL; | ||
3120 | } | ||
3121 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3122 | dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%llu %lu)\n", | ||
3123 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
3124 | return -EINVAL; | ||
3125 | } | ||
3126 | p->idx += 9; | ||
3127 | break; | ||
3128 | default: | ||
3129 | DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc); | ||
3130 | return -EINVAL; | ||
3131 | } | ||
3132 | } | ||
3133 | } else { | ||
3134 | if (new_cmd) { | ||
3135 | switch (misc) { | ||
3136 | case 0: | ||
3137 | /* L2L, byte */ | ||
3138 | src_offset = ib[idx+2]; | ||
3139 | src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | ||
3140 | dst_offset = ib[idx+1]; | ||
3141 | dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | ||
3142 | if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) { | ||
3143 | dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n", | ||
3144 | src_offset + count, radeon_bo_size(src_reloc->robj)); | ||
3145 | return -EINVAL; | ||
3146 | } | ||
3147 | if ((dst_offset + count) > radeon_bo_size(dst_reloc->robj)) { | ||
3148 | dev_warn(p->dev, "DMA L2L, byte dst buffer too small (%llu %lu)\n", | ||
3149 | dst_offset + count, radeon_bo_size(dst_reloc->robj)); | ||
3150 | return -EINVAL; | ||
3151 | } | ||
3152 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff); | ||
3153 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff); | ||
3154 | ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3155 | ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3156 | p->idx += 5; | ||
3157 | break; | ||
3158 | case 1: | ||
3159 | /* L2L, partial */ | ||
3160 | if (p->family < CHIP_CAYMAN) { | ||
3161 | DRM_ERROR("L2L Partial is cayman only !\n"); | ||
3162 | return -EINVAL; | ||
3163 | } | ||
3164 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff); | ||
3165 | ib[idx+2] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3166 | ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff); | ||
3167 | ib[idx+5] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3168 | |||
3169 | p->idx += 9; | ||
3170 | break; | ||
3171 | case 4: | ||
3172 | /* L2L, dw, broadcast */ | ||
3173 | r = r600_dma_cs_next_reloc(p, &dst2_reloc); | ||
3174 | if (r) { | ||
3175 | DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); | ||
3176 | return -EINVAL; | ||
3177 | } | ||
3178 | dst_offset = ib[idx+1]; | ||
3179 | dst_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | ||
3180 | dst2_offset = ib[idx+2]; | ||
3181 | dst2_offset |= ((u64)(ib[idx+5] & 0xff)) << 32; | ||
3182 | src_offset = ib[idx+3]; | ||
3183 | src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32; | ||
3184 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
3185 | dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n", | ||
3186 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
3187 | return -EINVAL; | ||
3188 | } | ||
3189 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3190 | dev_warn(p->dev, "DMA L2L, dw, broadcast dst buffer too small (%llu %lu)\n", | ||
3191 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
3192 | return -EINVAL; | ||
3193 | } | ||
3194 | if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) { | ||
3195 | dev_warn(p->dev, "DMA L2L, dw, broadcast dst2 buffer too small (%llu %lu)\n", | ||
3196 | dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj)); | ||
3197 | return -EINVAL; | ||
3198 | } | ||
3199 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3200 | ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3201 | ib[idx+3] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3202 | ib[idx+4] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3203 | ib[idx+5] += upper_32_bits(dst2_reloc->lobj.gpu_offset) & 0xff; | ||
3204 | ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3205 | p->idx += 7; | ||
3206 | break; | ||
3207 | default: | ||
3208 | DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc); | ||
3209 | return -EINVAL; | ||
3210 | } | ||
3211 | } else { | ||
3212 | /* L2L, dw */ | ||
3213 | src_offset = ib[idx+2]; | ||
3214 | src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | ||
3215 | dst_offset = ib[idx+1]; | ||
3216 | dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | ||
3217 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | ||
3218 | dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n", | ||
3219 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | ||
3220 | return -EINVAL; | ||
3221 | } | ||
3222 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3223 | dev_warn(p->dev, "DMA L2L, dw dst buffer too small (%llu %lu)\n", | ||
3224 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | ||
3225 | return -EINVAL; | ||
3226 | } | ||
3227 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3228 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3229 | ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | ||
3230 | ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | ||
3231 | p->idx += 5; | ||
3232 | } | ||
3233 | } | ||
3234 | break; | ||
3235 | case DMA_PACKET_CONSTANT_FILL: | ||
3236 | r = r600_dma_cs_next_reloc(p, &dst_reloc); | ||
3237 | if (r) { | ||
3238 | DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); | ||
3239 | return -EINVAL; | ||
3240 | } | ||
3241 | dst_offset = ib[idx+1]; | ||
3242 | dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16; | ||
3243 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | ||
3244 | dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", | ||
3245 | dst_offset, radeon_bo_size(dst_reloc->robj)); | ||
3246 | return -EINVAL; | ||
3247 | } | ||
3248 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | ||
3249 | ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000; | ||
3250 | p->idx += 4; | ||
3251 | break; | ||
3252 | case DMA_PACKET_NOP: | ||
3253 | p->idx += 1; | ||
3254 | break; | ||
3255 | default: | ||
3256 | DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx); | ||
3257 | return -EINVAL; | ||
3258 | } | ||
3259 | } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); | ||
3260 | #if 0 | ||
3261 | for (r = 0; r < p->ib->length_dw; r++) { | ||
3262 | printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]); | ||
3263 | mdelay(1); | ||
3264 | } | ||
3265 | #endif | ||
3266 | return 0; | ||
3267 | } | ||
3268 | |||
2818 | /* vm parser */ | 3269 | /* vm parser */ |
2819 | static bool evergreen_vm_reg_valid(u32 reg) | 3270 | static bool evergreen_vm_reg_valid(u32 reg) |
2820 | { | 3271 | { |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index d3603417e5d..ac1d5702144 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c | |||
@@ -1204,7 +1204,7 @@ static struct radeon_asic evergreen_asic = { | |||
1204 | .ib_execute = &evergreen_dma_ring_ib_execute, | 1204 | .ib_execute = &evergreen_dma_ring_ib_execute, |
1205 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1205 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1206 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1206 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1207 | .cs_parse = NULL, | 1207 | .cs_parse = &evergreen_dma_cs_parse, |
1208 | .ring_test = &r600_dma_ring_test, | 1208 | .ring_test = &r600_dma_ring_test, |
1209 | .ib_test = &r600_dma_ib_test, | 1209 | .ib_test = &r600_dma_ib_test, |
1210 | .is_lockup = &r600_dma_is_lockup, | 1210 | .is_lockup = &r600_dma_is_lockup, |
@@ -1288,7 +1288,7 @@ static struct radeon_asic sumo_asic = { | |||
1288 | .ib_execute = &evergreen_dma_ring_ib_execute, | 1288 | .ib_execute = &evergreen_dma_ring_ib_execute, |
1289 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1289 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1290 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1290 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1291 | .cs_parse = NULL, | 1291 | .cs_parse = &evergreen_dma_cs_parse, |
1292 | .ring_test = &r600_dma_ring_test, | 1292 | .ring_test = &r600_dma_ring_test, |
1293 | .ib_test = &r600_dma_ib_test, | 1293 | .ib_test = &r600_dma_ib_test, |
1294 | .is_lockup = &r600_dma_is_lockup, | 1294 | .is_lockup = &r600_dma_is_lockup, |
@@ -1372,7 +1372,7 @@ static struct radeon_asic btc_asic = { | |||
1372 | .ib_execute = &evergreen_dma_ring_ib_execute, | 1372 | .ib_execute = &evergreen_dma_ring_ib_execute, |
1373 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1373 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1374 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1374 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1375 | .cs_parse = NULL, | 1375 | .cs_parse = &evergreen_dma_cs_parse, |
1376 | .ring_test = &r600_dma_ring_test, | 1376 | .ring_test = &r600_dma_ring_test, |
1377 | .ib_test = &r600_dma_ib_test, | 1377 | .ib_test = &r600_dma_ib_test, |
1378 | .is_lockup = &r600_dma_is_lockup, | 1378 | .is_lockup = &r600_dma_is_lockup, |
@@ -1486,7 +1486,7 @@ static struct radeon_asic cayman_asic = { | |||
1486 | .ib_execute = &cayman_dma_ring_ib_execute, | 1486 | .ib_execute = &cayman_dma_ring_ib_execute, |
1487 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1487 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1488 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1488 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1489 | .cs_parse = NULL, | 1489 | .cs_parse = &evergreen_dma_cs_parse, |
1490 | .ring_test = &r600_dma_ring_test, | 1490 | .ring_test = &r600_dma_ring_test, |
1491 | .ib_test = &r600_dma_ib_test, | 1491 | .ib_test = &r600_dma_ib_test, |
1492 | .is_lockup = &cayman_dma_is_lockup, | 1492 | .is_lockup = &cayman_dma_is_lockup, |
@@ -1496,7 +1496,7 @@ static struct radeon_asic cayman_asic = { | |||
1496 | .ib_execute = &cayman_dma_ring_ib_execute, | 1496 | .ib_execute = &cayman_dma_ring_ib_execute, |
1497 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1497 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1498 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1498 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1499 | .cs_parse = NULL, | 1499 | .cs_parse = &evergreen_dma_cs_parse, |
1500 | .ring_test = &r600_dma_ring_test, | 1500 | .ring_test = &r600_dma_ring_test, |
1501 | .ib_test = &r600_dma_ib_test, | 1501 | .ib_test = &r600_dma_ib_test, |
1502 | .is_lockup = &cayman_dma_is_lockup, | 1502 | .is_lockup = &cayman_dma_is_lockup, |
@@ -1611,7 +1611,7 @@ static struct radeon_asic trinity_asic = { | |||
1611 | .ib_execute = &cayman_dma_ring_ib_execute, | 1611 | .ib_execute = &cayman_dma_ring_ib_execute, |
1612 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1612 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1613 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1613 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1614 | .cs_parse = NULL, | 1614 | .cs_parse = &evergreen_dma_cs_parse, |
1615 | .ring_test = &r600_dma_ring_test, | 1615 | .ring_test = &r600_dma_ring_test, |
1616 | .ib_test = &r600_dma_ib_test, | 1616 | .ib_test = &r600_dma_ib_test, |
1617 | .is_lockup = &cayman_dma_is_lockup, | 1617 | .is_lockup = &cayman_dma_is_lockup, |
@@ -1621,7 +1621,7 @@ static struct radeon_asic trinity_asic = { | |||
1621 | .ib_execute = &cayman_dma_ring_ib_execute, | 1621 | .ib_execute = &cayman_dma_ring_ib_execute, |
1622 | .emit_fence = &evergreen_dma_fence_ring_emit, | 1622 | .emit_fence = &evergreen_dma_fence_ring_emit, |
1623 | .emit_semaphore = &r600_dma_semaphore_ring_emit, | 1623 | .emit_semaphore = &r600_dma_semaphore_ring_emit, |
1624 | .cs_parse = NULL, | 1624 | .cs_parse = &evergreen_dma_cs_parse, |
1625 | .ring_test = &r600_dma_ring_test, | 1625 | .ring_test = &r600_dma_ring_test, |
1626 | .ib_test = &r600_dma_ib_test, | 1626 | .ib_test = &r600_dma_ib_test, |
1627 | .is_lockup = &cayman_dma_is_lockup, | 1627 | .is_lockup = &cayman_dma_is_lockup, |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index b311c0a2ec6..d2ac64619f3 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
@@ -431,6 +431,7 @@ u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); | |||
431 | int evergreen_irq_set(struct radeon_device *rdev); | 431 | int evergreen_irq_set(struct radeon_device *rdev); |
432 | int evergreen_irq_process(struct radeon_device *rdev); | 432 | int evergreen_irq_process(struct radeon_device *rdev); |
433 | extern int evergreen_cs_parse(struct radeon_cs_parser *p); | 433 | extern int evergreen_cs_parse(struct radeon_cs_parser *p); |
434 | extern int evergreen_dma_cs_parse(struct radeon_cs_parser *p); | ||
434 | extern void evergreen_pm_misc(struct radeon_device *rdev); | 435 | extern void evergreen_pm_misc(struct radeon_device *rdev); |
435 | extern void evergreen_pm_prepare(struct radeon_device *rdev); | 436 | extern void evergreen_pm_prepare(struct radeon_device *rdev); |
436 | extern void evergreen_pm_finish(struct radeon_device *rdev); | 437 | extern void evergreen_pm_finish(struct radeon_device *rdev); |