From: Greg Kroah-Hartman Date: Tue, 23 Nov 2021 11:56:05 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v5.15.5~42 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e25b484b226fa55f407cd0d82332a6705ffcaa72;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: drm-amd-pm-avoid-duplicate-powergate-ungate-setting.patch drm-amdgpu-fix-set-scaling-mode-full-full-aspect-center-not-works-on-vga-and-dvi-connectors.patch drm-i915-dp-ensure-max-link-params-are-always-valid.patch drm-i915-dp-ensure-sink-rate-values-are-always-valid.patch drm-i915-fix-type1-dvi-dp-dual-mode-adapter-heuristic-for-modern-platforms.patch drm-nouveau-add-a-dedicated-mutex-for-the-clients-list.patch drm-nouveau-clean-up-all-clients-on-device-removal.patch drm-nouveau-use-drm_dev_unplug-during-device-removal.patch drm-prime-fix-use-after-free-in-mmap-with-drm_gem_ttm_mmap.patch --- diff --git a/queue-5.15/drm-amd-pm-avoid-duplicate-powergate-ungate-setting.patch b/queue-5.15/drm-amd-pm-avoid-duplicate-powergate-ungate-setting.patch new file mode 100644 index 00000000000..523f268998c --- /dev/null +++ b/queue-5.15/drm-amd-pm-avoid-duplicate-powergate-ungate-setting.patch @@ -0,0 +1,105 @@ +From 6ee27ee27ba8b2e725886951ba2d2d87f113bece Mon Sep 17 00:00:00 2001 +From: Evan Quan +Date: Fri, 5 Nov 2021 15:25:30 +0800 +Subject: drm/amd/pm: avoid duplicate powergate/ungate setting + +From: Evan Quan + +commit 6ee27ee27ba8b2e725886951ba2d2d87f113bece upstream. + +Just bail out if the target IP block is already in the desired +powergate/ungate state. This can avoid some duplicate settings +which sometimes may cause unexpected issues. + +Link: https://lore.kernel.org/all/YV81vidWQLWvATMM@zn.tnic/ +Bug: https://bugzilla.kernel.org/show_bug.cgi?id=214921 +Bug: https://bugzilla.kernel.org/show_bug.cgi?id=215025 +Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1789 +Fixes: bf756fb833cb ("drm/amdgpu: add missing cleanups for Polaris12 UVD/VCE on suspend") +Signed-off-by: Evan Quan +Tested-by: Borislav Petkov +Reviewed-by: Lijo Lazar +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +++ + drivers/gpu/drm/amd/include/amd_shared.h | 3 ++- + drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 10 ++++++++++ + drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 8 ++++++++ + 4 files changed, 23 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -3532,6 +3532,9 @@ int amdgpu_device_init(struct amdgpu_dev + adev->rmmio_size = pci_resource_len(adev->pdev, 2); + } + ++ for (i = 0; i < AMD_IP_BLOCK_TYPE_NUM; i++) ++ atomic_set(&adev->pm.pwr_state[i], POWER_STATE_UNKNOWN); ++ + adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size); + if (adev->rmmio == NULL) { + return -ENOMEM; +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -98,7 +98,8 @@ enum amd_ip_block_type { + AMD_IP_BLOCK_TYPE_ACP, + AMD_IP_BLOCK_TYPE_VCN, + AMD_IP_BLOCK_TYPE_MES, +- AMD_IP_BLOCK_TYPE_JPEG ++ AMD_IP_BLOCK_TYPE_JPEG, ++ AMD_IP_BLOCK_TYPE_NUM, + }; + + enum amd_clockgating_state { +--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +@@ -927,6 +927,13 @@ int amdgpu_dpm_set_powergating_by_smu(st + { + int ret = 0; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; ++ enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON; ++ ++ if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state) { ++ dev_dbg(adev->dev, "IP block%d already in the target %s state!", ++ block_type, gate ? "gate" : "ungate"); ++ return 0; ++ } + + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: +@@ -979,6 +986,9 @@ int amdgpu_dpm_set_powergating_by_smu(st + break; + } + ++ if (!ret) ++ atomic_set(&adev->pm.pwr_state[block_type], pwr_state); ++ + return ret; + } + +--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h ++++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +@@ -417,6 +417,12 @@ struct amdgpu_dpm { + enum amd_dpm_forced_level forced_level; + }; + ++enum ip_power_state { ++ POWER_STATE_UNKNOWN, ++ POWER_STATE_ON, ++ POWER_STATE_OFF, ++}; ++ + struct amdgpu_pm { + struct mutex mutex; + u32 current_sclk; +@@ -452,6 +458,8 @@ struct amdgpu_pm { + struct i2c_adapter smu_i2c; + struct mutex smu_i2c_mutex; + struct list_head pm_attr_list; ++ ++ atomic_t pwr_state[AMD_IP_BLOCK_TYPE_NUM]; + }; + + #define R600_SSTU_DFLT 0 diff --git a/queue-5.15/drm-amdgpu-fix-set-scaling-mode-full-full-aspect-center-not-works-on-vga-and-dvi-connectors.patch b/queue-5.15/drm-amdgpu-fix-set-scaling-mode-full-full-aspect-center-not-works-on-vga-and-dvi-connectors.patch new file mode 100644 index 00000000000..0fbe2e0affb --- /dev/null +++ b/queue-5.15/drm-amdgpu-fix-set-scaling-mode-full-full-aspect-center-not-works-on-vga-and-dvi-connectors.patch @@ -0,0 +1,38 @@ +From bf552083916a7f8800477b5986940d1c9a31b953 Mon Sep 17 00:00:00 2001 +From: hongao +Date: Thu, 11 Nov 2021 11:32:07 +0800 +Subject: drm/amdgpu: fix set scaling mode Full/Full aspect/Center not works on vga and dvi connectors + +From: hongao + +commit bf552083916a7f8800477b5986940d1c9a31b953 upstream. + +amdgpu_connector_vga_get_modes missed function amdgpu_get_native_mode +which assign amdgpu_encoder->native_mode with *preferred_mode result in +amdgpu_encoder->native_mode.clock always be 0. That will cause +amdgpu_connector_set_property returned early on: +if ((rmx_type != DRM_MODE_SCALE_NONE) && + (amdgpu_encoder->native_mode.clock == 0)) +when we try to set scaling mode Full/Full aspect/Center. +Add the missing function to amdgpu_connector_vga_get_mode can fix this. +It also works on dvi connectors because +amdgpu_connector_dvi_helper_funcs.get_mode use the same method. + +Signed-off-by: hongao +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -827,6 +827,7 @@ static int amdgpu_connector_vga_get_mode + + amdgpu_connector_get_edid(connector); + ret = amdgpu_connector_ddc_get_modes(connector); ++ amdgpu_get_native_mode(connector); + + return ret; + } diff --git a/queue-5.15/drm-i915-dp-ensure-max-link-params-are-always-valid.patch b/queue-5.15/drm-i915-dp-ensure-max-link-params-are-always-valid.patch new file mode 100644 index 00000000000..ba497db22fa --- /dev/null +++ b/queue-5.15/drm-i915-dp-ensure-max-link-params-are-always-valid.patch @@ -0,0 +1,92 @@ +From cc99bc62ff6902688ee7bd3a7b25eefc620fbb6a Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Mon, 18 Oct 2021 12:41:51 +0300 +Subject: drm/i915/dp: Ensure max link params are always valid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Imre Deak + +commit cc99bc62ff6902688ee7bd3a7b25eefc620fbb6a upstream. + +Atm until the DPCD for a connector is read the max link rate and lane +count params are invalid. If the connector is modeset, in +intel_dp_compute_config(), intel_dp_common_len_rate_limit(max_link_rate) +will return 0, leading to a intel_dp->common_rates[-1] access. + +Fix the above by making sure the max link params are always valid. + +The above access leads to an undefined behaviour by definition, though +not causing a user visible problem to my best knowledge, see the previous +patch why. Nevertheless it is an undefined behaviour and it triggers a +BUG() in CONFIG_UBSAN builds, hence CC:stable. + +Cc: Ville Syrjälä +Cc: +Signed-off-by: Imre Deak +Reviewed-by: Ville Syrjälä +Acked-by: Jani Nikula +Link: https://patchwork.freedesktop.org/patch/msgid/20211018094154.1407705-4-imre.deak@intel.com +(cherry picked from commit 9ad87de4735620ffc555592e8c5f580478fa3ed0) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_dp.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -1773,6 +1773,12 @@ void intel_dp_set_link_params(struct int + intel_dp->lane_count = lane_count; + } + ++static void intel_dp_reset_max_link_params(struct intel_dp *intel_dp) ++{ ++ intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp); ++ intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); ++} ++ + /* Enable backlight PWM and backlight PP control. */ + void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +@@ -1932,8 +1938,7 @@ void intel_dp_sync_state(struct intel_en + if (intel_dp->dpcd[DP_DPCD_REV] == 0) + intel_dp_get_dpcd(intel_dp); + +- intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp); +- intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); ++ intel_dp_reset_max_link_params(intel_dp); + } + + bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, +@@ -2506,6 +2511,7 @@ intel_edp_init_dpcd(struct intel_dp *int + intel_dp_set_sink_rates(intel_dp); + + intel_dp_set_common_rates(intel_dp); ++ intel_dp_reset_max_link_params(intel_dp); + + /* Read the eDP DSC DPCD registers */ + if (DISPLAY_VER(dev_priv) >= 10) +@@ -4249,12 +4255,7 @@ intel_dp_detect(struct drm_connector *co + * supports link training fallback params. + */ + if (intel_dp->reset_link_params || intel_dp->is_mst) { +- /* Initial max link lane count */ +- intel_dp->max_link_lane_count = intel_dp_max_common_lane_count(intel_dp); +- +- /* Initial max link rate */ +- intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); +- ++ intel_dp_reset_max_link_params(intel_dp); + intel_dp->reset_link_params = false; + } + +@@ -5307,6 +5308,7 @@ intel_dp_init_connector(struct intel_dig + intel_dp_set_source_rates(intel_dp); + intel_dp_set_default_sink_rates(intel_dp); + intel_dp_set_common_rates(intel_dp); ++ intel_dp_reset_max_link_params(intel_dp); + + intel_dp->reset_link_params = true; + intel_dp->pps.pps_pipe = INVALID_PIPE; diff --git a/queue-5.15/drm-i915-dp-ensure-sink-rate-values-are-always-valid.patch b/queue-5.15/drm-i915-dp-ensure-sink-rate-values-are-always-valid.patch new file mode 100644 index 00000000000..17b02a15cce --- /dev/null +++ b/queue-5.15/drm-i915-dp-ensure-sink-rate-values-are-always-valid.patch @@ -0,0 +1,97 @@ +From 6c34bd4532a3f39952952ddc102737595729afc4 Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Mon, 18 Oct 2021 17:34:17 +0300 +Subject: drm/i915/dp: Ensure sink rate values are always valid +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Imre Deak + +commit 6c34bd4532a3f39952952ddc102737595729afc4 upstream. + +Atm, there are no sink rate values set for DP (vs. eDP) sinks until the +DPCD capabilities are successfully read from the sink. During this time +intel_dp->num_common_rates is 0 which can lead to a + +intel_dp->common_rates[-1] (*) + +access, which is an undefined behaviour, in the following cases: + +- In intel_dp_sync_state(), if the encoder is enabled without a sink + connected to the encoder's connector (BIOS enabled a monitor, but the + user unplugged the monitor until the driver loaded). +- In intel_dp_sync_state() if the encoder is enabled with a sink + connected, but for some reason the DPCD read has failed. +- In intel_dp_compute_link_config() if modesetting a connector without + a sink connected on it. +- In intel_dp_compute_link_config() if modesetting a connector with a + a sink connected on it, but before probing the connector first. + +To avoid the (*) access in all the above cases, make sure that the sink +rate table - and hence the common rate table - is always valid, by +setting a default minimum sink rate when registering the connector +before anything could use it. + +I also considered setting all the DP link rates by default, so that +modesetting with higher resolution modes also succeeds in the last two +cases above. However in case a sink is not connected that would stop +working after the first modeset, due to the LT fallback logic. So this +would need more work, beyond the scope of this fix. + +As I mentioned in the previous patch, I don't think the issue this patch +fixes is user visible, however it is an undefined behaviour by +definition and triggers a BUG() in CONFIG_UBSAN builds, hence CC:stable. + +v2: Clear the default sink rates, before initializing these for eDP. + +Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4297 +References: https://gitlab.freedesktop.org/drm/intel/-/issues/4298 +Suggested-by: Ville Syrjälä +Cc: Ville Syrjälä +Cc: +Signed-off-by: Imre Deak +Reviewed-by: Ville Syrjälä +Acked-by: Jani Nikula +Link: https://patchwork.freedesktop.org/patch/msgid/20211018143417.1452632-1-imre.deak@intel.com +(cherry picked from commit 3f61ef9777c0ab0f03f4af0ed6fd3e5250537a8d) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_dp.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -111,6 +111,12 @@ bool intel_dp_is_edp(struct intel_dp *in + static void intel_dp_unset_edid(struct intel_dp *intel_dp); + static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); + ++static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) ++{ ++ intel_dp->sink_rates[0] = 162000; ++ intel_dp->num_sink_rates = 1; ++} ++ + /* update sink rates from dpcd */ + static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) + { +@@ -2462,6 +2468,9 @@ intel_edp_init_dpcd(struct intel_dp *int + */ + intel_psr_init_dpcd(intel_dp); + ++ /* Clear the default sink rates */ ++ intel_dp->num_sink_rates = 0; ++ + /* Read the eDP 1.4+ supported link rates. */ + if (intel_dp->edp_dpcd[0] >= DP_EDP_14) { + __le16 sink_rates[DP_MAX_SUPPORTED_RATES]; +@@ -5296,6 +5305,8 @@ intel_dp_init_connector(struct intel_dig + return false; + + intel_dp_set_source_rates(intel_dp); ++ intel_dp_set_default_sink_rates(intel_dp); ++ intel_dp_set_common_rates(intel_dp); + + intel_dp->reset_link_params = true; + intel_dp->pps.pps_pipe = INVALID_PIPE; diff --git a/queue-5.15/drm-i915-fix-type1-dvi-dp-dual-mode-adapter-heuristic-for-modern-platforms.patch b/queue-5.15/drm-i915-fix-type1-dvi-dp-dual-mode-adapter-heuristic-for-modern-platforms.patch new file mode 100644 index 00000000000..0a2d1a42263 --- /dev/null +++ b/queue-5.15/drm-i915-fix-type1-dvi-dp-dual-mode-adapter-heuristic-for-modern-platforms.patch @@ -0,0 +1,155 @@ +From 1977e8eb40ed53f0cac7db1a78295726f4ac0b24 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Mon, 25 Oct 2021 17:21:47 +0300 +Subject: drm/i915: Fix type1 DVI DP dual mode adapter heuristic for modern platforms +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +commit 1977e8eb40ed53f0cac7db1a78295726f4ac0b24 upstream. + +Looks like we never updated intel_bios_is_port_dp_dual_mode() when +the VBT port mapping became erratic on modern platforms. This +is causing us to look up the wrong child device and thus throwing +the heuristic off (ie. we might end looking at a child device for +a genuine DP++ port when we were supposed to look at one for a +native HDMI port). + +Fix it up by not using the outdated port_mapping[] in +intel_bios_is_port_dp_dual_mode() and rely on +intel_bios_encoder_data_lookup() instead. + +Cc: stable@vger.kernel.org +Tested-by: Randy Dunlap +Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4138 +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20211025142147.23897-1-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +(cherry picked from commit 32c2bc89c7420fad2959ee23ef5b6be8b05d2bde) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_bios.c | 85 ++++++++++++++++++++++-------- + 1 file changed, 63 insertions(+), 22 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -1692,6 +1692,39 @@ static u8 map_ddc_pin(struct drm_i915_pr + return 0; + } + ++static u8 dvo_port_type(u8 dvo_port) ++{ ++ switch (dvo_port) { ++ case DVO_PORT_HDMIA: ++ case DVO_PORT_HDMIB: ++ case DVO_PORT_HDMIC: ++ case DVO_PORT_HDMID: ++ case DVO_PORT_HDMIE: ++ case DVO_PORT_HDMIF: ++ case DVO_PORT_HDMIG: ++ case DVO_PORT_HDMIH: ++ case DVO_PORT_HDMII: ++ return DVO_PORT_HDMIA; ++ case DVO_PORT_DPA: ++ case DVO_PORT_DPB: ++ case DVO_PORT_DPC: ++ case DVO_PORT_DPD: ++ case DVO_PORT_DPE: ++ case DVO_PORT_DPF: ++ case DVO_PORT_DPG: ++ case DVO_PORT_DPH: ++ case DVO_PORT_DPI: ++ return DVO_PORT_DPA; ++ case DVO_PORT_MIPIA: ++ case DVO_PORT_MIPIB: ++ case DVO_PORT_MIPIC: ++ case DVO_PORT_MIPID: ++ return DVO_PORT_MIPIA; ++ default: ++ return dvo_port; ++ } ++} ++ + static enum port __dvo_port_to_port(int n_ports, int n_dvo, + const int port_mapping[][3], u8 dvo_port) + { +@@ -2622,35 +2655,17 @@ bool intel_bios_is_port_edp(struct drm_i + return false; + } + +-static bool child_dev_is_dp_dual_mode(const struct child_device_config *child, +- enum port port) ++static bool child_dev_is_dp_dual_mode(const struct child_device_config *child) + { +- static const struct { +- u16 dp, hdmi; +- } port_mapping[] = { +- /* +- * Buggy VBTs may declare DP ports as having +- * HDMI type dvo_port :( So let's check both. +- */ +- [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, }, +- [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, +- [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, +- [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, +- [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, }, +- }; +- +- if (port == PORT_A || port >= ARRAY_SIZE(port_mapping)) +- return false; +- + if ((child->device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) != + (DEVICE_TYPE_DP_DUAL_MODE & DEVICE_TYPE_DP_DUAL_MODE_BITS)) + return false; + +- if (child->dvo_port == port_mapping[port].dp) ++ if (dvo_port_type(child->dvo_port) == DVO_PORT_DPA) + return true; + + /* Only accept a HDMI dvo_port as DP++ if it has an AUX channel */ +- if (child->dvo_port == port_mapping[port].hdmi && ++ if (dvo_port_type(child->dvo_port) == DVO_PORT_HDMIA && + child->aux_channel != 0) + return true; + +@@ -2660,10 +2675,36 @@ static bool child_dev_is_dp_dual_mode(co + bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *i915, + enum port port) + { ++ static const struct { ++ u16 dp, hdmi; ++ } port_mapping[] = { ++ /* ++ * Buggy VBTs may declare DP ports as having ++ * HDMI type dvo_port :( So let's check both. ++ */ ++ [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, }, ++ [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, }, ++ [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, }, ++ [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, }, ++ [PORT_F] = { DVO_PORT_DPF, DVO_PORT_HDMIF, }, ++ }; + const struct intel_bios_encoder_data *devdata; + ++ if (HAS_DDI(i915)) { ++ const struct intel_bios_encoder_data *devdata; ++ ++ devdata = intel_bios_encoder_data_lookup(i915, port); ++ ++ return devdata && child_dev_is_dp_dual_mode(&devdata->child); ++ } ++ ++ if (port == PORT_A || port >= ARRAY_SIZE(port_mapping)) ++ return false; ++ + list_for_each_entry(devdata, &i915->vbt.display_devices, node) { +- if (child_dev_is_dp_dual_mode(&devdata->child, port)) ++ if ((devdata->child.dvo_port == port_mapping[port].dp || ++ devdata->child.dvo_port == port_mapping[port].hdmi) && ++ child_dev_is_dp_dual_mode(&devdata->child)) + return true; + } + diff --git a/queue-5.15/drm-nouveau-add-a-dedicated-mutex-for-the-clients-list.patch b/queue-5.15/drm-nouveau-add-a-dedicated-mutex-for-the-clients-list.patch new file mode 100644 index 00000000000..44be44920c6 --- /dev/null +++ b/queue-5.15/drm-nouveau-add-a-dedicated-mutex-for-the-clients-list.patch @@ -0,0 +1,86 @@ +From abae9164a421bc4a41a3769f01ebcd1f9d955e0e Mon Sep 17 00:00:00 2001 +From: Jeremy Cline +Date: Wed, 25 Nov 2020 15:26:47 -0500 +Subject: drm/nouveau: Add a dedicated mutex for the clients list + +From: Jeremy Cline + +commit abae9164a421bc4a41a3769f01ebcd1f9d955e0e upstream. + +Rather than protecting the nouveau_drm clients list with the lock within +the "client" nouveau_cli, add a dedicated lock to serialize access to +the list. This is both clearer and necessary to avoid lockdep being +upset with us when we need to iterate through all the clients in the +list and potentially lock their mutex, which is the same class as the +lock protecting the entire list. + +Cc: stable@vger.kernel.org # 5.4+ +Signed-off-by: Jeremy Cline +Reviewed-by: Lyude Paul +Reviewed-by: Ben Skeggs +Tested-by: Karol Herbst +Signed-off-by: Karol Herbst +Link: https://patchwork.freedesktop.org/patch/msgid/20201125202648.5220-3-jcline@redhat.com +Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/14 +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 10 ++++++---- + drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++++ + 2 files changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -562,6 +562,7 @@ nouveau_drm_device_init(struct drm_devic + nvkm_dbgopt(nouveau_debug, "DRM"); + + INIT_LIST_HEAD(&drm->clients); ++ mutex_init(&drm->clients_lock); + spin_lock_init(&drm->tile.lock); + + /* workaround an odd issue on nvc1 by disabling the device's +@@ -659,6 +660,7 @@ nouveau_drm_device_fini(struct drm_devic + nouveau_cli_fini(&drm->client); + nouveau_cli_fini(&drm->master); + nvif_parent_dtor(&drm->parent); ++ mutex_destroy(&drm->clients_lock); + kfree(drm); + } + +@@ -1090,9 +1092,9 @@ nouveau_drm_open(struct drm_device *dev, + + fpriv->driver_priv = cli; + +- mutex_lock(&drm->client.mutex); ++ mutex_lock(&drm->clients_lock); + list_add(&cli->head, &drm->clients); +- mutex_unlock(&drm->client.mutex); ++ mutex_unlock(&drm->clients_lock); + + done: + if (ret && cli) { +@@ -1118,9 +1120,9 @@ nouveau_drm_postclose(struct drm_device + nouveau_abi16_fini(cli->abi16); + mutex_unlock(&cli->mutex); + +- mutex_lock(&drm->client.mutex); ++ mutex_lock(&drm->clients_lock); + list_del(&cli->head); +- mutex_unlock(&drm->client.mutex); ++ mutex_unlock(&drm->clients_lock); + + nouveau_cli_fini(cli); + kfree(cli); +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -139,6 +139,11 @@ struct nouveau_drm { + + struct list_head clients; + ++ /** ++ * @clients_lock: Protects access to the @clients list of &struct nouveau_cli. ++ */ ++ struct mutex clients_lock; ++ + u8 old_pm_cap; + + struct { diff --git a/queue-5.15/drm-nouveau-clean-up-all-clients-on-device-removal.patch b/queue-5.15/drm-nouveau-clean-up-all-clients-on-device-removal.patch new file mode 100644 index 00000000000..67cea32b8c4 --- /dev/null +++ b/queue-5.15/drm-nouveau-clean-up-all-clients-on-device-removal.patch @@ -0,0 +1,108 @@ +From f55aaf63bde0d0336c3823bb3713bd4a464abbcf Mon Sep 17 00:00:00 2001 +From: Jeremy Cline +Date: Wed, 25 Nov 2020 15:26:48 -0500 +Subject: drm/nouveau: clean up all clients on device removal + +From: Jeremy Cline + +commit f55aaf63bde0d0336c3823bb3713bd4a464abbcf upstream. + +The postclose handler can run after the device has been removed (or the +driver has been unbound) since userspace clients are free to hold the +file open as long as they want. Because the device removal callback +frees the entire nouveau_drm structure, any reference to it in the +postclose handler will result in a use-after-free. + +To reproduce this, one must simply open the device file, unbind the +driver (or physically remove the device), and then close the device +file. This was found and can be reproduced easily with the IGT +core_hotunplug tests. + +To avoid this, all clients are cleaned up in the device finalization +rather than deferring it to the postclose handler, and the postclose +handler is protected by a critical section which ensures the +drm_dev_unplug() and the postclose handler won't race. + +This is not an ideal fix, since as I understand the proposed plan for +the kernel<->userspace interface for hotplug support, destroying the +client before the file is closed will cause problems. However, I believe +to properly fix this issue, the lifetime of the nouveau_drm structure +needs to be extended to match the drm_device, and this proved to be a +rather invasive change. Thus, I've broken this out so the fix can be +easily backported. + +This fixes with the two previous commits CVE-2020-27820 (Karol). + +Cc: stable@vger.kernel.org # 5.4+ +Signed-off-by: Jeremy Cline +Reviewed-by: Lyude Paul +Reviewed-by: Ben Skeggs +Tested-by: Karol Herbst +Signed-off-by: Karol Herbst +Link: https://patchwork.freedesktop.org/patch/msgid/20201125202648.5220-4-jcline@redhat.com +Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/14 +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -633,6 +633,7 @@ fail_alloc: + static void + nouveau_drm_device_fini(struct drm_device *dev) + { ++ struct nouveau_cli *cli, *temp_cli; + struct nouveau_drm *drm = nouveau_drm(dev); + + if (nouveau_pmops_runtime()) { +@@ -657,6 +658,24 @@ nouveau_drm_device_fini(struct drm_devic + nouveau_ttm_fini(drm); + nouveau_vga_fini(drm); + ++ /* ++ * There may be existing clients from as-yet unclosed files. For now, ++ * clean them up here rather than deferring until the file is closed, ++ * but this likely not correct if we want to support hot-unplugging ++ * properly. ++ */ ++ mutex_lock(&drm->clients_lock); ++ list_for_each_entry_safe(cli, temp_cli, &drm->clients, head) { ++ list_del(&cli->head); ++ mutex_lock(&cli->mutex); ++ if (cli->abi16) ++ nouveau_abi16_fini(cli->abi16); ++ mutex_unlock(&cli->mutex); ++ nouveau_cli_fini(cli); ++ kfree(cli); ++ } ++ mutex_unlock(&drm->clients_lock); ++ + nouveau_cli_fini(&drm->client); + nouveau_cli_fini(&drm->master); + nvif_parent_dtor(&drm->parent); +@@ -1112,6 +1131,16 @@ nouveau_drm_postclose(struct drm_device + { + struct nouveau_cli *cli = nouveau_cli(fpriv); + struct nouveau_drm *drm = nouveau_drm(dev); ++ int dev_index; ++ ++ /* ++ * The device is gone, and as it currently stands all clients are ++ * cleaned up in the removal codepath. In the future this may change ++ * so that we can support hot-unplugging, but for now we immediately ++ * return to avoid a double-free situation. ++ */ ++ if (!drm_dev_enter(dev, &dev_index)) ++ return; + + pm_runtime_get_sync(dev->dev); + +@@ -1128,6 +1157,7 @@ nouveau_drm_postclose(struct drm_device + kfree(cli); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); ++ drm_dev_exit(dev_index); + } + + static const struct drm_ioctl_desc diff --git a/queue-5.15/drm-nouveau-use-drm_dev_unplug-during-device-removal.patch b/queue-5.15/drm-nouveau-use-drm_dev_unplug-during-device-removal.patch new file mode 100644 index 00000000000..469e4b7333a --- /dev/null +++ b/queue-5.15/drm-nouveau-use-drm_dev_unplug-during-device-removal.patch @@ -0,0 +1,46 @@ +From aff2299e0d81b26304ccc6a1ec0170e437f38efc Mon Sep 17 00:00:00 2001 +From: Jeremy Cline +Date: Wed, 25 Nov 2020 15:26:46 -0500 +Subject: drm/nouveau: use drm_dev_unplug() during device removal + +From: Jeremy Cline + +commit aff2299e0d81b26304ccc6a1ec0170e437f38efc upstream. + +Nouveau does not currently support hot-unplugging, but it still makes +sense to switch from drm_dev_unregister() to drm_dev_unplug(). +drm_dev_unplug() calls drm_dev_unregister() after marking the device as +unplugged, but only after any device critical sections are finished. + +Since nouveau isn't using drm_dev_enter() and drm_dev_exit(), there are +no critical sections so this is nearly functionally equivalent. However, +the DRM layer does check to see if the device is unplugged, and if it is +returns appropriate error codes. + +In the future nouveau can add critical sections in order to truly +support hot-unplugging. + +Cc: stable@vger.kernel.org # 5.4+ +Signed-off-by: Jeremy Cline +Reviewed-by: Lyude Paul +Reviewed-by: Ben Skeggs +Tested-by: Karol Herbst +Signed-off-by: Karol Herbst +Link: https://patchwork.freedesktop.org/patch/msgid/20201125202648.5220-2-jcline@redhat.com +Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/14 +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -798,7 +798,7 @@ nouveau_drm_device_remove(struct drm_dev + struct nvkm_client *client; + struct nvkm_device *device; + +- drm_dev_unregister(dev); ++ drm_dev_unplug(dev); + + client = nvxx_client(&drm->client.base); + device = nvkm_device_find(client->device); diff --git a/queue-5.15/drm-prime-fix-use-after-free-in-mmap-with-drm_gem_ttm_mmap.patch b/queue-5.15/drm-prime-fix-use-after-free-in-mmap-with-drm_gem_ttm_mmap.patch new file mode 100644 index 00000000000..21fd42f245b --- /dev/null +++ b/queue-5.15/drm-prime-fix-use-after-free-in-mmap-with-drm_gem_ttm_mmap.patch @@ -0,0 +1,58 @@ +From 8244a3bc27b3efd057da154b8d7e414670d5044f Mon Sep 17 00:00:00 2001 +From: Anand K Mistry +Date: Thu, 30 Sep 2021 09:00:07 +1000 +Subject: drm/prime: Fix use after free in mmap with drm_gem_ttm_mmap + +From: Anand K Mistry + +commit 8244a3bc27b3efd057da154b8d7e414670d5044f upstream. + +drm_gem_ttm_mmap() drops a reference to the gem object on success. If +the gem object's refcount == 1 on entry to drm_gem_prime_mmap(), that +drop will free the gem object, and the subsequent drm_gem_object_get() +will be a UAF. Fix by grabbing a reference before calling the mmap +helper. + +This issue was forseen when the reference dropping was adding in +commit 9786b65bc61ac ("drm/ttm: fix mmap refcounting"): + "For that to work properly the drm_gem_object_get() call in + drm_gem_ttm_mmap() must be moved so it happens before calling + obj->funcs->mmap(), otherwise the gem refcount would go down + to zero." + +Signed-off-by: Anand K Mistry +Fixes: 9786b65bc61a ("drm/ttm: fix mmap refcounting") +Cc: Gerd Hoffmann +Cc: Daniel Vetter +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Thomas Zimmermann +Cc: David Airlie +Cc: Daniel Vetter +Cc: dri-devel@lists.freedesktop.org +Cc: # v5.5+ +Signed-off-by: Thomas Zimmermann +Link: https://patchwork.freedesktop.org/patch/msgid/20210930085932.1.I8043d61cc238e0168e2f4ca5f4783223434aa587@changeid +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/drm_prime.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -719,11 +719,13 @@ int drm_gem_prime_mmap(struct drm_gem_ob + if (obj->funcs && obj->funcs->mmap) { + vma->vm_ops = obj->funcs->vm_ops; + ++ drm_gem_object_get(obj); + ret = obj->funcs->mmap(obj, vma); +- if (ret) ++ if (ret) { ++ drm_gem_object_put(obj); + return ret; ++ } + vma->vm_private_data = obj; +- drm_gem_object_get(obj); + return 0; + } + diff --git a/queue-5.15/series b/queue-5.15/series index bd442535a46..654c0a7393d 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -245,3 +245,12 @@ drm-i915-guc-workaround-reset-g2h-is-received-after-schedule-done-g2h.patch drm-i915-guc-don-t-drop-ce-guc_active.lock-when-unwinding-context.patch drm-i915-guc-unwind-context-requests-in-reverse-order.patch drm-udl-fix-control-message-timeout.patch +drm-prime-fix-use-after-free-in-mmap-with-drm_gem_ttm_mmap.patch +drm-nouveau-add-a-dedicated-mutex-for-the-clients-list.patch +drm-nouveau-use-drm_dev_unplug-during-device-removal.patch +drm-nouveau-clean-up-all-clients-on-device-removal.patch +drm-i915-dp-ensure-sink-rate-values-are-always-valid.patch +drm-i915-dp-ensure-max-link-params-are-always-valid.patch +drm-i915-fix-type1-dvi-dp-dual-mode-adapter-heuristic-for-modern-platforms.patch +drm-amdgpu-fix-set-scaling-mode-full-full-aspect-center-not-works-on-vga-and-dvi-connectors.patch +drm-amd-pm-avoid-duplicate-powergate-ungate-setting.patch