[PATCH v2 4/4] drm/amdgpu: Implement virt req_ras_err_count
Lazar, Lijo
lijo.lazar at amd.com
Thu Nov 7 07:56:18 UTC 2024
On 11/6/2024 12:34 AM, Victor Skvortsov wrote:
> Enable RAS late init if VF RAS Telemetry is supported.
>
> When enabled, the VF can use this interface to query total
> RAS error counts from the host.
>
> The VF FB access may abruptly end due to a fatal error,
> therefore the VF must cache and sanitize the input.
>
> The Host allows 15 Telemetry messages every 60 seconds, afterwhich
> the host will ignore any more in-coming telemetry messages. The VF will
> rate limit its msg calling to once every 5 seconds (12 times in 60 seconds).
> While the VF is rate limited, it will continue to report the last
> good cached data.
>
> v2: Flip generate report & update statistics order for VF
>
> Signed-off-by: Victor Skvortsov <victor.skvortsov at amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 3 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 72 +++++++++--
> drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 3 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 138 +++++++++++++++++++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 15 +++
> 7 files changed, 231 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 383bbee87df5..c22a9925cba7 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -4235,7 +4235,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
> * for throttling interrupt) = 60 seconds.
> */
> ratelimit_state_init(&adev->throttling_logging_rs, (60 - 1) * HZ, 1);
> + ratelimit_state_init(&adev->virt.ras_telemetry_rs, 5 * HZ, 1);
> +
> ratelimit_set_flags(&adev->throttling_logging_rs, RATELIMIT_MSG_ON_RELEASE);
> + ratelimit_set_flags(&adev->virt.ras_telemetry_rs, RATELIMIT_MSG_ON_RELEASE);
>
> /* Registers mapping */
> /* TODO: block userspace mapping of io register */
> @@ -5185,6 +5188,9 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
> amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
> amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3))
> amdgpu_ras_resume(adev);
> +
> + amdgpu_virt_ras_telemetry_post_reset(adev);
> +
> return 0;
> }
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
> index b8cc4b146bdc..8c9fcfb7f22e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
> @@ -885,6 +885,9 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
> if (r)
> return r;
>
> + if (amdgpu_sriov_vf(adev))
> + return r;
> +
> if (adev->gfx.cp_ecc_error_irq.funcs) {
> r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
> if (r)
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> index 89d87dc17ac1..a8b4f4178e5a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
> @@ -1214,6 +1214,42 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev,
> }
> }
>
> +static void amdgpu_ras_virt_error_generate_report(struct amdgpu_device *adev,
> + struct ras_query_if *query_if,
> + struct ras_err_data *err_data,
> + struct ras_query_context *qctx)
> +{
> + unsigned long new_ue, new_ce, new_de;
> + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &query_if->head);
> + const char *blk_name = get_ras_block_str(&query_if->head);
> + u64 event_id = qctx->event_id;
> +
> + new_ce = err_data->ce_count - obj->err_data.ce_count;
> + new_ue = err_data->ue_count - obj->err_data.ue_count;
> + new_de = err_data->de_count - obj->err_data.de_count;
> +
> + if (new_ce) {
> + RAS_EVENT_LOG(adev, event_id, "%lu correctable hardware errors "
> + "detected in %s block\n",
> + new_ce,
> + blk_name);
> + }
> +
> + if (new_ue) {
> + RAS_EVENT_LOG(adev, event_id, "%lu uncorrectable hardware errors "
> + "detected in %s block\n",
> + new_ue,
> + blk_name);
> + }
> +
> + if (new_de) {
> + RAS_EVENT_LOG(adev, event_id, "%lu deferred hardware errors "
> + "detected in %s block\n",
> + new_de,
> + blk_name);
> + }
> +}
> +
> static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, struct ras_err_data *err_data)
> {
> struct ras_err_node *err_node;
> @@ -1237,6 +1273,15 @@ static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, s
> }
> }
>
> +static void amdgpu_ras_mgr_virt_error_data_statistics_update(struct ras_manager *obj,
> + struct ras_err_data *err_data)
> +{
> + /* Host reports absolute counts */
> + obj->err_data.ue_count = err_data->ue_count;
> + obj->err_data.ce_count = err_data->ce_count;
> + obj->err_data.de_count = err_data->de_count;
> +}
> +
> static struct ras_manager *get_ras_manager(struct amdgpu_device *adev, enum amdgpu_ras_block blk)
> {
> struct ras_common_if head;
> @@ -1323,7 +1368,9 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev,
> if (error_query_mode == AMDGPU_RAS_INVALID_ERROR_QUERY)
> return -EINVAL;
>
> - if (error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) {
> + if (error_query_mode == AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY) {
> + return amdgpu_virt_req_ras_err_count(adev, blk, err_data);
> + } else if (error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) {
> if (info->head.block == AMDGPU_RAS_BLOCK__UMC) {
> amdgpu_ras_get_ecc_info(adev, err_data);
> } else {
> @@ -1405,14 +1452,22 @@ static int amdgpu_ras_query_error_status_with_event(struct amdgpu_device *adev,
> if (ret)
> goto out_fini_err_data;
>
> - amdgpu_rasmgr_error_data_statistic_update(obj, &err_data);
> + if (error_query_mode != AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY) {
> + amdgpu_rasmgr_error_data_statistic_update(obj, &err_data);
> + amdgpu_ras_error_generate_report(adev, info, &err_data, &qctx);
> + } else {
> + /* Host provides absolute error counts. First generate the report
> + * using the previous VF internal count against new host count.
> + * Then Update VF internal count.
> + */
> + amdgpu_ras_virt_error_generate_report(adev, info, &err_data, &qctx);
> + amdgpu_ras_mgr_virt_error_data_statistics_update(obj, &err_data);
> + }
>
> info->ue_count = obj->err_data.ue_count;
> info->ce_count = obj->err_data.ce_count;
> info->de_count = obj->err_data.de_count;
>
> - amdgpu_ras_error_generate_report(adev, info, &err_data, &qctx);
> -
> out_fini_err_data:
> amdgpu_ras_error_data_fini(&err_data);
>
> @@ -3929,7 +3984,7 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev)
> }
>
> /* Guest side doesn't need init ras feature */
> - if (amdgpu_sriov_vf(adev))
> + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_telemetry_en(adev))
> return 0;
>
> list_for_each_entry_safe(node, tmp, &adev->ras_list, node) {
> @@ -4396,11 +4451,14 @@ bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev,
> return false;
> }
>
> - if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode))
> + if (amdgpu_sriov_vf(adev)) {
> + *error_query_mode = AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY;
> + } else if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode)) {
> *error_query_mode =
> (con->is_aca_debug_mode) ? AMDGPU_RAS_DIRECT_ERROR_QUERY : AMDGPU_RAS_FIRMWARE_ERROR_QUERY;
> - else
> + } else {
> *error_query_mode = AMDGPU_RAS_DIRECT_ERROR_QUERY;
> + }
>
> return true;
> }
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> index 871b2d6278e0..6db772ecfee4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
> @@ -365,6 +365,7 @@ enum amdgpu_ras_error_query_mode {
> AMDGPU_RAS_INVALID_ERROR_QUERY = 0,
> AMDGPU_RAS_DIRECT_ERROR_QUERY = 1,
> AMDGPU_RAS_FIRMWARE_ERROR_QUERY = 2,
> + AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY = 3,
> };
>
> /* ras error status reisger fields */
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
> index bb7b9b2eaac1..896f3609b0ee 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
> @@ -318,6 +318,9 @@ int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
> if (r)
> return r;
>
> + if (amdgpu_sriov_vf(adev))
> + return r;
> +
> if (amdgpu_ras_is_supported(adev, ras_block->block)) {
> r = amdgpu_irq_get(adev, &adev->gmc.ecc_irq, 0);
> if (r)
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
> index 53297c40f09c..b1e584e4ef13 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
> @@ -524,6 +524,8 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev)
> adev->unique_id =
> ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->uuid;
> adev->virt.ras_en_caps.all = ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->ras_en_caps.all;
> + adev->virt.ras_telemetry_en_caps.all =
> + ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->ras_telemetry_en_caps.all;
> break;
> default:
> dev_err(adev->dev, "invalid pf2vf version: 0x%x\n", pf2vf_info->version);
> @@ -704,6 +706,8 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev)
> adev->virt.fw_reserve.p_vf2pf =
> (struct amd_sriov_msg_vf2pf_info_header *)
> (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
> + adev->virt.fw_reserve.ras_telemetry =
> + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10));
Shouldn't it check if it's telemetry capable before this assignment?
Overall, it feels like it would be better to have a ras manager/ras
control block under virt which maintains
count_cache
ras_telemetry_rs
req_ras_err_count
ras_telemetry_en_caps
It gets initialized only if ras capability and ras telemetry capability
is detected - amdgpu_virt_ras_init and then go from there. Also, makes
it easier for read, if all starts like amdgpu_virt_ras
amdgpu_virt_req_ras_err_count => amdgpu_virt_ras_req_err_count
amdgpu_virt_cache_host_ => amdgpu_virt_ras_cache_host_errors
and so forth.
> } else if (adev->mman.drv_vram_usage_va) {
> adev->virt.fw_reserve.p_pf2vf =
> (struct amd_sriov_msg_pf2vf_info_header *)
> @@ -711,6 +715,8 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev)
> adev->virt.fw_reserve.p_vf2pf =
> (struct amd_sriov_msg_vf2pf_info_header *)
> (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10));
> + adev->virt.fw_reserve.ras_telemetry =
> + (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10));
> }
>
> amdgpu_virt_read_pf2vf_data(adev);
> @@ -1197,3 +1203,135 @@ bool amdgpu_virt_get_ras_capability(struct amdgpu_device *adev)
>
> return true;
> }
> +
> +static inline enum amd_sriov_ras_telemetry_gpu_block
> +amdgpu_ras_block_to_sriov(struct amdgpu_device *adev, enum amdgpu_ras_block block) {
> + switch (block) {
> + case AMDGPU_RAS_BLOCK__UMC:
> + return RAS_TELEMETRY_GPU_BLOCK_UMC;
> + case AMDGPU_RAS_BLOCK__SDMA:
> + return RAS_TELEMETRY_GPU_BLOCK_SDMA;
> + case AMDGPU_RAS_BLOCK__GFX:
> + return RAS_TELEMETRY_GPU_BLOCK_GFX;
> + case AMDGPU_RAS_BLOCK__MMHUB:
> + return RAS_TELEMETRY_GPU_BLOCK_MMHUB;
> + case AMDGPU_RAS_BLOCK__ATHUB:
> + return RAS_TELEMETRY_GPU_BLOCK_ATHUB;
> + case AMDGPU_RAS_BLOCK__PCIE_BIF:
> + return RAS_TELEMETRY_GPU_BLOCK_PCIE_BIF;
> + case AMDGPU_RAS_BLOCK__HDP:
> + return RAS_TELEMETRY_GPU_BLOCK_HDP;
> + case AMDGPU_RAS_BLOCK__XGMI_WAFL:
> + return RAS_TELEMETRY_GPU_BLOCK_XGMI_WAFL;
> + case AMDGPU_RAS_BLOCK__DF:
> + return RAS_TELEMETRY_GPU_BLOCK_DF;
> + case AMDGPU_RAS_BLOCK__SMN:
> + return RAS_TELEMETRY_GPU_BLOCK_SMN;
> + case AMDGPU_RAS_BLOCK__SEM:
> + return RAS_TELEMETRY_GPU_BLOCK_SEM;
> + case AMDGPU_RAS_BLOCK__MP0:
> + return RAS_TELEMETRY_GPU_BLOCK_MP0;
> + case AMDGPU_RAS_BLOCK__MP1:
> + return RAS_TELEMETRY_GPU_BLOCK_MP1;
> + case AMDGPU_RAS_BLOCK__FUSE:
> + return RAS_TELEMETRY_GPU_BLOCK_FUSE;
> + case AMDGPU_RAS_BLOCK__MCA:
> + return RAS_TELEMETRY_GPU_BLOCK_MCA;
> + case AMDGPU_RAS_BLOCK__VCN:
> + return RAS_TELEMETRY_GPU_BLOCK_VCN;
> + case AMDGPU_RAS_BLOCK__JPEG:
> + return RAS_TELEMETRY_GPU_BLOCK_JPEG;
> + case AMDGPU_RAS_BLOCK__IH:
> + return RAS_TELEMETRY_GPU_BLOCK_IH;
> + case AMDGPU_RAS_BLOCK__MPIO:
> + return RAS_TELEMETRY_GPU_BLOCK_MPIO;
> + default:
> + dev_err(adev->dev, "Unsupported SRIOV RAS telemetry block 0x%x\n", block);
> + return RAS_TELEMETRY_GPU_BLOCK_COUNT;
> + }
> +}
> +
> +static int amdgpu_virt_cache_host_error_counts(struct amdgpu_device *adev,
> + struct amdsriov_ras_telemetry *host_telemetry)
> +{
> + struct amd_sriov_ras_telemetry_error_count *tmp = { 0 };
> + uint32_t checksum, used_size, tmp_check;
> +
> + checksum = host_telemetry->header.checksum;
> + used_size = host_telemetry->header.used_size;
> +
> + if (used_size > (AMD_SRIOV_RAS_TELEMETRY_SIZE_KB << 10))
> + return 0;
> +
> + tmp = kmalloc(used_size, GFP_KERNEL);
> + if (!tmp)
> + return -ENOMEM;
> +
> + memcpy(tmp, &host_telemetry->body.error_count, used_size);
> +
> + tmp_check = amd_sriov_msg_checksum(tmp, used_size, 0, 0);
> + if (checksum != amd_sriov_msg_checksum(tmp, used_size, 0, 0))
> + goto out;
> +
> + /* Copy sanitized data to guest cache */
> + memcpy(&adev->virt.count_cache, tmp, sizeof(adev->virt.count_cache));
> +out:
> + kfree(tmp);
> +
> + return 0;
> +}
> +
> +static int amdgpu_virt_req_ras_err_count_internal(struct amdgpu_device *adev, bool force_update)
> +{
> + struct amdgpu_virt *virt = &adev->virt;
> +
> + /* Host allows 15 ras telemetry requests per 60 seconds. Afterwhich, the Host
> + * will ignore incoming guest messages. Ratelimit the guest messages to
> + * prevent guest self DOS.
> + */
> + if (__ratelimit(&adev->virt.ras_telemetry_rs) || force_update) {
> + if (!virt->ops->req_ras_err_count(adev))
> + amdgpu_virt_cache_host_error_counts(adev,
> + adev->virt.fw_reserve.ras_telemetry);
> + }
> +
> + return 0;
> +}
> +
> +/* Bypass ACA interface and query ECC counts directly from host */
> +int amdgpu_virt_req_ras_err_count(struct amdgpu_device *adev, enum amdgpu_ras_block block,
> + struct ras_err_data *err_data)
> +{
> + int ret;
> + enum amd_sriov_ras_telemetry_gpu_block sriov_block;
> +
> + sriov_block = amdgpu_ras_block_to_sriov(adev, block);
> +
> + if (sriov_block >= RAS_TELEMETRY_GPU_BLOCK_COUNT ||
> + !amdgpu_sriov_ras_telemetry_block_en(adev, sriov_block))
> + return -EOPNOTSUPP;
> +
> + /* Host Access may be lost during reset, just return last cached data. */
> + if (down_read_trylock(&adev->reset_domain->sem)) {
> + amdgpu_virt_req_ras_err_count_internal(adev, false);
> + up_read(&adev->reset_domain->sem);
> + }
> +
> + err_data->ue_count = adev->virt.count_cache.block[sriov_block].ue_count;
> + err_data->ce_count = adev->virt.count_cache.block[sriov_block].ce_count;
> + err_data->de_count = adev->virt.count_cache.block[sriov_block].de_count;
> +
> + return 0;
> +}
> +
> +int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev)
> +{
> + unsigned long ue_count, ce_count;
> +
> + if (amdgpu_sriov_ras_telemetry_en(adev)) {
> + amdgpu_virt_req_ras_err_count_internal(adev, true);
> + amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, NULL);
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
> index f0ff84add692..5381b8d596e6 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
> @@ -104,6 +104,7 @@ struct amdgpu_virt_ops {
> struct amdgpu_virt_fw_reserve {
> struct amd_sriov_msg_pf2vf_info_header *p_pf2vf;
> struct amd_sriov_msg_vf2pf_info_header *p_vf2pf;
> + void *ras_telemetry;
> unsigned int checksum_key;
> };
>
> @@ -138,6 +139,7 @@ enum AMDGIM_FEATURE_FLAG {
> /* MES info */
> AMDGIM_FEATURE_MES_INFO_ENABLE = (1 << 8),
> AMDGIM_FEATURE_RAS_CAPS = (1 << 9),
> + AMDGIM_FEATURE_RAS_TELEMETRY = (1 << 10),
> };
>
> enum AMDGIM_REG_ACCESS_FLAG {
> @@ -280,6 +282,10 @@ struct amdgpu_virt {
> struct mutex rlcg_reg_lock;
>
> union amd_sriov_ras_caps ras_en_caps;
> + union amd_sriov_ras_caps ras_telemetry_en_caps;
> +
> + struct ratelimit_state ras_telemetry_rs;
> + struct amd_sriov_ras_telemetry_error_count count_cache;
> };
>
> struct amdgpu_video_codec_info;
> @@ -327,6 +333,12 @@ struct amdgpu_video_codec_info;
> #define amdgpu_sriov_ras_caps_en(adev) \
> ((adev)->virt.gim_feature & AMDGIM_FEATURE_RAS_CAPS)
>
> +#define amdgpu_sriov_ras_telemetry_en(adev) \
> +(((adev)->virt.gim_feature & AMDGIM_FEATURE_RAS_TELEMETRY) && (adev)->virt.fw_reserve.ras_telemetry)
> +
As a matter of coding style/easier read, would be good if you could
maintain gim_feature checks at one place. Now it's mixed across.
Thanks,
Lijo
> +#define amdgpu_sriov_ras_telemetry_block_en(adev, sriov_blk) \
> +(amdgpu_sriov_ras_telemetry_en((adev)) && (adev)->virt.ras_telemetry_en_caps.all & BIT(sriov_blk))
> +
> static inline bool is_virtual_machine(void)
> {
> #if defined(CONFIG_X86)
> @@ -391,4 +403,7 @@ bool amdgpu_virt_get_rlcg_reg_access_flag(struct amdgpu_device *adev,
> bool write, u32 *rlcg_flag);
> u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v, u32 flag, u32 xcc_id);
> bool amdgpu_virt_get_ras_capability(struct amdgpu_device *adev);
> +int amdgpu_virt_req_ras_err_count(struct amdgpu_device *adev, enum amdgpu_ras_block block,
> + struct ras_err_data *err_data);
> +int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev);
> #endif
More information about the amd-gfx
mailing list