OSDN Git Service

drm/amdgpu: add helper for rlcg indirect reg access
authorHawking Zhang <Hawking.Zhang@amd.com>
Tue, 18 Jan 2022 13:44:06 +0000 (21:44 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 25 Jan 2022 23:00:33 +0000 (18:00 -0500)
The helper will be used to access registers from sriov
guest in full access time

Signed-off-by: Hawking Zhang <Hawking.Zhang@amd.com>
Reviewed-by: Zhou, Peng Ju <PengJu.Zhou@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h

index a40e4fc..8c27d31 100644 (file)
@@ -855,3 +855,114 @@ bool amdgpu_virt_get_rlcg_reg_access_flag(struct amdgpu_device *adev, u32 acc_fl
        }
        return ret;
 }
+
+static u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v, u32 flag)
+{
+       struct amdgpu_rlcg_reg_access_ctrl *reg_access_ctrl;
+       uint32_t timeout = 50000;
+       uint32_t i, tmp;
+       uint32_t ret = 0;
+       static void *scratch_reg0;
+       static void *scratch_reg1;
+       static void *scratch_reg2;
+       static void *scratch_reg3;
+       static void *spare_int;
+
+       if (!adev->gfx.rlc.rlcg_reg_access_supported) {
+               dev_err(adev->dev,
+                       "indirect registers access through rlcg is not available\n");
+               return 0;
+       }
+
+       scratch_reg0 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg0;
+       scratch_reg1 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg1;
+       scratch_reg2 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg2;
+       scratch_reg3 = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->scratch_reg3;
+       if (reg_access_ctrl->spare_int)
+               spare_int = (void __iomem *)adev->rmmio + 4 * reg_access_ctrl->spare_int;
+
+       if (offset == reg_access_ctrl->grbm_cntl) {
+               /* if the target reg offset is grbm_cntl, write to scratch_reg2 */
+               writel(v, scratch_reg2);
+               writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
+       } else if (offset == reg_access_ctrl->grbm_idx) {
+               /* if the target reg offset is grbm_idx, write to scratch_reg3 */
+               writel(v, scratch_reg3);
+               writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
+       } else {
+               /*
+                * SCRATCH_REG0         = read/write value
+                * SCRATCH_REG1[30:28]  = command
+                * SCRATCH_REG1[19:0]   = address in dword
+                * SCRATCH_REG1[26:24]  = Error reporting
+                */
+               writel(v, scratch_reg0);
+               writel((offset | flag), scratch_reg1);
+               if (reg_access_ctrl->spare_int)
+                       writel(1, spare_int);
+
+               for (i = 0; i < timeout; i++) {
+                       tmp = readl(scratch_reg1);
+                       if (!(tmp & flag))
+                               break;
+                       udelay(10);
+               }
+
+               if (i >= timeout) {
+                       if (amdgpu_sriov_rlcg_error_report_enabled(adev)) {
+                               if (tmp & AMDGPU_RLCG_VFGATE_DISABLED) {
+                                       dev_err(adev->dev,
+                                               "vfgate is disabled, rlcg failed to program reg: 0x%05x\n", offset);
+                               } else if (tmp & AMDGPU_RLCG_WRONG_OPERATION_TYPE) {
+                                       dev_err(adev->dev,
+                                               "wrong operation type, rlcg failed to program reg: 0x%05x\n", offset);
+                               } else if (tmp & AMDGPU_RLCG_REG_NOT_IN_RANGE) {
+                                       dev_err(adev->dev,
+                                               "regiser is not in range, rlcg failed to program reg: 0x%05x\n", offset);
+                               } else {
+                                       dev_err(adev->dev,
+                                               "unknown error type, rlcg failed to program reg: 0x%05x\n", offset);
+                               }
+                       } else {
+                               dev_err(adev->dev,
+                                       "timeout: rlcg faled to program reg: 0x%05x\n", offset);
+                       }
+               }
+       }
+
+       ret = readl(scratch_reg0);
+       return ret;
+}
+
+void amdgpu_sriov_wreg(struct amdgpu_device *adev,
+                      u32 offset, u32 value,
+                      u32 acc_flags, u32 hwip)
+{
+       u32 rlcg_flag;
+
+       if (!amdgpu_sriov_runtime(adev) &&
+           amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags, hwip, true, &rlcg_flag)) {
+               amdgpu_virt_rlcg_reg_rw(adev, offset, value, rlcg_flag);
+               return;
+       }
+
+       if (acc_flags & AMDGPU_REGS_NO_KIQ)
+               WREG32_NO_KIQ(offset, value);
+       else
+               WREG32(offset, value);
+}
+
+u32 amdgpu_sriov_rreg(struct amdgpu_device *adev,
+                     u32 offset, u32 acc_flags, u32 hwip)
+{
+       u32 rlcg_flag;
+
+       if (!amdgpu_sriov_runtime(adev) &&
+           amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags, hwip, false, &rlcg_flag))
+               return amdgpu_virt_rlcg_reg_rw(adev, offset, 0, rlcg_flag);
+
+       if (acc_flags & AMDGPU_REGS_NO_KIQ)
+               return RREG32_NO_KIQ(offset);
+       else
+               return RREG32(offset);
+}
index 404a06e..dbfa3ba 100644 (file)
 #define AMDGPU_RLCG_GC_READ            (0x1 << 28)
 #define AMDGPU_RLCG_MMHUB_WRITE        (0x2 << 28)
 
+/* error code for indirect register access path supported by rlcg for sriov */
+#define AMDGPU_RLCG_VFGATE_DISABLED            0x4000000
+#define AMDGPU_RLCG_WRONG_OPERATION_TYPE       0x2000000
+#define AMDGPU_RLCG_REG_NOT_IN_RANGE           0x1000000
+
 /* all asic after AI use this offset */
 #define mmRCC_IOV_FUNC_IDENTIFIER 0xDE5
 /* tonga/fiji use this offset */
@@ -281,6 +286,9 @@ struct amdgpu_video_codec_info;
 (amdgpu_sriov_vf((adev)) && \
        ((adev)->virt.reg_access & (AMDGIM_FEATURE_GC_REG_RLC_EN)))
 
+#define amdgpu_sriov_rlcg_error_report_enabled(adev) \
+        (amdgpu_sriov_reg_indirect_mmhub(adev) || amdgpu_sriov_reg_indirect_gc(adev))
+
 #define amdgpu_passthrough(adev) \
 ((adev)->virt.caps & AMDGPU_PASSTHROUGH_MODE)
 
@@ -299,7 +307,6 @@ static inline bool is_virtual_machine(void)
        ((!amdgpu_in_reset(adev)) && adev->virt.tdr_debug)
 #define amdgpu_sriov_is_normal(adev) \
        ((!amdgpu_in_reset(adev)) && (!adev->virt.tdr_debug))
-
 bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev);
 void amdgpu_virt_init_setting(struct amdgpu_device *adev);
 void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
@@ -329,4 +336,9 @@ void amdgpu_virt_update_sriov_video_codec(struct amdgpu_device *adev,
                        struct amdgpu_video_codec_info *decode, uint32_t decode_array_size);
 bool amdgpu_virt_get_rlcg_reg_access_flag(struct amdgpu_device *adev, u32 acc_flags,
                                          u32 hwip, bool write, u32 *rlcg_flag);
+void amdgpu_sriov_wreg(struct amdgpu_device *adev,
+                      u32 offset, u32 value,
+                      u32 acc_flags, u32 hwip);
+u32 amdgpu_sriov_rreg(struct amdgpu_device *adev,
+                     u32 offset, u32 acc_flags, u32 hwip);
 #endif