drm/amdgpu/si: implement get/set pcie_lanes asic callback
authorAlex Deucher <alexander.deucher@amd.com>
Tue, 3 Apr 2018 17:54:33 +0000 (12:54 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Apr 2018 07:36:35 +0000 (09:36 +0200)
commit 20ca25e86c56f5490bdc80318f4fc06466e4c21b upstream.

Required for dpm setup on some asics. Fixes a NULL dereference
on asics that require it.

Acked-by: Christian König <christian.koenig@amd.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=102553
Tested-by: Abel Garcia Dorta <mercuriete@yahoo.es>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/amd/amdgpu/si.c

index 4c178fe..40520a9 100644 (file)
@@ -1231,6 +1231,71 @@ static void si_detect_hw_virtualization(struct amdgpu_device *adev)
                adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE;
 }
 
+static int si_get_pcie_lanes(struct amdgpu_device *adev)
+{
+       u32 link_width_cntl;
+
+       if (adev->flags & AMD_IS_APU)
+               return 0;
+
+       link_width_cntl = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+
+       switch ((link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT) {
+       case LC_LINK_WIDTH_X1:
+               return 1;
+       case LC_LINK_WIDTH_X2:
+               return 2;
+       case LC_LINK_WIDTH_X4:
+               return 4;
+       case LC_LINK_WIDTH_X8:
+               return 8;
+       case LC_LINK_WIDTH_X0:
+       case LC_LINK_WIDTH_X16:
+       default:
+               return 16;
+       }
+}
+
+static void si_set_pcie_lanes(struct amdgpu_device *adev, int lanes)
+{
+       u32 link_width_cntl, mask;
+
+       if (adev->flags & AMD_IS_APU)
+               return;
+
+       switch (lanes) {
+       case 0:
+               mask = LC_LINK_WIDTH_X0;
+               break;
+       case 1:
+               mask = LC_LINK_WIDTH_X1;
+               break;
+       case 2:
+               mask = LC_LINK_WIDTH_X2;
+               break;
+       case 4:
+               mask = LC_LINK_WIDTH_X4;
+               break;
+       case 8:
+               mask = LC_LINK_WIDTH_X8;
+               break;
+       case 16:
+               mask = LC_LINK_WIDTH_X16;
+               break;
+       default:
+               DRM_ERROR("invalid pcie lane request: %d\n", lanes);
+               return;
+       }
+
+       link_width_cntl = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+       link_width_cntl &= ~LC_LINK_WIDTH_MASK;
+       link_width_cntl |= mask << LC_LINK_WIDTH_SHIFT;
+       link_width_cntl |= (LC_RECONFIG_NOW |
+                           LC_RECONFIG_ARC_MISSING_ESCAPE);
+
+       WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+}
+
 static const struct amdgpu_asic_funcs si_asic_funcs =
 {
        .read_disabled_bios = &si_read_disabled_bios,
@@ -1241,6 +1306,8 @@ static const struct amdgpu_asic_funcs si_asic_funcs =
        .get_xclk = &si_get_xclk,
        .set_uvd_clocks = &si_set_uvd_clocks,
        .set_vce_clocks = NULL,
+       .get_pcie_lanes = &si_get_pcie_lanes,
+       .set_pcie_lanes = &si_set_pcie_lanes,
        .get_config_memsize = &si_get_config_memsize,
 };