drm/amdgpu: Add ability to determine and report if board supports ECC.
authorDavid Panariti <David.Panariti@amd.com>
Fri, 15 Sep 2017 20:30:08 +0000 (16:30 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 6 Dec 2017 17:47:48 +0000 (12:47 -0500)
Make initialization code check the ECC related registers, which are initialized
by the VBIOS, to see if ECC is present and initialized and DRM_INFO() the
result.

Signed-off-by: David Panariti <David.Panariti@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c

index b067b46a418f7729f50a15f0d0f550e708513405..d9a91098bcb162121cceab239fa9849e6f7a7cd8 100644 (file)
@@ -36,6 +36,7 @@
 #include "vega10/ATHUB/athub_1_0_offset.h"
 
 #include "soc15_common.h"
+#include "vega10/UMC/umc_6_0_sh_mask.h"
 
 #include "nbio_v6_1.h"
 #include "nbio_v7_0.h"
@@ -85,6 +86,121 @@ static const u32 golden_settings_athub_1_0_0[] =
        SOC15_REG_OFFSET(ATHUB, 0, mmRPB_ARB_CNTL2), 0x00ff00ff, 0x00080008
 };
 
+/* Ecc related register addresses, (BASE + reg offset) */
+/* Universal Memory Controller caps (may be fused). */
+/* UMCCH:UmcLocalCap */
+#define UMCLOCALCAPS_ADDR0     (0x00014306 + 0x00000000)
+#define UMCLOCALCAPS_ADDR1     (0x00014306 + 0x00000800)
+#define UMCLOCALCAPS_ADDR2     (0x00014306 + 0x00001000)
+#define UMCLOCALCAPS_ADDR3     (0x00014306 + 0x00001800)
+#define UMCLOCALCAPS_ADDR4     (0x00054306 + 0x00000000)
+#define UMCLOCALCAPS_ADDR5     (0x00054306 + 0x00000800)
+#define UMCLOCALCAPS_ADDR6     (0x00054306 + 0x00001000)
+#define UMCLOCALCAPS_ADDR7     (0x00054306 + 0x00001800)
+#define UMCLOCALCAPS_ADDR8     (0x00094306 + 0x00000000)
+#define UMCLOCALCAPS_ADDR9     (0x00094306 + 0x00000800)
+#define UMCLOCALCAPS_ADDR10    (0x00094306 + 0x00001000)
+#define UMCLOCALCAPS_ADDR11    (0x00094306 + 0x00001800)
+#define UMCLOCALCAPS_ADDR12    (0x000d4306 + 0x00000000)
+#define UMCLOCALCAPS_ADDR13    (0x000d4306 + 0x00000800)
+#define UMCLOCALCAPS_ADDR14    (0x000d4306 + 0x00001000)
+#define UMCLOCALCAPS_ADDR15    (0x000d4306 + 0x00001800)
+
+/* Universal Memory Controller Channel config. */
+/* UMCCH:UMC_CONFIG */
+#define UMCCH_UMC_CONFIG_ADDR0 (0x00014040 + 0x00000000)
+#define UMCCH_UMC_CONFIG_ADDR1 (0x00014040 + 0x00000800)
+#define UMCCH_UMC_CONFIG_ADDR2 (0x00014040 + 0x00001000)
+#define UMCCH_UMC_CONFIG_ADDR3 (0x00014040 + 0x00001800)
+#define UMCCH_UMC_CONFIG_ADDR4 (0x00054040 + 0x00000000)
+#define UMCCH_UMC_CONFIG_ADDR5 (0x00054040 + 0x00000800)
+#define UMCCH_UMC_CONFIG_ADDR6 (0x00054040 + 0x00001000)
+#define UMCCH_UMC_CONFIG_ADDR7 (0x00054040 + 0x00001800)
+#define UMCCH_UMC_CONFIG_ADDR8 (0x00094040 + 0x00000000)
+#define UMCCH_UMC_CONFIG_ADDR9 (0x00094040 + 0x00000800)
+#define UMCCH_UMC_CONFIG_ADDR10        (0x00094040 + 0x00001000)
+#define UMCCH_UMC_CONFIG_ADDR11        (0x00094040 + 0x00001800)
+#define UMCCH_UMC_CONFIG_ADDR12        (0x000d4040 + 0x00000000)
+#define UMCCH_UMC_CONFIG_ADDR13        (0x000d4040 + 0x00000800)
+#define UMCCH_UMC_CONFIG_ADDR14        (0x000d4040 + 0x00001000)
+#define UMCCH_UMC_CONFIG_ADDR15        (0x000d4040 + 0x00001800)
+
+/* Universal Memory Controller Channel Ecc config. */
+/* UMCCH:EccCtrl */
+#define UMCCH_ECCCTRL_ADDR0    (0x00014053 + 0x00000000)
+#define UMCCH_ECCCTRL_ADDR1    (0x00014053 + 0x00000800)
+#define UMCCH_ECCCTRL_ADDR2    (0x00014053 + 0x00001000)
+#define UMCCH_ECCCTRL_ADDR3    (0x00014053 + 0x00001800)
+#define UMCCH_ECCCTRL_ADDR4    (0x00054053 + 0x00000000)
+#define UMCCH_ECCCTRL_ADDR5    (0x00054053 + 0x00000800)
+#define UMCCH_ECCCTRL_ADDR6    (0x00054053 + 0x00001000)
+#define UMCCH_ECCCTRL_ADDR7    (0x00054053 + 0x00001800)
+#define UMCCH_ECCCTRL_ADDR8    (0x00094053 + 0x00000000)
+#define UMCCH_ECCCTRL_ADDR9    (0x00094053 + 0x00000800)
+#define UMCCH_ECCCTRL_ADDR10   (0x00094053 + 0x00001000)
+#define UMCCH_ECCCTRL_ADDR11   (0x00094053 + 0x00001800)
+#define UMCCH_ECCCTRL_ADDR12   (0x000d4053 + 0x00000000)
+#define UMCCH_ECCCTRL_ADDR13   (0x000d4053 + 0x00000800)
+#define UMCCH_ECCCTRL_ADDR14   (0x000d4053 + 0x00001000)
+#define UMCCH_ECCCTRL_ADDR15   (0x000d4053 + 0x00001800)
+
+static const uint32_t ecc_umclocalcap_addrs[] = {
+       UMCLOCALCAPS_ADDR0,
+       UMCLOCALCAPS_ADDR1,
+       UMCLOCALCAPS_ADDR2,
+       UMCLOCALCAPS_ADDR3,
+       UMCLOCALCAPS_ADDR4,
+       UMCLOCALCAPS_ADDR5,
+       UMCLOCALCAPS_ADDR6,
+       UMCLOCALCAPS_ADDR7,
+       UMCLOCALCAPS_ADDR8,
+       UMCLOCALCAPS_ADDR9,
+       UMCLOCALCAPS_ADDR10,
+       UMCLOCALCAPS_ADDR11,
+       UMCLOCALCAPS_ADDR12,
+       UMCLOCALCAPS_ADDR13,
+       UMCLOCALCAPS_ADDR14,
+       UMCLOCALCAPS_ADDR15,
+};
+
+static const uint32_t ecc_umcch_umc_config_addrs[] = {
+       UMCCH_UMC_CONFIG_ADDR0,
+       UMCCH_UMC_CONFIG_ADDR1,
+       UMCCH_UMC_CONFIG_ADDR2,
+       UMCCH_UMC_CONFIG_ADDR3,
+       UMCCH_UMC_CONFIG_ADDR4,
+       UMCCH_UMC_CONFIG_ADDR5,
+       UMCCH_UMC_CONFIG_ADDR6,
+       UMCCH_UMC_CONFIG_ADDR7,
+       UMCCH_UMC_CONFIG_ADDR8,
+       UMCCH_UMC_CONFIG_ADDR9,
+       UMCCH_UMC_CONFIG_ADDR10,
+       UMCCH_UMC_CONFIG_ADDR11,
+       UMCCH_UMC_CONFIG_ADDR12,
+       UMCCH_UMC_CONFIG_ADDR13,
+       UMCCH_UMC_CONFIG_ADDR14,
+       UMCCH_UMC_CONFIG_ADDR15,
+};
+
+static const uint32_t ecc_umcch_eccctrl_addrs[] = {
+       UMCCH_ECCCTRL_ADDR0,
+       UMCCH_ECCCTRL_ADDR1,
+       UMCCH_ECCCTRL_ADDR2,
+       UMCCH_ECCCTRL_ADDR3,
+       UMCCH_ECCCTRL_ADDR4,
+       UMCCH_ECCCTRL_ADDR5,
+       UMCCH_ECCCTRL_ADDR6,
+       UMCCH_ECCCTRL_ADDR7,
+       UMCCH_ECCCTRL_ADDR8,
+       UMCCH_ECCCTRL_ADDR9,
+       UMCCH_ECCCTRL_ADDR10,
+       UMCCH_ECCCTRL_ADDR11,
+       UMCCH_ECCCTRL_ADDR12,
+       UMCCH_ECCCTRL_ADDR13,
+       UMCCH_ECCCTRL_ADDR14,
+       UMCCH_ECCCTRL_ADDR15,
+};
+
 static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
                                        struct amdgpu_irq_src *src,
                                        unsigned type,
