* [PATCH 0/5] Add support for XGMI hive reset.
@ 2018-11-21 18:10 Andrey Grodzovsky
[not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
0 siblings, 1 reply; 21+ messages in thread
From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw)
To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Alexander.Deucher-5C7GfCeVMHo, Monk.Liu-5C7GfCeVMHo
This set of patches adds support to reset entire XGMI hive
when reset is required.
Patches 1 and 2 add place holder for PSP mode 0 reset.
The actual implementation is still TBD on PSP side.
Patches 3-4 refactoring a bit the XGMI infrastructure as
preparaton for the actual hive reset change.
Patch 5 is GPU reset/recovery refactored to support XGMI
hive reset.
Andrey Grodzovsky (5)
drm/amdgpu/psp: Add mode 0 reset function.
drm/amdgpu/psp: Enable mode 0 reset for XGMI.
drm/amdgpu: Refactor amdgpu_xgmi_add_device
drm/amdgpu: Expose hive adev list and xgmi_mutex
drm/amdgpu: Refactor GPU reset for XGMI hive case.
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 10 ++
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 371 +++++++++++++++++++++++++++++++++++++++++++++--------------------
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 3 +
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 62 +++++++----
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 8 ++
6 files changed, 321 insertions(+), 139 deletions(-)
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 21+ messages in thread[parent not found: <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* [PATCH 1/5] drm/amdgpu/psp: Add mode 0 reset function. [not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 18:10 ` Andrey Grodzovsky [not found] ` <1542823821-15631-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 2/5] drm/amdgpu/psp: Enable mode 0 reset for XGMI Andrey Grodzovsky ` (3 subsequent siblings) 4 siblings, 1 reply; 21+ messages in thread From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw) To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW Cc: Alexander.Deucher-5C7GfCeVMHo, Andrey Grodzovsky, Monk.Liu-5C7GfCeVMHo Currently just a place holder until support from PSP in place. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 3 +++ drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 9ec5d1a..2bdb394 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -83,6 +83,7 @@ struct psp_funcs enum AMDGPU_UCODE_ID ucode_type); bool (*smu_reload_quirk)(struct psp_context *psp); int (*mode1_reset)(struct psp_context *psp); + int (*mode0_reset)(struct psp_context *psp); uint64_t (*xgmi_get_node_id)(struct psp_context *psp); uint64_t (*xgmi_get_hive_id)(struct psp_context *psp); int (*xgmi_get_topology_info)(struct psp_context *psp, int number_devices, @@ -194,6 +195,8 @@ struct psp_xgmi_topology_info { ((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false) #define psp_mode1_reset(psp) \ ((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false) +#define psp_mode0_reset(psp) \ + ((psp)->funcs->mode0_reset ? (psp)->funcs->mode1_reset((psp)) : false) #define psp_xgmi_get_node_id(psp) \ ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp)) : 0) #define psp_xgmi_get_hive_id(psp) \ diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index 082093a..8feb580 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -573,6 +573,13 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp) return 0; } +static int psp_v11_0_mode0_reset(struct psp_context *psp) +{ + /* TBD Once support from PSP in place */ + + return 0; +} + /* TODO: Fill in follow functions once PSP firmware interface for XGMI is ready. * For now, return success and hack the hive_id so high level code can * start testing @@ -698,6 +705,7 @@ static const struct psp_funcs psp_v11_0_funcs = { .cmd_submit = psp_v11_0_cmd_submit, .compare_sram_data = psp_v11_0_compare_sram_data, .mode1_reset = psp_v11_0_mode1_reset, + .mode0_reset = psp_v11_0_mode0_reset, .xgmi_get_topology_info = psp_v11_0_xgmi_get_topology_info, .xgmi_set_topology_info = psp_v11_0_xgmi_set_topology_info, .xgmi_get_hive_id = psp_v11_0_xgmi_get_hive_id, -- 2.7.4 _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply related [flat|nested] 21+ messages in thread
[parent not found: <1542823821-15631-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 1/5] drm/amdgpu/psp: Add mode 0 reset function. [not found] ` <1542823821-15631-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:22 ` Alex Deucher 0 siblings, 0 replies; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:22 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 1:10 PM Andrey Grodzovsky <andrey.grodzovsky@amd.com> wrote: > > Currently just a place holder until support from PSP in place. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> I think we can drop this patch for now until we figure out what the proper reset method will be for this. We may end up using baco. Alex > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 3 +++ > drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 8 ++++++++ > 2 files changed, 11 insertions(+) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h > index 9ec5d1a..2bdb394 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h > @@ -83,6 +83,7 @@ struct psp_funcs > enum AMDGPU_UCODE_ID ucode_type); > bool (*smu_reload_quirk)(struct psp_context *psp); > int (*mode1_reset)(struct psp_context *psp); > + int (*mode0_reset)(struct psp_context *psp); > uint64_t (*xgmi_get_node_id)(struct psp_context *psp); > uint64_t (*xgmi_get_hive_id)(struct psp_context *psp); > int (*xgmi_get_topology_info)(struct psp_context *psp, int number_devices, > @@ -194,6 +195,8 @@ struct psp_xgmi_topology_info { > ((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false) > #define psp_mode1_reset(psp) \ > ((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false) > +#define psp_mode0_reset(psp) \ > + ((psp)->funcs->mode0_reset ? (psp)->funcs->mode1_reset((psp)) : false) > #define psp_xgmi_get_node_id(psp) \ > ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp)) : 0) > #define psp_xgmi_get_hive_id(psp) \ > diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c > index 082093a..8feb580 100644 > --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c > +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c > @@ -573,6 +573,13 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp) > return 0; > } > > +static int psp_v11_0_mode0_reset(struct psp_context *psp) > +{ > + /* TBD Once support from PSP in place */ > + > + return 0; > +} > + > /* TODO: Fill in follow functions once PSP firmware interface for XGMI is ready. > * For now, return success and hack the hive_id so high level code can > * start testing > @@ -698,6 +705,7 @@ static const struct psp_funcs psp_v11_0_funcs = { > .cmd_submit = psp_v11_0_cmd_submit, > .compare_sram_data = psp_v11_0_compare_sram_data, > .mode1_reset = psp_v11_0_mode1_reset, > + .mode0_reset = psp_v11_0_mode0_reset, > .xgmi_get_topology_info = psp_v11_0_xgmi_get_topology_info, > .xgmi_set_topology_info = psp_v11_0_xgmi_set_topology_info, > .xgmi_get_hive_id = psp_v11_0_xgmi_get_hive_id, > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 2/5] drm/amdgpu/psp: Enable mode 0 reset for XGMI. [not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 1/5] drm/amdgpu/psp: Add mode 0 reset function Andrey Grodzovsky @ 2018-11-21 18:10 ` Andrey Grodzovsky [not found] ` <1542823821-15631-3-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device Andrey Grodzovsky ` (2 subsequent siblings) 4 siblings, 1 reply; 21+ messages in thread From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw) To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW Cc: Alexander.Deucher-5C7GfCeVMHo, Andrey Grodzovsky, Monk.Liu-5C7GfCeVMHo In case of active XGMI hive do mode 0 reset as requsted by design. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index e05dc66..befee12 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -733,7 +733,11 @@ int psp_gpu_reset(struct amdgpu_device *adev) if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) return 0; - return psp_mode1_reset(&adev->psp); + + if (adev->gmc.xgmi.num_physical_nodes > 1) + return psp_mode0_reset(&adev->psp); + else + return psp_mode1_reset(&adev->psp); } static bool psp_check_fw_loading_status(struct amdgpu_device *adev, -- 2.7.4 _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply related [flat|nested] 21+ messages in thread
[parent not found: <1542823821-15631-3-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 2/5] drm/amdgpu/psp: Enable mode 0 reset for XGMI. [not found] ` <1542823821-15631-3-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:23 ` Alex Deucher 0 siblings, 0 replies; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:23 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 1:10 PM Andrey Grodzovsky <andrey.grodzovsky@amd.com> wrote: > > In case of active XGMI hive do mode 0 reset as requsted > by design. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> I think we can drop this patch for now as well. Maybe just add a comment here about xgmi. Alex > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c > index e05dc66..befee12 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c > @@ -733,7 +733,11 @@ int psp_gpu_reset(struct amdgpu_device *adev) > if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) > return 0; > > - return psp_mode1_reset(&adev->psp); > + > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + return psp_mode0_reset(&adev->psp); > + else > + return psp_mode1_reset(&adev->psp); > } > > static bool psp_check_fw_loading_status(struct amdgpu_device *adev, > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device [not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 1/5] drm/amdgpu/psp: Add mode 0 reset function Andrey Grodzovsky 2018-11-21 18:10 ` [PATCH 2/5] drm/amdgpu/psp: Enable mode 0 reset for XGMI Andrey Grodzovsky @ 2018-11-21 18:10 ` Andrey Grodzovsky [not found] ` <1542823821-15631-4-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 4/5] drm/amdgpu: Expose hive adev list and xgmi_mutex Andrey Grodzovsky 2018-11-21 18:10 ` [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case Andrey Grodzovsky 4 siblings, 1 reply; 21+ messages in thread From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw) To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW Cc: Alexander.Deucher-5C7GfCeVMHo, Andrey Grodzovsky, Monk.Liu-5C7GfCeVMHo This is prep work for updating each PSP FW in hive after GPU reset. Split into build topology SW state and update each PSP FW in the hive. Save topology and count of XGMI devices for reuse. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 55 +++++++++++++++++++------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 2c80453..3e5bede 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1226,6 +1226,11 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, /* * functions used by amdgpu_xgmi.c */ + +struct amdgpu_hive_info; + +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); int amdgpu_xgmi_add_device(struct amdgpu_device *adev); /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 909216a..23e4e16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -34,12 +34,14 @@ static DEFINE_MUTEX(xgmi_mutex); struct amdgpu_hive_info { uint64_t hive_id; struct list_head device_list; + struct psp_xgmi_topology_info topology_info; + int number_devices; }; static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; static unsigned hive_count = 0; -static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) { int i; struct amdgpu_hive_info *tmp; @@ -61,12 +63,33 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) return tmp; } +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev) +{ + int ret = -EINVAL; + + /* Each psp need to set the latest topology */ + ret = psp_xgmi_set_topology_info(&adev->psp, + hive->number_devices, + &hive->topology_info); + if (ret) + dev_err(adev->dev, + "XGMI: Set topology failure on device %llx, hive %llx, ret %d", + adev->gmc.xgmi.node_id, + adev->gmc.xgmi.hive_id, ret); + else + dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", + adev->gmc.xgmi.physical_node_id, + adev->gmc.xgmi.hive_id); + + return ret; +} + int amdgpu_xgmi_add_device(struct amdgpu_device *adev) { - struct psp_xgmi_topology_info *tmp_topology; + struct psp_xgmi_topology_info *hive_topology; struct amdgpu_hive_info *hive; struct amdgpu_xgmi *entry; - struct amdgpu_device *tmp_adev; + struct amdgpu_device *tmp_adev = NULL; int count = 0, ret = -EINVAL; @@ -76,21 +99,21 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp); adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp); - tmp_topology = kzalloc(sizeof(struct psp_xgmi_topology_info), GFP_KERNEL); - if (!tmp_topology) - return -ENOMEM; mutex_lock(&xgmi_mutex); hive = amdgpu_get_xgmi_hive(adev); if (!hive) goto exit; + hive_topology = &hive->topology_info; + list_add_tail(&adev->gmc.xgmi.head, &hive->device_list); list_for_each_entry(entry, &hive->device_list, head) - tmp_topology->nodes[count++].node_id = entry->node_id; + hive_topology->nodes[count++].node_id = entry->node_id; + hive->number_devices = count; /* Each psp need to get the latest topology */ list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { - ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, tmp_topology); + ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, hive_topology); if (ret) { dev_err(tmp_adev->dev, "XGMI: Get topology failure on device %llx, hive %llx, ret %d", @@ -101,25 +124,13 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) } } - /* Each psp need to set the latest topology */ list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { - ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology); - if (ret) { - dev_err(tmp_adev->dev, - "XGMI: Set topology failure on device %llx, hive %llx, ret %d", - tmp_adev->gmc.xgmi.node_id, - tmp_adev->gmc.xgmi.hive_id, ret); - /* To do : continue with some node failed or disable the whole hive */ + ret = amdgpu_xgmi_update_topology(hive, tmp_adev); + if (ret) break; - } } - if (!ret) - dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", - adev->gmc.xgmi.physical_node_id, - adev->gmc.xgmi.hive_id); exit: mutex_unlock(&xgmi_mutex); - kfree(tmp_topology); return ret; } -- 2.7.4 _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply related [flat|nested] 21+ messages in thread
[parent not found: <1542823821-15631-4-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device [not found] ` <1542823821-15631-4-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:29 ` Alex Deucher [not found] ` <CADnq5_MSpxAXsdwh+NzXCrOGVVo3gog9FjdzRNaX9ZhwuatmKg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:29 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 1:11 PM Andrey Grodzovsky <andrey.grodzovsky@amd.com> wrote: > > This is prep work for updating each PSP FW in hive after > GPU reset. > Split into build topology SW state and update each PSP FW in the hive. > Save topology and count of XGMI devices for reuse. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +++ > drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 55 +++++++++++++++++++------------- > 2 files changed, 38 insertions(+), 22 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 2c80453..3e5bede 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -1226,6 +1226,11 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, > /* > * functions used by amdgpu_xgmi.c > */ > + > +struct amdgpu_hive_info; > + > +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); > +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); > int amdgpu_xgmi_add_device(struct amdgpu_device *adev); We should move these to their own header, amdgpu_xgmi.h, rather than dumping them in amdgpu.h > > /* > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > index 909216a..23e4e16 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > @@ -34,12 +34,14 @@ static DEFINE_MUTEX(xgmi_mutex); > struct amdgpu_hive_info { > uint64_t hive_id; > struct list_head device_list; > + struct psp_xgmi_topology_info topology_info; > + int number_devices; > }; > > static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; > static unsigned hive_count = 0; > > -static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) Any reason to make this public? > { > int i; > struct amdgpu_hive_info *tmp; > @@ -61,12 +63,33 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > return tmp; > } > > +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev) > +{ > + int ret = -EINVAL; > + > + /* Each psp need to set the latest topology */ > + ret = psp_xgmi_set_topology_info(&adev->psp, > + hive->number_devices, > + &hive->topology_info); > + if (ret) > + dev_err(adev->dev, > + "XGMI: Set topology failure on device %llx, hive %llx, ret %d", > + adev->gmc.xgmi.node_id, > + adev->gmc.xgmi.hive_id, ret); > + else > + dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", > + adev->gmc.xgmi.physical_node_id, > + adev->gmc.xgmi.hive_id); > + > + return ret; > +} Indentation in this function looks wrong. > + > int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > { > - struct psp_xgmi_topology_info *tmp_topology; > + struct psp_xgmi_topology_info *hive_topology; > struct amdgpu_hive_info *hive; > struct amdgpu_xgmi *entry; > - struct amdgpu_device *tmp_adev; > + struct amdgpu_device *tmp_adev = NULL; > > int count = 0, ret = -EINVAL; > > @@ -76,21 +99,21 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp); > adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp); > > - tmp_topology = kzalloc(sizeof(struct psp_xgmi_topology_info), GFP_KERNEL); > - if (!tmp_topology) > - return -ENOMEM; > mutex_lock(&xgmi_mutex); > hive = amdgpu_get_xgmi_hive(adev); > if (!hive) > goto exit; > > + hive_topology = &hive->topology_info; > + > list_add_tail(&adev->gmc.xgmi.head, &hive->device_list); > list_for_each_entry(entry, &hive->device_list, head) > - tmp_topology->nodes[count++].node_id = entry->node_id; > + hive_topology->nodes[count++].node_id = entry->node_id; > + hive->number_devices = count; > > /* Each psp need to get the latest topology */ > list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { > - ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, tmp_topology); > + ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, hive_topology); > if (ret) { > dev_err(tmp_adev->dev, > "XGMI: Get topology failure on device %llx, hive %llx, ret %d", > @@ -101,25 +124,13 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > } > } > > - /* Each psp need to set the latest topology */ > list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { > - ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology); > - if (ret) { > - dev_err(tmp_adev->dev, > - "XGMI: Set topology failure on device %llx, hive %llx, ret %d", > - tmp_adev->gmc.xgmi.node_id, > - tmp_adev->gmc.xgmi.hive_id, ret); > - /* To do : continue with some node failed or disable the whole hive */ > + ret = amdgpu_xgmi_update_topology(hive, tmp_adev); > + if (ret) > break; > - } > } > - if (!ret) > - dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", > - adev->gmc.xgmi.physical_node_id, > - adev->gmc.xgmi.hive_id); > > exit: > mutex_unlock(&xgmi_mutex); > - kfree(tmp_topology); > return ret; > } > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <CADnq5_MSpxAXsdwh+NzXCrOGVVo3gog9FjdzRNaX9ZhwuatmKg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device [not found] ` <CADnq5_MSpxAXsdwh+NzXCrOGVVo3gog9FjdzRNaX9ZhwuatmKg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2018-11-21 19:36 ` Grodzovsky, Andrey [not found] ` <aa7ee809-8f1f-c4de-c674-4b11f77b70f3-5C7GfCeVMHo@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Grodzovsky, Andrey @ 2018-11-21 19:36 UTC (permalink / raw) To: Alex Deucher; +Cc: Deucher, Alexander, Liu, Monk, amd-gfx list On 11/21/2018 02:29 PM, Alex Deucher wrote: > On Wed, Nov 21, 2018 at 1:11 PM Andrey Grodzovsky > <andrey.grodzovsky@amd.com> wrote: >> This is prep work for updating each PSP FW in hive after >> GPU reset. >> Split into build topology SW state and update each PSP FW in the hive. >> Save topology and count of XGMI devices for reuse. >> >> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >> --- >> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +++ >> drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 55 +++++++++++++++++++------------- >> 2 files changed, 38 insertions(+), 22 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> index 2c80453..3e5bede 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> @@ -1226,6 +1226,11 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, >> /* >> * functions used by amdgpu_xgmi.c >> */ >> + >> +struct amdgpu_hive_info; >> + >> +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); >> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); > We should move these to their own header, amdgpu_xgmi.h, rather than > dumping them in amdgpu.h > >> /* >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c >> index 909216a..23e4e16 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c >> @@ -34,12 +34,14 @@ static DEFINE_MUTEX(xgmi_mutex); >> struct amdgpu_hive_info { >> uint64_t hive_id; >> struct list_head device_list; >> + struct psp_xgmi_topology_info topology_info; >> + int number_devices; >> }; >> >> static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; >> static unsigned hive_count = 0; >> >> -static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) >> +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > Any reason to make this public? It is used in Patch 5. Andrey > >> { >> int i; >> struct amdgpu_hive_info *tmp; >> @@ -61,12 +63,33 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) >> return tmp; >> } >> >> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev) >> +{ >> + int ret = -EINVAL; >> + >> + /* Each psp need to set the latest topology */ >> + ret = psp_xgmi_set_topology_info(&adev->psp, >> + hive->number_devices, >> + &hive->topology_info); >> + if (ret) >> + dev_err(adev->dev, >> + "XGMI: Set topology failure on device %llx, hive %llx, ret %d", >> + adev->gmc.xgmi.node_id, >> + adev->gmc.xgmi.hive_id, ret); >> + else >> + dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", >> + adev->gmc.xgmi.physical_node_id, >> + adev->gmc.xgmi.hive_id); >> + >> + return ret; >> +} > Indentation in this function looks wrong. > >> + >> int amdgpu_xgmi_add_device(struct amdgpu_device *adev) >> { >> - struct psp_xgmi_topology_info *tmp_topology; >> + struct psp_xgmi_topology_info *hive_topology; >> struct amdgpu_hive_info *hive; >> struct amdgpu_xgmi *entry; >> - struct amdgpu_device *tmp_adev; >> + struct amdgpu_device *tmp_adev = NULL; >> >> int count = 0, ret = -EINVAL; >> >> @@ -76,21 +99,21 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) >> adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp); >> adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp); >> >> - tmp_topology = kzalloc(sizeof(struct psp_xgmi_topology_info), GFP_KERNEL); >> - if (!tmp_topology) >> - return -ENOMEM; >> mutex_lock(&xgmi_mutex); >> hive = amdgpu_get_xgmi_hive(adev); >> if (!hive) >> goto exit; >> >> + hive_topology = &hive->topology_info; >> + >> list_add_tail(&adev->gmc.xgmi.head, &hive->device_list); >> list_for_each_entry(entry, &hive->device_list, head) >> - tmp_topology->nodes[count++].node_id = entry->node_id; >> + hive_topology->nodes[count++].node_id = entry->node_id; >> + hive->number_devices = count; >> >> /* Each psp need to get the latest topology */ >> list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { >> - ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, tmp_topology); >> + ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, hive_topology); >> if (ret) { >> dev_err(tmp_adev->dev, >> "XGMI: Get topology failure on device %llx, hive %llx, ret %d", >> @@ -101,25 +124,13 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) >> } >> } >> >> - /* Each psp need to set the latest topology */ >> list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { >> - ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology); >> - if (ret) { >> - dev_err(tmp_adev->dev, >> - "XGMI: Set topology failure on device %llx, hive %llx, ret %d", >> - tmp_adev->gmc.xgmi.node_id, >> - tmp_adev->gmc.xgmi.hive_id, ret); >> - /* To do : continue with some node failed or disable the whole hive */ >> + ret = amdgpu_xgmi_update_topology(hive, tmp_adev); >> + if (ret) >> break; >> - } >> } >> - if (!ret) >> - dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", >> - adev->gmc.xgmi.physical_node_id, >> - adev->gmc.xgmi.hive_id); >> >> exit: >> mutex_unlock(&xgmi_mutex); >> - kfree(tmp_topology); >> return ret; >> } >> -- >> 2.7.4 >> >> _______________________________________________ >> amd-gfx mailing list >> amd-gfx@lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <aa7ee809-8f1f-c4de-c674-4b11f77b70f3-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device [not found] ` <aa7ee809-8f1f-c4de-c674-4b11f77b70f3-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:38 ` Alex Deucher 0 siblings, 0 replies; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:38 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 2:36 PM Grodzovsky, Andrey <Andrey.Grodzovsky@amd.com> wrote: > > > > On 11/21/2018 02:29 PM, Alex Deucher wrote: > > On Wed, Nov 21, 2018 at 1:11 PM Andrey Grodzovsky > > <andrey.grodzovsky@amd.com> wrote: > >> This is prep work for updating each PSP FW in hive after > >> GPU reset. > >> Split into build topology SW state and update each PSP FW in the hive. > >> Save topology and count of XGMI devices for reuse. > >> > >> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> > >> --- > >> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +++ > >> drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 55 +++++++++++++++++++------------- > >> 2 files changed, 38 insertions(+), 22 deletions(-) > >> > >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > >> index 2c80453..3e5bede 100644 > >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > >> @@ -1226,6 +1226,11 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, > >> /* > >> * functions used by amdgpu_xgmi.c > >> */ > >> + > >> +struct amdgpu_hive_info; > >> + > >> +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); > >> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); > >> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); > > We should move these to their own header, amdgpu_xgmi.h, rather than > > dumping them in amdgpu.h > > > >> /* > >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > >> index 909216a..23e4e16 100644 > >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > >> @@ -34,12 +34,14 @@ static DEFINE_MUTEX(xgmi_mutex); > >> struct amdgpu_hive_info { > >> uint64_t hive_id; > >> struct list_head device_list; > >> + struct psp_xgmi_topology_info topology_info; > >> + int number_devices; > >> }; > >> > >> static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; > >> static unsigned hive_count = 0; > >> > >> -static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > >> +struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > > Any reason to make this public? > > It is used in Patch 5. Ok. thanks. Alex > > Andrey > > > > >> { > >> int i; > >> struct amdgpu_hive_info *tmp; > >> @@ -61,12 +63,33 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > >> return tmp; > >> } > >> > >> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev) > >> +{ > >> + int ret = -EINVAL; > >> + > >> + /* Each psp need to set the latest topology */ > >> + ret = psp_xgmi_set_topology_info(&adev->psp, > >> + hive->number_devices, > >> + &hive->topology_info); > >> + if (ret) > >> + dev_err(adev->dev, > >> + "XGMI: Set topology failure on device %llx, hive %llx, ret %d", > >> + adev->gmc.xgmi.node_id, > >> + adev->gmc.xgmi.hive_id, ret); > >> + else > >> + dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", > >> + adev->gmc.xgmi.physical_node_id, > >> + adev->gmc.xgmi.hive_id); > >> + > >> + return ret; > >> +} > > Indentation in this function looks wrong. > > > >> + > >> int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > >> { > >> - struct psp_xgmi_topology_info *tmp_topology; > >> + struct psp_xgmi_topology_info *hive_topology; > >> struct amdgpu_hive_info *hive; > >> struct amdgpu_xgmi *entry; > >> - struct amdgpu_device *tmp_adev; > >> + struct amdgpu_device *tmp_adev = NULL; > >> > >> int count = 0, ret = -EINVAL; > >> > >> @@ -76,21 +99,21 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > >> adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp); > >> adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp); > >> > >> - tmp_topology = kzalloc(sizeof(struct psp_xgmi_topology_info), GFP_KERNEL); > >> - if (!tmp_topology) > >> - return -ENOMEM; > >> mutex_lock(&xgmi_mutex); > >> hive = amdgpu_get_xgmi_hive(adev); > >> if (!hive) > >> goto exit; > >> > >> + hive_topology = &hive->topology_info; > >> + > >> list_add_tail(&adev->gmc.xgmi.head, &hive->device_list); > >> list_for_each_entry(entry, &hive->device_list, head) > >> - tmp_topology->nodes[count++].node_id = entry->node_id; > >> + hive_topology->nodes[count++].node_id = entry->node_id; > >> + hive->number_devices = count; > >> > >> /* Each psp need to get the latest topology */ > >> list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { > >> - ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, tmp_topology); > >> + ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, hive_topology); > >> if (ret) { > >> dev_err(tmp_adev->dev, > >> "XGMI: Get topology failure on device %llx, hive %llx, ret %d", > >> @@ -101,25 +124,13 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) > >> } > >> } > >> > >> - /* Each psp need to set the latest topology */ > >> list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { > >> - ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology); > >> - if (ret) { > >> - dev_err(tmp_adev->dev, > >> - "XGMI: Set topology failure on device %llx, hive %llx, ret %d", > >> - tmp_adev->gmc.xgmi.node_id, > >> - tmp_adev->gmc.xgmi.hive_id, ret); > >> - /* To do : continue with some node failed or disable the whole hive */ > >> + ret = amdgpu_xgmi_update_topology(hive, tmp_adev); > >> + if (ret) > >> break; > >> - } > >> } > >> - if (!ret) > >> - dev_info(adev->dev, "XGMI: Add node %d to hive 0x%llx.\n", > >> - adev->gmc.xgmi.physical_node_id, > >> - adev->gmc.xgmi.hive_id); > >> > >> exit: > >> mutex_unlock(&xgmi_mutex); > >> - kfree(tmp_topology); > >> return ret; > >> } > >> -- > >> 2.7.4 > >> > >> _______________________________________________ > >> amd-gfx mailing list > >> amd-gfx@lists.freedesktop.org > >> https://lists.freedesktop.org/mailman/listinfo/amd-gfx > _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 4/5] drm/amdgpu: Expose hive adev list and xgmi_mutex [not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> ` (2 preceding siblings ...) 2018-11-21 18:10 ` [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device Andrey Grodzovsky @ 2018-11-21 18:10 ` Andrey Grodzovsky [not found] ` <1542823821-15631-5-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 18:10 ` [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case Andrey Grodzovsky 4 siblings, 1 reply; 21+ messages in thread From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw) To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW Cc: Alexander.Deucher-5C7GfCeVMHo, Andrey Grodzovsky, Monk.Liu-5C7GfCeVMHo It's needed for device reset of entire hive. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 3e5bede..4ef5f7a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1227,8 +1227,10 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, * functions used by amdgpu_xgmi.c */ +extern struct mutex xgmi_mutex; struct amdgpu_hive_info; +struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); int amdgpu_xgmi_add_device(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 23e4e16..e483e60 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -26,7 +26,7 @@ #include "amdgpu_psp.h" -static DEFINE_MUTEX(xgmi_mutex); +DEFINE_MUTEX(xgmi_mutex); #define AMDGPU_MAX_XGMI_HIVE 8 #define AMDGPU_MAX_XGMI_DEVICE_PER_HIVE 4 @@ -41,6 +41,11 @@ struct amdgpu_hive_info { static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; static unsigned hive_count = 0; +struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive) +{ + return &hive->device_list; +} + struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) { int i; -- 2.7.4 _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply related [flat|nested] 21+ messages in thread
[parent not found: <1542823821-15631-5-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 4/5] drm/amdgpu: Expose hive adev list and xgmi_mutex [not found] ` <1542823821-15631-5-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:45 ` Alex Deucher 0 siblings, 0 replies; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:45 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 1:11 PM Andrey Grodzovsky <andrey.grodzovsky@amd.com> wrote: > > It's needed for device reset of entire hive. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 ++ > drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 7 ++++++- > 2 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 3e5bede..4ef5f7a 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -1227,8 +1227,10 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, > * functions used by amdgpu_xgmi.c > */ > > +extern struct mutex xgmi_mutex; > struct amdgpu_hive_info; > > +struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); > struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); > int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); > int amdgpu_xgmi_add_device(struct amdgpu_device *adev); > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > index 23e4e16..e483e60 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c > @@ -26,7 +26,7 @@ > #include "amdgpu_psp.h" > > > -static DEFINE_MUTEX(xgmi_mutex); > +DEFINE_MUTEX(xgmi_mutex); > > #define AMDGPU_MAX_XGMI_HIVE 8 > #define AMDGPU_MAX_XGMI_DEVICE_PER_HIVE 4 > @@ -41,6 +41,11 @@ struct amdgpu_hive_info { > static struct amdgpu_hive_info xgmi_hives[AMDGPU_MAX_XGMI_HIVE]; > static unsigned hive_count = 0; > > +struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive) > +{ > + return &hive->device_list; > +} > + > struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) > { > int i; > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> ` (3 preceding siblings ...) 2018-11-21 18:10 ` [PATCH 4/5] drm/amdgpu: Expose hive adev list and xgmi_mutex Andrey Grodzovsky @ 2018-11-21 18:10 ` Andrey Grodzovsky [not found] ` <1542823821-15631-6-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 4 siblings, 1 reply; 21+ messages in thread From: Andrey Grodzovsky @ 2018-11-21 18:10 UTC (permalink / raw) To: amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW Cc: Alexander.Deucher-5C7GfCeVMHo, Andrey Grodzovsky, Monk.Liu-5C7GfCeVMHo For XGMI hive case do reset in steps where each step iterates over all devs in hive. This especially important for asic reset since all PSP FW in hive must come up within a limited time (around 1 sec) to properply negotiate the link. Do this by refactoring amdgpu_device_gpu_recover and amdgpu_device_reset into pre_asic_reset, asic_reset and post_asic_reset functions where is part is exectued for all the GPUs in the hive before going to the next step. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 ++++++++++++++++++++--------- 2 files changed, 264 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 4ef5f7a..bd06d45 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1026,6 +1026,9 @@ struct amdgpu_device { unsigned long last_mm_index; bool in_gpu_reset; struct mutex lock_reset; + + int asic_reset_res; + int resched; }; static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); int amdgpu_xgmi_add_device(struct amdgpu_device *adev); /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index cb06e68..8e94d7f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) return 0; } -/** - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough - * - * @adev: amdgpu device pointer - * - * attempt to do soft-reset or full-reset and reinitialize Asic - * return 0 means succeeded otherwise failed - */ -static int amdgpu_device_reset(struct amdgpu_device *adev) -{ - bool need_full_reset, vram_lost = 0; - int r; - - need_full_reset = amdgpu_device_ip_need_full_reset(adev); - - if (!need_full_reset) { - amdgpu_device_ip_pre_soft_reset(adev); - r = amdgpu_device_ip_soft_reset(adev); - amdgpu_device_ip_post_soft_reset(adev); - if (r || amdgpu_device_ip_check_soft_reset(adev)) { - DRM_INFO("soft reset failed, will fallback to full reset!\n"); - need_full_reset = true; - } - } - - if (need_full_reset) { - r = amdgpu_device_ip_suspend(adev); - -retry: - r = amdgpu_asic_reset(adev); - /* post card */ - amdgpu_atom_asic_init(adev->mode_info.atom_context); - - if (!r) { - dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); - r = amdgpu_device_ip_resume_phase1(adev); - if (r) - goto out; - - vram_lost = amdgpu_device_check_vram_lost(adev); - if (vram_lost) { - DRM_ERROR("VRAM is lost!\n"); - atomic_inc(&adev->vram_lost_counter); - } - - r = amdgpu_gtt_mgr_recover( - &adev->mman.bdev.man[TTM_PL_TT]); - if (r) - goto out; - - r = amdgpu_device_fw_loading(adev); - if (r) - return r; - - r = amdgpu_device_ip_resume_phase2(adev); - if (r) - goto out; - - if (vram_lost) - amdgpu_device_fill_reset_magic(adev); - } - } - -out: - if (!r) { - amdgpu_irq_gpu_reset_resume_helper(adev); - r = amdgpu_ib_ring_tests(adev); - if (r) { - dev_err(adev->dev, "ib ring test failed (%d).\n", r); - r = amdgpu_device_ip_suspend(adev); - need_full_reset = true; - goto retry; - } - } - - if (!r) - r = amdgpu_device_recover_vram(adev); - - return r; -} /** * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf @@ -3335,31 +3255,16 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) return false; } -/** - * amdgpu_device_gpu_recover - reset the asic and recover scheduler - * - * @adev: amdgpu device pointer - * @job: which job trigger hang - * - * Attempt to reset the GPU if it has hung (all asics). - * Returns 0 for success or an error on failure. - */ -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, - struct amdgpu_job *job) -{ - int i, r, resched; - - dev_info(adev->dev, "GPU reset begin!\n"); - - mutex_lock(&adev->lock_reset); - atomic_inc(&adev->gpu_reset_counter); - adev->in_gpu_reset = 1; - /* Block kfd */ - amdgpu_amdkfd_pre_reset(adev); +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, + struct amdgpu_job *job, + bool *need_full_reset_arg) +{ + int i, r = 0; + bool need_full_reset = *need_full_reset_arg; /* block TTM */ - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); /* block all schedulers and reset given job's ring */ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, amdgpu_fence_driver_force_completion(ring); } - if (amdgpu_sriov_vf(adev)) - r = amdgpu_device_reset_sriov(adev, job ? false : true); - else - r = amdgpu_device_reset(adev); + if (!amdgpu_sriov_vf(adev)) { + + if (!need_full_reset) + need_full_reset = amdgpu_device_ip_need_full_reset(adev); + + if (!need_full_reset) { + amdgpu_device_ip_pre_soft_reset(adev); + r = amdgpu_device_ip_soft_reset(adev); + amdgpu_device_ip_post_soft_reset(adev); + if (r || amdgpu_device_ip_check_soft_reset(adev)) { + DRM_INFO("soft reset failed, will fallback to full reset!\n"); + need_full_reset = true; + } + } + + if (need_full_reset) + r = amdgpu_device_ip_suspend(adev); + + *need_full_reset_arg = need_full_reset; + } + + return r; +} + +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, + struct list_head *device_list_handle, + bool *need_full_reset_arg) +{ + struct amdgpu_device *tmp_adev = NULL; + bool need_full_reset = *need_full_reset_arg, vram_lost = false; + int r = 0; + + /* + * ASIC reset has to be done on all HGMI hive nodes ASAP + * to allow proper links negotiation in FW (within 1 sec) + */ + if (need_full_reset) { + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { + r = amdgpu_asic_reset(tmp_adev); + if (r) + DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s", + r, tmp_adev->ddev->unique); + } + } + + + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { + if (need_full_reset) { + /* post card */ + if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) + DRM_WARN("asic atom init failed!"); + + if (!r) { + dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); + r = amdgpu_device_ip_resume_phase1(tmp_adev); + if (r) + goto out; + + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); + if (vram_lost) { + DRM_ERROR("VRAM is lost!\n"); + atomic_inc(&tmp_adev->vram_lost_counter); + } + + r = amdgpu_gtt_mgr_recover( + &tmp_adev->mman.bdev.man[TTM_PL_TT]); + if (r) + goto out; + + r = amdgpu_device_fw_loading(tmp_adev); + if (r) + return r; + + r = amdgpu_device_ip_resume_phase2(tmp_adev); + if (r) + goto out; + + if (vram_lost) + amdgpu_device_fill_reset_magic(tmp_adev); + + /* Update PSP FW topology after reset */ + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) + r = amdgpu_xgmi_update_topology(hive, tmp_adev); + } + } + + +out: + if (!r) { + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); + r = amdgpu_ib_ring_tests(tmp_adev); + if (r) { + dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); + r = amdgpu_device_ip_suspend(tmp_adev); + need_full_reset = true; + r = -EAGAIN; + goto end; + } + } + + if (!r) + r = amdgpu_device_recover_vram(tmp_adev); + else + tmp_adev->asic_reset_res = r; + } + +end: + *need_full_reset_arg = need_full_reset; + return r; +} + +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, + struct amdgpu_job *job) +{ + int i; for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, * or all rings (in the case @job is NULL) * after above amdgpu_reset accomplished */ - if ((!job || job->base.sched == &ring->sched) && !r) + if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res) drm_sched_job_recovery(&ring->sched); kthread_unpark(ring->sched.thread); @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, drm_helper_resume_force_mode(adev->ddev); } - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); - if (r) { - /* bad news, how to tell it to userspace ? */ - dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); - } else { - dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); - } + adev->asic_reset_res = adev->resched = 0; + +} +static void amdgpu_lock_adev(struct amdgpu_device *adev) +{ + mutex_lock(&adev->lock_reset); + atomic_inc(&adev->gpu_reset_counter); + adev->in_gpu_reset = 1; + /* Block kfd */ + amdgpu_amdkfd_pre_reset(adev); +} + +static void amdgpu_unlock_adev(struct amdgpu_device *adev) +{ /*unlock kfd */ amdgpu_amdkfd_post_reset(adev); amdgpu_vf_error_trans_all(adev); adev->in_gpu_reset = 0; mutex_unlock(&adev->lock_reset); +} + + +/** + * amdgpu_device_gpu_recover - reset the asic and recover scheduler + * + * @adev: amdgpu device pointer + * @job: which job trigger hang + * + * Attempt to reset the GPU if it has hung (all asics). + * Attempt to do soft-reset or full-reset and reinitialize Asic + * Returns 0 for success or an error on failure. + */ + +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + struct amdgpu_job *job) +{ + int r; + struct amdgpu_hive_info *hive = NULL; + bool need_full_reset = false; + struct amdgpu_device *tmp_adev = NULL; + struct list_head device_list, *device_list_handle = NULL; + + INIT_LIST_HEAD(&device_list); + + dev_info(adev->dev, "GPU reset begin!\n"); + + /* + * In case of XGMI hive disallow concurrent resets to be triggered + * by different nodes. + */ + if (adev->gmc.xgmi.num_physical_nodes > 1) + mutex_lock(&xgmi_mutex); + + /* Start with adev pre asic reset first for soft reset check.*/ + amdgpu_lock_adev(adev); + r = amdgpu_device_pre_asic_reset(adev, + job, + &need_full_reset); + if (r) { + /*TODO Should we stop ?*/ + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", + r, adev->ddev->unique); + adev->asic_reset_res = r; + } + + /* Build list of devices to reset */ + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { + hive = amdgpu_get_xgmi_hive(adev); + if (!hive) { + r = -ENODEV; + + amdgpu_unlock_adev(adev); + + if (adev->gmc.xgmi.num_physical_nodes > 1) + mutex_unlock(&xgmi_mutex); + return r; + } + + /* + * In case we are in XGMI hive mode device reset is done for all the + * nodes in the hive to retrain all XGMI links and hence the reset + * sequence is executed in loop on all nodes. + */ + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); + } else { + list_add_tail(&adev->gmc.xgmi.head, &device_list); + device_list_handle = &device_list; + } + +retry: /* Rest of adevs pre asic reset from XGMI hive. */ + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { + + if (tmp_adev == adev) + continue; + + dev_info(tmp_adev->dev, "GPU reset begin for drm dev %s!\n", adev->ddev->unique); + + amdgpu_lock_adev(tmp_adev); + r = amdgpu_device_pre_asic_reset(tmp_adev, + NULL, + &need_full_reset); + /*TODO Should we stop ?*/ + if (r) { + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", + r, tmp_adev->ddev->unique); + tmp_adev->asic_reset_res = r; + } + } + + /* Actual ASIC resets if needed.*/ + /* TODO Implement XGMI hive reset logic for SRIOV */ + if (amdgpu_sriov_vf(adev)) { + r = amdgpu_device_reset_sriov(adev, job ? false : true); + if (r) + adev->asic_reset_res = r; + } else { + r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); + if (r && r == -EAGAIN) + goto retry; + } + + /* Post ASIC reset for all devs .*/ + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); + + if (r) { + /* bad news, how to tell it to userspace ? */ + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); + amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); + } else { + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter)); + } + + amdgpu_unlock_adev(tmp_adev); + } + + if (adev->gmc.xgmi.num_physical_nodes > 1) + mutex_unlock(&xgmi_mutex); + + if (r) + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); return r; } -- 2.7.4 _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply related [flat|nested] 21+ messages in thread
[parent not found: <1542823821-15631-6-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <1542823821-15631-6-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 19:45 ` Alex Deucher 2018-11-21 20:49 ` Liu, Shaoyun 1 sibling, 0 replies; 21+ messages in thread From: Alex Deucher @ 2018-11-21 19:45 UTC (permalink / raw) To: Andrey Grodzovsky; +Cc: Deucher, Alexander, monk.liu, amd-gfx list On Wed, Nov 21, 2018 at 1:11 PM Andrey Grodzovsky <andrey.grodzovsky@amd.com> wrote: > > For XGMI hive case do reset in steps where each step iterates over > all devs in hive. This especially important for asic reset > since all PSP FW in hive must come up within a limited time > (around 1 sec) to properply negotiate the link. > Do this by refactoring amdgpu_device_gpu_recover and amdgpu_device_reset > into pre_asic_reset, asic_reset and post_asic_reset functions where is part > is exectued for all the GPUs in the hive before going to the next step. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 ++++++++++++++++++++--------- > 2 files changed, 264 insertions(+), 116 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 4ef5f7a..bd06d45 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -1026,6 +1026,9 @@ struct amdgpu_device { > unsigned long last_mm_index; > bool in_gpu_reset; > struct mutex lock_reset; > + > + int asic_reset_res; > + int resched; > }; > > static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) > @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; > > struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); > struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); > -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); > +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); > int amdgpu_xgmi_add_device(struct amdgpu_device *adev); > > /* > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > index cb06e68..8e94d7f 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) > return 0; > } > > -/** > - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough > - * > - * @adev: amdgpu device pointer > - * > - * attempt to do soft-reset or full-reset and reinitialize Asic > - * return 0 means succeeded otherwise failed > - */ > -static int amdgpu_device_reset(struct amdgpu_device *adev) > -{ > - bool need_full_reset, vram_lost = 0; > - int r; > - > - need_full_reset = amdgpu_device_ip_need_full_reset(adev); > - > - if (!need_full_reset) { > - amdgpu_device_ip_pre_soft_reset(adev); > - r = amdgpu_device_ip_soft_reset(adev); > - amdgpu_device_ip_post_soft_reset(adev); > - if (r || amdgpu_device_ip_check_soft_reset(adev)) { > - DRM_INFO("soft reset failed, will fallback to full reset!\n"); > - need_full_reset = true; > - } > - } > - > - if (need_full_reset) { > - r = amdgpu_device_ip_suspend(adev); > - > -retry: > - r = amdgpu_asic_reset(adev); > - /* post card */ > - amdgpu_atom_asic_init(adev->mode_info.atom_context); > - > - if (!r) { > - dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); > - r = amdgpu_device_ip_resume_phase1(adev); > - if (r) > - goto out; > - > - vram_lost = amdgpu_device_check_vram_lost(adev); > - if (vram_lost) { > - DRM_ERROR("VRAM is lost!\n"); > - atomic_inc(&adev->vram_lost_counter); > - } > - > - r = amdgpu_gtt_mgr_recover( > - &adev->mman.bdev.man[TTM_PL_TT]); > - if (r) > - goto out; > - > - r = amdgpu_device_fw_loading(adev); > - if (r) > - return r; > - > - r = amdgpu_device_ip_resume_phase2(adev); > - if (r) > - goto out; > - > - if (vram_lost) > - amdgpu_device_fill_reset_magic(adev); > - } > - } > - > -out: > - if (!r) { > - amdgpu_irq_gpu_reset_resume_helper(adev); > - r = amdgpu_ib_ring_tests(adev); > - if (r) { > - dev_err(adev->dev, "ib ring test failed (%d).\n", r); > - r = amdgpu_device_ip_suspend(adev); > - need_full_reset = true; > - goto retry; > - } > - } > - > - if (!r) > - r = amdgpu_device_recover_vram(adev); > - > - return r; > -} > > /** > * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf > @@ -3335,31 +3255,16 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) > return false; > } > > -/** > - * amdgpu_device_gpu_recover - reset the asic and recover scheduler > - * > - * @adev: amdgpu device pointer > - * @job: which job trigger hang > - * > - * Attempt to reset the GPU if it has hung (all asics). > - * Returns 0 for success or an error on failure. > - */ > -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > - struct amdgpu_job *job) > -{ > - int i, r, resched; > - > - dev_info(adev->dev, "GPU reset begin!\n"); > - > - mutex_lock(&adev->lock_reset); > - atomic_inc(&adev->gpu_reset_counter); > - adev->in_gpu_reset = 1; > > - /* Block kfd */ > - amdgpu_amdkfd_pre_reset(adev); > +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, > + struct amdgpu_job *job, > + bool *need_full_reset_arg) > +{ > + int i, r = 0; > + bool need_full_reset = *need_full_reset_arg; > > /* block TTM */ > - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); > + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); > > /* block all schedulers and reset given job's ring */ > for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { > @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > amdgpu_fence_driver_force_completion(ring); > } > > - if (amdgpu_sriov_vf(adev)) > - r = amdgpu_device_reset_sriov(adev, job ? false : true); > - else > - r = amdgpu_device_reset(adev); > + if (!amdgpu_sriov_vf(adev)) { > + > + if (!need_full_reset) > + need_full_reset = amdgpu_device_ip_need_full_reset(adev); > + > + if (!need_full_reset) { > + amdgpu_device_ip_pre_soft_reset(adev); > + r = amdgpu_device_ip_soft_reset(adev); > + amdgpu_device_ip_post_soft_reset(adev); > + if (r || amdgpu_device_ip_check_soft_reset(adev)) { > + DRM_INFO("soft reset failed, will fallback to full reset!\n"); > + need_full_reset = true; > + } > + } > + > + if (need_full_reset) > + r = amdgpu_device_ip_suspend(adev); > + > + *need_full_reset_arg = need_full_reset; > + } > + > + return r; > +} > + > +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, > + struct list_head *device_list_handle, > + bool *need_full_reset_arg) > +{ > + struct amdgpu_device *tmp_adev = NULL; > + bool need_full_reset = *need_full_reset_arg, vram_lost = false; > + int r = 0; > + > + /* > + * ASIC reset has to be done on all HGMI hive nodes ASAP > + * to allow proper links negotiation in FW (within 1 sec) > + */ > + if (need_full_reset) { > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + r = amdgpu_asic_reset(tmp_adev); > + if (r) > + DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s", > + r, tmp_adev->ddev->unique); > + } > + } > + > + > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + if (need_full_reset) { > + /* post card */ > + if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) > + DRM_WARN("asic atom init failed!"); > + > + if (!r) { > + dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); > + r = amdgpu_device_ip_resume_phase1(tmp_adev); > + if (r) > + goto out; > + > + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); > + if (vram_lost) { > + DRM_ERROR("VRAM is lost!\n"); > + atomic_inc(&tmp_adev->vram_lost_counter); > + } > + > + r = amdgpu_gtt_mgr_recover( > + &tmp_adev->mman.bdev.man[TTM_PL_TT]); > + if (r) > + goto out; > + > + r = amdgpu_device_fw_loading(tmp_adev); > + if (r) > + return r; > + > + r = amdgpu_device_ip_resume_phase2(tmp_adev); > + if (r) > + goto out; > + > + if (vram_lost) > + amdgpu_device_fill_reset_magic(tmp_adev); > + > + /* Update PSP FW topology after reset */ > + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) > + r = amdgpu_xgmi_update_topology(hive, tmp_adev); > + } > + } > + > + > +out: > + if (!r) { > + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); > + r = amdgpu_ib_ring_tests(tmp_adev); > + if (r) { > + dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); > + r = amdgpu_device_ip_suspend(tmp_adev); > + need_full_reset = true; > + r = -EAGAIN; > + goto end; > + } > + } > + > + if (!r) > + r = amdgpu_device_recover_vram(tmp_adev); > + else > + tmp_adev->asic_reset_res = r; > + } > + > +end: > + *need_full_reset_arg = need_full_reset; > + return r; > +} > + > +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, > + struct amdgpu_job *job) > +{ > + int i; > > for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { > struct amdgpu_ring *ring = adev->rings[i]; > @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > * or all rings (in the case @job is NULL) > * after above amdgpu_reset accomplished > */ > - if ((!job || job->base.sched == &ring->sched) && !r) > + if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res) > drm_sched_job_recovery(&ring->sched); > > kthread_unpark(ring->sched.thread); > @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > drm_helper_resume_force_mode(adev->ddev); > } > > - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); > + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); > > - if (r) { > - /* bad news, how to tell it to userspace ? */ > - dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); > - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); > - } else { > - dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); > - } > + adev->asic_reset_res = adev->resched = 0; > + > +} > > +static void amdgpu_lock_adev(struct amdgpu_device *adev) > +{ > + mutex_lock(&adev->lock_reset); > + atomic_inc(&adev->gpu_reset_counter); > + adev->in_gpu_reset = 1; > + /* Block kfd */ > + amdgpu_amdkfd_pre_reset(adev); > +} > + > +static void amdgpu_unlock_adev(struct amdgpu_device *adev) > +{ > /*unlock kfd */ > amdgpu_amdkfd_post_reset(adev); > amdgpu_vf_error_trans_all(adev); > adev->in_gpu_reset = 0; > mutex_unlock(&adev->lock_reset); > +} For consistency add "device" to the names of these functions. static void amdgpu_device_unlock_adev(struct amdgpu_device *adev) static void amdgpu_device_lock_adev(struct amdgpu_device *adev) WIth that fixed: Reviewed-by: Alex Deucher <alexander.deucher@amd.com> > + > + > +/** > + * amdgpu_device_gpu_recover - reset the asic and recover scheduler > + * > + * @adev: amdgpu device pointer > + * @job: which job trigger hang > + * > + * Attempt to reset the GPU if it has hung (all asics). > + * Attempt to do soft-reset or full-reset and reinitialize Asic > + * Returns 0 for success or an error on failure. > + */ > + > +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > + struct amdgpu_job *job) > +{ > + int r; > + struct amdgpu_hive_info *hive = NULL; > + bool need_full_reset = false; > + struct amdgpu_device *tmp_adev = NULL; > + struct list_head device_list, *device_list_handle = NULL; > + > + INIT_LIST_HEAD(&device_list); > + > + dev_info(adev->dev, "GPU reset begin!\n"); > + > + /* > + * In case of XGMI hive disallow concurrent resets to be triggered > + * by different nodes. > + */ > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_lock(&xgmi_mutex); > + > + /* Start with adev pre asic reset first for soft reset check.*/ > + amdgpu_lock_adev(adev); > + r = amdgpu_device_pre_asic_reset(adev, > + job, > + &need_full_reset); > + if (r) { > + /*TODO Should we stop ?*/ > + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", > + r, adev->ddev->unique); > + adev->asic_reset_res = r; > + } > + > + /* Build list of devices to reset */ > + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { > + hive = amdgpu_get_xgmi_hive(adev); > + if (!hive) { > + r = -ENODEV; > + > + amdgpu_unlock_adev(adev); > + > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_unlock(&xgmi_mutex); > + return r; > + } > + > + /* > + * In case we are in XGMI hive mode device reset is done for all the > + * nodes in the hive to retrain all XGMI links and hence the reset > + * sequence is executed in loop on all nodes. > + */ > + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); > + } else { > + list_add_tail(&adev->gmc.xgmi.head, &device_list); > + device_list_handle = &device_list; > + } > + > +retry: /* Rest of adevs pre asic reset from XGMI hive. */ > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + > + if (tmp_adev == adev) > + continue; > + > + dev_info(tmp_adev->dev, "GPU reset begin for drm dev %s!\n", adev->ddev->unique); > + > + amdgpu_lock_adev(tmp_adev); > + r = amdgpu_device_pre_asic_reset(tmp_adev, > + NULL, > + &need_full_reset); > + /*TODO Should we stop ?*/ > + if (r) { > + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", > + r, tmp_adev->ddev->unique); > + tmp_adev->asic_reset_res = r; > + } > + } > + > + /* Actual ASIC resets if needed.*/ > + /* TODO Implement XGMI hive reset logic for SRIOV */ > + if (amdgpu_sriov_vf(adev)) { > + r = amdgpu_device_reset_sriov(adev, job ? false : true); > + if (r) > + adev->asic_reset_res = r; > + } else { > + r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); > + if (r && r == -EAGAIN) > + goto retry; > + } > + > + /* Post ASIC reset for all devs .*/ > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); > + > + if (r) { > + /* bad news, how to tell it to userspace ? */ > + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); > + amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); > + } else { > + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter)); > + } > + > + amdgpu_unlock_adev(tmp_adev); > + } > + > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_unlock(&xgmi_mutex); > + > + if (r) > + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); > return r; > } > > -- > 2.7.4 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <1542823821-15631-6-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org> 2018-11-21 19:45 ` Alex Deucher @ 2018-11-21 20:49 ` Liu, Shaoyun [not found] ` <ef758cf9-9e27-9807-4e25-47148782249e-5C7GfCeVMHo@public.gmane.org> 1 sibling, 1 reply; 21+ messages in thread From: Liu, Shaoyun @ 2018-11-21 20:49 UTC (permalink / raw) To: Grodzovsky, Andrey, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk I saw you use the global xgmi_mutex to prevent concurrent reset to be triggered by different nodes , but after the mutex been released , current node may grap the mutex and continue to do another reset . Maybe we should check the GPU status and skip the reset in this case since the GPU may already be in good state . Regards shaoyun.liu On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: > For XGMI hive case do reset in steps where each step iterates over > all devs in hive. This especially important for asic reset > since all PSP FW in hive must come up within a limited time > (around 1 sec) to properply negotiate the link. > Do this by refactoring amdgpu_device_gpu_recover and amdgpu_device_reset > into pre_asic_reset, asic_reset and post_asic_reset functions where is part > is exectued for all the GPUs in the hive before going to the next step. > > Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 ++++++++++++++++++++--------- > 2 files changed, 264 insertions(+), 116 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > index 4ef5f7a..bd06d45 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h > @@ -1026,6 +1026,9 @@ struct amdgpu_device { > unsigned long last_mm_index; > bool in_gpu_reset; > struct mutex lock_reset; > + > + int asic_reset_res; > + int resched; > }; > > static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) > @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; > > struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); > struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); > -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); > +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); > int amdgpu_xgmi_add_device(struct amdgpu_device *adev); > > /* > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > index cb06e68..8e94d7f 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c > @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) > return 0; > } > > -/** > - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough > - * > - * @adev: amdgpu device pointer > - * > - * attempt to do soft-reset or full-reset and reinitialize Asic > - * return 0 means succeeded otherwise failed > - */ > -static int amdgpu_device_reset(struct amdgpu_device *adev) > -{ > - bool need_full_reset, vram_lost = 0; > - int r; > - > - need_full_reset = amdgpu_device_ip_need_full_reset(adev); > - > - if (!need_full_reset) { > - amdgpu_device_ip_pre_soft_reset(adev); > - r = amdgpu_device_ip_soft_reset(adev); > - amdgpu_device_ip_post_soft_reset(adev); > - if (r || amdgpu_device_ip_check_soft_reset(adev)) { > - DRM_INFO("soft reset failed, will fallback to full reset!\n"); > - need_full_reset = true; > - } > - } > - > - if (need_full_reset) { > - r = amdgpu_device_ip_suspend(adev); > - > -retry: > - r = amdgpu_asic_reset(adev); > - /* post card */ > - amdgpu_atom_asic_init(adev->mode_info.atom_context); > - > - if (!r) { > - dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); > - r = amdgpu_device_ip_resume_phase1(adev); > - if (r) > - goto out; > - > - vram_lost = amdgpu_device_check_vram_lost(adev); > - if (vram_lost) { > - DRM_ERROR("VRAM is lost!\n"); > - atomic_inc(&adev->vram_lost_counter); > - } > - > - r = amdgpu_gtt_mgr_recover( > - &adev->mman.bdev.man[TTM_PL_TT]); > - if (r) > - goto out; > - > - r = amdgpu_device_fw_loading(adev); > - if (r) > - return r; > - > - r = amdgpu_device_ip_resume_phase2(adev); > - if (r) > - goto out; > - > - if (vram_lost) > - amdgpu_device_fill_reset_magic(adev); > - } > - } > - > -out: > - if (!r) { > - amdgpu_irq_gpu_reset_resume_helper(adev); > - r = amdgpu_ib_ring_tests(adev); > - if (r) { > - dev_err(adev->dev, "ib ring test failed (%d).\n", r); > - r = amdgpu_device_ip_suspend(adev); > - need_full_reset = true; > - goto retry; > - } > - } > - > - if (!r) > - r = amdgpu_device_recover_vram(adev); > - > - return r; > -} > > /** > * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf > @@ -3335,31 +3255,16 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) > return false; > } > > -/** > - * amdgpu_device_gpu_recover - reset the asic and recover scheduler > - * > - * @adev: amdgpu device pointer > - * @job: which job trigger hang > - * > - * Attempt to reset the GPU if it has hung (all asics). > - * Returns 0 for success or an error on failure. > - */ > -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > - struct amdgpu_job *job) > -{ > - int i, r, resched; > - > - dev_info(adev->dev, "GPU reset begin!\n"); > - > - mutex_lock(&adev->lock_reset); > - atomic_inc(&adev->gpu_reset_counter); > - adev->in_gpu_reset = 1; > > - /* Block kfd */ > - amdgpu_amdkfd_pre_reset(adev); > +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, > + struct amdgpu_job *job, > + bool *need_full_reset_arg) > +{ > + int i, r = 0; > + bool need_full_reset = *need_full_reset_arg; > > /* block TTM */ > - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); > + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); > > /* block all schedulers and reset given job's ring */ > for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { > @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > amdgpu_fence_driver_force_completion(ring); > } > > - if (amdgpu_sriov_vf(adev)) > - r = amdgpu_device_reset_sriov(adev, job ? false : true); > - else > - r = amdgpu_device_reset(adev); > + if (!amdgpu_sriov_vf(adev)) { > + > + if (!need_full_reset) > + need_full_reset = amdgpu_device_ip_need_full_reset(adev); > + > + if (!need_full_reset) { > + amdgpu_device_ip_pre_soft_reset(adev); > + r = amdgpu_device_ip_soft_reset(adev); > + amdgpu_device_ip_post_soft_reset(adev); > + if (r || amdgpu_device_ip_check_soft_reset(adev)) { > + DRM_INFO("soft reset failed, will fallback to full reset!\n"); > + need_full_reset = true; > + } > + } > + > + if (need_full_reset) > + r = amdgpu_device_ip_suspend(adev); > + > + *need_full_reset_arg = need_full_reset; > + } > + > + return r; > +} > + > +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, > + struct list_head *device_list_handle, > + bool *need_full_reset_arg) > +{ > + struct amdgpu_device *tmp_adev = NULL; > + bool need_full_reset = *need_full_reset_arg, vram_lost = false; > + int r = 0; > + > + /* > + * ASIC reset has to be done on all HGMI hive nodes ASAP > + * to allow proper links negotiation in FW (within 1 sec) > + */ > + if (need_full_reset) { > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + r = amdgpu_asic_reset(tmp_adev); > + if (r) > + DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s", > + r, tmp_adev->ddev->unique); > + } > + } > + > + > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + if (need_full_reset) { > + /* post card */ > + if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) > + DRM_WARN("asic atom init failed!"); > + > + if (!r) { > + dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); > + r = amdgpu_device_ip_resume_phase1(tmp_adev); > + if (r) > + goto out; > + > + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); > + if (vram_lost) { > + DRM_ERROR("VRAM is lost!\n"); > + atomic_inc(&tmp_adev->vram_lost_counter); > + } > + > + r = amdgpu_gtt_mgr_recover( > + &tmp_adev->mman.bdev.man[TTM_PL_TT]); > + if (r) > + goto out; > + > + r = amdgpu_device_fw_loading(tmp_adev); > + if (r) > + return r; > + > + r = amdgpu_device_ip_resume_phase2(tmp_adev); > + if (r) > + goto out; > + > + if (vram_lost) > + amdgpu_device_fill_reset_magic(tmp_adev); > + > + /* Update PSP FW topology after reset */ > + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) > + r = amdgpu_xgmi_update_topology(hive, tmp_adev); > + } > + } > + > + > +out: > + if (!r) { > + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); > + r = amdgpu_ib_ring_tests(tmp_adev); > + if (r) { > + dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); > + r = amdgpu_device_ip_suspend(tmp_adev); > + need_full_reset = true; > + r = -EAGAIN; > + goto end; > + } > + } > + > + if (!r) > + r = amdgpu_device_recover_vram(tmp_adev); > + else > + tmp_adev->asic_reset_res = r; > + } > + > +end: > + *need_full_reset_arg = need_full_reset; > + return r; > +} > + > +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, > + struct amdgpu_job *job) > +{ > + int i; > > for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { > struct amdgpu_ring *ring = adev->rings[i]; > @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > * or all rings (in the case @job is NULL) > * after above amdgpu_reset accomplished > */ > - if ((!job || job->base.sched == &ring->sched) && !r) > + if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res) > drm_sched_job_recovery(&ring->sched); > > kthread_unpark(ring->sched.thread); > @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > drm_helper_resume_force_mode(adev->ddev); > } > > - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); > + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); > > - if (r) { > - /* bad news, how to tell it to userspace ? */ > - dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); > - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); > - } else { > - dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); > - } > + adev->asic_reset_res = adev->resched = 0; > + > +} > > +static void amdgpu_lock_adev(struct amdgpu_device *adev) > +{ > + mutex_lock(&adev->lock_reset); > + atomic_inc(&adev->gpu_reset_counter); > + adev->in_gpu_reset = 1; > + /* Block kfd */ > + amdgpu_amdkfd_pre_reset(adev); > +} > + > +static void amdgpu_unlock_adev(struct amdgpu_device *adev) > +{ > /*unlock kfd */ > amdgpu_amdkfd_post_reset(adev); > amdgpu_vf_error_trans_all(adev); > adev->in_gpu_reset = 0; > mutex_unlock(&adev->lock_reset); > +} > + > + > +/** > + * amdgpu_device_gpu_recover - reset the asic and recover scheduler > + * > + * @adev: amdgpu device pointer > + * @job: which job trigger hang > + * > + * Attempt to reset the GPU if it has hung (all asics). > + * Attempt to do soft-reset or full-reset and reinitialize Asic > + * Returns 0 for success or an error on failure. > + */ > + > +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, > + struct amdgpu_job *job) > +{ > + int r; > + struct amdgpu_hive_info *hive = NULL; > + bool need_full_reset = false; > + struct amdgpu_device *tmp_adev = NULL; > + struct list_head device_list, *device_list_handle = NULL; > + > + INIT_LIST_HEAD(&device_list); > + > + dev_info(adev->dev, "GPU reset begin!\n"); > + > + /* > + * In case of XGMI hive disallow concurrent resets to be triggered > + * by different nodes. > + */ > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_lock(&xgmi_mutex); > + > + /* Start with adev pre asic reset first for soft reset check.*/ > + amdgpu_lock_adev(adev); > + r = amdgpu_device_pre_asic_reset(adev, > + job, > + &need_full_reset); > + if (r) { > + /*TODO Should we stop ?*/ > + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", > + r, adev->ddev->unique); > + adev->asic_reset_res = r; > + } > + > + /* Build list of devices to reset */ > + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { > + hive = amdgpu_get_xgmi_hive(adev); > + if (!hive) { > + r = -ENODEV; > + > + amdgpu_unlock_adev(adev); > + > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_unlock(&xgmi_mutex); > + return r; > + } > + > + /* > + * In case we are in XGMI hive mode device reset is done for all the > + * nodes in the hive to retrain all XGMI links and hence the reset > + * sequence is executed in loop on all nodes. > + */ > + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); > + } else { > + list_add_tail(&adev->gmc.xgmi.head, &device_list); > + device_list_handle = &device_list; > + } > + > +retry: /* Rest of adevs pre asic reset from XGMI hive. */ > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + > + if (tmp_adev == adev) > + continue; > + > + dev_info(tmp_adev->dev, "GPU reset begin for drm dev %s!\n", adev->ddev->unique); > + > + amdgpu_lock_adev(tmp_adev); > + r = amdgpu_device_pre_asic_reset(tmp_adev, > + NULL, > + &need_full_reset); > + /*TODO Should we stop ?*/ > + if (r) { > + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", > + r, tmp_adev->ddev->unique); > + tmp_adev->asic_reset_res = r; > + } > + } > + > + /* Actual ASIC resets if needed.*/ > + /* TODO Implement XGMI hive reset logic for SRIOV */ > + if (amdgpu_sriov_vf(adev)) { > + r = amdgpu_device_reset_sriov(adev, job ? false : true); > + if (r) > + adev->asic_reset_res = r; > + } else { > + r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); > + if (r && r == -EAGAIN) > + goto retry; > + } > + > + /* Post ASIC reset for all devs .*/ > + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { > + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); > + > + if (r) { > + /* bad news, how to tell it to userspace ? */ > + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); > + amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); > + } else { > + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter)); > + } > + > + amdgpu_unlock_adev(tmp_adev); > + } > + > + if (adev->gmc.xgmi.num_physical_nodes > 1) > + mutex_unlock(&xgmi_mutex); > + > + if (r) > + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); > return r; > } > _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <ef758cf9-9e27-9807-4e25-47148782249e-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <ef758cf9-9e27-9807-4e25-47148782249e-5C7GfCeVMHo@public.gmane.org> @ 2018-11-21 22:02 ` Grodzovsky, Andrey [not found] ` <5f257299-4833-82b7-83ec-75bf02c4e441-5C7GfCeVMHo@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Grodzovsky, Andrey @ 2018-11-21 22:02 UTC (permalink / raw) To: Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk Depends what was the reason for triggering the reset for that node how do we know ? If the reason was RAS error that probably not hard to check all errors are cleared, but if the reason was job timeout on that specific node I will need to recheck that no jobs are left in incomplete state state. And if the reason is manual gpu reset trigger from sysfs, then what's the policy ? Sounds to me it's just easier to go ahead and allow all the pending resets to proceed unless there is a clear and quick criteria you can check after you grab the mutex then sure - but I don't know what it would be. Andrey On 11/21/2018 03:49 PM, Liu, Shaoyun wrote: > I saw you use the global xgmi_mutex to prevent concurrent reset to be > triggered by different nodes , but after the mutex been released , > current node may grap the mutex and continue to do another reset . > Maybe we should check the GPU status and skip the reset in this case > since the GPU may already be in good state . > > Regards > > shaoyun.liu > > On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: >> For XGMI hive case do reset in steps where each step iterates over >> all devs in hive. This especially important for asic reset >> since all PSP FW in hive must come up within a limited time >> (around 1 sec) to properply negotiate the link. >> Do this by refactoring amdgpu_device_gpu_recover and amdgpu_device_reset >> into pre_asic_reset, asic_reset and post_asic_reset functions where is part >> is exectued for all the GPUs in the hive before going to the next step. >> >> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >> --- >> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- >> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 ++++++++++++++++++++--------- >> 2 files changed, 264 insertions(+), 116 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> index 4ef5f7a..bd06d45 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >> @@ -1026,6 +1026,9 @@ struct amdgpu_device { >> unsigned long last_mm_index; >> bool in_gpu_reset; >> struct mutex lock_reset; >> + >> + int asic_reset_res; >> + int resched; >> }; >> >> static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) >> @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; >> >> struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); >> struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); >> -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); >> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); >> >> /* >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >> index cb06e68..8e94d7f 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >> @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) >> return 0; >> } >> >> -/** >> - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough >> - * >> - * @adev: amdgpu device pointer >> - * >> - * attempt to do soft-reset or full-reset and reinitialize Asic >> - * return 0 means succeeded otherwise failed >> - */ >> -static int amdgpu_device_reset(struct amdgpu_device *adev) >> -{ >> - bool need_full_reset, vram_lost = 0; >> - int r; >> - >> - need_full_reset = amdgpu_device_ip_need_full_reset(adev); >> - >> - if (!need_full_reset) { >> - amdgpu_device_ip_pre_soft_reset(adev); >> - r = amdgpu_device_ip_soft_reset(adev); >> - amdgpu_device_ip_post_soft_reset(adev); >> - if (r || amdgpu_device_ip_check_soft_reset(adev)) { >> - DRM_INFO("soft reset failed, will fallback to full reset!\n"); >> - need_full_reset = true; >> - } >> - } >> - >> - if (need_full_reset) { >> - r = amdgpu_device_ip_suspend(adev); >> - >> -retry: >> - r = amdgpu_asic_reset(adev); >> - /* post card */ >> - amdgpu_atom_asic_init(adev->mode_info.atom_context); >> - >> - if (!r) { >> - dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); >> - r = amdgpu_device_ip_resume_phase1(adev); >> - if (r) >> - goto out; >> - >> - vram_lost = amdgpu_device_check_vram_lost(adev); >> - if (vram_lost) { >> - DRM_ERROR("VRAM is lost!\n"); >> - atomic_inc(&adev->vram_lost_counter); >> - } >> - >> - r = amdgpu_gtt_mgr_recover( >> - &adev->mman.bdev.man[TTM_PL_TT]); >> - if (r) >> - goto out; >> - >> - r = amdgpu_device_fw_loading(adev); >> - if (r) >> - return r; >> - >> - r = amdgpu_device_ip_resume_phase2(adev); >> - if (r) >> - goto out; >> - >> - if (vram_lost) >> - amdgpu_device_fill_reset_magic(adev); >> - } >> - } >> - >> -out: >> - if (!r) { >> - amdgpu_irq_gpu_reset_resume_helper(adev); >> - r = amdgpu_ib_ring_tests(adev); >> - if (r) { >> - dev_err(adev->dev, "ib ring test failed (%d).\n", r); >> - r = amdgpu_device_ip_suspend(adev); >> - need_full_reset = true; >> - goto retry; >> - } >> - } >> - >> - if (!r) >> - r = amdgpu_device_recover_vram(adev); >> - >> - return r; >> -} >> >> /** >> * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf >> @@ -3335,31 +3255,16 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) >> return false; >> } >> >> -/** >> - * amdgpu_device_gpu_recover - reset the asic and recover scheduler >> - * >> - * @adev: amdgpu device pointer >> - * @job: which job trigger hang >> - * >> - * Attempt to reset the GPU if it has hung (all asics). >> - * Returns 0 for success or an error on failure. >> - */ >> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >> - struct amdgpu_job *job) >> -{ >> - int i, r, resched; >> - >> - dev_info(adev->dev, "GPU reset begin!\n"); >> - >> - mutex_lock(&adev->lock_reset); >> - atomic_inc(&adev->gpu_reset_counter); >> - adev->in_gpu_reset = 1; >> >> - /* Block kfd */ >> - amdgpu_amdkfd_pre_reset(adev); >> +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, >> + struct amdgpu_job *job, >> + bool *need_full_reset_arg) >> +{ >> + int i, r = 0; >> + bool need_full_reset = *need_full_reset_arg; >> >> /* block TTM */ >> - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >> + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >> >> /* block all schedulers and reset given job's ring */ >> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >> @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >> amdgpu_fence_driver_force_completion(ring); >> } >> >> - if (amdgpu_sriov_vf(adev)) >> - r = amdgpu_device_reset_sriov(adev, job ? false : true); >> - else >> - r = amdgpu_device_reset(adev); >> + if (!amdgpu_sriov_vf(adev)) { >> + >> + if (!need_full_reset) >> + need_full_reset = amdgpu_device_ip_need_full_reset(adev); >> + >> + if (!need_full_reset) { >> + amdgpu_device_ip_pre_soft_reset(adev); >> + r = amdgpu_device_ip_soft_reset(adev); >> + amdgpu_device_ip_post_soft_reset(adev); >> + if (r || amdgpu_device_ip_check_soft_reset(adev)) { >> + DRM_INFO("soft reset failed, will fallback to full reset!\n"); >> + need_full_reset = true; >> + } >> + } >> + >> + if (need_full_reset) >> + r = amdgpu_device_ip_suspend(adev); >> + >> + *need_full_reset_arg = need_full_reset; >> + } >> + >> + return r; >> +} >> + >> +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, >> + struct list_head *device_list_handle, >> + bool *need_full_reset_arg) >> +{ >> + struct amdgpu_device *tmp_adev = NULL; >> + bool need_full_reset = *need_full_reset_arg, vram_lost = false; >> + int r = 0; >> + >> + /* >> + * ASIC reset has to be done on all HGMI hive nodes ASAP >> + * to allow proper links negotiation in FW (within 1 sec) >> + */ >> + if (need_full_reset) { >> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >> + r = amdgpu_asic_reset(tmp_adev); >> + if (r) >> + DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s", >> + r, tmp_adev->ddev->unique); >> + } >> + } >> + >> + >> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >> + if (need_full_reset) { >> + /* post card */ >> + if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) >> + DRM_WARN("asic atom init failed!"); >> + >> + if (!r) { >> + dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); >> + r = amdgpu_device_ip_resume_phase1(tmp_adev); >> + if (r) >> + goto out; >> + >> + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); >> + if (vram_lost) { >> + DRM_ERROR("VRAM is lost!\n"); >> + atomic_inc(&tmp_adev->vram_lost_counter); >> + } >> + >> + r = amdgpu_gtt_mgr_recover( >> + &tmp_adev->mman.bdev.man[TTM_PL_TT]); >> + if (r) >> + goto out; >> + >> + r = amdgpu_device_fw_loading(tmp_adev); >> + if (r) >> + return r; >> + >> + r = amdgpu_device_ip_resume_phase2(tmp_adev); >> + if (r) >> + goto out; >> + >> + if (vram_lost) >> + amdgpu_device_fill_reset_magic(tmp_adev); >> + >> + /* Update PSP FW topology after reset */ >> + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) >> + r = amdgpu_xgmi_update_topology(hive, tmp_adev); >> + } >> + } >> + >> + >> +out: >> + if (!r) { >> + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); >> + r = amdgpu_ib_ring_tests(tmp_adev); >> + if (r) { >> + dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); >> + r = amdgpu_device_ip_suspend(tmp_adev); >> + need_full_reset = true; >> + r = -EAGAIN; >> + goto end; >> + } >> + } >> + >> + if (!r) >> + r = amdgpu_device_recover_vram(tmp_adev); >> + else >> + tmp_adev->asic_reset_res = r; >> + } >> + >> +end: >> + *need_full_reset_arg = need_full_reset; >> + return r; >> +} >> + >> +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, >> + struct amdgpu_job *job) >> +{ >> + int i; >> >> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >> struct amdgpu_ring *ring = adev->rings[i]; >> @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >> * or all rings (in the case @job is NULL) >> * after above amdgpu_reset accomplished >> */ >> - if ((!job || job->base.sched == &ring->sched) && !r) >> + if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res) >> drm_sched_job_recovery(&ring->sched); >> >> kthread_unpark(ring->sched.thread); >> @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >> drm_helper_resume_force_mode(adev->ddev); >> } >> >> - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); >> + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); >> >> - if (r) { >> - /* bad news, how to tell it to userspace ? */ >> - dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); >> - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >> - } else { >> - dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); >> - } >> + adev->asic_reset_res = adev->resched = 0; >> + >> +} >> >> +static void amdgpu_lock_adev(struct amdgpu_device *adev) >> +{ >> + mutex_lock(&adev->lock_reset); >> + atomic_inc(&adev->gpu_reset_counter); >> + adev->in_gpu_reset = 1; >> + /* Block kfd */ >> + amdgpu_amdkfd_pre_reset(adev); >> +} >> + >> +static void amdgpu_unlock_adev(struct amdgpu_device *adev) >> +{ >> /*unlock kfd */ >> amdgpu_amdkfd_post_reset(adev); >> amdgpu_vf_error_trans_all(adev); >> adev->in_gpu_reset = 0; >> mutex_unlock(&adev->lock_reset); >> +} >> + >> + >> +/** >> + * amdgpu_device_gpu_recover - reset the asic and recover scheduler >> + * >> + * @adev: amdgpu device pointer >> + * @job: which job trigger hang >> + * >> + * Attempt to reset the GPU if it has hung (all asics). >> + * Attempt to do soft-reset or full-reset and reinitialize Asic >> + * Returns 0 for success or an error on failure. >> + */ >> + >> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >> + struct amdgpu_job *job) >> +{ >> + int r; >> + struct amdgpu_hive_info *hive = NULL; >> + bool need_full_reset = false; >> + struct amdgpu_device *tmp_adev = NULL; >> + struct list_head device_list, *device_list_handle = NULL; >> + >> + INIT_LIST_HEAD(&device_list); >> + >> + dev_info(adev->dev, "GPU reset begin!\n"); >> + >> + /* >> + * In case of XGMI hive disallow concurrent resets to be triggered >> + * by different nodes. >> + */ >> + if (adev->gmc.xgmi.num_physical_nodes > 1) >> + mutex_lock(&xgmi_mutex); >> + >> + /* Start with adev pre asic reset first for soft reset check.*/ >> + amdgpu_lock_adev(adev); >> + r = amdgpu_device_pre_asic_reset(adev, >> + job, >> + &need_full_reset); >> + if (r) { >> + /*TODO Should we stop ?*/ >> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", >> + r, adev->ddev->unique); >> + adev->asic_reset_res = r; >> + } >> + >> + /* Build list of devices to reset */ >> + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { >> + hive = amdgpu_get_xgmi_hive(adev); >> + if (!hive) { >> + r = -ENODEV; >> + >> + amdgpu_unlock_adev(adev); >> + >> + if (adev->gmc.xgmi.num_physical_nodes > 1) >> + mutex_unlock(&xgmi_mutex); >> + return r; >> + } >> + >> + /* >> + * In case we are in XGMI hive mode device reset is done for all the >> + * nodes in the hive to retrain all XGMI links and hence the reset >> + * sequence is executed in loop on all nodes. >> + */ >> + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); >> + } else { >> + list_add_tail(&adev->gmc.xgmi.head, &device_list); >> + device_list_handle = &device_list; >> + } >> + >> +retry: /* Rest of adevs pre asic reset from XGMI hive. */ >> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >> + >> + if (tmp_adev == adev) >> + continue; >> + >> + dev_info(tmp_adev->dev, "GPU reset begin for drm dev %s!\n", adev->ddev->unique); >> + >> + amdgpu_lock_adev(tmp_adev); >> + r = amdgpu_device_pre_asic_reset(tmp_adev, >> + NULL, >> + &need_full_reset); >> + /*TODO Should we stop ?*/ >> + if (r) { >> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", >> + r, tmp_adev->ddev->unique); >> + tmp_adev->asic_reset_res = r; >> + } >> + } >> + >> + /* Actual ASIC resets if needed.*/ >> + /* TODO Implement XGMI hive reset logic for SRIOV */ >> + if (amdgpu_sriov_vf(adev)) { >> + r = amdgpu_device_reset_sriov(adev, job ? false : true); >> + if (r) >> + adev->asic_reset_res = r; >> + } else { >> + r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); >> + if (r && r == -EAGAIN) >> + goto retry; >> + } >> + >> + /* Post ASIC reset for all devs .*/ >> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >> + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); >> + >> + if (r) { >> + /* bad news, how to tell it to userspace ? */ >> + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); >> + amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >> + } else { >> + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter)); >> + } >> + >> + amdgpu_unlock_adev(tmp_adev); >> + } >> + >> + if (adev->gmc.xgmi.num_physical_nodes > 1) >> + mutex_unlock(&xgmi_mutex); >> + >> + if (r) >> + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); >> return r; >> } >> _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <5f257299-4833-82b7-83ec-75bf02c4e441-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <5f257299-4833-82b7-83ec-75bf02c4e441-5C7GfCeVMHo@public.gmane.org> @ 2018-11-22 11:16 ` Christian König [not found] ` <8e9f51a4-7f0a-c435-c507-34eea96e0b08-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Christian König @ 2018-11-22 11:16 UTC (permalink / raw) To: Grodzovsky, Andrey, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk How about using a lock per hive and then acquiring that with trylock() instead? This way you should at least catch cases where multiple causes try to reset the same hive at the same time. True that there is still some racing involved, but it's at least a good start. Additional to that I would try improve the pre, middle, post handling towards checking if we made some progress in between. In other words we stop all schedulers in the pre handling and disconnect the scheduler fences from the hardware fence like I did in patch "drm/sched: fix timeout handling v2". Then before we do the actual reset in the middle handling we check if the offending job has completed or at least made some progress in the meantime. In the case of a manual reset we skip that because we don't have an offending job to check. In the post handling we stitch everything together again and start the scheduler to go on with job submission. Christian. Am 21.11.18 um 23:02 schrieb Grodzovsky, Andrey: > Depends what was the reason for triggering the reset for that node how > do we know ? > If the reason was RAS error that probably not hard to check all errors > are cleared, but > if the reason was job timeout on that specific node I will need to > recheck that no jobs are left in incomplete state > state. And if the reason is manual gpu reset trigger from sysfs, then > what's the policy ? > Sounds to me it's just easier to go ahead and allow all the pending > resets to proceed unless there is > a clear and quick criteria you can check after you grab the mutex then > sure - but I don't know what it would be. > > Andrey > > On 11/21/2018 03:49 PM, Liu, Shaoyun wrote: >> I saw you use the global xgmi_mutex to prevent concurrent reset to be >> triggered by different nodes , but after the mutex been released , >> current node may grap the mutex and continue to do another reset . >> Maybe we should check the GPU status and skip the reset in this case >> since the GPU may already be in good state . >> >> Regards >> >> shaoyun.liu >> >> On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: >>> For XGMI hive case do reset in steps where each step iterates over >>> all devs in hive. This especially important for asic reset >>> since all PSP FW in hive must come up within a limited time >>> (around 1 sec) to properply negotiate the link. >>> Do this by refactoring amdgpu_device_gpu_recover and amdgpu_device_reset >>> into pre_asic_reset, asic_reset and post_asic_reset functions where is part >>> is exectued for all the GPUs in the hive before going to the next step. >>> >>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >>> --- >>> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- >>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 ++++++++++++++++++++--------- >>> 2 files changed, 264 insertions(+), 116 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>> index 4ef5f7a..bd06d45 100644 >>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>> @@ -1026,6 +1026,9 @@ struct amdgpu_device { >>> unsigned long last_mm_index; >>> bool in_gpu_reset; >>> struct mutex lock_reset; >>> + >>> + int asic_reset_res; >>> + int resched; >>> }; >>> >>> static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) >>> @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; >>> >>> struct list_head *amdgpu_xgmi_get_adev_list_handle(struct amdgpu_hive_info *hive); >>> struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev); >>> -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >>> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, struct amdgpu_device *adev); >>> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); >>> >>> /* >>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>> index cb06e68..8e94d7f 100644 >>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>> @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) >>> return 0; >>> } >>> >>> -/** >>> - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough >>> - * >>> - * @adev: amdgpu device pointer >>> - * >>> - * attempt to do soft-reset or full-reset and reinitialize Asic >>> - * return 0 means succeeded otherwise failed >>> - */ >>> -static int amdgpu_device_reset(struct amdgpu_device *adev) >>> -{ >>> - bool need_full_reset, vram_lost = 0; >>> - int r; >>> - >>> - need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>> - >>> - if (!need_full_reset) { >>> - amdgpu_device_ip_pre_soft_reset(adev); >>> - r = amdgpu_device_ip_soft_reset(adev); >>> - amdgpu_device_ip_post_soft_reset(adev); >>> - if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>> - DRM_INFO("soft reset failed, will fallback to full reset!\n"); >>> - need_full_reset = true; >>> - } >>> - } >>> - >>> - if (need_full_reset) { >>> - r = amdgpu_device_ip_suspend(adev); >>> - >>> -retry: >>> - r = amdgpu_asic_reset(adev); >>> - /* post card */ >>> - amdgpu_atom_asic_init(adev->mode_info.atom_context); >>> - >>> - if (!r) { >>> - dev_info(adev->dev, "GPU reset succeeded, trying to resume\n"); >>> - r = amdgpu_device_ip_resume_phase1(adev); >>> - if (r) >>> - goto out; >>> - >>> - vram_lost = amdgpu_device_check_vram_lost(adev); >>> - if (vram_lost) { >>> - DRM_ERROR("VRAM is lost!\n"); >>> - atomic_inc(&adev->vram_lost_counter); >>> - } >>> - >>> - r = amdgpu_gtt_mgr_recover( >>> - &adev->mman.bdev.man[TTM_PL_TT]); >>> - if (r) >>> - goto out; >>> - >>> - r = amdgpu_device_fw_loading(adev); >>> - if (r) >>> - return r; >>> - >>> - r = amdgpu_device_ip_resume_phase2(adev); >>> - if (r) >>> - goto out; >>> - >>> - if (vram_lost) >>> - amdgpu_device_fill_reset_magic(adev); >>> - } >>> - } >>> - >>> -out: >>> - if (!r) { >>> - amdgpu_irq_gpu_reset_resume_helper(adev); >>> - r = amdgpu_ib_ring_tests(adev); >>> - if (r) { >>> - dev_err(adev->dev, "ib ring test failed (%d).\n", r); >>> - r = amdgpu_device_ip_suspend(adev); >>> - need_full_reset = true; >>> - goto retry; >>> - } >>> - } >>> - >>> - if (!r) >>> - r = amdgpu_device_recover_vram(adev); >>> - >>> - return r; >>> -} >>> >>> /** >>> * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf >>> @@ -3335,31 +3255,16 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) >>> return false; >>> } >>> >>> -/** >>> - * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>> - * >>> - * @adev: amdgpu device pointer >>> - * @job: which job trigger hang >>> - * >>> - * Attempt to reset the GPU if it has hung (all asics). >>> - * Returns 0 for success or an error on failure. >>> - */ >>> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>> - struct amdgpu_job *job) >>> -{ >>> - int i, r, resched; >>> - >>> - dev_info(adev->dev, "GPU reset begin!\n"); >>> - >>> - mutex_lock(&adev->lock_reset); >>> - atomic_inc(&adev->gpu_reset_counter); >>> - adev->in_gpu_reset = 1; >>> >>> - /* Block kfd */ >>> - amdgpu_amdkfd_pre_reset(adev); >>> +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, >>> + struct amdgpu_job *job, >>> + bool *need_full_reset_arg) >>> +{ >>> + int i, r = 0; >>> + bool need_full_reset = *need_full_reset_arg; >>> >>> /* block TTM */ >>> - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>> + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>> >>> /* block all schedulers and reset given job's ring */ >>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>> @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>> amdgpu_fence_driver_force_completion(ring); >>> } >>> >>> - if (amdgpu_sriov_vf(adev)) >>> - r = amdgpu_device_reset_sriov(adev, job ? false : true); >>> - else >>> - r = amdgpu_device_reset(adev); >>> + if (!amdgpu_sriov_vf(adev)) { >>> + >>> + if (!need_full_reset) >>> + need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>> + >>> + if (!need_full_reset) { >>> + amdgpu_device_ip_pre_soft_reset(adev); >>> + r = amdgpu_device_ip_soft_reset(adev); >>> + amdgpu_device_ip_post_soft_reset(adev); >>> + if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>> + DRM_INFO("soft reset failed, will fallback to full reset!\n"); >>> + need_full_reset = true; >>> + } >>> + } >>> + >>> + if (need_full_reset) >>> + r = amdgpu_device_ip_suspend(adev); >>> + >>> + *need_full_reset_arg = need_full_reset; >>> + } >>> + >>> + return r; >>> +} >>> + >>> +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, >>> + struct list_head *device_list_handle, >>> + bool *need_full_reset_arg) >>> +{ >>> + struct amdgpu_device *tmp_adev = NULL; >>> + bool need_full_reset = *need_full_reset_arg, vram_lost = false; >>> + int r = 0; >>> + >>> + /* >>> + * ASIC reset has to be done on all HGMI hive nodes ASAP >>> + * to allow proper links negotiation in FW (within 1 sec) >>> + */ >>> + if (need_full_reset) { >>> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >>> + r = amdgpu_asic_reset(tmp_adev); >>> + if (r) >>> + DRM_WARN("ASIC reset failed with err r, %d for drm dev, %s", >>> + r, tmp_adev->ddev->unique); >>> + } >>> + } >>> + >>> + >>> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >>> + if (need_full_reset) { >>> + /* post card */ >>> + if (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) >>> + DRM_WARN("asic atom init failed!"); >>> + >>> + if (!r) { >>> + dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); >>> + r = amdgpu_device_ip_resume_phase1(tmp_adev); >>> + if (r) >>> + goto out; >>> + >>> + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); >>> + if (vram_lost) { >>> + DRM_ERROR("VRAM is lost!\n"); >>> + atomic_inc(&tmp_adev->vram_lost_counter); >>> + } >>> + >>> + r = amdgpu_gtt_mgr_recover( >>> + &tmp_adev->mman.bdev.man[TTM_PL_TT]); >>> + if (r) >>> + goto out; >>> + >>> + r = amdgpu_device_fw_loading(tmp_adev); >>> + if (r) >>> + return r; >>> + >>> + r = amdgpu_device_ip_resume_phase2(tmp_adev); >>> + if (r) >>> + goto out; >>> + >>> + if (vram_lost) >>> + amdgpu_device_fill_reset_magic(tmp_adev); >>> + >>> + /* Update PSP FW topology after reset */ >>> + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) >>> + r = amdgpu_xgmi_update_topology(hive, tmp_adev); >>> + } >>> + } >>> + >>> + >>> +out: >>> + if (!r) { >>> + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); >>> + r = amdgpu_ib_ring_tests(tmp_adev); >>> + if (r) { >>> + dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); >>> + r = amdgpu_device_ip_suspend(tmp_adev); >>> + need_full_reset = true; >>> + r = -EAGAIN; >>> + goto end; >>> + } >>> + } >>> + >>> + if (!r) >>> + r = amdgpu_device_recover_vram(tmp_adev); >>> + else >>> + tmp_adev->asic_reset_res = r; >>> + } >>> + >>> +end: >>> + *need_full_reset_arg = need_full_reset; >>> + return r; >>> +} >>> + >>> +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, >>> + struct amdgpu_job *job) >>> +{ >>> + int i; >>> >>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>> struct amdgpu_ring *ring = adev->rings[i]; >>> @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>> * or all rings (in the case @job is NULL) >>> * after above amdgpu_reset accomplished >>> */ >>> - if ((!job || job->base.sched == &ring->sched) && !r) >>> + if ((!job || job->base.sched == &ring->sched) && !adev->asic_reset_res) >>> drm_sched_job_recovery(&ring->sched); >>> >>> kthread_unpark(ring->sched.thread); >>> @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>> drm_helper_resume_force_mode(adev->ddev); >>> } >>> >>> - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); >>> + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); >>> >>> - if (r) { >>> - /* bad news, how to tell it to userspace ? */ >>> - dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); >>> - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >>> - } else { >>> - dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); >>> - } >>> + adev->asic_reset_res = adev->resched = 0; >>> + >>> +} >>> >>> +static void amdgpu_lock_adev(struct amdgpu_device *adev) >>> +{ >>> + mutex_lock(&adev->lock_reset); >>> + atomic_inc(&adev->gpu_reset_counter); >>> + adev->in_gpu_reset = 1; >>> + /* Block kfd */ >>> + amdgpu_amdkfd_pre_reset(adev); >>> +} >>> + >>> +static void amdgpu_unlock_adev(struct amdgpu_device *adev) >>> +{ >>> /*unlock kfd */ >>> amdgpu_amdkfd_post_reset(adev); >>> amdgpu_vf_error_trans_all(adev); >>> adev->in_gpu_reset = 0; >>> mutex_unlock(&adev->lock_reset); >>> +} >>> + >>> + >>> +/** >>> + * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>> + * >>> + * @adev: amdgpu device pointer >>> + * @job: which job trigger hang >>> + * >>> + * Attempt to reset the GPU if it has hung (all asics). >>> + * Attempt to do soft-reset or full-reset and reinitialize Asic >>> + * Returns 0 for success or an error on failure. >>> + */ >>> + >>> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>> + struct amdgpu_job *job) >>> +{ >>> + int r; >>> + struct amdgpu_hive_info *hive = NULL; >>> + bool need_full_reset = false; >>> + struct amdgpu_device *tmp_adev = NULL; >>> + struct list_head device_list, *device_list_handle = NULL; >>> + >>> + INIT_LIST_HEAD(&device_list); >>> + >>> + dev_info(adev->dev, "GPU reset begin!\n"); >>> + >>> + /* >>> + * In case of XGMI hive disallow concurrent resets to be triggered >>> + * by different nodes. >>> + */ >>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>> + mutex_lock(&xgmi_mutex); >>> + >>> + /* Start with adev pre asic reset first for soft reset check.*/ >>> + amdgpu_lock_adev(adev); >>> + r = amdgpu_device_pre_asic_reset(adev, >>> + job, >>> + &need_full_reset); >>> + if (r) { >>> + /*TODO Should we stop ?*/ >>> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", >>> + r, adev->ddev->unique); >>> + adev->asic_reset_res = r; >>> + } >>> + >>> + /* Build list of devices to reset */ >>> + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { >>> + hive = amdgpu_get_xgmi_hive(adev); >>> + if (!hive) { >>> + r = -ENODEV; >>> + >>> + amdgpu_unlock_adev(adev); >>> + >>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>> + mutex_unlock(&xgmi_mutex); >>> + return r; >>> + } >>> + >>> + /* >>> + * In case we are in XGMI hive mode device reset is done for all the >>> + * nodes in the hive to retrain all XGMI links and hence the reset >>> + * sequence is executed in loop on all nodes. >>> + */ >>> + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); >>> + } else { >>> + list_add_tail(&adev->gmc.xgmi.head, &device_list); >>> + device_list_handle = &device_list; >>> + } >>> + >>> +retry: /* Rest of adevs pre asic reset from XGMI hive. */ >>> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >>> + >>> + if (tmp_adev == adev) >>> + continue; >>> + >>> + dev_info(tmp_adev->dev, "GPU reset begin for drm dev %s!\n", adev->ddev->unique); >>> + >>> + amdgpu_lock_adev(tmp_adev); >>> + r = amdgpu_device_pre_asic_reset(tmp_adev, >>> + NULL, >>> + &need_full_reset); >>> + /*TODO Should we stop ?*/ >>> + if (r) { >>> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm dev, %s ", >>> + r, tmp_adev->ddev->unique); >>> + tmp_adev->asic_reset_res = r; >>> + } >>> + } >>> + >>> + /* Actual ASIC resets if needed.*/ >>> + /* TODO Implement XGMI hive reset logic for SRIOV */ >>> + if (amdgpu_sriov_vf(adev)) { >>> + r = amdgpu_device_reset_sriov(adev, job ? false : true); >>> + if (r) >>> + adev->asic_reset_res = r; >>> + } else { >>> + r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); >>> + if (r && r == -EAGAIN) >>> + goto retry; >>> + } >>> + >>> + /* Post ASIC reset for all devs .*/ >>> + list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { >>> + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? job : NULL); >>> + >>> + if (r) { >>> + /* bad news, how to tell it to userspace ? */ >>> + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); >>> + amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >>> + } else { >>> + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&adev->gpu_reset_counter)); >>> + } >>> + >>> + amdgpu_unlock_adev(tmp_adev); >>> + } >>> + >>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>> + mutex_unlock(&xgmi_mutex); >>> + >>> + if (r) >>> + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); >>> return r; >>> } >>> > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <8e9f51a4-7f0a-c435-c507-34eea96e0b08-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <8e9f51a4-7f0a-c435-c507-34eea96e0b08-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2018-11-22 15:44 ` Grodzovsky, Andrey [not found] ` <9e016b33-6c94-b1cb-cdcd-b68b91436e90-5C7GfCeVMHo@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Grodzovsky, Andrey @ 2018-11-22 15:44 UTC (permalink / raw) To: Koenig, Christian, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk On 11/22/2018 06:16 AM, Christian König wrote: > How about using a lock per hive and then acquiring that with trylock() > instead? > > This way you should at least catch cases where multiple causes try to > reset the same hive at the same time. True that there is still some > racing involved, but it's at least a good start. What about using per hive work_struct which when scheduled will execute amdgpu_device_gpu_recover ? Since work queue rejects duplicates we will get per hive serialization automatically from that without need of using any new mutex. Also this might be necessary anyway for RAS as I believe RAS will trigger interrupt when errors are detected and might then decide to reset the GPU so we will have to switch to button half context anyway. And I don't think it's a problem to schedule this work from job timeout handler if needed. > > > > Additional to that I would try improve the pre, middle, post handling > towards checking if we made some progress in between. > > In other words we stop all schedulers in the pre handling and > disconnect the scheduler fences from the hardware fence like I did in > patch "drm/sched: fix timeout handling v2". > > Then before we do the actual reset in the middle handling we check if > the offending job has completed or at least made some progress in the > meantime. I understand how to check if the job completed - if it's fence already signaled, but how do I test if the job made 'at least some progress' ? Another question - what's the purpose of this progress check - if I've already completed the pre handling sequence I can't bail out even if the guilty job is is signaled by the time I do the progress check, I have to complete at least the post handling to. Do you mean I can at least skip the ASIC reset phase in that case ? Andrey > In the case of a manual reset we skip that because we don't have an > offending job to check. > > In the post handling we stitch everything together again and start the > scheduler to go on with job submission. > > Christian. > > Am 21.11.18 um 23:02 schrieb Grodzovsky, Andrey: >> Depends what was the reason for triggering the reset for that node how >> do we know ? >> If the reason was RAS error that probably not hard to check all errors >> are cleared, but >> if the reason was job timeout on that specific node I will need to >> recheck that no jobs are left in incomplete state >> state. And if the reason is manual gpu reset trigger from sysfs, then >> what's the policy ? >> Sounds to me it's just easier to go ahead and allow all the pending >> resets to proceed unless there is >> a clear and quick criteria you can check after you grab the mutex then >> sure - but I don't know what it would be. >> >> Andrey >> >> On 11/21/2018 03:49 PM, Liu, Shaoyun wrote: >>> I saw you use the global xgmi_mutex to prevent concurrent reset to be >>> triggered by different nodes , but after the mutex been released , >>> current node may grap the mutex and continue to do another reset . >>> Maybe we should check the GPU status and skip the reset in this case >>> since the GPU may already be in good state . >>> >>> Regards >>> >>> shaoyun.liu >>> >>> On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: >>>> For XGMI hive case do reset in steps where each step iterates over >>>> all devs in hive. This especially important for asic reset >>>> since all PSP FW in hive must come up within a limited time >>>> (around 1 sec) to properply negotiate the link. >>>> Do this by refactoring amdgpu_device_gpu_recover and >>>> amdgpu_device_reset >>>> into pre_asic_reset, asic_reset and post_asic_reset functions where >>>> is part >>>> is exectued for all the GPUs in the hive before going to the next >>>> step. >>>> >>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >>>> --- >>>> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- >>>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 >>>> ++++++++++++++++++++--------- >>>> 2 files changed, 264 insertions(+), 116 deletions(-) >>>> >>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>> index 4ef5f7a..bd06d45 100644 >>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>> @@ -1026,6 +1026,9 @@ struct amdgpu_device { >>>> unsigned long last_mm_index; >>>> bool in_gpu_reset; >>>> struct mutex lock_reset; >>>> + >>>> + int asic_reset_res; >>>> + int resched; >>>> }; >>>> static inline struct amdgpu_device *amdgpu_ttm_adev(struct >>>> ttm_bo_device *bdev) >>>> @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; >>>> struct list_head *amdgpu_xgmi_get_adev_list_handle(struct >>>> amdgpu_hive_info *hive); >>>> struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct >>>> amdgpu_device *adev); >>>> -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >>>> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, >>>> struct amdgpu_device *adev); >>>> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); >>>> /* >>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>> index cb06e68..8e94d7f 100644 >>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>> @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct >>>> amdgpu_device *adev) >>>> return 0; >>>> } >>>> -/** >>>> - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough >>>> - * >>>> - * @adev: amdgpu device pointer >>>> - * >>>> - * attempt to do soft-reset or full-reset and reinitialize Asic >>>> - * return 0 means succeeded otherwise failed >>>> - */ >>>> -static int amdgpu_device_reset(struct amdgpu_device *adev) >>>> -{ >>>> - bool need_full_reset, vram_lost = 0; >>>> - int r; >>>> - >>>> - need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>>> - >>>> - if (!need_full_reset) { >>>> - amdgpu_device_ip_pre_soft_reset(adev); >>>> - r = amdgpu_device_ip_soft_reset(adev); >>>> - amdgpu_device_ip_post_soft_reset(adev); >>>> - if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>> - DRM_INFO("soft reset failed, will fallback to full >>>> reset!\n"); >>>> - need_full_reset = true; >>>> - } >>>> - } >>>> - >>>> - if (need_full_reset) { >>>> - r = amdgpu_device_ip_suspend(adev); >>>> - >>>> -retry: >>>> - r = amdgpu_asic_reset(adev); >>>> - /* post card */ >>>> - amdgpu_atom_asic_init(adev->mode_info.atom_context); >>>> - >>>> - if (!r) { >>>> - dev_info(adev->dev, "GPU reset succeeded, trying to >>>> resume\n"); >>>> - r = amdgpu_device_ip_resume_phase1(adev); >>>> - if (r) >>>> - goto out; >>>> - >>>> - vram_lost = amdgpu_device_check_vram_lost(adev); >>>> - if (vram_lost) { >>>> - DRM_ERROR("VRAM is lost!\n"); >>>> - atomic_inc(&adev->vram_lost_counter); >>>> - } >>>> - >>>> - r = amdgpu_gtt_mgr_recover( >>>> - &adev->mman.bdev.man[TTM_PL_TT]); >>>> - if (r) >>>> - goto out; >>>> - >>>> - r = amdgpu_device_fw_loading(adev); >>>> - if (r) >>>> - return r; >>>> - >>>> - r = amdgpu_device_ip_resume_phase2(adev); >>>> - if (r) >>>> - goto out; >>>> - >>>> - if (vram_lost) >>>> - amdgpu_device_fill_reset_magic(adev); >>>> - } >>>> - } >>>> - >>>> -out: >>>> - if (!r) { >>>> - amdgpu_irq_gpu_reset_resume_helper(adev); >>>> - r = amdgpu_ib_ring_tests(adev); >>>> - if (r) { >>>> - dev_err(adev->dev, "ib ring test failed (%d).\n", r); >>>> - r = amdgpu_device_ip_suspend(adev); >>>> - need_full_reset = true; >>>> - goto retry; >>>> - } >>>> - } >>>> - >>>> - if (!r) >>>> - r = amdgpu_device_recover_vram(adev); >>>> - >>>> - return r; >>>> -} >>>> /** >>>> * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf >>>> @@ -3335,31 +3255,16 @@ bool >>>> amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) >>>> return false; >>>> } >>>> -/** >>>> - * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>> - * >>>> - * @adev: amdgpu device pointer >>>> - * @job: which job trigger hang >>>> - * >>>> - * Attempt to reset the GPU if it has hung (all asics). >>>> - * Returns 0 for success or an error on failure. >>>> - */ >>>> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>> - struct amdgpu_job *job) >>>> -{ >>>> - int i, r, resched; >>>> - >>>> - dev_info(adev->dev, "GPU reset begin!\n"); >>>> - >>>> - mutex_lock(&adev->lock_reset); >>>> - atomic_inc(&adev->gpu_reset_counter); >>>> - adev->in_gpu_reset = 1; >>>> - /* Block kfd */ >>>> - amdgpu_amdkfd_pre_reset(adev); >>>> +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, >>>> + struct amdgpu_job *job, >>>> + bool *need_full_reset_arg) >>>> +{ >>>> + int i, r = 0; >>>> + bool need_full_reset = *need_full_reset_arg; >>>> /* block TTM */ >>>> - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>> + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>> /* block all schedulers and reset given job's ring */ >>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>> @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct >>>> amdgpu_device *adev, >>>> amdgpu_fence_driver_force_completion(ring); >>>> } >>>> - if (amdgpu_sriov_vf(adev)) >>>> - r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>> - else >>>> - r = amdgpu_device_reset(adev); >>>> + if (!amdgpu_sriov_vf(adev)) { >>>> + >>>> + if (!need_full_reset) >>>> + need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>>> + >>>> + if (!need_full_reset) { >>>> + amdgpu_device_ip_pre_soft_reset(adev); >>>> + r = amdgpu_device_ip_soft_reset(adev); >>>> + amdgpu_device_ip_post_soft_reset(adev); >>>> + if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>> + DRM_INFO("soft reset failed, will fallback to full >>>> reset!\n"); >>>> + need_full_reset = true; >>>> + } >>>> + } >>>> + >>>> + if (need_full_reset) >>>> + r = amdgpu_device_ip_suspend(adev); >>>> + >>>> + *need_full_reset_arg = need_full_reset; >>>> + } >>>> + >>>> + return r; >>>> +} >>>> + >>>> +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, >>>> + struct list_head *device_list_handle, >>>> + bool *need_full_reset_arg) >>>> +{ >>>> + struct amdgpu_device *tmp_adev = NULL; >>>> + bool need_full_reset = *need_full_reset_arg, vram_lost = false; >>>> + int r = 0; >>>> + >>>> + /* >>>> + * ASIC reset has to be done on all HGMI hive nodes ASAP >>>> + * to allow proper links negotiation in FW (within 1 sec) >>>> + */ >>>> + if (need_full_reset) { >>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>> gmc.xgmi.head) { >>>> + r = amdgpu_asic_reset(tmp_adev); >>>> + if (r) >>>> + DRM_WARN("ASIC reset failed with err r, %d for drm >>>> dev, %s", >>>> + r, tmp_adev->ddev->unique); >>>> + } >>>> + } >>>> + >>>> + >>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>> gmc.xgmi.head) { >>>> + if (need_full_reset) { >>>> + /* post card */ >>>> + if >>>> (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) >>>> + DRM_WARN("asic atom init failed!"); >>>> + >>>> + if (!r) { >>>> + dev_info(tmp_adev->dev, "GPU reset succeeded, >>>> trying to resume\n"); >>>> + r = amdgpu_device_ip_resume_phase1(tmp_adev); >>>> + if (r) >>>> + goto out; >>>> + >>>> + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); >>>> + if (vram_lost) { >>>> + DRM_ERROR("VRAM is lost!\n"); >>>> + atomic_inc(&tmp_adev->vram_lost_counter); >>>> + } >>>> + >>>> + r = amdgpu_gtt_mgr_recover( >>>> + &tmp_adev->mman.bdev.man[TTM_PL_TT]); >>>> + if (r) >>>> + goto out; >>>> + >>>> + r = amdgpu_device_fw_loading(tmp_adev); >>>> + if (r) >>>> + return r; >>>> + >>>> + r = amdgpu_device_ip_resume_phase2(tmp_adev); >>>> + if (r) >>>> + goto out; >>>> + >>>> + if (vram_lost) >>>> + amdgpu_device_fill_reset_magic(tmp_adev); >>>> + >>>> + /* Update PSP FW topology after reset */ >>>> + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) >>>> + r = amdgpu_xgmi_update_topology(hive, tmp_adev); >>>> + } >>>> + } >>>> + >>>> + >>>> +out: >>>> + if (!r) { >>>> + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); >>>> + r = amdgpu_ib_ring_tests(tmp_adev); >>>> + if (r) { >>>> + dev_err(tmp_adev->dev, "ib ring test failed >>>> (%d).\n", r); >>>> + r = amdgpu_device_ip_suspend(tmp_adev); >>>> + need_full_reset = true; >>>> + r = -EAGAIN; >>>> + goto end; >>>> + } >>>> + } >>>> + >>>> + if (!r) >>>> + r = amdgpu_device_recover_vram(tmp_adev); >>>> + else >>>> + tmp_adev->asic_reset_res = r; >>>> + } >>>> + >>>> +end: >>>> + *need_full_reset_arg = need_full_reset; >>>> + return r; >>>> +} >>>> + >>>> +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, >>>> + struct amdgpu_job *job) >>>> +{ >>>> + int i; >>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>> struct amdgpu_ring *ring = adev->rings[i]; >>>> @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct >>>> amdgpu_device *adev, >>>> * or all rings (in the case @job is NULL) >>>> * after above amdgpu_reset accomplished >>>> */ >>>> - if ((!job || job->base.sched == &ring->sched) && !r) >>>> + if ((!job || job->base.sched == &ring->sched) && >>>> !adev->asic_reset_res) >>>> drm_sched_job_recovery(&ring->sched); >>>> kthread_unpark(ring->sched.thread); >>>> @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct >>>> amdgpu_device *adev, >>>> drm_helper_resume_force_mode(adev->ddev); >>>> } >>>> - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); >>>> + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); >>>> - if (r) { >>>> - /* bad news, how to tell it to userspace ? */ >>>> - dev_info(adev->dev, "GPU reset(%d) failed\n", >>>> atomic_read(&adev->gpu_reset_counter)); >>>> - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, >>>> 0, r); >>>> - } else { >>>> - dev_info(adev->dev, "GPU reset(%d) >>>> succeeded!\n",atomic_read(&adev->gpu_reset_counter)); >>>> - } >>>> + adev->asic_reset_res = adev->resched = 0; >>>> + >>>> +} >>>> +static void amdgpu_lock_adev(struct amdgpu_device *adev) >>>> +{ >>>> + mutex_lock(&adev->lock_reset); >>>> + atomic_inc(&adev->gpu_reset_counter); >>>> + adev->in_gpu_reset = 1; >>>> + /* Block kfd */ >>>> + amdgpu_amdkfd_pre_reset(adev); >>>> +} >>>> + >>>> +static void amdgpu_unlock_adev(struct amdgpu_device *adev) >>>> +{ >>>> /*unlock kfd */ >>>> amdgpu_amdkfd_post_reset(adev); >>>> amdgpu_vf_error_trans_all(adev); >>>> adev->in_gpu_reset = 0; >>>> mutex_unlock(&adev->lock_reset); >>>> +} >>>> + >>>> + >>>> +/** >>>> + * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>> + * >>>> + * @adev: amdgpu device pointer >>>> + * @job: which job trigger hang >>>> + * >>>> + * Attempt to reset the GPU if it has hung (all asics). >>>> + * Attempt to do soft-reset or full-reset and reinitialize Asic >>>> + * Returns 0 for success or an error on failure. >>>> + */ >>>> + >>>> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>> + struct amdgpu_job *job) >>>> +{ >>>> + int r; >>>> + struct amdgpu_hive_info *hive = NULL; >>>> + bool need_full_reset = false; >>>> + struct amdgpu_device *tmp_adev = NULL; >>>> + struct list_head device_list, *device_list_handle = NULL; >>>> + >>>> + INIT_LIST_HEAD(&device_list); >>>> + >>>> + dev_info(adev->dev, "GPU reset begin!\n"); >>>> + >>>> + /* >>>> + * In case of XGMI hive disallow concurrent resets to be >>>> triggered >>>> + * by different nodes. >>>> + */ >>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>> + mutex_lock(&xgmi_mutex); >>>> + >>>> + /* Start with adev pre asic reset first for soft reset check.*/ >>>> + amdgpu_lock_adev(adev); >>>> + r = amdgpu_device_pre_asic_reset(adev, >>>> + job, >>>> + &need_full_reset); >>>> + if (r) { >>>> + /*TODO Should we stop ?*/ >>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm >>>> dev, %s ", >>>> + r, adev->ddev->unique); >>>> + adev->asic_reset_res = r; >>>> + } >>>> + >>>> + /* Build list of devices to reset */ >>>> + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { >>>> + hive = amdgpu_get_xgmi_hive(adev); >>>> + if (!hive) { >>>> + r = -ENODEV; >>>> + >>>> + amdgpu_unlock_adev(adev); >>>> + >>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>> + mutex_unlock(&xgmi_mutex); >>>> + return r; >>>> + } >>>> + >>>> + /* >>>> + * In case we are in XGMI hive mode device reset is done >>>> for all the >>>> + * nodes in the hive to retrain all XGMI links and hence >>>> the reset >>>> + * sequence is executed in loop on all nodes. >>>> + */ >>>> + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); >>>> + } else { >>>> + list_add_tail(&adev->gmc.xgmi.head, &device_list); >>>> + device_list_handle = &device_list; >>>> + } >>>> + >>>> +retry: /* Rest of adevs pre asic reset from XGMI hive. */ >>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>> gmc.xgmi.head) { >>>> + >>>> + if (tmp_adev == adev) >>>> + continue; >>>> + >>>> + dev_info(tmp_adev->dev, "GPU reset begin for drm dev >>>> %s!\n", adev->ddev->unique); >>>> + >>>> + amdgpu_lock_adev(tmp_adev); >>>> + r = amdgpu_device_pre_asic_reset(tmp_adev, >>>> + NULL, >>>> + &need_full_reset); >>>> + /*TODO Should we stop ?*/ >>>> + if (r) { >>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for >>>> drm dev, %s ", >>>> + r, tmp_adev->ddev->unique); >>>> + tmp_adev->asic_reset_res = r; >>>> + } >>>> + } >>>> + >>>> + /* Actual ASIC resets if needed.*/ >>>> + /* TODO Implement XGMI hive reset logic for SRIOV */ >>>> + if (amdgpu_sriov_vf(adev)) { >>>> + r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>> + if (r) >>>> + adev->asic_reset_res = r; >>>> + } else { >>>> + r = amdgpu_do_asic_reset(hive, device_list_handle, >>>> &need_full_reset); >>>> + if (r && r == -EAGAIN) >>>> + goto retry; >>>> + } >>>> + >>>> + /* Post ASIC reset for all devs .*/ >>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>> gmc.xgmi.head) { >>>> + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? >>>> job : NULL); >>>> + >>>> + if (r) { >>>> + /* bad news, how to tell it to userspace ? */ >>>> + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", >>>> atomic_read(&adev->gpu_reset_counter)); >>>> + amdgpu_vf_error_put(tmp_adev, >>>> AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >>>> + } else { >>>> + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", >>>> atomic_read(&adev->gpu_reset_counter)); >>>> + } >>>> + >>>> + amdgpu_unlock_adev(tmp_adev); >>>> + } >>>> + >>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>> + mutex_unlock(&xgmi_mutex); >>>> + >>>> + if (r) >>>> + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); >>>> return r; >>>> } >> _______________________________________________ >> amd-gfx mailing list >> amd-gfx@lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/amd-gfx > _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <9e016b33-6c94-b1cb-cdcd-b68b91436e90-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <9e016b33-6c94-b1cb-cdcd-b68b91436e90-5C7GfCeVMHo@public.gmane.org> @ 2018-11-22 19:03 ` Christian König [not found] ` <0f048ac9-1247-8d87-d8c8-5a249e24cdcb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Christian König @ 2018-11-22 19:03 UTC (permalink / raw) To: Grodzovsky, Andrey, Koenig, Christian, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk Am 22.11.18 um 16:44 schrieb Grodzovsky, Andrey: > > On 11/22/2018 06:16 AM, Christian König wrote: >> How about using a lock per hive and then acquiring that with trylock() >> instead? >> >> This way you should at least catch cases where multiple causes try to >> reset the same hive at the same time. True that there is still some >> racing involved, but it's at least a good start. > What about using per hive work_struct which when scheduled will execute > amdgpu_device_gpu_recover ? Since work queue rejects duplicates we will > get per hive serialization automatically from that without need of using > any new mutex. Also this might be necessary anyway for RAS as I believe > RAS will trigger interrupt when errors are detected and might then > decide to reset the GPU so we will have to switch to button half context > anyway. And I don't think it's a problem to schedule this work from job > timeout handler if needed. Mhm, what is the advantage to the trylock variant? The key problem with that is how to get the offending job into the background worker. E.g. we have trouble guaranteeing that the job isn't destroyed when this is in a background worker. >> >> >> Additional to that I would try improve the pre, middle, post handling >> towards checking if we made some progress in between. >> >> In other words we stop all schedulers in the pre handling and >> disconnect the scheduler fences from the hardware fence like I did in >> patch "drm/sched: fix timeout handling v2". >> >> Then before we do the actual reset in the middle handling we check if >> the offending job has completed or at least made some progress in the >> meantime. > I understand how to check if the job completed - if it's fence already > signaled, but how do I test if the job made 'at least some progress' ? Good question. Maybe we can somehow query from the hardware the number of primitives or pixels processed so far and then compare after a moment? > Another question - what's the purpose of this progress check - if I've > already completed the pre handling sequence I can't bail out even if > the guilty job is is signaled by the time I do the progress check, I > have to complete at least the post handling to. Do you mean I can at > least skip the ASIC reset phase in that case ? Yes exactly. We have a rather big race problem in the current reset logic between completing the job and resetting the hardware. In other words when the job completes exactly in the moment we reset the GPU we try to signal it twice etc etc... The whole handling here is not really thought through. Christian. > > Andrey > >> In the case of a manual reset we skip that because we don't have an >> offending job to check. >> >> In the post handling we stitch everything together again and start the >> scheduler to go on with job submission. >> >> Christian. >> >> Am 21.11.18 um 23:02 schrieb Grodzovsky, Andrey: >>> Depends what was the reason for triggering the reset for that node how >>> do we know ? >>> If the reason was RAS error that probably not hard to check all errors >>> are cleared, but >>> if the reason was job timeout on that specific node I will need to >>> recheck that no jobs are left in incomplete state >>> state. And if the reason is manual gpu reset trigger from sysfs, then >>> what's the policy ? >>> Sounds to me it's just easier to go ahead and allow all the pending >>> resets to proceed unless there is >>> a clear and quick criteria you can check after you grab the mutex then >>> sure - but I don't know what it would be. >>> >>> Andrey >>> >>> On 11/21/2018 03:49 PM, Liu, Shaoyun wrote: >>>> I saw you use the global xgmi_mutex to prevent concurrent reset to be >>>> triggered by different nodes , but after the mutex been released , >>>> current node may grap the mutex and continue to do another reset . >>>> Maybe we should check the GPU status and skip the reset in this case >>>> since the GPU may already be in good state . >>>> >>>> Regards >>>> >>>> shaoyun.liu >>>> >>>> On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: >>>>> For XGMI hive case do reset in steps where each step iterates over >>>>> all devs in hive. This especially important for asic reset >>>>> since all PSP FW in hive must come up within a limited time >>>>> (around 1 sec) to properply negotiate the link. >>>>> Do this by refactoring amdgpu_device_gpu_recover and >>>>> amdgpu_device_reset >>>>> into pre_asic_reset, asic_reset and post_asic_reset functions where >>>>> is part >>>>> is exectued for all the GPUs in the hive before going to the next >>>>> step. >>>>> >>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >>>>> --- >>>>> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- >>>>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 >>>>> ++++++++++++++++++++--------- >>>>> 2 files changed, 264 insertions(+), 116 deletions(-) >>>>> >>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>> index 4ef5f7a..bd06d45 100644 >>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>> @@ -1026,6 +1026,9 @@ struct amdgpu_device { >>>>> unsigned long last_mm_index; >>>>> bool in_gpu_reset; >>>>> struct mutex lock_reset; >>>>> + >>>>> + int asic_reset_res; >>>>> + int resched; >>>>> }; >>>>> static inline struct amdgpu_device *amdgpu_ttm_adev(struct >>>>> ttm_bo_device *bdev) >>>>> @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; >>>>> struct list_head *amdgpu_xgmi_get_adev_list_handle(struct >>>>> amdgpu_hive_info *hive); >>>>> struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct >>>>> amdgpu_device *adev); >>>>> -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >>>>> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, >>>>> struct amdgpu_device *adev); >>>>> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); >>>>> /* >>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>> index cb06e68..8e94d7f 100644 >>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>> @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct >>>>> amdgpu_device *adev) >>>>> return 0; >>>>> } >>>>> -/** >>>>> - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or passthrough >>>>> - * >>>>> - * @adev: amdgpu device pointer >>>>> - * >>>>> - * attempt to do soft-reset or full-reset and reinitialize Asic >>>>> - * return 0 means succeeded otherwise failed >>>>> - */ >>>>> -static int amdgpu_device_reset(struct amdgpu_device *adev) >>>>> -{ >>>>> - bool need_full_reset, vram_lost = 0; >>>>> - int r; >>>>> - >>>>> - need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>>>> - >>>>> - if (!need_full_reset) { >>>>> - amdgpu_device_ip_pre_soft_reset(adev); >>>>> - r = amdgpu_device_ip_soft_reset(adev); >>>>> - amdgpu_device_ip_post_soft_reset(adev); >>>>> - if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>>> - DRM_INFO("soft reset failed, will fallback to full >>>>> reset!\n"); >>>>> - need_full_reset = true; >>>>> - } >>>>> - } >>>>> - >>>>> - if (need_full_reset) { >>>>> - r = amdgpu_device_ip_suspend(adev); >>>>> - >>>>> -retry: >>>>> - r = amdgpu_asic_reset(adev); >>>>> - /* post card */ >>>>> - amdgpu_atom_asic_init(adev->mode_info.atom_context); >>>>> - >>>>> - if (!r) { >>>>> - dev_info(adev->dev, "GPU reset succeeded, trying to >>>>> resume\n"); >>>>> - r = amdgpu_device_ip_resume_phase1(adev); >>>>> - if (r) >>>>> - goto out; >>>>> - >>>>> - vram_lost = amdgpu_device_check_vram_lost(adev); >>>>> - if (vram_lost) { >>>>> - DRM_ERROR("VRAM is lost!\n"); >>>>> - atomic_inc(&adev->vram_lost_counter); >>>>> - } >>>>> - >>>>> - r = amdgpu_gtt_mgr_recover( >>>>> - &adev->mman.bdev.man[TTM_PL_TT]); >>>>> - if (r) >>>>> - goto out; >>>>> - >>>>> - r = amdgpu_device_fw_loading(adev); >>>>> - if (r) >>>>> - return r; >>>>> - >>>>> - r = amdgpu_device_ip_resume_phase2(adev); >>>>> - if (r) >>>>> - goto out; >>>>> - >>>>> - if (vram_lost) >>>>> - amdgpu_device_fill_reset_magic(adev); >>>>> - } >>>>> - } >>>>> - >>>>> -out: >>>>> - if (!r) { >>>>> - amdgpu_irq_gpu_reset_resume_helper(adev); >>>>> - r = amdgpu_ib_ring_tests(adev); >>>>> - if (r) { >>>>> - dev_err(adev->dev, "ib ring test failed (%d).\n", r); >>>>> - r = amdgpu_device_ip_suspend(adev); >>>>> - need_full_reset = true; >>>>> - goto retry; >>>>> - } >>>>> - } >>>>> - >>>>> - if (!r) >>>>> - r = amdgpu_device_recover_vram(adev); >>>>> - >>>>> - return r; >>>>> -} >>>>> /** >>>>> * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf >>>>> @@ -3335,31 +3255,16 @@ bool >>>>> amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) >>>>> return false; >>>>> } >>>>> -/** >>>>> - * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>>> - * >>>>> - * @adev: amdgpu device pointer >>>>> - * @job: which job trigger hang >>>>> - * >>>>> - * Attempt to reset the GPU if it has hung (all asics). >>>>> - * Returns 0 for success or an error on failure. >>>>> - */ >>>>> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>>> - struct amdgpu_job *job) >>>>> -{ >>>>> - int i, r, resched; >>>>> - >>>>> - dev_info(adev->dev, "GPU reset begin!\n"); >>>>> - >>>>> - mutex_lock(&adev->lock_reset); >>>>> - atomic_inc(&adev->gpu_reset_counter); >>>>> - adev->in_gpu_reset = 1; >>>>> - /* Block kfd */ >>>>> - amdgpu_amdkfd_pre_reset(adev); >>>>> +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, >>>>> + struct amdgpu_job *job, >>>>> + bool *need_full_reset_arg) >>>>> +{ >>>>> + int i, r = 0; >>>>> + bool need_full_reset = *need_full_reset_arg; >>>>> /* block TTM */ >>>>> - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>>> + adev->resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>>> /* block all schedulers and reset given job's ring */ >>>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>>> @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct >>>>> amdgpu_device *adev, >>>>> amdgpu_fence_driver_force_completion(ring); >>>>> } >>>>> - if (amdgpu_sriov_vf(adev)) >>>>> - r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>>> - else >>>>> - r = amdgpu_device_reset(adev); >>>>> + if (!amdgpu_sriov_vf(adev)) { >>>>> + >>>>> + if (!need_full_reset) >>>>> + need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>>>> + >>>>> + if (!need_full_reset) { >>>>> + amdgpu_device_ip_pre_soft_reset(adev); >>>>> + r = amdgpu_device_ip_soft_reset(adev); >>>>> + amdgpu_device_ip_post_soft_reset(adev); >>>>> + if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>>> + DRM_INFO("soft reset failed, will fallback to full >>>>> reset!\n"); >>>>> + need_full_reset = true; >>>>> + } >>>>> + } >>>>> + >>>>> + if (need_full_reset) >>>>> + r = amdgpu_device_ip_suspend(adev); >>>>> + >>>>> + *need_full_reset_arg = need_full_reset; >>>>> + } >>>>> + >>>>> + return r; >>>>> +} >>>>> + >>>>> +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, >>>>> + struct list_head *device_list_handle, >>>>> + bool *need_full_reset_arg) >>>>> +{ >>>>> + struct amdgpu_device *tmp_adev = NULL; >>>>> + bool need_full_reset = *need_full_reset_arg, vram_lost = false; >>>>> + int r = 0; >>>>> + >>>>> + /* >>>>> + * ASIC reset has to be done on all HGMI hive nodes ASAP >>>>> + * to allow proper links negotiation in FW (within 1 sec) >>>>> + */ >>>>> + if (need_full_reset) { >>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>> gmc.xgmi.head) { >>>>> + r = amdgpu_asic_reset(tmp_adev); >>>>> + if (r) >>>>> + DRM_WARN("ASIC reset failed with err r, %d for drm >>>>> dev, %s", >>>>> + r, tmp_adev->ddev->unique); >>>>> + } >>>>> + } >>>>> + >>>>> + >>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>> gmc.xgmi.head) { >>>>> + if (need_full_reset) { >>>>> + /* post card */ >>>>> + if >>>>> (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) >>>>> + DRM_WARN("asic atom init failed!"); >>>>> + >>>>> + if (!r) { >>>>> + dev_info(tmp_adev->dev, "GPU reset succeeded, >>>>> trying to resume\n"); >>>>> + r = amdgpu_device_ip_resume_phase1(tmp_adev); >>>>> + if (r) >>>>> + goto out; >>>>> + >>>>> + vram_lost = amdgpu_device_check_vram_lost(tmp_adev); >>>>> + if (vram_lost) { >>>>> + DRM_ERROR("VRAM is lost!\n"); >>>>> + atomic_inc(&tmp_adev->vram_lost_counter); >>>>> + } >>>>> + >>>>> + r = amdgpu_gtt_mgr_recover( >>>>> + &tmp_adev->mman.bdev.man[TTM_PL_TT]); >>>>> + if (r) >>>>> + goto out; >>>>> + >>>>> + r = amdgpu_device_fw_loading(tmp_adev); >>>>> + if (r) >>>>> + return r; >>>>> + >>>>> + r = amdgpu_device_ip_resume_phase2(tmp_adev); >>>>> + if (r) >>>>> + goto out; >>>>> + >>>>> + if (vram_lost) >>>>> + amdgpu_device_fill_reset_magic(tmp_adev); >>>>> + >>>>> + /* Update PSP FW topology after reset */ >>>>> + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) >>>>> + r = amdgpu_xgmi_update_topology(hive, tmp_adev); >>>>> + } >>>>> + } >>>>> + >>>>> + >>>>> +out: >>>>> + if (!r) { >>>>> + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); >>>>> + r = amdgpu_ib_ring_tests(tmp_adev); >>>>> + if (r) { >>>>> + dev_err(tmp_adev->dev, "ib ring test failed >>>>> (%d).\n", r); >>>>> + r = amdgpu_device_ip_suspend(tmp_adev); >>>>> + need_full_reset = true; >>>>> + r = -EAGAIN; >>>>> + goto end; >>>>> + } >>>>> + } >>>>> + >>>>> + if (!r) >>>>> + r = amdgpu_device_recover_vram(tmp_adev); >>>>> + else >>>>> + tmp_adev->asic_reset_res = r; >>>>> + } >>>>> + >>>>> +end: >>>>> + *need_full_reset_arg = need_full_reset; >>>>> + return r; >>>>> +} >>>>> + >>>>> +static void amdgpu_device_post_asic_reset(struct amdgpu_device *adev, >>>>> + struct amdgpu_job *job) >>>>> +{ >>>>> + int i; >>>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>>> struct amdgpu_ring *ring = adev->rings[i]; >>>>> @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct >>>>> amdgpu_device *adev, >>>>> * or all rings (in the case @job is NULL) >>>>> * after above amdgpu_reset accomplished >>>>> */ >>>>> - if ((!job || job->base.sched == &ring->sched) && !r) >>>>> + if ((!job || job->base.sched == &ring->sched) && >>>>> !adev->asic_reset_res) >>>>> drm_sched_job_recovery(&ring->sched); >>>>> kthread_unpark(ring->sched.thread); >>>>> @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct >>>>> amdgpu_device *adev, >>>>> drm_helper_resume_force_mode(adev->ddev); >>>>> } >>>>> - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); >>>>> + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); >>>>> - if (r) { >>>>> - /* bad news, how to tell it to userspace ? */ >>>>> - dev_info(adev->dev, "GPU reset(%d) failed\n", >>>>> atomic_read(&adev->gpu_reset_counter)); >>>>> - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, >>>>> 0, r); >>>>> - } else { >>>>> - dev_info(adev->dev, "GPU reset(%d) >>>>> succeeded!\n",atomic_read(&adev->gpu_reset_counter)); >>>>> - } >>>>> + adev->asic_reset_res = adev->resched = 0; >>>>> + >>>>> +} >>>>> +static void amdgpu_lock_adev(struct amdgpu_device *adev) >>>>> +{ >>>>> + mutex_lock(&adev->lock_reset); >>>>> + atomic_inc(&adev->gpu_reset_counter); >>>>> + adev->in_gpu_reset = 1; >>>>> + /* Block kfd */ >>>>> + amdgpu_amdkfd_pre_reset(adev); >>>>> +} >>>>> + >>>>> +static void amdgpu_unlock_adev(struct amdgpu_device *adev) >>>>> +{ >>>>> /*unlock kfd */ >>>>> amdgpu_amdkfd_post_reset(adev); >>>>> amdgpu_vf_error_trans_all(adev); >>>>> adev->in_gpu_reset = 0; >>>>> mutex_unlock(&adev->lock_reset); >>>>> +} >>>>> + >>>>> + >>>>> +/** >>>>> + * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>>> + * >>>>> + * @adev: amdgpu device pointer >>>>> + * @job: which job trigger hang >>>>> + * >>>>> + * Attempt to reset the GPU if it has hung (all asics). >>>>> + * Attempt to do soft-reset or full-reset and reinitialize Asic >>>>> + * Returns 0 for success or an error on failure. >>>>> + */ >>>>> + >>>>> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>>> + struct amdgpu_job *job) >>>>> +{ >>>>> + int r; >>>>> + struct amdgpu_hive_info *hive = NULL; >>>>> + bool need_full_reset = false; >>>>> + struct amdgpu_device *tmp_adev = NULL; >>>>> + struct list_head device_list, *device_list_handle = NULL; >>>>> + >>>>> + INIT_LIST_HEAD(&device_list); >>>>> + >>>>> + dev_info(adev->dev, "GPU reset begin!\n"); >>>>> + >>>>> + /* >>>>> + * In case of XGMI hive disallow concurrent resets to be >>>>> triggered >>>>> + * by different nodes. >>>>> + */ >>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>> + mutex_lock(&xgmi_mutex); >>>>> + >>>>> + /* Start with adev pre asic reset first for soft reset check.*/ >>>>> + amdgpu_lock_adev(adev); >>>>> + r = amdgpu_device_pre_asic_reset(adev, >>>>> + job, >>>>> + &need_full_reset); >>>>> + if (r) { >>>>> + /*TODO Should we stop ?*/ >>>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm >>>>> dev, %s ", >>>>> + r, adev->ddev->unique); >>>>> + adev->asic_reset_res = r; >>>>> + } >>>>> + >>>>> + /* Build list of devices to reset */ >>>>> + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > 1) { >>>>> + hive = amdgpu_get_xgmi_hive(adev); >>>>> + if (!hive) { >>>>> + r = -ENODEV; >>>>> + >>>>> + amdgpu_unlock_adev(adev); >>>>> + >>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>> + mutex_unlock(&xgmi_mutex); >>>>> + return r; >>>>> + } >>>>> + >>>>> + /* >>>>> + * In case we are in XGMI hive mode device reset is done >>>>> for all the >>>>> + * nodes in the hive to retrain all XGMI links and hence >>>>> the reset >>>>> + * sequence is executed in loop on all nodes. >>>>> + */ >>>>> + device_list_handle = amdgpu_xgmi_get_adev_list_handle(hive); >>>>> + } else { >>>>> + list_add_tail(&adev->gmc.xgmi.head, &device_list); >>>>> + device_list_handle = &device_list; >>>>> + } >>>>> + >>>>> +retry: /* Rest of adevs pre asic reset from XGMI hive. */ >>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>> gmc.xgmi.head) { >>>>> + >>>>> + if (tmp_adev == adev) >>>>> + continue; >>>>> + >>>>> + dev_info(tmp_adev->dev, "GPU reset begin for drm dev >>>>> %s!\n", adev->ddev->unique); >>>>> + >>>>> + amdgpu_lock_adev(tmp_adev); >>>>> + r = amdgpu_device_pre_asic_reset(tmp_adev, >>>>> + NULL, >>>>> + &need_full_reset); >>>>> + /*TODO Should we stop ?*/ >>>>> + if (r) { >>>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for >>>>> drm dev, %s ", >>>>> + r, tmp_adev->ddev->unique); >>>>> + tmp_adev->asic_reset_res = r; >>>>> + } >>>>> + } >>>>> + >>>>> + /* Actual ASIC resets if needed.*/ >>>>> + /* TODO Implement XGMI hive reset logic for SRIOV */ >>>>> + if (amdgpu_sriov_vf(adev)) { >>>>> + r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>>> + if (r) >>>>> + adev->asic_reset_res = r; >>>>> + } else { >>>>> + r = amdgpu_do_asic_reset(hive, device_list_handle, >>>>> &need_full_reset); >>>>> + if (r && r == -EAGAIN) >>>>> + goto retry; >>>>> + } >>>>> + >>>>> + /* Post ASIC reset for all devs .*/ >>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>> gmc.xgmi.head) { >>>>> + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? >>>>> job : NULL); >>>>> + >>>>> + if (r) { >>>>> + /* bad news, how to tell it to userspace ? */ >>>>> + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", >>>>> atomic_read(&adev->gpu_reset_counter)); >>>>> + amdgpu_vf_error_put(tmp_adev, >>>>> AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >>>>> + } else { >>>>> + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", >>>>> atomic_read(&adev->gpu_reset_counter)); >>>>> + } >>>>> + >>>>> + amdgpu_unlock_adev(tmp_adev); >>>>> + } >>>>> + >>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>> + mutex_unlock(&xgmi_mutex); >>>>> + >>>>> + if (r) >>>>> + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); >>>>> return r; >>>>> } >>> _______________________________________________ >>> amd-gfx mailing list >>> amd-gfx@lists.freedesktop.org >>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <0f048ac9-1247-8d87-d8c8-5a249e24cdcb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <0f048ac9-1247-8d87-d8c8-5a249e24cdcb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2018-11-22 19:56 ` Grodzovsky, Andrey [not found] ` <329e176f-ab36-fc79-8646-484975ebb8c3-5C7GfCeVMHo@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Grodzovsky, Andrey @ 2018-11-22 19:56 UTC (permalink / raw) To: Koenig, Christian, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk On 11/22/2018 02:03 PM, Christian König wrote: > Am 22.11.18 um 16:44 schrieb Grodzovsky, Andrey: >> >> On 11/22/2018 06:16 AM, Christian König wrote: >>> How about using a lock per hive and then acquiring that with trylock() >>> instead? >>> >>> This way you should at least catch cases where multiple causes try to >>> reset the same hive at the same time. True that there is still some >>> racing involved, but it's at least a good start. >> What about using per hive work_struct which when scheduled will execute >> amdgpu_device_gpu_recover ? Since work queue rejects duplicates we will >> get per hive serialization automatically from that without need of using >> any new mutex. Also this might be necessary anyway for RAS as I believe >> RAS will trigger interrupt when errors are detected and might then >> decide to reset the GPU so we will have to switch to button half context >> anyway. And I don't think it's a problem to schedule this work from job >> timeout handler if needed. > > Mhm, what is the advantage to the trylock variant? The key problem > with that is how to get the offending job into the background worker. > > E.g. we have trouble guaranteeing that the job isn't destroyed when > this is in a background worker. Yea, actually there isn't. > >>> >>> >>> Additional to that I would try improve the pre, middle, post handling >>> towards checking if we made some progress in between. >>> >>> In other words we stop all schedulers in the pre handling and >>> disconnect the scheduler fences from the hardware fence like I did in >>> patch "drm/sched: fix timeout handling v2". >>> >>> Then before we do the actual reset in the middle handling we check if >>> the offending job has completed or at least made some progress in the >>> meantime. >> I understand how to check if the job completed - if it's fence already >> signaled, but how do I test if the job made 'at least some progress' ? > > Good question. Maybe we can somehow query from the hardware the number > of primitives or pixels processed so far and then compare after a moment? I will check on this later. In the mean while I will update the code with the proposed per hive locking and I will add the check if the guilty job completed before ASIC reset skipping the reset if it's did. Andrey > >> Another question - what's the purpose of this progress check - if I've >> already completed the pre handling sequence I can't bail out even if >> the guilty job is is signaled by the time I do the progress check, I >> have to complete at least the post handling to. Do you mean I can at >> least skip the ASIC reset phase in that case ? > > Yes exactly. We have a rather big race problem in the current reset > logic between completing the job and resetting the hardware. > > In other words when the job completes exactly in the moment we reset > the GPU we try to signal it twice etc etc... The whole handling here > is not really thought through. > > Christian. > >> >> Andrey >> >>> In the case of a manual reset we skip that because we don't have an >>> offending job to check. >>> >>> In the post handling we stitch everything together again and start the >>> scheduler to go on with job submission. >>> >>> Christian. >>> >>> Am 21.11.18 um 23:02 schrieb Grodzovsky, Andrey: >>>> Depends what was the reason for triggering the reset for that node how >>>> do we know ? >>>> If the reason was RAS error that probably not hard to check all errors >>>> are cleared, but >>>> if the reason was job timeout on that specific node I will need to >>>> recheck that no jobs are left in incomplete state >>>> state. And if the reason is manual gpu reset trigger from sysfs, then >>>> what's the policy ? >>>> Sounds to me it's just easier to go ahead and allow all the pending >>>> resets to proceed unless there is >>>> a clear and quick criteria you can check after you grab the mutex then >>>> sure - but I don't know what it would be. >>>> >>>> Andrey >>>> >>>> On 11/21/2018 03:49 PM, Liu, Shaoyun wrote: >>>>> I saw you use the global xgmi_mutex to prevent concurrent reset >>>>> to be >>>>> triggered by different nodes , but after the mutex been released , >>>>> current node may grap the mutex and continue to do another reset . >>>>> Maybe we should check the GPU status and skip the reset in this >>>>> case >>>>> since the GPU may already be in good state . >>>>> >>>>> Regards >>>>> >>>>> shaoyun.liu >>>>> >>>>> On 2018-11-21 1:10 p.m., Andrey Grodzovsky wrote: >>>>>> For XGMI hive case do reset in steps where each step iterates over >>>>>> all devs in hive. This especially important for asic reset >>>>>> since all PSP FW in hive must come up within a limited time >>>>>> (around 1 sec) to properply negotiate the link. >>>>>> Do this by refactoring amdgpu_device_gpu_recover and >>>>>> amdgpu_device_reset >>>>>> into pre_asic_reset, asic_reset and post_asic_reset functions where >>>>>> is part >>>>>> is exectued for all the GPUs in the hive before going to the next >>>>>> step. >>>>>> >>>>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> >>>>>> --- >>>>>> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 +- >>>>>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 375 >>>>>> ++++++++++++++++++++--------- >>>>>> 2 files changed, 264 insertions(+), 116 deletions(-) >>>>>> >>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>>> index 4ef5f7a..bd06d45 100644 >>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h >>>>>> @@ -1026,6 +1026,9 @@ struct amdgpu_device { >>>>>> unsigned long last_mm_index; >>>>>> bool in_gpu_reset; >>>>>> struct mutex lock_reset; >>>>>> + >>>>>> + int asic_reset_res; >>>>>> + int resched; >>>>>> }; >>>>>> static inline struct amdgpu_device *amdgpu_ttm_adev(struct >>>>>> ttm_bo_device *bdev) >>>>>> @@ -1232,7 +1235,7 @@ struct amdgpu_hive_info; >>>>>> struct list_head *amdgpu_xgmi_get_adev_list_handle(struct >>>>>> amdgpu_hive_info *hive); >>>>>> struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct >>>>>> amdgpu_device *adev); >>>>>> -int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive); >>>>>> +int amdgpu_xgmi_update_topology(struct amdgpu_hive_info *hive, >>>>>> struct amdgpu_device *adev); >>>>>> int amdgpu_xgmi_add_device(struct amdgpu_device *adev); >>>>>> /* >>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>>> index cb06e68..8e94d7f 100644 >>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c >>>>>> @@ -3157,86 +3157,6 @@ static int amdgpu_device_recover_vram(struct >>>>>> amdgpu_device *adev) >>>>>> return 0; >>>>>> } >>>>>> -/** >>>>>> - * amdgpu_device_reset - reset ASIC/GPU for bare-metal or >>>>>> passthrough >>>>>> - * >>>>>> - * @adev: amdgpu device pointer >>>>>> - * >>>>>> - * attempt to do soft-reset or full-reset and reinitialize Asic >>>>>> - * return 0 means succeeded otherwise failed >>>>>> - */ >>>>>> -static int amdgpu_device_reset(struct amdgpu_device *adev) >>>>>> -{ >>>>>> - bool need_full_reset, vram_lost = 0; >>>>>> - int r; >>>>>> - >>>>>> - need_full_reset = amdgpu_device_ip_need_full_reset(adev); >>>>>> - >>>>>> - if (!need_full_reset) { >>>>>> - amdgpu_device_ip_pre_soft_reset(adev); >>>>>> - r = amdgpu_device_ip_soft_reset(adev); >>>>>> - amdgpu_device_ip_post_soft_reset(adev); >>>>>> - if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>>>> - DRM_INFO("soft reset failed, will fallback to full >>>>>> reset!\n"); >>>>>> - need_full_reset = true; >>>>>> - } >>>>>> - } >>>>>> - >>>>>> - if (need_full_reset) { >>>>>> - r = amdgpu_device_ip_suspend(adev); >>>>>> - >>>>>> -retry: >>>>>> - r = amdgpu_asic_reset(adev); >>>>>> - /* post card */ >>>>>> - amdgpu_atom_asic_init(adev->mode_info.atom_context); >>>>>> - >>>>>> - if (!r) { >>>>>> - dev_info(adev->dev, "GPU reset succeeded, trying to >>>>>> resume\n"); >>>>>> - r = amdgpu_device_ip_resume_phase1(adev); >>>>>> - if (r) >>>>>> - goto out; >>>>>> - >>>>>> - vram_lost = amdgpu_device_check_vram_lost(adev); >>>>>> - if (vram_lost) { >>>>>> - DRM_ERROR("VRAM is lost!\n"); >>>>>> - atomic_inc(&adev->vram_lost_counter); >>>>>> - } >>>>>> - >>>>>> - r = amdgpu_gtt_mgr_recover( >>>>>> - &adev->mman.bdev.man[TTM_PL_TT]); >>>>>> - if (r) >>>>>> - goto out; >>>>>> - >>>>>> - r = amdgpu_device_fw_loading(adev); >>>>>> - if (r) >>>>>> - return r; >>>>>> - >>>>>> - r = amdgpu_device_ip_resume_phase2(adev); >>>>>> - if (r) >>>>>> - goto out; >>>>>> - >>>>>> - if (vram_lost) >>>>>> - amdgpu_device_fill_reset_magic(adev); >>>>>> - } >>>>>> - } >>>>>> - >>>>>> -out: >>>>>> - if (!r) { >>>>>> - amdgpu_irq_gpu_reset_resume_helper(adev); >>>>>> - r = amdgpu_ib_ring_tests(adev); >>>>>> - if (r) { >>>>>> - dev_err(adev->dev, "ib ring test failed (%d).\n", r); >>>>>> - r = amdgpu_device_ip_suspend(adev); >>>>>> - need_full_reset = true; >>>>>> - goto retry; >>>>>> - } >>>>>> - } >>>>>> - >>>>>> - if (!r) >>>>>> - r = amdgpu_device_recover_vram(adev); >>>>>> - >>>>>> - return r; >>>>>> -} >>>>>> /** >>>>>> * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf >>>>>> @@ -3335,31 +3255,16 @@ bool >>>>>> amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) >>>>>> return false; >>>>>> } >>>>>> -/** >>>>>> - * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>>>> - * >>>>>> - * @adev: amdgpu device pointer >>>>>> - * @job: which job trigger hang >>>>>> - * >>>>>> - * Attempt to reset the GPU if it has hung (all asics). >>>>>> - * Returns 0 for success or an error on failure. >>>>>> - */ >>>>>> -int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>>>> - struct amdgpu_job *job) >>>>>> -{ >>>>>> - int i, r, resched; >>>>>> - >>>>>> - dev_info(adev->dev, "GPU reset begin!\n"); >>>>>> - >>>>>> - mutex_lock(&adev->lock_reset); >>>>>> - atomic_inc(&adev->gpu_reset_counter); >>>>>> - adev->in_gpu_reset = 1; >>>>>> - /* Block kfd */ >>>>>> - amdgpu_amdkfd_pre_reset(adev); >>>>>> +static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, >>>>>> + struct amdgpu_job *job, >>>>>> + bool *need_full_reset_arg) >>>>>> +{ >>>>>> + int i, r = 0; >>>>>> + bool need_full_reset = *need_full_reset_arg; >>>>>> /* block TTM */ >>>>>> - resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>>>> + adev->resched = >>>>>> ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); >>>>>> /* block all schedulers and reset given job's ring */ >>>>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>>>> @@ -3379,10 +3284,121 @@ int amdgpu_device_gpu_recover(struct >>>>>> amdgpu_device *adev, >>>>>> amdgpu_fence_driver_force_completion(ring); >>>>>> } >>>>>> - if (amdgpu_sriov_vf(adev)) >>>>>> - r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>>>> - else >>>>>> - r = amdgpu_device_reset(adev); >>>>>> + if (!amdgpu_sriov_vf(adev)) { >>>>>> + >>>>>> + if (!need_full_reset) >>>>>> + need_full_reset = >>>>>> amdgpu_device_ip_need_full_reset(adev); >>>>>> + >>>>>> + if (!need_full_reset) { >>>>>> + amdgpu_device_ip_pre_soft_reset(adev); >>>>>> + r = amdgpu_device_ip_soft_reset(adev); >>>>>> + amdgpu_device_ip_post_soft_reset(adev); >>>>>> + if (r || amdgpu_device_ip_check_soft_reset(adev)) { >>>>>> + DRM_INFO("soft reset failed, will fallback to full >>>>>> reset!\n"); >>>>>> + need_full_reset = true; >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + if (need_full_reset) >>>>>> + r = amdgpu_device_ip_suspend(adev); >>>>>> + >>>>>> + *need_full_reset_arg = need_full_reset; >>>>>> + } >>>>>> + >>>>>> + return r; >>>>>> +} >>>>>> + >>>>>> +static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, >>>>>> + struct list_head *device_list_handle, >>>>>> + bool *need_full_reset_arg) >>>>>> +{ >>>>>> + struct amdgpu_device *tmp_adev = NULL; >>>>>> + bool need_full_reset = *need_full_reset_arg, vram_lost = false; >>>>>> + int r = 0; >>>>>> + >>>>>> + /* >>>>>> + * ASIC reset has to be done on all HGMI hive nodes ASAP >>>>>> + * to allow proper links negotiation in FW (within 1 sec) >>>>>> + */ >>>>>> + if (need_full_reset) { >>>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>>> gmc.xgmi.head) { >>>>>> + r = amdgpu_asic_reset(tmp_adev); >>>>>> + if (r) >>>>>> + DRM_WARN("ASIC reset failed with err r, %d for drm >>>>>> dev, %s", >>>>>> + r, tmp_adev->ddev->unique); >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + >>>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>>> gmc.xgmi.head) { >>>>>> + if (need_full_reset) { >>>>>> + /* post card */ >>>>>> + if >>>>>> (amdgpu_atom_asic_init(tmp_adev->mode_info.atom_context)) >>>>>> + DRM_WARN("asic atom init failed!"); >>>>>> + >>>>>> + if (!r) { >>>>>> + dev_info(tmp_adev->dev, "GPU reset succeeded, >>>>>> trying to resume\n"); >>>>>> + r = amdgpu_device_ip_resume_phase1(tmp_adev); >>>>>> + if (r) >>>>>> + goto out; >>>>>> + >>>>>> + vram_lost = >>>>>> amdgpu_device_check_vram_lost(tmp_adev); >>>>>> + if (vram_lost) { >>>>>> + DRM_ERROR("VRAM is lost!\n"); >>>>>> + atomic_inc(&tmp_adev->vram_lost_counter); >>>>>> + } >>>>>> + >>>>>> + r = amdgpu_gtt_mgr_recover( >>>>>> + &tmp_adev->mman.bdev.man[TTM_PL_TT]); >>>>>> + if (r) >>>>>> + goto out; >>>>>> + >>>>>> + r = amdgpu_device_fw_loading(tmp_adev); >>>>>> + if (r) >>>>>> + return r; >>>>>> + >>>>>> + r = amdgpu_device_ip_resume_phase2(tmp_adev); >>>>>> + if (r) >>>>>> + goto out; >>>>>> + >>>>>> + if (vram_lost) >>>>>> + amdgpu_device_fill_reset_magic(tmp_adev); >>>>>> + >>>>>> + /* Update PSP FW topology after reset */ >>>>>> + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) >>>>>> + r = amdgpu_xgmi_update_topology(hive, >>>>>> tmp_adev); >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + >>>>>> +out: >>>>>> + if (!r) { >>>>>> + amdgpu_irq_gpu_reset_resume_helper(tmp_adev); >>>>>> + r = amdgpu_ib_ring_tests(tmp_adev); >>>>>> + if (r) { >>>>>> + dev_err(tmp_adev->dev, "ib ring test failed >>>>>> (%d).\n", r); >>>>>> + r = amdgpu_device_ip_suspend(tmp_adev); >>>>>> + need_full_reset = true; >>>>>> + r = -EAGAIN; >>>>>> + goto end; >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + if (!r) >>>>>> + r = amdgpu_device_recover_vram(tmp_adev); >>>>>> + else >>>>>> + tmp_adev->asic_reset_res = r; >>>>>> + } >>>>>> + >>>>>> +end: >>>>>> + *need_full_reset_arg = need_full_reset; >>>>>> + return r; >>>>>> +} >>>>>> + >>>>>> +static void amdgpu_device_post_asic_reset(struct amdgpu_device >>>>>> *adev, >>>>>> + struct amdgpu_job *job) >>>>>> +{ >>>>>> + int i; >>>>>> for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { >>>>>> struct amdgpu_ring *ring = adev->rings[i]; >>>>>> @@ -3394,7 +3410,7 @@ int amdgpu_device_gpu_recover(struct >>>>>> amdgpu_device *adev, >>>>>> * or all rings (in the case @job is NULL) >>>>>> * after above amdgpu_reset accomplished >>>>>> */ >>>>>> - if ((!job || job->base.sched == &ring->sched) && !r) >>>>>> + if ((!job || job->base.sched == &ring->sched) && >>>>>> !adev->asic_reset_res) >>>>>> drm_sched_job_recovery(&ring->sched); >>>>>> kthread_unpark(ring->sched.thread); >>>>>> @@ -3404,21 +3420,150 @@ int amdgpu_device_gpu_recover(struct >>>>>> amdgpu_device *adev, >>>>>> drm_helper_resume_force_mode(adev->ddev); >>>>>> } >>>>>> - ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); >>>>>> + ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, adev->resched); >>>>>> - if (r) { >>>>>> - /* bad news, how to tell it to userspace ? */ >>>>>> - dev_info(adev->dev, "GPU reset(%d) failed\n", >>>>>> atomic_read(&adev->gpu_reset_counter)); >>>>>> - amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, >>>>>> 0, r); >>>>>> - } else { >>>>>> - dev_info(adev->dev, "GPU reset(%d) >>>>>> succeeded!\n",atomic_read(&adev->gpu_reset_counter)); >>>>>> - } >>>>>> + adev->asic_reset_res = adev->resched = 0; >>>>>> + >>>>>> +} >>>>>> +static void amdgpu_lock_adev(struct amdgpu_device *adev) >>>>>> +{ >>>>>> + mutex_lock(&adev->lock_reset); >>>>>> + atomic_inc(&adev->gpu_reset_counter); >>>>>> + adev->in_gpu_reset = 1; >>>>>> + /* Block kfd */ >>>>>> + amdgpu_amdkfd_pre_reset(adev); >>>>>> +} >>>>>> + >>>>>> +static void amdgpu_unlock_adev(struct amdgpu_device *adev) >>>>>> +{ >>>>>> /*unlock kfd */ >>>>>> amdgpu_amdkfd_post_reset(adev); >>>>>> amdgpu_vf_error_trans_all(adev); >>>>>> adev->in_gpu_reset = 0; >>>>>> mutex_unlock(&adev->lock_reset); >>>>>> +} >>>>>> + >>>>>> + >>>>>> +/** >>>>>> + * amdgpu_device_gpu_recover - reset the asic and recover scheduler >>>>>> + * >>>>>> + * @adev: amdgpu device pointer >>>>>> + * @job: which job trigger hang >>>>>> + * >>>>>> + * Attempt to reset the GPU if it has hung (all asics). >>>>>> + * Attempt to do soft-reset or full-reset and reinitialize Asic >>>>>> + * Returns 0 for success or an error on failure. >>>>>> + */ >>>>>> + >>>>>> +int amdgpu_device_gpu_recover(struct amdgpu_device *adev, >>>>>> + struct amdgpu_job *job) >>>>>> +{ >>>>>> + int r; >>>>>> + struct amdgpu_hive_info *hive = NULL; >>>>>> + bool need_full_reset = false; >>>>>> + struct amdgpu_device *tmp_adev = NULL; >>>>>> + struct list_head device_list, *device_list_handle = NULL; >>>>>> + >>>>>> + INIT_LIST_HEAD(&device_list); >>>>>> + >>>>>> + dev_info(adev->dev, "GPU reset begin!\n"); >>>>>> + >>>>>> + /* >>>>>> + * In case of XGMI hive disallow concurrent resets to be >>>>>> triggered >>>>>> + * by different nodes. >>>>>> + */ >>>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>>> + mutex_lock(&xgmi_mutex); >>>>>> + >>>>>> + /* Start with adev pre asic reset first for soft reset check.*/ >>>>>> + amdgpu_lock_adev(adev); >>>>>> + r = amdgpu_device_pre_asic_reset(adev, >>>>>> + job, >>>>>> + &need_full_reset); >>>>>> + if (r) { >>>>>> + /*TODO Should we stop ?*/ >>>>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for drm >>>>>> dev, %s ", >>>>>> + r, adev->ddev->unique); >>>>>> + adev->asic_reset_res = r; >>>>>> + } >>>>>> + >>>>>> + /* Build list of devices to reset */ >>>>>> + if (need_full_reset && adev->gmc.xgmi.num_physical_nodes > >>>>>> 1) { >>>>>> + hive = amdgpu_get_xgmi_hive(adev); >>>>>> + if (!hive) { >>>>>> + r = -ENODEV; >>>>>> + >>>>>> + amdgpu_unlock_adev(adev); >>>>>> + >>>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>>> + mutex_unlock(&xgmi_mutex); >>>>>> + return r; >>>>>> + } >>>>>> + >>>>>> + /* >>>>>> + * In case we are in XGMI hive mode device reset is done >>>>>> for all the >>>>>> + * nodes in the hive to retrain all XGMI links and hence >>>>>> the reset >>>>>> + * sequence is executed in loop on all nodes. >>>>>> + */ >>>>>> + device_list_handle = >>>>>> amdgpu_xgmi_get_adev_list_handle(hive); >>>>>> + } else { >>>>>> + list_add_tail(&adev->gmc.xgmi.head, &device_list); >>>>>> + device_list_handle = &device_list; >>>>>> + } >>>>>> + >>>>>> +retry: /* Rest of adevs pre asic reset from XGMI hive. */ >>>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>>> gmc.xgmi.head) { >>>>>> + >>>>>> + if (tmp_adev == adev) >>>>>> + continue; >>>>>> + >>>>>> + dev_info(tmp_adev->dev, "GPU reset begin for drm dev >>>>>> %s!\n", adev->ddev->unique); >>>>>> + >>>>>> + amdgpu_lock_adev(tmp_adev); >>>>>> + r = amdgpu_device_pre_asic_reset(tmp_adev, >>>>>> + NULL, >>>>>> + &need_full_reset); >>>>>> + /*TODO Should we stop ?*/ >>>>>> + if (r) { >>>>>> + DRM_ERROR("GPU pre asic reset failed with err, %d for >>>>>> drm dev, %s ", >>>>>> + r, tmp_adev->ddev->unique); >>>>>> + tmp_adev->asic_reset_res = r; >>>>>> + } >>>>>> + } >>>>>> + >>>>>> + /* Actual ASIC resets if needed.*/ >>>>>> + /* TODO Implement XGMI hive reset logic for SRIOV */ >>>>>> + if (amdgpu_sriov_vf(adev)) { >>>>>> + r = amdgpu_device_reset_sriov(adev, job ? false : true); >>>>>> + if (r) >>>>>> + adev->asic_reset_res = r; >>>>>> + } else { >>>>>> + r = amdgpu_do_asic_reset(hive, device_list_handle, >>>>>> &need_full_reset); >>>>>> + if (r && r == -EAGAIN) >>>>>> + goto retry; >>>>>> + } >>>>>> + >>>>>> + /* Post ASIC reset for all devs .*/ >>>>>> + list_for_each_entry(tmp_adev, device_list_handle, >>>>>> gmc.xgmi.head) { >>>>>> + amdgpu_device_post_asic_reset(tmp_adev, tmp_adev == adev ? >>>>>> job : NULL); >>>>>> + >>>>>> + if (r) { >>>>>> + /* bad news, how to tell it to userspace ? */ >>>>>> + dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", >>>>>> atomic_read(&adev->gpu_reset_counter)); >>>>>> + amdgpu_vf_error_put(tmp_adev, >>>>>> AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); >>>>>> + } else { >>>>>> + dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", >>>>>> atomic_read(&adev->gpu_reset_counter)); >>>>>> + } >>>>>> + >>>>>> + amdgpu_unlock_adev(tmp_adev); >>>>>> + } >>>>>> + >>>>>> + if (adev->gmc.xgmi.num_physical_nodes > 1) >>>>>> + mutex_unlock(&xgmi_mutex); >>>>>> + >>>>>> + if (r) >>>>>> + dev_info(adev->dev, "GPU reset end with ret = %d\n", r); >>>>>> return r; >>>>>> } >>>> _______________________________________________ >>>> amd-gfx mailing list >>>> amd-gfx@lists.freedesktop.org >>>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx >> _______________________________________________ >> amd-gfx mailing list >> amd-gfx@lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/amd-gfx > _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <329e176f-ab36-fc79-8646-484975ebb8c3-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <329e176f-ab36-fc79-8646-484975ebb8c3-5C7GfCeVMHo@public.gmane.org> @ 2018-11-26 19:28 ` Grodzovsky, Andrey [not found] ` <71b1c9db-68ec-d4bf-d125-1aed69769fc1-5C7GfCeVMHo@public.gmane.org> 0 siblings, 1 reply; 21+ messages in thread From: Grodzovsky, Andrey @ 2018-11-26 19:28 UTC (permalink / raw) To: Koenig, Christian, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk [-- Attachment #1.1: Type: text/plain, Size: 2031 bytes --] Actually, after looking again at drm_sched_job_timedout from which the amdgpu_device_gpu_recover will be called I see that we already disconnect all the pending scheduler fences from the HW fence, including the guilty job. I also see that in drm_sched_job_timedout job_list_lock is released before calling sched->ops->timedout_job and then required after, so new jobs can slip into ring_mirror_list in between. And also i will end up going over the ring_mirror_list twice, once from amdgpu_device_post_asic_reset and later from drm_sched_job_timedout - this might cause double fence processing. Isn't it more correct only do the disconnect from HW fence after the schedules have been stopped and connect back before we restart the schedulers (as you pointed out here before) What I mean is - should we get rid of dma_fence_add/remove_callback logic in drm_sched_job_timedout and do it for each driver in between scheduler deactivation and activation back ? Andrey On 11/22/2018 02:56 PM, Grodzovsky, Andrey wrote: Additional to that I would try improve the pre, middle, post handling towards checking if we made some progress in between. In other words we stop all schedulers in the pre handling and disconnect the scheduler fences from the hardware fence like I did in patch "drm/sched: fix timeout handling v2". Then before we do the actual reset in the middle handling we check if the offending job has completed or at least made some progress in the meantime. I understand how to check if the job completed - if it's fence already signaled, but how do I test if the job made 'at least some progress' ? Good question. Maybe we can somehow query from the hardware the number of primitives or pixels processed so far and then compare after a moment? I will check on this later. In the mean while I will update the code with the proposed per hive locking and I will add the check if the guilty job completed before ASIC reset skipping the reset if it's did. Andrey [-- Attachment #1.2: Type: text/html, Size: 2698 bytes --] [-- Attachment #2: Type: text/plain, Size: 154 bytes --] _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <71b1c9db-68ec-d4bf-d125-1aed69769fc1-5C7GfCeVMHo@public.gmane.org>]
* Re: [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case. [not found] ` <71b1c9db-68ec-d4bf-d125-1aed69769fc1-5C7GfCeVMHo@public.gmane.org> @ 2018-11-26 19:34 ` Christian König 0 siblings, 0 replies; 21+ messages in thread From: Christian König @ 2018-11-26 19:34 UTC (permalink / raw) To: Grodzovsky, Andrey, Koenig, Christian, Liu, Shaoyun, amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org Cc: Deucher, Alexander, Liu, Monk [-- Attachment #1.1: Type: text/plain, Size: 2714 bytes --] > What I mean is - should we get rid of dma_fence_add/remove_callback > logic in drm_sched_job_timedout and do it for each driver in between > > scheduler deactivation and activation back ? > Yes, exactly. That's the reason why I already have a revert for the patch and remove the dance from drm_sched_job_timedout again. Christian. Am 26.11.18 um 20:28 schrieb Grodzovsky, Andrey: > > > Actually, after looking again at drm_sched_job_timedout from which > the amdgpu_device_gpu_recover will be called I see that we already > disconnect all the pending scheduler fences from the HW fence, including > the guilty job. I also see that in drm_sched_job_timedout > job_list_lock is released before calling sched->ops->timedout_job and > then required after, so new jobs can slip into ring_mirror_list in > between. > > And also i will end up going over the ring_mirror_list twice, once > from amdgpu_device_post_asic_reset and later from > drm_sched_job_timedout - this might cause double fence processing. > > Isn't it more correct only do the disconnect from HW fence after the > schedules have been stopped and connect back before we restart the > schedulers (as you pointed out here before) > > What I mean is - should we get rid of dma_fence_add/remove_callback > logic in drm_sched_job_timedout and do it for each driver in between > > scheduler deactivation and activation back ? > > Andrey > > > On 11/22/2018 02:56 PM, Grodzovsky, Andrey wrote: >>>>> Additional to that I would try improve the pre, middle, post handling >>>>> towards checking if we made some progress in between. >>>>> >>>>> In other words we stop all schedulers in the pre handling and >>>>> disconnect the scheduler fences from the hardware fence like I did in >>>>> patch "drm/sched: fix timeout handling v2". >>>>> >>>>> Then before we do the actual reset in the middle handling we check if >>>>> the offending job has completed or at least made some progress in the >>>>> meantime. >>>> I understand how to check if the job completed - if it's fence already >>>> signaled, but how do I test if the job made 'at least some progress' ? >>> Good question. Maybe we can somehow query from the hardware the number >>> of primitives or pixels processed so far and then compare after a moment? >> I will check on this later. In the mean while I will update the code >> with the proposed per hive locking and I will add the check if the >> guilty job completed before ASIC reset skipping the reset if it's did. >> >> Andrey >> > > > _______________________________________________ > amd-gfx mailing list > amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx [-- Attachment #1.2: Type: text/html, Size: 4366 bytes --] [-- Attachment #2: Type: text/plain, Size: 154 bytes --] _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2018-11-26 19:34 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-21 18:10 [PATCH 0/5] Add support for XGMI hive reset Andrey Grodzovsky
[not found] ` <1542823821-15631-1-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 18:10 ` [PATCH 1/5] drm/amdgpu/psp: Add mode 0 reset function Andrey Grodzovsky
[not found] ` <1542823821-15631-2-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:22 ` Alex Deucher
2018-11-21 18:10 ` [PATCH 2/5] drm/amdgpu/psp: Enable mode 0 reset for XGMI Andrey Grodzovsky
[not found] ` <1542823821-15631-3-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:23 ` Alex Deucher
2018-11-21 18:10 ` [PATCH 3/5] drm/amdgpu: Refactor amdgpu_xgmi_add_device Andrey Grodzovsky
[not found] ` <1542823821-15631-4-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:29 ` Alex Deucher
[not found] ` <CADnq5_MSpxAXsdwh+NzXCrOGVVo3gog9FjdzRNaX9ZhwuatmKg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-11-21 19:36 ` Grodzovsky, Andrey
[not found] ` <aa7ee809-8f1f-c4de-c674-4b11f77b70f3-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:38 ` Alex Deucher
2018-11-21 18:10 ` [PATCH 4/5] drm/amdgpu: Expose hive adev list and xgmi_mutex Andrey Grodzovsky
[not found] ` <1542823821-15631-5-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:45 ` Alex Deucher
2018-11-21 18:10 ` [PATCH 5/5] drm/amdgpu: Refactor GPU reset for XGMI hive case Andrey Grodzovsky
[not found] ` <1542823821-15631-6-git-send-email-andrey.grodzovsky-5C7GfCeVMHo@public.gmane.org>
2018-11-21 19:45 ` Alex Deucher
2018-11-21 20:49 ` Liu, Shaoyun
[not found] ` <ef758cf9-9e27-9807-4e25-47148782249e-5C7GfCeVMHo@public.gmane.org>
2018-11-21 22:02 ` Grodzovsky, Andrey
[not found] ` <5f257299-4833-82b7-83ec-75bf02c4e441-5C7GfCeVMHo@public.gmane.org>
2018-11-22 11:16 ` Christian König
[not found] ` <8e9f51a4-7f0a-c435-c507-34eea96e0b08-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-11-22 15:44 ` Grodzovsky, Andrey
[not found] ` <9e016b33-6c94-b1cb-cdcd-b68b91436e90-5C7GfCeVMHo@public.gmane.org>
2018-11-22 19:03 ` Christian König
[not found] ` <0f048ac9-1247-8d87-d8c8-5a249e24cdcb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2018-11-22 19:56 ` Grodzovsky, Andrey
[not found] ` <329e176f-ab36-fc79-8646-484975ebb8c3-5C7GfCeVMHo@public.gmane.org>
2018-11-26 19:28 ` Grodzovsky, Andrey
[not found] ` <71b1c9db-68ec-d4bf-d125-1aed69769fc1-5C7GfCeVMHo@public.gmane.org>
2018-11-26 19:34 ` Christian König
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox