Blob Blame History Raw
From: David Panariti <David.Panariti@amd.com>
Date: Fri, 15 Sep 2017 16:30:08 -0400
Subject: drm/amdgpu: Add ability to determine and report if board supports ECC.
Git-commit: 02bab92328b4d4e0f688be960f0fb5fed1c07ea2
Patch-mainline: v4.16-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

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>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c |  206 ++++++++++++++++++++++++++++++++++
 1 file changed, 206 insertions(+)

--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -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
 	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 *han
 	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 *hand
 	 */
 	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 *hand
 	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);
 }