[PATCH 079/109] drm/amd/ras: introduce row page address buffer alloc/free interfaces

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

Introduce row page address buffer alloc/free interfaces.

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/cmd.h           |   2 +-
 drivers/gpu/drm/amd/ras/core/core.c          |  11 +-
 drivers/gpu/drm/amd/ras/core/ras_umc.c       | 137 ++++++++++++-------
 drivers/gpu/drm/amd/ras/core/ras_umc.h       |  11 +-
 drivers/gpu/drm/amd/ras/core/ras_umc_v12_0.c |   3 +
 5 files changed, 99 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/amd/ras/core/cmd.h b/drivers/gpu/drm/amd/ras/core/cmd.h
index 728fbe55d1765..a37b050e913ab 100644
--- a/drivers/gpu/drm/amd/ras/core/cmd.h
+++ b/drivers/gpu/drm/amd/ras/core/cmd.h
@@ -452,7 +452,7 @@ struct ras_cmd_convert_retired_address_req {
 	uint32_t reserved[6];
 };
 
-#define RAS_CMD_MAX_RETIRED_ADDR_COUNT  32
+#define RAS_CMD_MAX_RETIRED_ADDR_COUNT  128
 struct ras_cmd_convert_retired_address_rsp {
 	uint32_t version;
 	uint32_t retired_count;
diff --git a/drivers/gpu/drm/amd/ras/core/core.c b/drivers/gpu/drm/amd/ras/core/core.c
index 00dc6084454cd..71c7c54ddb7c8 100644
--- a/drivers/gpu/drm/amd/ras/core/core.c
+++ b/drivers/gpu/drm/amd/ras/core/core.c
@@ -700,23 +700,14 @@ int ras_core_convert_soc_pa_to_cur_nps_pages(struct ras_core_context *ras_core,
 		uint64_t soc_pa, uint64_t *page_pfn, uint32_t max_pages)
 {
 	struct eeprom_umc_record record;
-	uint32_t cur_nps_mode;
-	int count = 0;
 
 	if (!ras_core || !page_pfn || !max_pages)
 		return -EINVAL;
 
-	cur_nps_mode = ras_core_get_curr_nps_mode(ras_core);
-	if (!cur_nps_mode || cur_nps_mode > UMC_MEMORY_PARTITION_MODE_NPS8)
-		return -EINVAL;
-
 	memset(&record, 0, sizeof(record));
 	record.cur_nps_retired_row_pfn = RAS_ADDR_TO_PFN(soc_pa);
 
-	count = ras_umc_convert_record_to_nps_pages(ras_core,
-				&record, cur_nps_mode, page_pfn, max_pages);
-
-	return count;
+	return ras_umc_convert_record_to_row_pages(ras_core, &record, page_pfn, max_pages);
 }
 
 int ras_core_check_address_sanity(struct ras_core_context *ras_core,
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.c b/drivers/gpu/drm/amd/ras/core/ras_umc.c
index c30d11942a72b..299426d6d8318 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.c
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.c
@@ -70,11 +70,15 @@ static uint64_t ras_umc_get_eeprom_timestamp(struct ras_core_context *ras_core)
 static const struct ras_umc_ip_func *ras_umc_get_ip_func(
 				struct ras_core_context *ras_core, uint32_t ip_version)
 {
+	struct ras_umc *ras_umc = &ras_core->ras_umc;
+
 	switch (ip_version) {
 	case IP_VERSION(12, 0, 0):
 	case IP_VERSION(12, 5, 0):
+		ras_umc->max_pages_per_row = 16;
 		return &ras_umc_func_v12_0;
 	case IP_VERSION(15, 0, 0):
+		ras_umc->max_pages_per_row = 128;
 		return &ras_umc_func_v15_0;
 	default:
 		RAS_DEV_ERR(ras_core->dev,
@@ -177,6 +181,44 @@ int ras_umc_clear_logged_ecc(struct ras_core_context *ras_core)
 	return 0;
 }
 
+int ras_umc_alloc_row_pages(struct ras_core_context *ras_core,
+		uint64_t **page_pfns, uint32_t *nr_page_pfns)
+{
+	struct ras_umc *ras_umc = &ras_core->ras_umc;
+	uint64_t *address;
+	uint64_t page_num;
+
+	if (!page_pfns || !nr_page_pfns)
+		return -EINVAL;
+
+	if (!ras_umc->max_pages_per_row) {
+		RAS_DEV_ERR(ras_core->dev, "max_pages_per_row was not initialized!\n");
+		return -EPERM;
+	}
+
+	page_num = ras_umc->max_pages_per_row;
+
+	address = kcalloc(page_num, sizeof(*address), GFP_KERNEL);
+	if (!address)
+		return -ENOMEM;
+
+	*page_pfns = address;
+	*nr_page_pfns = page_num;
+
+	return 0;
+}
+
+int ras_umc_free_row_pages(struct ras_core_context *ras_core,
+		uint64_t *page_pfns)
+{
+	if (!page_pfns)
+		return -EINVAL;
+
+	kfree(page_pfns);
+
+	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)
 {
@@ -209,9 +251,8 @@ static int ras_umc_expand_row_pages(struct ras_core_context *ras_core,
 	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_pfns, uint32_t nr_page_pfns)
+int ras_umc_convert_record_to_row_pages(struct ras_core_context *ras_core,
+	struct eeprom_umc_record *record, uint64_t *page_pfns, uint32_t nr_page_pfns)
 {
 	uint32_t new_nps;
 	int ret, count = 0;
@@ -236,26 +277,21 @@ int ras_umc_convert_record_to_nps_pages(struct ras_core_context *ras_core,
 	return count;
 }
 
-static void ras_umc_reserve_eeprom_record(struct ras_core_context *ras_core,
-				struct eeprom_umc_record *record)
+static void ras_umc_reserve_row_pages(struct ras_core_context *ras_core,
+	struct eeprom_umc_record *record, uint64_t *pages, uint32_t nr_pages)
 {
-	uint64_t page_pfn[16];
-	int count = 0, i;
+	struct ras_umc *ras_umc = &ras_core->ras_umc;
+	int i;
 
-	memset(page_pfn, 0, sizeof(page_pfn));
-	count = ras_umc_convert_record_to_nps_pages(ras_core,
-					record, record->cur_nps, page_pfn, ARRAY_SIZE(page_pfn));
-	if (count <= 0) {
-		RAS_DEV_ERR(ras_core->dev,
-			"Fail to convert error address! count:%d\n", count);
+	if (!pages || !nr_pages ||
+		(nr_pages > ras_umc->max_pages_per_row))
 		return;
-	}
 
 	/* Reserve memory */
-	for (i = 0; i < count; i++)
+	for (i = 0; i < nr_pages; i++)
 		ras_core_event_notify(ras_core, ras_core_in_early_init(ras_core) ?
 			RAS_EVENT_ID__EARLY_INIT_RESERVE_PAGE : RAS_EVENT_ID__RESERVE_BAD_PAGE,
-			&page_pfn[i]);
+			&pages[i]);
 }
 
 /* When gpu reset is ongoing, ecc logging operations will be pended.
@@ -614,44 +650,25 @@ static int ras_umc_update_eeprom_rom_data(struct ras_core_context *ras_core,
 }
 
 static int ras_umc_update_eeprom_ram_data(struct ras_core_context *ras_core,
-				struct eeprom_umc_record *bps)
+		struct eeprom_umc_record *bps, uint64_t *page_pfns, uint32_t nr_page_pfns)
 {
 	struct ras_umc *ras_umc = &ras_core->ras_umc;
 	struct eeprom_store_record *data = &ras_umc->umc_err_data.ram_data;
-	uint64_t page_pfn[16];
-	int count = 0, i, j;
+	int j;
+
+	if (!bps || !page_pfns || !nr_page_pfns ||
+		(nr_page_pfns > ras_umc->max_pages_per_row))
+		return -EINVAL;
 
 	if (!data->space_left &&
-		ras_umc_realloc_err_data_space(ras_core, data, 256)) {
-		return	-ENOMEM;
-	}
+		ras_umc_realloc_err_data_space(ras_core, data, 256))
+		return -ENOMEM;
 
-	memset(page_pfn, 0, sizeof(page_pfn));
-	count = ras_umc_convert_record_to_nps_pages(ras_core,
-					bps, bps->cur_nps, page_pfn, ARRAY_SIZE(page_pfn));
-	if (count > 0) {
-		for (j = 0; j < count; j++) {
-			if (ras_core_check_address_sanity(ras_core,
-				page_pfn[j] << AMDGPU_GPU_PAGE_SHIFT)) {
-
-				for (i = 0; i < data->count; i++)
-					if (page_pfn[j] == data->bps[i].cur_nps_retired_row_pfn)
-						break;
-				data->bps[data->count].cur_nps_retired_row_pfn = U64_MAX;
-				data->count++;
-				data->space_left--;
-				continue;
-			}
-
-			bps->cur_nps_retired_row_pfn = page_pfn[j];
-			memcpy(&data->bps[data->count], bps, sizeof(*data->bps));
-			data->count++;
-			data->space_left--;
-			data->bad_page_num++;
-		}
-	} else {
-		RAS_DEV_ERR(ras_core->dev, "Failed to convert record to nps pages!");
-		return -EINVAL;
+	for (j = 0; j < nr_page_pfns; j++) {
+		bps->cur_nps_retired_row_pfn = page_pfns[j];
+		memcpy(&data->bps[data->count], bps, sizeof(*data->bps));
+		data->count++;
+		data->space_left--;
 	}
 
 	/* update bad channel bitmap */
@@ -694,17 +711,33 @@ int ras_umc_add_bad_pages(struct ras_core_context *ras_core,
 	struct eeprom_umc_record *bps, uint32_t bps_sz, uint32_t *valid_sz)
 {
 	struct ras_umc *ras_umc = &ras_core->ras_umc;
+	uint64_t *page_pfns = NULL;
+	uint32_t nr_page_pfns = 0;
+	int nr_valid_pfns = 0;
 	uint32_t i, c = 0;
 	int ret = 0;
 
 	if (!bps || !bps_sz || !valid_sz)
 		return -EINVAL;
 
+	ret = ras_umc_alloc_row_pages(ras_core, &page_pfns, &nr_page_pfns);
+	if (ret)
+		return ret;
+
 	mutex_lock(&ras_umc->umc_lock);
 	for (i = 0; i < bps_sz; i++) {
 		if (ras_umc_check_retired_record(ras_core, &bps[i]))
 			continue;
 
+		nr_valid_pfns = ras_umc_convert_record_to_row_pages(ras_core,
+					&bps[i], page_pfns, nr_page_pfns);
+		if (nr_valid_pfns < 0) {
+			RAS_DEV_ERR(ras_core->dev,
+				"Failed to lookup record bad pages! %d\n", nr_valid_pfns);
+			ret = nr_valid_pfns;
+			goto out;
+		}
+
 		ret = ras_umc_update_eeprom_rom_data(ras_core, &bps[i]);
 		if (ret)
 			goto out;
@@ -713,9 +746,11 @@ int ras_umc_add_bad_pages(struct ras_core_context *ras_core,
 		if (ret)
 			goto out;
 
-		ras_umc_reserve_eeprom_record(ras_core, &bps[i]);
+		ras_umc_reserve_row_pages(ras_core,
+			&bps[i], page_pfns, nr_valid_pfns);
 
-		ret = ras_umc_update_eeprom_ram_data(ras_core, &bps[i]);
+		ret = ras_umc_update_eeprom_ram_data(ras_core,
+				&bps[i], page_pfns, nr_valid_pfns);
 		if (ret)
 			goto out;
 		c++;
@@ -731,7 +766,7 @@ int ras_umc_add_bad_pages(struct ras_core_context *ras_core,
 
 out:
 	mutex_unlock(&ras_umc->umc_lock);
-
+	ras_umc_free_row_pages(ras_core, page_pfns);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/amd/ras/core/ras_umc.h b/drivers/gpu/drm/amd/ras/core/ras_umc.h
index b52480ba886b8..362c9ce6a404b 100644
--- a/drivers/gpu/drm/amd/ras/core/ras_umc.h
+++ b/drivers/gpu/drm/amd/ras/core/ras_umc.h
@@ -183,6 +183,8 @@ struct ras_umc {
 
 	u32 last_record_count;
 	u64 last_channel_bitmap;
+
+	u32 max_pages_per_row;
 };
 
 /*
@@ -222,9 +224,8 @@ int ras_umc_get_badpage_record(struct ras_core_context *ras_core, uint32_t index
 bool ras_umc_check_retired_addr(struct ras_core_context *ras_core, uint64_t addr);
 int ras_umc_translate_soc_pa_and_bank(struct ras_core_context *ras_core,
 			uint64_t *soc_pa, struct umc_bank_addr *bank_addr, bool bank_to_pa);
-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);
+int ras_umc_convert_record_to_row_pages(struct ras_core_context *ras_core,
+	struct eeprom_umc_record *record, uint64_t *page_addrs, uint32_t nr_page_addrs);
 uint32_t ras_umc_bit_wise_xor(uint32_t val);
 int ras_umc_ma2pa(struct ras_core_context *ras_core,
 	struct umc_mca_addr *addr_in, struct umc_phy_addr *addr_out,
@@ -235,4 +236,8 @@ int ras_umc_record_to_nps_record(struct ras_core_context *ras_core,
 		struct eeprom_umc_record *record,  uint32_t nps);
 int ras_umc_dump_fw_records(struct ras_core_context *ras_core);
 void ras_umc_report_badpage_info(struct ras_core_context *ras_core);
+int ras_umc_alloc_row_pages(struct ras_core_context *ras_core,
+		uint64_t **page_pfns, uint32_t *nr_page_pfns);
+int ras_umc_free_row_pages(struct ras_core_context *ras_core,
+		uint64_t *page_pfns);
 #endif
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 37fa24acddd02..c637ad9314103 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
@@ -473,6 +473,9 @@ static int umc_v12_0_eeprom_record_to_nps_record(struct ras_core_context *ras_co
 	uint64_t row_pfn;
 	int ret = 0;
 
+	if (!record || !nps)
+		return -EINVAL;
+
 	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);
-- 
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.