All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] drm/amdgpu: fix the issue of reserving bad pages failed
@ 2020-10-27  9:05 Dennis Li
  2020-10-27  9:47 ` Christian König
  0 siblings, 1 reply; 2+ messages in thread
From: Dennis Li @ 2020-10-27  9:05 UTC (permalink / raw)
  To: amd-gfx, Alexander.Deucher, felix.kuehling, Hawking.Zhang,
	christian.koenig
  Cc: Wenhui Sheng, Dennis Li

In amdgpu_ras_reset_gpu, because bad pages may not be freed,
it has high probability to reserve bad pages failed.

Change to reserve bad pages when freeing VRAM.

v2:
1. avoid allocating the drm_mm node outside of amdgpu_vram_mgr.c
2. move bad page reserving into amdgpu_ras_add_bad_pages, if vram mgr
   reserve bad page failed, it will put it into pending list, otherwise
   put it into processed list;
3. remove amdgpu_ras_release_bad_pages, because retired page's info has
   been moved into amdgpu_vram_mgr

v3:
1. formate code style;
2. rename amdgpu_vram_reserve_scope as amdgpu_vram_reservation;
3. rename scope_pending as reservations_pending;
4. rename scope_processed as reserved_pages;
5. change to iterate over all the pending ones and try to insert them
   with drm_mm_reserve_node();

v4:
1. rename amdgpu_vram_mgr_reserve_scope as
amdgpu_vram_mgr_reserve_range;
2. remove unused include "amdgpu_ras.h";
3. rename amdgpu_vram_mgr_check_and_reserve as
amdgpu_vram_mgr_do_reserve;
4. refine amdgpu_vram_mgr_reserve_range to call
amdgpu_vram_mgr_do_reserve.

Signed-off-by: Dennis Li <Dennis.Li@amd.com>
Signed-off-by: Wenhui Sheng <Wenhui.Sheng@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c      | 150 +++++--------------
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h      |   8 -
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h      |   4 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 115 ++++++++++++++
 4 files changed, 158 insertions(+), 119 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index 0f57a0003df6..84bb55ab6ac5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -80,6 +80,8 @@ enum amdgpu_ras_retire_page_reservation {
 
 atomic_t amdgpu_ras_in_intr = ATOMIC_INIT(0);
 
+static bool amdgpu_ras_check_bad_page_unlock(struct amdgpu_ras *con,
+				uint64_t addr);
 static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev,
 				uint64_t addr);
 
@@ -1573,10 +1575,12 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
 			.size = AMDGPU_GPU_PAGE_SIZE,
 			.flags = AMDGPU_RAS_RETIRE_PAGE_RESERVED,
 		};
-
-		if (data->last_reserved <= i)
+		ret = amdgpu_vram_mgr_query_page_status(
+				&adev->mman.bdev.man[TTM_PL_VRAM],
+				data->bps[i].retired_page);
+		if (ret == -EBUSY)
 			(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING;
-		else if (data->bps_bo[i] == NULL)
+		else if (ret == -ENOENT)
 			(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_FAULT;
 	}
 
@@ -1628,12 +1632,9 @@ static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev,
 	unsigned int new_space = old_space + pages;
 	unsigned int align_space = ALIGN(new_space, 512);
 	void *bps = kmalloc(align_space * sizeof(*data->bps), GFP_KERNEL);
-	struct amdgpu_bo **bps_bo =
-			kmalloc(align_space * sizeof(*data->bps_bo), GFP_KERNEL);
 
-	if (!bps || !bps_bo) {
+	if (!bps) {
 		kfree(bps);
-		kfree(bps_bo);
 		return -ENOMEM;
 	}
 
@@ -1642,14 +1643,8 @@ static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev,
 				data->count * sizeof(*data->bps));
 		kfree(data->bps);
 	}
-	if (data->bps_bo) {
-		memcpy(bps_bo, data->bps_bo,
-				data->count * sizeof(*data->bps_bo));
-		kfree(data->bps_bo);
-	}
 
 	data->bps = bps;
-	data->bps_bo = bps_bo;
 	data->space_left += align_space - old_space;
 	return 0;
 }
@@ -1661,6 +1656,7 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
 	struct ras_err_handler_data *data;
 	int ret = 0;
+	uint32_t i;
 
 	if (!con || !con->eh_data || !bps || pages <= 0)
 		return 0;
@@ -1670,16 +1666,26 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
 	if (!data)
 		goto out;
 
-	if (data->space_left <= pages)
-		if (amdgpu_ras_realloc_eh_data_space(adev, data, pages)) {
+	for (i = 0; i < pages; i++) {
+		if (amdgpu_ras_check_bad_page_unlock(con,
+			bps[i].retired_page << AMDGPU_GPU_PAGE_SHIFT))
+			continue;
+
+		if (!data->space_left &&
+			amdgpu_ras_realloc_eh_data_space(adev, data, 256)) {
 			ret = -ENOMEM;
 			goto out;
 		}
 
-	memcpy(&data->bps[data->count], bps, pages * sizeof(*data->bps));
-	data->count += pages;
-	data->space_left -= pages;
+		amdgpu_vram_mgr_reserve_range(
+			&adev->mman.bdev.man[TTM_PL_VRAM],
+			bps[i].retired_page << AMDGPU_GPU_PAGE_SHIFT,
+			AMDGPU_GPU_PAGE_SIZE);
 
+		memcpy(&data->bps[data->count], &bps[i], sizeof(*data->bps));
+		data->count++;
+		data->space_left--;
+	}
 out:
 	mutex_unlock(&con->recovery_lock);
 
@@ -1752,6 +1758,20 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev)
 	return ret;
 }
 
+static bool amdgpu_ras_check_bad_page_unlock(struct amdgpu_ras *con,
+				uint64_t addr)
+{
+	struct ras_err_handler_data *data = con->eh_data;
+	int i;
+
+	addr >>= AMDGPU_GPU_PAGE_SHIFT;
+	for (i = 0; i < data->count; i++)
+		if (addr == data->bps[i].retired_page)
+			return true;
+
+	return false;
+}
+
 /*
  * check if an address belongs to bad page
  *
@@ -1761,26 +1781,13 @@ static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev,
 				uint64_t addr)
 {
 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
-	struct ras_err_handler_data *data;
-	int i;
 	bool ret = false;
 
 	if (!con || !con->eh_data)
 		return ret;
 
 	mutex_lock(&con->recovery_lock);
-	data = con->eh_data;
-	if (!data)
-		goto out;
-
-	addr >>= AMDGPU_GPU_PAGE_SHIFT;
-	for (i = 0; i < data->count; i++)
-		if (addr == data->bps[i].retired_page) {
-			ret = true;
-			goto out;
-		}
-
-out:
+	ret = amdgpu_ras_check_bad_page_unlock(con, addr);
 	mutex_unlock(&con->recovery_lock);
 	return ret;
 }
@@ -1826,77 +1833,6 @@ static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev,
 	}
 }
 
-/* called in gpu recovery/init */
-int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev)
-{
-	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
-	struct ras_err_handler_data *data;
-	uint64_t bp;
-	struct amdgpu_bo *bo = NULL;
-	int i, ret = 0;
-
-	/* Not reserve bad page when amdgpu_bad_page_threshold == 0. */
-	if (!con || !con->eh_data || (amdgpu_bad_page_threshold == 0))
-		return 0;
-
-	mutex_lock(&con->recovery_lock);
-	data = con->eh_data;
-	if (!data)
-		goto out;
-	/* reserve vram at driver post stage. */
-	for (i = data->last_reserved; i < data->count; i++) {
-		bp = data->bps[i].retired_page;
-
-		/* There are two cases of reserve error should be ignored:
-		 * 1) a ras bad page has been allocated (used by someone);
-		 * 2) a ras bad page has been reserved (duplicate error injection
-		 *    for one page);
-		 */
-		if (amdgpu_bo_create_kernel_at(adev, bp << AMDGPU_GPU_PAGE_SHIFT,
-					       AMDGPU_GPU_PAGE_SIZE,
-					       AMDGPU_GEM_DOMAIN_VRAM,
-					       &bo, NULL))
-			dev_warn(adev->dev, "RAS WARN: reserve vram for "
-					"retired page %llx fail\n", bp);
-
-		data->bps_bo[i] = bo;
-		data->last_reserved = i + 1;
-		bo = NULL;
-	}
-out:
-	mutex_unlock(&con->recovery_lock);
-	return ret;
-}
-
-/* called when driver unload */
-static int amdgpu_ras_release_bad_pages(struct amdgpu_device *adev)
-{
-	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
-	struct ras_err_handler_data *data;
-	struct amdgpu_bo *bo;
-	int i;
-
-	if (!con || !con->eh_data)
-		return 0;
-
-	mutex_lock(&con->recovery_lock);
-	data = con->eh_data;
-	if (!data)
-		goto out;
-
-	for (i = data->last_reserved - 1; i >= 0; i--) {
-		bo = data->bps_bo[i];
-
-		amdgpu_bo_free_kernel(&bo, NULL, NULL);
-
-		data->bps_bo[i] = bo;
-		data->last_reserved = i;
-	}
-out:
-	mutex_unlock(&con->recovery_lock);
-	return 0;
-}
-
 int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
 {
 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
@@ -1936,18 +1872,12 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
 		ret = amdgpu_ras_load_bad_pages(adev);
 		if (ret)
 			goto free;
-		ret = amdgpu_ras_reserve_bad_pages(adev);
-		if (ret)
-			goto release;
 	}
 
 	return 0;
 
-release:
-	amdgpu_ras_release_bad_pages(adev);
 free:
 	kfree((*data)->bps);
-	kfree((*data)->bps_bo);
 	kfree(*data);
 	con->eh_data = NULL;
 out:
@@ -1975,12 +1905,10 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev)
 		return 0;
 
 	cancel_work_sync(&con->recovery_work);
-	amdgpu_ras_release_bad_pages(adev);
 
 	mutex_lock(&con->recovery_lock);
 	con->eh_data = NULL;
 	kfree(data->bps);
-	kfree(data->bps_bo);
 	kfree(data);
 	mutex_unlock(&con->recovery_lock);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index 7c39d706e6d1..4667cce38582 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -362,14 +362,10 @@ struct ras_err_data {
 struct ras_err_handler_data {
 	/* point to bad page records array */
 	struct eeprom_table_record *bps;
-	/* point to reserved bo array */
-	struct amdgpu_bo **bps_bo;
 	/* the count of entries */
 	int count;
 	/* the space can place new entries */
 	int space_left;
-	/* last reserved entry's index + 1 */
-	int last_reserved;
 };
 
 typedef int (*ras_ih_cb)(struct amdgpu_device *adev,
@@ -506,15 +502,11 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
 		struct eeprom_table_record *bps, int pages);
 
 int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev);
-int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev);
 
 static inline int amdgpu_ras_reset_gpu(struct amdgpu_device *adev)
 {
 	struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
 
-	if (in_task())
-		amdgpu_ras_reserve_bad_pages(adev);
-
 	if (atomic_cmpxchg(&ras->in_recovery, 0, 1) == 0)
 		schedule_work(&ras->recovery_work);
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index de37ceff0e56..90a3ed682466 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -103,6 +103,10 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
 			      struct sg_table *sgt);
 uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man);
 uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man);
+int amdgpu_vram_mgr_reserve_range(struct ttm_mem_type_manager *man,
+				  uint64_t start, uint64_t size);
+int amdgpu_vram_mgr_query_page_status(struct ttm_mem_type_manager *man,
+				      uint64_t start);
 
 int amdgpu_ttm_init(struct amdgpu_device *adev);
 void amdgpu_ttm_late_init(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 91098a385ed6..db573e77e216 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -28,9 +28,16 @@
 #include "amdgpu_atomfirmware.h"
 #include "atom.h"
 
+struct amdgpu_vram_reservation {
+	struct list_head node;
+	struct drm_mm_node mm_node;
+};
+
 struct amdgpu_vram_mgr {
 	struct drm_mm mm;
 	spinlock_t lock;
+	struct list_head reservations_pending;
+	struct list_head reserved_pages;
 	atomic64_t usage;
 	atomic64_t vis_usage;
 };
@@ -179,6 +186,8 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
 
 	drm_mm_init(&mgr->mm, 0, p_size);
 	spin_lock_init(&mgr->lock);
+	INIT_LIST_HEAD(&mgr->reservations_pending);
+	INIT_LIST_HEAD(&mgr->reserved_pages);
 	man->priv = mgr;
 
 	/* Add the two VRAM-related sysfs files */
@@ -201,8 +210,18 @@ static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
 {
 	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
 	struct amdgpu_vram_mgr *mgr = man->priv;
+	struct amdgpu_vram_reservation *rsv, *temp;
 
 	spin_lock(&mgr->lock);
+
+	list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
+		kfree(rsv);
+
+	list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
+		drm_mm_remove_node(&rsv->mm_node);
+		kfree(rsv);
+	}
+
 	drm_mm_takedown(&mgr->mm);
 	spin_unlock(&mgr->lock);
 	kfree(mgr);
@@ -260,6 +279,101 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 	return usage;
 }
 
+static void amdgpu_vram_mgr_do_reserve(struct ttm_mem_type_manager *man)
+{
+	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
+	struct amdgpu_vram_mgr *mgr = man->priv;
+	struct drm_mm *mm = &mgr->mm;
+	struct amdgpu_vram_reservation *rsv, *temp;
+	uint64_t vis_usage;
+
+	list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
+		if (drm_mm_reserve_node(mm, &rsv->mm_node))
+			continue;
+
+		dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Successed\n",
+			rsv->mm_node.start, rsv->mm_node.size);
+
+		vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
+		atomic64_add(vis_usage, &mgr->vis_usage);
+		atomic64_add(rsv->mm_node.size << PAGE_SHIFT, &mgr->usage);
+		list_move(&rsv->node, &mgr->reserved_pages);
+	}
+}
+
+/**
+ * amdgpu_vram_mgr_reserve_range - Reserve a range from VRAM
+ *
+ * @man: TTM memory type manager
+ * @start: start address of the range in VRAM
+ * @size: size of the range
+ *
+ * Reserve memory from start addess with the specified size in VRAM
+ */
+int amdgpu_vram_mgr_reserve_range(struct ttm_mem_type_manager *man,
+				  uint64_t start, uint64_t size)
+{
+	struct amdgpu_vram_mgr *mgr = man->priv;
+	struct amdgpu_vram_reservation *rsv;
+
+	rsv = kzalloc(sizeof(*rsv), GFP_KERNEL);
+	if (!rsv)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&rsv->node);
+	rsv->mm_node.start = start >> PAGE_SHIFT;
+	rsv->mm_node.size = size >> PAGE_SHIFT;
+
+	spin_lock(&mgr->lock);
+	list_add_tail(&mgr->reservations_pending, &rsv->node);
+	amdgpu_vram_mgr_do_reserve(man);
+	spin_unlock(&mgr->lock);
+
+	return 0;
+}
+
+/**
+ * amdgpu_vram_mgr_query_page_status - query the reservation status
+ *
+ * @man: TTM memory type manager
+ * @start: start address of a page in VRAM
+ *
+ * Returns:
+ *	-EBUSY: the page is still hold and in pending list
+ *	0: the page has been reserved
+ *	-ENOENT: the input page is not a reservation
+ */
+int amdgpu_vram_mgr_query_page_status(struct ttm_mem_type_manager *man,
+				      uint64_t start)
+{
+	struct amdgpu_vram_mgr *mgr = man->priv;
+	struct amdgpu_vram_reservation *rsv;
+	int ret;
+
+	spin_lock(&mgr->lock);
+
+	list_for_each_entry(rsv, &mgr->reservations_pending, node) {
+		if ((rsv->mm_node.start <= start) &&
+		    (start < (rsv->mm_node.start + rsv->mm_node.size))) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	list_for_each_entry(rsv, &mgr->reserved_pages, node) {
+		if ((rsv->mm_node.start <= start) &&
+		    (start < (rsv->mm_node.start + rsv->mm_node.size))) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	ret = -ENOENT;
+out:
+	spin_unlock(&mgr->lock);
+	return ret;
+}
+
 /**
  * amdgpu_vram_mgr_virt_start - update virtual start address
  *
@@ -430,6 +544,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
 		vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
 		++nodes;
 	}
+	amdgpu_vram_mgr_do_reserve(man);
 	spin_unlock(&mgr->lock);
 
 	atomic64_sub(usage, &mgr->usage);
-- 
2.17.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 3/3] drm/amdgpu: fix the issue of reserving bad pages failed
  2020-10-27  9:05 [PATCH 3/3] drm/amdgpu: fix the issue of reserving bad pages failed Dennis Li
@ 2020-10-27  9:47 ` Christian König
  0 siblings, 0 replies; 2+ messages in thread
