drm/radeon/si: Add support for CP DMA to CS checker for compute v2
authorTom Stellard <thomas.stellard@amd.com>
Fri, 16 Aug 2013 21:47:39 +0000 (17:47 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 30 Aug 2013 20:30:59 +0000 (16:30 -0400)
Also add a new RADEON_INFO query to check that CP DMA packets are
supported on the compute ring.

CP DMA has been supported since the 3.8 kernel, but due to an oversight
we forgot to teach the CS checker that the CP DMA packet was legal for
the compute ring on Southern Islands GPUs.

This patch fixes a bug where the radeon driver will incorrectly reject a legal
CP DMA packet from user space.  I would like to have the patch
backported to stable so that we don't have to require Mesa users to use a
bleeding edge kernel in order to take advantage of this feature which
is already present in the stable kernels (3.8 and newer).

v2:
  - Don't bump kms version, so this patch can be backported to stable
    kernels.

Cc: stable@vger.kernel.org
Signed-off-by: Tom Stellard <thomas.stellard@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/si.c
include/uapi/drm/radeon_drm.h

index 49ff3d1a610238009f242af5fdf4606d9a1951b9..cc2ca380e0c1729df2e2b6ab164fd2d9ea3b3006 100644 (file)
@@ -433,6 +433,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                        return -EINVAL;
                }
                break;
+       case RADEON_INFO_SI_CP_DMA_COMPUTE:
+               *value = 1;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index d5f77eb2344177c5b765cbc6ac82dfb796e5e606..0b4e979b2cbff29e818858a52b59eceefbbca9f1 100644 (file)
@@ -4051,13 +4051,64 @@ static int si_vm_packet3_ce_check(struct radeon_device *rdev,
        return 0;
 }
 
+static int si_vm_packet3_cp_dma_check(u32 *ib, u32 idx)
+{
+       u32 start_reg, reg, i;
+       u32 command = ib[idx + 4];
+       u32 info = ib[idx + 1];
+       u32 idx_value = ib[idx];
+       if (command & PACKET3_CP_DMA_CMD_SAS) {
+               /* src address space is register */
+               if (((info & 0x60000000) >> 29) == 0) {
+                       start_reg = idx_value << 2;
+                       if (command & PACKET3_CP_DMA_CMD_SAIC) {
+                               reg = start_reg;
+                               if (!si_vm_reg_valid(reg)) {
+                                       DRM_ERROR("CP DMA Bad SRC register\n");
+                                       return -EINVAL;
+                               }
+                       } else {
+                               for (i = 0; i < (command & 0x1fffff); i++) {
+                                       reg = start_reg + (4 * i);
+                                       if (!si_vm_reg_valid(reg)) {
+                                               DRM_ERROR("CP DMA Bad SRC register\n");
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (command & PACKET3_CP_DMA_CMD_DAS) {
+               /* dst address space is register */
+               if (((info & 0x00300000) >> 20) == 0) {
+                       start_reg = ib[idx + 2];
+                       if (command & PACKET3_CP_DMA_CMD_DAIC) {
+                               reg = start_reg;
+                               if (!si_vm_reg_valid(reg)) {
+                                       DRM_ERROR("CP DMA Bad DST register\n");
+                                       return -EINVAL;
+                               }
+                       } else {
+                               for (i = 0; i < (command & 0x1fffff); i++) {
+                                       reg = start_reg + (4 * i);
+                               if (!si_vm_reg_valid(reg)) {
+                                               DRM_ERROR("CP DMA Bad DST register\n");
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
                                   u32 *ib, struct radeon_cs_packet *pkt)
 {
+       int r;
        u32 idx = pkt->idx + 1;
        u32 idx_value = ib[idx];
        u32 start_reg, end_reg, reg, i;
-       u32 command, info;
 
        switch (pkt->opcode) {
        case PACKET3_NOP:
@@ -4158,50 +4209,9 @@ static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
                }
                break;
        case PACKET3_CP_DMA:
-               command = ib[idx + 4];
-               info = ib[idx + 1];
-               if (command & PACKET3_CP_DMA_CMD_SAS) {
-                       /* src address space is register */
-                       if (((info & 0x60000000) >> 29) == 0) {
-                               start_reg = idx_value << 2;
-                               if (command & PACKET3_CP_DMA_CMD_SAIC) {
-                                       reg = start_reg;
-                                       if (!si_vm_reg_valid(reg)) {
-                                               DRM_ERROR("CP DMA Bad SRC register\n");
-                                               return -EINVAL;
-                                       }
-                               } else {
-                                       for (i = 0; i < (command & 0x1fffff); i++) {
-                                               reg = start_reg + (4 * i);
-                                               if (!si_vm_reg_valid(reg)) {
-                                                       DRM_ERROR("CP DMA Bad SRC register\n");
-                                                       return -EINVAL;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               if (command & PACKET3_CP_DMA_CMD_DAS) {
-                       /* dst address space is register */
-                       if (((info & 0x00300000) >> 20) == 0) {
-                               start_reg = ib[idx + 2];
-                               if (command & PACKET3_CP_DMA_CMD_DAIC) {
-                                       reg = start_reg;
-                                       if (!si_vm_reg_valid(reg)) {
-                                               DRM_ERROR("CP DMA Bad DST register\n");
-                                               return -EINVAL;
-                                       }
-                               } else {
-                                       for (i = 0; i < (command & 0x1fffff); i++) {
-                                               reg = start_reg + (4 * i);
-                                               if (!si_vm_reg_valid(reg)) {
-                                                       DRM_ERROR("CP DMA Bad DST register\n");
-                                                       return -EINVAL;
-                                               }
-                                       }
-                               }
-                       }
-               }
+               r = si_vm_packet3_cp_dma_check(ib, idx);
+               if (r)
+                       return r;
                break;
        default:
                DRM_ERROR("Invalid GFX packet3: 0x%x\n", pkt->opcode);
@@ -4213,6 +4223,7 @@ static int si_vm_packet3_gfx_check(struct radeon_device *rdev,
 static int si_vm_packet3_compute_check(struct radeon_device *rdev,
                                       u32 *ib, struct radeon_cs_packet *pkt)
 {
+       int r;
        u32 idx = pkt->idx + 1;
        u32 idx_value = ib[idx];
        u32 start_reg, reg, i;
@@ -4285,6 +4296,11 @@ static int si_vm_packet3_compute_check(struct radeon_device *rdev,
                                return -EINVAL;
                }
                break;
+       case PACKET3_CP_DMA:
+               r = si_vm_packet3_cp_dma_check(ib, idx);
+               if (r)
+                       return r;
+               break;
        default:
                DRM_ERROR("Invalid Compute packet3: 0x%x\n", pkt->opcode);
                return -EINVAL;
index 321d4ac5c5128ba58aafafb1d7b624ce25980461..fa8b3adf9ffbbc478a7aae0f83ffbe3bd584a91b 100644 (file)
@@ -979,6 +979,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_RING_WORKING       0x15
 /* SI tile mode array */
 #define RADEON_INFO_SI_TILE_MODE_ARRAY 0x16
+/* query if CP DMA is supported on the compute ring */
+#define RADEON_INFO_SI_CP_DMA_COMPUTE  0x17
 
 
 struct drm_radeon_info {