[PATCH 078/109] drm/amdgpu/ras: use flip-bit mask to generalize bad page address derivation

Alex Deucher <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: YiPeng Chai <[email protected]>

Use flip-bit mask to generalize bad page address derivation in a row.

Signed-off-by: YiPeng Chai <[email protected]>
Reviewed-by: Tao Zhou <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/ras/core/eeprom.h        |   1 +
 drivers/gpu/drm/amd/ras/core/ras_umc.c       |  77 +++++++++++--
 drivers/gpu/drm/amd/ras/core/ras_umc.h       |   3 -
 drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c | 110 ++++++++++++++++---
 drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c |  49 ++++-----
 5 files changed, 181 insertions(+), 59 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/eeprom.h b/drivers/gpu/drm/amd/ras/core/eeprom.h
index ae22bb3f83187..bf721c2a11f1e 100644
--- a/drivers/gpu/drm/amd/ras/core/eeprom.h
+++ b/drivers/gpu/drm/amd/ras/core/eeprom.h
@@ -167,6 +167,7 @@ struct eeprom_umc_record {
 	 * used with cur_nps_retired_row_pfn to derive all bad page addresses
 	 */
 	uint64_t cur_nps_pa_flip_mask;
+	uint32_t cur_nps_valid_page_num;
 	uint32_t cur_nps_bank;
 	uint32_t cur_nps;
 	uint64_t ipid;
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.c b/drivers/gpu/drm/amd/ras/core/ras_umc.c
index cef5770a75a60..c30d11942a72b 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.c
@@ -177,19 +177,61 @@ int ras_umc_clear_logged_ecc(struct ras_core_context *ras_core)
 	return 0;
 }
 
+static int ras_umc_expand_row_pages(struct ras_core_context *ras_core,
+	struct eeprom_umc_record *record, uint64_t *page_pfns, uint32_t nr_page_pfns)
+{
+	uint64_t retired_addr = RAS_PFN_TO_ADDR(record->cur_nps_retired_row_pfn);
+	uint64_t flip_mask = record->cur_nps_pa_flip_mask;
+	uint64_t subset;
+	uint64_t row_pa, addr;
+	uint32_t count = 0;
+
+	if (!retired_addr || !flip_mask || !page_pfns || !nr_page_pfns)
+		return -ENOEXEC;
+
+	row_pa = retired_addr & ~(flip_mask);
+
+	if (count < nr_page_pfns)
+		page_pfns[count++] = RAS_ADDR_TO_PFN(row_pa);
+
+	subset = flip_mask;
+	while (subset) {
+		addr = row_pa ^ subset;
+
+		if (count >= nr_page_pfns)
+			break;
+
+		page_pfns[count++] = RAS_ADDR_TO_PFN(addr);
+
+		subset = (subset - 1) & flip_mask;
+	};
+
+	return count;
+}
+
 int ras_umc_convert_record_to_nps_pages(struct ras_core_context *ras_core,
 		struct eeprom_umc_record *record, uint32_t nps,
-		uint64_t *page_pfn, uint32_t max_pages)
+		uint64_t *page_pfns, uint32_t nr_page_pfns)
 {
-	int count = 0;
-	struct ras_umc *ras_umc = &ras_core->ras_umc;
+	uint32_t new_nps;
+	int ret, count = 0;
 
-	if (!page_pfn || !max_pages)
+	if (!page_pfns || !nr_page_pfns || !record ||
+	    (record->cur_nps > UMC_MEMORY_PARTITION_MODE_NPS8))
 		return -EINVAL;
 
-	if (ras_umc->ip_func && ras_umc->ip_func->eeprom_record_to_nps_pages)
-		count = ras_umc->ip_func->eeprom_record_to_nps_pages(ras_core,
-					record, nps, page_pfn, max_pages);
+	if (!record->cur_nps || !record->cur_nps_retired_row_pfn ||
+	    !record->cur_nps_pa_flip_mask) {
+		new_nps = record->cur_nps ?
+			record->cur_nps : ras_core_get_curr_nps_mode(ras_core);
+		ret = ras_umc_record_to_nps_record(ras_core, record, new_nps);
+		if (ret)
+			return ret;
+	}
+
+	count = ras_umc_expand_row_pages(ras_core, record, page_pfns, nr_page_pfns);
+	if (count > 0)
+		record->cur_nps_valid_page_num = count;
 
 	return count;
 }