From: Christian König @ 2020-10-27  9:47 UTC (permalink / raw)
  To: Dennis Li, amd-gfx, Alexander.Deucher, felix.kuehling, Hawking.Zhang
  Cc: Wenhui Sheng

Am 27.10.20 um 10:05 schrieb Dennis Li:
> In amdgpu_ras_reset_gpu, because bad pages may not be freed,
> it has high probability to reserve bad pages failed.
>
> Change to reserve bad pages when freeing VRAM.
>
> v2:
> 1. avoid allocating the drm_mm node outside of amdgpu_vram_mgr.c
> 2. move bad page reserving into amdgpu_ras_add_bad_pages, if vram mgr
>     reserve bad page failed, it will put it into pending list, otherwise
>     put it into processed list;
> 3. remove amdgpu_ras_release_bad_pages, because retired page's info has
>     been moved into amdgpu_vram_mgr
>
> v3:
> 1. formate code style;
> 2. rename amdgpu_vram_reserve_scope as amdgpu_vram_reservation;
> 3. rename scope_pending as reservations_pending;
> 4. rename scope_processed as reserved_pages;
> 5. change to iterate over all the pending ones and try to insert them
>     with drm_mm_reserve_node();
>
> v4:
> 1. rename amdgpu_vram_mgr_reserve_scope as
> amdgpu_vram_mgr_reserve_range;
> 2. remove unused include "amdgpu_ras.h";
> 3. rename amdgpu_vram_mgr_check_and_reserve as
> amdgpu_vram_mgr_do_reserve;
> 4. refine amdgpu_vram_mgr_reserve_range to call
> amdgpu_vram_mgr_do_reserve.
>
> Signed-off-by: Dennis Li <Dennis.Li@amd.com>
> Signed-off-by: Wenhui Sheng <Wenhui.Sheng@amd.com>

