From cabbba1716c576a0c7089bc665a890cbd2f030b1 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 18 Dec 2025 18:41:35 +0800 Subject: [PATCH] drm/amdgpu: add generic interfaces for PTL requests in virtualization Add Performance Throttle Limiter (PTL) support for SR-IOV guest. Since VF cannot communicate with PSP directly at runtime in SR-IOV environment, use mailbox data fields to pass PTL parameters to PF, and parse response status from host mailbox registers. v2: - remove redundent checks - remove unused marco Signed-off-by: Victor Zhao Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 20 ++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 36 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 11 +++++++ drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 27 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c | 28 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h | 2 ++ 6 files changed, 121 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 2c23ea625171..aefe0967f010 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1292,8 +1292,19 @@ static int psp_ptl_invoke(struct psp_context *psp, u32 req_code, { struct psp_gfx_cmd_resp *cmd; struct amdgpu_ptl *ptl = &psp->ptl; + struct amdgpu_device *adev = psp->adev; int ret; + if (amdgpu_sriov_vf(adev)) { + ret = amdgpu_virt_ptl_request(adev, req_code, ptl_state, fmt1, fmt2); + if (!ret) { + ptl->enabled = *ptl_state; + ptl->fmt1 = *fmt1; + ptl->fmt2 = *fmt2; + } + return ret; + } + cmd = acquire_psp_cmd_buf(psp); cmd->cmd_id = GFX_CMD_ID_PERF_HW; @@ -1356,15 +1367,18 @@ int amdgpu_ptl_perf_monitor_ctrl(struct amdgpu_device *adev, u32 req_code, if (!adev || !ptl_state || !fmt1 || !fmt2) return -EINVAL; - if (amdgpu_sriov_vf(adev)) - return 0; - psp = &adev->psp; ptl = &psp->ptl; if (ptl->permanently_disabled && *ptl_state == 1) return 0; + if (amdgpu_sriov_vf(adev)) { + ptl_fmt1 = *fmt1; + ptl_fmt2 = *fmt2; + return psp_ptl_invoke(psp, req_code, ptl_state, &ptl_fmt1, &ptl_fmt2); + } + if (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 4) || psp->sos.fw_version < 0x0036081a) return -EOPNOTSUPP; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 8f4b86063507..b43fc643668d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -2090,3 +2090,39 @@ int amdgpu_virt_send_remote_ras_cmd(struct amdgpu_device *adev, return ret; } + +int amdgpu_virt_ptl_request(struct amdgpu_device *adev, u32 req_code, + uint32_t *ptl_state, uint32_t *fmt1, uint32_t *fmt2) +{ + int ret; + + if (!ptl_state || !fmt1 || !fmt2) + return -EINVAL; + + if (!amdgpu_sriov_ptl_support(adev) || + !adev->virt.ops || !adev->virt.ops->req_ptl_update) + return -EOPNOTSUPP; + + if (req_code == PSP_PTL_PERF_MON_SET && *ptl_state) { + if (*fmt1 == *fmt2) { + dev_warn(adev->dev, + "PTL formats must be different (fmt1=%u, fmt2=%u)\n", + *fmt1, *fmt2); + return -EINVAL; + } + } + + ret = adev->virt.ops->req_ptl_update(adev, req_code, *ptl_state, *fmt1, *fmt2); + if (ret) { + dev_warn(adev->dev, "VF PTL update request failed: %d\n", ret); + return ret; + } + + if (req_code == PSP_PTL_PERF_MON_QUERY) { + *ptl_state = adev->virt.ptl_state; + *fmt1 = adev->virt.ptl_pref_format1; + *fmt2 = adev->virt.ptl_pref_format2; + } + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index d8500c3e48a1..bcf7156a4a9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -116,6 +116,8 @@ struct amdgpu_virt_ops { int (*req_ras_chk_criti)(struct amdgpu_device *adev, u64 addr); int (*req_remote_ras_cmd)(struct amdgpu_device *adev, u32 param1, u32 param2, u32 param3); + int (*req_ptl_update)(struct amdgpu_device *adev, + u32 req_code, u32 ptl_state, u32 fmt1, u32 fmt2); }; /* @@ -341,6 +343,11 @@ struct amdgpu_virt { /* Spinlock to protect access to the RLCG register interface */ spinlock_t rlcg_reg_lock; + /* PTL (Performance Throttle Limiter) response from host */ + uint32_t ptl_state; + uint32_t ptl_pref_format1; + uint32_t ptl_pref_format2; + struct mutex access_req_mutex; union amd_sriov_ras_caps ras_en_caps; @@ -447,6 +454,8 @@ static inline bool is_virtual_machine(void) ((adev)->virt.gim_feature & AMDGIM_FEATURE_MES_INFO_ENABLE) #define amdgpu_sriov_is_unitid_support(adev) \ ((adev)->virt.gim_feature & AMDGIM_FEATURE_UNITID_SUPPORT) +#define amdgpu_sriov_ptl_support(adev) \ + ((adev)->virt.gim_feature & AMDGIM_FEATURE_PTL_SUPPORT) #define amdgpu_virt_xgmi_migrate_enabled(adev) \ ((adev)->virt.is_xgmi_node_migrate_enabled && (adev)->gmc.xgmi.node_segment_size != 0) @@ -457,6 +466,8 @@ int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init); int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init); int amdgpu_virt_reset_gpu(struct amdgpu_device *adev); void amdgpu_virt_request_init_data(struct amdgpu_device *adev); +int amdgpu_virt_ptl_request(struct amdgpu_device *adev, u32 req_code, + uint32_t *ptl_state, uint32_t *fmt1, uint32_t *fmt2); void amdgpu_virt_ready_to_reset(struct amdgpu_device *adev); int amdgpu_virt_wait_reset(struct amdgpu_device *adev); int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index b02561f41b58..33421ccdff04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -404,6 +404,9 @@ enum amd_sriov_mailbox_request_message { MB_REQ_RAS_ERROR_COUNT = 203, MB_REQ_RAS_CPER_DUMP = 204, MB_REQ_RAS_BAD_PAGES = 205, + MB_REQ_RAS_CHK_CRITI = 206, + MB_REQ_RAS_REMOTE_CMD = 207, + MB_REQ_MSG_PTL_UPDATE = 208, }; /* mailbox message send from host to guest */ @@ -424,9 +427,33 @@ enum amd_sriov_mailbox_response_message { MB_RES_MSG_RAS_BAD_PAGES_READY = 15, MB_RES_MSG_RAS_BAD_PAGES_NOTIFICATION = 16, MB_RES_MSG_UNRECOV_ERR_NOTIFICATION = 17, + MB_RES_RAS_CHK_CRITI_READY = 18, + MB_RES_RAS_REMOTE_CMD_READY = 19, + MB_RES_MSG_PTL_UPDATE_READY = 20, MB_RES_MSG_TEXT_MESSAGE = 255 }; +/* + * Generic response status codes for mailbox data fields. + * Used in msg_data[1..N] to indicate operation result. + */ +enum amd_sriov_response_status { + AMD_SRIOV_RESP_SUCCESS = 0, + AMD_SRIOV_RESP_FAIL = 1, + AMD_SRIOV_RESP_UNSUPPORTED = 2, +}; + +/* + * PTL mailbox data format: + * Request: msg_data[1]=req_code, msg_data[2]=ptl_state, msg_data[3]=(fmt1<<16)|fmt2 + * Response: msg_data[1]=(status<<16)|ptl_state, msg_data[2]=(fmt1<<16)|fmt2 + */ +#define AMD_SRIOV_PTL_PACK_FORMATS(fmt1, fmt2) ((((fmt1) & 0xFFFF) << 16) | ((fmt2) & 0xFFFF)) +#define AMD_SRIOV_PTL_UNPACK_STATUS(dw) (((dw) >> 16) & 0xFFFF) +#define AMD_SRIOV_PTL_UNPACK_STATE(dw) ((dw) & 0xFFFF) +#define AMD_SRIOV_PTL_UNPACK_FMT1(dw) (((dw) >> 16) & 0xFFFF) +#define AMD_SRIOV_PTL_UNPACK_FMT2(dw) ((dw) & 0xFFFF) + enum amd_sriov_ras_telemetry_gpu_block { RAS_TELEMETRY_GPU_BLOCK_UMC = 0, RAS_TELEMETRY_GPU_BLOCK_SDMA = 1, diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index f2e456390b27..eb537b2ae685 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -214,6 +214,9 @@ static int xgpu_nv_send_access_requests_with_param(struct amdgpu_device *adev, case IDH_REQ_RAS_REMOTE_CMD: event = IDH_REQ_RAS_REMOTE_CMD_READY; break; + case IDH_REQ_PTL_UPDATE: + event = IDH_PTL_UPDATE_READY; + break; default: break; } @@ -253,6 +256,23 @@ static int xgpu_nv_send_access_requests_with_param(struct amdgpu_device *adev, adev->virt.fw_reserve.checksum_key = RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW2); } + + /* Retrieve PTL response from mailbox */ + if (req == IDH_REQ_PTL_UPDATE) { + u32 dw1 = RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW1); + u32 dw2 = RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW2); + u32 status = AMD_SRIOV_PTL_UNPACK_STATUS(dw1); + + if (status == AMD_SRIOV_RESP_UNSUPPORTED) { + r = -EOPNOTSUPP; + } else if (status == AMD_SRIOV_RESP_FAIL) { + r = -EIO; + } else { + adev->virt.ptl_state = AMD_SRIOV_PTL_UNPACK_STATE(dw1); + adev->virt.ptl_pref_format1 = AMD_SRIOV_PTL_UNPACK_FMT1(dw2); + adev->virt.ptl_pref_format2 = AMD_SRIOV_PTL_UNPACK_FMT2(dw2); + } + } } out: @@ -597,6 +617,13 @@ static int xgpu_nv_req_remote_ras_cmd(struct amdgpu_device *adev, adev, IDH_REQ_RAS_REMOTE_CMD, param1, param2, param3); } +static int xgpu_nv_req_ptl_update(struct amdgpu_device *adev, + u32 req_code, u32 ptl_state, u32 fmt1, u32 fmt2) +{ + return xgpu_nv_send_access_requests_with_param(adev, IDH_REQ_PTL_UPDATE, + req_code, ptl_state, AMD_SRIOV_PTL_PACK_FORMATS(fmt1, fmt2)); +} + const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .req_full_gpu = xgpu_nv_request_full_gpu_access, .rel_full_gpu = xgpu_nv_release_full_gpu_access, @@ -612,4 +639,5 @@ const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .req_bad_pages = xgpu_nv_req_ras_bad_pages, .req_ras_chk_criti = xgpu_nv_check_vf_critical_region, .req_remote_ras_cmd = xgpu_nv_req_remote_ras_cmd, + .req_ptl_update = xgpu_nv_req_ptl_update, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h index dc57a4f697ee..5023113e7600 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h @@ -45,6 +45,7 @@ enum idh_request { IDH_REQ_RAS_BAD_PAGES = 205, IDH_REQ_RAS_CHK_CRITI = 206, IDH_REQ_RAS_REMOTE_CMD = 207, + IDH_REQ_PTL_UPDATE = 208 }; enum idh_event { @@ -66,6 +67,7 @@ enum idh_event { IDH_UNRECOV_ERR_NOTIFICATION = 17, IDH_REQ_RAS_CHK_CRITI_READY = 18, IDH_REQ_RAS_REMOTE_CMD_READY = 19, + IDH_PTL_UPDATE_READY = 20, IDH_TEXT_MESSAGE = 255, };