@@ -496,7 +538,7 @@ static bool ras_umc_check_retired_record(struct ras_core_context *ras_core,
 	int ret;
 
 	nps = ras_core_get_curr_nps_mode(ras_core);
-	ret = ras_umc_eeprom_rec2nps_rec(ras_core, record, nps);
+	ret = ras_umc_record_to_nps_record(ras_core, record, nps);
 	if (ret) {
 		RAS_DEV_ERR(ras_core->dev, "Failed to translate nps record! ret:%d\n", ret);
 		return true;
@@ -993,11 +1035,28 @@ int ras_umc_bank_to_umc_record(struct ras_core_context *ras_core,
 int ras_umc_record_to_nps_record(struct ras_core_context *ras_core,
 		struct eeprom_umc_record *record,  uint32_t nps)
 {
+	struct ras_umc *ras_umc = &ras_core->ras_umc;
+	uint64_t ch_idx_v2;
+	uint32_t save_nps;
+
 	if (!record || !nps ||
 		(nps >= UMC_MEMORY_PARTITION_MODE_UNKNOWN))
 		return -EINVAL;
 
-	return ras_umc_eeprom_rec2nps_rec(ras_core, record, nps);
+	/* Avoid redundant conversion for the same NPS mode */
+	if ((record->cur_nps == nps) && record->cur_nps_retired_row_pfn &&
+	    record->cur_nps_pa_flip_mask)
+		return 0;
+
+	save_nps = EEPROM_RECORD_UMC_NPS_MODE(record);
+	ch_idx_v2 = record->retired_row_pfn & UMC_CHANNEL_IDX_V2;
+	if (!save_nps && !ch_idx_v2)
+		return ras_umc_eeprom_rec2nps_rec(ras_core, record, nps);
+
+	if (!ras_umc->ip_func || !ras_umc->ip_func->eeprom_record_to_nps_record)
+		return -EOPNOTSUPP;
+
+	return ras_umc->ip_func->eeprom_record_to_nps_record(ras_core, record, nps);
 }
 
 int ras_umc_dump_fw_records(struct ras_core_context *ras_core)
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.h b/drivers/gpu/drm/amd/ras/core/ras_umc.h
index a64b5106d0051..b52480ba886b8 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.h
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.h
@@ -128,9 +128,6 @@ struct umc_bank_addr {
 struct ras_umc_ip_func {
 	int (*bank_to_eeprom_record)(struct ras_core_context *ras_core,
 			struct ras_bank_ecc *bank, struct eeprom_umc_record *record);
-	int (*eeprom_record_to_nps_pages)(struct ras_core_context *ras_core,
-			struct eeprom_umc_record *record, uint32_t nps,
-			uint64_t *pfns, uint32_t num);
 	int (*eeprom_record_to_nps_record)(struct ras_core_context *ras_core,
 			struct eeprom_umc_record *record, uint32_t nps);
 	int (*bank_to_soc_pa)(struct ras_core_context *ras_core,
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c b/drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c
index 438270adcfcbb..37fa24acddd02 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c
@@ -148,21 +148,31 @@ static void __get_nps_pa_flip_bits(struct ras_core_context *ras_core,
 	}
 }
 
-static uint64_t umc_v12_0_nps_pa_to_row_pa(struct ras_core_context *ras_core,
-		uint64_t pa, enum umc_memory_partition_mode nps, bool zero_pfn_ok)
+static uint64_t __get_nps_pa_flip_mask(struct ras_core_context *ras_core,
+		enum umc_memory_partition_mode nps)
 {
 	struct umc_flip_bits flip_bits = {0};
-	uint64_t row_pa;
+	uint64_t flip_mask = 0;
 	int i;
 
 	__get_nps_pa_flip_bits(ras_core, nps, &flip_bits);
 
-	row_pa = pa;
-	/* clear loop bits in soc physical address */
 	for (i = 0; i < flip_bits.bit_num; i++)
-		row_pa &= ~BIT_ULL(flip_bits.flip_bits_in_pa[i]);
+		flip_mask |= BIT_ULL(flip_bits.flip_bits_in_pa[i]);
+
+	return flip_mask;
+}
+
+static uint64_t umc_v12_0_nps_pa_to_row_pa(struct ras_core_context *ras_core,
+		uint64_t pa, enum umc_memory_partition_mode nps, bool zero_pfn_ok)
+{
+	struct umc_flip_bits flip_bits = {0};
+	uint64_t row_pa;
 
-	if (!zero_pfn_ok && !RAS_ADDR_TO_PFN(row_pa))
+	__get_nps_pa_flip_bits(ras_core, nps, &flip_bits);
+	row_pa = pa & ~__get_nps_pa_flip_mask(ras_core, nps);
+
+	if (!zero_pfn_ok && !RAS_ADDR_TO_PFN(row_pa) && flip_bits.bit_num > 2)
 		row_pa |= BIT_ULL(flip_bits.flip_bits_in_pa[2]);
 
 	return row_pa;
@@ -176,13 +186,15 @@ static int lookup_bad_pages_in_a_row(struct ras_core_context *ras_core,
 	uint32_t col, col_lower, row, row_lower, idx, row_high;
 	uint64_t soc_pa, row_pa, column, err_addr;
 	uint64_t retired_addr = RAS_PFN_TO_ADDR(record->cur_nps_retired_row_pfn);
+	uint64_t flip_mask = 0;
 	struct umc_flip_bits flip_bits = {0};
 	uint32_t retire_unit;
 	uint32_t i;
 
 	__get_nps_pa_flip_bits(ras_core, nps, &flip_bits);
 
-	row_pa = umc_v12_0_nps_pa_to_row_pa(ras_core, retired_addr, nps, true);
+	flip_mask = __get_nps_pa_flip_mask(ras_core, nps);
+	row_pa = retired_addr & ~(flip_mask);
 
 	err_addr = record->address;
 	/* get column bit 0 and 1 in mca address */
@@ -348,7 +360,24 @@ static int umc_v12_0_ma2pa(struct ras_core_context *ras_core,
 
 	return 0;
 }
+static int convert_ma_to_pa(struct ras_core_context *ras_core,
+			struct umc_mca_addr *addr_in, struct umc_phy_addr *addr_out,
+			uint32_t nps)
+{
+	int ret;
 
+	if (ras_psp_check_supported_cmd(ras_core, RAS_TA_CMD_ID__QUERY_ADDRESS))
+		ret = ras_umc_ras_ta_translate_addr(ras_core,
+				addr_in, addr_out, nps);
+	else
+		ret = umc_v12_0_ma2pa(ras_core,
+				addr_in, addr_out, nps);
+
+	if (!addr_out->pa_flip_mask)
+		addr_out->pa_flip_mask = __get_nps_pa_flip_mask(ras_core, nps);
+
+	return ret;
+}
 static int convert_bank_to_nps_addr(struct ras_core_context *ras_core,
 			struct ras_bank_ecc *bank, struct umc_phy_addr *pa_addr, uint32_t nps)
 {
@@ -365,10 +394,10 @@ static int convert_bank_to_nps_addr(struct ras_core_context *ras_core,
 	addr_in.node_inst = ACA_IPID_2_DIE_ID(bank->ipid);
 	addr_in.socket_id = ACA_IPID_2_SOCKET_ID(bank->ipid);
 
-	ret = ras_umc_ma2pa(ras_core, &addr_in, &addr_out, nps);
+	ret = convert_ma_to_pa(ras_core, &addr_in, &addr_out, nps);
 	if (!ret) {
-		pa_addr->pa =
-			umc_v12_0_nps_pa_to_row_pa(ras_core, addr_out.pa, nps, false);
+		pa_addr->pa_flip_mask = addr_out.pa_flip_mask;
+		pa_addr->pa = addr_out.pa | pa_addr->pa_flip_mask;
 		pa_addr->channel_idx = addr_out.channel_idx;
 		pa_addr->bank = addr_out.bank;
 	}
@@ -408,12 +437,59 @@ static int umc_v12_0_bank_to_eeprom_record(struct ras_core_context *ras_core,
 	return 0;
 }
 
-static int umc_v12_0_eeprom_record_to_nps_pages(struct ras_core_context *ras_core,
-			struct eeprom_umc_record *record, uint32_t nps,
-			uint64_t *pfns, uint32_t num)
+static int convert_eeprom_record_to_nps_addr(struct ras_core_context *ras_core,
+	struct eeprom_umc_record *record, uint64_t *pa, uint64_t *pa_flip_mask, uint32_t nps)
 {
-	return lookup_bad_pages_in_a_row(ras_core,
-				record, nps, pfns, num, 0, false);
+	struct device_system_info dev_info = {0};
+	struct umc_mca_addr addr_in;
+	struct umc_phy_addr addr_out;
+	int ret;
+
+	memset(&addr_in, 0, sizeof(addr_in));
+	memset(&addr_out, 0, sizeof(addr_out));
+
+	ras_core_get_device_system_info(ras_core, &dev_info);
+
+	addr_in.err_addr = record->address;
+	addr_in.ch_inst = record->mem_channel;
+	addr_in.umc_inst = record->mcumc_id;
+	addr_in.node_inst = UMC_INV_AID_NODE;
+	addr_in.socket_id = dev_info.socket_id;
+
+	ret = convert_ma_to_pa(ras_core, &addr_in, &addr_out, nps);
+	if (ret)
+		return ret;
+
+	*pa_flip_mask = addr_out.pa_flip_mask;
+	*pa = addr_out.pa | addr_out.pa_flip_mask;
+
+	return 0;
+}
+
+static int umc_v12_0_eeprom_record_to_nps_record(struct ras_core_context *ras_core,
+				struct eeprom_umc_record *record, uint32_t nps)
+{
+	uint64_t pa = 0, flip_mask = 0;
+	uint64_t row_pfn;
+	int ret = 0;
+
+	if (nps == EEPROM_RECORD_UMC_NPS_MODE(record)) {
+		record->cur_nps_pa_flip_mask = __get_nps_pa_flip_mask(ras_core, nps);
+		row_pfn = EEPROM_RECORD_UMC_ADDR_PFN(record);
+		record->cur_nps_retired_row_pfn =
+			RAS_ADDR_TO_PFN(RAS_PFN_TO_ADDR(row_pfn) | record->cur_nps_pa_flip_mask);
+	} else {
+		ret = convert_eeprom_record_to_nps_addr(ras_core,
+				record, &pa, &flip_mask, nps);
+		if (!ret) {
+			record->cur_nps_retired_row_pfn = RAS_ADDR_TO_PFN(pa);
+			record->cur_nps_pa_flip_mask = flip_mask;
+		}
+	}
+
+	record->cur_nps = nps;
+
+	return ret;
 }
 
 static int umc_12_0_soc_pa_to_bank(struct ras_core_context *ras_core,
@@ -527,7 +603,7 @@ static uint32_t umc_v12_0_get_die_id(uint64_t mca_addr, uint64_t pa)
 
 const struct ras_umc_ip_func ras_umc_func_v12_0 = {
 	.bank_to_eeprom_record = umc_v12_0_bank_to_eeprom_record,
-	.eeprom_record_to_nps_pages = umc_v12_0_eeprom_record_to_nps_pages,
+	.eeprom_record_to_nps_record = umc_v12_0_eeprom_record_to_nps_record,
 	.bank_to_soc_pa = umc_12_0_bank_to_soc_pa,
 	.soc_pa_to_bank = umc_12_0_soc_pa_to_bank,
 	.mca_ipid_parse = umc_v12_0_mca_ipid_parse,
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
index 39e95a5515f83..8f3bba2621f89 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc_v15_0.c
@@ -33,27 +33,19 @@ static void __get_nps_pa_flip_bits(struct ras_core_context *ras_core,
 
 }
 
-static uint64_t  convert_nps_pa_to_row_pa(struct ras_core_context *ras_core,
-	struct umc_phy_addr *pa, enum umc_memory_partition_mode nps, bool zero_pfn_ok)
+static uint64_t  __get_nps_pa_flip_mask(struct ras_core_context *ras_core,
+		enum umc_memory_partition_mode nps)
 {
 	struct umc_flip_bits flip_bits = {0};
-	uint64_t row_pa;
+	uint64_t flip_mask = 0;
 	int i;
 
-	if (pa->pa_flip_mask)
-		return zero_pfn_ok ? (pa->pa & ~pa->pa_flip_mask) : pa->pa;
-
 	__get_nps_pa_flip_bits(ras_core, nps, &flip_bits);
 
-	row_pa = pa->pa;
-	/* clear loop bits in soc physical address */
 	for (i = 0; i < flip_bits.bit_num; i++)
-		row_pa &= ~BIT_ULL(flip_bits.flip_bits_in_pa[i]);
-
-	if (!zero_pfn_ok && !RAS_ADDR_TO_PFN(row_pa))
-		row_pa |= BIT_ULL(flip_bits.flip_bits_in_pa[2]);
+		flip_mask |= BIT_ULL(flip_bits.flip_bits_in_pa[i]);
 
-	return row_pa;
+	return flip_mask;
 }
 
 static int lookup_bad_pages_in_a_row(struct ras_core_context *ras_core,
@@ -113,9 +105,8 @@ static int convert_bank_to_nps_addr(struct ras_core_context *ras_core,
 
 	ret = convert_ma_to_pa(ras_core, &addr_in, &addr_out, nps);
 	if (!ret) {
-		pa_addr->pa =
-			convert_nps_pa_to_row_pa(ras_core, &addr_out, nps, false);
 		pa_addr->pa_flip_mask = addr_out.pa_flip_mask;
+		pa_addr->pa = addr_out.pa | pa_addr->pa_flip_mask;
 		pa_addr->channel_idx = addr_out.channel_idx;
 		pa_addr->bank = addr_out.bank;
 	}
@@ -153,7 +144,7 @@ static int umc_v15_0_bank_to_eeprom_record(struct ras_core_context *ras_core,
 }
 
 static int convert_eeprom_record_to_nps_addr(struct ras_core_context *ras_core,
-			struct eeprom_umc_record *record, uint64_t *pa, uint32_t nps)
+	struct eeprom_umc_record *record, uint64_t *pa, uint64_t *pa_flip_mask, uint32_t nps)
 {
 	struct device_system_info dev_info = {0};
 	struct umc_mca_addr addr_in;
@@ -175,7 +166,8 @@ static int convert_eeprom_record_to_nps_addr(struct ras_core_context *ras_core,
 	if (ret)
 		return ret;
 
-	*pa = convert_nps_pa_to_row_pa(ras_core, &addr_out, nps, false);
+	*pa_flip_mask = addr_out.pa_flip_mask;
+	*pa = addr_out.pa | addr_out.pa_flip_mask;
 
 	return 0;
 }
@@ -183,16 +175,22 @@ static int convert_eeprom_record_to_nps_addr(struct ras_core_context *ras_core,
 static int umc_v15_0_eeprom_record_to_nps_record(struct ras_core_context *ras_core,
 				struct eeprom_umc_record *record, uint32_t nps)
 {
-	uint64_t pa = 0;
+	uint64_t pa = 0, flip_mask = 0;
+	uint64_t row_pfn;
 	int ret = 0;
 
 	if (nps == EEPROM_RECORD_UMC_NPS_MODE(record)) {
-		record->cur_nps_retired_row_pfn = EEPROM_RECORD_UMC_ADDR_PFN(record);
+		record->cur_nps_pa_flip_mask = __get_nps_pa_flip_mask(ras_core, nps);
+		row_pfn = EEPROM_RECORD_UMC_ADDR_PFN(record);
+		record->cur_nps_retired_row_pfn =
+			RAS_ADDR_TO_PFN(RAS_PFN_TO_ADDR(row_pfn) | record->cur_nps_pa_flip_mask);
 	} else {
 		ret = convert_eeprom_record_to_nps_addr(ras_core,
-				record, &pa, nps);
-		if (!ret)
+				record, &pa, &flip_mask, nps);
+		if (!ret) {
 			record->cur_nps_retired_row_pfn = RAS_ADDR_TO_PFN(pa);
+			record->cur_nps_pa_flip_mask = flip_mask;
+		}
 	}
 
 	record->cur_nps = nps;
@@ -200,14 +198,6 @@ static int umc_v15_0_eeprom_record_to_nps_record(struct ras_core_context *ras_co
 	return ret;
 }
 
-static int umc_v15_0_eeprom_record_to_nps_pages(struct ras_core_context *ras_core,
-			struct eeprom_umc_record *record, uint32_t nps,
-			uint64_t *pfns, uint32_t num)
-{
-	return lookup_bad_pages_in_a_row(ras_core,
-				record, nps, pfns, num, 0, false);
-}
-
 static int umc_v15_0_soc_pa_to_bank(struct ras_core_context *ras_core,
 			uint64_t soc_pa,
 			struct umc_bank_addr *bank_addr)
@@ -225,7 +215,6 @@ static int umc_v15_0_bank_to_soc_pa(struct ras_core_context *ras_core,
 const struct ras_umc_ip_func ras_umc_func_v15_0 = {
 	.bank_to_eeprom_record = umc_v15_0_bank_to_eeprom_record,
 	.eeprom_record_to_nps_record = umc_v15_0_eeprom_record_to_nps_record,
-	.eeprom_record_to_nps_pages = umc_v15_0_eeprom_record_to_nps_pages,
 	.bank_to_soc_pa = umc_v15_0_bank_to_soc_pa,
 	.soc_pa_to_bank = umc_v15_0_soc_pa_to_bank,
 };
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.