I don't know the RAS code vell enough to judge, but at least the 
vram_mgr part is Reviewed-by: Christian König <christian.koenig@amd.com>

> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c      | 150 +++++--------------
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h      |   8 -
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h      |   4 +
>   drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 115 ++++++++++++++
>   4 files changed, 158 insertions(+), 119 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> index 0f57a0003df6..84bb55ab6ac5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> @@ -80,6 +80,8 @@ enum amdgpu_ras_retire_page_reservation {
>   
>   atomic_t amdgpu_ras_in_intr = ATOMIC_INIT(0);
>   
> +static bool amdgpu_ras_check_bad_page_unlock(struct amdgpu_ras *con,
> +				uint64_t addr);
>   static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev,
>   				uint64_t addr);
>   
> @@ -1573,10 +1575,12 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev,
>   			.size = AMDGPU_GPU_PAGE_SIZE,
>   			.flags = AMDGPU_RAS_RETIRE_PAGE_RESERVED,
>   		};
> -
> -		if (data->last_reserved <= i)
> +		ret = amdgpu_vram_mgr_query_page_status(
> +				&adev->mman.bdev.man[TTM_PL_VRAM],
> +				data->bps[i].retired_page);
> +		if (ret == -EBUSY)
>   			(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING;
> -		else if (data->bps_bo[i] == NULL)
> +		else if (ret == -ENOENT)
>   			(*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_FAULT;
>   	}
>   
> @@ -1628,12 +1632,9 @@ static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev,
>   	unsigned int new_space = old_space + pages;
>   	unsigned int align_space = ALIGN(new_space, 512);
>   	void *bps = kmalloc(align_space * sizeof(*data->bps), GFP_KERNEL);
> -	struct amdgpu_bo **bps_bo =
> -			kmalloc(align_space * sizeof(*data->bps_bo), GFP_KERNEL);
>   
> -	if (!bps || !bps_bo) {
> +	if (!bps) {
>   		kfree(bps);
> -		kfree(bps_bo);
>   		return -ENOMEM;
>   	}
>   
> @@ -1642,14 +1643,8 @@ static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev,
>   				data->count * sizeof(*data->bps));
>   		kfree(data->bps);
>   	}
> -	if (data->bps_bo) {
> -		memcpy(bps_bo, data->bps_bo,
> -				data->count * sizeof(*data->bps_bo));
> -		kfree(data->bps_bo);
> -	}
>   
>   	data->bps = bps;
> -	data->bps_bo = bps_bo;
>   	data->space_left += align_space - old_space;
>   	return 0;
>   }
> @@ -1661,6 +1656,7 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
>   	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
>   	struct ras_err_handler_data *data;
>   	int ret = 0;
> +	uint32_t i;
>   
>   	if (!con || !con->eh_data || !bps || pages <= 0)
>   		return 0;
> @@ -1670,16 +1666,26 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
>   	if (!data)
>   		goto out;
>   
> -	if (data->space_left <= pages)
> -		if (amdgpu_ras_realloc_eh_data_space(adev, data, pages)) {
> +	for (i = 0; i < pages; i++) {
> +		if (amdgpu_ras_check_bad_page_unlock(con,
> +			bps[i].retired_page << AMDGPU_GPU_PAGE_SHIFT))
> +			continue;
> +
> +		if (!data->space_left &&
> +			amdgpu_ras_realloc_eh_data_space(adev, data, 256)) {
>   			ret = -ENOMEM;
>   			goto out;
>   		}
>   
> -	memcpy(&data->bps[data->count], bps, pages * sizeof(*data->bps));
> -	data->count += pages;
> -	data->space_left -= pages;
> +		amdgpu_vram_mgr_reserve_range(
> +			&adev->mman.bdev.man[TTM_PL_VRAM],
> +			bps[i].retired_page << AMDGPU_GPU_PAGE_SHIFT,
> +			AMDGPU_GPU_PAGE_SIZE);
>   
> +		memcpy(&data->bps[data->count], &bps[i], sizeof(*data->bps));
> +		data->count++;
> +		data->space_left--;
> +	}
>   out:
>   	mutex_unlock(&con->recovery_lock);
>   
> @@ -1752,6 +1758,20 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev)
>   	return ret;
>   }
>   
> +static bool amdgpu_ras_check_bad_page_unlock(struct amdgpu_ras *con,
> +				uint64_t addr)
> +{
> +	struct ras_err_handler_data *data = con->eh_data;
> +	int i;
> +
> +	addr >>= AMDGPU_GPU_PAGE_SHIFT;
> +	for (i = 0; i < data->count; i++)
> +		if (addr == data->bps[i].retired_page)
> +			return true;
> +
> +	return false;
> +}
> +
>   /*
>    * check if an address belongs to bad page
>    *
> @@ -1761,26 +1781,13 @@ static bool amdgpu_ras_check_bad_page(struct amdgpu_device *adev,
>   				uint64_t addr)
>   {
>   	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
> -	struct ras_err_handler_data *data;
> -	int i;
>   	bool ret = false;
>   
>   	if (!con || !con->eh_data)
>   		return ret;
>   
>   	mutex_lock(&con->recovery_lock);
> -	data = con->eh_data;
> -	if (!data)
> -		goto out;
> -
> -	addr >>= AMDGPU_GPU_PAGE_SHIFT;
> -	for (i = 0; i < data->count; i++)
> -		if (addr == data->bps[i].retired_page) {
> -			ret = true;
> -			goto out;
> -		}
> -
> -out:
> +	ret = amdgpu_ras_check_bad_page_unlock(con, addr);
>   	mutex_unlock(&con->recovery_lock);
>   	return ret;
>   }
> @@ -1826,77 +1833,6 @@ static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev,
>   	}
>   }
>   
> -/* called in gpu recovery/init */
> -int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev)
> -{
> -	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
> -	struct ras_err_handler_data *data;
> -	uint64_t bp;
> -	struct amdgpu_bo *bo = NULL;
> -	int i, ret = 0;
> -
> -	/* Not reserve bad page when amdgpu_bad_page_threshold == 0. */
> -	if (!con || !con->eh_data || (amdgpu_bad_page_threshold == 0))
> -		return 0;
> -
> -	mutex_lock(&con->recovery_lock);
> -	data = con->eh_data;
> -	if (!data)
> -		goto out;
> -	/* reserve vram at driver post stage. */
> -	for (i = data->last_reserved; i < data->count; i++) {
> -		bp = data->bps[i].retired_page;
> -
> -		/* There are two cases of reserve error should be ignored:
> -		 * 1) a ras bad page has been allocated (used by someone);
> -		 * 2) a ras bad page has been reserved (duplicate error injection
> -		 *    for one page);
> -		 */
> -		if (amdgpu_bo_create_kernel_at(adev, bp << AMDGPU_GPU_PAGE_SHIFT,
> -					       AMDGPU_GPU_PAGE_SIZE,
> -					       AMDGPU_GEM_DOMAIN_VRAM,
> -					       &bo, NULL))
> -			dev_warn(adev->dev, "RAS WARN: reserve vram for "
> -					"retired page %llx fail\n", bp);
> -
> -		data->bps_bo[i] = bo;
> -		data->last_reserved = i + 1;
> -		bo = NULL;
> -	}
> -out:
> -	mutex_unlock(&con->recovery_lock);
> -	return ret;
> -}
> -
> -/* called when driver unload */
> -static int amdgpu_ras_release_bad_pages(struct amdgpu_device *adev)
> -{
> -	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
> -	struct ras_err_handler_data *data;
> -	struct amdgpu_bo *bo;
> -	int i;
> -
> -	if (!con || !con->eh_data)
> -		return 0;
> -
> -	mutex_lock(&con->recovery_lock);
> -	data = con->eh_data;
> -	if (!data)
> -		goto out;
> -
> -	for (i = data->last_reserved - 1; i >= 0; i--) {
> -		bo = data->bps_bo[i];
> -
> -		amdgpu_bo_free_kernel(&bo, NULL, NULL);
> -
> -		data->bps_bo[i] = bo;
> -		data->last_reserved = i;
> -	}
> -out:
> -	mutex_unlock(&con->recovery_lock);
> -	return 0;
> -}
> -
>   int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
>   {
>   	struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
> @@ -1936,18 +1872,12 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
>   		ret = amdgpu_ras_load_bad_pages(adev);
>   		if (ret)
>   			goto free;
> -		ret = amdgpu_ras_reserve_bad_pages(adev);
> -		if (ret)
> -			goto release;
>   	}
>   
>   	return 0;
>   
> -release:
> -	amdgpu_ras_release_bad_pages(adev);
>   free:
>   	kfree((*data)->bps);
> -	kfree((*data)->bps_bo);
>   	kfree(*data);
>   	con->eh_data = NULL;
>   out:
> @@ -1975,12 +1905,10 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev)
>   		return 0;
>   
>   	cancel_work_sync(&con->recovery_work);
> -	amdgpu_ras_release_bad_pages(adev);
>   
>   	mutex_lock(&con->recovery_lock);
>   	con->eh_data = NULL;
>   	kfree(data->bps);
> -	kfree(data->bps_bo);
>   	kfree(data);
>   	mutex_unlock(&con->recovery_lock);
>   
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> index 7c39d706e6d1..4667cce38582 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> @@ -362,14 +362,10 @@ struct ras_err_data {
>   struct ras_err_handler_data {
>   	/* point to bad page records array */
>   	struct eeprom_table_record *bps;
> -	/* point to reserved bo array */
> -	struct amdgpu_bo **bps_bo;
>   	/* the count of entries */
>   	int count;
>   	/* the space can place new entries */
>   	int space_left;
> -	/* last reserved entry's index + 1 */
> -	int last_reserved;
>   };
>   
>   typedef int (*ras_ih_cb)(struct amdgpu_device *adev,
> @@ -506,15 +502,11 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
>   		struct eeprom_table_record *bps, int pages);
>   
>   int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev);
> -int amdgpu_ras_reserve_bad_pages(struct amdgpu_device *adev);
>   
>   static inline int amdgpu_ras_reset_gpu(struct amdgpu_device *adev)
>   {
>   	struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
>   
> -	if (in_task())
> -		amdgpu_ras_reserve_bad_pages(adev);
> -
>   	if (atomic_cmpxchg(&ras->in_recovery, 0, 1) == 0)
>   		schedule_work(&ras->recovery_work);
>   	return 0;
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> index de37ceff0e56..90a3ed682466 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> @@ -103,6 +103,10 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
>   			      struct sg_table *sgt);
>   uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man);
>   uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man);
> +int amdgpu_vram_mgr_reserve_range(struct ttm_mem_type_manager *man,
> +				  uint64_t start, uint64_t size);
> +int amdgpu_vram_mgr_query_page_status(struct ttm_mem_type_manager *man,
> +				      uint64_t start);
>   
>   int amdgpu_ttm_init(struct amdgpu_device *adev);
>   void amdgpu_ttm_late_init(struct amdgpu_device *adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> index 91098a385ed6..db573e77e216 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> @@ -28,9 +28,16 @@
>   #include "amdgpu_atomfirmware.h"
>   #include "atom.h"
>   
> +struct amdgpu_vram_reservation {
> +	struct list_head node;
> +	struct drm_mm_node mm_node;
> +};
> +
>   struct amdgpu_vram_mgr {
>   	struct drm_mm mm;
>   	spinlock_t lock;
> +	struct list_head reservations_pending;
> +	struct list_head reserved_pages;
>   	atomic64_t usage;
>   	atomic64_t vis_usage;
>   };
> @@ -179,6 +186,8 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
>   
>   	drm_mm_init(&mgr->mm, 0, p_size);
>   	spin_lock_init(&mgr->lock);
> +	INIT_LIST_HEAD(&mgr->reservations_pending);
> +	INIT_LIST_HEAD(&mgr->reserved_pages);
>   	man->priv = mgr;
>   
>   	/* Add the two VRAM-related sysfs files */
> @@ -201,8 +210,18 @@ static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
>   {
>   	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
>   	struct amdgpu_vram_mgr *mgr = man->priv;
> +	struct amdgpu_vram_reservation *rsv, *temp;
>   
>   	spin_lock(&mgr->lock);
> +
> +	list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
> +		kfree(rsv);
> +
> +	list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
> +		drm_mm_remove_node(&rsv->mm_node);
> +		kfree(rsv);
> +	}
> +
>   	drm_mm_takedown(&mgr->mm);
>   	spin_unlock(&mgr->lock);
>   	kfree(mgr);
> @@ -260,6 +279,101 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
>   	return usage;
>   }
>   
> +static void amdgpu_vram_mgr_do_reserve(struct ttm_mem_type_manager *man)
> +{
> +	struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
> +	struct amdgpu_vram_mgr *mgr = man->priv;
> +	struct drm_mm *mm = &mgr->mm;
> +	struct amdgpu_vram_reservation *rsv, *temp;
> +	uint64_t vis_usage;
> +
> +	list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
> +		if (drm_mm_reserve_node(mm, &rsv->mm_node))
> +			continue;
> +
> +		dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Successed\n",
> +			rsv->mm_node.start, rsv->mm_node.size);
> +
> +		vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
> +		atomic64_add(vis_usage, &mgr->vis_usage);
> +		atomic64_add(rsv->mm_node.size << PAGE_SHIFT, &mgr->usage);
> +		list_move(&rsv->node, &mgr->reserved_pages);
> +	}
> +}
> +
> +/**
> + * amdgpu_vram_mgr_reserve_range - Reserve a range from VRAM
> + *
> + * @man: TTM memory type manager
> + * @start: start address of the range in VRAM
> + * @size: size of the range
> + *
> + * Reserve memory from start addess with the specified size in VRAM
> + */
> +int amdgpu_vram_mgr_reserve_range(struct ttm_mem_type_manager *man,
> +				  uint64_t start, uint64_t size)
> +{
> +	struct amdgpu_vram_mgr *mgr = man->priv;
> +	struct amdgpu_vram_reservation *rsv;
> +
> +	rsv = kzalloc(sizeof(*rsv), GFP_KERNEL);
> +	if (!rsv)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&rsv->node);
> +	rsv->mm_node.start = start >> PAGE_SHIFT;
> +	rsv->mm_node.size = size >> PAGE_SHIFT;
> +
> +	spin_lock(&mgr->lock);
> +	list_add_tail(&mgr->reservations_pending, &rsv->node);
> +	amdgpu_vram_mgr_do_reserve(man);
> +	spin_unlock(&mgr->lock);
> +
> +	return 0;
> +}
> +
> +/**
> + * amdgpu_vram_mgr_query_page_status - query the reservation status
> + *
> + * @man: TTM memory type manager
> + * @start: start address of a page in VRAM
> + *
> + * Returns:
> + *	-EBUSY: the page is still hold and in pending list
> + *	0: the page has been reserved
> + *	-ENOENT: the input page is not a reservation
> + */
> +int amdgpu_vram_mgr_query_page_status(struct ttm_mem_type_manager *man,
> +				      uint64_t start)
> +{
> +	struct amdgpu_vram_mgr *mgr = man->priv;
> +	struct amdgpu_vram_reservation *rsv;
> +	int ret;
> +
> +	spin_lock(&mgr->lock);
> +
> +	list_for_each_entry(rsv, &mgr->reservations_pending, node) {
> +		if ((rsv->mm_node.start <= start) &&
> +		    (start < (rsv->mm_node.start + rsv->mm_node.size))) {
> +			ret = -EBUSY;
> +			goto out;
> +		}
> +	}
> +
> +	list_for_each_entry(rsv, &mgr->reserved_pages, node) {
> +		if ((rsv->mm_node.start <= start) &&
> +		    (start < (rsv->mm_node.start + rsv->mm_node.size))) {
> +			ret = 0;
> +			goto out;
> +		}
> +	}
> +
> +	ret = -ENOENT;
> +out:
> +	spin_unlock(&mgr->lock);
> +	return ret;
> +}
> +
>   /**
>    * amdgpu_vram_mgr_virt_start - update virtual start address
>    *
> @@ -430,6 +544,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
>   		vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
>   		++nodes;
>   	}
> +	amdgpu_vram_mgr_do_reserve(man);
>   	spin_unlock(&mgr->lock);
>   
>   	atomic64_sub(usage, &mgr->usage);

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-10-27  9:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-27  9:05 [PATCH 3/3] drm/amdgpu: fix the issue of reserving bad pages failed Dennis Li
2020-10-27  9:47 ` Christian König

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.