From: Andre Eikmeyer <[email protected]> fwupd reads /dev/drm_dp_aux* while the GPU is runtime suspended. The AUX device holds no runtime PM reference, so the transfer touched registers of the powered off GPU and caused a CPU CATTER.
Signed-off-by: Andre Eikmeyer <[email protected]> --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 7261317d4..b099bf520 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -24,6 +24,7 @@ * */ +#include <linux/pm_runtime.h> #include <linux/vmalloc.h> #include <drm/display/drm_dp_helper.h> #include <drm/display/drm_dp_mst_helper.h> @@ -111,6 +112,20 @@ STATIC_IFN_KUNIT ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, if (WARN_ON(msg->size > 16)) return -E2BIG; + ddc = TO_DM_AUX(aux)->ddc_service; + adev = ddc->ctx->driver_context; + + /* + * User space reaches this through the drm_dp_aux_dev character device + * without a runtime PM reference. Refuse the transfer while GMUX keeps + * the GPU powered off, a register access then hangs the PEG link. + */ + pm_runtime_get_noresume(adev->dev); + if (READ_ONCE(adev->gmux_off)) { + pm_runtime_put_noidle(adev->dev); + return -EBUSY; + } + payload.address = msg->address; payload.data = msg->buffer; payload.length = msg->size; @@ -126,13 +141,13 @@ STATIC_IFN_KUNIT ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload, &operation_result); + pm_runtime_put_autosuspend(adev->dev); + /* * w/a on certain intel platform where hpd is unexpected to pull low during * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON * aux transaction is succuess in such case, therefore bypass the error */ - ddc = TO_DM_AUX(aux)->ddc_service; - adev = ddc->ctx->driver_context; if (adev->dm.aux_hpd_discon_quirk) { if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE && operation_result == AUX_RET_ERROR_HPD_DISCON) { -- 2.55.0
