--- /dev/null
+From 7a46f05e5e163c00e41892e671294286e53fe15c Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 3 Feb 2021 13:42:41 +0100
+Subject: drm/amd/display: Add a backlight module option
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 7a46f05e5e163c00e41892e671294286e53fe15c upstream.
+
+There seem devices that don't work with the aux channel backlight
+control. For allowing such users to test with the other backlight
+control method, provide a new module option, aux_backlight, to specify
+enabling or disabling the aux backport support explicitly. As
+default, the aux support is detected by the hardware capability.
+
+v2: make the backlight option generic in case we add future
+backlight types (Alex)
+
+BugLink: https://bugzilla.opensuse.org/show_bug.cgi?id=1180749
+BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1438
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 4 ++++
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +++++
+ 3 files changed, 10 insertions(+)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -178,6 +178,7 @@ extern uint amdgpu_smu_memory_pool_size;
+ extern uint amdgpu_dc_feature_mask;
+ extern uint amdgpu_dc_debug_mask;
+ extern uint amdgpu_dm_abm_level;
++extern int amdgpu_backlight;
+ extern struct amdgpu_mgpu_info mgpu_info;
+ extern int amdgpu_ras_enable;
+ extern uint amdgpu_ras_mask;
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -768,6 +768,10 @@ uint amdgpu_dm_abm_level = 0;
+ MODULE_PARM_DESC(abmlevel, "ABM level (0 = off (default), 1-4 = backlight reduction level) ");
+ module_param_named(abmlevel, amdgpu_dm_abm_level, uint, 0444);
+
++int amdgpu_backlight = -1;
++MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto (default))");
++module_param_named(backlight, amdgpu_backlight, bint, 0444);
++
+ /**
+ * DOC: tmz (int)
+ * Trusted Memory Zone (TMZ) is a method to protect data being written
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -2140,6 +2140,11 @@ static void update_connector_ext_caps(st
+ caps->ext_caps->bits.hdr_aux_backlight_control == 1)
+ caps->aux_support = true;
+
++ if (amdgpu_backlight == 0)
++ caps->aux_support = false;
++ else if (amdgpu_backlight == 1)
++ caps->aux_support = true;
++
+ /* From the specification (CTA-861-G), for calculating the maximum
+ * luminance we need to use:
+ * Luminance = 50*2**(CV/32)
--- /dev/null
+From 15e8b95d5f7509e0b09289be8c422c459c9f0412 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= <holger@applied-asynchrony.com>
+Date: Fri, 5 Mar 2021 12:39:21 +0100
+Subject: drm/amd/display: Fix nested FPU context in dcn21_validate_bandwidth()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Holger Hoffstätte <holger@applied-asynchrony.com>
+
+commit 15e8b95d5f7509e0b09289be8c422c459c9f0412 upstream.
+
+Commit 41401ac67791 added FPU wrappers to dcn21_validate_bandwidth(),
+which was correct. Unfortunately a nested function alredy contained
+DC_FP_START()/DC_FP_END() calls, which results in nested FPU context
+enter/exit and complaints by kernel_fpu_begin_mask().
+This can be observed e.g. with 5.10.20, which backported 41401ac67791
+and now emits the following warning on boot:
+
+WARNING: CPU: 6 PID: 858 at arch/x86/kernel/fpu/core.c:129 kernel_fpu_begin_mask+0xa5/0xc0
+Call Trace:
+ dcn21_calculate_wm+0x47/0xa90 [amdgpu]
+ dcn21_validate_bandwidth_fp+0x15d/0x2b0 [amdgpu]
+ dcn21_validate_bandwidth+0x29/0x40 [amdgpu]
+ dc_validate_global_state+0x3c7/0x4c0 [amdgpu]
+
+The warning is emitted due to the additional DC_FP_START/END calls in
+patch_bounding_box(), which is inlined into dcn21_calculate_wm(),
+its only caller. Removing the calls brings the code in line with
+dcn20 and makes the warning disappear.
+
+Fixes: 41401ac67791 ("drm/amd/display: Add FPU wrappers to dcn21_validate_bandwidth()")
+Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+@@ -1058,8 +1058,6 @@ static void patch_bounding_box(struct dc
+ {
+ int i;
+
+- DC_FP_START();
+-
+ if (dc->bb_overrides.sr_exit_time_ns) {
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ dc->clk_mgr->bw_params->wm_table.entries[i].sr_exit_time_us =
+@@ -1084,8 +1082,6 @@ static void patch_bounding_box(struct dc
+ dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+ }
+ }
+-
+- DC_FP_END();
+ }
+
+ void dcn21_calculate_wm(
--- /dev/null
+From 50ceb1fe7acd50831180f4b5597bf7b39e8059c8 Mon Sep 17 00:00:00 2001
+From: Kenneth Feng <kenneth.feng@amd.com>
+Date: Tue, 9 Mar 2021 21:10:16 +0800
+Subject: drm/amd/pm: bug fix for pcie dpm
+
+From: Kenneth Feng <kenneth.feng@amd.com>
+
+commit 50ceb1fe7acd50831180f4b5597bf7b39e8059c8 upstream.
+
+Currently the pcie dpm has two problems.
+1. Only the high dpm level speed/width can be overrided
+if the requested values are out of the pcie capability.
+2. The high dpm level is always overrided though sometimes
+it's not necesarry.
+
+Signed-off-by: Kenneth Feng <kenneth.feng@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c | 48 +++++++++++++
+ drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c | 66 ++++++++++++++++++
+ drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c | 48 +++++++------
+ 3 files changed, 141 insertions(+), 21 deletions(-)
+
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+@@ -1506,6 +1506,48 @@ static int vega10_populate_single_lclk_l
+ return 0;
+ }
+
++static int vega10_override_pcie_parameters(struct pp_hwmgr *hwmgr)
++{
++ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
++ struct vega10_hwmgr *data =
++ (struct vega10_hwmgr *)(hwmgr->backend);
++ uint32_t pcie_gen = 0, pcie_width = 0;
++ PPTable_t *pp_table = &(data->smc_state_table.pp_table);
++ int i;
++
++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
++ pcie_gen = 3;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
++ pcie_gen = 2;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
++ pcie_gen = 1;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
++ pcie_gen = 0;
++
++ if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
++ pcie_width = 6;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
++ pcie_width = 5;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
++ pcie_width = 4;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
++ pcie_width = 3;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
++ pcie_width = 2;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
++ pcie_width = 1;
++
++ for (i = 0; i < NUM_LINK_LEVELS; i++) {
++ if (pp_table->PcieGenSpeed[i] > pcie_gen)
++ pp_table->PcieGenSpeed[i] = pcie_gen;
++
++ if (pp_table->PcieLaneCount[i] > pcie_width)
++ pp_table->PcieLaneCount[i] = pcie_width;
++ }
++
++ return 0;
++}
++
+ static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
+ {
+ int result = -1;
+@@ -2557,6 +2599,11 @@ static int vega10_init_smc_table(struct
+ "Failed to initialize Link Level!",
+ return result);
+
++ result = vega10_override_pcie_parameters(hwmgr);
++ PP_ASSERT_WITH_CODE(!result,
++ "Failed to override pcie parameters!",
++ return result);
++
+ result = vega10_populate_all_graphic_levels(hwmgr);
+ PP_ASSERT_WITH_CODE(!result,
+ "Failed to initialize Graphics Level!",
+@@ -2923,6 +2970,7 @@ static int vega10_start_dpm(struct pp_hw
+ return 0;
+ }
+
++
+ static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable)
+ {
+ struct vega10_hwmgr *data = hwmgr->backend;
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+@@ -481,6 +481,67 @@ static void vega12_init_dpm_state(struct
+ dpm_state->hard_max_level = 0xffff;
+ }
+
++static int vega12_override_pcie_parameters(struct pp_hwmgr *hwmgr)
++{
++ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
++ struct vega12_hwmgr *data =
++ (struct vega12_hwmgr *)(hwmgr->backend);
++ uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
++ PPTable_t *pp_table = &(data->smc_state_table.pp_table);
++ int i;
++ int ret;
++
++ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
++ pcie_gen = 3;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
++ pcie_gen = 2;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
++ pcie_gen = 1;
++ else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
++ pcie_gen = 0;
++
++ if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
++ pcie_width = 6;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
++ pcie_width = 5;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
++ pcie_width = 4;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
++ pcie_width = 3;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
++ pcie_width = 2;
++ else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
++ pcie_width = 1;
++
++ /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
++ * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
++ * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32
++ */
++ for (i = 0; i < NUM_LINK_LEVELS; i++) {
++ pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
++ pp_table->PcieGenSpeed[i];
++ pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
++ pp_table->PcieLaneCount[i];
++
++ if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
++ pp_table->PcieLaneCount[i]) {
++ smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
++ ret = smum_send_msg_to_smc_with_parameter(hwmgr,
++ PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
++ NULL);
++ PP_ASSERT_WITH_CODE(!ret,
++ "[OverridePcieParameters] Attempt to override pcie params failed!",
++ return ret);
++ }
++
++ /* update the pptable */
++ pp_table->PcieGenSpeed[i] = pcie_gen_arg;
++ pp_table->PcieLaneCount[i] = pcie_width_arg;
++ }
++
++ return 0;
++}
++
+ static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
+ PPCLK_e clk_id, uint32_t *num_of_levels)
+ {
+@@ -969,6 +1030,11 @@ static int vega12_enable_dpm_tasks(struc
+ "Failed to enable all smu features!",
+ return result);
+
++ result = vega12_override_pcie_parameters(hwmgr);
++ PP_ASSERT_WITH_CODE(!result,
++ "[EnableDPMTasks] Failed to override pcie parameters!",
++ return result);
++
+ tmp_result = vega12_power_control_set_level(hwmgr);
+ PP_ASSERT_WITH_CODE(!tmp_result,
+ "Failed to power control set level!",
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+@@ -832,7 +832,9 @@ static int vega20_override_pcie_paramete
+ struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ struct vega20_hwmgr *data =
+ (struct vega20_hwmgr *)(hwmgr->backend);
+- uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg;
++ uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
++ PPTable_t *pp_table = &(data->smc_state_table.pp_table);
++ int i;
+ int ret;
+
+ if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
+@@ -861,17 +863,27 @@ static int vega20_override_pcie_paramete
+ * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
+ * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32
+ */
+- smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width;
+- ret = smum_send_msg_to_smc_with_parameter(hwmgr,
+- PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
+- NULL);
+- PP_ASSERT_WITH_CODE(!ret,
+- "[OverridePcieParameters] Attempt to override pcie params failed!",
+- return ret);
++ for (i = 0; i < NUM_LINK_LEVELS; i++) {
++ pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
++ pp_table->PcieGenSpeed[i];
++ pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
++ pp_table->PcieLaneCount[i];
++
++ if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
++ pp_table->PcieLaneCount[i]) {
++ smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
++ ret = smum_send_msg_to_smc_with_parameter(hwmgr,
++ PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
++ NULL);
++ PP_ASSERT_WITH_CODE(!ret,
++ "[OverridePcieParameters] Attempt to override pcie params failed!",
++ return ret);
++ }
+
+- data->pcie_parameters_override = true;
+- data->pcie_gen_level1 = pcie_gen;
+- data->pcie_width_level1 = pcie_width;
++ /* update the pptable */
++ pp_table->PcieGenSpeed[i] = pcie_gen_arg;
++ pp_table->PcieLaneCount[i] = pcie_width_arg;
++ }
+
+ return 0;
+ }
+@@ -3320,9 +3332,7 @@ static int vega20_print_clock_levels(str
+ data->od8_settings.od8_settings_array;
+ OverDriveTable_t *od_table =
+ &(data->smc_state_table.overdrive_table);
+- struct phm_ppt_v3_information *pptable_information =
+- (struct phm_ppt_v3_information *)hwmgr->pptable;
+- PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
++ PPTable_t *pptable = &(data->smc_state_table.pp_table);
+ struct pp_clock_levels_with_latency clocks;
+ struct vega20_single_dpm_table *fclk_dpm_table =
+ &(data->dpm_table.fclk_table);
+@@ -3421,13 +3431,9 @@ static int vega20_print_clock_levels(str
+ current_lane_width =
+ vega20_get_current_pcie_link_width_level(hwmgr);
+ for (i = 0; i < NUM_LINK_LEVELS; i++) {
+- if (i == 1 && data->pcie_parameters_override) {
+- gen_speed = data->pcie_gen_level1;
+- lane_width = data->pcie_width_level1;
+- } else {
+- gen_speed = pptable->PcieGenSpeed[i];
+- lane_width = pptable->PcieLaneCount[i];
+- }
++ gen_speed = pptable->PcieGenSpeed[i];
++ lane_width = pptable->PcieLaneCount[i];
++
+ size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
+ (gen_speed == 0) ? "2.5GT/s," :
+ (gen_speed == 1) ? "5.0GT/s," :
--- /dev/null
+From dfd8b7fbd985ec1cf76fe10f2875a50b10833740 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexander.deucher@amd.com>
+Date: Thu, 10 Dec 2020 01:20:08 -0500
+Subject: drm/amdgpu/display: don't assert in set backlight function
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+commit dfd8b7fbd985ec1cf76fe10f2875a50b10833740 upstream.
+
+It just spams the logs.
+
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+@@ -2555,7 +2555,6 @@ bool dc_link_set_backlight_level(const s
+ if (pipe_ctx->plane_state == NULL)
+ frame_ramp = 0;
+ } else {
+- ASSERT(false);
+ return false;
+ }
+
--- /dev/null
+From 0ad3e64eb46d8c47de3af552e282894e3893e973 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexander.deucher@amd.com>
+Date: Thu, 10 Dec 2020 01:45:12 -0500
+Subject: drm/amdgpu/display: handle aux backlight in backlight_get_brightness
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+commit 0ad3e64eb46d8c47de3af552e282894e3893e973 upstream.
+
+Need to fetch it via aux.
+
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 ++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -3116,11 +3116,27 @@ static int amdgpu_dm_backlight_update_st
+ static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
+ {
+ struct amdgpu_display_manager *dm = bl_get_data(bd);
+- int ret = dc_link_get_backlight_level(dm->backlight_link);
++ struct amdgpu_dm_backlight_caps caps;
+
+- if (ret == DC_ERROR_UNEXPECTED)
+- return bd->props.brightness;
+- return convert_brightness_to_user(&dm->backlight_caps, ret);
++ amdgpu_dm_update_backlight_caps(dm);
++ caps = dm->backlight_caps;
++
++ if (caps.aux_support) {
++ struct dc_link *link = (struct dc_link *)dm->backlight_link;
++ u32 avg, peak;
++ bool rc;
++
++ rc = dc_link_get_backlight_level_nits(link, &avg, &peak);
++ if (!rc)
++ return bd->props.brightness;
++ return convert_brightness_to_user(&caps, avg);
++ } else {
++ int ret = dc_link_get_backlight_level(dm->backlight_link);
++
++ if (ret == DC_ERROR_UNEXPECTED)
++ return bd->props.brightness;
++ return convert_brightness_to_user(&caps, ret);
++ }
+ }
+
+ static const struct backlight_ops amdgpu_dm_backlight_ops = {
--- /dev/null
+From a2f8d988698d7d3645b045f4940415b045140b81 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexander.deucher@amd.com>
+Date: Thu, 10 Dec 2020 01:18:40 -0500
+Subject: drm/amdgpu/display: simplify backlight setting
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+commit a2f8d988698d7d3645b045f4940415b045140b81 upstream.
+
+Avoid the extra wrapper function.
+
+Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 20 ++++----------------
+ 1 file changed, 4 insertions(+), 16 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -3043,19 +3043,6 @@ static void amdgpu_dm_update_backlight_c
+ #endif
+ }
+
+-static int set_backlight_via_aux(struct dc_link *link, uint32_t brightness)
+-{
+- bool rc;
+-
+- if (!link)
+- return 1;
+-
+- rc = dc_link_set_backlight_level_nits(link, true, brightness,
+- AUX_BL_DEFAULT_TRANSITION_TIME_MS);
+-
+- return rc ? 0 : 1;
+-}
+-
+ static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
+ unsigned *min, unsigned *max)
+ {
+@@ -3118,9 +3105,10 @@ static int amdgpu_dm_backlight_update_st
+ brightness = convert_brightness_from_user(&caps, bd->props.brightness);
+ // Change brightness based on AUX property
+ if (caps.aux_support)
+- return set_backlight_via_aux(link, brightness);
+-
+- rc = dc_link_set_backlight_level(dm->backlight_link, brightness, 0);
++ rc = dc_link_set_backlight_level_nits(link, true, brightness,
++ AUX_BL_DEFAULT_TRANSITION_TIME_MS);
++ else
++ rc = dc_link_set_backlight_level(dm->backlight_link, brightness, 0);
+
+ return rc ? 0 : 1;
+ }
--- /dev/null
+From 680174cfd1e1cea70a8f30ccb44d8fbdf996018e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= <holger@applied-asynchrony.com>
+Date: Fri, 5 Mar 2021 15:23:18 +0100
+Subject: drm/amdgpu/display: use GFP_ATOMIC in dcn21_validate_bandwidth_fp()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Holger Hoffstätte <holger@applied-asynchrony.com>
+
+commit 680174cfd1e1cea70a8f30ccb44d8fbdf996018e upstream.
+
+After fixing nested FPU contexts caused by 41401ac67791 we're still seeing
+complaints about spurious kernel_fpu_end(). As it turns out this was
+already fixed for dcn20 in commit f41ed88cbd ("drm/amdgpu/display:
+use GFP_ATOMIC in dcn20_validate_bandwidth_internal") but never moved
+forward to dcn21.
+
+Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+@@ -1183,7 +1183,7 @@ static noinline bool dcn21_validate_band
+ int vlevel = 0;
+ int pipe_split_from[MAX_PIPES];
+ int pipe_cnt = 0;
+- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
++ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
+ DC_LOGGER_INIT(dc->ctx->logger);
+
+ BW_VAL_TRACE_COUNT();
--- /dev/null
+From de066e116306baf3a6a62691ac63cfc0b1dabddb Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Mon, 22 Feb 2021 11:06:43 +0100
+Subject: drm/compat: Clear bounce structures
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit de066e116306baf3a6a62691ac63cfc0b1dabddb upstream.
+
+Some of them have gaps, or fields we don't clear. Native ioctl code
+does full copies plus zero-extends on size mismatch, so nothing can
+leak. But compat is more hand-rolled so need to be careful.
+
+None of these matter for performance, so just memset.
+
+Also I didn't fix up the CONFIG_DRM_LEGACY or CONFIG_DRM_AGP ioctl, those
+are security holes anyway.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Reported-by: syzbot+620cf21140fc7e772a5d@syzkaller.appspotmail.com # vblank ioctl
+Cc: syzbot+620cf21140fc7e772a5d@syzkaller.appspotmail.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210222100643.400935-1-daniel.vetter@ffwll.ch
+(cherry picked from commit e926c474ebee404441c838d18224cd6f246a71b7)
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_ioc32.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/gpu/drm/drm_ioc32.c
++++ b/drivers/gpu/drm/drm_ioc32.c
+@@ -99,6 +99,8 @@ static int compat_drm_version(struct fil
+ if (copy_from_user(&v32, (void __user *)arg, sizeof(v32)))
+ return -EFAULT;
+
++ memset(&v, 0, sizeof(v));
++
+ v = (struct drm_version) {
+ .name_len = v32.name_len,
+ .name = compat_ptr(v32.name),
+@@ -137,6 +139,9 @@ static int compat_drm_getunique(struct f
+
+ if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
+ return -EFAULT;
++
++ memset(&uq, 0, sizeof(uq));
++
+ uq = (struct drm_unique){
+ .unique_len = uq32.unique_len,
+ .unique = compat_ptr(uq32.unique),
+@@ -265,6 +270,8 @@ static int compat_drm_getclient(struct f
+ if (copy_from_user(&c32, argp, sizeof(c32)))
+ return -EFAULT;
+
++ memset(&client, 0, sizeof(client));
++
+ client.idx = c32.idx;
+
+ err = drm_ioctl_kernel(file, drm_getclient, &client, 0);
+@@ -852,6 +859,8 @@ static int compat_drm_wait_vblank(struct
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
++ memset(&req, 0, sizeof(req));
++
+ req.request.type = req32.request.type;
+ req.request.sequence = req32.request.sequence;
+ req.request.signal = req32.request.signal;
+@@ -889,6 +898,8 @@ static int compat_drm_mode_addfb2(struct
+ struct drm_mode_fb_cmd2 req64;
+ int err;
+
++ memset(&req64, 0, sizeof(req64));
++
+ if (copy_from_user(&req64, argp,
+ offsetof(drm_mode_fb_cmd232_t, modifier)))
+ return -EFAULT;
--- /dev/null
+From d611b4a0907cece060699f2fd347c492451cd2aa Mon Sep 17 00:00:00 2001
+From: Neil Roberts <nroberts@igalia.com>
+Date: Tue, 23 Feb 2021 16:51:24 +0100
+Subject: drm/shmem-helper: Check for purged buffers in fault handler
+
+From: Neil Roberts <nroberts@igalia.com>
+
+commit d611b4a0907cece060699f2fd347c492451cd2aa upstream.
+
+When a buffer is madvised as not needed and then purged, any attempts to
+access the buffer from user-space should cause a bus fault. This patch
+adds a check for that.
+
+Cc: stable@vger.kernel.org
+Fixes: 17acb9f35ed7 ("drm/shmem: Add madvise state and purge helpers")
+Signed-off-by: Neil Roberts <nroberts@igalia.com>
+Reviewed-by: Steven Price <steven.price@arm.com>
+Signed-off-by: Steven Price <steven.price@arm.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210223155125.199577-2-nroberts@igalia.com
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_gem_shmem_helper.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
++++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
+@@ -534,14 +534,24 @@ static vm_fault_t drm_gem_shmem_fault(st
+ struct drm_gem_object *obj = vma->vm_private_data;
+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+ loff_t num_pages = obj->size >> PAGE_SHIFT;
++ vm_fault_t ret;
+ struct page *page;
+
+- if (vmf->pgoff >= num_pages || WARN_ON_ONCE(!shmem->pages))
+- return VM_FAULT_SIGBUS;
++ mutex_lock(&shmem->pages_lock);
+
+- page = shmem->pages[vmf->pgoff];
++ if (vmf->pgoff >= num_pages ||
++ WARN_ON_ONCE(!shmem->pages) ||
++ shmem->madv < 0) {
++ ret = VM_FAULT_SIGBUS;
++ } else {
++ page = shmem->pages[vmf->pgoff];
+
+- return vmf_insert_page(vma, vmf->address, page);
++ ret = vmf_insert_page(vma, vmf->address, page);
++ }
++
++ mutex_unlock(&shmem->pages_lock);
++
++ return ret;
+ }
+
+ static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
--- /dev/null
+From 11d5a4745e00e73745774671dbf2fb07bd6e2363 Mon Sep 17 00:00:00 2001
+From: Neil Roberts <nroberts@igalia.com>
+Date: Tue, 23 Feb 2021 16:51:25 +0100
+Subject: drm/shmem-helper: Don't remove the offset in vm_area_struct pgoff
+
+From: Neil Roberts <nroberts@igalia.com>
+
+commit 11d5a4745e00e73745774671dbf2fb07bd6e2363 upstream.
+
+When mmapping the shmem, it would previously adjust the pgoff in the
+vm_area_struct to remove the fake offset that is added to be able to
+identify the buffer. This patch removes the adjustment and makes the
+fault handler use the vm_fault address to calculate the page offset
+instead. Although using this address is apparently discouraged, several
+DRM drivers seem to be doing it anyway.
+
+The problem with removing the pgoff is that it prevents
+drm_vma_node_unmap from working because that searches the mapping tree
+by address. That doesn't work because all of the mappings are at offset
+0. drm_vma_node_unmap is being used by the shmem helpers when purging
+the buffer.
+
+This fixes a bug in Panfrost which is using drm_gem_shmem_purge. Without
+this the mapping for the purged buffer can still be accessed which might
+mean it would access random pages from other buffers
+
+v2: Don't check whether the unsigned page_offset is less than 0.
+
+Cc: stable@vger.kernel.org
+Fixes: 17acb9f35ed7 ("drm/shmem: Add madvise state and purge helpers")
+Signed-off-by: Neil Roberts <nroberts@igalia.com>
+Reviewed-by: Steven Price <steven.price@arm.com>
+Signed-off-by: Steven Price <steven.price@arm.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210223155125.199577-3-nroberts@igalia.com
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_gem_shmem_helper.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
++++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
+@@ -536,15 +536,19 @@ static vm_fault_t drm_gem_shmem_fault(st
+ loff_t num_pages = obj->size >> PAGE_SHIFT;
+ vm_fault_t ret;
+ struct page *page;
++ pgoff_t page_offset;
++
++ /* We don't use vmf->pgoff since that has the fake offset */
++ page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+
+ mutex_lock(&shmem->pages_lock);
+
+- if (vmf->pgoff >= num_pages ||
++ if (page_offset >= num_pages ||
+ WARN_ON_ONCE(!shmem->pages) ||
+ shmem->madv < 0) {
+ ret = VM_FAULT_SIGBUS;
+ } else {
+- page = shmem->pages[vmf->pgoff];
++ page = shmem->pages[page_offset];
+
+ ret = vmf_insert_page(vma, vmf->address, page);
+ }
+@@ -600,9 +604,6 @@ int drm_gem_shmem_mmap(struct drm_gem_ob
+ struct drm_gem_shmem_object *shmem;
+ int ret;
+
+- /* Remove the fake offset */
+- vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
+-
+ if (obj->import_attach) {
+ /* Drop the reference drm_gem_mmap_obj() acquired.*/
+ drm_gem_object_put(obj);
--- /dev/null
+From 659ab7a49cbebe0deffcbe1f9560e82006b21817 Mon Sep 17 00:00:00 2001
+From: Thomas Zimmermann <tzimmermann@suse.de>
+Date: Wed, 3 Mar 2021 14:32:29 +0100
+Subject: drm: Use USB controller's DMA mask when importing dmabufs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+commit 659ab7a49cbebe0deffcbe1f9560e82006b21817 upstream.
+
+USB devices cannot perform DMA and hence have no dma_mask set in their
+device structure. Therefore importing dmabuf into a USB-based driver
+fails, which breaks joining and mirroring of display in X11.
+
+For USB devices, pick the associated USB controller as attachment device.
+This allows the DRM import helpers to perform the DMA setup. If the DMA
+controller does not support DMA transfers, we're out of luck and cannot
+import. Our current USB-based DRM drivers don't use DMA, so the actual
+DMA device is not important.
+
+Tested by joining/mirroring displays of udl and radeon under Gnome/X11.
+
+v8:
+ * release dmadev if device initialization fails (Noralf)
+ * fix commit description (Noralf)
+v7:
+ * fix use-before-init bug in gm12u320 (Dan)
+v6:
+ * implement workaround in DRM drivers and hold reference to
+ DMA device while USB device is in use
+ * remove dev_is_usb() (Greg)
+ * collapse USB helper into usb_intf_get_dma_device() (Alan)
+ * integrate Daniel's TODO statement (Daniel)
+ * fix typos (Greg)
+v5:
+ * provide a helper for USB interfaces (Alan)
+ * add FIXME item to documentation and TODO list (Daniel)
+v4:
+ * implement workaround with USB helper functions (Greg)
+ * use struct usb_device->bus->sysdev as DMA device (Takashi)
+v3:
+ * drop gem_create_object
+ * use DMA mask of USB controller, if any (Daniel, Christian, Noralf)
+v2:
+ * move fix to importer side (Christian, Daniel)
+ * update SHMEM and CMA helpers for new PRIME callbacks
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Fixes: 6eb0233ec2d0 ("usb: don't inherity DMA properties for USB devices")
+Tested-by: Pavel Machek <pavel@ucw.cz>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Christian König <christian.koenig@amd.com>
+Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Acked-by: Noralf Trønnes <noralf@tronnes.org>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: <stable@vger.kernel.org> # v5.10+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210303133229.3288-1-tzimmermann@suse.de
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/gpu/todo.rst | 21 +++++++++++++++++++
+ drivers/gpu/drm/tiny/gm12u320.c | 44 ++++++++++++++++++++++++++++++++--------
+ drivers/gpu/drm/udl/udl_drv.c | 17 +++++++++++++++
+ drivers/gpu/drm/udl/udl_drv.h | 1
+ drivers/gpu/drm/udl/udl_main.c | 10 +++++++++
+ drivers/usb/core/usb.c | 32 +++++++++++++++++++++++++++++
+ include/linux/usb.h | 2 +
+ 7 files changed, 119 insertions(+), 8 deletions(-)
+
+--- a/Documentation/gpu/todo.rst
++++ b/Documentation/gpu/todo.rst
+@@ -560,6 +560,27 @@ Some of these date from the very introdu
+
+ Level: Intermediate
+
++Remove automatic page mapping from dma-buf importing
++----------------------------------------------------
++
++When importing dma-bufs, the dma-buf and PRIME frameworks automatically map
++imported pages into the importer's DMA area. drm_gem_prime_fd_to_handle() and
++drm_gem_prime_handle_to_fd() require that importers call dma_buf_attach()
++even if they never do actual device DMA, but only CPU access through
++dma_buf_vmap(). This is a problem for USB devices, which do not support DMA
++operations.
++
++To fix the issue, automatic page mappings should be removed from the
++buffer-sharing code. Fixing this is a bit more involved, since the import/export
++cache is also tied to &drm_gem_object.import_attach. Meanwhile we paper over
++this problem for USB devices by fishing out the USB host controller device, as
++long as that supports DMA. Otherwise importing can still needlessly fail.
++
++Contact: Thomas Zimmermann <tzimmermann@suse.de>, Daniel Vetter
++
++Level: Advanced
++
++
+ Better Testing
+ ==============
+
+--- a/drivers/gpu/drm/tiny/gm12u320.c
++++ b/drivers/gpu/drm/tiny/gm12u320.c
+@@ -83,6 +83,7 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco
+
+ struct gm12u320_device {
+ struct drm_device dev;
++ struct device *dmadev;
+ struct drm_simple_display_pipe pipe;
+ struct drm_connector conn;
+ struct usb_device *udev;
+@@ -598,6 +599,22 @@ static const uint64_t gm12u320_pipe_modi
+ DRM_FORMAT_MOD_INVALID
+ };
+
++/*
++ * FIXME: Dma-buf sharing requires DMA support by the importing device.
++ * This function is a workaround to make USB devices work as well.
++ * See todo.rst for how to fix the issue in the dma-buf framework.
++ */
++static struct drm_gem_object *gm12u320_gem_prime_import(struct drm_device *dev,
++ struct dma_buf *dma_buf)
++{
++ struct gm12u320_device *gm12u320 = to_gm12u320(dev);
++
++ if (!gm12u320->dmadev)
++ return ERR_PTR(-ENODEV);
++
++ return drm_gem_prime_import_dev(dev, dma_buf, gm12u320->dmadev);
++}
++
+ DEFINE_DRM_GEM_FOPS(gm12u320_fops);
+
+ static struct drm_driver gm12u320_drm_driver = {
+@@ -611,6 +628,7 @@ static struct drm_driver gm12u320_drm_dr
+
+ .fops = &gm12u320_fops,
+ DRM_GEM_SHMEM_DRIVER_OPS,
++ .gem_prime_import = gm12u320_gem_prime_import,
+ };
+
+ static const struct drm_mode_config_funcs gm12u320_mode_config_funcs = {
+@@ -637,16 +655,19 @@ static int gm12u320_usb_probe(struct usb
+ struct gm12u320_device, dev);
+ if (IS_ERR(gm12u320))
+ return PTR_ERR(gm12u320);
++ dev = &gm12u320->dev;
++
++ gm12u320->dmadev = usb_intf_get_dma_device(to_usb_interface(dev->dev));
++ if (!gm12u320->dmadev)
++ drm_warn(dev, "buffer sharing not supported"); /* not an error */
+
+ gm12u320->udev = interface_to_usbdev(interface);
+ INIT_DELAYED_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
+ mutex_init(&gm12u320->fb_update.lock);
+
+- dev = &gm12u320->dev;
+-
+ ret = drmm_mode_config_init(dev);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ dev->mode_config.min_width = GM12U320_USER_WIDTH;
+ dev->mode_config.max_width = GM12U320_USER_WIDTH;
+@@ -656,15 +677,15 @@ static int gm12u320_usb_probe(struct usb
+
+ ret = gm12u320_usb_alloc(gm12u320);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ ret = gm12u320_set_ecomode(gm12u320);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ ret = gm12u320_conn_init(gm12u320);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ ret = drm_simple_display_pipe_init(&gm12u320->dev,
+ &gm12u320->pipe,
+@@ -674,24 +695,31 @@ static int gm12u320_usb_probe(struct usb
+ gm12u320_pipe_modifiers,
+ &gm12u320->conn);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ drm_mode_config_reset(dev);
+
+ usb_set_intfdata(interface, dev);
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+- return ret;
++ goto err_put_device;
+
+ drm_fbdev_generic_setup(dev, 0);
+
+ return 0;
++
++err_put_device:
++ put_device(gm12u320->dmadev);
++ return ret;
+ }
+
+ static void gm12u320_usb_disconnect(struct usb_interface *interface)
+ {
+ struct drm_device *dev = usb_get_intfdata(interface);
++ struct gm12u320_device *gm12u320 = to_gm12u320(dev);
+
++ put_device(gm12u320->dmadev);
++ gm12u320->dmadev = NULL;
+ drm_dev_unplug(dev);
+ drm_atomic_helper_shutdown(dev);
+ }
+--- a/drivers/gpu/drm/udl/udl_drv.c
++++ b/drivers/gpu/drm/udl/udl_drv.c
+@@ -32,6 +32,22 @@ static int udl_usb_resume(struct usb_int
+ return drm_mode_config_helper_resume(dev);
+ }
+
++/*
++ * FIXME: Dma-buf sharing requires DMA support by the importing device.
++ * This function is a workaround to make USB devices work as well.
++ * See todo.rst for how to fix the issue in the dma-buf framework.
++ */
++static struct drm_gem_object *udl_driver_gem_prime_import(struct drm_device *dev,
++ struct dma_buf *dma_buf)
++{
++ struct udl_device *udl = to_udl(dev);
++
++ if (!udl->dmadev)
++ return ERR_PTR(-ENODEV);
++
++ return drm_gem_prime_import_dev(dev, dma_buf, udl->dmadev);
++}
++
+ DEFINE_DRM_GEM_FOPS(udl_driver_fops);
+
+ static struct drm_driver driver = {
+@@ -42,6 +58,7 @@ static struct drm_driver driver = {
+
+ .fops = &udl_driver_fops,
+ DRM_GEM_SHMEM_DRIVER_OPS,
++ .gem_prime_import = udl_driver_gem_prime_import,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+--- a/drivers/gpu/drm/udl/udl_drv.h
++++ b/drivers/gpu/drm/udl/udl_drv.h
+@@ -50,6 +50,7 @@ struct urb_list {
+ struct udl_device {
+ struct drm_device drm;
+ struct device *dev;
++ struct device *dmadev;
+ struct usb_device *udev;
+
+ struct drm_simple_display_pipe display_pipe;
+--- a/drivers/gpu/drm/udl/udl_main.c
++++ b/drivers/gpu/drm/udl/udl_main.c
+@@ -314,6 +314,10 @@ int udl_init(struct udl_device *udl)
+
+ DRM_DEBUG("\n");
+
++ udl->dmadev = usb_intf_get_dma_device(to_usb_interface(dev->dev));
++ if (!udl->dmadev)
++ drm_warn(dev, "buffer sharing not supported"); /* not an error */
++
+ mutex_init(&udl->gem_lock);
+
+ if (!udl_parse_vendor_descriptor(dev, udl->udev)) {
+@@ -342,12 +346,18 @@ int udl_init(struct udl_device *udl)
+ err:
+ if (udl->urbs.count)
+ udl_free_urb_list(dev);
++ put_device(udl->dmadev);
+ DRM_ERROR("%d\n", ret);
+ return ret;
+ }
+
+ int udl_drop_usb(struct drm_device *dev)
+ {
++ struct udl_device *udl = to_udl(dev);
++
+ udl_free_urb_list(dev);
++ put_device(udl->dmadev);
++ udl->dmadev = NULL;
++
+ return 0;
+ }
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -748,6 +748,38 @@ void usb_put_intf(struct usb_interface *
+ }
+ EXPORT_SYMBOL_GPL(usb_put_intf);
+
++/**
++ * usb_intf_get_dma_device - acquire a reference on the usb interface's DMA endpoint
++ * @intf: the usb interface
++ *
++ * While a USB device cannot perform DMA operations by itself, many USB
++ * controllers can. A call to usb_intf_get_dma_device() returns the DMA endpoint
++ * for the given USB interface, if any. The returned device structure must be
++ * released with put_device().
++ *
++ * See also usb_get_dma_device().
++ *
++ * Returns: A reference to the usb interface's DMA endpoint; or NULL if none
++ * exists.
++ */
++struct device *usb_intf_get_dma_device(struct usb_interface *intf)
++{
++ struct usb_device *udev = interface_to_usbdev(intf);
++ struct device *dmadev;
++
++ if (!udev->bus)
++ return NULL;
++
++ dmadev = get_device(udev->bus->sysdev);
++ if (!dmadev || !dmadev->dma_mask) {
++ put_device(dmadev);
++ return NULL;
++ }
++
++ return dmadev;
++}
++EXPORT_SYMBOL_GPL(usb_intf_get_dma_device);
++
+ /* USB device locking
+ *
+ * USB devices and interfaces are locked using the semaphore in their
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -746,6 +746,8 @@ extern int usb_lock_device_for_reset(str
+ extern int usb_reset_device(struct usb_device *dev);
+ extern void usb_queue_reset_device(struct usb_interface *dev);
+
++extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
++
+ #ifdef CONFIG_ACPI
+ extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
+ bool enable);
gpiolib-read-gpio-line-names-from-a-firmware-node.patch
gpio-pca953x-set-irq-type-when-handle-intel-galileo-gen-2.patch
gpio-fix-gpio-device-list-corruption.patch
+drm-compat-clear-bounce-structures.patch
+drm-amd-display-add-a-backlight-module-option.patch
+drm-amdgpu-display-use-gfp_atomic-in-dcn21_validate_bandwidth_fp.patch
+drm-amd-display-fix-nested-fpu-context-in-dcn21_validate_bandwidth.patch
+drm-amd-pm-bug-fix-for-pcie-dpm.patch
+drm-amdgpu-display-simplify-backlight-setting.patch
+drm-amdgpu-display-don-t-assert-in-set-backlight-function.patch
+drm-amdgpu-display-handle-aux-backlight-in-backlight_get_brightness.patch
+drm-shmem-helper-check-for-purged-buffers-in-fault-handler.patch
+drm-shmem-helper-don-t-remove-the-offset-in-vm_area_struct-pgoff.patch
+drm-use-usb-controller-s-dma-mask-when-importing-dmabufs.patch