@@ -389,6 +505,85 @@ static int gmc_v9_0_early_init(void *handle)
        return 0;
 }
 
+static int gmc_v9_0_ecc_available(struct amdgpu_device *adev)
+{
+       uint32_t reg_val;
+       uint32_t reg_addr;
+       uint32_t field_val;
+       size_t i;
+       uint32_t fv2;
+       size_t lost_sheep;
+
+       DRM_DEBUG("ecc: gmc_v9_0_ecc_available()\n");
+
+       lost_sheep = 0;
+       for (i = 0; i < ARRAY_SIZE(ecc_umclocalcap_addrs); ++i) {
+               reg_addr = ecc_umclocalcap_addrs[i];
+               DRM_DEBUG("ecc: "
+                         "UMCCH_UmcLocalCap[%zu]: reg_addr: 0x%08x\n",
+                         i, reg_addr);
+               reg_val = RREG32(reg_addr);
+               field_val = REG_GET_FIELD(reg_val, UMCCH0_0_UmcLocalCap,
+                                         EccDis);
+               DRM_DEBUG("ecc: "
+                         "reg_val: 0x%08x, "
+                         "EccDis: 0x%08x, ",
+                         reg_val, field_val);
+               if (field_val) {
+                       DRM_ERROR("ecc: UmcLocalCap:EccDis is set.\n");
+                       ++lost_sheep;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ecc_umcch_umc_config_addrs); ++i) {
+               reg_addr = ecc_umcch_umc_config_addrs[i];
+               DRM_DEBUG("ecc: "
+                         "UMCCH0_0_UMC_CONFIG[%zu]: reg_addr: 0x%08x",
+                         i, reg_addr);
+               reg_val = RREG32(reg_addr);
+               field_val = REG_GET_FIELD(reg_val, UMCCH0_0_UMC_CONFIG,
+                                         DramReady);
+               DRM_DEBUG("ecc: "
+                         "reg_val: 0x%08x, "
+                         "DramReady: 0x%08x\n",
+                         reg_val, field_val);
+
+               if (!field_val) {
+                       DRM_ERROR("ecc: UMC_CONFIG:DramReady is not set.\n");
+                       ++lost_sheep;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ecc_umcch_eccctrl_addrs); ++i) {
+               reg_addr = ecc_umcch_eccctrl_addrs[i];
+               DRM_DEBUG("ecc: "
+                         "UMCCH_EccCtrl[%zu]: reg_addr: 0x%08x, ",
+                         i, reg_addr);
+               reg_val = RREG32(reg_addr);
+               field_val = REG_GET_FIELD(reg_val, UMCCH0_0_EccCtrl,
+                                         WrEccEn);
+               fv2 = REG_GET_FIELD(reg_val, UMCCH0_0_EccCtrl,
+                                   RdEccEn);
+               DRM_DEBUG("ecc: "
+                         "reg_val: 0x%08x, "
+                         "WrEccEn: 0x%08x, "
+                         "RdEccEn: 0x%08x\n",
+                         reg_val, field_val, fv2);
+
+               if (!field_val) {
+                       DRM_ERROR("ecc: WrEccEn is not set\n");
+                       ++lost_sheep;
+               }
+               if (!fv2) {
+                       DRM_ERROR("ecc: RdEccEn is not set\n");
+                       ++lost_sheep;
+               }
+       }
+
+       DRM_DEBUG("ecc: lost_sheep: %zu\n", lost_sheep);
+       return lost_sheep == 0;
+}
+
 static int gmc_v9_0_late_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -403,6 +598,7 @@ static int gmc_v9_0_late_init(void *handle)
         */
        unsigned vm_inv_eng[AMDGPU_MAX_VMHUBS] = { 4, 4 };
        unsigned i;
+       int r;
 
        for(i = 0; i < adev->num_rings; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
@@ -418,6 +614,16 @@ static int gmc_v9_0_late_init(void *handle)
        for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i)
                BUG_ON(vm_inv_eng[i] > 16);
 
+       r = gmc_v9_0_ecc_available(adev);
+       if (r == 1) {
+               DRM_INFO("ECC is active.\n");
+       } else if (r == 0) {
+               DRM_INFO("ECC is not present.\n");
+       } else {
+               DRM_ERROR("gmc_v9_0_ecc_available() failed. r: %d\n", r);
+               return r;
+       }
+
        return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
 }