From: Jani Nikula jani.nikula@intel.com
[ Upstream commit 5bacecc3c56131c31f18b23d366f2184328fd9cf ]
Add a helper to get a pointer to struct displayid_header. To be pedantic, add buffer overflow checks to not touch the base if that itself would overflow.
Cc: Iaroslav Boliukin iam@lach.pw Cc: Dmitry Osipenko dmitry.osipenko@collabora.com Signed-off-by: Jani Nikula jani.nikula@intel.com Tested-by: Dmitry Osipenko dmitry.osipenko@collabora.com Reviewed-by: Dmitry Osipenko dmitry.osipenko@collabora.com Signed-off-by: Dmitry Osipenko dmitry.osipenko@collabora.com Link: https://patchwork.freedesktop.org/patch/msgid/4a03b3a5132642d3cdb6d4c2641422... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/drm_displayid.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 38ea8203df45b..7d03159dc1461 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -7,13 +7,28 @@ #include <drm/drm_edid.h> #include <drm/drm_print.h>
+static const struct displayid_header * +displayid_get_header(const u8 *displayid, int length, int index) +{ + const struct displayid_header *base; + + if (sizeof(*base) > length - index) + return ERR_PTR(-EINVAL); + + base = (const struct displayid_header *)&displayid[index]; + + return base; +} + static int validate_displayid(const u8 *displayid, int length, int idx) { int i, dispid_length; u8 csum = 0; const struct displayid_header *base;
- base = (const struct displayid_header *)&displayid[idx]; + base = displayid_get_header(displayid, length, idx); + if (IS_ERR(base)) + return PTR_ERR(base);
DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", base->rev, base->bytes, base->prod_id, base->ext_count);
From: Ayush Gupta ayush.gupta@amd.com
[ Upstream commit 9bb10b7aaec3b6278f9cc410c17dcaa129bbbbf0 ]
[Why] System restart observed while changing the display resolution to 8k with extended mode. Sytem restart was caused by a page fault.
[How] When the driver populates subvp info it did it for both the pipes using vblank which caused an outof bounds array access causing the page fault. added checks to allow the top pipe only to fix this issue.
Co-authored-by: Ayush Gupta ayush.gupta@amd.com Reviewed-by: Alvin Lee Alvin.Lee2@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Ayush Gupta ayush.gupta@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index c2092775ca88f..7f27e29fae116 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -750,7 +750,8 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, !pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); - } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE) { + } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE && + !pipe->top_pipe && !pipe->prev_odm_pipe) { // Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where // we run through DML without calculating "natural" P-state support populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
From: Paul Hsieh Paul.Hsieh@amd.com
[ Upstream commit 26a9f53198c955b15161da48cdb51041a38d5325 ]
[Why] In 2560x1440@240p eDP panel, some use cases will enable MPC combine with RGB MPO then underflow happened. This case is not allowed from HW formula.
[How] Correct eDP, DP and DP2 output bpp calculation to align HW formula.
Reviewed-by: Nicholas Kazlauskas Nicholas.Kazlauskas@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Paul Hsieh Paul.Hsieh@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- .../dc/dml/dcn31/display_mode_vba_31.c | 298 ++++++++++++------ .../dc/dml/dcn314/display_mode_vba_314.c | 298 ++++++++++++------ 2 files changed, 392 insertions(+), 204 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index 27f488405335f..8f8e2e7e5cc53 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -4308,11 +4308,11 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->AudioSampleRate[k], v->AudioSampleLayout[k], v->ODMCombineEnablePerState[i][k]); - } else if (v->Output[k] == dm_dp || v->Output[k] == dm_edp) { + } else if (v->Output[k] == dm_dp || v->Output[k] == dm_edp || v->Output[k] == dm_dp2p0) { if (v->DSCEnable[k] == true) { v->RequiresDSC[i][k] = true; v->LinkDSCEnable = true; - if (v->Output[k] == dm_dp) { + if (v->Output[k] == dm_dp || v->Output[k] == dm_dp2p0) { v->RequiresFEC[i][k] = true; } else { v->RequiresFEC[i][k] = false; @@ -4320,107 +4320,201 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } else { v->RequiresDSC[i][k] = false; v->LinkDSCEnable = false; - v->RequiresFEC[i][k] = false; - } - - v->Outbpp = BPP_INVALID; - if (v->PHYCLKPerState[i] >= 270.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 2700, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 540.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 5400, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR2" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 810.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 8100, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR3" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 10000.0 / 18) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 10000, - 4, - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "10x4"; + if (v->Output[k] == dm_dp2p0) { + v->RequiresFEC[i][k] = true; + } else { + v->RequiresFEC[i][k] = false; + } } - if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 12000.0 / 18) { - v->Outbpp = TruncToValidBPP( - 12000, - 4, - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "12x4"; + if (v->Output[k] == dm_dp2p0) { + v->Outbpp = BPP_INVALID; + if ((v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr10) && + v->PHYCLKD18PerState[k] >= 10000.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 10000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[k] < 13500.0 / 18.0 && + v->DSCEnable[k] == true && v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 10000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR10" + } + if (v->Outbpp == BPP_INVALID && + (v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr13p5) && + v->PHYCLKD18PerState[k] >= 13500.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 13500, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[k] < 20000.0 / 18.0 && + v->DSCEnable[k] == true && v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 13500, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR13p5" + } + if (v->Outbpp == BPP_INVALID && + (v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr20) && + v->PHYCLKD18PerState[k] >= 20000.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 20000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->DSCEnable[k] == true && + v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 20000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR20" + } + } else { + v->Outbpp = BPP_INVALID; + if (v->PHYCLKPerState[i] >= 270.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 2700, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 540.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 5400, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR2" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 810.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 8100, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR3" + } } } } else { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index c843b394aeb4a..e8bcae63f2656 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -4406,11 +4406,11 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ v->AudioSampleRate[k], v->AudioSampleLayout[k], v->ODMCombineEnablePerState[i][k]); - } else if (v->Output[k] == dm_dp || v->Output[k] == dm_edp) { + } else if (v->Output[k] == dm_dp || v->Output[k] == dm_edp || v->Output[k] == dm_dp2p0) { if (v->DSCEnable[k] == true) { v->RequiresDSC[i][k] = true; v->LinkDSCEnable = true; - if (v->Output[k] == dm_dp) { + if (v->Output[k] == dm_dp || v->Output[k] == dm_dp2p0) { v->RequiresFEC[i][k] = true; } else { v->RequiresFEC[i][k] = false; @@ -4418,107 +4418,201 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ } else { v->RequiresDSC[i][k] = false; v->LinkDSCEnable = false; - v->RequiresFEC[i][k] = false; - } - - v->Outbpp = BPP_INVALID; - if (v->PHYCLKPerState[i] >= 270.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 2700, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 540.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 5400, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR2" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 810.0) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 8100, - v->OutputLinkDPLanes[k], - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - // TODO: Need some other way to handle this nonsense - // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR3" - } - if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 10000.0 / 18) { - v->Outbpp = TruncToValidBPP( - (1.0 - v->Downspreading / 100.0) * 10000, - 4, - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "10x4"; + if (v->Output[k] == dm_dp2p0) { + v->RequiresFEC[i][k] = true; + } else { + v->RequiresFEC[i][k] = false; + } } - if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[i] >= 12000.0 / 18) { - v->Outbpp = TruncToValidBPP( - 12000, - 4, - v->HTotal[k], - v->HActive[k], - v->PixelClockBackEnd[k], - v->ForcedOutputLinkBPP[k], - v->LinkDSCEnable, - v->Output[k], - v->OutputFormat[k], - v->DSCInputBitPerComponent[k], - v->NumberOfDSCSlices[k], - v->AudioSampleRate[k], - v->AudioSampleLayout[k], - v->ODMCombineEnablePerState[i][k]); - v->OutputBppPerState[i][k] = v->Outbpp; - //v->OutputTypeAndRatePerState[i][k] = v->Output[k] & "12x4"; + if (v->Output[k] == dm_dp2p0) { + v->Outbpp = BPP_INVALID; + if ((v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr10) && + v->PHYCLKD18PerState[k] >= 10000.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 10000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[k] < 13500.0 / 18.0 && + v->DSCEnable[k] == true && v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 10000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR10" + } + if (v->Outbpp == BPP_INVALID && + (v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr13p5) && + v->PHYCLKD18PerState[k] >= 13500.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 13500, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->PHYCLKD18PerState[k] < 20000.0 / 18.0 && + v->DSCEnable[k] == true && v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 13500, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR13p5" + } + if (v->Outbpp == BPP_INVALID && + (v->OutputLinkDPRate[k] == dm_dp_rate_na || v->OutputLinkDPRate[k] == dm_dp_rate_uhbr20) && + v->PHYCLKD18PerState[k] >= 20000.0 / 18.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 20000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + if (v->Outbpp == BPP_INVALID && v->DSCEnable[k] == true && + v->ForcedOutputLinkBPP[k] == 0) { + v->RequiresDSC[i][k] = true; + v->LinkDSCEnable = true; + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 20000, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + } + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " UHBR20" + } + } else { + v->Outbpp = BPP_INVALID; + if (v->PHYCLKPerState[i] >= 270.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 2700, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 540.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 5400, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR2" + } + if (v->Outbpp == BPP_INVALID && v->PHYCLKPerState[i] >= 810.0) { + v->Outbpp = TruncToValidBPP( + (1.0 - v->Downspreading / 100.0) * 8100, + v->OutputLinkDPLanes[k], + v->HTotal[k], + v->HActive[k], + v->PixelClockBackEnd[k], + v->ForcedOutputLinkBPP[k], + v->LinkDSCEnable, + v->Output[k], + v->OutputFormat[k], + v->DSCInputBitPerComponent[k], + v->NumberOfDSCSlices[k], + v->AudioSampleRate[k], + v->AudioSampleLayout[k], + v->ODMCombineEnablePerState[i][k]); + v->OutputBppPerState[i][k] = v->Outbpp; + // TODO: Need some other way to handle this nonsense + // v->OutputTypeAndRatePerState[i][k] = v->Output[k] & " HBR3" + } } } } else {
From: Samson Tam samson.tam@amd.com
[ Upstream commit f3f8f16b10f8258f1836e1110099097490a1d6c1 ]
[Why] In disable_dangling_plane, for phantom pipes, we enable OTG so disable programming gets the double buffer update. But this causes an underflow to occur.
[How] Enable DPG prior to enabling OTG.
Reviewed-by: Alvin Lee Alvin.Lee2@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Samson Tam samson.tam@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/core/dc.c | 47 +++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 1c218c5266509..510661d303e8a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -74,6 +74,8 @@
#include "dc_trace.h"
+#include "hw_sequencer_private.h" + #include "dce/dmub_outbox.h"
#define CTX \ @@ -1057,6 +1059,44 @@ static void apply_ctx_interdependent_lock(struct dc *dc, struct dc_state *contex } }
+static void phantom_pipe_blank( + struct dc *dc, + struct timing_generator *tg, + int width, + int height) +{ + struct dce_hwseq *hws = dc->hwseq; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + otg_active_width = width; + otg_active_height = height; + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); + opp = dc->res_pool->opps[opp_id_src0]; + + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + + hws->funcs.wait_for_blank_complete(opp); +} + static void disable_dangling_plane(struct dc *dc, struct dc_state *context) { int i, j; @@ -1115,8 +1155,13 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) * again for different use. */ if (old_stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (tg->funcs->enable_crtc) + if (tg->funcs->enable_crtc) { + int main_pipe_width, main_pipe_height; + main_pipe_width = old_stream->mall_stream_config.paired_stream->dst.width; + main_pipe_height = old_stream->mall_stream_config.paired_stream->dst.height; + phantom_pipe_blank(dc, tg, main_pipe_width, main_pipe_height); tg->funcs->enable_crtc(tg); + } } dc_rem_all_planes_for_stream(dc, old_stream, dangling_context); disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context);
From: Hans de Goede hdegoede@redhat.com
[ Upstream commit 2f0cf1e85ddb5ae17284050dc1adafb89e4f1d8f ]
The Acer Iconia One 7 B1-750 is a x86 ACPI tablet which ships with Android x86 as factory OS. Its DSDT contains a bunch of I2C devices which are not actually there, causing various resource conflicts. Enumeration of these is skipped through the acpi_quirk_skip_i2c_client_enumeration().
Add support for manually instantiating the I2C + other devices which are actually present on this tablet by adding the necessary device info to the x86-android-tablets module.
Signed-off-by: Hans de Goede hdegoede@redhat.com Reviewed-by: Andy Shevchenko andy.shevchenko@gmail.com Link: https://lore.kernel.org/r/20230301092331.7038-2-hdegoede@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/platform/x86/x86-android-tablets.c | 101 +++++++++++++++++++-- 1 file changed, 91 insertions(+), 10 deletions(-)
diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c index 111b007656fc4..8405e1c58d520 100644 --- a/drivers/platform/x86/x86-android-tablets.c +++ b/drivers/platform/x86/x86-android-tablets.c @@ -265,6 +265,88 @@ static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = { }, };
+static struct gpiod_lookup_table int3496_reference_gpios = { + .dev_id = "intel-int3496", + .table = { + GPIO_LOOKUP("INT33FC:01", 15, "vbus", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("INT33FC:02", 18, "id", GPIO_ACTIVE_HIGH), + { } + }, +}; + +/* Acer Iconia One 7 B1-750 has an Android factory img with everything hardcoded */ +static const char * const acer_b1_750_mount_matrix[] = { + "-1", "0", "0", + "0", "1", "0", + "0", "0", "1" +}; + +static const struct property_entry acer_b1_750_bma250e_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix), + { } +}; + +static const struct software_node acer_b1_750_bma250e_node = { + .properties = acer_b1_750_bma250e_props, +}; + +static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = { + { + /* Novatek NVT-ts touchscreen */ + .board_info = { + .type = "NVT-ts", + .addr = 0x34, + .dev_name = "NVT-ts", + }, + .adapter_path = "\_SB_.I2C4", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 3, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_LOW, + }, + }, { + /* BMA250E accelerometer */ + .board_info = { + .type = "bma250e", + .addr = 0x18, + .swnode = &acer_b1_750_bma250e_node, + }, + .adapter_path = "\_SB_.I2C3", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 25, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + }, +}; + +static struct gpiod_lookup_table acer_b1_750_goodix_gpios = { + .dev_id = "i2c-NVT-ts", + .table = { + GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW), + { } + }, +}; + +static struct gpiod_lookup_table * const acer_b1_750_gpios[] = { + &acer_b1_750_goodix_gpios, + &int3496_reference_gpios, + NULL +}; + +static const struct x86_dev_info acer_b1_750_info __initconst = { + .i2c_client_info = acer_b1_750_i2c_clients, + .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients), + .pdev_info = int3496_pdevs, + .pdev_count = ARRAY_SIZE(int3496_pdevs), + .gpiod_lookup_tables = acer_b1_750_gpios, +}; + /* * Advantech MICA-071 * This is a standard Windows tablet, but it has an extra "quick launch" button @@ -1298,17 +1380,8 @@ static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst }, };
-static struct gpiod_lookup_table nextbook_ares8_int3496_gpios = { - .dev_id = "intel-int3496", - .table = { - GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("INT33FC:02", 18, "id", GPIO_ACTIVE_HIGH), - { } - }, -}; - static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = { - &nextbook_ares8_int3496_gpios, + &int3496_reference_gpios, NULL };
@@ -1435,6 +1508,14 @@ static const struct x86_dev_info xiaomi_mipad2_info __initconst = { };
static const struct dmi_system_id x86_android_tablet_ids[] __initconst = { + { + /* Acer Iconia One 7 B1-750 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "VESPA2"), + }, + .driver_data = (void *)&acer_b1_750_info, + }, { /* Advantech MICA-071 */ .matches = {
From: Gabe Teeger gabe.teeger@amd.com
[ Upstream commit 97fa4dfa66fdd52ad3d0c9fadeaaa1e87605bac7 ]
[Why] There is underflow and flickering occuring. The underflow stops when hostvm is forced to active. According to policy, hostvm should be enabled if riommu is active, but this is not taken into account when deciding whether to enable hostvm.
[What] For DCN314, set hostvm to true if riommu is active.
Reviewed-by: Nicholas Kazlauskas Nicholas.Kazlauskas@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Gabe Teeger gabe.teeger@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index acda3e1babd4a..c52b76610bd29 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -308,6 +308,10 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c pipe->plane_state->src_rect.width < pipe->plane_state->dst_rect.width)) upscaled = true;
+ /* Apply HostVM policy - either based on hypervisor globally enabled, or rIOMMU active */ + if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE) + pipes[i].pipe.src.hostvm = dc->vm_pa_config.is_hvm_enabled || dc->res_pool->hubbub->riommu_active; + /* * Immediate flip can be set dynamically after enabling the plane. * We need to require support for immediate flip or underflow can be
From: Rodrigo Siqueira Rodrigo.Siqueira@amd.com
[ Upstream commit 7222f5841ff49709ca666b05ff336776e0664a20 ]
[Why & How] DC now uses a new commit sequence which is more robust since it addresses cases where we need to reorganize pipes based on planes and other parameters. As a result, this new commit sequence reset the DC state by cleaning plane states and re-creating them accordingly with the need. For this reason, the dce_transform_set_pixel_storage_depth can be invoked after a plane state is destroyed and before its re-creation. In this situation and on DCE devices, DC will hit a condition that will trigger a dmesg log that looks like this:
Console: switching to colour frame buffer device 240x67 ------------[ cut here ]------------ [..] Hardware name: System manufacturer System Product Name/PRIME X370-PRO, BIOS 5603 07/28/2020 RIP: 0010:dce_transform_set_pixel_storage_depth+0x3f8/0x480 [amdgpu] [..] RSP: 0018:ffffc9000202b850 EFLAGS: 00010293 RAX: ffffffffa081d100 RBX: ffff888110790000 RCX: 000000000000000c RDX: ffff888100bedbf8 RSI: 0000000000001a50 RDI: ffff88810463c900 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000007 R10: 0000000000000001 R11: 0000000000000f00 R12: ffff88810f500010 R13: ffff888100bedbf8 R14: ffff88810f515688 R15: 0000000000000000 FS: 00007ff0159249c0(0000) GS:ffff88840e940000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ff01528e550 CR3: 0000000002a10000 CR4: 00000000003506e0 Call Trace: <TASK> ? dm_write_reg_func+0x21/0x80 [amdgpu 340dadd3f7c8cf4be11cf0bdc850245e99abe0e8] dc_stream_set_dither_option+0xfb/0x130 [amdgpu 340dadd3f7c8cf4be11cf0bdc850245e99abe0e8] amdgpu_dm_crtc_configure_crc_source+0x10b/0x190 [amdgpu 340dadd3f7c8cf4be11cf0bdc850245e99abe0e8] amdgpu_dm_atomic_commit_tail+0x20a8/0x2a90 [amdgpu 340dadd3f7c8cf4be11cf0bdc850245e99abe0e8] ? free_unref_page_commit+0x98/0x170 ? free_unref_page+0xcc/0x150 commit_tail+0x94/0x120 drm_atomic_helper_commit+0x10f/0x140 drm_atomic_commit+0x94/0xc0 ? drm_plane_get_damage_clips.cold+0x1c/0x1c drm_client_modeset_commit_atomic+0x203/0x250 drm_client_modeset_commit_locked+0x56/0x150 drm_client_modeset_commit+0x21/0x40 drm_fb_helper_lastclose+0x42/0x70 amdgpu_driver_lastclose_kms+0xa/0x10 [amdgpu 340dadd3f7c8cf4be11cf0bdc850245e99abe0e8] drm_release+0xda/0x110 __fput+0x89/0x240 task_work_run+0x5c/0x90 do_exit+0x333/0xae0 do_group_exit+0x2d/0x90 __x64_sys_exit_group+0x14/0x20 do_syscall_64+0x5b/0x80 ? exit_to_user_mode_prepare+0x1e/0x140 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7ff016ceaca1 Code: Unable to access opcode bytes at RIP 0x7ff016ceac77. RSP: 002b:00007ffe7a2357e8 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 00007ff016e15a00 RCX: 00007ff016ceaca1 RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000000 RBP: 0000000000000000 R08: ffffffffffffff78 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007ff016e15a00 R13: 0000000000000000 R14: 00007ff016e1aee8 R15: 00007ff016e1af00 </TASK>
Since this issue only happens in a transition state on DC, this commit replace BREAK_TO_DEBUGGER with DC_LOG_DC.
Reviewed-by: Harry Wentland Harry.Wentland@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Rodrigo Siqueira Rodrigo.Siqueira@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dce/dce_transform.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index d9fd4ec60588f..670d5ab9d9984 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -1009,7 +1009,7 @@ static void dce_transform_set_pixel_storage_depth( color_depth = COLOR_DEPTH_101010; pixel_depth = 0; expan_mode = 1; - BREAK_TO_DEBUGGER(); + DC_LOG_DC("The pixel depth %d is not valid, set COLOR_DEPTH_101010 instead.", depth); break; }
@@ -1023,8 +1023,7 @@ static void dce_transform_set_pixel_storage_depth( if (!(xfm_dce->lb_pixel_depth_supported & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ - DC_LOG_WARNING("%s: Capability not supported", - __func__); + DC_LOG_DC("%s: Capability not supported", __func__); } }
From: Alexander Stein alexander.stein@ew.tq-group.com
[ Upstream commit fd883d79e4dcd2417c2b80756f22a2ff03b0f6e0 ]
There is no sense in doing a cache sync on REGCACHE_NONE regmaps. Instead of panicking the kernel due to missing cache_ops, return an error to client driver.
Signed-off-by: Alexander Stein alexander.stein@ew.tq-group.com Link: https://lore.kernel.org/r/20230313071812.13577-1-alexander.stein@ew.tq-group... Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/base/regmap/regcache.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 362e043e26d86..8031007b4887d 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -349,6 +349,9 @@ int regcache_sync(struct regmap *map) const char *name; bool bypass;
+ if (WARN_ON(map->cache_type == REGCACHE_NONE)) + return -EINVAL; + BUG_ON(!map->cache_ops);
map->lock(map->lock_arg); @@ -418,6 +421,9 @@ int regcache_sync_region(struct regmap *map, unsigned int min, const char *name; bool bypass;
+ if (WARN_ON(map->cache_type == REGCACHE_NONE)) + return -EINVAL; + BUG_ON(!map->cache_ops);
map->lock(map->lock_arg);
From: Iuliana Prodan iuliana.prodan@nxp.com
[ Upstream commit 408ec1ff0caa340c57eecf4cbd14ef0132036a50 ]
The IRAM is part of the HiFi DSP. According to hardware specification only 32-bits write are allowed otherwise we get a Kernel panic.
Therefore add a custom memory copy and memset functions to deal with the above restriction.
Signed-off-by: Iuliana Prodan iuliana.prodan@nxp.com Link: https://lore.kernel.org/r/20230221170356.27923-1-iuliana.prodan@oss.nxp.com Signed-off-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/remoteproc/imx_dsp_rproc.c | 187 ++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 95da1cbefacf0..6255864442a2b 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -715,6 +715,191 @@ static void imx_dsp_rproc_kick(struct rproc *rproc, int vqid) dev_err(dev, "%s: failed (%d, err:%d)\n", __func__, vqid, err); }
+/* + * Custom memory copy implementation for i.MX DSP Cores + * + * The IRAM is part of the HiFi DSP. + * According to hw specs only 32-bits writes are allowed. + */ +static int imx_dsp_rproc_memcpy(void *dest, const void *src, size_t size) +{ + const u8 *src_byte = src; + const u32 *source = src; + u32 affected_mask; + u32 *dst = dest; + int i, q, r; + u32 tmp; + + /* destination must be 32bit aligned */ + if (!IS_ALIGNED((uintptr_t)dest, 4)) + return -EINVAL; + + q = size / 4; + r = size % 4; + + /* copy data in units of 32 bits at a time */ + for (i = 0; i < q; i++) + writel(source[i], &dst[i]); + + if (r) { + affected_mask = GENMASK(8 * r, 0); + + /* + * first read the 32bit data of dest, then change affected + * bytes, and write back to dest. + * For unaffected bytes, it should not be changed + */ + tmp = readl(dest + q * 4); + tmp &= ~affected_mask; + + /* avoid reading after end of source */ + for (i = 0; i < r; i++) + tmp |= (src_byte[q * 4 + i] << (8 * i)); + + writel(tmp, dest + q * 4); + } + + return 0; +} + +/* + * Custom memset implementation for i.MX DSP Cores + * + * The IRAM is part of the HiFi DSP. + * According to hw specs only 32-bits writes are allowed. + */ +static int imx_dsp_rproc_memset(void *addr, u8 value, size_t size) +{ + u32 tmp_val = value; + u32 *tmp_dst = addr; + u32 affected_mask; + int q, r; + u32 tmp; + + /* destination must be 32bit aligned */ + if (!IS_ALIGNED((uintptr_t)addr, 4)) + return -EINVAL; + + tmp_val |= tmp_val << 8; + tmp_val |= tmp_val << 16; + + q = size / 4; + r = size % 4; + + while (q--) + writel(tmp_val, tmp_dst++); + + if (r) { + affected_mask = GENMASK(8 * r, 0); + + /* + * first read the 32bit data of addr, then change affected + * bytes, and write back to addr. + * For unaffected bytes, it should not be changed + */ + tmp = readl(tmp_dst); + tmp &= ~affected_mask; + + tmp |= (tmp_val & affected_mask); + writel(tmp, tmp_dst); + } + + return 0; +} + +/* + * imx_dsp_rproc_elf_load_segments() - load firmware segments to memory + * @rproc: remote processor which will be booted using these fw segments + * @fw: the ELF firmware image + * + * This function loads the firmware segments to memory, where the remote + * processor expects them. + * + * Return: 0 on success and an appropriate error code otherwise + */ +static int imx_dsp_rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) +{ + struct device *dev = &rproc->dev; + const void *ehdr, *phdr; + int i, ret = 0; + u16 phnum; + const u8 *elf_data = fw->data; + u8 class = fw_elf_get_class(fw); + u32 elf_phdr_get_size = elf_size_of_phdr(class); + + ehdr = elf_data; + phnum = elf_hdr_get_e_phnum(class, ehdr); + phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr); + + /* go through the available ELF segments */ + for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) { + u64 da = elf_phdr_get_p_paddr(class, phdr); + u64 memsz = elf_phdr_get_p_memsz(class, phdr); + u64 filesz = elf_phdr_get_p_filesz(class, phdr); + u64 offset = elf_phdr_get_p_offset(class, phdr); + u32 type = elf_phdr_get_p_type(class, phdr); + void *ptr; + + if (type != PT_LOAD || !memsz) + continue; + + dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n", + type, da, memsz, filesz); + + if (filesz > memsz) { + dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n", + filesz, memsz); + ret = -EINVAL; + break; + } + + if (offset + filesz > fw->size) { + dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n", + offset + filesz, fw->size); + ret = -EINVAL; + break; + } + + if (!rproc_u64_fit_in_size_t(memsz)) { + dev_err(dev, "size (%llx) does not fit in size_t type\n", + memsz); + ret = -EOVERFLOW; + break; + } + + /* grab the kernel address for this device address */ + ptr = rproc_da_to_va(rproc, da, memsz, NULL); + if (!ptr) { + dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da, + memsz); + ret = -EINVAL; + break; + } + + /* put the segment where the remote processor expects it */ + if (filesz) { + ret = imx_dsp_rproc_memcpy(ptr, elf_data + offset, filesz); + if (ret) { + dev_err(dev, "memory copy failed for da 0x%llx memsz 0x%llx\n", + da, memsz); + break; + } + } + + /* zero out remaining memory for this segment */ + if (memsz > filesz) { + ret = imx_dsp_rproc_memset(ptr + filesz, 0, memsz - filesz); + if (ret) { + dev_err(dev, "memset failed for da 0x%llx memsz 0x%llx\n", + da, memsz); + break; + } + } + } + + return ret; +} + static int imx_dsp_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) { if (rproc_elf_load_rsc_table(rproc, fw)) @@ -729,7 +914,7 @@ static const struct rproc_ops imx_dsp_rproc_ops = { .start = imx_dsp_rproc_start, .stop = imx_dsp_rproc_stop, .kick = imx_dsp_rproc_kick, - .load = rproc_elf_load_segments, + .load = imx_dsp_rproc_elf_load_segments, .parse_fw = imx_dsp_rproc_parse_fw, .sanity_check = rproc_elf_sanity_check, .get_boot_addr = rproc_elf_get_boot_addr,
From: Konrad Dybcio konrad.dybcio@linaro.org
[ Upstream commit d0af0537e28f6eace02deed63b585396de939213 ]
Add missing dwc3 quirks from msm-3.18. Unfortunately, none of them make `dwc3-qcom 6af8800.usb: HS-PHY not in L2` go away.
Signed-off-by: Konrad Dybcio konrad.dybcio@linaro.org Signed-off-by: Bjorn Andersson andersson@kernel.org Link: https://lore.kernel.org/r/20230302011849.1873056-1-konrad.dybcio@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- arch/arm64/boot/dts/qcom/msm8996.dtsi | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 905678e7175d8..c3cf973a69ad1 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -3006,8 +3006,11 @@ usb3_dwc3: usb@6a00000 { interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>; phys = <&hsusb_phy1>, <&ssusb_phy_0>; phy-names = "usb2-phy", "usb3-phy"; + snps,hird-threshold = /bits/ 8 <0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; + snps,is-utmi-l1-suspend; + tx-fifo-resize; }; };
From: Tomer Tayar ttayar@habana.ai
[ Upstream commit 2e8e9a895c4589f124a37fc84d123b5114406e94 ]
The memory manager IDR is currently destroyed when user releases the file descriptor. However, at this point the user context might be still held, and memory buffers might be still in use. Later on, calls to release those buffers will fail due to not finding their handles in the IDR, leading to a memory leak. To avoid this leak, split the IDR destruction from the memory manager fini, and postpone it to hpriv_release() when there is no user context and no buffers are used.
Signed-off-by: Tomer Tayar ttayar@habana.ai Reviewed-by: Oded Gabbay ogabbay@kernel.org Signed-off-by: Oded Gabbay ogabbay@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/accel/habanalabs/common/device.c | 9 +++++++++ drivers/accel/habanalabs/common/habanalabs.h | 1 + drivers/accel/habanalabs/common/habanalabs_drv.c | 1 + drivers/accel/habanalabs/common/memory_mgr.c | 13 ++++++++++++- 4 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/accel/habanalabs/common/device.c b/drivers/accel/habanalabs/common/device.c index 9933e5858a363..c91436609f080 100644 --- a/drivers/accel/habanalabs/common/device.c +++ b/drivers/accel/habanalabs/common/device.c @@ -423,6 +423,9 @@ static void hpriv_release(struct kref *ref) mutex_destroy(&hpriv->ctx_lock); mutex_destroy(&hpriv->restore_phase_mutex);
+ /* There should be no memory buffers at this point and handles IDR can be destroyed */ + hl_mem_mgr_idr_destroy(&hpriv->mem_mgr); + /* Device should be reset if reset-upon-device-release is enabled, or if there is a pending * reset that waits for device release. */ @@ -514,6 +517,10 @@ static int hl_device_release(struct inode *inode, struct file *filp) }
hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); + + /* Memory buffers might be still in use at this point and thus the handles IDR destruction + * is postponed to hpriv_release(). + */ hl_mem_mgr_fini(&hpriv->mem_mgr);
hdev->compute_ctx_in_release = 1; @@ -887,6 +894,7 @@ static int device_early_init(struct hl_device *hdev)
free_cb_mgr: hl_mem_mgr_fini(&hdev->kernel_mem_mgr); + hl_mem_mgr_idr_destroy(&hdev->kernel_mem_mgr); free_chip_info: kfree(hdev->hl_chip_info); free_prefetch_wq: @@ -930,6 +938,7 @@ static void device_early_fini(struct hl_device *hdev) mutex_destroy(&hdev->clk_throttling.lock);
hl_mem_mgr_fini(&hdev->kernel_mem_mgr); + hl_mem_mgr_idr_destroy(&hdev->kernel_mem_mgr);
kfree(hdev->hl_chip_info);
diff --git a/drivers/accel/habanalabs/common/habanalabs.h b/drivers/accel/habanalabs/common/habanalabs.h index fa05e76d3d21a..829b30ab1961a 100644 --- a/drivers/accel/habanalabs/common/habanalabs.h +++ b/drivers/accel/habanalabs/common/habanalabs.h @@ -3861,6 +3861,7 @@ const char *hl_sync_engine_to_string(enum hl_sync_engine_type engine_type);
void hl_mem_mgr_init(struct device *dev, struct hl_mem_mgr *mmg); void hl_mem_mgr_fini(struct hl_mem_mgr *mmg); +void hl_mem_mgr_idr_destroy(struct hl_mem_mgr *mmg); int hl_mem_mgr_mmap(struct hl_mem_mgr *mmg, struct vm_area_struct *vma, void *args); struct hl_mmap_mem_buf *hl_mmap_mem_buf_get(struct hl_mem_mgr *mmg, diff --git a/drivers/accel/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c index 03dae57dc8386..e3781cfe8a7fe 100644 --- a/drivers/accel/habanalabs/common/habanalabs_drv.c +++ b/drivers/accel/habanalabs/common/habanalabs_drv.c @@ -237,6 +237,7 @@ int hl_device_open(struct inode *inode, struct file *filp) out_err: mutex_unlock(&hdev->fpriv_list_lock); hl_mem_mgr_fini(&hpriv->mem_mgr); + hl_mem_mgr_idr_destroy(&hpriv->mem_mgr); hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr); filp->private_data = NULL; mutex_destroy(&hpriv->ctx_lock); diff --git a/drivers/accel/habanalabs/common/memory_mgr.c b/drivers/accel/habanalabs/common/memory_mgr.c index 0f2759e265477..f8e8261cc83d8 100644 --- a/drivers/accel/habanalabs/common/memory_mgr.c +++ b/drivers/accel/habanalabs/common/memory_mgr.c @@ -341,8 +341,19 @@ void hl_mem_mgr_fini(struct hl_mem_mgr *mmg) "%s: Buff handle %u for CTX is still alive\n", topic, id); } +}
- /* TODO: can it happen that some buffer is still in use at this point? */ +/** + * hl_mem_mgr_idr_destroy() - destroy memory manager IDR. + * @mmg: parent unified memory manager + * + * Destroy the memory manager IDR. + * Shall be called when IDR is empty and no memory buffers are in use. + */ +void hl_mem_mgr_idr_destroy(struct hl_mem_mgr *mmg) +{ + if (!idr_is_empty(&mmg->handles)) + dev_crit(mmg->dev, "memory manager IDR is destroyed while it is not empty!\n");
idr_destroy(&mmg->handles); }
From: Samson Tam Samson.Tam@amd.com
[ Upstream commit 5f3401eeb064fab5ce50728cce46532cce7a85c5 ]
[Why] For dual displays where pixel rate is much higher on one display, we may get underflow when DET is evenly allocated.
[How] Allocate less DET segments for the lower pixel rate display and more DET segments for the higher pixel rate display
Reviewed-by: Alvin Lee Alvin.Lee2@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Samson Tam Samson.Tam@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- .../display/dc/dcn32/dcn32_resource_helpers.c | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 3a2d7bcc4b6d6..8310bcf651728 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -261,6 +261,8 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe) return psr_capable; }
+#define DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER 7 + /** * ******************************************************************************************* * dcn32_determine_det_override: Determine DET allocation for each pipe @@ -272,7 +274,6 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe) * If there is a plane that's driven by more than 1 pipe (i.e. pipe split), then the * number of DET for that given plane will be split among the pipes driving that plane. * - * * High level algorithm: * 1. Split total DET among number of streams * 2. For each stream, split DET among the planes @@ -280,6 +281,18 @@ bool dcn32_is_psr_capable(struct pipe_ctx *pipe) * among those pipes. * 4. Assign the DET override to the DML pipes. * + * Special cases: + * + * For two displays that have a large difference in pixel rate, we may experience + * underflow on the larger display when we divide the DET equally. For this, we + * will implement a modified algorithm to assign more DET to larger display. + * + * 1. Calculate difference in pixel rates ( multiplier ) between two displays + * 2. If the multiplier exceeds DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER, then + * implement the modified DET override algorithm. + * 3. Assign smaller DET size for lower pixel display and higher DET size for + * higher pixel display + * * @param [in]: dc: Current DC state * @param [in]: context: New DC state to be programmed * @param [in]: pipes: Array of DML pipes @@ -299,18 +312,46 @@ void dcn32_determine_det_override(struct dc *dc, struct dc_plane_state *current_plane = NULL; uint8_t stream_count = 0;
+ int phy_pix_clk_mult, lower_mode_stream_index; + int phy_pix_clk[MAX_PIPES] = {0}; + bool use_new_det_override_algorithm = false; + for (i = 0; i < context->stream_count; i++) { /* Don't count SubVP streams for DET allocation */ if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM) { + phy_pix_clk[i] = context->streams[i]->phy_pix_clk; stream_count++; } }
+ /* Check for special case with two displays, one with much higher pixel rate */ + if (stream_count == 2) { + ASSERT(!phy_pix_clk[0] || !phy_pix_clk[1]); + if (phy_pix_clk[0] < phy_pix_clk[1]) { + lower_mode_stream_index = 0; + phy_pix_clk_mult = phy_pix_clk[1] / phy_pix_clk[0]; + } else { + lower_mode_stream_index = 1; + phy_pix_clk_mult = phy_pix_clk[0] / phy_pix_clk[1]; + } + + if (phy_pix_clk_mult >= DCN3_2_NEW_DET_OVERRIDE_MIN_MULTIPLIER) + use_new_det_override_algorithm = true; + } + if (stream_count > 0) { stream_segments = 18 / stream_count; for (i = 0; i < context->stream_count; i++) { if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM) continue; + + if (use_new_det_override_algorithm) { + if (i == lower_mode_stream_index) + stream_segments = 4; + else + stream_segments = 14; + } + if (context->stream_status[i].plane_count > 0) plane_segments = stream_segments / context->stream_status[i].plane_count; else
From: Kees Cook keescook@chromium.org
[ Upstream commit 474acc639fc8671fa4c1919d9e03253c82b6d321 ]
The call of mxc_jpeg_get_plane_size() from mxc_jpeg_dec_irq() sets plane_no argument to 1. The compiler sees that it's possible to end up with an access beyond the bounds of sizeimage, if mem_planes was too large:
if (plane_no >= fmt->mem_planes) // mem_planes = 2+ return 0;
if (fmt->mem_planes == fmt->comp_planes) // comp_planes != mem_planes return q_data->sizeimage[plane_no];
if (plane_no < fmt->mem_planes - 1) // mem_planes = 2 return q_data->sizeimage[plane_no];
comp_planes == 0 or 1 is safe. comp_planes > 2 would be out of bounds.
(This isn't currently possible given the contents of mxc_formats, though.)
Silence the warning by bounds checking comp_planes for future robustness. Seen with GCC 13:
In function 'mxc_jpeg_get_plane_size', inlined from 'mxc_jpeg_dec_irq' at ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c:729:14: ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c:641:42: warning: array subscript 2 is above array bounds of 'u32[2]' {aka 'unsigned int[2]'} [-Warray-bounds=] 641 | size += q_data->sizeimage[i]; | ~~~~~~~~~~~~~~~~~^~~ In file included from ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h:112, from ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c:63: ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h: In function 'mxc_jpeg_dec_irq': ../drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h:84:41: note: while referencing 'sizeimage' 84 | u32 sizeimage[MXC_JPEG_MAX_PLANES]; | ^~~~~~~~~
Cc: Mirela Rabulea mirela.rabulea@nxp.com Cc: NXP Linux Team linux-imx@nxp.com Cc: Shawn Guo shawnguo@kernel.org Cc: Sascha Hauer s.hauer@pengutronix.de Cc: Pengutronix Kernel Team kernel@pengutronix.de Cc: Fabio Estevam festevam@gmail.com Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Kees Cook keescook@chromium.org Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index f085f14d676ad..c898116b763a2 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -637,6 +637,11 @@ static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no) return q_data->sizeimage[plane_no];
size = q_data->sizeimage[fmt->mem_planes - 1]; + + /* Should be impossible given mxc_formats. */ + if (WARN_ON_ONCE(fmt->comp_planes > ARRAY_SIZE(q_data->sizeimage))) + return size; + for (i = fmt->mem_planes; i < fmt->comp_planes; i++) size += q_data->sizeimage[i];
From: harperchen harperchen1110@gmail.com
[ Upstream commit 47e8b73bc35d7c54642f78e498697692f6358996 ]
When the driver calls cx23885_risc_buffer() to prepare the buffer, the function call dma_alloc_coherent may fail, resulting in a empty buffer risc->cpu. Later when we free the buffer or access the buffer, null ptr deref is triggered.
This bug is similar to the following one: https://git.linuxtv.org/media_stage.git/commit/?id=2b064d91440b33fba5b452f2d....
We believe the bug can be also dynamically triggered from user side. Similarly, we fix this by checking the return value of cx23885_risc_buffer() and the value of risc->cpu before buffer free.
Signed-off-by: harperchen harperchen1110@gmail.com Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/pci/cx23885/cx23885-core.c | 4 +++- drivers/media/pci/cx23885/cx23885-video.c | 13 +++++++------ 2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 9232a966bcabb..2ce2914576cf2 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1325,7 +1325,9 @@ void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { struct cx23885_riscmem *risc = &buf->risc;
- dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma); + if (risc->cpu) + dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma); + memset(risc, 0, sizeof(*risc)); }
static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 3d03f5e95786a..671fc0588e431 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -342,6 +342,7 @@ static int queue_setup(struct vb2_queue *q,
static int buffer_prepare(struct vb2_buffer *vb) { + int ret; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = @@ -358,12 +359,12 @@ static int buffer_prepare(struct vb2_buffer *vb)
switch (dev->field) { case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, + ret = cx23885_risc_buffer(dev->pci, &buf->risc, sgt->sgl, 0, UNSET, buf->bpl, 0, dev->height); break; case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, + ret = cx23885_risc_buffer(dev->pci, &buf->risc, sgt->sgl, UNSET, 0, buf->bpl, 0, dev->height); break; @@ -391,21 +392,21 @@ static int buffer_prepare(struct vb2_buffer *vb) line0_offset = 0; line1_offset = buf->bpl; } - cx23885_risc_buffer(dev->pci, &buf->risc, + ret = cx23885_risc_buffer(dev->pci, &buf->risc, sgt->sgl, line0_offset, line1_offset, buf->bpl, buf->bpl, dev->height >> 1); break; case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, + ret = cx23885_risc_buffer(dev->pci, &buf->risc, sgt->sgl, 0, buf->bpl * (dev->height >> 1), buf->bpl, 0, dev->height >> 1); break; case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, + ret = cx23885_risc_buffer(dev->pci, &buf->risc, sgt->sgl, buf->bpl * (dev->height >> 1), 0, buf->bpl, 0, @@ -418,7 +419,7 @@ static int buffer_prepare(struct vb2_buffer *vb) buf, buf->vb.vb2_buf.index, dev->width, dev->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); - return 0; + return ret; }
static void buffer_finish(struct vb2_buffer *vb)
From: harperchen harperchen1110@gmail.com
[ Upstream commit 1634b7adcc5bef645b3666fdd564e5952a9e24e0 ]
When the driver calls tw68_risc_buffer() to prepare the buffer, the function call dma_alloc_coherent may fail, resulting in a empty buffer buf->cpu. Later when we free the buffer or access the buffer, null ptr deref is triggered.
This bug is similar to the following one: https://git.linuxtv.org/media_stage.git/commit/?id=2b064d91440b33fba5b452f2d....
We believe the bug can be also dynamically triggered from user side. Similarly, we fix this by checking the return value of tw68_risc_buffer() and the value of buf->cpu before buffer free.
Signed-off-by: harperchen harperchen1110@gmail.com Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/pci/tw68/tw68-video.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 0cbc5b038073b..773a18702d369 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -437,6 +437,7 @@ static void tw68_buf_queue(struct vb2_buffer *vb) */ static int tw68_buf_prepare(struct vb2_buffer *vb) { + int ret; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; struct tw68_dev *dev = vb2_get_drv_priv(vq); @@ -452,30 +453,30 @@ static int tw68_buf_prepare(struct vb2_buffer *vb) bpl = (dev->width * dev->fmt->depth) >> 3; switch (dev->field) { case V4L2_FIELD_TOP: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, UNSET, bpl, 0, dev->height); break; case V4L2_FIELD_BOTTOM: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, UNSET, 0, bpl, 0, dev->height); break; case V4L2_FIELD_SEQ_TB: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, bpl * (dev->height >> 1), bpl, 0, dev->height >> 1); break; case V4L2_FIELD_SEQ_BT: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, bpl * (dev->height >> 1), 0, bpl, 0, dev->height >> 1); break; case V4L2_FIELD_INTERLACED: default: - tw68_risc_buffer(dev->pci, buf, dma->sgl, + ret = tw68_risc_buffer(dev->pci, buf, dma->sgl, 0, bpl, bpl, bpl, dev->height >> 1); break; } - return 0; + return ret; }
static void tw68_buf_finish(struct vb2_buffer *vb) @@ -485,7 +486,8 @@ static void tw68_buf_finish(struct vb2_buffer *vb) struct tw68_dev *dev = vb2_get_drv_priv(vq); struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);
- dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma); + if (buf->cpu) + dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma); }
static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
From: Tom Rix trix@redhat.com
[ Upstream commit 1107283b3351bef138cd12dbda1f999891cab7db ]
A rand config causes this link error vmlinux.o: In function `pvr2_dvb_create': (.text+0x8af1d2): undefined reference to `dvb_register_adapter'
The rand config has CONFIG_VIDEO_PVRUSB2=y CONFIG_VIDEO_DEV=y CONFIG_DVB_CORE=m
VIDEO_PVRUSB2 should also depend on DVB_CORE.
Signed-off-by: Tom Rix trix@redhat.com Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/usb/pvrusb2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index f2b64e49c5a20..9501b10b31aa5 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_DEV && I2C + depends on VIDEO_DEV && I2C && DVB_CORE select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X
From: "David E. Box" david.e.box@linux.intel.com
[ Upstream commit 3f95ecf2a3e4db09e58d307932037e8f1210d6e7 ]
Discovered Intel VSEC/DVSEC capabilities are enabled by default and only get disabled by quirk. Instead, remove such quirks and only enable support for capabilities that have been explicitly added to a new capabilities field. While here, also reorder the device info structures alphabetically.
Signed-off-by: David E. Box david.e.box@linux.intel.com Reviewed-by: Andy Shevchenko andy.shevchenko@gmail.com Link: https://lore.kernel.org/r/20230316224628.2855884-1-david.e.box@linux.intel.c... Reviewed-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/platform/x86/intel/vsec.c | 69 ++++++++++++++----------------- drivers/platform/x86/intel/vsec.h | 9 +++- 2 files changed, 38 insertions(+), 40 deletions(-)
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 2311c16cb975d..91be391bba3f7 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -67,14 +67,6 @@ enum intel_vsec_id { VSEC_ID_TPMI = 66, };
-static enum intel_vsec_id intel_vsec_allow_list[] = { - VSEC_ID_TELEMETRY, - VSEC_ID_WATCHER, - VSEC_ID_CRASHLOG, - VSEC_ID_SDSI, - VSEC_ID_TPMI, -}; - static const char *intel_vsec_name(enum intel_vsec_id id) { switch (id) { @@ -98,26 +90,19 @@ static const char *intel_vsec_name(enum intel_vsec_id id) } }
-static bool intel_vsec_allowed(u16 id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(intel_vsec_allow_list); i++) - if (intel_vsec_allow_list[i] == id) - return true; - - return false; -} - -static bool intel_vsec_disabled(u16 id, unsigned long quirks) +static bool intel_vsec_supported(u16 id, unsigned long caps) { switch (id) { + case VSEC_ID_TELEMETRY: + return !!(caps & VSEC_CAP_TELEMETRY); case VSEC_ID_WATCHER: - return !!(quirks & VSEC_QUIRK_NO_WATCHER); - + return !!(caps & VSEC_CAP_WATCHER); case VSEC_ID_CRASHLOG: - return !!(quirks & VSEC_QUIRK_NO_CRASHLOG); - + return !!(caps & VSEC_CAP_CRASHLOG); + case VSEC_ID_SDSI: + return !!(caps & VSEC_CAP_SDSI); + case VSEC_ID_TPMI: + return !!(caps & VSEC_CAP_TPMI); default: return false; } @@ -206,7 +191,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he unsigned long quirks = info->quirks; int i;
- if (!intel_vsec_allowed(header->id) || intel_vsec_disabled(header->id, quirks)) + if (!intel_vsec_supported(header->id, info->caps)) return -EINVAL;
if (!header->num_entries) { @@ -261,14 +246,14 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he static bool intel_vsec_walk_header(struct pci_dev *pdev, struct intel_vsec_platform_info *info) { - struct intel_vsec_header **header = info->capabilities; + struct intel_vsec_header **header = info->headers; bool have_devices = false; int ret;
for ( ; *header; header++) { ret = intel_vsec_add_dev(pdev, *header, info); if (ret) - dev_info(&pdev->dev, "Could not add device for DVSEC id %d\n", + dev_info(&pdev->dev, "Could not add device for VSEC id %d\n", (*header)->id); else have_devices = true; @@ -403,14 +388,8 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id return 0; }
-/* TGL info */ -static const struct intel_vsec_platform_info tgl_info = { - .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | - VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, -}; - /* DG1 info */ -static struct intel_vsec_header dg1_telemetry = { +static struct intel_vsec_header dg1_header = { .length = 0x10, .id = 2, .num_entries = 1, @@ -419,19 +398,31 @@ static struct intel_vsec_header dg1_telemetry = { .offset = 0x466000, };
-static struct intel_vsec_header *dg1_capabilities[] = { - &dg1_telemetry, +static struct intel_vsec_header *dg1_headers[] = { + &dg1_header, NULL };
static const struct intel_vsec_platform_info dg1_info = { - .capabilities = dg1_capabilities, + .caps = VSEC_CAP_TELEMETRY, + .headers = dg1_headers, .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, };
/* MTL info */ static const struct intel_vsec_platform_info mtl_info = { - .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG, + .caps = VSEC_CAP_TELEMETRY, +}; + +/* OOBMSM info */ +static const struct intel_vsec_platform_info oobmsm_info = { + .caps = VSEC_CAP_TELEMETRY | VSEC_CAP_SDSI | VSEC_CAP_TPMI, +}; + +/* TGL info */ +static const struct intel_vsec_platform_info tgl_info = { + .caps = VSEC_CAP_TELEMETRY, + .quirks = VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, };
#define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d @@ -446,7 +437,7 @@ static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_MTL_M, &mtl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_MTL_S, &mtl_info) }, - { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, + { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &oobmsm_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { } diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h index ae8fe92c5595b..0fd042c171ba0 100644 --- a/drivers/platform/x86/intel/vsec.h +++ b/drivers/platform/x86/intel/vsec.h @@ -5,6 +5,12 @@ #include <linux/auxiliary_bus.h> #include <linux/bits.h>
+#define VSEC_CAP_TELEMETRY BIT(0) +#define VSEC_CAP_WATCHER BIT(1) +#define VSEC_CAP_CRASHLOG BIT(2) +#define VSEC_CAP_SDSI BIT(3) +#define VSEC_CAP_TPMI BIT(4) + struct pci_dev; struct resource;
@@ -27,7 +33,8 @@ enum intel_vsec_quirks {
/* Platform specific data */ struct intel_vsec_platform_info { - struct intel_vsec_header **capabilities; + struct intel_vsec_header **headers; + unsigned long caps; unsigned long quirks; };
From: Kang Chen void0red@gmail.com
[ Upstream commit 4dea41775d951ff1f7b472a346a8ca3ae7e74455 ]
devm_kzalloc() may fail, clk_data->name might be NULL and will cause a NULL pointer dereference later.
Signed-off-by: Kang Chen void0red@gmail.com [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/acpi/acpi_apd.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 3bbe2276cac76..80f945cbec8a7 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -83,6 +83,8 @@ static int fch_misc_setup(struct apd_private_data *pdata) if (!acpi_dev_get_property(adev, "clk-name", ACPI_TYPE_STRING, &obj)) { clk_data->name = devm_kzalloc(&adev->dev, obj->string.length, GFP_KERNEL); + if (!clk_data->name) + return -ENOMEM;
strcpy(clk_data->name, obj->string.pointer); } else {
From: Toby Chen tobyc@nvidia.com
[ Upstream commit b5af48eedcb53491c02ded55d5991e03d6da6dbf ]
This fixes a use-after-free crash during rmmod.
The DRM encoder is embedded inside the larger rockchip_hdmi, which is allocated with the component. The component memory gets freed before the main drm device is destroyed. Fix it by running encoder cleanup before tearing down its container.
Signed-off-by: Toby Chen tobyc@nvidia.com [moved encoder cleanup above clk_disable, similar to bind-error-path] Signed-off-by: Heiko Stuebner heiko@sntech.de Link: https://patchwork.freedesktop.org/patch/msgid/20230317005126.496-1-tobyc@nvi... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 2f4b8f64cbad3..ae857bf8bd624 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -640,6 +640,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi); + drm_encoder_cleanup(&hdmi->encoder.encoder); clk_disable_unprepare(hdmi->ref_clk);
regulator_disable(hdmi->avdd_1v8);
From: Zheng Wang zyytlz.wz@163.com
[ Upstream commit 63264422785021704c39b38f65a78ab9e4a186d7 ]
In r592_probe, dev->detect_timer was bound with r592_detect_timer. In r592_irq function, the timer function will be invoked by mod_timer.
If we remove the module which will call hantro_release to make cleanup, there may be a unfinished work. The possible sequence is as follows, which will cause a typical UAF bug.
Fix it by canceling the work before cleanup in r592_remove.
CPU0 CPU1
|r592_detect_timer r592_remove | memstick_free_host| put_device; | kfree(host); | | | queue_work | &host->media_checker //use
Signed-off-by: Zheng Wang zyytlz.wz@163.com Link: https://lore.kernel.org/r/20230307164338.1246287-1-zyytlz.wz@163.com Signed-off-by: Ulf Hansson ulf.hansson@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/memstick/host/r592.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 1d35d147552d4..42bfc46842b82 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -829,7 +829,7 @@ static void r592_remove(struct pci_dev *pdev) /* Stop the processing thread. That ensures that we won't take any more requests */ kthread_stop(dev->io_thread); - + del_timer_sync(&dev->detect_timer); r592_enable_device(dev, false);
while (!error && dev->req) {
From: Sebastian Krzyszkowiak sebastian.krzyszkowiak@puri.sm
[ Upstream commit cfe9de291bd2bbce18c5cd79e1dd582cbbacdb4f ]
This reduces power consumption in system suspend by about 10%.
Signed-off-by: Sebastian Krzyszkowiak sebastian.krzyszkowiak@puri.sm Signed-off-by: Martin Kepplinger martin.kepplinger@puri.sm Signed-off-by: Shawn Guo shawnguo@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi index 6895bcc121651..de0dde01fd5c4 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi @@ -1299,7 +1299,6 @@ &usb_dwc3_0 { #address-cells = <1>; #size-cells = <0>; dr_mode = "otg"; - snps,dis_u3_susphy_quirk; usb-role-switch; status = "okay";
From: Pierre Gondois pierre.gondois@arm.com
[ Upstream commit d2c48b2387eb89e0bf2a2e06e30987cf410acad4 ]
Running a preempt-rt (v6.2-rc3-rt1) based kernel on an Ampere Altra triggers:
BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:46 in_atomic(): 0, irqs_disabled(): 128, non_block: 0, pid: 24, name: cpuhp/0 preempt_count: 0, expected: 0 RCU nest depth: 0, expected: 0 3 locks held by cpuhp/0/24: #0: ffffda30217c70d0 (cpu_hotplug_lock){++++}-{0:0}, at: cpuhp_thread_fun+0x5c/0x248 #1: ffffda30217c7120 (cpuhp_state-up){+.+.}-{0:0}, at: cpuhp_thread_fun+0x5c/0x248 #2: ffffda3021c711f0 (sdei_list_lock){....}-{3:3}, at: sdei_cpuhp_up+0x3c/0x130 irq event stamp: 36 hardirqs last enabled at (35): [<ffffda301e85b7bc>] finish_task_switch+0xb4/0x2b0 hardirqs last disabled at (36): [<ffffda301e812fec>] cpuhp_thread_fun+0x21c/0x248 softirqs last enabled at (0): [<ffffda301e80b184>] copy_process+0x63c/0x1ac0 softirqs last disabled at (0): [<0000000000000000>] 0x0 CPU: 0 PID: 24 Comm: cpuhp/0 Not tainted 5.19.0-rc3-rt5-[...] Hardware name: WIWYNN Mt.Jade Server [...] Call trace: dump_backtrace+0x114/0x120 show_stack+0x20/0x70 dump_stack_lvl+0x9c/0xd8 dump_stack+0x18/0x34 __might_resched+0x188/0x228 rt_spin_lock+0x70/0x120 sdei_cpuhp_up+0x3c/0x130 cpuhp_invoke_callback+0x250/0xf08 cpuhp_thread_fun+0x120/0x248 smpboot_thread_fn+0x280/0x320 kthread+0x130/0x140 ret_from_fork+0x10/0x20
sdei_cpuhp_up() is called in the STARTING hotplug section, which runs with interrupts disabled. Use a CPUHP_AP_ONLINE_DYN entry instead to execute the cpuhp cb later, with preemption enabled.
SDEI originally got its own cpuhp slot to allow interacting with perf. It got superseded by pNMI and this early slot is not relevant anymore. [1]
Some SDEI calls (e.g. SDEI_1_0_FN_SDEI_PE_MASK) take actions on the calling CPU. It is checked that preemption is disabled for them. _ONLINE cpuhp cb are executed in the 'per CPU hotplug thread'. Preemption is enabled in those threads, but their cpumask is limited to 1 CPU. Move 'WARN_ON_ONCE(preemptible())' statements so that SDEI cpuhp cb don't trigger them.
Also add a check for the SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI call which acts on the calling CPU.
[1]: https://lore.kernel.org/all/5813b8c5-ae3e-87fd-fccc-94c9cd08816d@arm.com/
Suggested-by: James Morse james.morse@arm.com Signed-off-by: Pierre Gondois pierre.gondois@arm.com Reviewed-by: James Morse james.morse@arm.com Link: https://lore.kernel.org/r/20230216084920.144064-1-pierre.gondois@arm.com Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/firmware/arm_sdei.c | 37 ++++++++++++++++++++----------------- include/linux/cpuhotplug.h | 1 - 2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index 1e1a51510e83b..f9040bd610812 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -43,6 +43,8 @@ static asmlinkage void (*sdei_firmware_call)(unsigned long function_id, /* entry point from firmware to arch asm code */ static unsigned long sdei_entry_point;
+static int sdei_hp_state; + struct sdei_event { /* These three are protected by the sdei_list_lock */ struct list_head list; @@ -301,8 +303,6 @@ int sdei_mask_local_cpu(void) { int err;
- WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to mask CPU[%u]: %d\n", @@ -315,6 +315,7 @@ int sdei_mask_local_cpu(void)
static void _ipi_mask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_mask_local_cpu(); }
@@ -322,8 +323,6 @@ int sdei_unmask_local_cpu(void) { int err;
- WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to unmask CPU[%u]: %d\n", @@ -336,6 +335,7 @@ int sdei_unmask_local_cpu(void)
static void _ipi_unmask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_unmask_local_cpu(); }
@@ -343,6 +343,8 @@ static void _ipi_private_reset(void *ignored) { int err;
+ WARN_ON_ONCE(preemptible()); + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) @@ -389,8 +391,6 @@ static void _local_event_enable(void *data) int err; struct sdei_crosscall_args *arg = data;
- WARN_ON_ONCE(preemptible()); - err = sdei_api_event_enable(arg->event->event_num);
sdei_cross_call_return(arg, err); @@ -479,8 +479,6 @@ static void _local_event_unregister(void *data) int err; struct sdei_crosscall_args *arg = data;
- WARN_ON_ONCE(preemptible()); - err = sdei_api_event_unregister(arg->event->event_num);
sdei_cross_call_return(arg, err); @@ -561,8 +559,6 @@ static void _local_event_register(void *data) struct sdei_registered_event *reg; struct sdei_crosscall_args *arg = data;
- WARN_ON(preemptible()); - reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id()); err = sdei_api_event_register(arg->event->event_num, sdei_entry_point, reg, 0, 0); @@ -717,6 +713,8 @@ static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action, { int rv;
+ WARN_ON_ONCE(preemptible()); + switch (action) { case CPU_PM_ENTER: rv = sdei_mask_local_cpu(); @@ -765,7 +763,7 @@ static int sdei_device_freeze(struct device *dev) int err;
/* unregister private events */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_entry_point);
err = sdei_unregister_shared(); if (err) @@ -786,12 +784,15 @@ static int sdei_device_thaw(struct device *dev) return err; }
- err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) + if (err < 0) { pr_warn("Failed to re-register CPU hotplug notifier...\n"); + return err; + }
- return err; + sdei_hp_state = err; + return 0; }
static int sdei_device_restore(struct device *dev) @@ -823,7 +824,7 @@ static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action, * We are going to reset the interface, after this there is no point * doing work when we take CPUs offline. */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_hp_state);
sdei_platform_reset();
@@ -1003,13 +1004,15 @@ static int sdei_probe(struct platform_device *pdev) goto remove_cpupm; }
- err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) { + if (err < 0) { pr_warn("Failed to register CPU hotplug notifier...\n"); goto remove_reboot; }
+ sdei_hp_state = err; + return 0;
remove_reboot: diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 5b2f8147d1ae3..0f1001dca0e00 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -163,7 +163,6 @@ enum cpuhp_state { CPUHP_AP_PERF_X86_CSTATE_STARTING, CPUHP_AP_PERF_XTENSA_STARTING, CPUHP_AP_MIPS_OP_LOONGSON3_STARTING, - CPUHP_AP_ARM_SDEI_STARTING, CPUHP_AP_ARM_VFP_STARTING, CPUHP_AP_ARM64_DEBUG_MONITORS_STARTING, CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING,
From: Armin Wolf W_Armin@gmx.de
[ Upstream commit e5b492c6bb900fcf9722e05f4a10924410e170c1 ]
When removing custom query handlers, the handler might still be used inside the EC query workqueue, causing a kernel oops if the module holding the callback function was already unloaded.
Fix this by flushing the EC query workqueue when removing custom query handlers.
Tested on a Acer Travelmate 4002WLMi
Signed-off-by: Armin Wolf W_Armin@gmx.de Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/acpi/ec.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 105d2e795afad..9658e348dc17d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1122,6 +1122,7 @@ static void acpi_ec_remove_query_handlers(struct acpi_ec *ec, void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { acpi_ec_remove_query_handlers(ec, false, query_bit); + flush_workqueue(ec_query_wq); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
From: Ayush Gupta ayugupta@amd.com
[ Upstream commit 37403ced9f2873fab7f39ab4ac963bbb33fb0bc0 ]
[Why] Observing underflow on dcn30+ system config at 4k144hz
[How] We set the UCLK hardmax on AC/DC switch if softmax is enabled and also on boot. While booting up the UCLK Hardmax is set to softmax before the init sequence and the init sequence resets the hardmax to UCLK max which enables P-state switching. Just added a conditional check to avoid setting hardmax on init.
Reviewed-by: Alvin Lee Alvin.Lee2@amd.com Reviewed-by: Martin Leung Martin.Leung@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Ayush Gupta ayugupta@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c | 3 ++- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index df787fcf8e86e..0e730445459c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -629,7 +629,8 @@ void dcn30_init_hw(struct dc *dc) if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
- if (dc->clk_mgr->funcs->set_hard_max_memclk) + //if softmax is enabled then hardmax will be set by a different call + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
if (dc->res_pool->hubbub->funcs->force_pstate_change_control) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index d13e46eeee3c0..6d3f2335b9f1e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -285,7 +285,7 @@ void dcn31_init_hw(struct dc *dc) if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
- if (dc->clk_mgr->funcs->set_hard_max_memclk) + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
if (dc->res_pool->hubbub->funcs->force_pstate_change_control) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index 9d14045cccd63..ae96157e98ecb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -895,7 +895,7 @@ void dcn32_init_hw(struct dc *dc) if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
- if (dc->clk_mgr->funcs->set_hard_max_memclk) + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
From: Arnaud Pouliquen arnaud.pouliquen@foss.st.com
[ Upstream commit 35bdafda40cc343ad2ba2cce105eba03a70241cc ]
The workqueue may execute late even after remoteproc is stopped or stopping, some resources (rpmsg device and endpoint) have been released in rproc_stop_subdevices(), then rproc_vq_interrupt() accessing these resources will cause kernel dump.
Call trace: virtqueue_add_inbuf virtqueue_add_inbuf rpmsg_recv_single rpmsg_recv_done vring_interrupt stm32_rproc_mb_vq_work process_one_work worker_thread kthread
Suggested-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Arnaud Pouliquen arnaud.pouliquen@foss.st.com Link: https://lore.kernel.org/r/20230331160634.3113031-1-arnaud.pouliquen@foss.st.... Signed-off-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/remoteproc/stm32_rproc.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 7d782ed9e5896..f618405cf4200 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -287,8 +287,16 @@ static void stm32_rproc_mb_vq_work(struct work_struct *work) struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work); struct rproc *rproc = dev_get_drvdata(mb->client.dev);
+ mutex_lock(&rproc->lock); + + if (rproc->state != RPROC_RUNNING) + goto unlock_mutex; + if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); + +unlock_mutex: + mutex_unlock(&rproc->lock); }
static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data)
From: Karol Wachowski karol.wachowski@linux.intel.com
[ Upstream commit cb949ce504e829193234e26cb3042bb448465d52 ]
VPU on MTL has hardware optimizations and does not require 10ms D0 - D3hot transition delay imposed by PCI specification (PCIe r6.0, sec 5.9.) .
The delay removal is traditionally done by adding PCI ID to quirk_remove_d3hot_delay() in drivers/pci/quirks.c . But since we do not need that optimization before driver probe and we can better specify in the ivpu driver on what (future) hardware use the optimization, we do not use quirk_remove_d3hot_delay() for that.
Signed-off-by: Karol Wachowski karol.wachowski@linux.intel.com Signed-off-by: Stanislaw Gruszka stanislaw.gruszka@linux.intel.com Reviewed-by: Jeffrey Hugo quic_jhugo@quicinc.com Signed-off-by: Jacek Lawrynowicz jacek.lawrynowicz@linux.intel.com Link: https://patchwork.freedesktop.org/patch/msgid/20230403121545.2995279-1-stani... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/accel/ivpu/ivpu_drv.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 6a320a73e3ccf..8396db2b52030 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -437,6 +437,10 @@ static int ivpu_pci_init(struct ivpu_device *vdev) /* Clear any pending errors */ pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f);
+ /* VPU MTL does not require PCI spec 10m D3hot delay */ + if (ivpu_is_mtl(vdev)) + pdev->d3hot_delay = 0; + ret = pcim_enable_device(pdev); if (ret) { ivpu_err(vdev, "Failed to enable PCI device: %d\n", ret);
From: Nur Hussein hussein@unixcat.org
[ Upstream commit 2429b3c529da29d4277d519bd66d034842dcd70c ]
In tegra_sor_compute_config(), the 32-bit value mode->clock is multiplied by 1000, and assigned to the u64 variable pclk. We can avoid a potential 32-bit integer overflow by casting mode->clock to u64 before we do the arithmetic and assignment.
Signed-off-by: Nur Hussein hussein@unixcat.org Signed-off-by: Thierry Reding treding@nvidia.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/tegra/sor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 8af632740673a..77723d5f1d3fd 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -1153,7 +1153,7 @@ static int tegra_sor_compute_config(struct tegra_sor *sor, struct drm_dp_link *link) { const u64 f = 100000, link_rate = link->rate * 1000; - const u64 pclk = mode->clock * 1000; + const u64 pclk = (u64)mode->clock * 1000; u64 input, output, watermark, num; struct tegra_sor_params params; u32 num_syms_per_line;
From: Douglas Anderson dianders@chromium.org
[ Upstream commit b20566cdef05cd40d95f10869d2a7646f48b1bbe ]
The DP AUX interrupt handling was a bit of a mess. * There were two functions (one for "native" transfers and one for "i2c" transfers) that were quite similar. It was hard to say how many of the differences between the two functions were on purpose and how many of them were just an accident of how they were coded. * Each function sometimes used "else if" to test for error bits and sometimes didn't and again it was hard to say if this was on purpose or just an accident. * The two functions wouldn't notice whether "unknown" bits were set. For instance, there seems to be a bit "DP_INTR_PLL_UNLOCKED" and if it was set there would be no indication. * The two functions wouldn't notice if more than one error was set.
Let's fix this by being more consistent / explicit about what we're doing.
By design this could cause different handling for AUX transfers, though I'm not actually aware of any bug fixed as a result of this patch (this patch was created because we simply noticed how odd the old code was by code inspection). Specific notes here: 1. In the old native transfer case if we got "done + wrong address" we'd ignore the "wrong address" (because of the "else if"). Now we won't. 2. In the old native transfer case if we got "done + timeout" we'd ignore the "timeout" (because of the "else if"). Now we won't. 3. In the old native transfer case we'd see "nack_defer" and translate it to the error number for "nack". This differed from the i2c transfer case where "nack_defer" was given the error number for "nack_defer". This 100% can't matter because the only user of this error number treats "nack defer" the same as "nack", so it's clear that the difference between the "native" and "i2c" was pointless here. 4. In the old i2c transfer case if we got "done" plus any error besides "nack" or "defer" then we'd ignore the error. Now we don't. 5. If there is more than one error signaled by the hardware it's possible that we'll report a different one than we used to. I don't know if this matters. If someone is aware of a case this matters we should document it and change the code to make it explicit. 6. One quirk we keep (I don't know if this is important) is that in the i2c transfer case if we see "done + defer" we report that as a "nack". That seemed too intentional in the old code to just drop.
After this change we will add extra logging, including: * A warning if we see more than one error bit set. * A warning if we see an unexpected interrupt. * A warning if we get an AUX transfer interrupt when shouldn't.
It actually turns out that as a result of this change then at boot we sometimes see an error: [drm:dp_aux_isr] *ERROR* Unexpected DP AUX IRQ 0x01000000 when not busy That means that, during init, we are seeing DP_INTR_PLL_UNLOCKED. For now I'm going to say that leaving this error reported in the logs is OK-ish and hopefully it will encourage someone to track down what's going on at init time.
One last note here is that this change renames one of the interrupt bits. The bit named "i2c done" clearly was used for native transfers being done too, so I renamed it to indicate this.
Signed-off-by: Douglas Anderson dianders@chromium.org Tested-by: Kuogee Hsieh quic_khsieh@quicinc.com Reviewed-by: Kuogee Hsieh quic_khsieh@quicinc.com Patchwork: https://patchwork.freedesktop.org/patch/520658/ Link: https://lore.kernel.org/r/20230126170745.v2.1.I90ffed3ddd21e818ae534f820cb4d... Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/dp/dp_aux.c | 80 ++++++++++++----------------- drivers/gpu/drm/msm/dp/dp_catalog.c | 2 +- drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +- 3 files changed, 36 insertions(+), 48 deletions(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index cc3efed593aa1..84f9e3e5f9642 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -162,47 +162,6 @@ static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, return i; }
-static void dp_aux_native_handler(struct dp_aux_private *aux, u32 isr) -{ - if (isr & DP_INTR_AUX_I2C_DONE) - aux->aux_error_num = DP_AUX_ERR_NONE; - else if (isr & DP_INTR_WRONG_ADDR) - aux->aux_error_num = DP_AUX_ERR_ADDR; - else if (isr & DP_INTR_TIMEOUT) - aux->aux_error_num = DP_AUX_ERR_TOUT; - if (isr & DP_INTR_NACK_DEFER) - aux->aux_error_num = DP_AUX_ERR_NACK; - if (isr & DP_INTR_AUX_ERROR) { - aux->aux_error_num = DP_AUX_ERR_PHY; - dp_catalog_aux_clear_hw_interrupts(aux->catalog); - } -} - -static void dp_aux_i2c_handler(struct dp_aux_private *aux, u32 isr) -{ - if (isr & DP_INTR_AUX_I2C_DONE) { - if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER)) - aux->aux_error_num = DP_AUX_ERR_NACK; - else - aux->aux_error_num = DP_AUX_ERR_NONE; - } else { - if (isr & DP_INTR_WRONG_ADDR) - aux->aux_error_num = DP_AUX_ERR_ADDR; - else if (isr & DP_INTR_TIMEOUT) - aux->aux_error_num = DP_AUX_ERR_TOUT; - if (isr & DP_INTR_NACK_DEFER) - aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; - if (isr & DP_INTR_I2C_NACK) - aux->aux_error_num = DP_AUX_ERR_NACK; - if (isr & DP_INTR_I2C_DEFER) - aux->aux_error_num = DP_AUX_ERR_DEFER; - if (isr & DP_INTR_AUX_ERROR) { - aux->aux_error_num = DP_AUX_ERR_PHY; - dp_catalog_aux_clear_hw_interrupts(aux->catalog); - } - } -} - static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) { @@ -427,13 +386,42 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux) if (!isr) return;
- if (!aux->cmd_busy) + if (!aux->cmd_busy) { + DRM_ERROR("Unexpected DP AUX IRQ %#010x when not busy\n", isr); return; + }
- if (aux->native) - dp_aux_native_handler(aux, isr); - else - dp_aux_i2c_handler(aux, isr); + /* + * The logic below assumes only one error bit is set (other than "done" + * which can apparently be set at the same time as some of the other + * bits). Warn if more than one get set so we know we need to improve + * the logic. + */ + if (hweight32(isr & ~DP_INTR_AUX_XFER_DONE) > 1) + DRM_WARN("Some DP AUX interrupts unhandled: %#010x\n", isr); + + if (isr & DP_INTR_AUX_ERROR) { + aux->aux_error_num = DP_AUX_ERR_PHY; + dp_catalog_aux_clear_hw_interrupts(aux->catalog); + } else if (isr & DP_INTR_NACK_DEFER) { + aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; + } else if (isr & DP_INTR_WRONG_ADDR) { + aux->aux_error_num = DP_AUX_ERR_ADDR; + } else if (isr & DP_INTR_TIMEOUT) { + aux->aux_error_num = DP_AUX_ERR_TOUT; + } else if (!aux->native && (isr & DP_INTR_I2C_NACK)) { + aux->aux_error_num = DP_AUX_ERR_NACK; + } else if (!aux->native && (isr & DP_INTR_I2C_DEFER)) { + if (isr & DP_INTR_AUX_XFER_DONE) + aux->aux_error_num = DP_AUX_ERR_NACK; + else + aux->aux_error_num = DP_AUX_ERR_DEFER; + } else if (isr & DP_INTR_AUX_XFER_DONE) { + aux->aux_error_num = DP_AUX_ERR_NONE; + } else { + DRM_WARN("Unexpected interrupt: %#010x\n", isr); + return; + }
complete(&aux->comp); } diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 676279d0ca8d9..421391755427d 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -27,7 +27,7 @@ #define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4)
#define DP_INTERRUPT_STATUS1 \ - (DP_INTR_AUX_I2C_DONE| \ + (DP_INTR_AUX_XFER_DONE| \ DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \ DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \ DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \ diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 1f717f45c1158..f36b7b372a065 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -13,7 +13,7 @@
/* interrupts */ #define DP_INTR_HPD BIT(0) -#define DP_INTR_AUX_I2C_DONE BIT(3) +#define DP_INTR_AUX_XFER_DONE BIT(3) #define DP_INTR_WRONG_ADDR BIT(6) #define DP_INTR_TIMEOUT BIT(9) #define DP_INTR_NACK_DEFER BIT(12)
From: Tamir Duberstein tamird@google.com
[ Upstream commit 05bb0167c80b8f93c6a4e0451b7da9b96db990c2 ]
ACPICA commit 770653e3ba67c30a629ca7d12e352d83c2541b1e
Before this change we see the following UBSAN stack trace in Fuchsia:
#0 0x000021e4213b3302 in acpi_ds_init_aml_walk(struct acpi_walk_state*, union acpi_parse_object*, struct acpi_namespace_node*, u8*, u32, struct acpi_evaluate_info*, u8) ../../third_party/acpica/source/components/dispatcher/dswstate.c:682 <platform-bus-x86.so>+0x233302 #1.2 0x000020d0f660777f in ubsan_get_stack_trace() compiler-rt/lib/ubsan/ubsan_diag.cpp:41 <libclang_rt.asan.so>+0x3d77f #1.1 0x000020d0f660777f in maybe_print_stack_trace() compiler-rt/lib/ubsan/ubsan_diag.cpp:51 <libclang_rt.asan.so>+0x3d77f #1 0x000020d0f660777f in ~scoped_report() compiler-rt/lib/ubsan/ubsan_diag.cpp:387 <libclang_rt.asan.so>+0x3d77f #2 0x000020d0f660b96d in handlepointer_overflow_impl() compiler-rt/lib/ubsan/ubsan_handlers.cpp:809 <libclang_rt.asan.so>+0x4196d #3 0x000020d0f660b50d in compiler-rt/lib/ubsan/ubsan_handlers.cpp:815 <libclang_rt.asan.so>+0x4150d #4 0x000021e4213b3302 in acpi_ds_init_aml_walk(struct acpi_walk_state*, union acpi_parse_object*, struct acpi_namespace_node*, u8*, u32, struct acpi_evaluate_info*, u8) ../../third_party/acpica/source/components/dispatcher/dswstate.c:682 <platform-bus-x86.so>+0x233302 #5 0x000021e4213e2369 in acpi_ds_call_control_method(struct acpi_thread_state*, struct acpi_walk_state*, union acpi_parse_object*) ../../third_party/acpica/source/components/dispatcher/dsmethod.c:605 <platform-bus-x86.so>+0x262369 #6 0x000021e421437fac in acpi_ps_parse_aml(struct acpi_walk_state*) ../../third_party/acpica/source/components/parser/psparse.c:550 <platform-bus-x86.so>+0x2b7fac #7 0x000021e4214464d2 in acpi_ps_execute_method(struct acpi_evaluate_info*) ../../third_party/acpica/source/components/parser/psxface.c:244 <platform-bus-x86.so>+0x2c64d2 #8 0x000021e4213aa052 in acpi_ns_evaluate(struct acpi_evaluate_info*) ../../third_party/acpica/source/components/namespace/nseval.c:250 <platform-bus-x86.so>+0x22a052 #9 0x000021e421413dd8 in acpi_ns_init_one_device(acpi_handle, u32, void*, void**) ../../third_party/acpica/source/components/namespace/nsinit.c:735 <platform-bus-x86.so>+0x293dd8 #10 0x000021e421429e98 in acpi_ns_walk_namespace(acpi_object_type, acpi_handle, u32, u32, acpi_walk_callback, acpi_walk_callback, void*, void**) ../../third_party/acpica/source/components/namespace/nswalk.c:298 <platform-bus-x86.so>+0x2a9e98 #11 0x000021e4214131ac in acpi_ns_initialize_devices(u32) ../../third_party/acpica/source/components/namespace/nsinit.c:268 <platform-bus-x86.so>+0x2931ac #12 0x000021e42147c40d in acpi_initialize_objects(u32) ../../third_party/acpica/source/components/utilities/utxfinit.c:304 <platform-bus-x86.so>+0x2fc40d #13 0x000021e42126d603 in acpi::acpi_impl::initialize_acpi(acpi::acpi_impl*) ../../src/devices/board/lib/acpi/acpi-impl.cc:224 <platform-bus-x86.so>+0xed603
Add a simple check that avoids incrementing a pointer by zero, but otherwise behaves as before. Note that our findings are against ACPICA 20221020, but the same code exists on master.
Link: https://github.com/acpica/acpica/commit/770653e3 Signed-off-by: Bob Moore robert.moore@intel.com Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/acpi/acpica/dswstate.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 0aa735d3b93cc..77076da2029d9 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -576,9 +576,14 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ds_init_aml_walk);
walk_state->parser_state.aml = - walk_state->parser_state.aml_start = aml_start; - walk_state->parser_state.aml_end = - walk_state->parser_state.pkg_end = aml_start + aml_length; + walk_state->parser_state.aml_start = + walk_state->parser_state.aml_end = + walk_state->parser_state.pkg_end = aml_start; + /* Avoid undefined behavior: applying zero offset to null pointer */ + if (aml_length != 0) { + walk_state->parser_state.aml_end += aml_length; + walk_state->parser_state.pkg_end += aml_length; + }
/* The next_op of the next_walk will be the beginning of the method */
From: void0red 30990023+void0red@users.noreply.github.com
[ Upstream commit ae5a0eccc85fc960834dd66e3befc2728284b86c ]
ACPICA commit 0d5f467d6a0ba852ea3aad68663cbcbd43300fd4
ACPI_ALLOCATE_ZEROED may fails, object_info might be null and will cause null pointer dereference later.
Link: https://github.com/acpica/acpica/commit/0d5f467d Signed-off-by: Bob Moore robert.moore@intel.com Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/acpi/acpica/dbnames.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 3615e1a6efd8a..b91155ea9c343 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -652,6 +652,9 @@ acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg) object_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info));
+ if (!object_info) + return (AE_NO_MEMORY); + /* Walk the namespace from the root */
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
From: Konrad Dybcio konrad.dybcio@linaro.org
[ Upstream commit fbc3a1df2866608ca43e7e6d602f66208a5afd88 ]
Drop the qcom,snoc-host-cap-skip-quirk that was never introduced to solve schema warnings.
Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Signed-off-by: Konrad Dybcio konrad.dybcio@linaro.org Signed-off-by: Bjorn Andersson andersson@kernel.org Link: https://lore.kernel.org/r/20230406-topic-ath10k_bindings-v3-2-00895afc7764@l... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts | 2 -- 1 file changed, 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts index 1b7fdbae6a2b5..56f2d855df78d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-polaris.dts @@ -712,7 +712,5 @@ &wifi { vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; vdd-3.3-ch0-supply = <&vreg_l25a_3p3>; vdd-3.3-ch1-supply = <&vreg_l23a_3p3>; - - qcom,snoc-host-cap-skip-quirk; status = "okay"; };
From: Konrad Dybcio konrad.dybcio@linaro.org
[ Upstream commit 8b0ac59c2da69aaf8e65c6bd648a06b755975302 ]
Add a ramoops node to enable retrieving crash logs.
Signed-off-by: Konrad Dybcio konrad.dybcio@linaro.org Signed-off-by: Bjorn Andersson andersson@kernel.org Link: https://lore.kernel.org/r/20230406-topic-lenovo_features-v2-1-625d7cb4a944@l... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/arm64/boot/dts/qcom/sm6115p-lenovo-j606f.dts | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sm6115p-lenovo-j606f.dts b/arch/arm64/boot/dts/qcom/sm6115p-lenovo-j606f.dts index 4ce2d905d70e1..42d89bab5d04b 100644 --- a/arch/arm64/boot/dts/qcom/sm6115p-lenovo-j606f.dts +++ b/arch/arm64/boot/dts/qcom/sm6115p-lenovo-j606f.dts @@ -52,6 +52,17 @@ key-volume-up { gpio-key,wakeup; }; }; + + reserved-memory { + ramoops@ffc00000 { + compatible = "ramoops"; + reg = <0x0 0xffc00000 0x0 0x100000>; + record-size = <0x1000>; + console-size = <0x40000>; + ftrace-size = <0x20000>; + ecc-size = <16>; + }; + }; };
&dispcc {
From: Shanker Donthineni sdonthineni@nvidia.com
[ Upstream commit 35727af2b15d98a2dd2811d631d3a3886111312e ]
The T241 platform suffers from the T241-FABRIC-4 erratum which causes unexpected behavior in the GIC when multiple transactions are received simultaneously from different sources. This hardware issue impacts NVIDIA server platforms that use more than two T241 chips interconnected. Each chip has support for 320 {E}SPIs.
This issue occurs when multiple packets from different GICs are incorrectly interleaved at the target chip. The erratum text below specifies exactly what can cause multiple transfer packets susceptible to interleaving and GIC state corruption. GIC state corruption can lead to a range of problems, including kernel panics, and unexpected behavior.
From the erratum text:
"In some cases, inter-socket AXI4 Stream packets with multiple transfers, may be interleaved by the fabric when presented to ARM Generic Interrupt Controller. GIC expects all transfers of a packet to be delivered without any interleaving.
The following GICv3 commands may result in multiple transfer packets over inter-socket AXI4 Stream interface: - Register reads from GICD_I* and GICD_N* - Register writes to 64-bit GICD registers other than GICD_IROUTERn* - ITS command MOVALL
Multiple commands in GICv4+ utilize multiple transfer packets, including VMOVP, VMOVI, VMAPP, and 64-bit register accesses."
This issue impacts system configurations with more than 2 sockets, that require multi-transfer packets to be sent over inter-socket AXI4 Stream interface between GIC instances on different sockets. GICv4 cannot be supported. GICv3 SW model can only be supported with the workaround. Single and Dual socket configurations are not impacted by this issue and support GICv3 and GICv4."
Link: https://developer.nvidia.com/docs/t241-fabric-4/nvidia-t241-fabric-4-errata....
Writing to the chip alias region of the GICD_In{E} registers except GICD_ICENABLERn has an equivalent effect as writing to the global distributor. The SPI interrupt deactivate path is not impacted by the erratum.
To fix this problem, implement a workaround that ensures read accesses to the GICD_In{E} registers are directed to the chip that owns the SPI, and disable GICv4.x features. To simplify code changes, the gic_configure_irq() function uses the same alias region for both read and write operations to GICD_ICFGR.
Co-developed-by: Vikram Sethi vsethi@nvidia.com Signed-off-by: Vikram Sethi vsethi@nvidia.com Signed-off-by: Shanker Donthineni sdonthineni@nvidia.com Acked-by: Sudeep Holla sudeep.holla@arm.com (for SMCCC/SOC ID bits) Signed-off-by: Marc Zyngier maz@kernel.org Link: https://lore.kernel.org/r/20230319024314.3540573-2-sdonthineni@nvidia.com Signed-off-by: Sasha Levin sashal@kernel.org --- Documentation/arm64/silicon-errata.rst | 2 + drivers/firmware/smccc/smccc.c | 26 ++++++ drivers/firmware/smccc/soc_id.c | 28 ++---- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-gic-v3.c | 115 ++++++++++++++++++++++--- include/linux/arm-smccc.h | 18 ++++ 6 files changed, 156 insertions(+), 34 deletions(-)
diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst index ec5f889d76819..e31f6c0687041 100644 --- a/Documentation/arm64/silicon-errata.rst +++ b/Documentation/arm64/silicon-errata.rst @@ -172,6 +172,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | NVIDIA | Carmel Core | N/A | NVIDIA_CARMEL_CNP_ERRATUM | +----------------+-----------------+-----------------+-----------------------------+ +| NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+ | Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 | +----------------+-----------------+-----------------+-----------------------------+ diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c index 60ccf3e90d7de..db818f9dcb8ee 100644 --- a/drivers/firmware/smccc/smccc.c +++ b/drivers/firmware/smccc/smccc.c @@ -17,9 +17,13 @@ static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
bool __ro_after_init smccc_trng_available = false; u64 __ro_after_init smccc_has_sve_hint = false; +s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED; +s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) { + struct arm_smccc_res res; + smccc_version = version; smccc_conduit = conduit;
@@ -27,6 +31,18 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) if (IS_ENABLED(CONFIG_ARM64_SVE) && smccc_version >= ARM_SMCCC_VERSION_1_3) smccc_has_sve_hint = true; + + if ((smccc_version >= ARM_SMCCC_VERSION_1_2) && + (smccc_conduit != SMCCC_CONDUIT_NONE)) { + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_SOC_ID, &res); + if ((s32)res.a0 >= 0) { + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); + smccc_soc_id_version = (s32)res.a0; + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); + smccc_soc_id_revision = (s32)res.a0; + } + } }
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) @@ -44,6 +60,16 @@ u32 arm_smccc_get_version(void) } EXPORT_SYMBOL_GPL(arm_smccc_get_version);
+s32 arm_smccc_get_soc_id_version(void) +{ + return smccc_soc_id_version; +} + +s32 arm_smccc_get_soc_id_revision(void) +{ + return smccc_soc_id_revision; +} + static int __init smccc_devices_init(void) { struct platform_device *pdev; diff --git a/drivers/firmware/smccc/soc_id.c b/drivers/firmware/smccc/soc_id.c index dd7c3d5e8b0bb..890eb454599a3 100644 --- a/drivers/firmware/smccc/soc_id.c +++ b/drivers/firmware/smccc/soc_id.c @@ -42,41 +42,23 @@ static int __init smccc_soc_init(void) if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) return 0;
- if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) { - pr_err("%s: invalid SMCCC conduit\n", __func__); - return -EOPNOTSUPP; - } - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, - ARM_SMCCC_ARCH_SOC_ID, &res); - - if ((int)res.a0 == SMCCC_RET_NOT_SUPPORTED) { + soc_id_version = arm_smccc_get_soc_id_version(); + if (soc_id_version == SMCCC_RET_NOT_SUPPORTED) { pr_info("ARCH_SOC_ID not implemented, skipping ....\n"); return 0; }
- if ((int)res.a0 < 0) { - pr_info("ARCH_FEATURES(ARCH_SOC_ID) returned error: %lx\n", - res.a0); - return -EINVAL; - } - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); - if ((int)res.a0 < 0) { + if (soc_id_version < 0) { pr_err("ARCH_SOC_ID(0) returned error: %lx\n", res.a0); return -EINVAL; }
- soc_id_version = res.a0; - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); - if ((int)res.a0 < 0) { + soc_id_rev = arm_smccc_get_soc_id_revision(); + if (soc_id_rev < 0) { pr_err("ARCH_SOC_ID(1) returned error: %lx\n", res.a0); return -EINVAL; }
- soc_id_rev = res.a0; - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7dc990eb2c9ba..9efb383fc688f 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -35,6 +35,7 @@ config ARM_GIC_V3 select IRQ_DOMAIN_HIERARCHY select PARTITION_PERCPU select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP + select HAVE_ARM_SMCCC_DISCOVERY
config ARM_GIC_V3_ITS bool diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd134e1f481a2..6fcee221f2017 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -24,6 +24,9 @@ #include <linux/irqchip/arm-gic-common.h> #include <linux/irqchip/arm-gic-v3.h> #include <linux/irqchip/irq-partition-percpu.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/arm-smccc.h>
#include <asm/cputype.h> #include <asm/exception.h> @@ -47,6 +50,7 @@ struct redist_region {
struct gic_chip_data { struct fwnode_handle *fwnode; + phys_addr_t dist_phys_base; void __iomem *dist_base; struct redist_region *redist_regions; struct rdists rdists; @@ -59,6 +63,10 @@ struct gic_chip_data { struct partition_desc **ppi_descs; };
+#define T241_CHIPS_MAX 4 +static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly; +static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum); + static struct gic_chip_data gic_data __read_mostly; static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
@@ -179,6 +187,39 @@ static inline bool gic_irq_in_rdist(struct irq_data *d) } }
+static inline void __iomem *gic_dist_base_alias(struct irq_data *d) +{ + if (static_branch_unlikely(&gic_nvidia_t241_erratum)) { + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 chip; + + /* + * For the erratum T241-FABRIC-4, read accesses to GICD_In{E} + * registers are directed to the chip that owns the SPI. The + * the alias region can also be used for writes to the + * GICD_In{E} except GICD_ICENABLERn. Each chip has support + * for 320 {E}SPIs. Mappings for all 4 chips: + * Chip0 = 32-351 + * Chip1 = 352-671 + * Chip2 = 672-991 + * Chip3 = 4096-4415 + */ + switch (__get_intid_range(hwirq)) { + case SPI_RANGE: + chip = (hwirq - 32) / 320; + break; + case ESPI_RANGE: + chip = 3; + break; + default: + unreachable(); + } + return t241_dist_base_alias[chip]; + } + + return gic_data.dist_base; +} + static inline void __iomem *gic_dist_base(struct irq_data *d) { switch (get_intid_range(d)) { @@ -337,7 +378,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else - base = gic_data.dist_base; + base = gic_dist_base_alias(d);
return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask); } @@ -588,7 +629,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else - base = gic_data.dist_base; + base = gic_dist_base_alias(d);
offset = convert_offset_index(d, GICD_ICFGR, &index);
@@ -1708,6 +1749,43 @@ static bool gic_enable_quirk_hip06_07(void *data) return false; }
+#define T241_CHIPN_MASK GENMASK_ULL(45, 44) +#define T241_CHIP_GICDA_OFFSET 0x1580000 +#define SMCCC_SOC_ID_T241 0x036b0241 + +static bool gic_enable_quirk_nvidia_t241(void *data) +{ + s32 soc_id = arm_smccc_get_soc_id_version(); + unsigned long chip_bmask = 0; + phys_addr_t phys; + u32 i; + + /* Check JEP106 code for NVIDIA T241 chip (036b:0241) */ + if ((soc_id < 0) || (soc_id != SMCCC_SOC_ID_T241)) + return false; + + /* Find the chips based on GICR regions PHYS addr */ + for (i = 0; i < gic_data.nr_redist_regions; i++) { + chip_bmask |= BIT(FIELD_GET(T241_CHIPN_MASK, + (u64)gic_data.redist_regions[i].phys_base)); + } + + if (hweight32(chip_bmask) < 3) + return false; + + /* Setup GICD alias regions */ + for (i = 0; i < ARRAY_SIZE(t241_dist_base_alias); i++) { + if (chip_bmask & BIT(i)) { + phys = gic_data.dist_phys_base + T241_CHIP_GICDA_OFFSET; + phys |= FIELD_PREP(T241_CHIPN_MASK, i); + t241_dist_base_alias[i] = ioremap(phys, SZ_64K); + WARN_ON_ONCE(!t241_dist_base_alias[i]); + } + } + static_branch_enable(&gic_nvidia_t241_erratum); + return true; +} + static const struct gic_quirk gic_quirks[] = { { .desc = "GICv3: Qualcomm MSM8996 broken firmware", @@ -1739,6 +1817,12 @@ static const struct gic_quirk gic_quirks[] = { .mask = 0xe8f00fff, .init = gic_enable_quirk_cavium_38539, }, + { + .desc = "GICv3: NVIDIA erratum T241-FABRIC-4", + .iidr = 0x0402043b, + .mask = 0xffffffff, + .init = gic_enable_quirk_nvidia_t241, + }, { } }; @@ -1798,7 +1882,8 @@ static void gic_enable_nmi_support(void) gic_chip.flags |= IRQCHIP_SUPPORTS_NMI; }
-static int __init gic_init_bases(void __iomem *dist_base, +static int __init gic_init_bases(phys_addr_t dist_phys_base, + void __iomem *dist_base, struct redist_region *rdist_regs, u32 nr_redist_regions, u64 redist_stride, @@ -1814,6 +1899,7 @@ static int __init gic_init_bases(void __iomem *dist_base, pr_info("GIC: Using split EOI/Deactivate mode\n");
gic_data.fwnode = handle; + gic_data.dist_phys_base = dist_phys_base; gic_data.dist_base = dist_base; gic_data.redist_regions = rdist_regs; gic_data.nr_redist_regions = nr_redist_regions; @@ -1841,10 +1927,13 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); - gic_data.rdists.has_rvpeid = true; - gic_data.rdists.has_vlpis = true; - gic_data.rdists.has_direct_lpi = true; - gic_data.rdists.has_vpend_valid_dirty = true; + if (!static_branch_unlikely(&gic_nvidia_t241_erratum)) { + /* Disable GICv4.x features for the erratum T241-FABRIC-4 */ + gic_data.rdists.has_rvpeid = true; + gic_data.rdists.has_vlpis = true; + gic_data.rdists.has_direct_lpi = true; + gic_data.rdists.has_vpend_valid_dirty = true; + }
if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { err = -ENOMEM; @@ -2050,6 +2139,7 @@ static void __iomem *gic_of_iomap(struct device_node *node, int idx,
static int __init gic_of_init(struct device_node *node, struct device_node *parent) { + phys_addr_t dist_phys_base; void __iomem *dist_base; struct redist_region *rdist_regs; struct resource res; @@ -2063,6 +2153,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare return PTR_ERR(dist_base); }
+ dist_phys_base = res.start; + err = gic_validate_dist_version(dist_base); if (err) { pr_err("%pOF: no distributor detected, giving up\n", node); @@ -2094,8 +2186,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
gic_enable_of_quirks(node, gic_quirks, &gic_data);
- err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, - redist_stride, &node->fwnode); + err = gic_init_bases(dist_phys_base, dist_base, rdist_regs, + nr_redist_regions, redist_stride, &node->fwnode); if (err) goto out_unmap_rdist;
@@ -2411,8 +2503,9 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) goto out_redist_unmap; }
- err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs, - acpi_data.nr_redist_regions, 0, gsi_domain_handle); + err = gic_init_bases(dist->base_address, acpi_data.dist_base, + acpi_data.redist_regs, acpi_data.nr_redist_regions, + 0, gsi_domain_handle); if (err) goto out_fwhandle_free;
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 220c8c60e021a..f196c19f8e55c 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -226,6 +226,24 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);
extern u64 smccc_has_sve_hint;
+/** + * arm_smccc_get_soc_id_version() + * + * Returns the SOC ID version. + * + * When ARM_SMCCC_ARCH_SOC_ID is not present, returns SMCCC_RET_NOT_SUPPORTED. + */ +s32 arm_smccc_get_soc_id_version(void); + +/** + * arm_smccc_get_soc_id_revision() + * + * Returns the SOC ID revision. + * + * When ARM_SMCCC_ARCH_SOC_ID is not present, returns SMCCC_RET_NOT_SUPPORTED. + */ +s32 arm_smccc_get_soc_id_revision(void); + /** * struct arm_smccc_res - Result from SMC/HVC call * @a0-a3 result values from registers 0 to 3
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit 0ff7aee24e47beb4306ce050824b54147f2fabfa ]
Exiting early in remove without releasing all acquired resources yields leaks. Note that e.g. memory allocated with devm_zalloc() is freed after .remove() returns, even if the return code was negative.
While blocking_notifier_chain_unregister() won't fail and so the change is somewhat cosmetic, platform driver's .remove callbacks are about to be converted to return void. To prepare that, keep the error message but don't return early.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 6ebedc71d67d4..960432230bbf1 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -332,14 +332,16 @@ static int cros_ec_cec_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret;
+ /* + * blocking_notifier_chain_unregister() only fails if the notifier isn't + * in the list. We know it was added to it by .probe(), so there should + * be no need for error checking. Be cautious and still check. + */ ret = blocking_notifier_chain_unregister( &cros_ec_cec->cros_ec->event_notifier, &cros_ec_cec->notifier); - - if (ret) { + if (ret) dev_err(dev, "failed to unregister notifier\n"); - return ret; - }
cec_notifier_cec_adap_unregister(cros_ec_cec->notify, cros_ec_cec->adap);
Hello,
On Sun, Apr 30, 2023 at 10:56:22PM -0400, Sasha Levin wrote:
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit 0ff7aee24e47beb4306ce050824b54147f2fabfa ]
Exiting early in remove without releasing all acquired resources yields leaks. Note that e.g. memory allocated with devm_zalloc() is freed after .remove() returns, even if the return code was negative.
While blocking_notifier_chain_unregister() won't fail and so the change is somewhat cosmetic, platform driver's .remove callbacks are about to be converted to return void. To prepare that, keep the error message but don't return early.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Sasha Levin sashal@kernel.org
While I'm positive this change doesn't break anything, it also doesn't fix anything and is only cosmetic (+ preparing a later change).
Unless you need it as a dependency I'd say, don't backport it for stable.
Best regards Uwe
On Mon, May 01, 2023 at 05:26:32PM +0200, Uwe Kleine-König wrote:
Hello,
On Sun, Apr 30, 2023 at 10:56:22PM -0400, Sasha Levin wrote:
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de
[ Upstream commit 0ff7aee24e47beb4306ce050824b54147f2fabfa ]
Exiting early in remove without releasing all acquired resources yields leaks. Note that e.g. memory allocated with devm_zalloc() is freed after .remove() returns, even if the return code was negative.
While blocking_notifier_chain_unregister() won't fail and so the change is somewhat cosmetic, platform driver's .remove callbacks are about to be converted to return void. To prepare that, keep the error message but don't return early.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Sasha Levin sashal@kernel.org
While I'm positive this change doesn't break anything, it also doesn't fix anything and is only cosmetic (+ preparing a later change).
Unless you need it as a dependency I'd say, don't backport it for stable.
Ack, dropped. Thanks!
From: Bingbu Cao bingbu.cao@intel.com
[ Upstream commit 567f97bd381fd79fa8563808118fc757cb6fa4ff ]
In current cio2-bridge, it is using the hid name to register software node and software node will create kobject and sysfs entry according to the node name, if there are multiple sensors and VCMs which are sharing same HID name, it will cause the software nodes registration failure:
sysfs: cannot create duplicate filename '/kernel/software_nodes/dw9714' ... Call Trace: software_node_register_nodes cio2_bridge_init ... kobject_add_internal failed for dw9714 with -EEXIST, don't try to register things with the same name in the same directory.
One solution is appending the sensor link(Mipi Port) in SSDB as suffix of the node name to fix this problem.
Signed-off-by: Bingbu Cao bingbu.cao@intel.com Signed-off-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/pci/intel/ipu3/cio2-bridge.c | 15 +++++++++++---- drivers/media/pci/intel/ipu3/cio2-bridge.h | 3 ++- 2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index dfefe0d8aa959..45427a3a3a252 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -212,6 +212,7 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge, struct cio2_sensor *sensor) { struct software_node *nodes = sensor->swnodes; + char vcm_name[ACPI_ID_LEN + 4];
cio2_bridge_init_swnode_names(sensor);
@@ -229,9 +230,13 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge, sensor->node_names.endpoint, &nodes[SWNODE_CIO2_PORT], sensor->cio2_properties); - if (sensor->ssdb.vcmtype) - nodes[SWNODE_VCM] = - NODE_VCM(cio2_vcm_types[sensor->ssdb.vcmtype - 1]); + if (sensor->ssdb.vcmtype) { + /* append ssdb.link to distinguish VCM nodes with same HID */ + snprintf(vcm_name, sizeof(vcm_name), "%s-%u", + cio2_vcm_types[sensor->ssdb.vcmtype - 1], + sensor->ssdb.link); + nodes[SWNODE_VCM] = NODE_VCM(vcm_name); + }
cio2_bridge_init_swnode_group(sensor); } @@ -295,7 +300,6 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, }
sensor = &bridge->sensors[bridge->n_sensors]; - strscpy(sensor->name, cfg->hid, sizeof(sensor->name));
ret = cio2_bridge_read_acpi_buffer(adev, "SSDB", &sensor->ssdb, @@ -303,6 +307,9 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, if (ret) goto err_put_adev;
+ snprintf(sensor->name, sizeof(sensor->name), "%s-%u", + cfg->hid, sensor->ssdb.link); + if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) { dev_warn(&adev->dev, "Unknown VCM type %d\n", sensor->ssdb.vcmtype); diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h index b93b749c65bda..b76ed8a641e20 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.h +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h @@ -113,7 +113,8 @@ struct cio2_sensor_config { };
struct cio2_sensor { - char name[ACPI_ID_LEN]; + /* append ssdb.link(u8) in "-%u" format as suffix of HID */ + char name[ACPI_ID_LEN + 4]; struct acpi_device *adev; struct i2c_client *vcm_i2c_client;
From: Hans de Goede hdegoede@redhat.com
[ Upstream commit abe4f5ae5efa6a63c7d5abfa07eb02bb56b4654e ]
After the recent backlight changes acpi_video# backlight devices are only registered when explicitly requested from the cmdline, by DMI quirk or by the GPU driver.
This means that we no longer get false-positive backlight control support advertised on desktop boards.
Remove the 3 DMI quirks for desktop boards where the false-positive issue was fixed through quirks before. Note many more desktop boards were affected but we never build a full quirk list for this.
Reviewed-by: Mario Limonciello mario.limonciello@amd.com Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/acpi/video_detect.c | 35 ----------------------------------- 1 file changed, 35 deletions(-)
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index e85729fc481fd..69ef2d9710c2c 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -130,12 +130,6 @@ static int video_detect_force_native(const struct dmi_system_id *d) return 0; }
-static int video_detect_force_none(const struct dmi_system_id *d) -{ - acpi_backlight_dmi = acpi_backlight_none; - return 0; -} - static const struct dmi_system_id video_detect_dmi_table[] = { /* * Models which should use the vendor backlight interface, @@ -768,35 +762,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15 3535"), }, }, - - /* - * Desktops which falsely report a backlight and which our heuristics - * for this do not catch. - */ - { - .callback = video_detect_force_none, - /* Dell OptiPlex 9020M */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"), - }, - }, - { - .callback = video_detect_force_none, - /* GIGABYTE GB-BXBT-2807 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), - DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"), - }, - }, - { - .callback = video_detect_force_none, - /* MSI MS-7721 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MSI"), - DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"), - }, - }, { }, };
From: Paul Hsieh Paul.Hsieh@amd.com
[ Upstream commit 385c3e4c29e1d4ce8f68687a8c84621e4c0e0416 ]
[Why] In 2560x1600@240p eDP panel, driver use lowest voltage level to play 1080p video cause underflow. According to HW SPEC, the senario should use high voltage level.
[How] ChromaPre value is zero when bandwidth validation. Correct ChromaPre calculation.
Reviewed-by: Nicholas Kazlauskas Nicholas.Kazlauskas@amd.com Reviewed-by: Jun Lei Jun.Lei@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Paul Hsieh Paul.Hsieh@amd.com Tested-by: Daniel Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c | 2 +- drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c | 2 +- .../gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c | 2 +- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index c3d75e56410cc..997aefde32cc3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -4866,7 +4866,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NoUrgentLatencyHidingPre[k]); }
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index 8f8e2e7e5cc53..becad3009d26c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -5192,7 +5192,7 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NotUrgentLatencyHidingPre[k]); }
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index e8bcae63f2656..193f153df0dfb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -5289,7 +5289,7 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ v->DETBufferSizeCThisState[k], &v->UrgentBurstFactorCursorPre[k], &v->UrgentBurstFactorLumaPre[k], - &v->UrgentBurstFactorChroma[k], + &v->UrgentBurstFactorChromaPre[k], &v->NotUrgentLatencyHidingPre[k]); }
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 3b2a014ccf8f5..916f8c5d7d7ad 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -3353,7 +3353,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /* Output */ &mode_lib->vba.UrgentBurstFactorCursorPre[k], &mode_lib->vba.UrgentBurstFactorLumaPre[k], - &mode_lib->vba.UrgentBurstFactorChroma[k], + &mode_lib->vba.UrgentBurstFactorChromaPre[k], &mode_lib->vba.NotUrgentLatencyHidingPre[k]); }
From: Mario Limonciello mario.limonciello@amd.com
[ Upstream commit d116db180decec1b21bba31d2ff495ac4d8e1b83 ]
The array is hardcoded to 8 in atomfirmware.h, but firmware provides a bigger one sometimes. Deferencing the larger array causes an out of bounds error.
commit 4fc1ba4aa589 ("drm/amd/display: fix array index out of bound error in bios parser") fixed some of this, but there are two other cases not covered by it. Fix those as well.
Reported-by: erhard_f@mailbox.org Link: https://bugzilla.kernel.org/show_bug.cgi?id=214853 Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2473 Signed-off-by: Mario Limonciello mario.limonciello@amd.com Reviewed-by: Harry Wentland harry.wentland@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index e381de2429fa6..ae3783a7d7f45 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -515,11 +515,8 @@ static enum bp_result get_gpio_i2c_info( info->i2c_slave_address = record->i2c_slave_addr;
/* TODO: check how to get register offset for en, Y, etc. */ - info->gpio_info.clk_a_register_index = - le16_to_cpu( - header->gpio_pin[table_index].data_a_reg_index); - info->gpio_info.clk_a_shift = - header->gpio_pin[table_index].gpio_bitshift; + info->gpio_info.clk_a_register_index = le16_to_cpu(pin->data_a_reg_index); + info->gpio_info.clk_a_shift = pin->gpio_bitshift;
return BP_RESULT_OK; }
From: lyndonli Lyndon.Li@amd.com
[ Upstream commit 5e08e9c742a00384e5abe74bd40cf4dc15cb3a2e ]
Fix sdma v4 sw fini error for sdma 4.2.2 to solve the following general protection fault
[ +0.108196] general protection fault, probably for non-canonical address 0xd5e5a4ae79d24a32: 0000 [#1] PREEMPT SMP PTI [ +0.000018] RIP: 0010:free_fw_priv+0xd/0x70 [ +0.000022] Call Trace: [ +0.000012] <TASK> [ +0.000011] release_firmware+0x55/0x80 [ +0.000021] amdgpu_ucode_release+0x11/0x20 [amdgpu] [ +0.000415] amdgpu_sdma_destroy_inst_ctx+0x4f/0x90 [amdgpu] [ +0.000360] sdma_v4_0_sw_fini+0xce/0x110 [amdgpu]
Signed-off-by: lyndonli Lyndon.Li@amd.com Reviewed-by: Likun Gao Likun.Gao@amd.com Reviewed-by: Feifei Xu Feifei.Xu@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index b5affba221569..96b0c3d42346a 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1870,7 +1870,7 @@ static int sdma_v4_0_sw_fini(void *handle) amdgpu_ring_fini(&adev->sdma.instance[i].page); }
- if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 0) || + if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) || adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) amdgpu_sdma_destroy_inst_ctx(adev, true); else
From: Laurent Pinchart laurent.pinchart@ideasonboard.com
[ Upstream commit e3a69496a1cde364c74a600d7a370179b58aed29 ]
Structures passed to subdev pad operations are all zero-initialized, but not always with the same kind of code constructs. While most drivers used designated initializers, which zero all the fields that are not specified, when declaring variables, some use memset(). Those two methods lead to the same end result, and, depending on compiler optimizations, may even be completely equivalent, but they're not consistent.
Improve coding style consistency by using designated initializers instead of calling memset(). Where applicable, also move the variables to inner scopes of for loops to ensure correct initialization in all iterations.
Signed-off-by: Laurent Pinchart laurent.pinchart@ideasonboard.com Reviewed-by: Lad Prabhakar prabhakar.csengg@gmail.com # For am437x Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Reviewed-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Reviewed-by: Kieran Bingham kieran.bingham+renesas@ideasonboard.com Reviewed-by: Philipp Zabel p.zabel@pengutronix.de Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/platform/renesas/vsp1/vsp1_drm.c | 18 +++++++++--------- .../media/platform/renesas/vsp1/vsp1_entity.c | 11 +++++------ .../platform/samsung/exynos4-is/fimc-capture.c | 7 ++++--- drivers/media/platform/ti/am437x/am437x-vpfe.c | 15 ++++++++------- drivers/media/platform/ti/cal/cal-video.c | 8 ++++---- drivers/media/usb/dvb-usb/cxusb-analog.c | 14 +++++++------- drivers/staging/media/imx/imx-media-capture.c | 12 ++++++------ drivers/staging/media/imx/imx-media-utils.c | 8 ++++---- drivers/staging/media/omap4iss/iss_video.c | 6 +++--- 9 files changed, 50 insertions(+), 49 deletions(-)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c index c6f25200982c8..7fe375b6322cd 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c @@ -66,7 +66,9 @@ static int vsp1_du_insert_uif(struct vsp1_device *vsp1, struct vsp1_entity *prev, unsigned int prev_pad, struct vsp1_entity *next, unsigned int next_pad) { - struct v4l2_subdev_format format; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret;
if (!uif) { @@ -82,8 +84,6 @@ static int vsp1_du_insert_uif(struct vsp1_device *vsp1, prev->sink = uif; prev->sink_pad = UIF_PAD_SINK;
- memset(&format, 0, sizeof(format)); - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; format.pad = prev_pad;
ret = v4l2_subdev_call(&prev->subdev, pad, get_fmt, NULL, &format); @@ -118,8 +118,12 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1, struct vsp1_entity *uif, unsigned int brx_input) { - struct v4l2_subdev_selection sel; - struct v4l2_subdev_format format; + struct v4l2_subdev_selection sel = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; const struct v4l2_rect *crop; int ret;
@@ -129,8 +133,6 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1, */ crop = &vsp1->drm->inputs[rpf->entity.index].crop;
- memset(&format, 0, sizeof(format)); - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; format.pad = RWPF_PAD_SINK; format.format.width = crop->width + crop->left; format.format.height = crop->height + crop->top; @@ -147,8 +149,6 @@ static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1, __func__, format.format.width, format.format.height, format.format.code, rpf->entity.index);
- memset(&sel, 0, sizeof(sel)); - sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; sel.pad = RWPF_PAD_SINK; sel.target = V4L2_SEL_TGT_CROP; sel.r = *crop; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 4c3bd2b1ca287..c31f05a80bb56 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -184,15 +184,14 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity, int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - struct v4l2_subdev_format format; unsigned int pad;
for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { - memset(&format, 0, sizeof(format)); - - format.pad = pad; - format.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY - : V4L2_SUBDEV_FORMAT_ACTIVE; + struct v4l2_subdev_format format = { + .pad = pad, + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY + : V4L2_SUBDEV_FORMAT_ACTIVE, + };
v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format); } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index e3b95a2b7e040..beaee54ee73bf 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -763,7 +763,10 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe); struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR]; - struct v4l2_subdev_format sfmt; + struct v4l2_subdev_format sfmt = { + .which = set ? V4L2_SUBDEV_FORMAT_ACTIVE + : V4L2_SUBDEV_FORMAT_TRY, + }; struct v4l2_mbus_framefmt *mf = &sfmt.format; struct media_entity *me; struct fimc_fmt *ffmt; @@ -774,9 +777,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, if (WARN_ON(!sd || !tfmt)) return -EINVAL;
- memset(&sfmt, 0, sizeof(sfmt)); sfmt.format = *tfmt; - sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
me = fimc_pipeline_get_head(&sd->entity);
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 2dfae9bc0bba8..dffac89cbd210 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -1499,7 +1499,9 @@ static int vpfe_enum_size(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { struct vpfe_device *vpfe = video_drvdata(file); - struct v4l2_subdev_frame_size_enum fse; + struct v4l2_subdev_frame_size_enum fse = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct v4l2_subdev *sd = vpfe->current_subdev->sd; struct vpfe_fmt *fmt; int ret; @@ -1514,11 +1516,9 @@ static int vpfe_enum_size(struct file *file, void *priv,
memset(fsize->reserved, 0x0, sizeof(fsize->reserved));
- memset(&fse, 0x0, sizeof(fse)); fse.index = fsize->index; fse.pad = 0; fse.code = fmt->code; - fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); if (ret) return ret; @@ -2146,7 +2146,6 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, { struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, struct vpfe_device, v4l2_dev); - struct v4l2_subdev_mbus_code_enum mbus_code; struct vpfe_subdev_info *sdinfo; struct vpfe_fmt *fmt; int ret = 0; @@ -2173,9 +2172,11 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
vpfe->num_active_fmt = 0; for (j = 0, i = 0; (ret != -EINVAL); ++j) { - memset(&mbus_code, 0, sizeof(mbus_code)); - mbus_code.index = j; - mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; + struct v4l2_subdev_mbus_code_enum mbus_code = { + .index = j, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code); if (ret) diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 4eade409d5d36..bbfd2719725aa 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -811,7 +811,6 @@ static const struct v4l2_file_operations cal_fops = {
static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) { - struct v4l2_subdev_mbus_code_enum mbus_code; struct v4l2_mbus_framefmt mbus_fmt; const struct cal_format_info *fmtinfo; unsigned int i, j, k; @@ -826,10 +825,11 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) ctx->num_active_fmt = 0;
for (j = 0, i = 0; ; ++j) { + struct v4l2_subdev_mbus_code_enum mbus_code = { + .index = j, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + };
- memset(&mbus_code, 0, sizeof(mbus_code)); - mbus_code.index = j; - mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code, NULL, &mbus_code); if (ret == -EINVAL) diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index e93183ddd7975..deba5224cb8df 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -1014,7 +1014,10 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, { struct dvb_usb_device *dvbdev = video_drvdata(file); struct cxusb_medion_dev *cxdev = dvbdev->priv; - struct v4l2_subdev_format subfmt; + struct v4l2_subdev_format subfmt = { + .which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : + V4L2_SUBDEV_FORMAT_TRY, + }; u32 field; int ret;
@@ -1024,9 +1027,6 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, field = vb2_start_streaming_called(&cxdev->videoqueue) ? cxdev->field_order : cxusb_medion_field_order(cxdev);
- memset(&subfmt, 0, sizeof(subfmt)); - subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : - V4L2_SUBDEV_FORMAT_TRY; subfmt.format.width = f->fmt.pix.width & ~1; subfmt.format.height = f->fmt.pix.height & ~1; subfmt.format.code = MEDIA_BUS_FMT_FIXED; @@ -1464,7 +1464,9 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) .buf = tuner_analog_msg_data, .len = sizeof(tuner_analog_msg_data) }; - struct v4l2_subdev_format subfmt; + struct v4l2_subdev_format subfmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret;
/* switch tuner to analog mode so IF demod will become accessible */ @@ -1507,8 +1509,6 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm); v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
- memset(&subfmt, 0, sizeof(subfmt)); - subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; subfmt.format.width = cxdev->width; subfmt.format.height = cxdev->height; subfmt.format.code = MEDIA_BUS_FMT_FIXED; diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index 93ba092360105..5cc67786b9169 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -501,14 +501,14 @@ static int capture_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct capture_priv *priv = video_drvdata(file); - struct v4l2_subdev_frame_interval fi; + struct v4l2_subdev_frame_interval fi = { + .pad = priv->src_sd_pad, + }; int ret;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL;
- memset(&fi, 0, sizeof(fi)); - fi.pad = priv->src_sd_pad; ret = v4l2_subdev_call(priv->src_sd, video, g_frame_interval, &fi); if (ret < 0) return ret; @@ -523,14 +523,14 @@ static int capture_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct capture_priv *priv = video_drvdata(file); - struct v4l2_subdev_frame_interval fi; + struct v4l2_subdev_frame_interval fi = { + .pad = priv->src_sd_pad, + }; int ret;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL;
- memset(&fi, 0, sizeof(fi)); - fi.pad = priv->src_sd_pad; fi.interval = a->parm.capture.timeperframe; ret = v4l2_subdev_call(priv->src_sd, video, s_frame_interval, &fi); if (ret < 0) diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 411e907b68eba..b545750ca5262 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -432,15 +432,15 @@ int imx_media_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf_try; - struct v4l2_subdev_format format; unsigned int pad; int ret;
for (pad = 0; pad < sd->entity.num_pads; pad++) { - memset(&format, 0, sizeof(format)); + struct v4l2_subdev_format format = { + .pad = pad, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + };
- format.pad = pad; - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); if (ret) continue; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 05548eab7daad..74fb0d185a8ff 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -237,7 +237,9 @@ static int __iss_video_get_format(struct iss_video *video, struct v4l2_mbus_framefmt *format) { - struct v4l2_subdev_format fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct v4l2_subdev *subdev; u32 pad; int ret; @@ -246,9 +248,7 @@ __iss_video_get_format(struct iss_video *video, if (!subdev) return -EINVAL;
- memset(&fmt, 0, sizeof(fmt)); fmt.pad = pad; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
mutex_lock(&video->mutex); ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
From: Mukul Joshi mukul.joshi@amd.com
[ Upstream commit 318e431b306e966d2ee99e900a11bdc9a701ee83 ]
This patch enables the IH retry CAM on GFX9 series cards. This retry filter is used to prevent sending lots of retry interrupts in a short span of time and overflowing the IH ring buffer. This will also help reduce CPU interrupt workload.
Signed-off-by: Mukul Joshi mukul.joshi@amd.com Reviewed-by: Felix Kuehling Felix.Kuehling@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h | 2 + drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 51 +++++++++++------ drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c | 2 +- drivers/gpu/drm/amd/amdgpu/vega20_ih.c | 55 +++++++++---------- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 10 +++- .../asic_reg/oss/osssys_4_2_0_offset.h | 6 ++ .../asic_reg/oss/osssys_4_2_0_sh_mask.h | 11 ++++ 7 files changed, 88 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h index e9f2c11ea416c..be243adf3e657 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h @@ -98,6 +98,8 @@ struct amdgpu_irq { struct irq_domain *domain; /* GPU irq controller domain */ unsigned virq[AMDGPU_MAX_IRQ_SRC_ID]; uint32_t srbm_soft_reset; + u32 retry_cam_doorbell_index; + bool retry_cam_enabled; };
void amdgpu_irq_disable_all(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index b06170c00dfca..6573903876fd8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -553,32 +553,49 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, const char *mmhub_cid; const char *hub_name; u64 addr; + uint32_t cam_index = 0; + int ret;
addr = (u64)entry->src_data[0] << 12; addr |= ((u64)entry->src_data[1] & 0xf) << 44;
if (retry_fault) { - /* Returning 1 here also prevents sending the IV to the KFD */ + if (adev->irq.retry_cam_enabled) { + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + } + + cam_index = entry->src_data[2] & 0x3ff;
- /* Process it onyl if it's the first fault for this address */ - if (entry->ih != &adev->irq.ih_soft && - amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, + ret = amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault); + WDOORBELL32(adev->irq.retry_cam_doorbell_index, cam_index); + if (ret) + return 1; + } else { + /* Process it onyl if it's the first fault for this address */ + if (entry->ih != &adev->irq.ih_soft && + amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid, entry->timestamp)) - return 1; + return 1;
- /* Delegate it to a different ring if the hardware hasn't - * already done it. - */ - if (entry->ih == &adev->irq.ih) { - amdgpu_irq_delegate(adev, entry, 8); - return 1; - } + /* Delegate it to a different ring if the hardware hasn't + * already done it. + */ + if (entry->ih == &adev->irq.ih) { + amdgpu_irq_delegate(adev, entry, 8); + return 1; + }
- /* Try to handle the recoverable page faults by filling page - * tables - */ - if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault)) - return 1; + /* Try to handle the recoverable page faults by filling page + * tables + */ + if (amdgpu_vm_handle_fault(adev, entry->pasid, addr, write_fault)) + return 1; + } }
if (!printk_ratelimit()) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 19455a7259391..685abf57ffddc 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -238,7 +238,7 @@ static void nbio_v7_4_ih_doorbell_range(struct amdgpu_device *adev,
if (use_doorbell) { ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, OFFSET, doorbell_index); - ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 4); + ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 8); } else ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range, BIF_IH_DOORBELL_RANGE, SIZE, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c index 1706081d054dd..6a8fb1fb48a3d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c @@ -38,6 +38,11 @@ #define mmIH_CHICKEN_ALDEBARAN 0x18d #define mmIH_CHICKEN_ALDEBARAN_BASE_IDX 0
+#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN 0x00ea +#define mmIH_RETRY_INT_CAM_CNTL_ALDEBARAN_BASE_IDX 0 +#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE__SHIFT 0x10 +#define IH_RETRY_INT_CAM_CNTL_ALDEBARAN__ENABLE_MASK 0x00010000L + static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev);
/** @@ -251,36 +256,14 @@ static int vega20_ih_enable_ring(struct amdgpu_device *adev, return 0; }
-/** - * vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring - * - * @adev: amdgpu_device pointer - * - * Reroute VMC and UMC interrupts on primary ih ring to - * ih ring 1 so they won't lose when bunches of page faults - * interrupts overwhelms the interrupt handler(VEGA20) - */ -static void vega20_ih_reroute_ih(struct amdgpu_device *adev) +static uint32_t vega20_setup_retry_doorbell(u32 doorbell_index) { - uint32_t tmp; + u32 val = 0;
- /* vega20 ih reroute will go through psp this - * function is used for newer asics starting arcturus - */ - if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) { - /* Reroute to IH ring 1 for VMC */ - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12); - tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp); - - /* Reroute IH ring 1 for UTCL2 */ - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B); - tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); - tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1); - WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp); - } + val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, OFFSET, doorbell_index); + val = REG_SET_FIELD(val, IH_DOORBELL_RPTR, ENABLE, 1); + + return val; }
/** @@ -332,8 +315,6 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
for (i = 0; i < ARRAY_SIZE(ih); i++) { if (ih[i]->ring_size) { - if (i == 1) - vega20_ih_reroute_ih(adev); ret = vega20_ih_enable_ring(adev, ih[i]); if (ret) return ret; @@ -346,6 +327,20 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev)
pci_set_master(adev->pdev);
+ /* Allocate the doorbell for IH Retry CAM */ + adev->irq.retry_cam_doorbell_index = (adev->doorbell_index.ih + 3) << 1; + WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RETRY_CAM, + vega20_setup_retry_doorbell(adev->irq.retry_cam_doorbell_index)); + + /* Enable IH Retry CAM */ + if (adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 4, 0)) + WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL_ALDEBARAN, + ENABLE, 1); + else + WREG32_FIELD15(OSSSYS, 0, IH_RETRY_INT_CAM_CNTL, ENABLE, 1); + + adev->irq.retry_cam_enabled = true; + /* enable interrupts */ ret = vega20_ih_toggle_interrupts(adev, true); if (ret) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index dc6fd69670509..96a138a395150 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2172,7 +2172,15 @@ static void svm_range_drain_retry_fault(struct svm_range_list *svms) pr_debug("drain retry fault gpu %d svms %p\n", i, svms);
amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev, - &pdd->dev->adev->irq.ih1); + pdd->dev->adev->irq.retry_cam_enabled ? + &pdd->dev->adev->irq.ih : + &pdd->dev->adev->irq.ih1); + + if (pdd->dev->adev->irq.retry_cam_enabled) + amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev, + &pdd->dev->adev->irq.ih_soft); + + pr_debug("drain retry fault gpu %d svms 0x%p done\n", i, svms); } if (atomic_cmpxchg(&svms->drain_pagefaults, drain, 0) != drain) diff --git a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h index bd129266ebfd1..a84a7cfaf71e5 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_offset.h @@ -135,6 +135,8 @@ #define mmIH_RB_WPTR_ADDR_LO_BASE_IDX 0 #define mmIH_DOORBELL_RPTR 0x0087 #define mmIH_DOORBELL_RPTR_BASE_IDX 0 +#define mmIH_DOORBELL_RETRY_CAM 0x0088 +#define mmIH_DOORBELL_RETRY_CAM_BASE_IDX 0 #define mmIH_RB_CNTL_RING1 0x008c #define mmIH_RB_CNTL_RING1_BASE_IDX 0 #define mmIH_RB_BASE_RING1 0x008d @@ -159,6 +161,8 @@ #define mmIH_RB_WPTR_RING2_BASE_IDX 0 #define mmIH_DOORBELL_RPTR_RING2 0x009f #define mmIH_DOORBELL_RPTR_RING2_BASE_IDX 0 +#define mmIH_RETRY_CAM_ACK 0x00a4 +#define mmIH_RETRY_CAM_ACK_BASE_IDX 0 #define mmIH_VERSION 0x00a5 #define mmIH_VERSION_BASE_IDX 0 #define mmIH_CNTL 0x00c0 @@ -235,6 +239,8 @@ #define mmIH_MMHUB_ERROR_BASE_IDX 0 #define mmIH_MEM_POWER_CTRL 0x00e8 #define mmIH_MEM_POWER_CTRL_BASE_IDX 0 +#define mmIH_RETRY_INT_CAM_CNTL 0x00e9 +#define mmIH_RETRY_INT_CAM_CNTL_BASE_IDX 0 #define mmIH_REGISTER_LAST_PART2 0x00ff #define mmIH_REGISTER_LAST_PART2_BASE_IDX 0 #define mmSEM_CLK_CTRL 0x0100 diff --git a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h index 3ea83ea9ce3a4..75c04fc275a0c 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_2_0_sh_mask.h @@ -349,6 +349,17 @@ #define IH_DOORBELL_RPTR_RING2__ENABLE__SHIFT 0x1c #define IH_DOORBELL_RPTR_RING2__OFFSET_MASK 0x03FFFFFFL #define IH_DOORBELL_RPTR_RING2__ENABLE_MASK 0x10000000L +//IH_RETRY_INT_CAM_CNTL +#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE__SHIFT 0x0 +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE__SHIFT 0x8 +#define IH_RETRY_INT_CAM_CNTL__ENABLE__SHIFT 0x10 +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE__SHIFT 0x11 +#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE__SHIFT 0x14 +#define IH_RETRY_INT_CAM_CNTL__CAM_SIZE_MASK 0x0000001FL +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_SKID_VALUE_MASK 0x00003F00L +#define IH_RETRY_INT_CAM_CNTL__ENABLE_MASK 0x00010000L +#define IH_RETRY_INT_CAM_CNTL__BACK_PRESSURE_ENABLE_MASK 0x00020000L +#define IH_RETRY_INT_CAM_CNTL__PER_VF_ENTRY_SIZE_MASK 0x00300000L //IH_VERSION #define IH_VERSION__MINVER__SHIFT 0x0 #define IH_VERSION__MAJVER__SHIFT 0x8
From: Wei Chen harperchen1110@gmail.com
[ Upstream commit 8fbcf730cb89c3647f3365226fe7014118fa93c7 ]
variable *nplanes is provided by user via system call argument. The possible value of q_data->fmt->num_planes is 1-3, while the value of *nplanes can be 1-8. The array access by index i can cause array out-of-bounds.
Fix this bug by checking *nplanes against the array size.
Signed-off-by: Wei Chen harperchen1110@gmail.com Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 641f533c417fd..173407664cf42 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -753,6 +753,13 @@ int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, }
if (*nplanes) { + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (*nplanes != q_data->fmt->num_planes) + return -EINVAL; + } else { + if (*nplanes != 1) + return -EINVAL; + } for (i = 0; i < *nplanes; i++) { if (sizes[i] < q_data->sizeimage[i]) return -EINVAL;
From: Feng Jiang jiangfeng@kylinos.cn
[ Upstream commit f6e7ac4c35a28aef0be93b32c533ae678ad0b9e7 ]
Function amd_pmc_stb_debugfs_open_v2() may be called when the STB debug mechanism enabled.
When amd_pmc_send_cmd() fails, the 'buf' needs to be released.
Signed-off-by: Feng Jiang jiangfeng@kylinos.cn Link: https://lore.kernel.org/r/20230412093734.1126410-1-jiangfeng@kylinos.cn Reviewed-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/platform/x86/amd/pmc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 2edaae04a6912..91d04e710486e 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -268,6 +268,7 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) dev->msg_port = 0; if (ret) { dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); + kfree(buf); return ret; }
From: Aleksandr Mezin mezin.alexander@gmail.com
[ Upstream commit 4a148e9b1ee04e608263fa9536a96214d5561220 ]
This seems to be a new revision of the device. RGB controls have changed, but this driver doesn't touch them anyway.
Fan speed control reported to be working with existing userspace (hidraw) software, so I assume it's compatible. Fan channel count is the same.
Recently added (0x1e71, 0x2019) seems to be the same device.
Discovered in liquidctl project:
https://github.com/liquidctl/liquidctl/issues/541
Signed-off-by: Aleksandr Mezin mezin.alexander@gmail.com Link: https://lore.kernel.org/r/20230219105924.333007-1-mezin.alexander@gmail.com Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/nzxt-smart2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c index 2b93ba89610ae..a8e72d8fd0605 100644 --- a/drivers/hwmon/nzxt-smart2.c +++ b/drivers/hwmon/nzxt-smart2.c @@ -791,7 +791,8 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = { { HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */ - { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */ + { HID_USB_DEVICE(0x1e71, 0x2011) }, /* NZXT RGB & Fan Controller (6 RGB) */ + { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller (6 RGB) */ {}, };
linux-stable-mirror@lists.linaro.org