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 <Victor.Zhao@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Victor Zhao 2025-12-18 18:41:35 +08:00 committed by Alex Deucher
parent 0827279ac1
commit cabbba1716
6 changed files with 121 additions and 3 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View File

@ -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,
};

View File

@ -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,
};