From: Hans de Goede hdegoede@redhat.com
[ Upstream commit 8a238d7f7eea7592e0764bc3b9e79e7c6354b04c ]
The Lenovo Yoga Tab 3 X90F has a portrait 1600x2560 LCD used in landscape mode, add a quirk for this.
Signed-off-by: Hans de Goede hdegoede@redhat.com Reviewed-by: Javier Martinez Canillas javierm@redhat.com Link: https://patchwork.freedesktop.org/patch/msgid/20221127181539.104223-1-hdegoe... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 3659f0465a724..23d63a4d42d9c 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -127,6 +127,12 @@ static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = { .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, };
+static const struct drm_dmi_panel_orientation_data lcd1600x2560_rightside_up = { + .width = 1600, + .height = 2560, + .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, +}; + static const struct dmi_system_id orientation_data[] = { { /* Acer One 10 (S1003) */ .matches = { @@ -331,6 +337,13 @@ static const struct dmi_system_id orientation_data[] = { DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), }, .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Lenovo Yoga Tab 3 X90F */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), + }, + .driver_data = (void *)&lcd1600x2560_rightside_up, }, { /* Nanote UMPC-01 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),
From: Allen Ballway ballway@chromium.org
[ Upstream commit a3caf7ea0c3d5872ed0f2c51f5476aee0c47a73a ]
Like the ASUS T100HAN for which there is already a quirk, the DynaBook K50 has a 800x1280 portrait screen mounted in the tablet part of a landscape oriented 2-in-1. Update the quirk to be more generic and apply to this device.
Signed-off-by: Allen Ballway ballway@chromium.org Reviewed-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com Link: https://patchwork.freedesktop.org/patch/msgid/20221130170811.1.Iee9a49454754... Signed-off-by: Sasha Levin sashal@kernel.org --- .../gpu/drm/drm_panel_orientation_quirks.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index 23d63a4d42d9c..b409fe256fd0a 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -30,12 +30,6 @@ struct drm_dmi_panel_orientation_data { int orientation; };
-static const struct drm_dmi_panel_orientation_data asus_t100ha = { - .width = 800, - .height = 1280, - .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, -}; - static const struct drm_dmi_panel_orientation_data gpd_micropc = { .width = 720, .height = 1280, @@ -97,6 +91,12 @@ static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = { .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, };
+static const struct drm_dmi_panel_orientation_data lcd800x1280_leftside_up = { + .width = 800, + .height = 1280, + .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, +}; + static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = { .width = 800, .height = 1280, @@ -157,7 +157,7 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"), }, - .driver_data = (void *)&asus_t100ha, + .driver_data = (void *)&lcd800x1280_leftside_up, }, { /* Asus T101HA */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), @@ -202,6 +202,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Hi10 pro tablet"), }, .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Dynabook K50 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"), + }, + .driver_data = (void *)&lcd800x1280_leftside_up, }, { /* GPD MicroPC (generic strings, also match on bios date) */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
From: Dillon Varone Dillon.Varone@amd.com
[ Upstream commit 6b81090d6d4cc0fd818c9ec9dbb6906f921ad396 ]
[Description] Modify soc BB to reduce expected sdp bandwidth and align with measurements to fix underflow issues.
Reviewed-by: Jun Lei Jun.Lei@amd.com Acked-by: Jasdeep Dhillon jdhillon@amd.com Signed-off-by: Dillon Varone Dillon.Varone@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/dcn321/dcn321_fpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index f4b176599be7a..0ea406145c1d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -136,7 +136,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, - .pct_ideal_sdp_bw_after_urgent = 100.0, + .pct_ideal_sdp_bw_after_urgent = 90.0, .pct_ideal_fabric_bw_after_urgent = 67.0, .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0, .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
From: Ian Chen ian.chen@amd.com
[ Upstream commit 639f6ad6df7f47db48b59956b469a6917a136afb ]
[WHY] It causes regression AMD source will not write DPCD 340.
Reviewed-by: Wayne Lin Wayne.Lin@amd.com Acked-by: Jasdeep Dhillon jdhillon@amd.com Signed-off-by: Ian Chen ian.chen@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_link.c | 6 ------ drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 14 +++----------- drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 1 - 3 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 40b9d2ce08e66..328c5e33cc66b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1916,12 +1916,6 @@ struct dc_link *link_create(const struct link_init_data *init_params) if (false == dc_link_construct(link, init_params)) goto construct_fail;
- /* - * Must use preferred_link_setting, not reported_link_cap or verified_link_cap, - * since struct preferred_link_setting won't be reset after S3. - */ - link->preferred_link_setting.dpcd_source_device_specific_field_support = true; - return link;
construct_fail: diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 1254d38f1778a..24f1aba4ae133 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -6591,18 +6591,10 @@ void dpcd_set_source_specific_data(struct dc_link *link)
uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period;
- if (link->preferred_link_setting.dpcd_source_device_specific_field_support) { - result_write_min_hblank = core_link_write_dpcd(link, - DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size), - sizeof(hblank_size)); - - if (result_write_min_hblank == DC_ERROR_UNEXPECTED) - link->preferred_link_setting.dpcd_source_device_specific_field_support = false; - } else { - DC_LOG_DC("Sink device does not support 00340h DPCD write. Skipping on purpose.\n"); - } + result_write_min_hblank = core_link_write_dpcd(link, + DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size), + sizeof(hblank_size)); } - DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION, WPP_BIT_FLAG_DC_DETECTION_DP_CAPS, "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'", diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 2c54b6e0498bf..296793d8b2bf2 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -149,7 +149,6 @@ struct dc_link_settings { enum dc_link_spread link_spread; bool use_link_rate_set; uint8_t link_rate_set; - bool dpcd_source_device_specific_field_support; };
union dc_dp_ffe_preset {
From: Roman Li roman.li@amd.com
[ Upstream commit 7a7175a2cd84b7874bebbf8e59f134557a34161b ]
[Why] Fixing smatch error: dm_resume() error: we previously assumed 'aconnector->dc_link' could be null
[How] Check if dc_link null at the beginning of the loop, so further checks can be dropped.
Reported-by: kernel test robot lkp@intel.com Reported-by: Dan Carpenter dan.carpenter@oracle.com
Reviewed-by: Wayne Lin Wayne.Lin@amd.com Acked-by: Jasdeep Dhillon jdhillon@amd.com Signed-off-by: Roman Li roman.li@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index e9c4f22696c5c..6028e332e35d9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2750,12 +2750,14 @@ static int dm_resume(void *handle) drm_for_each_connector_iter(connector, &iter) { aconnector = to_amdgpu_dm_connector(connector);
+ if (!aconnector->dc_link) + continue; + /* * this is the case when traversing through already created * MST connectors, should be skipped */ - if (aconnector->dc_link && - aconnector->dc_link->type == dc_connection_mst_branch) + if (aconnector->dc_link->type == dc_connection_mst_branch) continue;
mutex_lock(&aconnector->hpd_lock);
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
[ Upstream commit cfca78971b9233aef0891507a98fba62046d4542 ]
dsi_dump_dsi_irqs(), a function used for debugfs prints, has a large struct in its frame, which can result in:
drivers/gpu/drm/omapdrm/dss/dsi.c:1126:1: warning: the frame size of 1060 bytes is larger than 1024 bytes [-Wframe-larger-than=]
As the performance of the function is of no concern, let's allocate the struct with kmalloc instead.
Compile-tested only.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Reported-by: kernel test robot lkp@intel.com Reviewed-by: Arnd Bergmann arnd@arndb.de Link: https://patchwork.freedesktop.org/patch/msgid/20220916082206.167427-1-tomi.v... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/omapdrm/dss/dsi.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index a6845856cbce4..4c1084eb01759 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1039,22 +1039,26 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p) { struct dsi_data *dsi = s->private; unsigned long flags; - struct dsi_irq_stats stats; + struct dsi_irq_stats *stats; + + stats = kmalloc(sizeof(*stats), GFP_KERNEL); + if (!stats) + return -ENOMEM;
spin_lock_irqsave(&dsi->irq_stats_lock, flags);
- stats = dsi->irq_stats; + *stats = dsi->irq_stats; memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats)); dsi->irq_stats.last_reset = jiffies;
spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
seq_printf(s, "period %u ms\n", - jiffies_to_msecs(jiffies - stats.last_reset)); + jiffies_to_msecs(jiffies - stats->last_reset));
- seq_printf(s, "irqs %d\n", stats.irq_count); + seq_printf(s, "irqs %d\n", stats->irq_count); #define PIS(x) \ - seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); + seq_printf(s, "%-20s %10d\n", #x, stats->dsi_irqs[ffs(DSI_IRQ_##x)-1]);
seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1); PIS(VC0); @@ -1078,10 +1082,10 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
#define PIS(x) \ seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \ - stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \ - stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]); + stats->vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \ + stats->vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
seq_printf(s, "-- VC interrupts --\n"); PIS(CS); @@ -1097,7 +1101,7 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
#define PIS(x) \ seq_printf(s, "%-20s %10d\n", #x, \ - stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]); + stats->cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
seq_printf(s, "-- CIO interrupts --\n"); PIS(ERRSYNCESC1); @@ -1122,6 +1126,8 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p) PIS(ULPSACTIVENOT_ALL1); #undef PIS
+ kfree(stats); + return 0; } #endif
From: Jingyuan Liang jingyliang@chromium.org
[ Upstream commit 2d60f9f4f26785a00273cb81fe60eff129ebd449 ]
HUTRR110 added a new usage code for a key that is supposed to mute/unmute microphone system-wide.
Map the new usage code(0x01 0xa9) to keycode KEY_MICMUTE. Additionally hid-debug is adjusted to recognize this keycode as well.
Signed-off-by: Jingyuan Liang jingyliang@chromium.org Reviewed-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-debug.c | 1 + drivers/hid/hid-input.c | 8 ++++++++ 2 files changed, 9 insertions(+)
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 2ca6ab600bc9f..15e35702773cd 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -972,6 +972,7 @@ static const char *keys[KEY_MAX + 1] = { [KEY_KBD_LAYOUT_NEXT] = "KbdLayoutNext", [KEY_EMOJI_PICKER] = "EmojiPicker", [KEY_DICTATE] = "Dictate", + [KEY_MICMUTE] = "MicrophoneMute", [KEY_BRIGHTNESS_MIN] = "BrightnessMin", [KEY_BRIGHTNESS_MAX] = "BrightnessMax", [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3ee5a9fea20e6..ee5050306225f 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -789,6 +789,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; }
+ if ((usage->hid & 0xf0) == 0xa0) { /* SystemControl */ + switch (usage->hid & 0xf) { + case 0x9: map_key_clear(KEY_MICMUTE); break; + default: goto ignore; + } + break; + } + if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */ switch (usage->hid & 0xf) { case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break;
From: Carlo Caione ccaione@baylibre.com
[ Upstream commit 77772e607522daa61f3af74df018559db75c43d6 ]
The pixel data for the ILI9486 is always 16-bits wide and it must be sent over the SPI bus. When the controller is only able to deal with 8-bit transfers, this 16-bits data needs to be swapped before the sending to account for the big endian bus, this is on the contrary not needed when the SPI controller already supports 16-bits transfers.
The decision about swapping the pixel data or not is taken in the MIPI DBI code by probing the controller capabilities: if the controller only suppors 8-bit transfers the data is swapped, otherwise it is not.
This swapping/non-swapping is relying on the assumption that when the controller does support 16-bit transactions then the data is sent unswapped in 16-bits-per-word over SPI.
The problem with the ILI9486 driver is that it is forcing 8-bit transactions also for controllers supporting 16-bits, violating the assumption and corrupting the pixel data.
Align the driver to what is done in the MIPI DBI code by adjusting the transfer size to the maximum allowed by the SPI controller.
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org Signed-off-by: Carlo Caione ccaione@baylibre.com Reviewed-by: Kamlesh Gurudasani kamlesh.gurudasani@gmail.com Signed-off-by: Neil Armstrong neil.armstrong@linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20221116-s905x_spi_ili9486-v4-... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/tiny/ili9486.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index c80028bb1d110..7b3048a3d9086 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -43,6 +43,7 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par, size_t num) { struct spi_device *spi = mipi->spi; + unsigned int bpw = 8; void *data = par; u32 speed_hz; int i, ret; @@ -56,8 +57,6 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par, * The displays are Raspberry Pi HATs and connected to the 8-bit only * SPI controller, so 16-bit command and parameters need byte swapping * before being transferred as 8-bit on the big endian SPI bus. - * Pixel data bytes have already been swapped before this function is - * called. */ buf[0] = cpu_to_be16(*cmd); gpiod_set_value_cansleep(mipi->dc, 0); @@ -71,12 +70,18 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par, for (i = 0; i < num; i++) buf[i] = cpu_to_be16(par[i]); num *= 2; - speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num); data = buf; }
+ /* + * Check whether pixel data bytes needs to be swapped or not + */ + if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !mipi->swap_bytes) + bpw = 16; + gpiod_set_value_cansleep(mipi->dc, 1); - ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num); + speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num); + ret = mipi_dbi_spi_transfer(spi, speed_hz, bpw, data, num); free: kfree(buf);
From: Nicholas Kazlauskas nicholas.kazlauskas@amd.com
[ Upstream commit 2d90a1c054831338d57b39aec4d273cf3e867590 ]
[Why] On some monitors we see a brief flash of corruption during the monitor disable sequence caused by FIFO being disabled in the middle of an active DP stream.
[How] Wait until DP vid stream is disabled before turning off the FIFO.
The FIFO reset on DP unblank should take care of clearing any FIFO error, if any.
Acked-by: Aurabindo Pillai aurabindo.pillai@amd.com Signed-off-by: Nicholas Kazlauskas nicholas.kazlauskas@amd.com Reviewed-by: Syed Hassan Syed.Hassan@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 --- .../drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c index 38842f938bed0..0926db0183383 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c @@ -278,10 +278,10 @@ static void enc314_stream_encoder_dp_blank( struct dc_link *link, struct stream_encoder *enc) { - /* New to DCN314 - disable the FIFO before VID stream disable. */ - enc314_disable_fifo(enc); - enc1_stream_encoder_dp_blank(link, enc); + + /* Disable FIFO after the DP vid stream is disabled to avoid corruption. */ + enc314_disable_fifo(enc); }
static void enc314_stream_encoder_dp_unblank(
From: Liwei Song liwei.song@windriver.com
[ Upstream commit 4773fadedca918faec443daaca5e4ea1c0ced144 ]
Fix below kmemleak when unload radeon driver:
unreferenced object 0xffff9f8608ede200 (size 512): comm "systemd-udevd", pid 326, jiffies 4294682822 (age 716.338s) hex dump (first 32 bytes): 00 00 00 00 c4 aa ec aa 14 ab 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<0000000062fadebe>] kmem_cache_alloc_trace+0x2f1/0x500 [<00000000b6883cea>] atom_parse+0x117/0x230 [radeon] [<00000000158c23fd>] radeon_atombios_init+0xab/0x170 [radeon] [<00000000683f672e>] si_init+0x57/0x750 [radeon] [<00000000566cc31f>] radeon_device_init+0x559/0x9c0 [radeon] [<0000000046efabb3>] radeon_driver_load_kms+0xc1/0x1a0 [radeon] [<00000000b5155064>] drm_dev_register+0xdd/0x1d0 [<0000000045fec835>] radeon_pci_probe+0xbd/0x100 [radeon] [<00000000e69ecca3>] pci_device_probe+0xe1/0x160 [<0000000019484b76>] really_probe.part.0+0xc1/0x2c0 [<000000003f2649da>] __driver_probe_device+0x96/0x130 [<00000000231c5bb1>] driver_probe_device+0x24/0xf0 [<0000000000a42377>] __driver_attach+0x77/0x190 [<00000000d7574da6>] bus_for_each_dev+0x7f/0xd0 [<00000000633166d2>] driver_attach+0x1e/0x30 [<00000000313b05b8>] bus_add_driver+0x12c/0x1e0
iio was allocated in atom_index_iio() called by atom_parse(), but it doesn't got released when the dirver is shutdown. Fix this kmemleak by free it in radeon_atombios_fini().
Signed-off-by: Liwei Song liwei.song@windriver.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a556b6be11374..e1f3ab607e4f4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1023,6 +1023,7 @@ void radeon_atombios_fini(struct radeon_device *rdev) { if (rdev->mode_info.atom_context) { kfree(rdev->mode_info.atom_context->scratch); + kfree(rdev->mode_info.atom_context->iio); } kfree(rdev->mode_info.atom_context); rdev->mode_info.atom_context = NULL;
From: Mario Limonciello mario.limonciello@amd.com
[ Upstream commit 93fec4f8c158584065134b4d45e875499bf517c8 ]
No need to crash the kernel. AMDGPU will now fail to probe.
Reviewed-by: Alex Deucher alexander.deucher@amd.com Reviewed-by: Lijo Lazar lijo.lazar@amd.com Signed-off-by: Mario Limonciello mario.limonciello@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_psp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 712dd72f3ccf2..087147f09933a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -354,7 +354,7 @@ static int psp_init_sriov_microcode(struct psp_context *psp) adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA; break; default: - BUG(); + ret = -EINVAL; break; } return ret;
From: Philip Yang Philip.Yang@amd.com
[ Upstream commit 0c2dece8fb541ab07b68c3312a1065fa9c927a81 ]
Use page aligned size to reserve memory usage because page aligned TTM BO size is used to unreserve memory usage, otherwise no page aligned size causes memory usage accounting unbalanced.
Change vram_used definition type to int64_t to be able to trigger WARN_ONCE(adev && adev->kfd.vram_used < 0, "..."), to help debug the accounting issue with warning and backtrace.
Signed-off-by: Philip Yang Philip.Yang@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_amdkfd.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 12 +++++++----- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 9 +++++++-- 3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 30f145dc8724e..dbc842590b253 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -95,7 +95,7 @@ struct amdgpu_amdkfd_fence {
struct amdgpu_kfd_dev { struct kfd_dev *dev; - uint64_t vram_used; + int64_t vram_used; uint64_t vram_used_aligned; bool init_complete; struct work_struct reset_work; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 404c839683b1c..da01c1424b4ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1653,6 +1653,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( struct amdgpu_bo *bo; struct drm_gem_object *gobj = NULL; u32 domain, alloc_domain; + uint64_t aligned_size; u64 alloc_flags; int ret;
@@ -1703,22 +1704,23 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( * the memory. */ if ((*mem)->aql_queue) - size = size >> 1; + size >>= 1; + aligned_size = PAGE_ALIGN(size);
(*mem)->alloc_flags = flags;
amdgpu_sync_create(&(*mem)->sync);
- ret = amdgpu_amdkfd_reserve_mem_limit(adev, size, flags); + ret = amdgpu_amdkfd_reserve_mem_limit(adev, aligned_size, flags); if (ret) { pr_debug("Insufficient memory\n"); goto err_reserve_limit; }
pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n", - va, size, domain_string(alloc_domain)); + va, (*mem)->aql_queue ? size << 1 : size, domain_string(alloc_domain));
- ret = amdgpu_gem_object_create(adev, size, 1, alloc_domain, alloc_flags, + ret = amdgpu_gem_object_create(adev, aligned_size, 1, alloc_domain, alloc_flags, bo_type, NULL, &gobj); if (ret) { pr_debug("Failed to create BO on domain %s. ret %d\n", @@ -1775,7 +1777,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( /* Don't unreserve system mem limit twice */ goto err_reserve_limit; err_bo_create: - amdgpu_amdkfd_unreserve_mem_limit(adev, size, flags); + amdgpu_amdkfd_unreserve_mem_limit(adev, aligned_size, flags); err_reserve_limit: mutex_destroy(&(*mem)->lock); if (gobj) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 6d291aa6386bd..f79b8e964140e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1127,8 +1127,13 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, }
/* Update the VRAM usage count */ - if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) - WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + args->size); + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { + uint64_t size = args->size; + + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM) + size >>= 1; + WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + PAGE_ALIGN(size)); + }
mutex_unlock(&p->mutex);
From: Justin Tee justin.tee@broadcom.com
[ Upstream commit 21681b81b9ae548c5dae7ae00d931197a27f480c ]
During the sysfs firmware write process, a use-after-free read warning is logged from the lpfc_wr_object() routine:
BUG: KFENCE: use-after-free read in lpfc_wr_object+0x235/0x310 [lpfc] Use-after-free read at 0x0000000000cf164d (in kfence-#111): lpfc_wr_object+0x235/0x310 [lpfc] lpfc_write_firmware.cold+0x206/0x30d [lpfc] lpfc_sli4_request_firmware_update+0xa6/0x100 [lpfc] lpfc_request_firmware_upgrade_store+0x66/0xb0 [lpfc] kernfs_fop_write_iter+0x121/0x1b0 new_sync_write+0x11c/0x1b0 vfs_write+0x1ef/0x280 ksys_write+0x5f/0xe0 do_syscall_64+0x59/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd
The driver accessed wr_object pointer data, which was initialized into mailbox payload memory, after the mailbox object was released back to the mailbox pool.
Fix by moving the mailbox free calls to the end of the routine ensuring that we don't reference internal mailbox memory after release.
Signed-off-by: Justin Tee justin.tee@broadcom.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/lpfc/lpfc_sli.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 21c52154626f1..b93c948c4fcc4 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20802,6 +20802,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, struct lpfc_mbx_wr_object *wr_object; LPFC_MBOXQ_t *mbox; int rc = 0, i = 0; + int mbox_status = 0; uint32_t shdr_status, shdr_add_status, shdr_add_status_2; uint32_t shdr_change_status = 0, shdr_csf = 0; uint32_t mbox_tmo; @@ -20847,11 +20848,15 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, wr_object->u.request.bde_count = i; bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written); if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + mbox_status = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); else { mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + mbox_status = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); } + + /* The mbox status needs to be maintained to detect MBOX_TIMEOUT. */ + rc = mbox_status; + /* The IOCTL status is embedded in the mailbox subheader. */ shdr_status = bf_get(lpfc_mbox_hdr_status, &wr_object->header.cfg_shdr.response); @@ -20866,10 +20871,6 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, &wr_object->u.response); }
- if (!phba->sli4_hba.intr_enable) - mempool_free(mbox, phba->mbox_mem_pool); - else if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3025 Write Object mailbox failed with " @@ -20887,6 +20888,12 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status, shdr_add_status_2, shdr_change_status, shdr_csf); + + if (!phba->sli4_hba.intr_enable) + mempool_free(mbox, phba->mbox_mem_pool); + else if (mbox_status != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return rc; }
From: Thomas Zimmermann tzimmermann@suse.de
[ Upstream commit 12d5796d55f9fd9e4b621003127c99e176665064 ]
This reverts commit ae1287865f5361fa138d4d3b1b6277908b54eac9.
Always free the console font when deinitializing the framebuffer console. Subsequent framebuffer consoles will then use the default font. Rely on userspace to load any user-configured font for these consoles.
Commit ae1287865f53 ("fbcon: don't lose the console font across generic->chip driver switch") was introduced to work around losing the font during graphics-device handover. [1][2] It kept a dangling pointer with the font data between loading the two consoles, which is fairly adventurous hack. It also never covered cases when the other consoles, such as VGA text mode, where involved.
The problem has meanwhile been solved in userspace. Systemd comes with a udev rule that re-installs the configured font when a console comes up. [3] So the kernel workaround can be removed.
This also removes one of the two special cases triggered by setting FBINFO_MISC_FIRMWARE in an fbdev driver.
Tested during device handover from efifb and simpledrm to radeon. Udev reloads the configured console font for the new driver's terminal.
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de Link: https://bugzilla.redhat.com/show_bug.cgi?id=892340 # 1 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1074624 # 2 Link: https://cgit.freedesktop.org/systemd/systemd/tree/src/vconsole/90-vconsole.r... # 3 Reviewed-by: Javier Martinez Canillas javierm@redhat.com Link: https://patchwork.freedesktop.org/patch/msgid/20221219160516.23436-3-tzimmer... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/video/fbdev/core/fbcon.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 1b14c21af2b74..2bc8baa90c0f2 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -958,7 +958,7 @@ static const char *fbcon_startup(void) set_blitting_type(vc, info);
/* Setup default font */ - if (!p->fontdata && !vc->vc_font.data) { + if (!p->fontdata) { if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, info->var.yres, @@ -968,8 +968,6 @@ static const char *fbcon_startup(void) vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); vc->vc_font.charcount = font->charcount; - } else { - p->fontdata = vc->vc_font.data; }
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); @@ -1135,9 +1133,9 @@ static void fbcon_init(struct vc_data *vc, int init) ops->p = &fb_display[fg_console]; }
-static void fbcon_free_font(struct fbcon_display *p, bool freefont) +static void fbcon_free_font(struct fbcon_display *p) { - if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) + if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); p->fontdata = NULL; p->userfont = 0; @@ -1172,8 +1170,8 @@ static void fbcon_deinit(struct vc_data *vc) struct fb_info *info; struct fbcon_ops *ops; int idx; - bool free_font = true;
+ fbcon_free_font(p); idx = con2fb_map[vc->vc_num];
if (idx == -1) @@ -1184,8 +1182,6 @@ static void fbcon_deinit(struct vc_data *vc) if (!info) goto finished;
- if (info->flags & FBINFO_MISC_FIRMWARE) - free_font = false; ops = info->fbcon_par;
if (!ops) @@ -1197,9 +1193,8 @@ static void fbcon_deinit(struct vc_data *vc) ops->initialized = false; finished:
- fbcon_free_font(p, free_font); - if (free_font) - vc->vc_font.data = NULL; + fbcon_free_font(p); + vc->vc_font.data = NULL;
if (vc->vc_hi_font_mask && vc->vc_screenbuf) set_vc_hi_font(vc, false);
From: Mario Limonciello mario.limonciello@amd.com
[ Upstream commit 3e5019ee67760cd61b2a5fd605e1289c2f92d983 ]
On DCN314 when resuming from s0i3 an ASSERT is shown indicating that `VBIOSSMC_MSG_SetHardMinDcfclkByFreq` returned `VBIOSSMC_Result_Failed`.
This isn't a driver bug; it's a BIOS/configuration bug. To make this easier to triage, add an explicit warning when this issue happens.
This matches the behavior utilized for failures with `VBIOSSMC_MSG_TransferTableDram2Smu` configuration.
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/clk_mgr/dcn314/dcn314_smu.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c index 2db595672a469..aa264c600408d 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c @@ -146,6 +146,9 @@ static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu && param == TABLE_WATERMARKS) DC_LOG_WARNING("Watermarks table not configured properly by SMU"); + else if (msg_id == VBIOSSMC_MSG_SetHardMinDcfclkByFreq || + msg_id == VBIOSSMC_MSG_SetMinDeepSleepDcfclk) + DC_LOG_WARNING("DCFCLK_DPM is not enabled by BIOS"); else ASSERT(0); REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
From: Konstantin Meskhidze konstantin.meskhidze@huawei.com
[ Upstream commit 6b8701be1f66064ca72733c5f6e13748cdbf8397 ]
This commit fixes memory leakage in dc_construct_ctx() function.
Signed-off-by: Konstantin Meskhidze konstantin.meskhidze@huawei.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 | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 5260ad6de8038..24015f8cac75a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -878,6 +878,7 @@ static bool dc_construct_ctx(struct dc *dc,
dc_ctx->perf_trace = dc_perf_trace_create(); if (!dc_ctx->perf_trace) { + kfree(dc_ctx); ASSERT_CRITICAL(false); return false; }
From: Brandon Syu Brandon.Syu@amd.com
[ Upstream commit 9190d4a263264eabf715f5fc1827da45e3fdc247 ]
[Why] There is an issue mapping non-allocated location of memory. It would allocate gpio registers from an array out of bounds.
[How] Patch correct numbers of bounds for using.
Tested-by: Daniel Wheeler Daniel.Wheeler@amd.com Reviewed-by: Martin Leung Martin.Leung@amd.com Acked-by: Rodrigo Siqueira Rodrigo.Siqueira@amd.com Signed-off-by: Brandon Syu Brandon.Syu@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- .../gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c | 6 ++++-- .../gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c | 6 ++++-- .../gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c | 6 ++++-- drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h | 7 +++++++ 4 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c index 9b63c6c0cc844..e0bd0c722e006 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c @@ -138,7 +138,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) };
static const struct ddc_sh_mask ddc_mask[] = { @@ -147,7 +148,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) };
#include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c index 687d4f128480e..36a5736c58c92 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c @@ -145,7 +145,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) };
static const struct ddc_sh_mask ddc_mask[] = { @@ -154,7 +155,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) };
#include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c index 0ea52ba5ac827..9f6872ae40203 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c @@ -149,7 +149,8 @@ static const struct ddc_sh_mask ddc_shift[] = { DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), - DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6), + DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT) };
static const struct ddc_sh_mask ddc_mask[] = { @@ -158,7 +159,8 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 3), DDC_MASK_SH_LIST_DCN2(_MASK, 4), DDC_MASK_SH_LIST_DCN2(_MASK, 5), - DDC_MASK_SH_LIST_DCN2(_MASK, 6) + DDC_MASK_SH_LIST_DCN2(_MASK, 6), + DDC_MASK_SH_LIST_DCN2_VGA(_MASK) };
#include "../generic_regs.h" diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h index 308a543178a56..59884ef651b39 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h @@ -113,6 +113,13 @@ (PHY_AUX_CNTL__AUX## cd ##_PAD_RXSEL## mask_sh),\ (DC_GPIO_AUX_CTRL_5__DDC_PAD## cd ##_I2CMODE## mask_sh)}
+#define DDC_MASK_SH_LIST_DCN2_VGA(mask_sh) \ + {DDC_MASK_SH_LIST_COMMON(mask_sh),\ + 0,\ + 0,\ + 0,\ + 0} + struct ddc_registers { struct gpio_registers gpio; uint32_t ddc_setup;
From: Bjorn Andersson quic_bjorande@quicinc.com
[ Upstream commit e17af1c9d861dc177e5b56009bd4f71ace688d97 ]
During initalization of the DisplayPort controller an EV_HPD_INIT_SETUP event is generated, but with a delay of 100 units. This delay existed to circumvent bug in the QMP combo PHY driver, where if the DP part was powered up before USB, the common properties would not be properly initialized - and USB wouldn't work.
This issue was resolved in the recent refactoring of the QMP driver, so it's now possible to remove this delay.
While there is still a timing dependency in the current implementation, test indicates that it's now possible to boot with an external display on USB Type-C and have the display power up, without disconnecting and reconnecting the cable.
Signed-off-by: Bjorn Andersson quic_bjorande@quicinc.com Reviewed-by: Kuogee Hsieh quic_khsieh@quicinc.com Patchwork: https://patchwork.freedesktop.org/patch/518729/ Link: https://lore.kernel.org/r/20230117172951.2748456-1-quic_bjorande@quicinc.com Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/dp/dp_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index c9d9b384ddd03..85a375d94df56 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1497,7 +1497,7 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display) dp = container_of(dp_display, struct dp_display_private, dp_display);
if (!dp_display->is_edp) - dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100); + dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0); }
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
On Sun, Feb 26, 2023 at 09:04:16PM -0500, Sasha Levin wrote:
From: Bjorn Andersson quic_bjorande@quicinc.com
[ Upstream commit e17af1c9d861dc177e5b56009bd4f71ace688d97 ]
During initalization of the DisplayPort controller an EV_HPD_INIT_SETUP event is generated, but with a delay of 100 units. This delay existed to circumvent bug in the QMP combo PHY driver, where if the DP part was powered up before USB, the common properties would not be properly initialized - and USB wouldn't work.
This issue was resolved in the recent refactoring of the QMP driver, so it's now possible to remove this delay.
While there is still a timing dependency in the current implementation, test indicates that it's now possible to boot with an external display on USB Type-C and have the display power up, without disconnecting and reconnecting the cable.
Signed-off-by: Bjorn Andersson quic_bjorande@quicinc.com Reviewed-by: Kuogee Hsieh quic_khsieh@quicinc.com Patchwork: https://patchwork.freedesktop.org/patch/518729/ Link: https://lore.kernel.org/r/20230117172951.2748456-1-quic_bjorande@quicinc.com Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org
This is not a bug fix and should not be backported.
Johan
From: José Expósito jose.exposito89@gmail.com
[ Upstream commit 14b71e6ad8ca59dd734c7fa9676f3d60bddee2a9 ]
The report descriptor used to get information about UGEE v2 devices is incorrect in the XP-PEN Deco Pro SW. It indicates that the device frame is of type UCLOGIC_PARAMS_FRAME_BUTTONS but the device has a frame of type UCLOGIC_PARAMS_FRAME_MOUSE.
Here is the original report descriptor:
0x0e 0x03 0xc8 0xb3 0x34 0x65 0x08 0x00 0xff 0x1f 0xd8 0x13 0x00 0x00 ^ This byte should be 2
Add a quirk to be able to fix the reported frame type.
Tested-by: Mia Kanashi chad@redpilled.dev Tested-by: Andreas Grosse andig.mail@t-online.de Signed-off-by: José Expósito jose.exposito89@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-uclogic-core.c | 20 +------------------- drivers/hid/hid-uclogic-params.c | 5 +++++ drivers/hid/hid-uclogic-params.h | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index cfbbc39807a69..739984b8fa1b8 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -22,25 +22,6 @@
#include "hid-ids.h"
-/* Driver data */ -struct uclogic_drvdata { - /* Interface parameters */ - struct uclogic_params params; - /* Pointer to the replacement report descriptor. NULL if none. */ - __u8 *desc_ptr; - /* - * Size of the replacement report descriptor. - * Only valid if desc_ptr is not NULL - */ - unsigned int desc_size; - /* Pen input device */ - struct input_dev *pen_input; - /* In-range timer */ - struct timer_list inrange_timer; - /* Last rotary encoder state, or U8_MAX for none */ - u8 re_state; -}; - /** * uclogic_inrange_timeout - handle pen in-range state timeout. * Emulate input events normally generated when pen goes out of range for @@ -202,6 +183,7 @@ static int uclogic_probe(struct hid_device *hdev, } timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0); drvdata->re_state = U8_MAX; + drvdata->quirks = id->driver_data; hid_set_drvdata(hdev, drvdata);
/* Initialize the device and retrieve interface parameters */ diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 3c5eea3df3288..e052538a62fb3 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1298,6 +1298,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, struct hid_device *hdev) { int rc = 0; + struct uclogic_drvdata *drvdata; struct usb_interface *iface; __u8 bInterfaceNumber; const int str_desc_len = 12; @@ -1316,6 +1317,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, goto cleanup; }
+ drvdata = hid_get_drvdata(hdev); iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
@@ -1382,6 +1384,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params, p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
/* Initialize the frame interface */ + if (drvdata->quirks & UCLOGIC_MOUSE_FRAME_QUIRK) + frame_type = UCLOGIC_PARAMS_FRAME_MOUSE; + switch (frame_type) { case UCLOGIC_PARAMS_FRAME_DIAL: case UCLOGIC_PARAMS_FRAME_MOUSE: diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index a97477c02ff82..10a05c7fd9398 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -19,6 +19,8 @@ #include <linux/usb.h> #include <linux/hid.h>
+#define UCLOGIC_MOUSE_FRAME_QUIRK BIT(0) + /* Types of pen in-range reporting */ enum uclogic_params_pen_inrange { /* Normal reports: zero - out of proximity, one - in proximity */ @@ -215,6 +217,27 @@ struct uclogic_params { struct uclogic_params_frame frame_list[3]; };
+/* Driver data */ +struct uclogic_drvdata { + /* Interface parameters */ + struct uclogic_params params; + /* Pointer to the replacement report descriptor. NULL if none. */ + __u8 *desc_ptr; + /* + * Size of the replacement report descriptor. + * Only valid if desc_ptr is not NULL + */ + unsigned int desc_size; + /* Pen input device */ + struct input_dev *pen_input; + /* In-range timer */ + struct timer_list inrange_timer; + /* Last rotary encoder state, or U8_MAX for none */ + u8 re_state; + /* Device quirks */ + unsigned long quirks; +}; + /* Initialize a tablet interface and discover its parameters */ extern int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev);
From: José Expósito jose.exposito89@gmail.com
[ Upstream commit f60c377f52de37f8705c5fc6d57737fdaf309ff9 ]
Some UGEE v2 tablets have a wireless version with an internal battery and their firmware is able to report their battery level.
However, there was not found a field on their descriptor indicating whether the tablet has battery or not, making it mandatory to classify such devices through the UCLOGIC_BATTERY_QUIRK quirk.
Tested-by: Mia Kanashi chad@redpilled.dev Tested-by: Andreas Grosse andig.mail@t-online.de Signed-off-by: José Expósito jose.exposito89@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-uclogic-params.c | 5 +++++ drivers/hid/hid-uclogic-params.h | 1 + 2 files changed, 6 insertions(+)
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index e052538a62fb3..23624d5b07b5a 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1222,6 +1222,11 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p) */ static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev) { + struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); + + if (drvdata->quirks & UCLOGIC_BATTERY_QUIRK) + return true; + /* The XP-PEN Deco LW vendor, product and version are identical to the * Deco L. The only difference reported by their firmware is the product * name. Add a quirk to support battery reporting on the wireless diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index 10a05c7fd9398..b0e7f3807939b 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -20,6 +20,7 @@ #include <linux/hid.h>
#define UCLOGIC_MOUSE_FRAME_QUIRK BIT(0) +#define UCLOGIC_BATTERY_QUIRK BIT(1)
/* Types of pen in-range reporting */ enum uclogic_params_pen_inrange {
From: José Expósito jose.exposito89@gmail.com
[ Upstream commit 7744ca571af55b794595cff2da9d51a26904998f ]
The XP-PEN Deco Pro SW is a UGEE v2 device with a frame with 8 buttons, a bitmap dial and a mouse; however, the UCLOGIC_MOUSE_FRAME_QUIRK is required because it reports an incorrect frame type. Its pen has 2 buttons, supports tilt and pressure.
It can be connected using a USB cable or, to use it in wireless mode, using a USB Bluetooth dongle. When it is connected in wireless mode the device battery is used to power it.
All the pieces to support it are already in place. Add its ID and quirks in order to support the device.
Signed-off-by: José Expósito jose.exposito89@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-input.c | 2 ++ drivers/hid/hid-uclogic-core.c | 3 +++ drivers/hid/hid-uclogic-params.c | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 0f8c11842a3a5..9eca3e0cffae4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1297,6 +1297,7 @@ #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ee5050306225f..ee07d3e341fc4 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -376,6 +376,8 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L), HID_BATTERY_QUIRK_AVOID_QUERY }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW), + HID_BATTERY_QUIRK_AVOID_QUERY }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15), HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100), diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 739984b8fa1b8..7c05d38d3afad 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -513,6 +513,9 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW), + .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, { } diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 23624d5b07b5a..492a30f83575a 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1671,6 +1671,8 @@ int uclogic_params_init(struct uclogic_params *params, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S): + case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW): rc = uclogic_params_ugee_v2_init(&p, hdev); if (rc != 0) goto cleanup;
From: José Expósito jose.exposito89@gmail.com
[ Upstream commit 9266a88156d1fbb8e50d6eeff7bac44ad4eaecc2 ]
The XP-PEN Deco Pro MW is a UGEE v2 device with a frame with 8 buttons, a bitmap dial and a mouse. Its pen has 2 buttons, supports tilt and pressure.
It can be connected using a USB cable or, to use it in wireless mode, using a USB Bluetooth dongle. When it is connected in wireless mode the device battery is used to power it.
All the pieces to support it are already in place. Add its ID and quirks in order to support the device.
Link: https://github.com/DIGImend/digimend-kernel-drivers/issues/622 Tested-by: Andreas Grosse andig.mail@t-online.de Signed-off-by: José Expósito jose.exposito89@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-input.c | 2 ++ drivers/hid/hid-uclogic-core.c | 3 +++ drivers/hid/hid-uclogic-params.c | 2 ++ 4 files changed, 8 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9eca3e0cffae4..c0d983ca09107 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1296,6 +1296,7 @@ #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW 0x0934 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ee07d3e341fc4..3116aee21ceb9 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -376,6 +376,8 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L), HID_BATTERY_QUIRK_AVOID_QUERY }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW), + HID_BATTERY_QUIRK_AVOID_QUERY }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW), HID_BATTERY_QUIRK_AVOID_QUERY }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15), diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 7c05d38d3afad..bfbb51f8b5beb 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -511,6 +511,9 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW), + .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 492a30f83575a..0cc03c11ecc22 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1669,6 +1669,8 @@ int uclogic_params_init(struct uclogic_params *params, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): + case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S): case VID_PID(USB_VENDOR_ID_UGEE,
From: Allen Ballway ballway@chromium.org
[ Upstream commit a2f416bf062a38bb76cccd526d2d286b8e4db4d9 ]
Certain touchscreen devices, such as the ELAN9034, are oriented incorrectly and report touches on opposite points on the X and Y axes. For example, a 100x200 screen touched at (10,20) would report (90, 180) and vice versa.
This is fixed by adding device quirks to transform the touch points into the correct spaces, from X -> MAX(X) - X, and Y -> MAX(Y) - Y.
Signed-off-by: Allen Ballway ballway@chromium.org Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-multitouch.c | 39 ++++++++++++++++++--- drivers/hid/hid-quirks.c | 6 ++++ drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 43 ++++++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid.h | 3 ++ 4 files changed, 87 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 372cbdd223e09..e31be0cb8b850 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -71,6 +71,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) #define MT_QUIRK_DISABLE_WAKEUP BIT(21) +#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -1009,6 +1010,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, struct mt_usages *slot) { struct input_mt *mt = input->mt; + struct hid_device *hdev = td->hdev; __s32 quirks = app->quirks; bool valid = true; bool confidence_state = true; @@ -1086,6 +1088,10 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, int orientation = wide; int max_azimuth; int azimuth; + int x; + int y; + int cx; + int cy;
if (slot->a != DEFAULT_ZERO) { /* @@ -1104,6 +1110,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, if (azimuth > max_azimuth * 2) azimuth -= max_azimuth * 4; orientation = -azimuth; + if (quirks & MT_QUIRK_ORIENTATION_INVERT) + orientation = -orientation; + }
if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { @@ -1115,10 +1124,23 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, minor = minor >> 1; }
- input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y); - input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx); - input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy); + x = hdev->quirks & HID_QUIRK_X_INVERT ? + input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x : + *slot->x; + y = hdev->quirks & HID_QUIRK_Y_INVERT ? + input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y : + *slot->y; + cx = hdev->quirks & HID_QUIRK_X_INVERT ? + input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->cx : + *slot->cx; + cy = hdev->quirks & HID_QUIRK_Y_INVERT ? + input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->cy : + *slot->cy; + + input_event(input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); + input_event(input, EV_ABS, ABS_MT_TOOL_X, cx); + input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy); input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); @@ -1735,6 +1757,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true;
+ + /* Orientation is inverted if the X or Y axes are + * flipped, but normalized if both are inverted. + */ + if (hdev->quirks & (HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT) && + !((hdev->quirks & HID_QUIRK_X_INVERT) + && (hdev->quirks & HID_QUIRK_Y_INVERT))) + td->mtclass.quirks = MT_QUIRK_ORIENTATION_INVERT; + /* This allows the driver to correctly support devices * that emit events over several HID messages. */ diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index be3ad02573de8..d13f8e6ccee45 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -19,6 +19,7 @@ #include <linux/input/elan-i2c-ids.h>
#include "hid-ids.h" +#include "i2c-hid/i2c-hid.h"
/* * Alphabetically sorted by vendor then product. @@ -1297,6 +1298,11 @@ unsigned long hid_lookup_quirk(const struct hid_device *hdev) quirks = hid_gets_squirk(hdev); mutex_unlock(&dquirks_lock);
+ /* Get quirks specific to I2C devices */ + if (IS_ENABLED(CONFIG_I2C_DMI_CORE) && IS_ENABLED(CONFIG_DMI) && + hdev->bus == BUS_I2C) + quirks |= i2c_hid_get_dmi_quirks(hdev->vendor, hdev->product); + return quirks; } EXPORT_SYMBOL_GPL(hid_lookup_quirk); diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index 8e0f67455c098..554a7dc285365 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -10,8 +10,10 @@ #include <linux/types.h> #include <linux/dmi.h> #include <linux/mod_devicetable.h> +#include <linux/hid.h>
#include "i2c-hid.h" +#include "../hid-ids.h"
struct i2c_hid_desc_override { @@ -416,6 +418,28 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { { } /* Terminate list */ };
+static const struct hid_device_id i2c_hid_elan_flipped_quirks = { + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ELAN, 0x2dcd), + HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT +}; + +/* + * This list contains devices which have specific issues based on the system + * they're on and not just the device itself. The driver_data will have a + * specific hid device to match against. + */ +static const struct dmi_system_id i2c_hid_dmi_quirk_table[] = { + { + .ident = "DynaBook K50/FR", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"), + }, + .driver_data = (void *)&i2c_hid_elan_flipped_quirks, + }, + { } /* Terminate list */ +}; +
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) { @@ -450,3 +474,22 @@ char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, *size = override->hid_report_desc_size; return override->hid_report_desc; } + +u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product) +{ + u32 quirks = 0; + const struct dmi_system_id *system_id = + dmi_first_match(i2c_hid_dmi_quirk_table); + + if (system_id) { + const struct hid_device_id *device_id = + (struct hid_device_id *)(system_id->driver_data); + + if (device_id && device_id->vendor == vendor && + device_id->product == product) + quirks = device_id->driver_data; + } + + return quirks; +} +EXPORT_SYMBOL_GPL(i2c_hid_get_dmi_quirks); diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h index 96c75510ad3f1..2c7b66d5caa0f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.h +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -9,6 +9,7 @@ struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, unsigned int *size); +u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product); #else static inline struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) @@ -16,6 +17,8 @@ static inline struct i2c_hid_desc static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, unsigned int *size) { return NULL; } +static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product) +{ return 0; } #endif
/**
From: Jiasheng Jiang jiasheng@iscas.ac.cn
[ Upstream commit 115906ca7b535afb1fe7b5406c566ccd3873f82b ]
Add check for the return value of alloc_ordered_workqueue as it may return NULL pointer and cause NULL pointer dereference.
Signed-off-by: Jiasheng Jiang jiasheng@iscas.ac.cn Reviewed-by: Abhinav Kumar quic_abhinavk@quicinc.com Patchwork: https://patchwork.freedesktop.org/patch/517646/ Link: https://lore.kernel.org/r/20230110021651.12770-1-jiasheng@iscas.ac.cn Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/dsi/dsi_host.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 89aadd3b3202b..f167a45f1fbdd 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1977,6 +1977,9 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
/* setup workqueue */ msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); + if (!msm_host->workqueue) + return -ENOMEM; + INIT_WORK(&msm_host->err_work, dsi_err_worker);
msm_dsi->id = msm_host->id;
From: Tomi Valkeinen tomi.valkeinen+renesas@ideasonboard.com
[ Upstream commit 4f548bc48a2b4c4e54eecfddb6f7d24aa1b98768 ]
rcar_du_crtc.c does a soc_device_match() in rcar_du_crtc_set_display_timing() to find out if the SoC is H3 ES1.x, and if so, apply a workaround.
We will need another H3 ES1.x check in the following patch, so rather than adding more soc_device_match() calls, let's add a rcar_du_device_info entry for the ES1, and a quirk flag, RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY, for the workaround.
Signed-off-by: Tomi Valkeinen tomi.valkeinen+renesas@ideasonboard.com Reviewed-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 8 +---- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 48 ++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + 3 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 3619e1ddeb620..f2d3266509cc1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -10,7 +10,6 @@ #include <linux/clk.h> #include <linux/mutex.h> #include <linux/platform_device.h> -#include <linux/sys_soc.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> @@ -204,11 +203,6 @@ static void rcar_du_escr_divider(struct clk *clk, unsigned long target, } }
-static const struct soc_device_attribute rcar_du_r8a7795_es1[] = { - { .soc_id = "r8a7795", .revision = "ES1.*" }, - { /* sentinel */ } -}; - static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; @@ -238,7 +232,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) * no post-divider when a display PLL is present (as shown by * the workaround breaking HDMI output on M3-W during testing). */ - if (soc_device_match(rcar_du_r8a7795_es1)) { + if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY) { target *= 2; div = 1; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index a2776f1d6f2c2..0dada0646b2eb 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/slab.h> +#include <linux/sys_soc.h> #include <linux/wait.h>
#include <drm/drm_atomic_helper.h> @@ -386,6 +387,42 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = { .dpll_mask = BIT(2) | BIT(1), };
+static const struct rcar_du_device_info rcar_du_r8a7795_es1_info = { + .gen = 3, + .features = RCAR_DU_FEATURE_CRTC_IRQ + | RCAR_DU_FEATURE_CRTC_CLOCK + | RCAR_DU_FEATURE_VSP1_SOURCE + | RCAR_DU_FEATURE_INTERLACED + | RCAR_DU_FEATURE_TVM_SYNC, + .quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY, + .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), + .routes = { + /* + * R8A7795 has one RGB output, two HDMI outputs and one + * LVDS output. + */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(3), + .port = 0, + }, + [RCAR_DU_OUTPUT_HDMI0] = { + .possible_crtcs = BIT(1), + .port = 1, + }, + [RCAR_DU_OUTPUT_HDMI1] = { + .possible_crtcs = BIT(2), + .port = 2, + }, + [RCAR_DU_OUTPUT_LVDS0] = { + .possible_crtcs = BIT(0), + .port = 3, + }, + }, + .num_lvds = 1, + .num_rpf = 5, + .dpll_mask = BIT(2) | BIT(1), +}; + static const struct rcar_du_device_info rcar_du_r8a7796_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ @@ -554,6 +591,11 @@ static const struct of_device_id rcar_du_of_table[] = {
MODULE_DEVICE_TABLE(of, rcar_du_of_table);
+static const struct soc_device_attribute rcar_du_soc_table[] = { + { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_du_r8a7795_es1_info }, + { /* sentinel */ } +}; + const char *rcar_du_output_name(enum rcar_du_output output) { static const char * const names[] = { @@ -645,6 +687,7 @@ static void rcar_du_shutdown(struct platform_device *pdev)
static int rcar_du_probe(struct platform_device *pdev) { + const struct soc_device_attribute *soc_attr; struct rcar_du_device *rcdu; unsigned int mask; int ret; @@ -659,8 +702,13 @@ static int rcar_du_probe(struct platform_device *pdev) return PTR_ERR(rcdu);
rcdu->dev = &pdev->dev; + rcdu->info = of_device_get_match_data(rcdu->dev);
+ soc_attr = soc_device_match(rcar_du_soc_table); + if (soc_attr) + rcdu->info = soc_attr->data; + platform_set_drvdata(pdev, rcdu);
/* I/O resources */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 5cfa2bb7ad93d..df87ccab146f4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -34,6 +34,7 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ +#define RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY BIT(1) /* H3 ES1 has pclk stability issue */
enum rcar_du_output { RCAR_DU_OUTPUT_DPAD0,
From: Tomi Valkeinen tomi.valkeinen+renesas@ideasonboard.com
[ Upstream commit 5fbc2f3b91d27e12b614947048764099570cbb55 ]
On H3 ES1.x two bits in DPLLCR are used to select the DU input dot clock source. These are bits 20 and 21 for DU2, and bits 22 and 23 for DU1. On non-ES1.x, only the higher bits are used (bits 21 and 23), and the lower bits are reserved and should be set to 0.
The current code always sets the lower bits, even on non-ES1.x.
For both DU1 and DU2, on all SoC versions, when writing zeroes to those bits the input clock is DCLKIN, and thus there's no difference between ES1.x and non-ES1.x.
For DU1, writing 0b10 to the bits (or only writing the higher bit) results in using PLL0 as the input clock, so in this case there's also no difference between ES1.x and non-ES1.x.
However, for DU2, writing 0b10 to the bits results in using PLL0 as the input clock on ES1.x, whereas on non-ES1.x it results in using PLL1. On ES1.x you need to write 0b11 to select PLL1.
The current code always writes 0b11 to PLCS0 field to select PLL1 on all SoC versions, which works but causes an illegal (in the sense of not allowed by the documentation) write to a reserved bit field.
To remove the illegal bit write on PLSC0 we need to handle the input dot clock selection differently for ES1.x and non-ES1.x.
Add a new quirk, RCAR_DU_QUIRK_H3_ES1_PLL, for this. This way we can always set the bit 21 on PLSC0 when choosing the PLL as the source clock, and additionally set the bit 20 when on ES1.x.
Signed-off-by: Tomi Valkeinen tomi.valkeinen+renesas@ideasonboard.com Reviewed-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 23 ++++++++++++++++++++--- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 3 ++- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_regs.h | 8 ++------ 4 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index f2d3266509cc1..b7dd59fe119e6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -245,13 +245,30 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m) | DPLLCR_STBY;
- if (rcrtc->index == 1) + if (rcrtc->index == 1) { dpllcr |= DPLLCR_PLCS1 | DPLLCR_INCS_DOTCLKIN1; - else - dpllcr |= DPLLCR_PLCS0 + } else { + dpllcr |= DPLLCR_PLCS0_PLL | DPLLCR_INCS_DOTCLKIN0;
+ /* + * On ES2.x we have a single mux controlled via bit 21, + * which selects between DCLKIN source (bit 21 = 0) and + * a PLL source (bit 21 = 1), where the PLL is always + * PLL1. + * + * On ES1.x we have an additional mux, controlled + * via bit 20, for choosing between PLL0 (bit 20 = 0) + * and PLL1 (bit 20 = 1). We always want to use PLL1, + * so on ES1.x, in addition to setting bit 21, we need + * to set the bit 20. + */ + + if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PLL) + dpllcr |= DPLLCR_PLCS0_H3ES1X_PLL1; + } + rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
escr = ESCR_DCLKSEL_DCLKIN | div; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 0dada0646b2eb..6381578c4db58 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -394,7 +394,8 @@ static const struct rcar_du_device_info rcar_du_r8a7795_es1_info = { | RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_INTERLACED | RCAR_DU_FEATURE_TVM_SYNC, - .quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY, + .quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY + | RCAR_DU_QUIRK_H3_ES1_PLL, .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), .routes = { /* diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index df87ccab146f4..acc3673fefe18 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -35,6 +35,7 @@ struct rcar_du_device;
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY BIT(1) /* H3 ES1 has pclk stability issue */ +#define RCAR_DU_QUIRK_H3_ES1_PLL BIT(2) /* H3 ES1 PLL setup differs from non-ES1 */
enum rcar_du_output { RCAR_DU_OUTPUT_DPAD0, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index c1bcb0e8b5b4e..789ae9285108e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -283,12 +283,8 @@ #define DPLLCR 0x20044 #define DPLLCR_CODE (0x95 << 24) #define DPLLCR_PLCS1 (1 << 23) -/* - * PLCS0 is bit 21, but H3 ES1.x requires bit 20 to be set as well. As bit 20 - * isn't implemented by other SoC in the Gen3 family it can safely be set - * unconditionally. - */ -#define DPLLCR_PLCS0 (3 << 20) +#define DPLLCR_PLCS0_PLL (1 << 21) +#define DPLLCR_PLCS0_H3ES1X_PLL1 (1 << 20) #define DPLLCR_CLKE (1 << 18) #define DPLLCR_FDPLL(n) ((n) << 12) #define DPLLCR_N(n) ((n) << 5)
From: Wayne Lin Wayne.Lin@amd.com
[ Upstream commit d987150b539271b0394f24c1c648d2846662adb4 ]
[why & how] __drm_dbg() parameter set format is wrong and not aligned with the format under CONFIG_DRM_USE_DYNAMIC_DEBUG is on. Fix it.
Signed-off-by: Wayne Lin Wayne.Lin@amd.com Signed-off-by: Harry Wentland harry.wentland@amd.com Acked-by: Harry Wentland harry.wentland@amd.com Reviewed-by: Lyude Paul lyude@redhat.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- include/drm/drm_print.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index a44fb7ef257f6..094ded23534c7 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -521,7 +521,7 @@ __printf(1, 2) void __drm_err(const char *format, ...);
#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) -#define __drm_dbg(fmt, ...) ___drm_dbg(NULL, fmt, ##__VA_ARGS__) +#define __drm_dbg(cat, fmt, ...) ___drm_dbg(NULL, cat, fmt, ##__VA_ARGS__) #else #define __drm_dbg(cat, fmt, ...) \ _dynamic_func_call_cls(cat, fmt, ___drm_dbg, \
From: Roman Li roman.li@amd.com
[ Upstream commit 40e9f3f067bc6fb47b878f8ba0a9cc7b93abbf49 ]
[Why] After enabling S/G on dcn314 a screen corruption may be observed. HostVM flag should be set in S/G mode to be included in DML calculations.
[How] In S/G mode gpu_vm_support flag is set. Use its value to init is_hvm_enabled.
Reviewed-by: Nicholas Kazlauskas Nicholas.Kazlauskas@amd.com Acked-by: Alan Liu HaoPing.Liu@amd.com Signed-off-by: Roman Li roman.li@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/amdgpu_dm/amdgpu_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 6028e332e35d9..ed74cc7403980 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1248,7 +1248,7 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ pa_config->gart_config.page_table_end_addr = page_table_end.quad_part << 12; pa_config->gart_config.page_table_base_addr = page_table_base.quad_part;
- pa_config->is_hvm_enabled = 0; + pa_config->is_hvm_enabled = adev->mode_info.gpu_vm_support;
}
From: Moti Haimovski mhaimovski@habana.ai
[ Upstream commit 2a0a839b6a28f7c4c528bb75b740c7f38ef79a37 ]
This commit attaches the PCI device address to driver fatal messages in order to ease debugging in multi-device setups.
Signed-off-by: Moti Haimovski mhaimovski@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/misc/habanalabs/common/device.c | 38 ++++++++++++++++--------- 1 file changed, 25 insertions(+), 13 deletions(-)
diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 233d8b46c831f..e0dca445abf14 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1458,7 +1458,8 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) if (rc == -EBUSY) { if (hdev->device_fini_pending) { dev_crit(hdev->dev, - "Failed to kill all open processes, stopping hard reset\n"); + "%s Failed to kill all open processes, stopping hard reset\n", + dev_name(&(hdev)->pdev->dev)); goto out_err; }
@@ -1468,7 +1469,8 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
if (rc) { dev_crit(hdev->dev, - "Failed to kill all open processes, stopping hard reset\n"); + "%s Failed to kill all open processes, stopping hard reset\n", + dev_name(&(hdev)->pdev->dev)); goto out_err; }
@@ -1519,14 +1521,16 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) * ensure driver puts the driver in a unusable state */ dev_crit(hdev->dev, - "Consecutive FW fatal errors received, stopping hard reset\n"); + "%s Consecutive FW fatal errors received, stopping hard reset\n", + dev_name(&(hdev)->pdev->dev)); rc = -EIO; goto out_err; }
if (hdev->kernel_ctx) { dev_crit(hdev->dev, - "kernel ctx was alive during hard reset, something is terribly wrong\n"); + "%s kernel ctx was alive during hard reset, something is terribly wrong\n", + dev_name(&(hdev)->pdev->dev)); rc = -EBUSY; goto out_err; } @@ -1645,9 +1649,13 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) hdev->reset_info.needs_reset = false;
if (hard_reset) - dev_info(hdev->dev, "Successfully finished resetting the device\n"); + dev_info(hdev->dev, + "Successfully finished resetting the %s device\n", + dev_name(&(hdev)->pdev->dev)); else - dev_dbg(hdev->dev, "Successfully finished resetting the device\n"); + dev_dbg(hdev->dev, + "Successfully finished resetting the %s device\n", + dev_name(&(hdev)->pdev->dev));
if (hard_reset) { hdev->reset_info.hard_reset_cnt++; @@ -1681,7 +1689,9 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) hdev->reset_info.in_compute_reset = 0;
if (hard_reset) { - dev_err(hdev->dev, "Failed to reset! Device is NOT usable\n"); + dev_err(hdev->dev, + "%s Failed to reset! Device is NOT usable\n", + dev_name(&(hdev)->pdev->dev)); hdev->reset_info.hard_reset_cnt++; } else if (reset_upon_device_release) { spin_unlock(&hdev->reset_info.lock); @@ -2004,7 +2014,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) }
dev_notice(hdev->dev, - "Successfully added device to habanalabs driver\n"); + "Successfully added device %s to habanalabs driver\n", + dev_name(&(hdev)->pdev->dev));
hdev->init_done = true;
@@ -2053,11 +2064,11 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) device_cdev_sysfs_add(hdev); if (hdev->pdev) dev_err(&hdev->pdev->dev, - "Failed to initialize hl%d. Device is NOT usable !\n", - hdev->cdev_idx); + "Failed to initialize hl%d. Device %s is NOT usable !\n", + hdev->cdev_idx, dev_name(&(hdev)->pdev->dev)); else - pr_err("Failed to initialize hl%d. Device is NOT usable !\n", - hdev->cdev_idx); + pr_err("Failed to initialize hl%d. Device %s is NOT usable !\n", + hdev->cdev_idx, dev_name(&(hdev)->pdev->dev));
return rc; } @@ -2113,7 +2124,8 @@ void hl_device_fini(struct hl_device *hdev)
if (ktime_compare(ktime_get(), timeout) > 0) { dev_crit(hdev->dev, - "Failed to remove device because reset function did not finish\n"); + "%s Failed to remove device because reset function did not finish\n", + dev_name(&(hdev)->pdev->dev)); return; } }
From: farah kassabri fkassabri@habana.ai
[ Upstream commit ac5af9900f82b7034de7c9eb1d70d030ba325607 ]
Protect re-using the same timestamp buffer record before actually adding it to the to interrupt wait list. Mark ts buff offset as in use in the spinlock protection area of the interrupt wait list to avoid getting in the re-use section in ts_buff_get_kernel_ts_record before adding the node to the list. this scenario might happen when multiple threads are racing on same offset and one thread could set data in the ts buff in ts_buff_get_kernel_ts_record then the other thread takes over and get to ts_buff_get_kernel_ts_record and we will try to re-use the same ts buff offset then we will try to delete a non existing node from the list.
Signed-off-by: farah kassabri fkassabri@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 --- .../habanalabs/common/command_submission.c | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index fa05770865c65..1071bf492e423 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -3091,19 +3091,18 @@ static int ts_buff_get_kernel_ts_record(struct hl_mmap_mem_buf *buf, goto start_over; } } else { + /* Fill up the new registration node info */ + requested_offset_record->ts_reg_info.buf = buf; + requested_offset_record->ts_reg_info.cq_cb = cq_cb; + requested_offset_record->ts_reg_info.timestamp_kernel_addr = + (u64 *) ts_buff->user_buff_address + ts_offset; + requested_offset_record->cq_kernel_addr = + (u64 *) cq_cb->kernel_address + cq_offset; + requested_offset_record->cq_target_value = target_value; + spin_unlock_irqrestore(wait_list_lock, flags); }
- /* Fill up the new registration node info */ - requested_offset_record->ts_reg_info.in_use = 1; - requested_offset_record->ts_reg_info.buf = buf; - requested_offset_record->ts_reg_info.cq_cb = cq_cb; - requested_offset_record->ts_reg_info.timestamp_kernel_addr = - (u64 *) ts_buff->user_buff_address + ts_offset; - requested_offset_record->cq_kernel_addr = - (u64 *) cq_cb->kernel_address + cq_offset; - requested_offset_record->cq_target_value = target_value; - *pend = requested_offset_record;
dev_dbg(buf->mmg->dev, "Found available node in TS kernel CB %p\n", @@ -3151,7 +3150,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, goto put_cq_cb; }
- /* Find first available record */ + /* get ts buffer record */ rc = ts_buff_get_kernel_ts_record(buf, cq_cb, ts_offset, cq_counters_offset, target_value, &interrupt->wait_list_lock, &pend); @@ -3199,7 +3198,19 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, * Note that we cannot have sorted list by target value, * in order to shorten the list pass loop, since * same list could have nodes for different cq counter handle. + * Note: + * Mark ts buff offset as in use here in the spinlock protection area + * to avoid getting in the re-use section in ts_buff_get_kernel_ts_record + * before adding the node to the list. this scenario might happen when + * multiple threads are racing on same offset and one thread could + * set the ts buff in ts_buff_get_kernel_ts_record then the other thread + * takes over and get to ts_buff_get_kernel_ts_record and then we will try + * to re-use the same ts buff offset, and will try to delete a non existing + * node from the list. */ + if (register_ts_record) + pend->ts_reg_info.in_use = 1; + list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head); spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
From: Jakob Koschel jkl820.git@gmail.com
[ Upstream commit 6b219431037bf98c9efd49716aea9b68440477a3 ]
In order to debug the kernel successfully with gdb you need to run 'make scripts_gdb' nowadays.
This was changed with the following commit:
Commit 67274c083438340ad16c ("scripts/gdb: delay generation of gdb constants.py")
In order to have a complete guide for beginners this remark should be added to the offial documentation.
Signed-off-by: Jakob Koschel jkl820.git@gmail.com Link: https://lore.kernel.org/r/20230112-documentation-gdb-v2-1-292785c43dc9@gmail... Signed-off-by: Jonathan Corbet corbet@lwn.net Signed-off-by: Sasha Levin sashal@kernel.org --- Documentation/dev-tools/gdb-kernel-debugging.rst | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/Documentation/dev-tools/gdb-kernel-debugging.rst b/Documentation/dev-tools/gdb-kernel-debugging.rst index 8e0f1fe8d17ad..895285c037c72 100644 --- a/Documentation/dev-tools/gdb-kernel-debugging.rst +++ b/Documentation/dev-tools/gdb-kernel-debugging.rst @@ -39,6 +39,10 @@ Setup this mode. In this case, you should build the kernel with CONFIG_RANDOMIZE_BASE disabled if the architecture supports KASLR.
+- Build the gdb scripts (required on kernels v5.1 and above):: + + make scripts_gdb + - Enable the gdb stub of QEMU/KVM, either
- at VM startup time by appending "-s" to the QEMU command line
From: Marijn Suijten marijn.suijten@somainline.org
[ Upstream commit a7efe60e36b9c0e966d7f82ac90a89b591d984e9 ]
Add missing DSC hardware block register ranges to the snapshot utility to include them in dmesg (on MSM_DISP_SNAPSHOT_DUMP_IN_CONSOLE) and the kms debugfs file.
Signed-off-by: Marijn Suijten marijn.suijten@somainline.org Reviewed-by: Neil Armstrong neil.armstrong@linaro.org Reviewed-by: Abhinav Kumar quic_abhinavk@quicinc.com Patchwork: https://patchwork.freedesktop.org/patch/520175/ Link: https://lore.kernel.org/r/20230125101412.216924-1-marijn.suijten@somainline.... Signed-off-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 5e6e2626151e8..b7901b666612a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -942,6 +942,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len, dpu_kms->mmio + cat->mdp[0].base, "top");
+ /* dump DSC sub-blocks HW regs info */ + for (i = 0; i < cat->dsc_count; i++) + msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, + dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i); + pm_runtime_put_sync(&dpu_kms->pdev->dev); }
From: ê°•ì‹ í˜• s47.kang@samsung.com
[ Upstream commit aa9ff6a4955fdba02b54fbc4386db876603703b7 ]
If panic_on_warn is set and compress stream(DPCM) is started, then kernel panic occurred because card->pcm_mutex isn't held appropriately. In the following functions, warning were issued at this line "snd_soc_dpcm_mutex_assert_held".
static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream) { ... snd_soc_dpcm_mutex_assert_held(fe); ... }
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { ... snd_soc_dpcm_mutex_assert_held(fe); ... }
void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd, int stream, int action) { ... snd_soc_dpcm_mutex_assert_held(rtd); ... }
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) { ... snd_soc_dpcm_mutex_assert_held(fe); ... }
These functions are called by soc_compr_set_params_fe, soc_compr_open_fe and soc_compr_free_fe without pcm_mutex locking. And this is call stack.
[ 414.527841][ T2179] pc : dpcm_process_paths+0x5a4/0x750 [ 414.527848][ T2179] lr : dpcm_process_paths+0x37c/0x750 [ 414.527945][ T2179] Call trace: [ 414.527949][ T2179] dpcm_process_paths+0x5a4/0x750 [ 414.527955][ T2179] soc_compr_open_fe+0xb0/0x2cc [ 414.527972][ T2179] snd_compr_open+0x180/0x248 [ 414.527981][ T2179] snd_open+0x15c/0x194 [ 414.528003][ T2179] chrdev_open+0x1b0/0x220 [ 414.528023][ T2179] do_dentry_open+0x30c/0x594 [ 414.528045][ T2179] vfs_open+0x34/0x44 [ 414.528053][ T2179] path_openat+0x914/0xb08 [ 414.528062][ T2179] do_filp_open+0xc0/0x170 [ 414.528068][ T2179] do_sys_openat2+0x94/0x18c [ 414.528076][ T2179] __arm64_sys_openat+0x78/0xa4 [ 414.528084][ T2179] invoke_syscall+0x48/0x10c [ 414.528094][ T2179] el0_svc_common+0xbc/0x104 [ 414.528099][ T2179] do_el0_svc+0x34/0xd8 [ 414.528103][ T2179] el0_svc+0x34/0xc4 [ 414.528125][ T2179] el0t_64_sync_handler+0x8c/0xfc [ 414.528133][ T2179] el0t_64_sync+0x1a0/0x1a4 [ 414.528142][ T2179] Kernel panic - not syncing: panic_on_warn set ...
So, I reposition and add pcm_mutex to resolve lockdep error.
Signed-off-by: Shinhyung Kang s47.kang@samsung.com Link: https://lore.kernel.org/r/016401d90ac4%247b6848c0%247238da40%24@samsung.com Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/soc-compress.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 870f13e1d389c..7bce5088b4554 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -149,6 +149,8 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (ret < 0) goto be_err;
+ mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); + /* calculate valid and active FE <-> BE dpcms */ dpcm_process_paths(fe, stream, &list, 1); fe->dpcm[stream].runtime = fe_substream->runtime; @@ -184,7 +186,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
- mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); snd_soc_runtime_activate(fe, stream); mutex_unlock(&fe->card->pcm_mutex);
@@ -215,7 +216,6 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); snd_soc_runtime_deactivate(fe, stream); - mutex_unlock(&fe->card->pcm_mutex);
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
@@ -234,6 +234,8 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
dpcm_be_disconnect(fe, stream);
+ mutex_unlock(&fe->card->pcm_mutex); + fe->dpcm[stream].runtime = NULL;
snd_soc_link_compr_shutdown(cstream, 0); @@ -409,8 +411,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, ret = snd_soc_link_compr_set_params(cstream); if (ret < 0) goto out; - + mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); + mutex_unlock(&fe->card->pcm_mutex); fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
out:
From: Kees Cook keescook@chromium.org
[ Upstream commit b3bcedc0402fcdc5c8624c433562d9d1882749d8 ]
Walking the dram->cs array was seen as accesses beyond the first array item by the compiler. Instead, use the array index directly. This allows for run-time bounds checking under CONFIG_UBSAN_BOUNDS as well. Seen with GCC 13 with -fstrict-flex-arrays:
../sound/soc/kirkwood/kirkwood-dma.c: In function 'kirkwood_dma_conf_mbus_windows.constprop': ../sound/soc/kirkwood/kirkwood-dma.c:90:24: warning: array subscript 0 is outside array bounds of 'const struct mbus_dram_window[0]' [-Warray-bounds=] 90 | if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) { | ~~^~~~~~
Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Cc: Jaroslav Kysela perex@perex.cz Cc: Takashi Iwai tiwai@suse.com Cc: alsa-devel@alsa-project.org Signed-off-by: Kees Cook keescook@chromium.org Link: https://lore.kernel.org/r/20230127224128.never.410-kees@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/kirkwood/kirkwood-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 700a18561a940..640cebd2983e2 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -86,7 +86,7 @@ kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
/* try to find matching cs for current dma address */ for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; + const struct mbus_dram_window *cs = &dram->cs[i]; if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) { writel(cs->base & 0xffff0000, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
From: Kees Cook keescook@chromium.org
[ Upstream commit 4fd8bcec5fd7c0d586206fa2f42bd67b06cdaa7e ]
Explicitly bounds-check the id before accessing the opmode array. Seen with GCC 13:
../drivers/regulator/max77802-regulator.c: In function 'max77802_enable': ../drivers/regulator/max77802-regulator.c:217:29: warning: array subscript [0, 41] is outside array bounds of 'unsigned int[42]' [-Warray-bounds=] 217 | if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) | ~~~~~~~~~~~~~~~~^~~~ ../drivers/regulator/max77802-regulator.c:62:22: note: while referencing 'opmode' 62 | unsigned int opmode[MAX77802_REG_MAX]; | ^~~~~~
Cc: Javier Martinez Canillas javier@dowhile0.org Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Signed-off-by: Kees Cook keescook@chromium.org Acked-by: Javier Martinez Canillas javierm@redhat.com Link: https://lore.kernel.org/r/20230127225203.never.864-kees@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/regulator/max77802-regulator.c | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index 21e0eb0f43f94..befe5f319819b 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -94,9 +94,11 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev) { unsigned int val = MAX77802_OFF_PWRREQ; struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + unsigned int id = rdev_get_id(rdev); int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) + return -EINVAL; max77802->opmode[id] = val; return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, val << shift); @@ -110,7 +112,7 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev) static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + unsigned int id = rdev_get_id(rdev); unsigned int val; int shift = max77802_get_opmode_shift(id);
@@ -127,6 +129,9 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) return -EINVAL; }
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) + return -EINVAL; + max77802->opmode[id] = val; return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, val << shift); @@ -135,8 +140,10 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned max77802_get_mode(struct regulator_dev *rdev) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + unsigned int id = rdev_get_id(rdev);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) + return -EINVAL; return max77802_map_mode(max77802->opmode[id]); }
@@ -160,10 +167,13 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + unsigned int id = rdev_get_id(rdev); unsigned int val; int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) + return -EINVAL; + /* * If the regulator has been disabled for suspend * then is invalid to try setting a suspend mode. @@ -209,9 +219,11 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev, static int max77802_enable(struct regulator_dev *rdev) { struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + unsigned int id = rdev_get_id(rdev); int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) + return -EINVAL; if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
@@ -495,7 +507,7 @@ static int max77802_pmic_probe(struct platform_device *pdev)
for (i = 0; i < MAX77802_REG_MAX; i++) { struct regulator_dev *rdev; - int id = regulators[i].id; + unsigned int id = regulators[i].id; int shift = max77802_get_opmode_shift(id); int ret;
@@ -513,10 +525,12 @@ static int max77802_pmic_probe(struct platform_device *pdev) * the hardware reports OFF as the regulator operating mode. * Default to operating mode NORMAL in that case. */ - if (val == MAX77802_STATUS_OFF) - max77802->opmode[id] = MAX77802_OPMODE_NORMAL; - else - max77802->opmode[id] = val; + if (id < ARRAY_SIZE(max77802->opmode)) { + if (val == MAX77802_STATUS_OFF) + max77802->opmode[id] = MAX77802_OPMODE_NORMAL; + else + max77802->opmode[id] = val; + }
rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config);
From: Kees Cook keescook@chromium.org
[ Upstream commit e314e15a0b58f9d051c00b25951073bcdae61953 ]
The compiler has no way to know if "id" is within the array bounds of the regulators array. Add a check for this and a build-time check that the regulators and reg_voltage_map arrays are sized the same. Seen with GCC 13:
../drivers/regulator/s5m8767.c: In function 's5m8767_pmic_probe': ../drivers/regulator/s5m8767.c:936:35: warning: array subscript [0, 36] is outside array bounds of 'struct regulator_desc[37]' [-Warray-bounds=] 936 | regulators[id].vsel_reg = | ~~~~~~~~~~^~~~
Cc: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Cc: Liam Girdwood lgirdwood@gmail.com Cc: Mark Brown broonie@kernel.org Cc: linux-samsung-soc@vger.kernel.org Signed-off-by: Kees Cook keescook@chromium.org Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20230128005358.never.313-kees@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/regulator/s5m8767.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 35269f9982105..754c6fcc6e642 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -923,10 +923,14 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
for (i = 0; i < pdata->num_regulators; i++) { const struct sec_voltage_desc *desc; - int id = pdata->regulators[i].id; + unsigned int id = pdata->regulators[i].id; int enable_reg, enable_val; struct regulator_dev *rdev;
+ BUILD_BUG_ON(ARRAY_SIZE(regulators) != ARRAY_SIZE(reg_voltage_map)); + if (WARN_ON_ONCE(id >= ARRAY_SIZE(regulators))) + continue; + desc = reg_voltage_map[id]; if (desc) { regulators[id].n_voltages =
From: Vitaly Prosyak vitaly.prosyak@amd.com
[ Upstream commit 39934d3ed5725c5e3570ed1b67f612f1ea60ce03 ]
This reverts commit fac53471d0ea9693d314aa2df08d62b2e7e3a0f8. The following change: move the drm_dev_unplug call after amdgpu_driver_unload_kms in amdgpu_pci_remove. The reason is the following: amdgpu_pci_remove calls drm_dev_unregister and it should be called first to ensure userspace can't access the device instance anymore. If we call drm_dev_unplug after amdgpu_driver_unload_kms then we observe IGT PCI software unplug test failure (kernel hung) for all ASICs. This is how this regression was found.
After this revert, the following commands do work not, but it would be fixed in the next commit: - sudo modprobe -r amdgpu - sudo modprobe amdgpu
Signed-off-by: Vitaly Prosyak vitaly.prosyak@amd.com Reviewed-by Alex Deucher alexander.deucher@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_device.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a21b3f66fd708..824b0b356b3ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4012,7 +4012,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
amdgpu_gart_dummy_page_fini(adev);
- amdgpu_device_unmap_mmio(adev); + if (drm_dev_is_unplugged(adev_to_drm(adev))) + amdgpu_device_unmap_mmio(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 2e5d78b6635c4..dfbeef2c4a9e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2226,6 +2226,8 @@ amdgpu_pci_remove(struct pci_dev *pdev) struct drm_device *dev = pci_get_drvdata(pdev); struct amdgpu_device *adev = drm_to_adev(dev);
+ drm_dev_unplug(dev); + if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); @@ -2265,8 +2267,6 @@ amdgpu_pci_remove(struct pci_dev *pdev)
amdgpu_driver_unload_kms(dev);
- drm_dev_unplug(dev); - /* * Flush any in flight DMA operations from device. * Clear the Bus Master Enable bit and then wait on the PCIe Device
From: Vladimir Stempen vladimir.stempen@amd.com
[ Upstream commit 972243f973eb0821084e5833d5f7f4ed025f42da ]
[Why] Currently we set FCLK p-state change watermark calculated based on dummy p-state latency when UCLK p-state is not supported
[How] Calculate FCLK p-state change watermark based on on FCLK pstate change latency in case UCLK p-state is not supported
Reviewed-by: Nevenko Stupar Nevenko.Stupar@amd.com Acked-by: Alex Hung alex.hung@amd.com Signed-off-by: Vladimir Stempen vladimir.stempen@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/dcn32/dcn32_fpu.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index d90216d2fe3a8..04cc96e700981 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1963,6 +1963,10 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context, */ context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0; + /* Calculate FCLK p-state change watermark based on FCLK pstate change latency in case + * UCLK p-state is not supported, to avoid underflow in case FCLK pstate is supported + */ + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; } else { /* Set A: * All clocks min.
From: Andreas Gruenbacher agruenba@redhat.com
[ Upstream commit b66f723bb552ad59c2acb5d45ea45c890f84498b ]
In gfs2_make_fs_rw(), make sure to call gfs2_consist() to report an inconsistency and mark the filesystem as withdrawn when gfs2_find_jhead() fails.
At the end of gfs2_make_fs_rw(), when we discover that the filesystem has been withdrawn, make sure we report an error. This also replaces the gfs2_withdrawn() check after gfs2_find_jhead().
Reported-by: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Cc: syzbot+f51cb4b9afbd87ec06f2@syzkaller.appspotmail.com Signed-off-by: Andreas Gruenbacher agruenba@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/gfs2/super.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 011f9e7660ef8..2015bd05cba10 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -138,8 +138,10 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) return -EIO;
error = gfs2_find_jhead(sdp->sd_jdesc, &head, false); - if (error || gfs2_withdrawn(sdp)) + if (error) { + gfs2_consist(sdp); return error; + }
if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { gfs2_consist(sdp); @@ -151,7 +153,9 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) gfs2_log_pointers_init(sdp, head.lh_blkno);
error = gfs2_quota_init(sdp); - if (!error && !gfs2_withdrawn(sdp)) + if (!error && gfs2_withdrawn(sdp)) + error = -EIO; + if (!error) set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); return error; }
From: Robin Murphy robin.murphy@arm.com
[ Upstream commit 6d03bbff456befeccdd4d663177c4d6c75d0c4ff ]
Coretemp's platform driver is unconventional. All the real work is done globally by the initcall and CPU hotplug notifiers, while the "driver" effectively just wraps an allocation and the registration of the hwmon interface in a long-winded round-trip through the driver core. The whole logic of dynamically creating and destroying platform devices to bring the interfaces up and down is error prone, since it assumes platform_device_add() will synchronously bind the driver and set drvdata before it returns, thus results in a NULL dereference if drivers_autoprobe is turned off for the platform bus. Furthermore, the unusual approach of doing that from within a CPU hotplug notifier, already commented in the code that it deadlocks suspend, also causes lockdep issues for other drivers or subsystems which may want to legitimately register a CPU hotplug notifier from a platform bus notifier.
All of these issues can be solved by ripping this unusual behaviour out completely, simply tying the platform devices to the lifetime of the module itself, and directly managing the hwmon interfaces from the hotplug notifiers. There is a slight user-visible change in that /sys/bus/platform/drivers/coretemp will no longer appear, and /sys/devices/platform/coretemp.n will remain present if package n is hotplugged off, but hwmon users should really only be looking for the presence of the hwmon interfaces, whose behaviour remains unchanged.
Link: https://lore.kernel.org/lkml/20220922101036.87457-1-janusz.krzysztofik@linux... Link: https://gitlab.freedesktop.org/drm/intel/issues/6641 Signed-off-by: Robin Murphy robin.murphy@arm.com Signed-off-by: Janusz Krzysztofik janusz.krzysztofik@linux.intel.com Link: https://lore.kernel.org/r/20230103114620.15319-1-janusz.krzysztofik@linux.in... Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/coretemp.c | 128 ++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 70 deletions(-)
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 9bee4d33fbdf0..baaf8af4cb443 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -550,66 +550,49 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx) ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO); }
-static int coretemp_probe(struct platform_device *pdev) +static int coretemp_device_add(int zoneid) { - struct device *dev = &pdev->dev; + struct platform_device *pdev; struct platform_data *pdata; + int err;
/* Initialize the per-zone data structures */ - pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM;
- pdata->pkg_id = pdev->id; + pdata->pkg_id = zoneid; ida_init(&pdata->ida); - platform_set_drvdata(pdev, pdata);
- pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, - pdata, NULL); - return PTR_ERR_OR_ZERO(pdata->hwmon_dev); -} - -static int coretemp_remove(struct platform_device *pdev) -{ - struct platform_data *pdata = platform_get_drvdata(pdev); - int i; + pdev = platform_device_alloc(DRVNAME, zoneid); + if (!pdev) { + err = -ENOMEM; + goto err_free_pdata; + }
- for (i = MAX_CORE_DATA - 1; i >= 0; --i) - if (pdata->core_data[i]) - coretemp_remove_core(pdata, i); + err = platform_device_add(pdev); + if (err) + goto err_put_dev;
- ida_destroy(&pdata->ida); + platform_set_drvdata(pdev, pdata); + zone_devices[zoneid] = pdev; return 0; -}
-static struct platform_driver coretemp_driver = { - .driver = { - .name = DRVNAME, - }, - .probe = coretemp_probe, - .remove = coretemp_remove, -}; +err_put_dev: + platform_device_put(pdev); +err_free_pdata: + kfree(pdata); + return err; +}
-static struct platform_device *coretemp_device_add(unsigned int cpu) +static void coretemp_device_remove(int zoneid) { - int err, zoneid = topology_logical_die_id(cpu); - struct platform_device *pdev; - - if (zoneid < 0) - return ERR_PTR(-ENOMEM); - - pdev = platform_device_alloc(DRVNAME, zoneid); - if (!pdev) - return ERR_PTR(-ENOMEM); - - err = platform_device_add(pdev); - if (err) { - platform_device_put(pdev); - return ERR_PTR(err); - } + struct platform_device *pdev = zone_devices[zoneid]; + struct platform_data *pdata = platform_get_drvdata(pdev);
- zone_devices[zoneid] = pdev; - return pdev; + ida_destroy(&pdata->ida); + kfree(pdata); + platform_device_unregister(pdev); }
static int coretemp_cpu_online(unsigned int cpu) @@ -633,7 +616,10 @@ static int coretemp_cpu_online(unsigned int cpu) if (!cpu_has(c, X86_FEATURE_DTHERM)) return -ENODEV;
- if (!pdev) { + pdata = platform_get_drvdata(pdev); + if (!pdata->hwmon_dev) { + struct device *hwmon; + /* Check the microcode version of the CPU */ if (chk_ucode_version(cpu)) return -EINVAL; @@ -644,9 +630,11 @@ static int coretemp_cpu_online(unsigned int cpu) * online. So, initialize per-pkg data structures and * then bring this core online. */ - pdev = coretemp_device_add(cpu); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); + hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME, + pdata, NULL); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + pdata->hwmon_dev = hwmon;
/* * Check whether pkgtemp support is available. @@ -656,7 +644,6 @@ static int coretemp_cpu_online(unsigned int cpu) coretemp_add_core(pdev, cpu, 1); }
- pdata = platform_get_drvdata(pdev); /* * Check whether a thread sibling is already online. If not add the * interface for this CPU core. @@ -675,18 +662,14 @@ static int coretemp_cpu_offline(unsigned int cpu) struct temp_data *tdata; int i, indx = -1, target;
- /* - * Don't execute this on suspend as the device remove locks - * up the machine. - */ + /* No need to tear down any interfaces for suspend */ if (cpuhp_tasks_frozen) return 0;
/* If the physical CPU device does not exist, just return */ - if (!pdev) - return 0; - pd = platform_get_drvdata(pdev); + if (!pd->hwmon_dev) + return 0;
for (i = 0; i < NUM_REAL_CORES; i++) { if (pd->cpu_map[i] == topology_core_id(cpu)) { @@ -718,13 +701,14 @@ static int coretemp_cpu_offline(unsigned int cpu) }
/* - * If all cores in this pkg are offline, remove the device. This - * will invoke the platform driver remove function, which cleans up - * the rest. + * If all cores in this pkg are offline, remove the interface. */ + tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; if (cpumask_empty(&pd->cpumask)) { - zone_devices[topology_logical_die_id(cpu)] = NULL; - platform_device_unregister(pdev); + if (tdata) + coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO); + hwmon_device_unregister(pd->hwmon_dev); + pd->hwmon_dev = NULL; return 0; }
@@ -732,7 +716,6 @@ static int coretemp_cpu_offline(unsigned int cpu) * Check whether this core is the target for the package * interface. We need to assign it to some other cpu. */ - tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; if (tdata && tdata->cpu == cpu) { target = cpumask_first(&pd->cpumask); mutex_lock(&tdata->update_lock); @@ -751,7 +734,7 @@ static enum cpuhp_state coretemp_hp_online;
static int __init coretemp_init(void) { - int err; + int i, err;
/* * CPUID.06H.EAX[0] indicates whether the CPU has thermal @@ -767,20 +750,22 @@ static int __init coretemp_init(void) if (!zone_devices) return -ENOMEM;
- err = platform_driver_register(&coretemp_driver); - if (err) - goto outzone; + for (i = 0; i < max_zones; i++) { + err = coretemp_device_add(i); + if (err) + goto outzone; + }
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", coretemp_cpu_online, coretemp_cpu_offline); if (err < 0) - goto outdrv; + goto outzone; coretemp_hp_online = err; return 0;
-outdrv: - platform_driver_unregister(&coretemp_driver); outzone: + while (i--) + coretemp_device_remove(i); kfree(zone_devices); return err; } @@ -788,8 +773,11 @@ module_init(coretemp_init)
static void __exit coretemp_exit(void) { + int i; + cpuhp_remove_state(coretemp_hp_online); - platform_driver_unregister(&coretemp_driver); + for (i = 0; i < max_zones; i++) + coretemp_device_remove(i); kfree(zone_devices); } module_exit(coretemp_exit)
From: Denis Pauk pauk.denis@gmail.com
[ Upstream commit c3b3747d02f571da2543e719066a50dd966989d8 ]
New ASUS B650/B660/X670 boards firmware have not exposed WMI monitoring GUID and entrypoint method WMBD could be implemented for different device UID.
Implement the direct call to entrypoint method for monitoring the device UID of B550/X570 boards.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204807 Signed-off-by: Denis Pauk pauk.denis@gmail.com Co-developed-by: Ahmad Khalifa ahmad@khalifa.ws Signed-off-by: Ahmad Khalifa ahmad@khalifa.ws Link: https://lore.kernel.org/r/20230111212241.7456-1-pauk.denis@gmail.com [groeck: Fix multi-line formatting] Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/nct6775-platform.c | 98 ++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 30 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d3bccc8176c51..a5143d01b95f8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1508,7 +1508,7 @@ config SENSORS_NCT6775_CORE config SENSORS_NCT6775 tristate "Platform driver for Nuvoton NCT6775F and compatibles" depends on !PPC - depends on ACPI_WMI || ACPI_WMI=n + depends on ACPI || ACPI=n select HWMON_VID select SENSORS_NCT6775_CORE help diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index bf43f73dc835f..e5d4a79cd5f7d 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -17,7 +17,6 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/wmi.h>
#include "nct6775.h"
@@ -107,40 +106,50 @@ struct nct6775_sio_data { void (*sio_exit)(struct nct6775_sio_data *sio_data); };
-#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66" +#define ASUSWMI_METHOD "WMBD" #define ASUSWMI_METHODID_RSIO 0x5253494F #define ASUSWMI_METHODID_WSIO 0x5753494F #define ASUSWMI_METHODID_RHWM 0x5248574D #define ASUSWMI_METHODID_WHWM 0x5748574D #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE +#define ASUSWMI_DEVICE_HID "PNP0C14" +#define ASUSWMI_DEVICE_UID "ASUSWMI" + +#if IS_ENABLED(CONFIG_ACPI) +/* + * ASUS boards have only one device with WMI "WMBD" method and have provided + * access to only one SuperIO chip at 0x0290. + */ +static struct acpi_device *asus_acpi_dev; +#endif
static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) { -#if IS_ENABLED(CONFIG_ACPI_WMI) +#if IS_ENABLED(CONFIG_ACPI) + acpi_handle handle = acpi_device_handle(asus_acpi_dev); u32 args = bank | (reg << 8) | (val << 16); - struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + union acpi_object params[3]; + unsigned long long result; acpi_status status; - union acpi_object *obj; - u32 tmp = ASUSWMI_UNSUPPORTED_METHOD; - - status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0, - method_id, &input, &output);
+ params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = 0; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = method_id; + params[2].type = ACPI_TYPE_BUFFER; + params[2].buffer.length = sizeof(args); + params[2].buffer.pointer = (void *)&args; + input.count = 3; + input.pointer = params; + + status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result); if (ACPI_FAILURE(status)) return -EIO;
- obj = output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = obj->integer.value; - if (retval) - *retval = tmp; + *retval = (u32)result & 0xFFFFFFFF;
- kfree(obj); - - if (tmp == ASUSWMI_UNSUPPORTED_METHOD) - return -ENODEV; return 0; #else return -EOPNOTSUPP; @@ -1099,6 +1108,45 @@ static const char * const asus_wmi_boards[] = { "TUF GAMING Z490-PLUS (WI-FI)", };
+#if IS_ENABLED(CONFIG_ACPI) +/* + * Callback for acpi_bus_for_each_dev() to find the right device + * by _UID and _HID and return 1 to stop iteration. + */ +static int nct6775_asuswmi_device_match(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + const char *uid = acpi_device_uid(adev); + const char *hid = acpi_device_hid(adev); + + if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) { + asus_acpi_dev = adev; + return 1; + } + + return 0; +} +#endif + +static enum sensor_access nct6775_determine_access(const char *device_uid) +{ +#if IS_ENABLED(CONFIG_ACPI) + u8 tmp; + + acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid); + if (!asus_acpi_dev) + return access_direct; + + /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */ + if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { + pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp); + return access_asuswmi; + } +#endif + + return access_direct; +} + static int __init sensors_nct6775_platform_init(void) { int i, err; @@ -1109,7 +1157,6 @@ static int __init sensors_nct6775_platform_init(void) int sioaddr[2] = { 0x2e, 0x4e }; enum sensor_access access = access_direct; const char *board_vendor, *board_name; - u8 tmp;
err = platform_driver_register(&nct6775_driver); if (err) @@ -1122,15 +1169,8 @@ static int __init sensors_nct6775_platform_init(void) !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) { err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), board_name); - if (err >= 0) { - /* if reading chip id via WMI succeeds, use WMI */ - if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { - pr_info("Using Asus WMI to access %#x chip.\n", tmp); - access = access_asuswmi; - } else { - pr_err("Can't read ChipID by Asus WMI.\n"); - } - } + if (err >= 0) + access = nct6775_determine_access(ASUSWMI_DEVICE_UID); }
/*
From: Denis Pauk pauk.denis@gmail.com
[ Upstream commit e2e09989ccc21ad428d6393450add78584b143bd ]
Boards such as: "EX-B660M-V5 PRO D4", "PRIME B650-PLUS", "PRIME B650M-A", "PRIME B650M-A AX", "PRIME B650M-A II", "PRIME B650M-A WIFI", "PRIME B650M-A WIFI II", "PRIME B660M-A D4", "PRIME B660M-A WIFI D4", "PRIME X670-P", "PRIME X670-P WIFI", "PRIME X670E-PRO WIFI", "Pro B660M-C-D4", "ProArt B660-CREATOR D4", "ProArt X670E-CREATOR WIFI", "ROG CROSSHAIR X670E EXTREME", "ROG CROSSHAIR X670E GENE", "ROG CROSSHAIR X670E HERO", "ROG MAXIMUS XIII EXTREME GLACIAL", "ROG MAXIMUS Z690 EXTREME", "ROG MAXIMUS Z690 EXTREME GLACIAL", "ROG STRIX B650-A GAMING WIFI", "ROG STRIX B650E-E GAMING WIFI", "ROG STRIX B650E-F GAMING WIFI", "ROG STRIX B650E-I GAMING WIFI", "ROG STRIX B660-A GAMING WIFI D4", "ROG STRIX B660-F GAMING WIFI", "ROG STRIX B660-G GAMING WIFI", "ROG STRIX B660-I GAMING WIFI", "ROG STRIX X670E-A GAMING WIFI", "ROG STRIX X670E-E GAMING WIFI", "ROG STRIX X670E-F GAMING WIFI", "ROG STRIX X670E-I GAMING WIFI", "ROG STRIX Z590-A GAMING WIFI II", "ROG STRIX Z690-A GAMING WIFI D4", "TUF GAMING B650-PLUS", "TUF GAMING B650-PLUS WIFI", "TUF GAMING B650M-PLUS", "TUF GAMING B650M-PLUS WIFI", "TUF GAMING B660M-PLUS WIFI", "TUF GAMING X670E-PLUS", "TUF GAMING X670E-PLUS WIFI", "TUF GAMING Z590-PLUS WIFI", have got a NCT6799D chip, but by default there's no use of it because of resource conflict with WMI method.
This commit adds such boards to the monitoring list with new ACPI device UID.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204807 Signed-off-by: Denis Pauk pauk.denis@gmail.com Co-developed-by: Ahmad Khalifa ahmad@khalifa.ws Signed-off-by: Ahmad Khalifa ahmad@khalifa.ws Tested-by: Jeroen Beerstra jeroen@beerstra.org Tested-by: Slawomir Stepien sst@poczta.fm Link: https://lore.kernel.org/r/20230111212241.7456-2-pauk.denis@gmail.com Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hwmon/nct6775-platform.c | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index e5d4a79cd5f7d..76c6b564d7fc4 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -114,6 +114,7 @@ struct nct6775_sio_data { #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE #define ASUSWMI_DEVICE_HID "PNP0C14" #define ASUSWMI_DEVICE_UID "ASUSWMI" +#define ASUSMSI_DEVICE_UID "AsusMbSwInterface"
#if IS_ENABLED(CONFIG_ACPI) /* @@ -1108,6 +1109,52 @@ static const char * const asus_wmi_boards[] = { "TUF GAMING Z490-PLUS (WI-FI)", };
+static const char * const asus_msi_boards[] = { + "EX-B660M-V5 PRO D4", + "PRIME B650-PLUS", + "PRIME B650M-A", + "PRIME B650M-A AX", + "PRIME B650M-A II", + "PRIME B650M-A WIFI", + "PRIME B650M-A WIFI II", + "PRIME B660M-A D4", + "PRIME B660M-A WIFI D4", + "PRIME X670-P", + "PRIME X670-P WIFI", + "PRIME X670E-PRO WIFI", + "Pro B660M-C-D4", + "ProArt B660-CREATOR D4", + "ProArt X670E-CREATOR WIFI", + "ROG CROSSHAIR X670E EXTREME", + "ROG CROSSHAIR X670E GENE", + "ROG CROSSHAIR X670E HERO", + "ROG MAXIMUS XIII EXTREME GLACIAL", + "ROG MAXIMUS Z690 EXTREME", + "ROG MAXIMUS Z690 EXTREME GLACIAL", + "ROG STRIX B650-A GAMING WIFI", + "ROG STRIX B650E-E GAMING WIFI", + "ROG STRIX B650E-F GAMING WIFI", + "ROG STRIX B650E-I GAMING WIFI", + "ROG STRIX B660-A GAMING WIFI D4", + "ROG STRIX B660-F GAMING WIFI", + "ROG STRIX B660-G GAMING WIFI", + "ROG STRIX B660-I GAMING WIFI", + "ROG STRIX X670E-A GAMING WIFI", + "ROG STRIX X670E-E GAMING WIFI", + "ROG STRIX X670E-F GAMING WIFI", + "ROG STRIX X670E-I GAMING WIFI", + "ROG STRIX Z590-A GAMING WIFI II", + "ROG STRIX Z690-A GAMING WIFI D4", + "TUF GAMING B650-PLUS", + "TUF GAMING B650-PLUS WIFI", + "TUF GAMING B650M-PLUS", + "TUF GAMING B650M-PLUS WIFI", + "TUF GAMING B660M-PLUS WIFI", + "TUF GAMING X670E-PLUS", + "TUF GAMING X670E-PLUS WIFI", + "TUF GAMING Z590-PLUS WIFI", +}; + #if IS_ENABLED(CONFIG_ACPI) /* * Callback for acpi_bus_for_each_dev() to find the right device @@ -1171,6 +1218,11 @@ static int __init sensors_nct6775_platform_init(void) board_name); if (err >= 0) access = nct6775_determine_access(ASUSWMI_DEVICE_UID); + + err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards), + board_name); + if (err >= 0) + access = nct6775_determine_access(ASUSMSI_DEVICE_UID); }
/*
From: Claudiu Beznea claudiu.beznea@microchip.com
[ Upstream commit 1c4e5c470a56f7f7c649c0c70e603abc1eab15c4 ]
Use devm_kasprintf() instead of kasprintf() to avoid any potential leaks. At the moment drivers have no remove functionality thus there is no need for fixes tag.
Signed-off-by: Claudiu Beznea claudiu.beznea@microchip.com Link: https://lore.kernel.org/r/20230203132714.1931596-1-claudiu.beznea@microchip.... Signed-off-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/pinctrl/pinctrl-at91-pio4.c | 4 ++-- drivers/pinctrl/pinctrl-at91.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index 82b921fd630d5..7f193f2b1566a 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -1120,8 +1120,8 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
pin_desc[i].number = i; /* Pin naming convention: P(bank_name)(bank_pin_number). */ - pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d", - bank + 'A', line); + pin_desc[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "P%c%d", + bank + 'A', line);
group->name = group_names[i] = pin_desc[i].name; group->pin = pin_desc[i].number; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 81dbffab621fb..ff3b6a8a0b170 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1883,7 +1883,7 @@ static int at91_gpio_probe(struct platform_device *pdev) }
for (i = 0; i < chip->ngpio; i++) - names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i); + names[i] = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
chip->names = (const char *const *)names;
From: Wesley Chalmers Wesley.Chalmers@amd.com
[ Upstream commit 4f1b5e739dfd1edde33329e3f376733a131fb1ff ]
[WHY] Writing to DRR registers such as OTG_V_TOTAL_MIN on the same frame as a pipe commit can cause underflow.
[HOW] Defer all DPP adjustment requests till optimized_required is false.
Reviewed-by: Jun Lei Jun.Lei@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Wesley Chalmers Wesley.Chalmers@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 --- 1 file changed, 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 8c50457112649..c20e9f76f0213 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -992,8 +992,5 @@ void dcn30_prepare_bandwidth(struct dc *dc, dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
dcn20_prepare_bandwidth(dc, context); - - dc_dmub_srv_p_state_delegate(dc, - context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching, context); }
From: Wesley Chalmers Wesley.Chalmers@amd.com
[ Upstream commit 8f0d304d21b351d65e8c434c5399a40231876ba1 ]
[WHY] DRR and Pipe cannot be updated on the same frame, or else underflow will occur.
Reviewed-by: Jun Lei Jun.Lei@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Wesley Chalmers Wesley.Chalmers@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 | 15 +++++++++++++++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 3 ++- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c | 9 +++++++++ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h | 2 ++ .../drm/amd/display/dc/inc/hw/timing_generator.h | 1 + 5 files changed, 29 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 24015f8cac75a..af7aefe285ffd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3222,6 +3222,21 @@ static void commit_planes_for_stream(struct dc *dc,
dc_z10_restore(dc);
+ if (update_type == UPDATE_TYPE_FULL) { + /* wait for all double-buffer activity to clear on all pipes */ + int pipe_idx; + + for (pipe_idx = 0; pipe_idx < dc->res_pool->pipe_count; pipe_idx++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; + + if (!pipe_ctx->stream) + continue; + + if (pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear) + pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear(pipe_ctx->stream_res.tg); + } + } + if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) { /* Optimize seamless boot flag keeps clocks and watermarks high until * first flip. After first flip, optimization is required to lower diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 88ac5f6f4c96c..0b37bb0e184b2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -519,7 +519,8 @@ struct dcn_optc_registers { type OTG_CRC_DATA_STREAM_COMBINE_MODE;\ type OTG_CRC_DATA_STREAM_SPLIT_MODE;\ type OTG_CRC_DATA_FORMAT;\ - type OTG_V_TOTAL_LAST_USED_BY_DRR; + type OTG_V_TOTAL_LAST_USED_BY_DRR;\ + type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;
#define TG_REG_FIELD_LIST_DCN3_2(type) \ type OTG_H_TIMING_DIV_MODE_MANUAL; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c index 892d3c4d01a1e..25749f7d88366 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c @@ -282,6 +282,14 @@ static void optc3_set_timing_double_buffer(struct timing_generator *optc, bool e OTG_DRR_TIMING_DBUF_UPDATE_MODE, mode); }
+void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, 0, 2, 100000); /* 1 vupdate at 5hz */ + +} + void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max) { optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max); @@ -351,6 +359,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .program_manual_trigger = optc2_program_manual_trigger, .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, + .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, };
void dcn30_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h index dd45a5499b078..fb06dc9a48937 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h @@ -279,6 +279,7 @@ SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_END_X, mask_sh),\ SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh)
@@ -317,6 +318,7 @@ SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_END_X, mask_sh),\ SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh)
void dcn30_timing_generator_init(struct optc *optc1); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 25a1df45b2641..f96fb425345e4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -325,6 +325,7 @@ struct timing_generator_funcs { uint32_t vtotal_change_limit);
void (*init_odm)(struct timing_generator *tg); + void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg); };
#endif
From: Greg Kroah-Hartman gregkh@linuxfoundation.org
[ Upstream commit ad0e4e2fab928477f74d742e6e77d79245d3d3e7 ]
When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once.
Link: https://lore.kernel.org/r/20230202141009.2290380-1-gregkh@linuxfoundation.or... Cc: Karan Tilak Kumar kartilak@cisco.com Cc: Sesidhar Baddela sebaddel@cisco.com Cc: "James E.J. Bottomley" jejb@linux.ibm.com Cc: "Martin K. Petersen" martin.petersen@oracle.com Cc: linux-scsi@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/snic/snic_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c index 57bdc3ba49d9c..9dd975b36b5bd 100644 --- a/drivers/scsi/snic/snic_debugfs.c +++ b/drivers/scsi/snic/snic_debugfs.c @@ -437,6 +437,6 @@ void snic_trc_debugfs_init(void) void snic_trc_debugfs_term(void) { - debugfs_remove(debugfs_lookup(TRC_FILE, snic_glob->trc_root)); - debugfs_remove(debugfs_lookup(TRC_ENABLE_FILE, snic_glob->trc_root)); + debugfs_lookup_and_remove(TRC_FILE, snic_glob->trc_root); + debugfs_lookup_and_remove(TRC_ENABLE_FILE, snic_glob->trc_root); }
From: Mason Zhang Mason.Zhang@mediatek.com
[ Upstream commit 36822124f9de200cedc2f42516301b50d386a6cd ]
In the UFS error handling flow, the host will send a device management cmd (NOP OUT) to the device for link recovery. If this cmd times out and clearing the doorbell fails, ufshcd_wait_for_dev_cmd() will do nothing and return. hba->dev_cmd.complete struct is not set to NULL.
When this happens, if cmd has been completed by device, then we will call complete() in __ufshcd_transfer_req_compl(). Because the complete struct is allocated on the stack, the following crash will occur:
ipanic_die+0x24/0x38 [mrdump] die+0x344/0x748 arm64_notify_die+0x44/0x104 do_debug_exception+0x104/0x1e0 el1_dbg+0x38/0x54 el1_sync_handler+0x40/0x88 el1_sync+0x8c/0x140 queued_spin_lock_slowpath+0x2e4/0x3c0 __ufshcd_transfer_req_compl+0x3b0/0x1164 ufshcd_trc_handler+0x15c/0x308 ufshcd_host_reset_and_restore+0x54/0x260 ufshcd_reset_and_restore+0x28c/0x57c ufshcd_err_handler+0xeb8/0x1b6c process_one_work+0x288/0x964 worker_thread+0x4bc/0xc7c kthread+0x15c/0x264 ret_from_fork+0x10/0x30
Link: https://lore.kernel.org/r/20221216032532.1280-1-mason.zhang@mediatek.com Signed-off-by: Mason Zhang Mason.Zhang@mediatek.com Reviewed-by: Bart Van Assche bvanassche@acm.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/ufs/core/ufshcd.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fb5c9e2fc5348..dae49530201bf 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3006,6 +3006,22 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, } else { dev_err(hba->dev, "%s: failed to clear tag %d\n", __func__, lrbp->task_tag); + + spin_lock_irqsave(&hba->outstanding_lock, flags); + pending = test_bit(lrbp->task_tag, + &hba->outstanding_reqs); + if (pending) + hba->dev_cmd.complete = NULL; + spin_unlock_irqrestore(&hba->outstanding_lock, flags); + + if (!pending) { + /* + * The completion handler ran while we tried to + * clear the command. + */ + time_left = 1; + goto retry; + } } }
From: Bastien Nocera hadess@hadess.net
[ Upstream commit 498ba20690357691103de0f766960355247c78be ]
Don't stop and restart communication with the device unless we need to modify the connect flags used because of a device quirk.
Signed-off-by: Bastien Nocera hadess@hadess.net Link: https://lore.kernel.org/r/20230125121723.3122-1-hadess@hadess.net Signed-off-by: Benjamin Tissoires benjamin.tissoires@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-logitech-hidpp.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 07b8506eecc41..74cf4d47013ab 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4107,6 +4107,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) bool connected; unsigned int connect_mask = HID_CONNECT_DEFAULT; struct hidpp_ff_private_data data; + bool will_restart = false;
/* report_fixup needs drvdata to be set before we call hid_parse */ hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL); @@ -4162,6 +4163,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; }
+ if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT || + hidpp->quirks & HIDPP_QUIRK_UNIFYING) + will_restart = true; + INIT_WORK(&hidpp->work, delayed_work_cb); mutex_init(&hidpp->send_mutex); init_waitqueue_head(&hidpp->wait); @@ -4176,7 +4181,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) * Plain USB connections need to actually call start and open * on the transport driver to allow incoming data. */ - ret = hid_hw_start(hdev, 0); + ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask); if (ret) { hid_err(hdev, "hw start failed\n"); goto hid_hw_start_fail; @@ -4213,6 +4218,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp->wireless_feature_index = 0; else if (ret) goto hid_hw_init_fail; + ret = 0; }
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) { @@ -4227,19 +4233,21 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp_connect_event(hidpp);
- /* Reset the HID node state */ - hid_device_io_stop(hdev); - hid_hw_close(hdev); - hid_hw_stop(hdev); + if (will_restart) { + /* Reset the HID node state */ + hid_device_io_stop(hdev); + hid_hw_close(hdev); + hid_hw_stop(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) - connect_mask &= ~HID_CONNECT_HIDINPUT; + if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) + connect_mask &= ~HID_CONNECT_HIDINPUT;
- /* Now export the actual inputs and hidraw nodes to the world */ - ret = hid_hw_start(hdev, connect_mask); - if (ret) { - hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); - goto hid_hw_start_fail; + /* Now export the actual inputs and hidraw nodes to the world */ + ret = hid_hw_start(hdev, connect_mask); + if (ret) { + hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); + goto hid_hw_start_fail; + } }
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
From: Nicholas Kazlauskas nicholas.kazlauskas@amd.com
[ Upstream commit e383b12709e32d6494c948422070c2464b637e44 ]
[Why] DOMAIN power gating control is now required to be done via firmware due to interlock with other power features. This is to avoid intermittent issues in the LB memories.
[How] If the firmware supports the command then use the new firmware as the sequence can avoid potential display corruption issues.
The command will be ignored on firmware that does not support DOMAIN power control and the pipes will remain always on - frequent PG cycling can cause the issue to occur on the old sequence, so we should avoid it.
Reviewed-by: Hansen Dsouza hansen.dsouza@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Nicholas Kazlauskas nicholas.kazlauskas@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 --- .../drm/amd/display/dc/dcn314/dcn314_hwseq.c | 24 ++++++++++++++++++ .../drm/amd/display/dc/dcn314/dcn314_hwseq.h | 2 ++ .../drm/amd/display/dc/dcn314/dcn314_init.c | 2 +- .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 25 +++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index a0741794db62a..8e824dc81dede 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -391,3 +391,27 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, pix_per_cycle); } + +void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + struct dc_context *ctx = hws->ctx; + union dmub_rb_cmd cmd; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + + PERF_TRACE(); + + memset(&cmd, 0, sizeof(cmd)); + cmd.domain_control.header.type = DMUB_CMD__VBIOS; + cmd.domain_control.header.sub_type = DMUB_CMD__VBIOS_DOMAIN_CONTROL; + cmd.domain_control.header.payload_bytes = sizeof(cmd.domain_control.data); + cmd.domain_control.data.inst = hubp_inst; + cmd.domain_control.data.power_gate = !power_on; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(ctx->dmub_srv); + dc_dmub_srv_wait_idle(ctx->dmub_srv); + + PERF_TRACE(); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h index 244280298212c..c419d3dbdfee6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h @@ -41,4 +41,6 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
+void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); + #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 5b6c2d94ec71d..343f4d9dd5e34 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -137,7 +137,7 @@ static const struct hwseq_private_funcs dcn314_private_funcs = { .plane_atomic_disable = dcn20_plane_atomic_disable, .plane_atomic_power_down = dcn10_plane_atomic_power_down, .enable_power_gating_plane = dcn314_enable_power_gating_plane, - .hubp_pg_control = dcn31_hubp_pg_control, + .hubp_pg_control = dcn314_hubp_pg_control, .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .update_odm = dcn314_update_odm, .dsc_pg_control = dcn314_dsc_pg_control, diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 7a8f61517424c..27a4ea7dc74ec 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -450,6 +450,10 @@ enum dmub_cmd_vbios_type { * Query DP alt status on a transmitter. */ DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT = 26, + /** + * Controls domain power gating + */ + DMUB_CMD__VBIOS_DOMAIN_CONTROL = 28, };
//============================================================================== @@ -1191,6 +1195,23 @@ struct dmub_rb_cmd_dig1_transmitter_control { union dmub_cmd_dig1_transmitter_control_data transmitter_control; /**< payload */ };
+/** + * struct dmub_rb_cmd_domain_control_data - Data for DOMAIN power control + */ +struct dmub_rb_cmd_domain_control_data { + uint8_t inst : 6; /**< DOMAIN instance to control */ + uint8_t power_gate : 1; /**< 1=power gate, 0=power up */ + uint8_t reserved[3]; /**< Reserved for future use */ +}; + +/** + * struct dmub_rb_cmd_domain_control - Controls DOMAIN power gating + */ +struct dmub_rb_cmd_domain_control { + struct dmub_cmd_header header; /**< header */ + struct dmub_rb_cmd_domain_control_data data; /**< payload */ +}; + /** * DPIA tunnel command parameters. */ @@ -3187,6 +3208,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL command. */ struct dmub_rb_cmd_dig1_transmitter_control dig1_transmitter_control; + /** + * Definition of a DMUB_CMD__VBIOS_DOMAIN_CONTROL command. + */ + struct dmub_rb_cmd_domain_control domain_control; /** * Definition of a DMUB_CMD__PSR_SET_VERSION command. */
From: Nicholas Kazlauskas nicholas.kazlauskas@amd.com
[ Upstream commit 37d184b548db0f64d4a878960b2c6988b38a3e7e ]
[Why] To align with DCN31 behavior. This helps avoid p-state hangs in the case where underflow does occur.
[How] Flip the bit to true.
Reviewed-by: Hansen Dsouza hansen.dsouza@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Nicholas Kazlauskas nicholas.kazlauskas@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/dcn314/dcn314_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index c80c8c8f51e97..5985ce8df4e08 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -897,7 +897,7 @@ static const struct dc_debug_options debug_defaults_drv = { .max_downscale_src_width = 4096,/*upto true 4k*/ .disable_pplib_wm_range = false, .scl_reset_length10 = true, - .sanity_checks = false, + .sanity_checks = true, .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true,
From: Darrell Kavanagh darrell.kavanagh@gmail.com
[ Upstream commit 38b2d8efd03d2e56431b611e3523f0158306451d ]
Another Lenovo convertable where the panel is installed landscape but is reported to the kernel as portrait.
Signed-off-by: Darrell Kavanagh darrell.kavanagh@gmail.com Reviewed-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Hans de Goede hdegoede@redhat.com Link: https://patchwork.freedesktop.org/patch/msgid/20230214164659.3583-1-darrell.... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index b409fe256fd0a..5522d610c5cfd 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -322,6 +322,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"), }, .driver_data = (void *)&lcd800x1280_rightside_up, + }, { /* Lenovo IdeaPad Duet 3 10IGL5 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5"), + }, + .driver_data = (void *)&lcd1200x1920_rightside_up, }, { /* Lenovo Yoga Book X90F / X91F / X91L */ .matches = { /* Non exact match to match all versions */
From: Nicholas Kazlauskas nicholas.kazlauskas@amd.com
[ Upstream commit b7c67f72408b11b922f23f06c7df0f6743a2e89d ]
[Why] The DMCUB implementation required to workaround corruption is not currently stable and may cause intermittent corruption or hangs.
[How] Disable PG until the sequence is stable.
Reviewed-by: Hansen Dsouza hansen.dsouza@amd.com Acked-by: Qingqing Zhuo qingqing.zhuo@amd.com Signed-off-by: Nicholas Kazlauskas nicholas.kazlauskas@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/dcn314/dcn314_resource.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 5985ce8df4e08..9918bccd6defb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -888,6 +888,8 @@ static const struct dc_debug_options debug_defaults_drv = { .force_abm_enable = false, .timing_trace = false, .clock_trace = true, + .disable_dpp_power_gate = true, + .disable_hubp_power_gate = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false,
From: Mike Snitzer snitzer@kernel.org
[ Upstream commit e4f80303c2353952e6e980b23914e4214487f2a6 ]
Otherwise on resource constrained systems these workqueues may be too greedy.
Signed-off-by: Mike Snitzer snitzer@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/md/dm-thin.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 196f82559ad6b..d28c9077d6ed2 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2207,6 +2207,7 @@ static void process_thin_deferred_bios(struct thin_c *tc) throttle_work_update(&pool->throttle); dm_pool_issue_prefetches(pool->pmd); } + cond_resched(); } blk_finish_plug(&plug); } @@ -2289,6 +2290,7 @@ static void process_thin_deferred_cells(struct thin_c *tc) else pool->process_cell(tc, cell); } + cond_resched(); } while (!list_empty(&cells)); }
From: Mike Snitzer snitzer@kernel.org
[ Upstream commit 76227f6dc805e9e960128bcc6276647361e0827c ]
Otherwise on resource constrained systems these workqueues may be too greedy.
Signed-off-by: Mike Snitzer snitzer@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/md/dm-cache-target.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 5e92fac90b675..17fde3e5a1f7b 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -1805,6 +1805,7 @@ static void process_deferred_bios(struct work_struct *ws)
else commit_needed = process_bio(cache, bio) || commit_needed; + cond_resched(); }
if (commit_needed) @@ -1827,6 +1828,7 @@ static void requeue_deferred_bios(struct cache *cache) while ((bio = bio_list_pop(&bios))) { bio->bi_status = BLK_STS_DM_REQUEUE; bio_endio(bio); + cond_resched(); } }
@@ -1867,6 +1869,8 @@ static void check_migrations(struct work_struct *ws) r = mg_start(cache, op, NULL); if (r) break; + + cond_resched(); } }
From: Jeff Layton jlayton@kernel.org
[ Upstream commit 1f0001d43d0c0ac2a19a34a914f6595ad97cbc1d ]
At first, I thought this might be a source of nfsd_file overputs, but the current callers seem to avoid an extra put when nfsd4_verify_copy returns an error.
Still, it's "bad form" to leave the pointers filled out when we don't have a reference to them anymore, and that might lead to bugs later. Zero them out as a defensive coding measure.
Signed-off-by: Jeff Layton jlayton@kernel.org Signed-off-by: Chuck Lever chuck.lever@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/nfsd/nfs4proc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ba04ce9b9fa51..13603cb017346 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1227,8 +1227,10 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; out_put_dst: nfsd_file_put(*dst); + *dst = NULL; out_put_src: nfsd_file_put(*src); + *src = NULL; goto out; }
From: Jeff Layton jlayton@kernel.org
[ Upstream commit 6ba434cb1a8d403ea9aad1b667c3ea3ad8b3191f ]
There are two different flavors of the nfsd4_copy struct. One is embedded in the compound and is used directly in synchronous copies. The other is dynamically allocated, refcounted and tracked in the client struture. For the embedded one, the cleanup just involves releasing any nfsd_files held on its behalf. For the async one, the cleanup is a bit more involved, and we need to dequeue it from lists, unhash it, etc.
There is at least one potential refcount leak in this code now. If the kthread_create call fails, then both the src and dst nfsd_files in the original nfsd4_copy object are leaked.
The cleanup in this codepath is also sort of weird. In the async copy case, we'll have up to four nfsd_file references (src and dst for both flavors of copy structure). They are both put at the end of nfsd4_do_async_copy, even though the ones held on behalf of the embedded one outlive that structure.
Change it so that we always clean up the nfsd_file refs held by the embedded copy structure before nfsd4_copy returns. Rework cleanup_async_copy to handle both inter and intra copies. Eliminate nfsd4_cleanup_intra_ssc since it now becomes a no-op.
Signed-off-by: Jeff Layton jlayton@kernel.org Signed-off-by: Chuck Lever chuck.lever@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/nfsd/nfs4proc.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 13603cb017346..9cc498916aa22 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1530,7 +1530,6 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
nfs42_ssc_close(filp); - nfsd_file_put(dst); fput(filp);
if (!nn) { @@ -1597,13 +1596,6 @@ nfsd4_setup_intra_ssc(struct svc_rqst *rqstp, ©->nf_dst); }
-static void -nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst) -{ - nfsd_file_put(src); - nfsd_file_put(dst); -} - static void nfsd4_cb_offload_release(struct nfsd4_callback *cb) { struct nfsd4_cb_offload *cbo = @@ -1718,12 +1710,18 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) dst->ss_mnt = src->ss_mnt; }
+static void release_copy_files(struct nfsd4_copy *copy) +{ + if (copy->nf_src) + nfsd_file_put(copy->nf_src); + if (copy->nf_dst) + nfsd_file_put(copy->nf_dst); +} + static void cleanup_async_copy(struct nfsd4_copy *copy) { nfs4_free_copy_state(copy); - nfsd_file_put(copy->nf_dst); - if (!nfsd4_ssc_is_inter(copy)) - nfsd_file_put(copy->nf_src); + release_copy_files(copy); spin_lock(©->cp_clp->async_lock); list_del(©->copies); spin_unlock(©->cp_clp->async_lock); @@ -1783,7 +1781,6 @@ static int nfsd4_do_async_copy(void *data) } else { nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, copy->nf_dst->nf_file, false); - nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); }
do_callback: @@ -1847,9 +1844,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } else { status = nfsd4_do_copy(copy, copy->nf_src->nf_file, copy->nf_dst->nf_file, true); - nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); } out: + release_copy_files(copy); return status; out_err: if (async_copy)
From: Jeff Layton jlayton@kernel.org
[ Upstream commit 826b67e6376c2a788e3a62c4860dcd79500a27d5 ]
We had a bug report that xfstest generic/355 was failing on NFSv4.0. This test sets various combinations of setuid/setgid modes and tests whether DIO writes will cause them to be stripped.
What I found was that the server did properly strip those bits, but the client didn't notice because it held a delegation that was not recalled. The recall didn't occur because the client itself was the one generating the activity and we avoid recalls in that case.
Clearing setuid bits is an "implicit" activity. The client didn't specifically request that we do that, so we need the server to issue a CB_RECALL, or avoid the situation entirely by not issuing a delegation.
The easiest fix here is to simply not give out a delegation if the file is being opened for write, and the mode has the setuid and/or setgid bit set. Note that there is a potential race between the mode and lease being set, so we test for this condition both before and after setting the lease.
This patch fixes generic/355, generic/683 and generic/684 for me. (Note that 355 fails only on v4.0, and 683 and 684 require NFSv4.2 to run and fail).
Reported-by: Boyang Xue bxue@redhat.com Signed-off-by: Jeff Layton jlayton@kernel.org Signed-off-by: Chuck Lever chuck.lever@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2247d107da90b..925a963aea00f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5397,6 +5397,23 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, return 0; }
+/* + * We avoid breaking delegations held by a client due to its own activity, but + * clearing setuid/setgid bits on a write is an implicit activity and the client + * may not notice and continue using the old mode. Avoid giving out a delegation + * on setuid/setgid files when the client is requesting an open for write. + */ +static int +nfsd4_verify_setuid_write(struct nfsd4_open *open, struct nfsd_file *nf) +{ + struct inode *inode = file_inode(nf->nf_file); + + if ((open->op_share_access & NFS4_SHARE_ACCESS_WRITE) && + (inode->i_mode & (S_ISUID|S_ISGID))) + return -EAGAIN; + return 0; +} + static struct nfs4_delegation * nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, struct svc_fh *parent) @@ -5430,6 +5447,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, spin_lock(&fp->fi_lock); if (nfs4_delegation_exists(clp, fp)) status = -EAGAIN; + else if (nfsd4_verify_setuid_write(open, nf)) + status = -EAGAIN; else if (!fp->fi_deleg_file) { fp->fi_deleg_file = nf; /* increment early to prevent fi_deleg_file from being @@ -5470,6 +5489,14 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, if (status) goto out_unlock;
+ /* + * Now that the deleg is set, check again to ensure that nothing + * raced in and changed the mode while we weren't lookng. + */ + status = nfsd4_verify_setuid_write(open, fp->fi_deleg_file); + if (status) + goto out_unlock; + spin_lock(&state_lock); spin_lock(&fp->fi_lock); if (fp->fi_had_conflict)
From: Paulo Alcantara pc@cjr.nz
[ Upstream commit 3c0070f54b3128de498c2dd9934a21f0dd867111 ]
Make sure to get an up-to-date TCP_Server_Info::nr_targets value prior to waiting the server to be reconnected in smb2_reconnect(). It is set in cifs_tcp_ses_needs_reconnect() and protected by TCP_Server_Info::srv_lock.
Signed-off-by: Paulo Alcantara (SUSE) pc@cjr.nz Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/cifs/smb2pdu.c | 119 +++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 55 deletions(-)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 2c9ffa921e6f6..2d5c3df2277d4 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -139,6 +139,66 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd, return; }
+static int wait_for_server_reconnect(struct TCP_Server_Info *server, + __le16 smb2_command, bool retry) +{ + int timeout = 10; + int rc; + + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsNeedReconnect) { + spin_unlock(&server->srv_lock); + return 0; + } + timeout *= server->nr_targets; + spin_unlock(&server->srv_lock); + + /* + * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE + * here since they are implicitly done when session drops. + */ + switch (smb2_command) { + /* + * BB Should we keep oplock break and add flush to exceptions? + */ + case SMB2_TREE_DISCONNECT: + case SMB2_CANCEL: + case SMB2_CLOSE: + case SMB2_OPLOCK_BREAK: + return -EAGAIN; + } + + /* + * Give demultiplex thread up to 10 seconds to each target available for + * reconnect -- should be greater than cifs socket timeout which is 7 + * seconds. + * + * On "soft" mounts we wait once. Hard mounts keep retrying until + * process is killed or server comes back on-line. + */ + do { + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + timeout * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n", + __func__); + return -ERESTARTSYS; + } + + /* are we still trying to reconnect? */ + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsNeedReconnect) { + spin_unlock(&server->srv_lock); + return 0; + } + spin_unlock(&server->srv_lock); + } while (retry); + + cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__); + return -EHOSTDOWN; +} + static int smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, struct TCP_Server_Info *server) @@ -146,7 +206,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, int rc = 0; struct nls_table *nls_codepage; struct cifs_ses *ses; - int retries;
/* * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so @@ -184,61 +243,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, (!tcon->ses->server) || !server) return -EIO;
- ses = tcon->ses; - retries = server->nr_targets; - - /* - * Give demultiplex thread up to 10 seconds to each target available for - * reconnect -- should be greater than cifs socket timeout which is 7 - * seconds. - */ - while (server->tcpStatus == CifsNeedReconnect) { - /* - * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE - * here since they are implicitly done when session drops. - */ - switch (smb2_command) { - /* - * BB Should we keep oplock break and add flush to exceptions? - */ - case SMB2_TREE_DISCONNECT: - case SMB2_CANCEL: - case SMB2_CLOSE: - case SMB2_OPLOCK_BREAK: - return -EAGAIN; - } - - rc = wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus != CifsNeedReconnect), - 10 * HZ); - if (rc < 0) { - cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n", - __func__); - return -ERESTARTSYS; - } - - /* are we still trying to reconnect? */ - spin_lock(&server->srv_lock); - if (server->tcpStatus != CifsNeedReconnect) { - spin_unlock(&server->srv_lock); - break; - } - spin_unlock(&server->srv_lock); - - if (retries && --retries) - continue; + rc = wait_for_server_reconnect(server, smb2_command, tcon->retry); + if (rc) + return rc;
- /* - * on "soft" mounts we wait once. Hard mounts keep - * retrying until process is killed or server comes - * back on-line - */ - if (!tcon->retry) { - cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); - return -EHOSTDOWN; - } - retries = server->nr_targets; - } + ses = tcon->ses;
spin_lock(&ses->chan_lock); if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
linux-stable-mirror@lists.linaro.org