Add the necessary set of commands to support OpenGL
indirect draw calls on evergreen/cayman devices that
do not have VM.

Signed-off-by: Glenn Kennard <glenn.kennard at gmail.com>
---
Changes since patch V1:
* Removed multi draw indirect, not used by current userspace which instead
  decomposes multi into separate draw indirect calls
* Added validation to reject cs if indirect draw buffer is too small for 
address+offset
* Removed useless calls to evergreen_cs_track_check
* Reject attempt to call PACKET3_SET_BASE with other value than indirect draw 
buffer base for chips using VM.

I've left the index buffer logic unchanged, outside of scope for this feature,
additional checking of that would be part of support for 
GL_ARB/KHR_robust_buffer_access_behavior.

 drivers/gpu/drm/radeon/evergreen_cs.c | 76 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/radeon_drv.c   |  3 +-
 2 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c 
b/drivers/gpu/drm/radeon/evergreen_cs.c
index 924b1b7..5152c1f 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -83,6 +83,7 @@ struct evergreen_cs_track {
        u32                     htile_offset;
        u32                     htile_surface;
        struct radeon_bo        *htile_bo;
+       unsigned long           indirect_draw_buffer_size;
 };

 static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -1896,6 +1897,14 @@ static int evergreen_packet3_check(struct 
radeon_cs_parser *p,
                }
                break;
        }
+       case PACKET3_INDEX_BUFFER_SIZE:
+       {
+               if (pkt->count != 0) {
+                       DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
+                       return -EINVAL;
+               }
+               break;
+       }
        case PACKET3_DRAW_INDEX:
        {
                uint64_t offset;
@@ -2006,6 +2015,67 @@ static int evergreen_packet3_check(struct 
radeon_cs_parser *p,
                        return r;
                }
                break;
+       case PACKET3_SET_BASE:
+       {
+               /*
+               DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the 
Header will correspond to the shader type of the Load, see Type-3 Packet.
+                  2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies 
which base address is specified in the last two DWs.
+                    0001: DX11 Draw_Index_Indirect Patch Table Base: Base 
address for Draw_Index_Indirect data.
+                  3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned 
Address. Bits [2:0] - Reserved
+                  4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits 
of Address [47:32]
+               */
+               if (pkt->count != 2) {
+                       DRM_ERROR("bad SET_BASE\n");
+                       return -EINVAL;
+               }
+
+               /* currently only supporting setting indirect draw buffer base 
address */
+               if (idx_value != 1) {
+                       DRM_ERROR("bad SET_BASE\n");
+                       return -EINVAL;
+               }
+
+               r = radeon_cs_packet_next_reloc(p, &reloc, 0);
+               if (r) {
+                       DRM_ERROR("bad SET_BASE\n");
+                       return -EINVAL;
+               }
+
+               track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);
+
+               ib[idx+1] = reloc->gpu_offset;
+               ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;
+
+               break;
+       }
+       case PACKET3_DRAW_INDIRECT:
+       case PACKET3_DRAW_INDEX_INDIRECT:
+       {
+               u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;
+
+               /*
+               DW 1 HEADER
+                  2 DATA_OFFSET Bits [31:0] + byte aligned offset where the 
required data structure starts. Bits 1:0 are zero
+                  3 DRAW_INITIATOR Draw Initiator Register. Written to the 
VGT_DRAW_INITIATOR register for the assigned context
+               */
+               if (pkt->count != 1) {
+                       DRM_ERROR("bad DRAW_INDIRECT\n");
+                       return -EINVAL;
+               }
+
+               if (idx_value + size > track->indirect_draw_buffer_size) {
+                       dev_warn(p->dev, "DRAW_INDIRECT buffer too small %llu + 
%llu > %lu\n",
+                               idx_value, size, 
track->indirect_draw_buffer_size);
+                       return -EINVAL;
+               }
+
+               r = evergreen_cs_track_check(p);
+               if (r) {
+                       dev_warn(p->dev, "%s:%d invalid cmd stream\n", 
__func__, __LINE__);
+                       return r;
+               }
+               break;
+       }
        case PACKET3_DISPATCH_DIRECT:
                if (pkt->count != 3) {
                        DRM_ERROR("bad DISPATCH_DIRECT\n");
@@ -3243,7 +3313,13 @@ static int evergreen_vm_packet3_check(struct 
radeon_device *rdev,

        switch (pkt->opcode) {
        case PACKET3_NOP:
+               break;
        case PACKET3_SET_BASE:
+               if (idx_value != 1) {
+                       DRM_ERROR("bad SET_BASE");
+                       return -EINVAL;
+               }
+               break;
        case PACKET3_CLEAR_STATE:
        case PACKET3_INDEX_BUFFER_SIZE:
        case PACKET3_DISPATCH_DIRECT:
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c 
b/drivers/gpu/drm/radeon/radeon_drv.c
index 4f50fb0..5d684be 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -88,9 +88,10 @@
  *   2.39.0 - Add INFO query for number of active CUs
  *   2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
  *            CS to GPU on >= r600
+ *   2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing 
support
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       40
+#define KMS_DRIVER_MINOR       41
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
-- 
1.9.1

Reply via email to