From f3ccdfda345ca9a624ea425840a926b8338c1e25 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 25 Nov 2025 09:38:49 +0800 Subject: wifi: rtw88: limit indirect IO under powered off for RTL8822CS The indirect IO is necessary for RTL8822CS, but not necessary for other chips. Otherwiese, it throws errors and becomes unusable. rtw88_8723cs mmc1:0001:1: WOW Firmware version 11.0.0, H2C version 0 rtw88_8723cs mmc1:0001:1: Firmware version 11.0.0, H2C version 0 rtw88_8723cs mmc1:0001:1: sdio read32 failed (0xf0): -110 rtw88_8723cs mmc1:0001:1: sdio write8 failed (0x1c): -110 rtw88_8723cs mmc1:0001:1: sdio read32 failed (0xf0): -110 By vendor driver, only RTL8822CS and RTL8822ES need indirect IO, but RTL8822ES isn't supported yet. Therefore, limit it to RTL8822CS only. Reported-by: Andrey Skvortsov Closes: https://lore.kernel.org/linux-wireless/07a32e2d6c764eb1bd9415b5a921a652@realtek.com/T/#m997b4522f7209ba629561c776bfd1d13ab24c1d4 Fixes: 58de1f91e033 ("wifi: rtw88: sdio: use indirect IO for device registers before power-on") Signed-off-by: Ping-Ke Shih Tested-by: Andrey Skvortsov Link: https://patch.msgid.link/1764034729-1251-1-git-send-email-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/sdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 99d7c629eac6..e35de52d8eb4 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,8 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + bool might_indirect_under_power_off = rtwdev->chip->id == RTW_CHIP_TYPE_8822C; + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && - !rtw_sdio_is_bus_addr(addr)) + !rtw_sdio_is_bus_addr(addr) && might_indirect_under_power_off) return false; return !rtw_sdio_is_sdio30_supported(rtwdev) || -- cgit v1.2.3 From dd39edb445f07400e748da967a07d5dca5c5f96e Mon Sep 17 00:00:00 2001 From: Morning Star Date: Thu, 27 Nov 2025 16:37:08 +0800 Subject: wifi: rtlwifi: 8192cu: fix tid out of range in rtl92cu_tx_fill_desc() TID getting from ieee80211_get_tid() might be out of range of array size of sta_entry->tids[], so check TID is less than MAX_TID_COUNT. Othwerwise, UBSAN warn: UBSAN: array-index-out-of-bounds in drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c:514:30 index 10 is out of range for type 'rtl_tid_data [9]' Fixes: 8ca4cdef9329 ("wifi: rtlwifi: rtl8192cu: Fix TX aggregation") Signed-off-by: Morning Star Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/1764232628-13625-1-git-send-email-pkshih@realtek.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index aa702ba7c9f5..d6c35e8d02a5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -511,7 +511,8 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, if (sta) { sta_entry = (struct rtl_sta_info *)sta->drv_priv; tid = ieee80211_get_tid(hdr); - agg_state = sta_entry->tids[tid].agg.agg_state; + if (tid < MAX_TID_COUNT) + agg_state = sta_entry->tids[tid].agg.agg_state; ampdu_density = sta->deflink.ht_cap.ampdu_density; } -- cgit v1.2.3 From 0ff5e81e1518868286d7a1cda192c23db3110b7c Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 6 Dec 2025 20:32:43 +0200 Subject: Revert "wifi: rtw88: add WQ_UNBOUND to alloc_workqueue users" This reverts commit 9c194fe4625db18f93d5abcfb7f7997557a0b29d. This commit breaks all USB wifi adapters supported by rtw88: usb 1-2: new high-speed USB device number 6 using xhci_hcd usb 1-2: New USB device found, idVendor=2357, idProduct=0138, bcdDevice= 2.10 usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-2: Product: 802.11ac NIC usb 1-2: Manufacturer: Realtek usb 1-2: SerialNumber: 123456 ------------[ cut here ]------------ WARNING: CPU: 3 PID: 152 at kernel/workqueue.c:5667 alloc_workqueue_noprof+0x676/0x770 [...] Call Trace: ? rtw_usb_probe+0x30e/0xa5c [rtw88_usb 4af3cb64eedafeecbfb08f80c1e9e2893e2ee7a6] rtw_usb_probe+0x3eb/0xa5c [rtw88_usb 4af3cb64eedafeecbfb08f80c1e9e2893e2ee7a6] usb_probe_interface+0xdd/0x2c0 really_probe+0xdb/0x340 ? pm_runtime_barrier+0x55/0x90 ? __pfx___device_attach_driver+0x10/0x10 __driver_probe_device+0x78/0x140 driver_probe_device+0x1f/0xa0 __device_attach_driver+0x89/0x110 bus_for_each_drv+0x8f/0xe0 __device_attach+0xb0/0x1c0 bus_probe_device+0x90/0xa0 device_add+0x663/0x880 usb_set_configuration+0x5a5/0x870 usb_generic_driver_probe+0x4a/0x70 usb_probe_device+0x3d/0x140 ? driver_sysfs_add+0x59/0xd0 really_probe+0xdb/0x340 ? pm_runtime_barrier+0x55/0x90 ? __pfx___device_attach_driver+0x10/0x10 __driver_probe_device+0x78/0x140 driver_probe_device+0x1f/0xa0 __device_attach_driver+0x89/0x110 bus_for_each_drv+0x8f/0xe0 __device_attach+0xb0/0x1c0 bus_probe_device+0x90/0xa0 device_add+0x663/0x880 usb_new_device.cold+0x141/0x3b5 hub_event+0x1132/0x1900 ? page_counter_uncharge+0x4a/0x90 process_one_work+0x190/0x350 worker_thread+0x2d7/0x410 ? __pfx_worker_thread+0x10/0x10 kthread+0xf9/0x240 ? __pfx_kthread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1c1/0x1f0 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 ---[ end trace 0000000000000000 ]--- rtw88_8822bu 1-2:1.0: failed to create RX work queue rtw88_8822bu 1-2:1.0: failed to init USB RX rtw88_8822bu 1-2:1.0: Firmware version 27.2.0, H2C version 13 rtw88_8822bu 1-2:1.0: probe with driver rtw88_8822bu failed with error -12 WQ_UNBOUND is not compatible with WQ_BH. Comment in enum wq_flags in workqueue.h says: /* BH wq only allows the following flags */ __WQ_BH_ALLOWS = WQ_BH | WQ_HIGHPRI | WQ_PERCPU, Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/d57efe48-b8ff-4bf1-942c-7e808535eda6@gmail.com --- drivers/net/wireless/realtek/rtw88/usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 009202c627d2..3b5126ffc81a 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -965,8 +965,7 @@ static int rtw_usb_init_rx(struct rtw_dev *rtwdev) struct sk_buff *rx_skb; int i; - rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH | WQ_UNBOUND, - 0); + rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH, 0); if (!rtwusb->rxwq) { rtw_err(rtwdev, "failed to create RX work queue\n"); return -ENOMEM; -- cgit v1.2.3 From 433f7744cb302ac22800dc0cd50494319ce64ba0 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:10 -0500 Subject: platform/x86: alienware-wmi-wmax: Add support for new Area-51 laptops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AWCC support for new Alienware Area-51 laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-1-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index 1418bd326edf..fd8e69432a80 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -89,6 +89,22 @@ static struct awcc_quirks generic_quirks = { static struct awcc_quirks empty_quirks; static const struct dmi_system_id awcc_dmi_table[] __initconst = { + { + .ident = "Alienware 16 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16 Area-51"), + }, + .driver_data = &g_series_quirks, + }, + { + .ident = "Alienware 18 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 18 Area-51"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware 16 Aurora", .matches = { -- cgit v1.2.3 From a584644a490d276907e56817694859eaac2a4199 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:11 -0500 Subject: platform/x86: alienware-wmi-wmax: Add AWCC support for Alienware x16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AWCC support for Alienware x16 laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-2-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index fd8e69432a80..7fb7a795a9bb 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -177,6 +177,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { }, .driver_data = &generic_quirks, }, + { + .ident = "Alienware x16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x16"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware x17", .matches = { -- cgit v1.2.3 From 7f3c2499da24551968640528fee9aed3bb4f0c3f Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Fri, 5 Dec 2025 13:50:12 -0500 Subject: platform/x86: alienware-wmi-wmax: Add support for Alienware 16X Aurora MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AWCC support for Alienware 16X Aurora laptops. Cc: stable@vger.kernel.org Signed-off-by: Kurt Borja Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20251205-area-51-v1-3-d2cb13530851@gmail.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/alienware-wmi-wmax.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index 7fb7a795a9bb..e69b50162bb1 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -97,6 +97,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { }, .driver_data = &g_series_quirks, }, + { + .ident = "Alienware 16X Aurora", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16X Aurora"), + }, + .driver_data = &g_series_quirks, + }, { .ident = "Alienware 18 Area-51", .matches = { -- cgit v1.2.3 From 4dcb6e4af15bf45aa1526834e8f5e296ad7ce867 Mon Sep 17 00:00:00 2001 From: Werner Sembach Date: Fri, 12 Dec 2025 19:02:22 +0100 Subject: platform/x86/uniwill: Add TUXEDO Book BA15 Gen10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TUXEDO Book BA15 Gen10 to the list of supported devices of the Uniwill driver. Signed-off-by: Werner Sembach Link: https://patch.msgid.link/20251212180319.712913-1-wse@tuxedocomputers.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/uniwill/uniwill-acpi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c index bd7e63dd5181..0f935532f250 100644 --- a/drivers/platform/x86/uniwill/uniwill-acpi.c +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c @@ -1844,6 +1844,13 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"), }, }, + { + .ident = "TUXEDO Book BA15 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"), + }, + }, { .ident = "TUXEDO Pulse 14 Gen1 AMD", .matches = { -- cgit v1.2.3 From a260bd22a355bcdb74cedac6ab9b10739cd2c62c Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Tue, 9 Dec 2025 22:09:03 +0100 Subject: media: mc: fix potential use-after-free in media_request_alloc() Commit 6f504cbf108a ("media: convert media_request_alloc() to FD_PREPARE()") moved the call to fd_install() (now hidden in fd_publish()) before the snprintf(), making the later write to potentially already freed memory, as userland is free to call close() concurrently right after the call to fd_install() which may end up in the request_fops.release() handler freeing 'req'. Fixes: 6f504cbf108a ("media: convert media_request_alloc() to FD_PREPARE()") Signed-off-by: Mathias Krause Link: https://patch.msgid.link/20251209210903.603958-1-minipli@grsecurity.net Signed-off-by: Christian Brauner --- drivers/media/mc/mc-request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index 2ac9ac0a740b..3cca9a0c7c97 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c @@ -315,12 +315,12 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) fd_prepare_file(fdf)->private_data = req; - *alloc_fd = fd_publish(fdf); - snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d", - atomic_inc_return(&mdev->request_id), *alloc_fd); + atomic_inc_return(&mdev->request_id), fd_prepare_fd(fdf)); dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str); + *alloc_fd = fd_publish(fdf); + return 0; err_free_req: -- cgit v1.2.3 From e75665dd096819b1184087ba5718bd93beafff51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85strand?= Date: Wed, 3 Dec 2025 08:57:08 +0100 Subject: wifi: wlcore: ensure skb headroom before skb_push This avoids occasional skb_under_panic Oops from wl1271_tx_work. In this case, headroom is less than needed (typically 110 - 94 = 16 bytes). Signed-off-by: Peter Astrand Link: https://patch.msgid.link/097bd417-e1d7-acd4-be05-47b199075013@lysator.liu.se Signed-off-by: Johannes Berg --- drivers/net/wireless/ti/wlcore/tx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index f76087be2f75..6241866d39df 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -207,6 +207,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); if (total_blocks <= wl->tx_blocks_available) { + if (skb_headroom(skb) < (total_len - skb->len) && + pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) { + wl1271_free_tx_id(wl, id); + return -EAGAIN; + } desc = skb_push(skb, total_len - skb->len); wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, -- cgit v1.2.3 From 3d3352e73a55a4ccf110f8b3419bbe2fbfd8a030 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 5 Nov 2025 09:40:09 +0900 Subject: gpu: nova-core: select RUST_FW_LOADER_ABSTRACTIONS RUST_FW_LOADER_ABSTRACTIONS was depended on by NOVA_CORE, but NOVA_CORE is selected by DRM_NOVA. This creates a situation where, if DRM_NOVA is selected, NOVA_CORE gets enabled but not RUST_FW_LOADER_ABSTRACTIONS, which results in a build error. Since the firmware loader is an implementation detail of the driver, it should be enabled along with it, so change the "depends on" to a "select". Fixes: 54e6baf123fd ("gpu: nova-core: add initial driver stub") Closes: https://lore.kernel.org/oe-kbuild-all/202512061721.rxKGnt5q-lkp@intel.com/ Tested-by: Alyssa Ross Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251106-b4-select-rust-fw-v3-2-771172257755@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/nova-core/Kconfig b/drivers/gpu/nova-core/Kconfig index 20d3e6d0d796..527920f9c4d3 100644 --- a/drivers/gpu/nova-core/Kconfig +++ b/drivers/gpu/nova-core/Kconfig @@ -3,7 +3,7 @@ config NOVA_CORE depends on 64BIT depends on PCI depends on RUST - depends on RUST_FW_LOADER_ABSTRACTIONS + select RUST_FW_LOADER_ABSTRACTIONS select AUXILIARY_BUS default n help -- cgit v1.2.3 From b6c76518233e876a0f26e66b83643891c0f341db Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 16 Dec 2025 11:57:07 +0900 Subject: gpu: nova-core: bindings: add missing explicit padding Explicit padding is needed in order to avoid uninitialized bytes and safely implement `AsBytes`. The `--explicit-padding` of bindgen was omitted by mistake when these bindings were generated. Fixes: 13f85988d4fa ("gpu: nova-core: gsp: Retrieve GSP static info to gather GPU information") Reviewed-by: Lyude Paul Reviewed-by: Joel Fernandes Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251216-nova-fixes-v3-1-c7469a71f7c4@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs index 5bcfbcd1ad22..5f0569dcc4a0 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs @@ -325,6 +325,7 @@ pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS { pub totalVFs: u32_, pub firstVfOffset: u32_, pub vfFeatureMask: u32_, + pub __bindgen_padding_0: [u8; 4usize], pub FirstVFBar0Address: u64_, pub FirstVFBar1Address: u64_, pub FirstVFBar2Address: u64_, @@ -340,6 +341,7 @@ pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS { pub bClientRmAllocatedCtxBuffer: u8_, pub bNonPowerOf2ChannelCountSupported: u8_, pub bVfResizableBAR1Supported: u8_, + pub __bindgen_padding_1: [u8; 7usize], } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] @@ -347,11 +349,13 @@ pub struct NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS { pub BoardID: u32_, pub chipSKU: [ffi::c_char; 9usize], pub chipSKUMod: [ffi::c_char; 5usize], + pub __bindgen_padding_0: [u8; 2usize], pub skuConfigVersion: u32_, pub project: [ffi::c_char; 5usize], pub projectSKU: [ffi::c_char; 5usize], pub CDP: [ffi::c_char; 6usize], pub projectSKUMod: [ffi::c_char; 2usize], + pub __bindgen_padding_1: [u8; 2usize], pub businessCycle: u32_, } pub type NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG = [u8_; 17usize]; @@ -371,6 +375,7 @@ pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO { #[derive(Debug, Default, Copy, Clone)] pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS { pub numFBRegions: u32_, + pub __bindgen_padding_0: [u8; 4usize], pub fbRegion: [NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO; 16usize], } #[repr(C)] @@ -495,13 +500,16 @@ pub struct FW_WPR_LAYOUT_OFFSET { #[derive(Debug, Copy, Clone)] pub struct GspStaticConfigInfo_t { pub grCapsBits: [u8_; 23usize], + pub __bindgen_padding_0: u8, pub gidInfo: NV2080_CTRL_GPU_GET_GID_INFO_PARAMS, pub SKUInfo: NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS, + pub __bindgen_padding_1: [u8; 4usize], pub fbRegionInfoParams: NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS, pub sriovCaps: NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS, pub sriovMaxGfid: u32_, pub engineCaps: [u32_; 3usize], pub poisonFuseEnabled: u8_, + pub __bindgen_padding_2: [u8; 7usize], pub fb_length: u64_, pub fbio_mask: u64_, pub fb_bus_width: u32_, @@ -527,16 +535,20 @@ pub struct GspStaticConfigInfo_t { pub bIsMigSupported: u8_, pub RTD3GC6TotalBoardPower: u16_, pub RTD3GC6PerstDelay: u16_, + pub __bindgen_padding_3: [u8; 2usize], pub bar1PdeBase: u64_, pub bar2PdeBase: u64_, pub bVbiosValid: u8_, + pub __bindgen_padding_4: [u8; 3usize], pub vbiosSubVendor: u32_, pub vbiosSubDevice: u32_, pub bPageRetirementSupported: u8_, pub bSplitVasBetweenServerClientRm: u8_, pub bClRootportNeedsNosnoopWAR: u8_, + pub __bindgen_padding_5: u8, pub displaylessMaxHeads: VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS, pub displaylessMaxResolution: VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS, + pub __bindgen_padding_6: [u8; 4usize], pub displaylessMaxPixels: u64_, pub hInternalClient: u32_, pub hInternalDevice: u32_, -- cgit v1.2.3 From 9d250ab0cf80deb11148efe862d1184ebf5115f6 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 16 Dec 2025 11:57:08 +0900 Subject: gpu: nova-core: gsp: fix length of received messages The size of messages' payload is miscalculated, leading to extra data passed to the message handler. While this is not a problem with our current set of commands, others with a variable-length payload may misbehave. Fix this by introducing a method returning the payload size and using it. Fixes: 75f6b1de8133 ("gpu: nova-core: gsp: Add GSP command queue bindings and handling") Reviewed-by: Lyude Paul Reviewed-by: Joel Fernandes Reviewed-by: Alistair Popple Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251216-nova-fixes-v3-2-c7469a71f7c4@nvidia.com [acourbot@nvidia.com: update `PANIC:` comments as pointed out by Joel.] Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/gsp/cmdq.rs | 14 ++++++++------ drivers/gpu/nova-core/gsp/fw.rs | 13 +++++++++---- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index 6f946d14868a..3991ccc0c10f 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -588,21 +588,23 @@ impl Cmdq { header.length(), ); + let payload_length = header.payload_length(); + // Check that the driver read area is large enough for the message. - if slice_1.len() + slice_2.len() < header.length() { + if slice_1.len() + slice_2.len() < payload_length { return Err(EIO); } // Cut the message slices down to the actual length of the message. - let (slice_1, slice_2) = if slice_1.len() > header.length() { - // PANIC: we checked above that `slice_1` is at least as long as `msg_header.length()`. - (slice_1.split_at(header.length()).0, &slice_2[0..0]) + let (slice_1, slice_2) = if slice_1.len() > payload_length { + // PANIC: we checked above that `slice_1` is at least as long as `payload_length`. + (slice_1.split_at(payload_length).0, &slice_2[0..0]) } else { ( slice_1, // PANIC: we checked above that `slice_1.len() + slice_2.len()` is at least as - // large as `msg_header.length()`. - slice_2.split_at(header.length() - slice_1.len()).0, + // large as `payload_length`. + slice_2.split_at(payload_length - slice_1.len()).0, ) }; diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index abffd6beec65..7b8e710b33e7 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -853,11 +853,16 @@ impl GspMsgElement { self.inner.checkSum = checksum; } - /// Returns the total length of the message. + /// Returns the length of the message's payload. + pub(crate) fn payload_length(&self) -> usize { + // `rpc.length` includes the length of the RPC message header. + num::u32_as_usize(self.inner.rpc.length) + .saturating_sub(size_of::()) + } + + /// Returns the total length of the message, message and RPC headers included. pub(crate) fn length(&self) -> usize { - // `rpc.length` includes the length of the GspRpcHeader but not the message header. - size_of::() - size_of::() - + num::u32_as_usize(self.inner.rpc.length) + size_of::() + self.payload_length() } // Returns the sequence number of the message. -- cgit v1.2.3 From 523317152c4b1b3187d14c65ceacdfc0da451931 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 16 Dec 2025 11:57:09 +0900 Subject: gpu: nova-core: bindings: derive `MaybeZeroable` Commit 4846300ba8f9 ("rust: derive `Zeroable` for all structs & unions generated by bindgen where possible") automatically derives `MaybeZeroable` for all bindings. This is better than selectively deriving `Zeroable` as it ensures all types that can implement `Zeroable` do. Regenerate the nova-core bindings so they benefit from this, and remove a now unneeded implementation of `Zeroable`. Fixes: 75f6b1de8133 ("gpu: nova-core: gsp: Add GSP command queue bindings and handling") Reviewed-by: Lyude Paul Reviewed-by: Joel Fernandes Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251216-nova-fixes-v3-3-c7469a71f7c4@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/gsp/fw.rs | 7 -- drivers/gpu/nova-core/gsp/fw/r570_144.rs | 11 ++- drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 93 ++++++++++++----------- 3 files changed, 54 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 7b8e710b33e7..b754631d2d8d 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -797,13 +797,6 @@ impl bindings::rpc_message_header_v { } } -// SAFETY: We can't derive the Zeroable trait for this binding because the -// procedural macro doesn't support the syntax used by bindgen to create the -// __IncompleteArrayField types. So instead we implement it here, which is safe -// because these are explicitly padded structures only containing types for -// which any bit pattern, including all zeros, is valid. -unsafe impl Zeroable for bindings::rpc_message_header_v {} - /// GSP Message Element. /// /// This is essentially a message header expected to be followed by the message data. diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144.rs b/drivers/gpu/nova-core/gsp/fw/r570_144.rs index 048234d1a9d1..e99d315ae74c 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs @@ -24,8 +24,11 @@ unreachable_pub, unsafe_op_in_unsafe_fn )] -use kernel::{ - ffi, - prelude::Zeroable, // -}; +use kernel::ffi; +use pin_init::MaybeZeroable; + include!("r570_144/bindings.rs"); + +// SAFETY: This type has a size of zero, so its inclusion into another type should not affect their +// ability to implement `Zeroable`. +unsafe impl kernel::prelude::Zeroable for __IncompleteArrayField {} diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs index 5f0569dcc4a0..6d25fe0bffa9 100644 --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs +++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs @@ -320,7 +320,7 @@ pub const NV_VGPU_MSG_EVENT_RECOVERY_ACTION: _bindgen_ty_3 = 4130; pub const NV_VGPU_MSG_EVENT_NUM_EVENTS: _bindgen_ty_3 = 4131; pub type _bindgen_ty_3 = ffi::c_uint; #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS { pub totalVFs: u32_, pub firstVfOffset: u32_, @@ -344,7 +344,7 @@ pub struct NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS { pub __bindgen_padding_1: [u8; 7usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS { pub BoardID: u32_, pub chipSKU: [ffi::c_char; 9usize], @@ -360,7 +360,7 @@ pub struct NV2080_CTRL_BIOS_GET_SKU_INFO_PARAMS { } pub type NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG = [u8_; 17usize]; #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO { pub base: u64_, pub limit: u64_, @@ -372,14 +372,14 @@ pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO { pub blackList: NV2080_CTRL_CMD_FB_GET_FB_REGION_SURFACE_MEM_TYPE_FLAG, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct NV2080_CTRL_CMD_FB_GET_FB_REGION_INFO_PARAMS { pub numFBRegions: u32_, pub __bindgen_padding_0: [u8; 4usize], pub fbRegion: [NV2080_CTRL_CMD_FB_GET_FB_REGION_FB_REGION_INFO; 16usize], } #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MaybeZeroable)] pub struct NV2080_CTRL_GPU_GET_GID_INFO_PARAMS { pub index: u32_, pub flags: u32_, @@ -396,14 +396,14 @@ impl Default for NV2080_CTRL_GPU_GET_GID_INFO_PARAMS { } } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct DOD_METHOD_DATA { pub status: u32_, pub acpiIdListLen: u32_, pub acpiIdList: [u32_; 16usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct JT_METHOD_DATA { pub status: u32_, pub jtCaps: u32_, @@ -412,14 +412,14 @@ pub struct JT_METHOD_DATA { pub __bindgen_padding_0: u8, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct MUX_METHOD_DATA_ELEMENT { pub acpiId: u32_, pub mode: u32_, pub status: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct MUX_METHOD_DATA { pub tableLen: u32_, pub acpiIdMuxModeTable: [MUX_METHOD_DATA_ELEMENT; 16usize], @@ -427,13 +427,13 @@ pub struct MUX_METHOD_DATA { pub acpiIdMuxStateTable: [MUX_METHOD_DATA_ELEMENT; 16usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct CAPS_METHOD_DATA { pub status: u32_, pub optimusCaps: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct ACPI_METHOD_DATA { pub bValid: u8_, pub __bindgen_padding_0: [u8; 3usize], @@ -443,20 +443,20 @@ pub struct ACPI_METHOD_DATA { pub capsMethodData: CAPS_METHOD_DATA, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct VIRTUAL_DISPLAY_GET_MAX_RESOLUTION_PARAMS { pub headIndex: u32_, pub maxHResolution: u32_, pub maxVResolution: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct VIRTUAL_DISPLAY_GET_NUM_HEADS_PARAMS { pub numHeads: u32_, pub maxNumHeads: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct BUSINFO { pub deviceID: u16_, pub vendorID: u16_, @@ -466,7 +466,7 @@ pub struct BUSINFO { pub __bindgen_padding_0: u8, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_VF_INFO { pub totalVFs: u32_, pub firstVFOffset: u32_, @@ -479,25 +479,25 @@ pub struct GSP_VF_INFO { pub __bindgen_padding_0: [u8; 5usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_PCIE_CONFIG_REG { pub linkCap: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct EcidManufacturingInfo { pub ecidLow: u32_, pub ecidHigh: u32_, pub ecidExtended: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct FW_WPR_LAYOUT_OFFSET { pub nonWprHeapOffset: u64_, pub frtsOffset: u64_, } #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MaybeZeroable)] pub struct GspStaticConfigInfo_t { pub grCapsBits: [u8_; 23usize], pub __bindgen_padding_0: u8, @@ -570,7 +570,7 @@ impl Default for GspStaticConfigInfo_t { } } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GspSystemInfo { pub gpuPhysAddr: u64_, pub gpuPhysFbAddr: u64_, @@ -627,7 +627,7 @@ pub struct GspSystemInfo { pub hostPageSize: u64_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct MESSAGE_QUEUE_INIT_ARGUMENTS { pub sharedMemPhysAddr: u64_, pub pageTableEntryCount: u32_, @@ -636,7 +636,7 @@ pub struct MESSAGE_QUEUE_INIT_ARGUMENTS { pub statQueueOffset: u64_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SR_INIT_ARGUMENTS { pub oldLevel: u32_, pub flags: u32_, @@ -644,7 +644,7 @@ pub struct GSP_SR_INIT_ARGUMENTS { pub __bindgen_padding_0: [u8; 3usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_ARGUMENTS_CACHED { pub messageQueueInitArguments: MESSAGE_QUEUE_INIT_ARGUMENTS, pub srInitArguments: GSP_SR_INIT_ARGUMENTS, @@ -654,13 +654,13 @@ pub struct GSP_ARGUMENTS_CACHED { pub profilerArgs: GSP_ARGUMENTS_CACHED__bindgen_ty_1, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_ARGUMENTS_CACHED__bindgen_ty_1 { pub pa: u64_, pub size: u64_, } #[repr(C)] -#[derive(Copy, Clone, Zeroable)] +#[derive(Copy, Clone, MaybeZeroable)] pub union rpc_message_rpc_union_field_v03_00 { pub spare: u32_, pub cpuRmGfid: u32_, @@ -676,6 +676,7 @@ impl Default for rpc_message_rpc_union_field_v03_00 { } pub type rpc_message_rpc_union_field_v = rpc_message_rpc_union_field_v03_00; #[repr(C)] +#[derive(MaybeZeroable)] pub struct rpc_message_header_v03_00 { pub header_version: u32_, pub signature: u32_, @@ -698,7 +699,7 @@ impl Default for rpc_message_header_v03_00 { } pub type rpc_message_header_v = rpc_message_header_v03_00; #[repr(C)] -#[derive(Copy, Clone, Zeroable)] +#[derive(Copy, Clone, MaybeZeroable)] pub struct GspFwWprMeta { pub magic: u64_, pub revision: u64_, @@ -733,19 +734,19 @@ pub struct GspFwWprMeta { pub verified: u64_, } #[repr(C)] -#[derive(Copy, Clone, Zeroable)] +#[derive(Copy, Clone, MaybeZeroable)] pub union GspFwWprMeta__bindgen_ty_1 { pub __bindgen_anon_1: GspFwWprMeta__bindgen_ty_1__bindgen_ty_1, pub __bindgen_anon_2: GspFwWprMeta__bindgen_ty_1__bindgen_ty_2, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GspFwWprMeta__bindgen_ty_1__bindgen_ty_1 { pub sysmemAddrOfSignature: u64_, pub sizeOfSignature: u64_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GspFwWprMeta__bindgen_ty_1__bindgen_ty_2 { pub gspFwHeapFreeListWprOffset: u32_, pub unused0: u32_, @@ -761,13 +762,13 @@ impl Default for GspFwWprMeta__bindgen_ty_1 { } } #[repr(C)] -#[derive(Copy, Clone, Zeroable)] +#[derive(Copy, Clone, MaybeZeroable)] pub union GspFwWprMeta__bindgen_ty_2 { pub __bindgen_anon_1: GspFwWprMeta__bindgen_ty_2__bindgen_ty_1, pub __bindgen_anon_2: GspFwWprMeta__bindgen_ty_2__bindgen_ty_2, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GspFwWprMeta__bindgen_ty_2__bindgen_ty_1 { pub partitionRpcAddr: u64_, pub partitionRpcRequestOffset: u16_, @@ -779,7 +780,7 @@ pub struct GspFwWprMeta__bindgen_ty_2__bindgen_ty_1 { pub lsUcodeVersion: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GspFwWprMeta__bindgen_ty_2__bindgen_ty_2 { pub partitionRpcPadding: [u32_; 4usize], pub sysmemAddrOfCrashReportQueue: u64_, @@ -814,7 +815,7 @@ pub const LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_SYSMEM: LibosMemoryRegion pub const LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_FB: LibosMemoryRegionLoc = 2; pub type LibosMemoryRegionLoc = ffi::c_uint; #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct LibosMemoryRegionInitArgument { pub id8: LibosAddress, pub pa: LibosAddress, @@ -824,7 +825,7 @@ pub struct LibosMemoryRegionInitArgument { pub __bindgen_padding_0: [u8; 6usize], } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct PACKED_REGISTRY_ENTRY { pub nameOffset: u32_, pub type_: u8_, @@ -833,14 +834,14 @@ pub struct PACKED_REGISTRY_ENTRY { pub length: u32_, } #[repr(C)] -#[derive(Debug, Default)] +#[derive(Debug, Default, MaybeZeroable)] pub struct PACKED_REGISTRY_TABLE { pub size: u32_, pub numEntries: u32_, pub entries: __IncompleteArrayField, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct msgqTxHeader { pub version: u32_, pub size: u32_, @@ -852,13 +853,13 @@ pub struct msgqTxHeader { pub entryOff: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone, Zeroable)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct msgqRxHeader { pub readPtr: u32_, } #[repr(C)] #[repr(align(8))] -#[derive(Zeroable)] +#[derive(MaybeZeroable)] pub struct GSP_MSG_QUEUE_ELEMENT { pub authTagBuffer: [u8_; 16usize], pub aadBuffer: [u8_; 16usize], @@ -878,7 +879,7 @@ impl Default for GSP_MSG_QUEUE_ELEMENT { } } #[repr(C)] -#[derive(Debug, Default)] +#[derive(Debug, Default, MaybeZeroable)] pub struct rpc_run_cpu_sequencer_v17_00 { pub bufferSizeDWord: u32_, pub cmdIndex: u32_, @@ -896,20 +897,20 @@ pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT: GSP_SEQ_BUF_ pub const GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME: GSP_SEQ_BUF_OPCODE = 8; pub type GSP_SEQ_BUF_OPCODE = ffi::c_uint; #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SEQ_BUF_PAYLOAD_REG_WRITE { pub addr: u32_, pub val: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SEQ_BUF_PAYLOAD_REG_MODIFY { pub addr: u32_, pub mask: u32_, pub val: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SEQ_BUF_PAYLOAD_REG_POLL { pub addr: u32_, pub mask: u32_, @@ -918,24 +919,24 @@ pub struct GSP_SEQ_BUF_PAYLOAD_REG_POLL { pub error: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SEQ_BUF_PAYLOAD_DELAY_US { pub val: u32_, } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone, MaybeZeroable)] pub struct GSP_SEQ_BUF_PAYLOAD_REG_STORE { pub addr: u32_, pub index: u32_, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, MaybeZeroable)] pub struct GSP_SEQUENCER_BUFFER_CMD { pub opCode: GSP_SEQ_BUF_OPCODE, pub payload: GSP_SEQUENCER_BUFFER_CMD__bindgen_ty_1, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, MaybeZeroable)] pub union GSP_SEQUENCER_BUFFER_CMD__bindgen_ty_1 { pub regWrite: GSP_SEQ_BUF_PAYLOAD_REG_WRITE, pub regModify: GSP_SEQ_BUF_PAYLOAD_REG_MODIFY, -- cgit v1.2.3 From b58c87b0fde0ac06d550659a7e3ddbcd9183b7b9 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 16 Dec 2025 11:57:10 +0900 Subject: gpu: nova-core: gsp: replace firmware version with "bindings" alias We have an "bindings" alias to avoid having to mention the firmware version again and again, and limit the diff when upgrading the firmware. Use it where we neglected to. Fixes: eaf0989c77e4 ("gpu: nova-core: Add bindings required by GSP sequencer") Reviewed-by: Lyude Paul Reviewed-by: Joel Fernandes Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251216-nova-fixes-v3-4-c7469a71f7c4@nvidia.com Signed-off-by: Alexandre Courbot --- drivers/gpu/nova-core/gsp/fw.rs | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index b754631d2d8d..caeb0d251fe5 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -141,8 +141,8 @@ unsafe impl AsBytes for GspFwWprMeta {} // are valid. unsafe impl FromBytes for GspFwWprMeta {} -type GspFwWprMetaBootResumeInfo = r570_144::GspFwWprMeta__bindgen_ty_1; -type GspFwWprMetaBootInfo = r570_144::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; +type GspFwWprMetaBootResumeInfo = bindings::GspFwWprMeta__bindgen_ty_1; +type GspFwWprMetaBootInfo = bindings::GspFwWprMeta__bindgen_ty_1__bindgen_ty_1; impl GspFwWprMeta { /// Fill in and return a `GspFwWprMeta` suitable for booting `gsp_firmware` using the @@ -150,8 +150,8 @@ impl GspFwWprMeta { pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Self { Self(bindings::GspFwWprMeta { // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` unmodified. - magic: r570_144::GSP_FW_WPR_META_MAGIC as u64, - revision: u64::from(r570_144::GSP_FW_WPR_META_REVISION), + magic: bindings::GSP_FW_WPR_META_MAGIC as u64, + revision: u64::from(bindings::GSP_FW_WPR_META_REVISION), sysmemAddrOfRadix3Elf: gsp_firmware.radix3_dma_handle(), sizeOfRadix3Elf: u64::from_safe_cast(gsp_firmware.size), sysmemAddrOfBootloader: gsp_firmware.bootloader.ucode.dma_handle(), @@ -315,19 +315,19 @@ impl From for u32 { #[repr(u32)] pub(crate) enum SeqBufOpcode { // Core operation opcodes - CoreReset = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET, - CoreResume = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME, - CoreStart = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START, - CoreWaitForHalt = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT, + CoreReset = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET, + CoreResume = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME, + CoreStart = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START, + CoreWaitForHalt = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT, // Delay opcode - DelayUs = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US, + DelayUs = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US, // Register operation opcodes - RegModify = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY, - RegPoll = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL, - RegStore = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE, - RegWrite = r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE, + RegModify = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY, + RegPoll = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL, + RegStore = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE, + RegWrite = bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE, } impl fmt::Display for SeqBufOpcode { @@ -351,25 +351,25 @@ impl TryFrom for SeqBufOpcode { fn try_from(value: u32) -> Result { match value { - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET => { + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESET => { Ok(SeqBufOpcode::CoreReset) } - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME => { + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_RESUME => { Ok(SeqBufOpcode::CoreResume) } - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START => { + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_START => { Ok(SeqBufOpcode::CoreStart) } - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT => { + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_CORE_WAIT_FOR_HALT => { Ok(SeqBufOpcode::CoreWaitForHalt) } - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US => Ok(SeqBufOpcode::DelayUs), - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY => { + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_DELAY_US => Ok(SeqBufOpcode::DelayUs), + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_MODIFY => { Ok(SeqBufOpcode::RegModify) } - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL => Ok(SeqBufOpcode::RegPoll), - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => Ok(SeqBufOpcode::RegStore), - r570_144::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE => Ok(SeqBufOpcode::RegWrite), + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_POLL => Ok(SeqBufOpcode::RegPoll), + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_STORE => Ok(SeqBufOpcode::RegStore), + bindings::GSP_SEQ_BUF_OPCODE_GSP_SEQ_BUF_OPCODE_REG_WRITE => Ok(SeqBufOpcode::RegWrite), _ => Err(EINVAL), } } @@ -385,7 +385,7 @@ impl From for u32 { /// Wrapper for GSP sequencer register write payload. #[repr(transparent)] #[derive(Copy, Clone)] -pub(crate) struct RegWritePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_WRITE); +pub(crate) struct RegWritePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_WRITE); impl RegWritePayload { /// Returns the register address. @@ -408,7 +408,7 @@ unsafe impl AsBytes for RegWritePayload {} /// Wrapper for GSP sequencer register modify payload. #[repr(transparent)] #[derive(Copy, Clone)] -pub(crate) struct RegModifyPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY); +pub(crate) struct RegModifyPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY); impl RegModifyPayload { /// Returns the register address. @@ -436,7 +436,7 @@ unsafe impl AsBytes for RegModifyPayload {} /// Wrapper for GSP sequencer register poll payload. #[repr(transparent)] #[derive(Copy, Clone)] -pub(crate) struct RegPollPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_POLL); +pub(crate) struct RegPollPayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_POLL); impl RegPollPayload { /// Returns the register address. @@ -469,7 +469,7 @@ unsafe impl AsBytes for RegPollPayload {} /// Wrapper for GSP sequencer delay payload. #[repr(transparent)] #[derive(Copy, Clone)] -pub(crate) struct DelayUsPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_DELAY_US); +pub(crate) struct DelayUsPayload(bindings::GSP_SEQ_BUF_PAYLOAD_DELAY_US); impl DelayUsPayload { /// Returns the delay value in microseconds. @@ -487,7 +487,7 @@ unsafe impl AsBytes for DelayUsPayload {} /// Wrapper for GSP sequencer register store payload. #[repr(transparent)] #[derive(Copy, Clone)] -pub(crate) struct RegStorePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_STORE); +pub(crate) struct RegStorePayload(bindings::GSP_SEQ_BUF_PAYLOAD_REG_STORE); impl RegStorePayload { /// Returns the register address. @@ -510,7 +510,7 @@ unsafe impl AsBytes for RegStorePayload {} /// Wrapper for GSP sequencer buffer command. #[repr(transparent)] -pub(crate) struct SequencerBufferCmd(r570_144::GSP_SEQUENCER_BUFFER_CMD); +pub(crate) struct SequencerBufferCmd(bindings::GSP_SEQUENCER_BUFFER_CMD); impl SequencerBufferCmd { /// Returns the opcode as a `SeqBufOpcode` enum, or error if invalid. @@ -612,7 +612,7 @@ unsafe impl AsBytes for SequencerBufferCmd {} /// Wrapper for GSP run CPU sequencer RPC. #[repr(transparent)] -pub(crate) struct RunCpuSequencer(r570_144::rpc_run_cpu_sequencer_v17_00); +pub(crate) struct RunCpuSequencer(bindings::rpc_run_cpu_sequencer_v17_00); impl RunCpuSequencer { /// Returns the command index. -- cgit v1.2.3 From ca5898222914f399797cea1aeb0ce77109ca2e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 14 Nov 2025 00:28:52 +0200 Subject: wifi: iwlwifi: Fix firmware version handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On my system the arithmetic done on the firmware numbers results in a negative number, but since the types are unsigned it gets interpreted as a large positive number. The end result is that the firmware gets rejected and wifi is defunct. Switch to signed types to handle this case correctly. iwlwifi 0000:0c:00.0: Driver unable to support your firmware API. Driver supports FW core 4294967294..2, firmware is 2. iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-4.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-3.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-2.ucode failed with error -2 iwlwifi 0000:0c:00.0: Direct firmware load for iwlwifi-5000-1.ucode failed with error -2 iwlwifi 0000:0c:00.0: no suitable firmware found! iwlwifi 0000:0c:00.0: minimum version required: iwlwifi-5000-1 iwlwifi 0000:0c:00.0: maximum version supported: iwlwifi-5000-5 iwlwifi 0000:0c:00.0: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git Cc: stable@vger.kernel.org Fixes: 5f708cccde9d ("wifi: iwlwifi: add a new FW file numbering scheme") Signed-off-by: Ville Syrjälä Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220805 Link: https://patch.msgid.link/20251113222852.15896-1-ville.syrjala@linux.intel.com Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 3391f07b01de..f8fc6f30fbe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1597,7 +1597,7 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) */ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) { - unsigned int min_core, max_core, loaded_core; + int min_core, max_core, loaded_core; struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; const struct iwl_ucode_header *ucode; @@ -1676,7 +1676,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) if (loaded_core < min_core || loaded_core > max_core) { IWL_ERR(drv, "Driver unable to support your firmware API. " - "Driver supports FW core %u..%u, firmware is %u.\n", + "Driver supports FW core %d..%d, firmware is %d.\n", min_core, max_core, loaded_core); goto try_again; } -- cgit v1.2.3 From 81d90d93d22ca4f61833cba921dce9a0bd82218f Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 4 Dec 2025 12:32:04 +0000 Subject: wifi: iwlwifi: Implement settime64 as stub for MVM/MLD PTP Since commit dfb073d32cac ("ptp: Return -EINVAL on ptp_clock_register if required ops are NULL"), PTP clock registered through ptp_clock_register is required to have ptp_clock_info.settime64 set, however, neither MVM nor MLD's PTP clock implementation sets it, resulting in warnings when the interface starts up, like WARNING: drivers/ptp/ptp_clock.c:325 at ptp_clock_register+0x2c8/0x6b8, CPU#1: wpa_supplicant/469 CPU: 1 UID: 0 PID: 469 Comm: wpa_supplicant Not tainted 6.18.0+ #101 PREEMPT(full) ra: ffff800002732cd4 iwl_mvm_ptp_init+0x114/0x188 [iwlmvm] ERA: 9000000002fdc468 ptp_clock_register+0x2c8/0x6b8 iwlwifi 0000:01:00.0: Failed to register PHC clock (-22) I don't find an appropriate firmware interface to implement settime64() for iwlwifi MLD/MVM, thus instead create a stub that returns -EOPTNOTSUPP only, suppressing the warning and allowing the PTP clock to be registered. Reported-by: Nathan Chancellor Closes: https://lore.kernel.org/all/20251108044822.GA3262936@ax162/ Signed-off-by: Yao Zi Tested-by: Nathan Chancellor Reviewed-by: Simon Horman tested-by: damian Tometzki damian@riscv-rocks.de Tested-by: Oliver Hartkopp Acked-by: Miri Korenblit Link: https://patch.msgid.link/20251204123204.9316-1-ziyao@disroot.org Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mld/ptp.c | 7 +++++++ drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index ffeb37a7f830..231920425c06 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -121,6 +121,12 @@ static int iwl_mld_ptp_gettime(struct ptp_clock_info *ptp, return 0; } +static int iwl_mld_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + static int iwl_mld_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct iwl_mld *mld = container_of(ptp, struct iwl_mld, @@ -279,6 +285,7 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) mld->ptp_data.ptp_clock_info.owner = THIS_MODULE; mld->ptp_data.ptp_clock_info.gettime64 = iwl_mld_ptp_gettime; + mld->ptp_data.ptp_clock_info.settime64 = iwl_mld_ptp_settime; mld->ptp_data.ptp_clock_info.max_adj = 0x7fffffff; mld->ptp_data.ptp_clock_info.adjtime = iwl_mld_ptp_adjtime; mld->ptp_data.ptp_clock_info.adjfine = iwl_mld_ptp_adjfine; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 06a4c9f74797..ad156b82eaa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -220,6 +220,12 @@ static int iwl_mvm_ptp_gettime(struct ptp_clock_info *ptp, return 0; } +static int iwl_mvm_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + static int iwl_mvm_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, @@ -281,6 +287,7 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) mvm->ptp_data.ptp_clock_info.adjfine = iwl_mvm_ptp_adjfine; mvm->ptp_data.ptp_clock_info.adjtime = iwl_mvm_ptp_adjtime; mvm->ptp_data.ptp_clock_info.gettime64 = iwl_mvm_ptp_gettime; + mvm->ptp_data.ptp_clock_info.settime64 = iwl_mvm_ptp_settime; mvm->ptp_data.scaled_freq = SCALE_FACTOR; /* Give a short 'friendly name' to identify the PHC clock */ -- cgit v1.2.3 From a7b8e876e0ef0232b8076972c57ce9a7286b47ca Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Nov 2025 13:37:28 -0400 Subject: RDMA/core: Check for the presence of LS_NLA_TYPE_DGID correctly The netlink response for RDMA_NL_LS_OP_IP_RESOLVE should always have a LS_NLA_TYPE_DGID attribute, it is invalid if it does not. Use the nl parsing logic properly and call nla_parse_deprecated() to fill the nlattrs array and then directly index that array to get the data for the DGID. Just fail if it is NULL. Remove the for loop searching for the nla, and squash the validation and parsing into one function. Fixes an uninitialized read from the stack triggered by userspace if it does not provide the DGID to a kernel initiated RDMA_NL_LS_OP_IP_RESOLVE query. BUG: KMSAN: uninit-value in hex_byte_pack include/linux/hex.h:13 [inline] BUG: KMSAN: uninit-value in ip6_string+0xef4/0x13a0 lib/vsprintf.c:1490 hex_byte_pack include/linux/hex.h:13 [inline] ip6_string+0xef4/0x13a0 lib/vsprintf.c:1490 ip6_addr_string+0x18a/0x3e0 lib/vsprintf.c:1509 ip_addr_string+0x245/0xee0 lib/vsprintf.c:1633 pointer+0xc09/0x1bd0 lib/vsprintf.c:2542 vsnprintf+0xf8a/0x1bd0 lib/vsprintf.c:2930 vprintk_store+0x3ae/0x1530 kernel/printk/printk.c:2279 vprintk_emit+0x307/0xcd0 kernel/printk/printk.c:2426 vprintk_default+0x3f/0x50 kernel/printk/printk.c:2465 vprintk+0x36/0x50 kernel/printk/printk_safe.c:82 _printk+0x17e/0x1b0 kernel/printk/printk.c:2475 ib_nl_process_good_ip_rsep drivers/infiniband/core/addr.c:128 [inline] ib_nl_handle_ip_res_resp+0x963/0x9d0 drivers/infiniband/core/addr.c:141 rdma_nl_rcv_msg drivers/infiniband/core/netlink.c:-1 [inline] rdma_nl_rcv_skb drivers/infiniband/core/netlink.c:239 [inline] rdma_nl_rcv+0xefa/0x11c0 drivers/infiniband/core/netlink.c:259 netlink_unicast_kernel net/netlink/af_netlink.c:1320 [inline] netlink_unicast+0xf04/0x12b0 net/netlink/af_netlink.c:1346 netlink_sendmsg+0x10b3/0x1250 net/netlink/af_netlink.c:1896 sock_sendmsg_nosec net/socket.c:714 [inline] __sock_sendmsg+0x333/0x3d0 net/socket.c:729 ____sys_sendmsg+0x7e0/0xd80 net/socket.c:2617 ___sys_sendmsg+0x271/0x3b0 net/socket.c:2671 __sys_sendmsg+0x1aa/0x300 net/socket.c:2703 __compat_sys_sendmsg net/compat.c:346 [inline] __do_compat_sys_sendmsg net/compat.c:353 [inline] __se_compat_sys_sendmsg net/compat.c:350 [inline] __ia32_compat_sys_sendmsg+0xa4/0x100 net/compat.c:350 ia32_sys_call+0x3f6c/0x4310 arch/x86/include/generated/asm/syscalls_32.h:371 do_syscall_32_irqs_on arch/x86/entry/syscall_32.c:83 [inline] __do_fast_syscall_32+0xb0/0x150 arch/x86/entry/syscall_32.c:306 do_fast_syscall_32+0x38/0x80 arch/x86/entry/syscall_32.c:331 do_SYSENTER_32+0x1f/0x30 arch/x86/entry/syscall_32.c:3 Link: https://patch.msgid.link/r/0-v1-3fbaef094271+2cf-rdma_op_ip_rslv_syz_jgg@nvidia.com Cc: stable@vger.kernel.org Fixes: ae43f8286730 ("IB/core: Add IP to GID netlink offload") Reported-by: syzbot+938fcd548c303fe33c1a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/r/68dc3dac.a00a0220.102ee.004f.GAE@google.com Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/addr.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 61596cda2b65..35ba852a172a 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -80,37 +80,25 @@ static const struct nla_policy ib_nl_addr_policy[LS_NLA_TYPE_MAX] = { .min = sizeof(struct rdma_nla_ls_gid)}, }; -static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh) +static void ib_nl_process_ip_rsep(const struct nlmsghdr *nlh) { struct nlattr *tb[LS_NLA_TYPE_MAX] = {}; + union ib_gid gid; + struct addr_req *req; + int found = 0; int ret; if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR) - return false; + return; ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), nlmsg_len(nlh), ib_nl_addr_policy, NULL); if (ret) - return false; - - return true; -} - -static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh) -{ - const struct nlattr *head, *curr; - union ib_gid gid; - struct addr_req *req; - int len, rem; - int found = 0; - - head = (const struct nlattr *)nlmsg_data(nlh); - len = nlmsg_len(nlh); + return; - nla_for_each_attr(curr, head, len, rem) { - if (curr->nla_type == LS_NLA_TYPE_DGID) - memcpy(&gid, nla_data(curr), nla_len(curr)); - } + if (!tb[LS_NLA_TYPE_DGID]) + return; + memcpy(&gid, nla_data(tb[LS_NLA_TYPE_DGID]), sizeof(gid)); spin_lock_bh(&lock); list_for_each_entry(req, &req_list, list) { @@ -137,8 +125,7 @@ int ib_nl_handle_ip_res_resp(struct sk_buff *skb, !(NETLINK_CB(skb).sk)) return -EPERM; - if (ib_nl_is_good_ip_resp(nlh)) - ib_nl_process_good_ip_rsep(nlh); + ib_nl_process_ip_rsep(nlh); return 0; } -- cgit v1.2.3 From 57f3cb6c84159d12ba343574df2115fb18dd83ca Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 28 Nov 2025 20:53:21 -0400 Subject: RDMA/cm: Fix leaking the multicast GID table reference If the CM ID is destroyed while the CM event for multicast creating is still queued the cancel_work_sync() will prevent the work from running which also prevents destroying the ah_attr. This leaks a refcount and triggers a WARN: GID entry ref leak for dev syz1 index 2 ref=573 WARNING: CPU: 1 PID: 655 at drivers/infiniband/core/cache.c:809 release_gid_table drivers/infiniband/core/cache.c:806 [inline] WARNING: CPU: 1 PID: 655 at drivers/infiniband/core/cache.c:809 gid_table_release_one+0x284/0x3cc drivers/infiniband/core/cache.c:886 Destroy the ah_attr after canceling the work, it is safe to call this twice. Link: https://patch.msgid.link/r/0-v1-4285d070a6b2+20a-rdma_mc_gid_leak_syz_jgg@nvidia.com Cc: stable@vger.kernel.org Fixes: fe454dc31e84 ("RDMA/ucma: Fix use-after-free bug in ucma_create_uevent") Reported-by: syzbot+b0da83a6c0e2e2bddbd4@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68232e7b.050a0220.f2294.09f6.GAE@google.com Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 95e89f5c147c..f00f1d3fbd9c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2009,6 +2009,7 @@ static void destroy_mc(struct rdma_id_private *id_priv, ib_sa_free_multicast(mc->sa_mc); if (rdma_protocol_roce(id_priv->id.device, id_priv->id.port_num)) { + struct rdma_cm_event *event = &mc->iboe_join.event; struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct net_device *ndev = NULL; @@ -2031,6 +2032,8 @@ static void destroy_mc(struct rdma_id_private *id_priv, dev_put(ndev); cancel_work_sync(&mc->iboe_join.work); + if (event->event == RDMA_CM_EVENT_MULTICAST_JOIN) + rdma_destroy_ah_attr(&event->param.ud.ah_attr); } kfree(mc); } -- cgit v1.2.3 From 1f7d6e2efeedd8f545d3e0e9bf338023bf4ea584 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 11 Dec 2025 10:06:51 +0000 Subject: scsi: scsi_debug: Fix atomic write enable module param description The atomic write enable module param is "atomic_wr", and not "atomic_write", so fix the module param description. Fixes: 84f3a3c01d70 ("scsi: scsi_debug: Atomic write support") Signed-off-by: John Garry Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20251211100651.9056-1-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1f2a53ba5dd9..c5085e6d2e75 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7459,7 +7459,7 @@ MODULE_PARM_DESC(lbprz, MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(atomic_write, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); +MODULE_PARM_DESC(atomic_wr, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); -- cgit v1.2.3 From d373163194982f43b92c552c138c29d9f0b79553 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Thu, 11 Dec 2025 05:59:29 +0530 Subject: scsi: mpi3mr: Read missing IOCFacts flag for reply queue full overflow The driver was not reading the MAX_REQ_PER_REPLY_QUEUE_LIMIT IOCFacts flag, so the reply-queue-full handling was never enabled, even on firmware that supports it. Reading this flag enables the feature and prevents reply queue overflow. Fixes: f08b24d82749 ("scsi: mpi3mr: Avoid reply queue full condition") Cc: stable@vger.kernel.org Signed-off-by: Chandrakanth Patil Link: https://patch.msgid.link/20251211002929.22071-1-chandrakanth.patil@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 1 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index b42933fcd423..6561f98c3cb2 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -166,6 +166,7 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) +#define MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT (0x00000040) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e..8c4bb7169a87 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3158,6 +3158,8 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.dma_mask = (facts_flags & MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + mrioc->facts.max_req_limit = (facts_flags & + MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT); mrioc->facts.protocol_flags = facts_data->protocol_flags; mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); -- cgit v1.2.3 From 0e1677654259a2f3ccf728de1edde922a3c4ba57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 12 Dec 2025 17:08:23 +0100 Subject: scsi: sg: Fix occasional bogus elapsed time that exceeds timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A race condition was found in sg_proc_debug_helper(). It was observed on a system using an IBM LTO-9 SAS Tape Drive (ULTRIUM-TD9) and monitoring /proc/scsi/sg/debug every second. A very large elapsed time would sometimes appear. This is caused by two race conditions. We reproduced the issue with an IBM ULTRIUM-HH9 tape drive on an x86_64 architecture. A patched kernel was built, and the race condition could not be observed anymore after the application of this patch. A reproducer C program utilising the scsi_debug module was also built by Changhui Zhong and can be viewed here: https://github.com/MichaelRabek/linux-tests/blob/master/drivers/scsi/sg/sg_race_trigger.c The first race happens between the reading of hp->duration in sg_proc_debug_helper() and request completion in sg_rq_end_io(). The hp->duration member variable may hold either of two types of information: #1 - The start time of the request. This value is present while the request is not yet finished. #2 - The total execution time of the request (end_time - start_time). If sg_proc_debug_helper() executes *after* the value of hp->duration was changed from #1 to #2, but *before* srp->done is set to 1 in sg_rq_end_io(), a fresh timestamp is taken in the else branch, and the elapsed time (value type #2) is subtracted from a timestamp, which cannot yield a valid elapsed time (which is a type #2 value as well). To fix this issue, the value of hp->duration must change under the protection of the sfp->rq_list_lock in sg_rq_end_io(). Since sg_proc_debug_helper() takes this read lock, the change to srp->done and srp->header.duration will happen atomically from the perspective of sg_proc_debug_helper() and the race condition is thus eliminated. The second race condition happens between sg_proc_debug_helper() and sg_new_write(). Even though hp->duration is set to the current time stamp in sg_add_request() under the write lock's protection, it gets overwritten by a call to get_sg_io_hdr(), which calls copy_from_user() to copy struct sg_io_hdr from userspace into kernel space. hp->duration is set to the start time again in sg_common_write(). If sg_proc_debug_helper() is called between these two calls, an arbitrary value set by userspace (usually zero) is used to compute the elapsed time. To fix this issue, hp->duration must be set to the current timestamp again after get_sg_io_hdr() returns successfully. A small race window still exists between get_sg_io_hdr() and setting hp->duration, but this window is only a few instructions wide and does not result in observable issues in practice, as confirmed by testing. Additionally, we fix the format specifier from %d to %u for printing unsigned int values in sg_proc_debug_helper(). Signed-off-by: Michal Rábek Suggested-by: Tomas Henzl Tested-by: Changhui Zhong Reviewed-by: Ewan D. Milne Reviewed-by: John Meneghini Reviewed-by: Tomas Henzl Link: https://patch.msgid.link/20251212160900.64924-1-mrabek@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b3af9b78fa12..57fba34832ad 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -731,6 +731,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } + hp->duration = jiffies_to_msecs(jiffies); + if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; @@ -815,7 +817,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return -ENODEV; } - hp->duration = jiffies_to_msecs(jiffies); if (hp->interface_id != '\0' && /* v3 (or later) interface */ (SG_FLAG_Q_AT_TAIL & hp->flags)) at_head = 0; @@ -1338,9 +1339,6 @@ sg_rq_end_io(struct request *rq, blk_status_t status) "sg_cmd_done: pack_id=%d, res=0x%x\n", srp->header.pack_id, result)); srp->header.resid = resid; - ms = jiffies_to_msecs(jiffies); - srp->header.duration = (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; if (0 != result) { struct scsi_sense_hdr sshdr; @@ -1389,6 +1387,9 @@ sg_rq_end_io(struct request *rq, blk_status_t status) done = 0; } srp->done = done; + ms = jiffies_to_msecs(jiffies); + srp->header.duration = (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (likely(done)) { @@ -2533,6 +2534,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) const sg_io_hdr_t *hp; const char * cp; unsigned int ms; + unsigned int duration; k = 0; list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { @@ -2570,13 +2572,17 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - seq_printf(s, " dur=%d", hp->duration); + seq_printf(s, " dur=%u", hp->duration); else { ms = jiffies_to_msecs(jiffies); - seq_printf(s, " t_o/elap=%d/%d", + duration = READ_ONCE(hp->duration); + if (duration) + duration = (ms > duration ? + ms - duration : 0); + seq_printf(s, " t_o/elap=%u/%u", (new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout)), - (ms > hp->duration ? ms - hp->duration : 0)); + duration); } seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); -- cgit v1.2.3 From c9f36f04a8a2725172cdf2b5e32363e4addcb14c Mon Sep 17 00:00:00 2001 From: Seunghwan Baek Date: Wed, 10 Dec 2025 15:38:54 +0900 Subject: scsi: ufs: core: Add ufshcd_update_evt_hist() for UFS suspend error If UFS resume fails, the event history is updated in ufshcd_resume(), but there is no code anywhere to record UFS suspend. Therefore, add code to record UFS suspend error event history. Fixes: dd11376b9f1b ("scsi: ufs: Split the drivers/scsi/ufs directory") Cc: stable@vger.kernel.org Signed-off-by: Seunghwan Baek Reviewed-by: Peter Wang Link: https://patch.msgid.link/20251210063854.1483899-2-sh8267.baek@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 80c0b49f30b0..0babb7035200 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10359,7 +10359,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) ret = ufshcd_setup_clocks(hba, false); if (ret) { ufshcd_enable_irq(hba); - return ret; + goto out; } if (ufshcd_is_clkgating_allowed(hba)) { hba->clk_gating.state = CLKS_OFF; @@ -10371,6 +10371,9 @@ static int ufshcd_suspend(struct ufs_hba *hba) /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); ufshcd_pm_qos_update(hba, false); +out: + if (ret) + ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret); return ret; } -- cgit v1.2.3 From 74098cc06e753d3ffd8398b040a3a1dfb65260c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bartosik?= Date: Thu, 27 Nov 2025 11:16:44 +0000 Subject: xhci: dbgtty: fix device unregister: fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixup replaces tty_vhangup() call with call to tty_port_tty_vhangup(). Both calls hangup tty device synchronously however tty_port_tty_vhangup() increases reference count during the hangup operation using scoped_guard(tty_port_tty). Cc: stable Fixes: 1f73b8b56cf3 ("xhci: dbgtty: fix device unregister") Signed-off-by: Łukasz Bartosik Link: https://patch.msgid.link/20251127111644.3161386-1-ukaszb@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbgtty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 57cdda4e09c8..90282e51e23e 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -554,7 +554,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc) * Hang up the TTY. This wakes up any blocked * writers and causes subsequent writes to fail. */ - tty_vhangup(port->port.tty); + tty_port_tty_vhangup(&port->port); tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); -- cgit v1.2.3 From e1003aa7ec9eccdde4c926bd64ef42816ad55f25 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 26 Nov 2025 11:12:21 +0530 Subject: usb: dwc3: keep susphy enabled during exit to avoid controller faults On some platforms, switching USB roles from host to device can trigger controller faults due to premature PHY power-down. This occurs when the PHY is disabled too early during teardown, causing synchronization issues between the PHY and controller. Keep susphy enabled during dwc3_host_exit() and dwc3_gadget_exit() ensures the PHY remains in a low-power state capable of handling required commands during role switch. Cc: stable Fixes: 6d735722063a ("usb: dwc3: core: Prevent phy suspend during init") Suggested-by: Thinh Nguyen Signed-off-by: Udipto Goswami Acked-by: Thinh Nguyen Link: https://patch.msgid.link/20251126054221.120638-1-udipto.goswami@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/dwc3/host.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index bc3fe31638b9..8a35a6901db7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4826,7 +4826,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) if (!dwc->gadget) return; - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); usb_del_gadget(dwc->gadget); dwc3_gadget_free_endpoints(dwc); usb_put_gadget(dwc->gadget); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index cf6512ed17a6..96b588bd08cd 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -227,7 +227,7 @@ void dwc3_host_exit(struct dwc3 *dwc) if (dwc->sys_wakeup) device_init_wakeup(&dwc->xhci->dev, false); - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); platform_device_unregister(dwc->xhci); dwc->xhci = NULL; } -- cgit v1.2.3 From d14cd998e67ba8f1cca52a260a1ce1a60954fd8b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:11:07 +0100 Subject: usb: typec: ucsi: huawei-gaokin: add DRM dependency Selecting DRM_AUX_HPD_BRIDGE is not possible from a built-in driver when CONFIG_DRM=m: WARNING: unmet direct dependencies detected for DRM_AUX_HPD_BRIDGE Depends on [m]: HAS_IOMEM [=y] && DRM [=m] && DRM_BRIDGE [=y] && OF [=y] Selected by [y]: - UCSI_HUAWEI_GAOKUN [=y] && USB_SUPPORT [=y] && TYPEC [=y] && TYPEC_UCSI [=y] && EC_HUAWEI_GAOKUN [=y] && DRM_BRIDGE [=y] && OF [=y] Add the same dependency we have in similar drivers to work around this. Fixes: 00327d7f2c8c ("usb: typec: ucsi: add Huawei Matebook E Go ucsi driver") Cc: stable Signed-off-by: Arnd Bergmann Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/20251204101111.1035975-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 7fcb1e1de5d6..b812be4d0e67 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -96,6 +96,7 @@ config UCSI_LENOVO_YOGA_C630 config UCSI_HUAWEI_GAOKUN tristate "UCSI Interface Driver for Huawei Matebook E Go" depends on EC_HUAWEI_GAOKUN + depends on DRM || !DRM select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF help This driver enables UCSI support on the Huawei Matebook E Go tablet, -- cgit v1.2.3 From 36cc7e09df9e43db21b46519b740145410dd9f4a Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 4 Dec 2025 21:21:29 +0800 Subject: usb: renesas_usbhs: Fix a resource leak in usbhs_pipe_malloc() usbhsp_get_pipe() set pipe's flags to IS_USED. In error paths, usbhsp_put_pipe() is required to clear pipe's flags to prevent pipe exhaustion. Fixes: f1407d5c6624 ("usb: renesas_usbhs: Add Renesas USBHS common code") Cc: stable Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20251204132129.109234-1-haoxiang_li2024@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/pipe.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 75fff2e4cbc6..56fc3ff5016f 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -713,11 +713,13 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, /* make sure pipe is not busy */ ret = usbhsp_pipe_barrier(pipe); if (ret < 0) { + usbhsp_put_pipe(pipe); dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); return NULL; } if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { + usbhsp_put_pipe(pipe); dev_err(dev, "can't setup pipe\n"); return NULL; } -- cgit v1.2.3 From 41ca62e3e21e48c2903b3b45e232cf4f2ff7434f Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Fri, 5 Dec 2025 11:48:31 +0800 Subject: usb: phy: fsl-usb: Fix use-after-free in delayed work during device removal The delayed work item otg_event is initialized in fsl_otg_conf() and scheduled under two conditions: 1. When a host controller binds to the OTG controller. 2. When the USB ID pin state changes (cable insertion/removal). A race condition occurs when the device is removed via fsl_otg_remove(): the fsl_otg instance may be freed while the delayed work is still pending or executing. This leads to use-after-free when the work function fsl_otg_event() accesses the already freed memory. The problematic scenario: (detach thread) | (delayed work) fsl_otg_remove() | kfree(fsl_otg_dev) //FREE| fsl_otg_event() | og = container_of(...) //USE | og-> //USE Fix this by calling disable_delayed_work_sync() in fsl_otg_remove() before deallocating the fsl_otg structure. This ensures the delayed work is properly canceled and completes execution prior to memory deallocation. This bug was identified through static analysis. Fixes: 0807c500a1a6 ("USB: add Freescale USB OTG Transceiver driver") Cc: stable Signed-off-by: Duoming Zhou Link: https://patch.msgid.link/20251205034831.12846-1-duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-fsl-usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 40ac68e52cee..e266a47c4d48 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -988,6 +988,7 @@ static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); + disable_delayed_work_sync(&fsl_otg_dev->otg_event); usb_remove_phy(&fsl_otg_dev->phy); free_irq(fsl_otg_dev->irq, fsl_otg_dev); -- cgit v1.2.3 From 128bb7fab342546352603bde8b49ff54e3af0529 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Sat, 6 Dec 2025 15:04:45 +0800 Subject: usb: typec: altmodes/displayport: Drop the device reference in dp_altmode_probe() In error paths, call typec_altmode_put_plug() to drop the device reference obtained by typec_altmode_get_plug(). Fixes: 71ba4fe56656 ("usb: typec: altmodes/displayport: add SOP' support") Cc: stable Signed-off-by: Haoxiang Li Reviewed-by: Heikki Krogerus Link: https://patch.msgid.link/20251206070445.190770-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/altmodes/displayport.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 8d111ad3b71b..d96ab106a980 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -766,12 +766,16 @@ int dp_altmode_probe(struct typec_altmode *alt) if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & - DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) + DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) { + typec_altmode_put_plug(plug); return -ENODEV; + } dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); - if (!dp) + if (!dp) { + typec_altmode_put_plug(plug); return -ENOMEM; + } INIT_WORK(&dp->work, dp_altmode_work); mutex_init(&dp->lock); -- cgit v1.2.3 From c84117912bddd9e5d87e68daf182410c98181407 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Mon, 15 Dec 2025 10:09:31 +0800 Subject: USB: lpc32xx_udc: Fix error handling in probe lpc32xx_udc_probe() acquires an i2c_client reference through isp1301_get_client() but fails to release it in both error handling paths and the normal removal path. This could result in a reference count leak for the I2C device, preventing proper cleanup and potentially leading to resource exhaustion. Add put_device() to release the reference in the probe failure path and in the remove function. Calling path: isp1301_get_client() -> of_find_i2c_device_by_node() -> i2c_find_device_by_fwnode(). As comments of i2c_find_device_by_fwnode() says, 'The user must call put_device(&client->dev) once done with the i2c client.' Found by code review. Cc: stable Fixes: 24a28e428351 ("USB: gadget driver for LPC32xx") Signed-off-by: Ma Ke Link: https://patch.msgid.link/20251215020931.15324-1-make24@iscas.ac.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 1a7d3c4f652f..73c0f28a8585 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (retval) - return retval; + goto i2c_fail; udc->board = &lpc32xx_usbddata; @@ -3038,28 +3038,32 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) /* Get IRQs */ for (i = 0; i < 4; i++) { udc->udp_irq[i] = platform_get_irq(pdev, i); - if (udc->udp_irq[i] < 0) - return udc->udp_irq[i]; + if (udc->udp_irq[i] < 0) { + retval = udc->udp_irq[i]; + goto i2c_fail; + } } udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(udc->udp_baseaddr)) { dev_err(udc->dev, "IO map failure\n"); - return PTR_ERR(udc->udp_baseaddr); + retval = PTR_ERR(udc->udp_baseaddr); + goto i2c_fail; } /* Get USB device clock */ udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(udc->usb_slv_clk)) { dev_err(udc->dev, "failed to acquire USB device clock\n"); - return PTR_ERR(udc->usb_slv_clk); + retval = PTR_ERR(udc->usb_slv_clk); + goto i2c_fail; } /* Enable USB device clock */ retval = clk_prepare_enable(udc->usb_slv_clk); if (retval < 0) { dev_err(udc->dev, "failed to start USB device clock\n"); - return retval; + goto i2c_fail; } /* Setup deferred workqueue data */ @@ -3161,6 +3165,8 @@ dma_alloc_fail: dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); i2c_fail: + if (udc->isp1301_i2c_client) + put_device(&udc->isp1301_i2c_client->dev); clk_disable_unprepare(udc->usb_slv_clk); dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); @@ -3189,6 +3195,9 @@ static void lpc32xx_udc_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); + if (udc->isp1301_i2c_client) + put_device(&udc->isp1301_i2c_client->dev); + clk_disable_unprepare(udc->usb_slv_clk); } -- cgit v1.2.3 From 14ad4c10d5bdd413ff9a914260e89b5f54b7a2c7 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Tue, 16 Dec 2025 06:22:02 -0600 Subject: usb: typec: ucsi: Fix null pointer dereference in ucsi_sync_control_common Add missing null check for cci parameter before dereferencing it in ucsi_sync_control_common(). The function can be called with cci=NULL from ucsi_acknowledge(), which leads to a null pointer dereference when accessing *cci in the condition check. The crash occurs because the code checks if cci is not null before calling ucsi->ops->read_cci(ucsi, cci), but then immediately dereferences cci without a null check in the following condition: (*cci & UCSI_CCI_COMMAND_COMPLETE). KASAN trace: KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:ucsi_sync_control_common+0x2ae/0x4e0 [typec_ucsi] Cc: stable Fixes: 667ecac55861 ("usb: typec: ucsi: return CCI and message from sync_control callback") Reviewed-by: Heikki Krogerus Signed-off-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20251216122210.5457-1-superm1@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 9b3df776137a..7129973f19e7 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -97,7 +97,7 @@ out_clear_bit: if (!ret && cci) ret = ucsi->ops->read_cci(ucsi, cci); - if (!ret && ucsi->message_in_size > 0 && + if (!ret && cci && ucsi->message_in_size > 0 && (*cci & UCSI_CCI_COMMAND_COMPLETE)) ret = ucsi->ops->read_message_in(ucsi, ucsi->message_in, ucsi->message_in_size); -- cgit v1.2.3 From 3b4961313d31e200c9e974bb1536cdea217f78b5 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 10:49:36 +0400 Subject: usb: dwc3: of-simple: fix clock resource leak in dwc3_of_simple_probe When clk_bulk_prepare_enable() fails, the error path jumps to err_resetc_assert, skipping clk_bulk_put_all() and leaking the clock references acquired by clk_bulk_get_all(). Add err_clk_put_all label to properly release clock resources in all error paths. Found via static analysis and code review. Fixes: c0c61471ef86 ("usb: dwc3: of-simple: Convert to bulk clk API") Cc: stable Signed-off-by: Miaoqian Lin Acked-by: Thinh Nguyen Link: https://patch.msgid.link/20251211064937.2360510-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-of-simple.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index a4954a21be93..c116143335d9 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -70,11 +70,11 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) simple->num_clocks = ret; ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); if (ret) - goto err_resetc_assert; + goto err_clk_put_all; ret = of_platform_populate(np, NULL, NULL, dev); if (ret) - goto err_clk_put; + goto err_clk_disable; pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -82,8 +82,9 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) return 0; -err_clk_put: +err_clk_disable: clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); +err_clk_put_all: clk_bulk_put_all(simple->num_clocks, simple->clks); err_resetc_assert: -- cgit v1.2.3 From 24ec03cc55126b7b3adf102f4b3d9f716532b329 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 27 Nov 2025 17:36:50 +0100 Subject: serial: core: Restore sysfs fwnode information The change that restores sysfs fwnode information does it only for OF cases. Update the fix to cover all possible types of fwnodes. Fixes: d36f0e9a0002 ("serial: core: restore of_node information in sysfs") Cc: stable Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20251127163650.2942075-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 22749ab0428a..8e891984cdc0 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,6 +60,7 @@ void serial_base_driver_unregister(struct device_driver *driver) driver_unregister(driver); } +/* On failure the caller must put device @dev with put_device() */ static int serial_base_device_init(struct uart_port *port, struct device *dev, struct device *parent_dev, @@ -73,7 +74,8 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; - device_set_of_node_from_dev(dev, parent_dev); + + device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); if (!serial_base_initialized) { dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); @@ -94,7 +96,7 @@ static void serial_base_ctrl_release(struct device *dev) { struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(ctrl_dev); } @@ -142,7 +144,7 @@ static void serial_base_port_release(struct device *dev) { struct serial_port_device *port_dev = to_serial_base_port_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(port_dev); } -- cgit v1.2.3 From 5edb7338d6117bb0ce17ead7973c67390da42258 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 29 Nov 2025 17:51:23 +0300 Subject: serial: 8250: longson: Fix NULL vs IS_ERR() bug in probe The devm_platform_get_and_ioremap_resource() function never returns NULL, it returns error pointers. Fix the error checking to match. Fixes: 25e95d763176 ("serial: 8250: Add Loongson uart driver support") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/aSsIa3KdAlXh5uQC@stanley.mountain Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_loongson.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c index 53153a116c01..47df3c4c9d21 100644 --- a/drivers/tty/serial/8250/8250_loongson.c +++ b/drivers/tty/serial/8250/8250_loongson.c @@ -128,8 +128,8 @@ static int loongson_uart_probe(struct platform_device *pdev) port->private_data = priv; port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res); - if (!port->membase) - return -ENOMEM; + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); port->mapbase = priv->res->start; port->mapsize = resource_size(priv->res); -- cgit v1.2.3 From be43abc5514167cc129a8d8e9727b89b8e1d9719 Mon Sep 17 00:00:00 2001 From: Przemyslaw Korba Date: Thu, 20 Nov 2025 13:07:28 +0100 Subject: i40e: fix scheduling in set_rx_mode Add service task schedule to set_rx_mode. In some cases there are error messages printed out in PTP application (ptp4l): ptp4l[13848.762]: port 1 (ens2f3np3): received SYNC without timestamp ptp4l[13848.825]: port 1 (ens2f3np3): received SYNC without timestamp ptp4l[13848.887]: port 1 (ens2f3np3): received SYNC without timestamp This happens when service task would not run immediately after set_rx_mode, and we need it for setup tasks. This service task checks, if PTP RX packets are hung in firmware, and propagate correct settings such as multicast address for IEEE 1588 Precision Time Protocol. RX timestamping depends on some of these filters set. Bug happens only with high PTP packets frequency incoming, and not every run since sometimes service task is being ran from a different place immediately after starting ptp4l. Fixes: 0e4425ed641f ("i40e: fix: do not sleep in netdev_ops") Reviewed-by: Grzegorz Nitka Reviewed-by: Jacob Keller Reviewed-by: Aleksandr Loktionov Signed-off-by: Przemyslaw Korba Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 50be0a60ae13..07d32f2586c8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2234,6 +2234,7 @@ static void i40e_set_rx_mode(struct net_device *netdev) vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state); } + i40e_service_event_schedule(vsi->back); } /** -- cgit v1.2.3 From 69942834215323cd9131db557091b4dec43f19c5 Mon Sep 17 00:00:00 2001 From: Gregory Herrero Date: Fri, 12 Dec 2025 22:06:43 +0100 Subject: i40e: validate ring_len parameter against hardware-specific values The maximum number of descriptors supported by the hardware is hardware-dependent and can be retrieved using i40e_get_max_num_descriptors(). Move this function to a shared header and use it when checking for valid ring_len parameter rather than using hardcoded value. By fixing an over-acceptance issue, behavior change could be seen where ring_len could now be rejected while configuring rx and tx queues if its size is larger than the hardware-dependent maximum number of descriptors. Fixes: 55d225670def ("i40e: add validation for ring_len param") Signed-off-by: Gregory Herrero Tested-by: Rafal Romanowski Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e.h | 11 +++++++++++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 12 ------------ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index d2d03db2acec..dcb50c2e1aa2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1422,4 +1422,15 @@ static inline struct i40e_veb *i40e_pf_get_main_veb(struct i40e_pf *pf) return (pf->lan_veb != I40E_NO_VEB) ? pf->veb[pf->lan_veb] : NULL; } +static inline u32 i40e_get_max_num_descriptors(const struct i40e_pf *pf) +{ + const struct i40e_hw *hw = &pf->hw; + + switch (hw->mac.type) { + case I40E_MAC_XL710: + return I40E_MAX_NUM_DESCRIPTORS_XL710; + default: + return I40E_MAX_NUM_DESCRIPTORS; + } +} #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f2c2646ea298..6a47ea0927e9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2013,18 +2013,6 @@ static void i40e_get_drvinfo(struct net_device *netdev, drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN; } -static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf) -{ - struct i40e_hw *hw = &pf->hw; - - switch (hw->mac.type) { - case I40E_MAC_XL710: - return I40E_MAX_NUM_DESCRIPTORS_XL710; - default: - return I40E_MAX_NUM_DESCRIPTORS; - } -} - static void i40e_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 8b30a3accd31..1fa877b52f61 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -656,7 +656,7 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 8 */ if (!IS_ALIGNED(info->ring_len, 8) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_context; } @@ -726,7 +726,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 32 */ if (!IS_ALIGNED(info->ring_len, 32) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_param; } -- cgit v1.2.3 From 6daa2893f323981c7894c68440823326e93a7d61 Mon Sep 17 00:00:00 2001 From: Kohei Enju Date: Sun, 26 Oct 2025 01:58:50 +0900 Subject: iavf: fix off-by-one issues in iavf_config_rss_reg() There are off-by-one bugs when configuring RSS hash key and lookup table, causing out-of-bounds reads to memory [1] and out-of-bounds writes to device registers. Before commit 43a3d9ba34c9 ("i40evf: Allow PF driver to configure RSS"), the loop upper bounds were: i <= I40E_VFQF_{HKEY,HLUT}_MAX_INDEX which is safe since the value is the last valid index. That commit changed the bounds to: i <= adapter->rss_{key,lut}_size / 4 where `rss_{key,lut}_size / 4` is the number of dwords, so the last valid index is `(rss_{key,lut}_size / 4) - 1`. Therefore, using `<=` accesses one element past the end. Fix the issues by using `<` instead of `<=`, ensuring we do not exceed the bounds. [1] KASAN splat about rss_key_size off-by-one BUG: KASAN: slab-out-of-bounds in iavf_config_rss+0x619/0x800 Read of size 4 at addr ffff888102c50134 by task kworker/u8:6/63 CPU: 0 UID: 0 PID: 63 Comm: kworker/u8:6 Not tainted 6.18.0-rc2-enjuk-tnguy-00378-g3005f5b77652-dirty #156 PREEMPT(voluntary) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: iavf iavf_watchdog_task Call Trace: dump_stack_lvl+0x6f/0xb0 print_report+0x170/0x4f3 kasan_report+0xe1/0x1a0 iavf_config_rss+0x619/0x800 iavf_watchdog_task+0x2be7/0x3230 process_one_work+0x7fd/0x1420 worker_thread+0x4d1/0xd40 kthread+0x344/0x660 ret_from_fork+0x249/0x320 ret_from_fork_asm+0x1a/0x30 Allocated by task 63: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0x7f/0x90 __kmalloc_noprof+0x246/0x6f0 iavf_watchdog_task+0x28fc/0x3230 process_one_work+0x7fd/0x1420 worker_thread+0x4d1/0xd40 kthread+0x344/0x660 ret_from_fork+0x249/0x320 ret_from_fork_asm+0x1a/0x30 The buggy address belongs to the object at ffff888102c50100 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 0 bytes to the right of allocated 52-byte region [ffff888102c50100, ffff888102c50134) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x102c50 flags: 0x200000000000000(node=0|zone=2) page_type: f5(slab) raw: 0200000000000000 ffff8881000418c0 dead000000000122 0000000000000000 raw: 0000000000000000 0000000080200020 00000000f5000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888102c50000: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc ffff888102c50080: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc >ffff888102c50100: 00 00 00 00 00 00 04 fc fc fc fc fc fc fc fc fc ^ ffff888102c50180: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc ffff888102c50200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc Fixes: 43a3d9ba34c9 ("i40evf: Allow PF driver to configure RSS") Signed-off-by: Kohei Enju Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c2fbe443ef85..4b0fc8f354bc 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1726,11 +1726,11 @@ static int iavf_config_rss_reg(struct iavf_adapter *adapter) u16 i; dw = (u32 *)adapter->rss_key; - for (i = 0; i <= adapter->rss_key_size / 4; i++) + for (i = 0; i < adapter->rss_key_size / 4; i++) wr32(hw, IAVF_VFQF_HKEY(i), dw[i]); dw = (u32 *)adapter->rss_lut; - for (i = 0; i <= adapter->rss_lut_size / 4; i++) + for (i = 0; i < adapter->rss_lut_size / 4; i++) wr32(hw, IAVF_VFQF_HLUT(i), dw[i]); iavf_flush(hw); -- cgit v1.2.3 From 887bfe5986396aca908b7afd2d214471ba7d5544 Mon Sep 17 00:00:00 2001 From: Konstantin Taranov Date: Thu, 23 Oct 2025 03:03:00 -0700 Subject: RDMA/mana_ib: check cqe length for kernel CQs Check queue size during kernel CQ creation to prevent overflow of u32. Fixes: bec127e45d9f ("RDMA/mana_ib: create kernel-level CQs") Link: https://patch.msgid.link/r/1761213780-5457-1-git-send-email-kotaranov@linux.microsoft.com Signed-off-by: Konstantin Taranov Reviewed-by: Long Li Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mana/cq.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c index 1becc8779123..7600412b0739 100644 --- a/drivers/infiniband/hw/mana/cq.c +++ b/drivers/infiniband/hw/mana/cq.c @@ -56,6 +56,10 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, doorbell = mana_ucontext->doorbell; } else { is_rnic_cq = true; + if (attr->cqe > U32_MAX / COMP_ENTRY_SIZE / 2 + 1) { + ibdev_dbg(ibdev, "CQE %d exceeding limit\n", attr->cqe); + return -EINVAL; + } buf_size = MANA_PAGE_ALIGN(roundup_pow_of_two(attr->cqe * COMP_ENTRY_SIZE)); cq->cqe = buf_size / COMP_ENTRY_SIZE; err = mana_ib_create_kernel_queue(mdev, buf_size, GDMA_CQ, &cq->queue); -- cgit v1.2.3 From 6f05611728e9d0ab024832a4f1abb74a5f5d0bb0 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 27 Nov 2025 15:31:50 +0100 Subject: RDMA/irdma: avoid invalid read in irdma_net_event irdma_net_event() should not dereference anything from "neigh" (alias "ptr") until it has checked that the event is NETEVENT_NEIGH_UPDATE. Other events come with different structures pointed to by "ptr" and they may be smaller than struct neighbour. Move the read of neigh->dev under the NETEVENT_NEIGH_UPDATE case. The bug is mostly harmless, but it triggers KASAN on debug kernels: BUG: KASAN: stack-out-of-bounds in irdma_net_event+0x32e/0x3b0 [irdma] Read of size 8 at addr ffffc900075e07f0 by task kworker/27:2/542554 CPU: 27 PID: 542554 Comm: kworker/27:2 Kdump: loaded Not tainted 5.14.0-630.el9.x86_64+debug #1 Hardware name: [...] Workqueue: events rt6_probe_deferred Call Trace: dump_stack_lvl+0x60/0xb0 print_address_description.constprop.0+0x2c/0x3f0 print_report+0xb4/0x270 kasan_report+0x92/0xc0 irdma_net_event+0x32e/0x3b0 [irdma] notifier_call_chain+0x9e/0x180 atomic_notifier_call_chain+0x5c/0x110 rt6_do_redirect+0xb91/0x1080 tcp_v6_err+0xe9b/0x13e0 icmpv6_notify+0x2b2/0x630 ndisc_redirect_rcv+0x328/0x530 icmpv6_rcv+0xc16/0x1360 ip6_protocol_deliver_rcu+0xb84/0x12e0 ip6_input_finish+0x117/0x240 ip6_input+0xc4/0x370 ipv6_rcv+0x420/0x7d0 __netif_receive_skb_one_core+0x118/0x1b0 process_backlog+0xd1/0x5d0 __napi_poll.constprop.0+0xa3/0x440 net_rx_action+0x78a/0xba0 handle_softirqs+0x2d4/0x9c0 do_softirq+0xad/0xe0 Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions") Link: https://patch.msgid.link/r/20251127143150.121099-1-mschmidt@redhat.com Signed-off-by: Michal Schmidt Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/irdma/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index cc2a12f735d3..13d7499131d4 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -251,7 +251,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, void *ptr) { struct neighbour *neigh = ptr; - struct net_device *real_dev, *netdev = (struct net_device *)neigh->dev; + struct net_device *real_dev, *netdev; struct irdma_device *iwdev; struct ib_device *ibdev; __be32 *p; @@ -260,6 +260,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, switch (event) { case NETEVENT_NEIGH_UPDATE: + netdev = neigh->dev; real_dev = rdma_vlan_dev_real_dev(netdev); if (!real_dev) real_dev = netdev; -- cgit v1.2.3 From c1776ccba661c946f2e42aaa11eda81e2cd764c5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 28 Nov 2025 18:21:46 -0800 Subject: RTRS/rtrs: clean up rtrs headers kernel-doc Fix all (30+) kernel-doc warnings in rtrs.h and rtrs-pri.h. The changes are: - add ending ':' to enum member names - change enum description separators from '-' to ':' - add "struct" keyword to kernel-doc for structs where missing - fix enum names in enum rtrs_clt_con_type - add a '-' separator and drop the "()" in enum rtrs_clt_con_type - convert struct rtrs_addr to kernel-doc format - add missing struct member descriptions for struct rtrs_attrs Link: https://patch.msgid.link/r/20251129022146.1498273-1-rdunlap@infradead.org Signed-off-by: Randy Dunlap Acked-by: Jack Wang Signed-off-by: Jason Gunthorpe --- drivers/infiniband/ulp/rtrs/rtrs-pri.h | 32 +++++++++++++++++++++----------- drivers/infiniband/ulp/rtrs/rtrs.h | 24 +++++++++++++++--------- 2 files changed, 36 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/rtrs/rtrs-pri.h b/drivers/infiniband/ulp/rtrs/rtrs-pri.h index ef29bd483b5a..59529d593869 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-pri.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-pri.h @@ -150,7 +150,7 @@ enum rtrs_msg_types { /** * enum rtrs_msg_flags - RTRS message flags. - * @RTRS_NEED_INVAL: Send invalidation in response. + * @RTRS_MSG_NEED_INVAL_F: Send invalidation in response. * @RTRS_MSG_NEW_RKEY_F: Send refreshed rkey in response. */ enum rtrs_msg_flags { @@ -179,16 +179,19 @@ struct rtrs_sg_desc { * @recon_cnt: Reconnections counter * @sess_uuid: UUID of a session (path) * @paths_uuid: UUID of a group of sessions (paths) - * + * @first_conn: %1 if the connection request is the first for that session, + * otherwise %0 * NOTE: max size 56 bytes, see man rdma_connect(). */ struct rtrs_msg_conn_req { - /* Is set to 0 by cma.c in case of AF_IB, do not touch that. - * see https://www.spinics.net/lists/linux-rdma/msg22397.html + /** + * @__cma_version: Is set to 0 by cma.c in case of AF_IB, do not touch + * that. See https://www.spinics.net/lists/linux-rdma/msg22397.html */ u8 __cma_version; - /* On sender side that should be set to 0, or cma_save_ip_info() - * extract garbage and will fail. + /** + * @__ip_version: On sender side that should be set to 0, or + * cma_save_ip_info() extract garbage and will fail. */ u8 __ip_version; __le16 magic; @@ -199,6 +202,7 @@ struct rtrs_msg_conn_req { uuid_t sess_uuid; uuid_t paths_uuid; u8 first_conn : 1; + /* private: */ u8 reserved_bits : 7; u8 reserved[11]; }; @@ -211,6 +215,7 @@ struct rtrs_msg_conn_req { * @queue_depth: max inflight messages (queue-depth) in this session * @max_io_size: max io size server supports * @max_hdr_size: max msg header size server supports + * @flags: RTRS message flags for this message * * NOTE: size is 56 bytes, max possible is 136 bytes, see man rdma_accept(). */ @@ -222,22 +227,24 @@ struct rtrs_msg_conn_rsp { __le32 max_io_size; __le32 max_hdr_size; __le32 flags; + /* private: */ u8 reserved[36]; }; /** - * struct rtrs_msg_info_req + * struct rtrs_msg_info_req - client additional info request * @type: @RTRS_MSG_INFO_REQ * @pathname: Path name chosen by client */ struct rtrs_msg_info_req { __le16 type; u8 pathname[NAME_MAX]; + /* private: */ u8 reserved[15]; }; /** - * struct rtrs_msg_info_rsp + * struct rtrs_msg_info_rsp - server additional info response * @type: @RTRS_MSG_INFO_RSP * @sg_cnt: Number of @desc entries * @desc: RDMA buffers where the client can write to server @@ -245,12 +252,14 @@ struct rtrs_msg_info_req { struct rtrs_msg_info_rsp { __le16 type; __le16 sg_cnt; + /* private: */ u8 reserved[4]; + /* public: */ struct rtrs_sg_desc desc[]; }; /** - * struct rtrs_msg_rkey_rsp + * struct rtrs_msg_rkey_rsp - server refreshed rkey response * @type: @RTRS_MSG_RKEY_RSP * @buf_id: RDMA buf_id of the new rkey * @rkey: new remote key for RDMA buffers id from server @@ -264,6 +273,7 @@ struct rtrs_msg_rkey_rsp { /** * struct rtrs_msg_rdma_read - RDMA data transfer request from client * @type: always @RTRS_MSG_READ + * @flags: RTRS message flags (enum rtrs_msg_flags) * @usr_len: length of user payload * @sg_cnt: number of @desc entries * @desc: RDMA buffers where the server can write the result to @@ -277,7 +287,7 @@ struct rtrs_msg_rdma_read { }; /** - * struct_msg_rdma_write - Message transferred to server with RDMA-Write + * struct rtrs_msg_rdma_write - Message transferred to server with RDMA-Write * @type: always @RTRS_MSG_WRITE * @usr_len: length of user payload */ @@ -287,7 +297,7 @@ struct rtrs_msg_rdma_write { }; /** - * struct_msg_rdma_hdr - header for read or write request + * struct rtrs_msg_rdma_hdr - header for read or write request * @type: @RTRS_MSG_WRITE | @RTRS_MSG_READ */ struct rtrs_msg_rdma_hdr { diff --git a/drivers/infiniband/ulp/rtrs/rtrs.h b/drivers/infiniband/ulp/rtrs/rtrs.h index b48b53a7c143..b5bd35712de0 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs.h +++ b/drivers/infiniband/ulp/rtrs/rtrs.h @@ -24,8 +24,8 @@ struct rtrs_srv_op; /** * enum rtrs_clt_link_ev - Events about connectivity state of a client - * @RTRS_CLT_LINK_EV_RECONNECTED Client was reconnected. - * @RTRS_CLT_LINK_EV_DISCONNECTED Client was disconnected. + * @RTRS_CLT_LINK_EV_RECONNECTED: Client was reconnected. + * @RTRS_CLT_LINK_EV_DISCONNECTED: Client was disconnected. */ enum rtrs_clt_link_ev { RTRS_CLT_LINK_EV_RECONNECTED, @@ -33,7 +33,9 @@ enum rtrs_clt_link_ev { }; /** - * Source and destination address of a path to be established + * struct rtrs_addr - Source and destination address of a path to be established + * @src: source address + * @dst: destination address */ struct rtrs_addr { struct sockaddr_storage *src; @@ -41,7 +43,7 @@ struct rtrs_addr { }; /** - * rtrs_clt_ops - it holds the link event callback and private pointer. + * struct rtrs_clt_ops - it holds the link event callback and private pointer. * @priv: User supplied private data. * @link_ev: Event notification callback function for connection state changes * @priv: User supplied data that was passed to rtrs_clt_open() @@ -67,10 +69,10 @@ enum wait_type { }; /** - * enum rtrs_clt_con_type() type of ib connection to use with a given + * enum rtrs_clt_con_type - type of ib connection to use with a given * rtrs_permit - * @ADMIN_CON - use connection reserved for "service" messages - * @IO_CON - use a connection reserved for IO + * @RTRS_ADMIN_CON: use connection reserved for "service" messages + * @RTRS_IO_CON: use a connection reserved for IO */ enum rtrs_clt_con_type { RTRS_ADMIN_CON, @@ -85,7 +87,7 @@ void rtrs_clt_put_permit(struct rtrs_clt_sess *sess, struct rtrs_permit *permit); /** - * rtrs_clt_req_ops - it holds the request confirmation callback + * struct rtrs_clt_req_ops - it holds the request confirmation callback * and a private pointer. * @priv: User supplied private data. * @conf_fn: callback function to be called as confirmation @@ -105,7 +107,11 @@ int rtrs_clt_request(int dir, struct rtrs_clt_req_ops *ops, int rtrs_clt_rdma_cq_direct(struct rtrs_clt_sess *clt, unsigned int index); /** - * rtrs_attrs - RTRS session attributes + * struct rtrs_attrs - RTRS session attributes + * @queue_depth: queue_depth saved from rtrs_clt_sess message + * @max_io_size: max_io_size from rtrs_clt_sess message, capped to + * @max_segments * %SZ_4K + * @max_segments: max_segments saved from rtrs_clt_sess message */ struct rtrs_attrs { u32 queue_depth; -- cgit v1.2.3 From 85463eb6a46caf2f1e0e1a6d0731f2f3bab17780 Mon Sep 17 00:00:00 2001 From: Michael Margolin Date: Wed, 10 Dec 2025 17:36:56 +0000 Subject: RDMA/efa: Remove possible negative shift The page size used for device might in some cases be smaller than PAGE_SIZE what results in a negative shift when calculating the number of host pages in PAGE_SIZE for a debug log. Remove the debug line together with the calculation. Fixes: 40909f664d27 ("RDMA/efa: Add EFA verbs implementation") Link: https://patch.msgid.link/r/20251210173656.8180-1-mrgolin@amazon.com Reviewed-by: Tom Sela Reviewed-by: Yonatan Nachum Signed-off-by: Michael Margolin Reviewed-by: Gal Pressman Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/efa/efa_verbs.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 22d3e25c3b9d..755bba8d58bb 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -1320,13 +1320,9 @@ static int umem_to_page_list(struct efa_dev *dev, u32 hp_cnt, u8 hp_shift) { - u32 pages_in_hp = BIT(hp_shift - PAGE_SHIFT); struct ib_block_iter biter; unsigned int hp_idx = 0; - ibdev_dbg(&dev->ibdev, "hp_cnt[%u], pages_in_hp[%u]\n", - hp_cnt, pages_in_hp); - rdma_umem_for_each_dma_block(umem, &biter, BIT(hp_shift)) page_list[hp_idx++] = rdma_block_iter_dma_address(&biter); -- cgit v1.2.3 From 4af1f9a47291f7d446398065e0d6eb4943f7e184 Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Tue, 7 Oct 2025 13:46:22 +0200 Subject: idpf: fix LAN memory regions command on some NVMs IPU SDK versions 1.9 through 2.0.5 require send buffer to contain a single empty memory region. Set number of regions to 1 and use appropriate send buffer size to satisfy this requirement. Fixes: 6aa53e861c1a ("idpf: implement get LAN MMIO memory regions") Suggested-by: Michal Swiatkowski Reviewed-by: Aleksandr Loktionov Signed-off-by: Larysa Zaremba Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 44cd4b466c48..5bbe7d9294c1 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -1016,6 +1016,9 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) struct idpf_vc_xn_params xn_params = { .vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS, .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN, + .send_buf.iov_len = + sizeof(struct virtchnl2_get_lan_memory_regions) + + sizeof(struct virtchnl2_mem_region), .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC, }; int num_regions, size; @@ -1028,6 +1031,8 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) return -ENOMEM; xn_params.recv_buf.iov_base = rcvd_regions; + rcvd_regions->num_memory_regions = cpu_to_le16(1); + xn_params.send_buf.iov_base = rcvd_regions; reply_sz = idpf_vc_xn_exec(adapter, &xn_params); if (reply_sz < 0) return reply_sz; -- cgit v1.2.3 From b3d6bbae1d6d5638a4ab702ab195476787cde857 Mon Sep 17 00:00:00 2001 From: Brian Vazquez Date: Mon, 10 Nov 2025 20:58:37 +0000 Subject: idpf: reduce mbx_task schedule delay to 300us During the IDPF init phase, the mailbox runs in poll mode until it is configured to properly handle interrupts. The previous delay of 300ms is excessively long for the mailbox polling mechanism, which causes a slow initialization of ~2s: echo 0000:06:12.4 > /sys/bus/pci/drivers/idpf/bind [ 52.444239] idpf 0000:06:12.4: enabling device (0000 -> 0002) [ 52.485005] idpf 0000:06:12.4: Device HW Reset initiated [ 54.177181] idpf 0000:06:12.4: PTP init failed, err=-EOPNOTSUPP [ 54.206177] idpf 0000:06:12.4: Minimum RX descriptor support not provided, using the default [ 54.206182] idpf 0000:06:12.4: Minimum TX descriptor support not provided, using the default Changing the delay to 300us avoids the delays during the initial mailbox transactions, making the init phase much faster: [ 83.342590] idpf 0000:06:12.4: enabling device (0000 -> 0002) [ 83.384402] idpf 0000:06:12.4: Device HW Reset initiated [ 83.518323] idpf 0000:06:12.4: PTP init failed, err=-EOPNOTSUPP [ 83.547430] idpf 0000:06:12.4: Minimum RX descriptor support not provided, using the default [ 83.547435] idpf 0000:06:12.4: Minimum TX descriptor support not provided, using the default Fixes: 4930fbf419a7 ("idpf: add core init and interrupt request") Signed-off-by: Brian Vazquez Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 7a7e101afeb6..7ce4eb71a433 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1271,7 +1271,7 @@ void idpf_mbx_task(struct work_struct *work) idpf_mb_irq_enable(adapter); else queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, - msecs_to_jiffies(300)); + usecs_to_jiffies(300)); idpf_recv_mb_msg(adapter); } -- cgit v1.2.3 From 9c72a5182ed92904d01057f208c390a303f00a0f Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Mon, 1 Dec 2025 11:40:58 +0800 Subject: e1000: fix OOB in e1000_tbi_should_accept() In e1000_tbi_should_accept() we read the last byte of the frame via 'data[length - 1]' to evaluate the TBI workaround. If the descriptor- reported length is zero or larger than the actual RX buffer size, this read goes out of bounds and can hit unrelated slab objects. The issue is observed from the NAPI receive path (e1000_clean_rx_irq): ================================================================== BUG: KASAN: slab-out-of-bounds in e1000_tbi_should_accept+0x610/0x790 Read of size 1 at addr ffff888014114e54 by task sshd/363 CPU: 0 PID: 363 Comm: sshd Not tainted 5.18.0-rc1 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack_lvl+0x5a/0x74 print_address_description+0x7b/0x440 print_report+0x101/0x200 kasan_report+0xc1/0xf0 e1000_tbi_should_accept+0x610/0x790 e1000_clean_rx_irq+0xa8c/0x1110 e1000_clean+0xde2/0x3c10 __napi_poll+0x98/0x380 net_rx_action+0x491/0xa20 __do_softirq+0x2c9/0x61d do_softirq+0xd1/0x120 __local_bh_enable_ip+0xfe/0x130 ip_finish_output2+0x7d5/0xb00 __ip_queue_xmit+0xe24/0x1ab0 __tcp_transmit_skb+0x1bcb/0x3340 tcp_write_xmit+0x175d/0x6bd0 __tcp_push_pending_frames+0x7b/0x280 tcp_sendmsg_locked+0x2e4f/0x32d0 tcp_sendmsg+0x24/0x40 sock_write_iter+0x322/0x430 vfs_write+0x56c/0xa60 ksys_write+0xd1/0x190 do_syscall_64+0x43/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7f511b476b10 Code: 73 01 c3 48 8b 0d 88 d3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d f9 2b 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 8e 9b 01 00 48 89 04 24 RSP: 002b:00007ffc9211d4e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000004024 RCX: 00007f511b476b10 RDX: 0000000000004024 RSI: 0000559a9385962c RDI: 0000000000000003 RBP: 0000559a9383a400 R08: fffffffffffffff0 R09: 0000000000004f00 R10: 0000000000000070 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffc9211d57f R14: 0000559a9347bde7 R15: 0000000000000003 Allocated by task 1: __kasan_krealloc+0x131/0x1c0 krealloc+0x90/0xc0 add_sysfs_param+0xcb/0x8a0 kernel_add_sysfs_param+0x81/0xd4 param_sysfs_builtin+0x138/0x1a6 param_sysfs_init+0x57/0x5b do_one_initcall+0x104/0x250 do_initcall_level+0x102/0x132 do_initcalls+0x46/0x74 kernel_init_freeable+0x28f/0x393 kernel_init+0x14/0x1a0 ret_from_fork+0x22/0x30 The buggy address belongs to the object at ffff888014114000 which belongs to the cache kmalloc-2k of size 2048 The buggy address is located 1620 bytes to the right of 2048-byte region [ffff888014114000, ffff888014114800] The buggy address belongs to the physical page: page:ffffea0000504400 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x14110 head:ffffea0000504400 order:3 compound_mapcount:0 compound_pincount:0 flags: 0x100000000010200(slab|head|node=0|zone=1) raw: 0100000000010200 0000000000000000 dead000000000001 ffff888013442000 raw: 0000000000000000 0000000000080008 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected ================================================================== This happens because the TBI check unconditionally dereferences the last byte without validating the reported length first: u8 last_byte = *(data + length - 1); Fix by rejecting the frame early if the length is zero, or if it exceeds adapter->rx_buffer_len. This preserves the TBI workaround semantics for valid frames and prevents touching memory beyond the RX buffer. Fixes: 2037110c96d5 ("e1000: move tbi workaround code into helper function") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li Reviewed-by: Simon Horman Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000/e1000_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 292389aceb2d..7f078ec9c14c 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -4094,7 +4094,15 @@ static bool e1000_tbi_should_accept(struct e1000_adapter *adapter, u32 length, const u8 *data) { struct e1000_hw *hw = &adapter->hw; - u8 last_byte = *(data + length - 1); + u8 last_byte; + + /* Guard against OOB on data[length - 1] */ + if (unlikely(!length)) + return false; + /* Upper bound: length must not exceed rx_buffer_len */ + if (unlikely(length > adapter->rx_buffer_len)) + return false; + last_byte = *(data + length - 1); if (TBI_ACCEPT(hw, status, errors, length, last_byte)) { unsigned long irq_flags; -- cgit v1.2.3 From a05543d6b05ba998fdbb4b383319ae5121bb7407 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 10 Dec 2025 06:50:26 +0100 Subject: gpio: it87: balance superio enter/exit calls in error path We always call superio_enter() in it87_gpio_direction_out() but only call superio_exit() if the call to it87_gpio_set() succeeds. Move the label to balance the calls in error path as well. Fixes: ef877a159072 ("gpio: it87: use new line value setter callbacks") Reported-by: Daniel Gibson Closes: https://lore.kernel.org/all/bd0a00e3-9b8c-43e8-8772-e67b91f4c71e@gibson.sh/ Link: https://lore.kernel.org/r/20251210055026.23146-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-it87.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 5d677bcfccf2..2ad3c239367b 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -241,23 +242,17 @@ static int it87_gpio_direction_out(struct gpio_chip *chip, mask = 1 << (gpio_num % 8); group = (gpio_num / 8); - spin_lock(&it87_gpio->lock); + guard(spinlock)(&it87_gpio->lock); rc = superio_enter(); if (rc) - goto exit; + return rc; /* set the output enable bit */ superio_set_mask(mask, group + it87_gpio->output_base); rc = it87_gpio_set(chip, gpio_num, val); - if (rc) - goto exit; - superio_exit(); - -exit: - spin_unlock(&it87_gpio->lock); return rc; } -- cgit v1.2.3 From 6b991ad8dc3abfe5720fc2e9ee96be63ae43e362 Mon Sep 17 00:00:00 2001 From: Alessio Belle Date: Mon, 8 Dec 2025 09:11:00 +0000 Subject: drm/imagination: Disallow exporting of PM/FW protected objects These objects are meant to be used by the GPU firmware or by the PM unit within the GPU, in which case they may contain physical addresses. This adds a layer of protection against exposing potentially exploitable information outside of the driver. Fixes: ff5f643de0bf ("drm/imagination: Add GEM and VM related code") Signed-off-by: Alessio Belle Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251208-no-export-pm-fw-obj-v1-1-83ab12c61693@imgtec.com Signed-off-by: Matt Coster --- drivers/gpu/drm/imagination/pvr_gem.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/imagination/pvr_gem.c b/drivers/gpu/drm/imagination/pvr_gem.c index a66cf082af24..c07c9a915190 100644 --- a/drivers/gpu/drm/imagination/pvr_gem.c +++ b/drivers/gpu/drm/imagination/pvr_gem.c @@ -28,6 +28,16 @@ static void pvr_gem_object_free(struct drm_gem_object *obj) drm_gem_shmem_object_free(obj); } +static struct dma_buf *pvr_gem_export(struct drm_gem_object *obj, int flags) +{ + struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(obj); + + if (pvr_obj->flags & DRM_PVR_BO_PM_FW_PROTECT) + return ERR_PTR(-EPERM); + + return drm_gem_prime_export(obj, flags); +} + static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *vma) { struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(gem_obj); @@ -42,6 +52,7 @@ static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *v static const struct drm_gem_object_funcs pvr_gem_object_funcs = { .free = pvr_gem_object_free, .print_info = drm_gem_shmem_object_print_info, + .export = pvr_gem_export, .pin = drm_gem_shmem_object_pin, .unpin = drm_gem_shmem_object_unpin, .get_sg_table = drm_gem_shmem_object_get_sg_table, -- cgit v1.2.3 From b74fd80d7fe578898a76344064d2678ce1efda61 Mon Sep 17 00:00:00 2001 From: Chenghai Huang Date: Thu, 20 Nov 2025 21:21:24 +0800 Subject: crypto: hisilicon/qm - fix incorrect judgment in qm_get_complete_eqe_num() In qm_get_complete_eqe_num(), the function entry has already checked whether the interrupt is valid, so the interrupt event can be processed directly. Currently, the interrupt valid bit is being checked again redundantly, and no interrupt processing is performed. Therefore, the loop condition should be modified to directly process the interrupt event, and use do while instead of the current while loop, because the condition is always satisfied on the first iteration. Fixes: f5a332980a68 ("crypto: hisilicon/qm - add the save operation of eqe and aeqe") Signed-off-by: Chenghai Huang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index f8bfff5dd0bd..d47bf06a90f7 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -991,7 +991,7 @@ static void qm_get_complete_eqe_num(struct hisi_qm *qm) return; poll_data = &qm->poll_data[cqn]; - while (QM_EQE_PHASE(dw0) != qm->status.eqc_phase) { + do { poll_data->qp_finish_id[eqe_num] = dw0 & QM_EQE_CQN_MASK; eqe_num++; @@ -1004,11 +1004,10 @@ static void qm_get_complete_eqe_num(struct hisi_qm *qm) qm->status.eq_head++; } - if (eqe_num == (eq_depth >> 1) - 1) - break; - dw0 = le32_to_cpu(eqe->dw0); - } + if (QM_EQE_PHASE(dw0) != qm->status.eqc_phase) + break; + } while (eqe_num < (eq_depth >> 1) - 1); poll_data->eqe_num = eqe_num; queue_work(qm->wq, &poll_data->work); -- cgit v1.2.3 From f28beb69c51517aec7067dfb2074e7c751542384 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 15 Dec 2025 12:57:21 +0100 Subject: HID: usbhid: paper over wrong bNumDescriptor field Some faulty devices (ZWO EFWmini) have a wrong optional HID class descriptor count compared to the provided length. Given that we plainly ignore those optional descriptor, we can attempt to fix the provided number so we do not lock out those devices. Signed-off-by: Benjamin Tissoires --- drivers/hid/usbhid/hid-core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index aac0051a2cf6..758eb21430cd 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -985,6 +985,7 @@ static int usbhid_parse(struct hid_device *hid) struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_class_descriptor *hcdesc; + __u8 fixed_opt_descriptors_size; u32 quirks = 0; unsigned int rsize = 0; char *rdesc; @@ -1015,7 +1016,21 @@ static int usbhid_parse(struct hid_device *hid) (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) { dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n", hdesc->bLength, hdesc->bNumDescriptors); - return -EINVAL; + + /* + * Some devices may expose a wrong number of descriptors compared + * to the provided length. + * However, we ignore the optional hid class descriptors entirely + * so we can safely recompute the proper field. + */ + if (hdesc->bLength >= sizeof(*hdesc)) { + fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc); + + hid_warn(intf, "fixing wrong optional hid class descriptors count\n"); + hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1; + } else { + return -EINVAL; + } } hid->version = le16_to_cpu(hdesc->bcdHID); -- cgit v1.2.3 From e9143268d259d98e111a649affa061acb8e13c5b Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 11 Nov 2025 15:45:19 -0800 Subject: HID: playstation: Center initial joystick axes to prevent spurious events When a new PlayStation gamepad (DualShock 4 or DualSense) is initialized, the input subsystem sets the default value for its absolute axes (e.g., ABS_X, ABS_Y) to 0. However, the hardware's actual neutral/resting state for these joysticks is 128 (0x80). This creates a mismatch. When the first HID report arrives from the device, the driver sees the resting value of 128. The kernel compares this to its initial state of 0 and incorrectly interprets this as a delta (0 -> 128). Consequently, it generates EV_ABS events for this initial, non-existent movement. This behavior can fail userspace 'sanity check' tests (e.g., in Android CTS) that correctly assert no motion events should be generated from a device that is already at rest. This patch fixes the issue by explicitly setting the initial value of the main joystick axes (e.g., ABS_X, ABS_Y, ABS_RX, ABS_RY) to 128 (0x80) in the common ps_gamepad_create() function. This aligns the kernel's initial state with the hardware's expected neutral state, ensuring that the first report (at 128) produces no delta and thus, no spurious event. Signed-off-by: Siarhei Vishniakou Reviewed-by: Benjamin Tissoires Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-playstation.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 128aa6abd10b..e4dfcf26b04e 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -753,11 +753,16 @@ ps_gamepad_create(struct hid_device *hdev, if (IS_ERR(gamepad)) return ERR_CAST(gamepad); + /* Set initial resting state for joysticks to 128 (center) */ input_set_abs_params(gamepad, ABS_X, 0, 255, 0, 0); + gamepad->absinfo[ABS_X].value = 128; input_set_abs_params(gamepad, ABS_Y, 0, 255, 0, 0); + gamepad->absinfo[ABS_Y].value = 128; input_set_abs_params(gamepad, ABS_Z, 0, 255, 0, 0); input_set_abs_params(gamepad, ABS_RX, 0, 255, 0, 0); + gamepad->absinfo[ABS_RX].value = 128; input_set_abs_params(gamepad, ABS_RY, 0, 255, 0, 0); + gamepad->absinfo[ABS_RY].value = 128; input_set_abs_params(gamepad, ABS_RZ, 0, 255, 0, 0); input_set_abs_params(gamepad, ABS_HAT0X, -1, 1, 0, 0); -- cgit v1.2.3 From 0e13150c1a13a3a3d6184c24bfd080d5999945d1 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 3 Dec 2025 17:56:35 +0100 Subject: HID: Intel-thc-hid: Intel-thc: fix dma_unmap_sg() nents value The `dma_unmap_sg()` functions should be called with the same nents as the `dma_map_sg()`, not the value the map function returned. Save the number of entries in struct thc_dma_configuration. Fixes: a688404b2e20 ("HID: intel-thc-hid: intel-thc: Add THC DMA interfaces") Signed-off-by: Thomas Fourier Reviewed-by: Even Xu Reviewed-by: Andy Shevchenko Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c | 4 +++- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c index 82b8854843e0..a0c368aa7979 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c @@ -232,6 +232,7 @@ static int setup_dma_buffers(struct thc_device *dev, return 0; memset(config->sgls, 0, sizeof(config->sgls)); + memset(config->sgls_nent_pages, 0, sizeof(config->sgls_nent_pages)); memset(config->sgls_nent, 0, sizeof(config->sgls_nent)); cpu_addr = dma_alloc_coherent(dev->dev, prd_tbls_size, @@ -254,6 +255,7 @@ static int setup_dma_buffers(struct thc_device *dev, } count = dma_map_sg(dev->dev, config->sgls[i], nent, dir); + config->sgls_nent_pages[i] = nent; config->sgls_nent[i] = count; } @@ -299,7 +301,7 @@ static void release_dma_buffers(struct thc_device *dev, continue; dma_unmap_sg(dev->dev, config->sgls[i], - config->sgls_nent[i], + config->sgls_nent_pages[i], config->dir); sgl_free(config->sgls[i]); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h index 78917400492c..541d33995baf 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h @@ -91,6 +91,7 @@ struct thc_prd_table { * @dir: Direction of DMA for this config * @prd_tbls: PRD tables for current DMA * @sgls: Array of pointers to scatter-gather lists + * @sgls_nent_pages: Number of pages per scatter-gather list * @sgls_nent: Actual number of entries per scatter-gather list * @prd_tbl_num: Actual number of PRD tables * @max_packet_size: Size of the buffer needed for 1 DMA message (1 PRD table) @@ -107,6 +108,7 @@ struct thc_dma_configuration { struct thc_prd_table *prd_tbls; struct scatterlist *sgls[PRD_TABLES_NUM]; + u8 sgls_nent_pages[PRD_TABLES_NUM]; u8 sgls_nent[PRD_TABLES_NUM]; u8 prd_tbl_num; -- cgit v1.2.3 From daeed86b686855adda79f13729e0c9b0530990be Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Wed, 10 Dec 2025 10:53:28 +0800 Subject: HID: intel-ish-hid: Update ishtp bus match to support device ID table The ishtp_cl_bus_match() function previously only checked the first entry in the driver's device ID table. Update it to iterate over the entire table, allowing proper matching for drivers with multiple supported protocol GUIDs. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-ish-hid/ishtp/bus.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index c6ce37244e49..c3915f3a060e 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -240,9 +240,17 @@ static int ishtp_cl_bus_match(struct device *dev, const struct device_driver *dr { struct ishtp_cl_device *device = to_ishtp_cl_device(dev); struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv); + struct ishtp_fw_client *client = device->fw_client; + const struct ishtp_device_id *id; - return(device->fw_client ? guid_equal(&driver->id[0].guid, - &device->fw_client->props.protocol_name) : 0); + if (client) { + for (id = driver->id; !guid_is_null(&id->guid); id++) { + if (guid_equal(&id->guid, &client->props.protocol_name)) + return 1; + } + } + + return 0; } /** -- cgit v1.2.3 From 56e230723e3a818373bd62331bccb1c6d2b3881b Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Fri, 12 Dec 2025 10:51:50 +0800 Subject: HID: intel-ish-hid: Reset enum_devices_done before enumeration Some systems have enabled ISH without any sensors. In this case sending HOSTIF_DM_ENUM_DEVICES results in 0 sensors. This triggers ISH hardware reset on subsequent enumeration after S3/S4 resume. The enum_devices_done flag was not reset before sending the HOSTIF_DM_ENUM_DEVICES command. On subsequent enumeration calls (such as after S3/S4 resume), this flag retains its previous true value, causing the wait loop to be skipped and returning prematurely to hid_ishtp_cl_init(). If 0 HID devices are found, hid_ishtp_cl_init() skips getting HID device descriptors and sets init_done to true. When the delayed enumeration response arrives with init_done already true, the driver treats it as a bad packet and triggers an ISH hardware reset. Set enum_devices_done to false before sending the enumeration command, consistent with similar functions like ishtp_get_hid_descriptor() and ishtp_get_report_descriptor() which reset their respective flags. Signed-off-by: Zhang Lixu Acked-by: Srinivas Pandruvada Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index f37b3bc2bb7d..6d64008f2ce0 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -495,6 +495,7 @@ static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl) int rv; /* Send HOSTIF_DM_ENUM_DEVICES */ + client_data->enum_devices_done = false; memset(&msg, 0, sizeof(struct hostif_msg)); msg.hdr.command = HOSTIF_DM_ENUM_DEVICES; rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg, -- cgit v1.2.3 From ff3f234ff1dcd6d626a989151db067a1b7f0f215 Mon Sep 17 00:00:00 2001 From: DaytonCL Date: Sun, 14 Dec 2025 14:34:36 +0100 Subject: HID: multitouch: add MT_QUIRK_STICKY_FINGERS to MT_CLS_VTL Some VTL-class touchpads (e.g. TOPS0102:00 35CC:0104) intermittently fail to release a finger contact. A previous slot remains logically active, accompanied by stale BTN_TOOL_DOUBLETAP state, causing gestures to stay latched and resulting in stuck two-finger scrolling and false right-clicks. Apply MT_QUIRK_STICKY_FINGERS to handle the unreleased contact correctly. Link: https://gitlab.freedesktop.org/libinput/libinput/-/issues/1225 Suggested-by: Benjamin Tissoires Tested-by: DaytonCL Signed-off-by: DaytonCL Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-multitouch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 179dc316b4b5..a0c1ad5acb67 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -393,6 +393,7 @@ static const struct mt_class mt_classes[] = { { .name = MT_CLS_VTL, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_STICKY_FINGERS | MT_QUIRK_FORCE_GET_FEATURE, }, { .name = MT_CLS_GOOGLE, -- cgit v1.2.3 From f39006965dd37e7be823dba6ca484adccc7a4dff Mon Sep 17 00:00:00 2001 From: Even Xu Date: Fri, 19 Dec 2025 09:14:38 +0800 Subject: HID: Intel-thc-hid: Intel-thc: Fix wrong register reading Correct the read register for the setting of max input size and interrupt delay. Fixes: 22da60f0304b ("HID: Intel-thc-hid: Intel-thc: Introduce interrupt delay control") Fixes: 45e92a093099 ("HID: Intel-thc-hid: Intel-thc: Introduce max input size control") Signed-off-by: Even Xu Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 636a68306501..7e220a4c5ded 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -1593,7 +1593,7 @@ int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size) if (!max_rx_size) return -EOPNOTSUPP; - ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val); + ret = regmap_read(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, &val); if (ret) return ret; @@ -1662,7 +1662,7 @@ int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us) if (!delay_us) return -EOPNOTSUPP; - ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val); + ret = regmap_read(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, &val); if (ret) return ret; -- cgit v1.2.3 From 7f2e8e1d22f6e28edff3782535c16cfbace30902 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 18 Dec 2025 14:08:08 +0200 Subject: =?UTF-8?q?parisc:=20Set=20valid=20bit=20in=20high=20byte=20of=206?= =?UTF-8?q?4=E2=80=91bit=20physical=20address?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32‑bit systems, phys_addr_t is defined as u32. However, parisc expects physical addresses to be 64‑bit values so it can store a validity bit in the upper byte. Resolve this mismatch by casting the physical address to unsigned long, ensuring it is treated as a 64‑bit value where required. This fixes the failure to start block device drivers on the C3700 platform, as reported by Guenter. QEMU command line to reproduce the issue (with Debian SID as rootfs): qemu-system-hppa -machine C3700 \ -kernel arch/parisc/boot/bzImage \ -append "console=ttyS0 \ root=/dev/sda rw rootwait panic=-1" \ -nographic \ -device lsi53c895a \ -drive file=rootfs-hppa.img,if=none,format=raw,id=hd0 \ -device scsi-hd,drive=hd0 Fixes: 96ddf2ef58ec ("parisc: Convert DMA map_page to map_phys interface") Reported-by: Guenter Roeck Closes: https://lore.kernel.org/all/b184f1bf-96dc-4546-8512-9cba5ecb58f7@roeck-us.net/ Signed-off-by: Leon Romanovsky Tested-by: Guenter Roeck [mszyprow: dropped the lpa() macro removal] Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/20251218-fix-parisc-conversion-v1-1-4a04d26b0168@nvidia.com --- drivers/parisc/sba_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index a6eb6bffa5ea..eefb2bac8443 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -578,8 +578,8 @@ sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba, pba &= IOVP_MASK; pba |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */ - pba |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ - *pdir_ptr = cpu_to_le64(pba); /* swap and store into I/O Pdir */ + /* set "valid" bit, swap and store into I/O Pdir */ + *pdir_ptr = cpu_to_le64((unsigned long)pba | SBA_PDIR_VALID_BIT); /* * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set -- cgit v1.2.3 From ce26f588c8310e0fdd1bc7524a86fdf0ef6b1c85 Mon Sep 17 00:00:00 2001 From: Andrea della Porta Date: Thu, 18 Dec 2025 20:09:07 +0100 Subject: misc: rp1: drop overlay support The RP1 driver can load an overlay at runtime to describe the inner peripherals. This has led to a lot of confusion regarding the naming of nodes, their topology and the reclaiming of related node resources. Since the overlay is currently not fully functional, drop its support in the driver in favor of the fully described static DT. This also means that this driver does not depend on CONFIG_PCI_DYNAMIC_OF_NODES and no longer requires PCI quirks to dynamically create the intermediate PCI nodes. Signed-off-by: Andrea della Porta Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/4b0aa7160877cf128b9bc713776bcac73c46eb24.1766077285.git.andrea.porta@suse.com Signed-off-by: Florian Fainelli --- drivers/misc/rp1/Kconfig | 6 +----- drivers/misc/rp1/Makefile | 3 +-- drivers/misc/rp1/rp1-pci.dtso | 25 ------------------------- drivers/misc/rp1/rp1_pci.c | 37 ++++--------------------------------- drivers/pci/quirks.c | 1 - 5 files changed, 6 insertions(+), 66 deletions(-) delete mode 100644 drivers/misc/rp1/rp1-pci.dtso (limited to 'drivers') diff --git a/drivers/misc/rp1/Kconfig b/drivers/misc/rp1/Kconfig index 5232e70d3079..2c13b3968b01 100644 --- a/drivers/misc/rp1/Kconfig +++ b/drivers/misc/rp1/Kconfig @@ -5,8 +5,7 @@ config MISC_RP1 tristate "RaspberryPi RP1 misc device" - depends on OF_IRQ && OF_OVERLAY && PCI_MSI && PCI_QUIRKS - select PCI_DYNAMIC_OF_NODES + depends on OF_IRQ && PCI_MSI help Support the RP1 peripheral chip found on Raspberry Pi 5 board. @@ -15,6 +14,3 @@ config MISC_RP1 The driver is responsible for enabling the DT node once the PCIe endpoint has been configured, and handling interrupts. - - This driver uses an overlay to load other drivers to support for - RP1 internal sub-devices. diff --git a/drivers/misc/rp1/Makefile b/drivers/misc/rp1/Makefile index 508b4cb05627..ab32b433d7ed 100644 --- a/drivers/misc/rp1/Makefile +++ b/drivers/misc/rp1/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_MISC_RP1) += rp1-pci.o -rp1-pci-objs := rp1_pci.o rp1-pci.dtbo.o +obj-$(CONFIG_MISC_RP1) += rp1_pci.o diff --git a/drivers/misc/rp1/rp1-pci.dtso b/drivers/misc/rp1/rp1-pci.dtso deleted file mode 100644 index eea826b36e02..000000000000 --- a/drivers/misc/rp1/rp1-pci.dtso +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MIT) - -/* - * The dts overlay is included from the dts directory so - * it can be possible to check it with CHECK_DTBS while - * also compile it from the driver source directory. - */ - -/dts-v1/; -/plugin/; - -/ { - fragment@0 { - target-path=""; - __overlay__ { - compatible = "pci1de4,1"; - #address-cells = <3>; - #size-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - - #include "arm64/broadcom/rp1-common.dtsi" - }; - }; -}; diff --git a/drivers/misc/rp1/rp1_pci.c b/drivers/misc/rp1/rp1_pci.c index a342bcc6164b..d210da84c30a 100644 --- a/drivers/misc/rp1/rp1_pci.c +++ b/drivers/misc/rp1/rp1_pci.c @@ -34,16 +34,11 @@ /* Interrupts */ #define RP1_INT_END 61 -/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */ -extern char __dtbo_rp1_pci_begin[]; -extern char __dtbo_rp1_pci_end[]; - struct rp1_dev { struct pci_dev *pdev; struct irq_domain *domain; struct irq_data *pcie_irqds[64]; void __iomem *bar1; - int ovcs_id; /* overlay changeset id */ bool level_triggered_irq[RP1_INT_END]; }; @@ -184,24 +179,13 @@ static void rp1_unregister_interrupts(struct pci_dev *pdev) static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - u32 dtbo_size = __dtbo_rp1_pci_end - __dtbo_rp1_pci_begin; - void *dtbo_start = __dtbo_rp1_pci_begin; struct device *dev = &pdev->dev; struct device_node *rp1_node; - bool skip_ovl = true; struct rp1_dev *rp1; int err = 0; int i; - /* - * Either use rp1_nexus node if already present in DT, or - * set a flag to load it from overlay at runtime - */ - rp1_node = of_find_node_by_name(NULL, "rp1_nexus"); - if (!rp1_node) { - rp1_node = dev_of_node(dev); - skip_ovl = false; - } + rp1_node = dev_of_node(dev); if (!rp1_node) { dev_err(dev, "Missing of_node for device\n"); @@ -276,42 +260,29 @@ static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id) rp1_chained_handle_irq, rp1); } - if (!skip_ovl) { - err = of_overlay_fdt_apply(dtbo_start, dtbo_size, &rp1->ovcs_id, - rp1_node); - if (err) - goto err_unregister_interrupts; - } - err = of_platform_default_populate(rp1_node, NULL, dev); if (err) { dev_err_probe(&pdev->dev, err, "Error populating devicetree\n"); - goto err_unload_overlay; + goto err_unregister_interrupts; } - if (skip_ovl) - of_node_put(rp1_node); + of_node_put(rp1_node); return 0; -err_unload_overlay: - of_overlay_remove(&rp1->ovcs_id); err_unregister_interrupts: rp1_unregister_interrupts(pdev); err_put_node: - if (skip_ovl) - of_node_put(rp1_node); + of_node_put(rp1_node); return err; } static void rp1_remove(struct pci_dev *pdev) { - struct rp1_dev *rp1 = pci_get_drvdata(pdev); struct device *dev = &pdev->dev; of_platform_depopulate(dev); - of_overlay_remove(&rp1->ovcs_id); rp1_unregister_interrupts(pdev); } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b9c252aa6fe0..280cd50d693b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6308,7 +6308,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, 0x9660, of_pci_make_dev_node); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RPI_RP1_C0, of_pci_make_dev_node); /* * Devices known to require a longer delay before first config space access -- cgit v1.2.3 From 252714f1e8bdd542025b16321c790458014d6880 Mon Sep 17 00:00:00 2001 From: Raphael Pinsonneault-Thibeault Date: Wed, 10 Dec 2025 11:02:28 -0500 Subject: Bluetooth: btusb: revert use of devm_kzalloc in btusb This reverts commit 98921dbd00c4e ("Bluetooth: Use devm_kzalloc in btusb.c file"). In btusb_probe(), we use devm_kzalloc() to allocate the btusb data. This ties the lifetime of all the btusb data to the binding of a driver to one interface, INTF. In a driver that binds to other interfaces, ISOC and DIAG, this is an accident waiting to happen. The issue is revealed in btusb_disconnect(), where calling usb_driver_release_interface(&btusb_driver, data->intf) will have devm free the data that is also being used by the other interfaces of the driver that may not be released yet. To fix this, revert the use of devm and go back to freeing memory explicitly. Fixes: 98921dbd00c4e ("Bluetooth: Use devm_kzalloc in btusb.c file") Signed-off-by: Raphael Pinsonneault-Thibeault Signed-off-by: Luiz Augusto von Dentz --- drivers/bluetooth/btusb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8ed3883ab8ee..ded09e94d296 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4052,7 +4052,7 @@ static int btusb_probe(struct usb_interface *intf, return -ENODEV; } - data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -4075,8 +4075,10 @@ static int btusb_probe(struct usb_interface *intf, } } - if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) + if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { + kfree(data); return -ENODEV; + } if (id->driver_info & BTUSB_AMP) { data->cmdreq_type = USB_TYPE_CLASS | 0x01; @@ -4131,8 +4133,10 @@ static int btusb_probe(struct usb_interface *intf, data->recv_acl = hci_recv_frame; hdev = hci_alloc_dev_priv(priv_size); - if (!hdev) + if (!hdev) { + kfree(data); return -ENOMEM; + } hdev->bus = HCI_USB; hci_set_drvdata(hdev, data); @@ -4406,6 +4410,7 @@ out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); hci_free_dev(hdev); + kfree(data); return err; } @@ -4454,6 +4459,7 @@ static void btusb_disconnect(struct usb_interface *intf) } hci_free_dev(hdev); + kfree(data); } #ifdef CONFIG_PM -- cgit v1.2.3 From 129049d4fe22c998ae9fd1ec479fbb4ed5338c15 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 17 Nov 2025 15:51:35 +0100 Subject: drm/msm: adreno: fix deferencing ifpc_reglist when not declared On plaforms with an a7xx GPU not supporting IFPC, the ifpc_reglist if still deferenced in a7xx_patch_pwrup_reglist() which causes a kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 ... pc : a6xx_hw_init+0x155c/0x1e4c [msm] lr : a6xx_hw_init+0x9a8/0x1e4c [msm] ... Call trace: a6xx_hw_init+0x155c/0x1e4c [msm] (P) msm_gpu_hw_init+0x58/0x88 [msm] adreno_load_gpu+0x94/0x1fc [msm] msm_open+0xe4/0xf4 [msm] drm_file_alloc+0x1a0/0x2e4 [drm] drm_client_init+0x7c/0x104 [drm] drm_fbdev_client_setup+0x94/0xcf0 [drm_client_lib] drm_client_setup+0xb4/0xd8 [drm_client_lib] msm_drm_kms_post_init+0x2c/0x3c [msm] msm_drm_init+0x1a4/0x228 [msm] msm_drm_bind+0x30/0x3c [msm] ... Check the validity of ifpc_reglist before deferencing the table to setup the register values. Fixes: a6a0157cc68e ("drm/msm/a6xx: Enable IFPC on Adreno X1-85") Signed-off-by: Neil Armstrong Reviewed-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/688944/ Message-ID: <20251117-topic-sm8x50-fix-a6xx-non-ifpc-v1-1-e4473cbf5903@linaro.org> Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 0200a7e71cdf..7e71f6bb5283 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -873,15 +873,17 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) lock->gpu_req = lock->cpu_req = lock->turn = 0; reglist = adreno_gpu->info->a6xx->ifpc_reglist; - lock->ifpc_list_len = reglist->count; + if (reglist) { + lock->ifpc_list_len = reglist->count; - /* - * For each entry in each of the lists, write the offset and the current - * register value into the GPU buffer - */ - for (i = 0; i < reglist->count; i++) { - *dest++ = reglist->regs[i]; - *dest++ = gpu_read(gpu, reglist->regs[i]); + /* + * For each entry in each of the lists, write the offset and the current + * register value into the GPU buffer + */ + for (i = 0; i < reglist->count; i++) { + *dest++ = reglist->regs[i]; + *dest++ = gpu_read(gpu, reglist->regs[i]); + } } reglist = adreno_gpu->info->a6xx->pwrup_reglist; -- cgit v1.2.3 From ef3b04091fd8bc737dc45312375df8625b8318e2 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Thu, 13 Nov 2025 00:28:31 -0800 Subject: drm/msm/a6xx: move preempt_prepare_postamble after error check Move the call to preempt_prepare_postamble() after verifying that preempt_postamble_ptr is valid. If preempt_postamble_ptr is NULL, dereferencing it in preempt_prepare_postamble() would lead to a crash. This change avoids calling the preparation function when the postamble allocation has failed, preventing potential NULL pointer dereference and ensuring proper error handling. Fixes: 50117cad0c50 ("drm/msm/a6xx: Use posamble to reset counters on preemption") Signed-off-by: Alok Tiwari Patchwork: https://patchwork.freedesktop.org/patch/687659/ Message-ID: <20251113082839.3821867-1-alok.a.tiwari@oracle.com> Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index afc5f4aa3b17..747a22afad9f 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -454,11 +454,11 @@ void a6xx_preempt_init(struct msm_gpu *gpu) gpu->vm, &a6xx_gpu->preempt_postamble_bo, &a6xx_gpu->preempt_postamble_iova); - preempt_prepare_postamble(a6xx_gpu); - if (IS_ERR(a6xx_gpu->preempt_postamble_ptr)) goto fail; + preempt_prepare_postamble(a6xx_gpu); + timer_setup(&a6xx_gpu->preempt_timer, a6xx_preempt_timer, 0); return; -- cgit v1.2.3 From 6c6915bfea212d32844b2b7f22bc1aa3669eabc4 Mon Sep 17 00:00:00 2001 From: Anna Maniscalco Date: Thu, 27 Nov 2025 19:22:35 +0100 Subject: drm/msm: add PERFCTR_CNTL to ifpc_reglist Previously this register would become 0 after IFPC took place which broke all usages of counters. Fixes: a6a0157cc68e ("drm/msm/a6xx: Enable IFPC on Adreno X1-85") Cc: stable@vger.kernel.org Signed-off-by: Anna Maniscalco Reviewed-by: Akhil P Oommen Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/690960/ Message-ID: <20251127-ifpc_counters-v3-1-fac0a126bc88@gmail.com> Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 29107b362346..b731491dc522 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1392,6 +1392,7 @@ static const u32 a750_ifpc_reglist_regs[] = { REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(2), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(3), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(4), + REG_A6XX_RBBM_PERFCTR_CNTL, REG_A6XX_TPL1_NC_MODE_CNTL, REG_A6XX_SP_NC_MODE_CNTL, REG_A6XX_CP_DBG_ECO_CNTL, -- cgit v1.2.3 From d2b6e710d2706c8915fe5e2f961c3365976d2ae1 Mon Sep 17 00:00:00 2001 From: Anna Maniscalco Date: Mon, 1 Dec 2025 19:14:36 +0100 Subject: drm/msm: Fix a7xx per pipe register programming GEN7_GRAS_NC_MODE_CNTL was only programmed for BR and not for BV pipe but it needs to be programmed for both. Program both pipes in hw_init and introducea separate reglist for it in order to add this register to the dynamic reglist which supports restoring registers per pipe. Fixes: 91389b4e3263 ("drm/msm/a6xx: Add a pwrup_list field to a6xx_info") Cc: stable@vger.kernel.org Reviewed-by: Akhil P Oommen Signed-off-by: Anna Maniscalco Patchwork: https://patchwork.freedesktop.org/patch/691553/ Message-ID: <20251201-gras_nc_mode_fix-v3-1-92a8a10d91d0@gmail.com> Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_catalog.c | 12 ++++++++++- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 34 +++++++++++++++++++++++++++---- drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 1 + drivers/gpu/drm/msm/adreno/adreno_gpu.h | 13 ++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index b731491dc522..ac9a95aab2fb 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1376,7 +1376,6 @@ static const uint32_t a7xx_pwrup_reglist_regs[] = { REG_A6XX_UCHE_MODE_CNTL, REG_A6XX_RB_NC_MODE_CNTL, REG_A6XX_RB_CMP_DBG_ECO_CNTL, - REG_A7XX_GRAS_NC_MODE_CNTL, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, REG_A6XX_UCHE_GBIF_GX_CONFIG, REG_A6XX_UCHE_CLIENT_PF, @@ -1449,6 +1448,12 @@ static const u32 a750_ifpc_reglist_regs[] = { DECLARE_ADRENO_REGLIST_LIST(a750_ifpc_reglist); +static const struct adreno_reglist_pipe a7xx_dyn_pwrup_reglist_regs[] = { + { REG_A7XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, +}; + +DECLARE_ADRENO_REGLIST_PIPE_LIST(a7xx_dyn_pwrup_reglist); + static const struct adreno_info a7xx_gpus[] = { { .chip_ids = ADRENO_CHIP_IDS(0x07000200), @@ -1492,6 +1497,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a730_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_cgc_mode = 0x00020000, }, @@ -1514,6 +1520,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7020100, .gmu_cgc_mode = 0x00020202, @@ -1548,6 +1555,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .ifpc_reglist = &a750_ifpc_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7050001, @@ -1590,6 +1598,7 @@ static const struct adreno_info a7xx_gpus[] = { .a6xx = &(const struct a6xx_info) { .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .ifpc_reglist = &a750_ifpc_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7090100, @@ -1624,6 +1633,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x70f0000, .gmu_cgc_mode = 0x00020222, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 7e71f6bb5283..2129d230a92b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -849,9 +849,16 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu) min_acc_len_64b << 3 | hbb_lo << 1 | ubwc_mode); - if (adreno_is_a7xx(adreno_gpu)) - gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, - FIELD_PREP(GENMASK(8, 5), hbb_lo)); + if (adreno_is_a7xx(adreno_gpu)) { + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_BV; pipe_id++) { + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id)); + gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, + FIELD_PREP(GENMASK(8, 5), hbb_lo)); + } + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(PIPE_NONE)); + } gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, min_acc_len_64b << 23 | hbb_lo << 21); @@ -865,9 +872,11 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); const struct adreno_reglist_list *reglist; + const struct adreno_reglist_pipe_list *dyn_pwrup_reglist; void *ptr = a6xx_gpu->pwrup_reglist_ptr; struct cpu_gpu_lock *lock = ptr; u32 *dest = (u32 *)&lock->regs[0]; + u32 dyn_pwrup_reglist_count = 0; int i; lock->gpu_req = lock->cpu_req = lock->turn = 0; @@ -909,7 +918,24 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) * (
), and the length is * stored as number for triplets in dynamic_list_len. */ - lock->dynamic_list_len = 0; + dyn_pwrup_reglist = adreno_gpu->info->a6xx->dyn_pwrup_reglist; + if (dyn_pwrup_reglist) { + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_BV; pipe_id++) { + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id)); + for (i = 0; i < dyn_pwrup_reglist->count; i++) { + if ((dyn_pwrup_reglist->regs[i].pipe & BIT(pipe_id)) == 0) + continue; + *dest++ = A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id); + *dest++ = dyn_pwrup_reglist->regs[i].offset; + *dest++ = gpu_read(gpu, dyn_pwrup_reglist->regs[i].offset); + dyn_pwrup_reglist_count++; + } + } + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(PIPE_NONE)); + } + lock->dynamic_list_len = dyn_pwrup_reglist_count; } static int a7xx_preempt_start(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 6820216ec5fc..4eaa04711246 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -45,6 +45,7 @@ struct a6xx_info { const struct adreno_reglist *hwcg; const struct adreno_protect *protect; const struct adreno_reglist_list *pwrup_reglist; + const struct adreno_reglist_pipe_list *dyn_pwrup_reglist; const struct adreno_reglist_list *ifpc_reglist; const struct adreno_reglist *gbif_cx; const struct adreno_reglist_pipe *nonctxt_reglist; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 0f8d3de97636..1d0145f8b3ec 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -188,6 +188,19 @@ static const struct adreno_reglist_list name = { \ .count = ARRAY_SIZE(name ## _regs), \ }; +struct adreno_reglist_pipe_list { + /** @reg: List of register **/ + const struct adreno_reglist_pipe *regs; + /** @count: Number of registers in the list **/ + u32 count; +}; + +#define DECLARE_ADRENO_REGLIST_PIPE_LIST(name) \ +static const struct adreno_reglist_pipe_list name = { \ + .regs = name ## _regs, \ + .count = ARRAY_SIZE(name ## _regs), \ +}; + struct adreno_gpu { struct msm_gpu base; const struct adreno_info *info; -- cgit v1.2.3 From 560271e10b2c86e95ea35afa9e79822e4847f07a Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 11 Dec 2025 14:02:54 -0500 Subject: drm/nouveau/dispnv50: Don't call drm_atomic_get_crtc_state() in prepare_fb Since we recently started warning about uses of this function after the atomic check phase completes, we've started getting warnings about this in nouveau. It appears a misplaced drm_atomic_get_crtc_state() call has been hiding in our .prepare_fb callback for a while. So, fix this by adding a new nv50_head_atom_get_new() function and use that in our .prepare_fb callback instead. Signed-off-by: Lyude Paul Reviewed-by: Dave Airlie Fixes: 1590700d94ac ("drm/nouveau/kms/nv50-: split each resource type into their own source files") Cc: # v4.18+ Link: https://patch.msgid.link/20251211190256.396742-1-lyude@redhat.com --- drivers/gpu/drm/nouveau/dispnv50/atom.h | 13 +++++++++++++ drivers/gpu/drm/nouveau/dispnv50/wndw.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index 93f8f4f64578..b43c4f9bbcdf 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -152,8 +152,21 @@ static inline struct nv50_head_atom * nv50_head_atom_get(struct drm_atomic_state *state, struct drm_crtc *crtc) { struct drm_crtc_state *statec = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(statec)) return (void *)statec; + + return nv50_head_atom(statec); +} + +static inline struct nv50_head_atom * +nv50_head_atom_get_new(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *statec = drm_atomic_get_new_crtc_state(state, crtc); + + if (!statec) + return NULL; + return nv50_head_atom(statec); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index ef9e410babbf..9a2c20fce0f3 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -583,7 +583,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) asyw->image.offset[0] = nvbo->offset; if (wndw->func->prepare) { - asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); + asyh = nv50_head_atom_get_new(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh); -- cgit v1.2.3 From daa24603d9f0808929514ee62ced30052ca7221c Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Fri, 12 Dec 2025 17:19:49 -0700 Subject: ublk: clean up user copy references on ublk server exit If a ublk server process releases a ublk char device file, any requests dispatched to the ublk server but not yet completed will retain a ref value of UBLK_REFCOUNT_INIT. Before commit e63d2228ef83 ("ublk: simplify aborting ublk request"), __ublk_fail_req() would decrement the reference count before completing the failed request. However, that commit optimized __ublk_fail_req() to call __ublk_complete_rq() directly without decrementing the request reference count. The leaked reference count incorrectly allows user copy and zero copy operations on the completed ublk request. It also triggers the WARN_ON_ONCE(refcount_read(&io->ref)) warnings in ublk_queue_reinit() and ublk_deinit_queue(). Commit c5c5eb24ed61 ("ublk: avoid ublk_io_release() called after ublk char dev is closed") already fixed the issue for ublk devices using UBLK_F_SUPPORT_ZERO_COPY or UBLK_F_AUTO_BUF_REG. However, the reference count leak also affects UBLK_F_USER_COPY, the other reference-counted data copy mode. Fix the condition in ublk_check_and_reset_active_ref() to include all reference-counted data copy modes. This ensures that any ublk requests still owned by the ublk server when it exits have their reference counts reset to 0. Signed-off-by: Caleb Sander Mateos Fixes: e63d2228ef83 ("ublk: simplify aborting ublk request") Reviewed-by: Ming Lei Signed-off-by: Jens Axboe --- drivers/block/ublk_drv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index cfd2132410dd..49c208457198 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1607,8 +1607,7 @@ static bool ublk_check_and_reset_active_ref(struct ublk_device *ub) { int i, j; - if (!(ub->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | - UBLK_F_AUTO_BUF_REG))) + if (!ublk_dev_need_req_ref(ub)) return false; for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { -- cgit v1.2.3 From 1ddb815fdfd45613c32e9bd1f7137428f298e541 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 20 Dec 2025 11:46:10 +0300 Subject: block: rnbd-clt: Fix signedness bug in init_dev() The "dev->clt_device_id" variable is set using ida_alloc_max() which returns an int and in particular it returns negative error codes. Change the type from u32 to int to fix the error checking. Fixes: c9b5645fd8ca ("block: rnbd-clt: Fix leaked ID in init_dev()") Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe --- drivers/block/rnbd/rnbd-clt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/rnbd/rnbd-clt.h b/drivers/block/rnbd/rnbd-clt.h index a48e040abe63..fbc1ed766025 100644 --- a/drivers/block/rnbd/rnbd-clt.h +++ b/drivers/block/rnbd/rnbd-clt.h @@ -112,7 +112,7 @@ struct rnbd_clt_dev { struct rnbd_queue *hw_queues; u32 device_id; /* local Idr index - used to track minor number allocations. */ - u32 clt_device_id; + int clt_device_id; struct mutex lock; enum rnbd_clt_dev_state dev_state; refcount_t refcount; -- cgit v1.2.3 From 8aaa848eaddd9ef8680fc6aafbd3a0646da5df40 Mon Sep 17 00:00:00 2001 From: Jang Ingyu Date: Fri, 19 Dec 2025 13:15:08 +0900 Subject: RDMA/core: Fix logic error in ib_get_gids_from_rdma_hdr() Fix missing comparison operator for RDMA_NETWORK_ROCE_V1 in the conditional statement. The constant was used directly instead of being compared with net_type, causing the condition to always evaluate to true. Fixes: 1c15b4f2a42f ("RDMA/core: Modify enum ib_gid_type and enum rdma_network_type") Signed-off-by: Jang Ingyu Link: https://patch.msgid.link/20251219041508.1725947-1-ingyujang25@korea.ac.kr Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 11b1a194de44..ee390928511a 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -738,7 +738,7 @@ int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, (struct in6_addr *)dgid); return 0; } else if (net_type == RDMA_NETWORK_IPV6 || - net_type == RDMA_NETWORK_IB || RDMA_NETWORK_ROCE_V1) { + net_type == RDMA_NETWORK_IB || net_type == RDMA_NETWORK_ROCE_V1) { *dgid = hdr->ibgrh.dgid; *sgid = hdr->ibgrh.sgid; return 0; -- cgit v1.2.3 From 145a417a39d7efbc881f52e829817376972b278c Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 17 Dec 2025 02:01:41 -0800 Subject: RDMA/bnxt_re: Fix incorrect BAR check in bnxt_qplib_map_creq_db() RCFW_COMM_CONS_PCI_BAR_REGION is defined as BAR 2, so checking !creq_db->reg.bar_id is incorrect and always false. pci_resource_start() returns the BAR base address, and a value of 0 indicates that the BAR is unassigned. Update the condition to test bar_base == 0 instead. This ensures the driver detects and logs an error for an unassigned RCFW communication BAR. Fixes: cee0c7bba486 ("RDMA/bnxt_re: Refactor command queue management code") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251217100158.752504-1-alok.a.tiwari@oracle.com Reviewed-by: Kalesh AP Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 295a9610f3e6..4dad0cfcfa98 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -1112,7 +1112,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) creq_db->dbinfo.flags = 0; creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); - if (!creq_db->reg.bar_id) + if (!creq_db->reg.bar_base) dev_err(&pdev->dev, "QPLIB: CREQ BAR region %d resc start is 0!", creq_db->reg.bar_id); -- cgit v1.2.3 From de41cbc64d02ae85d56078764616b6ba75a55a48 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 19 Dec 2025 15:04:08 +0100 Subject: RDMA/rxe: let rxe_reclassify_recv_socket() call sk_owner_put() On kernels build with CONFIG_PROVE_LOCKING, CONFIG_MODULES and CONFIG_DEBUG_LOCK_ALLOC 'rmmod rdma_rxe' is no longer possible. For the global recv sockets rxe_net_exit() is where we call rxe_release_udp_tunnel-> udp_tunnel_sock_release(), which means the sockets are destroyed before 'rmmod rdma_rxe' finishes, so there's no need to protect against rxe_recv_slock_key and rxe_recv_sk_key disappearing while the sockets are still alive. Fixes: 80a85a771deb ("RDMA/rxe: reclassify sockets in order to avoid false positives from lockdep") Cc: Zhu Yanjun Cc: Jason Gunthorpe Cc: Leon Romanovsky Cc: Shinichiro Kawasaki Cc: linux-rdma@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-cifs@vger.kernel.org Signed-off-by: Stefan Metzmacher Link: https://patch.msgid.link/20251219140408.2300163-1-metze@samba.org Reviewed-by: Zhu Yanjun Tested-by: Shin'ichiro Kawasaki Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/rxe/rxe_net.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 0195d361e5e3..0bd0902b11f7 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -64,7 +64,39 @@ static inline void rxe_reclassify_recv_socket(struct socket *sock) break; default: WARN_ON_ONCE(1); + return; } + /* + * sock_lock_init_class_and_name() calls + * sk_owner_set(sk, THIS_MODULE); in order + * to make sure the referenced global + * variables rxe_recv_slock_key and + * rxe_recv_sk_key are not removed + * before the socket is closed. + * + * However this prevents rxe_net_exit() + * from being called and 'rmmod rdma_rxe' + * is refused because of the references. + * + * For the global sockets in recv_sockets, + * we are sure that rxe_net_exit() will call + * rxe_release_udp_tunnel -> udp_tunnel_sock_release. + * + * So we don't need the additional reference to + * our own (THIS_MODULE). + */ + sk_owner_put(sk); + /* + * We also call sk_owner_clear() otherwise + * sk_owner_put(sk) in sk_prot_free will + * fail, which is called via + * sk_free -> __sk_free -> sk_destruct + * and sk_destruct calls __sk_destruct + * directly or via call_rcu() + * so sk_prot_free() might be called + * after rxe_net_exit(). + */ + sk_owner_clear(sk); #endif /* CONFIG_DEBUG_LOCK_ALLOC */ } -- cgit v1.2.3 From fa3c411d21ebc26ffd175c7256c37cefa35020aa Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 20 Dec 2025 11:11:33 +0900 Subject: RDMA/core: always drop device refcount in ib_del_sub_device_and_put() Since nldev_deldev() (introduced by commit 060c642b2ab8 ("RDMA/nldev: Add support to add/delete a sub IB device through netlink") grabs a reference using ib_device_get_by_index() before calling ib_del_sub_device_and_put(), we need to drop that reference before returning -EOPNOTSUPP error. Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84 Fixes: bca51197620a ("RDMA/core: Support IB sub device with type "SMI"") Signed-off-by: Tetsuo Handa Link: https://patch.msgid.link/80749a85-cbe2-460c-8451-42516013f9fa@I-love.SAKURA.ne.jp Reviewed-by: Parav Pandit Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 13e8a1714bbd..1174ab7da629 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -2881,8 +2881,10 @@ int ib_del_sub_device_and_put(struct ib_device *sub) { struct ib_device *parent = sub->parent; - if (!parent) + if (!parent) { + ib_device_put(sub); return -EOPNOTSUPP; + } mutex_lock(&parent->subdev_lock); list_del(&sub->subdev_list); -- cgit v1.2.3 From 8f05e411aee3ce27ab7b790181cbac9eb81bfedc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 9 Dec 2025 14:41:58 +0100 Subject: drm/gem-shmem: Fix typos in documentation Fix the compile-time warnings Warning: drm_gem_shmem_helper.c:104 function parameter 'shmem' not described in 'drm_gem_shmem_init' Warning: drm_gem_shmem_helper.c:104 function parameter 'size' not described in 'drm_gem_shmem_init' Signed-off-by: Thomas Zimmermann Reviewed-by: Boris Brezillon Fixes: e3f4bdaf2c5b ("drm/gem/shmem: Extract drm_gem_shmem_init() from drm_gem_shmem_create()") Link: https://patch.msgid.link/20251209140141.94407-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 93b9cff89080..9cd52f8930fa 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -96,7 +96,8 @@ err_release: /** * drm_gem_shmem_init - Initialize an allocated object. * @dev: DRM device - * @obj: The allocated shmem GEM object. + * @shmem: The allocated shmem GEM object. + * @size: Buffer size in bytes * * Returns: * 0 on success, or a negative error code on failure. -- cgit v1.2.3 From 3fbd97618f49e07e05aad96510e5f2ed22d68809 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 9 Dec 2025 14:41:59 +0100 Subject: drm/gem-shmem: Fix the MODULE_LICENSE() string Replace the bogus "GPL v2" with "GPL" as MODULE_LICNSE() string. The value does not declare the module's exact license, but only lets the module loader test whether the module is Free Software or not. See commit bf7fbeeae6db ("module: Cure the MODULE_LICENSE "GPL" vs. "GPL v2" bogosity") in the details of the issue. The fix is to use "GPL" for all modules under any variant of the GPL. Signed-off-by: Thomas Zimmermann Reviewed-by: Boris Brezillon Fixes: 4b2b5e142ff4 ("drm: Move GEM memory managers into modules") Link: https://patch.msgid.link/20251209140141.94407-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 9cd52f8930fa..f13eb5f36e8a 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -896,4 +896,4 @@ EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_no_map); MODULE_DESCRIPTION("DRM SHMEM memory-management helpers"); MODULE_IMPORT_NS("DMA_BUF"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f01765a2361323e78e3d91b1cb1d5527a83c5cf7 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Fri, 19 Dec 2025 01:32:57 -0800 Subject: RDMA/bnxt_re: Fix IB_SEND_IP_CSUM handling in post_send The bnxt_re SEND path checks wr->send_flags to enable features such as IP checksum offload. However, send_flags is a bitmask and may contain multiple flags (e.g. IB_SEND_SIGNALED | IB_SEND_IP_CSUM), while the existing code uses a switch() statement that only matches when send_flags is exactly IB_SEND_IP_CSUM. As a result, checksum offload is not enabled when additional SEND flags are present. Replace the switch() with a bitmask test: if (wr->send_flags & IB_SEND_IP_CSUM) This ensures IP checksum offload is enabled correctly when multiple SEND flags are used. Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251219093308.2415620-1-alok.a.tiwari@oracle.com Reviewed-by: Kalesh AP Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index f19b55c13d58..ff91511bd338 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2919,14 +2919,9 @@ int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr, wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_ROCE_CRC; } - switch (wr->send_flags) { - case IB_SEND_IP_CSUM: + if (wr->send_flags & IB_SEND_IP_CSUM) wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_IP_CHKSUM; - break; - default: - break; - } fallthrough; case IB_WR_SEND_WITH_INV: rc = bnxt_re_build_send_wqe(qp, wr, &wqe); -- cgit v1.2.3 From 9b68a1cc966bc947d00e4c0df7722d118125aa37 Mon Sep 17 00:00:00 2001 From: Ding Hui Date: Mon, 8 Dec 2025 15:21:10 +0800 Subject: RDMA/bnxt_re: Fix OOB write in bnxt_re_copy_err_stats() Commit ef56081d1864 ("RDMA/bnxt_re: RoCE related hardware counters update") added three new counters and placed them after BNXT_RE_OUT_OF_SEQ_ERR. BNXT_RE_OUT_OF_SEQ_ERR acts as a boundary marker for allocating hardware statistics with different num_counters values on chip_gen_p5_p7 devices. As a result, BNXT_RE_NUM_STD_COUNTERS are used when allocating hw_stats, which leads to an out-of-bounds write in bnxt_re_copy_err_stats(). The counters BNXT_RE_REQ_CQE_ERROR, BNXT_RE_RESP_CQE_ERROR, and BNXT_RE_RESP_REMOTE_ACCESS_ERRS are applicable to generic hardware, not only p5/p7 devices. Fix this by moving these counters before BNXT_RE_OUT_OF_SEQ_ERR so they are included in the generic counter set. Fixes: ef56081d1864 ("RDMA/bnxt_re: RoCE related hardware counters update") Reported-by: Yingying Zheng Signed-off-by: Ding Hui Link: https://patch.msgid.link/20251208072110.28874-1-dinghui@sangfor.com.cn Reviewed-by: Kalesh AP Tested-by: Kalesh AP Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/hw_counters.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 09d371d442aa..cebec033f4a0 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -89,6 +89,9 @@ enum bnxt_re_hw_stats { BNXT_RE_RES_SRQ_LOAD_ERR, BNXT_RE_RES_TX_PCI_ERR, BNXT_RE_RES_RX_PCI_ERR, + BNXT_RE_REQ_CQE_ERROR, + BNXT_RE_RESP_CQE_ERROR, + BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_OUT_OF_SEQ_ERR, BNXT_RE_TX_ATOMIC_REQ, BNXT_RE_TX_READ_REQ, @@ -110,9 +113,6 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_CNP, BNXT_RE_RX_CNP, BNXT_RE_RX_ECN, - BNXT_RE_REQ_CQE_ERROR, - BNXT_RE_RESP_CQE_ERROR, - BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_NUM_EXT_COUNTERS }; -- cgit v1.2.3 From c81f30bde5b0449d9d82d31a66f0ffd608e610b5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sun, 21 Dec 2025 19:05:09 +0800 Subject: spi: sun6i: Support A523's SPI controllers The A523 has four SPI controllers. One of them supports MIPI DBI mode in addition to standard SPI. Compared to older generations, this newer controller now has a combined counter for the RX FIFO ad buffer levels. In older generations, the RX buffer level was a separate bitfield in the FIFO status register. In practice this difference is negligible. The buffer is mostly invisible to the implementation. If programmed I/O transfers are limited to the FIFO size, then the contents of the buffer seem to always be flushed over to the FIFO. For DMA, the DRQ trigger levels are only tied to the FIFO levels. In all other aspects, the controller is the same as the one in the R329. Support the standard SPI mode controllers using the settings for R329. DBI is left out as there currently is no infrastructure for enabling a DBI host controller, as was the case for the R329. Also fold the entry for the R329 to make the style consistent. Signed-off-by: Chen-Yu Tsai Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20251221110513.1850535-3-wens@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 871dfd3e77be..d1de6c99e762 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -795,10 +795,13 @@ static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = { static const struct of_device_id sun6i_spi_match[] = { { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg }, { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_cfg }, - { - .compatible = "allwinner,sun50i-r329-spi", - .data = &sun50i_r329_spi_cfg - }, + { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_cfg }, + /* + * A523's SPI controller has a combined RX buffer + FIFO counter + * at offset 0x400, instead of split buffer count in FIFO status + * register. But in practice we only care about the FIFO level. + */ + { .compatible = "allwinner,sun55i-a523-spi", .data = &sun50i_r329_spi_cfg }, {} }; MODULE_DEVICE_TABLE(of, sun6i_spi_match); -- cgit v1.2.3 From 23f9485510c338476b9735d516c1d4aacb810d46 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 18 Nov 2025 09:35:48 +0100 Subject: counter: interrupt-cnt: Drop IRQF_NO_THREAD flag An IRQ handler can either be IRQF_NO_THREAD or acquire spinlock_t, as CONFIG_PROVE_RAW_LOCK_NESTING warns: ============================= [ BUG: Invalid wait context ] 6.18.0-rc1+git... #1 ----------------------------- some-user-space-process/1251 is trying to lock: (&counter->events_list_lock){....}-{3:3}, at: counter_push_event [counter] other info that might help us debug this: context-{2:2} no locks held by some-user-space-process/.... stack backtrace: CPU: 0 UID: 0 PID: 1251 Comm: some-user-space-process 6.18.0-rc1+git... #1 PREEMPT Call trace: show_stack (C) dump_stack_lvl dump_stack __lock_acquire lock_acquire _raw_spin_lock_irqsave counter_push_event [counter] interrupt_cnt_isr [interrupt_cnt] __handle_irq_event_percpu handle_irq_event handle_simple_irq handle_irq_desc generic_handle_domain_irq gpio_irq_handler handle_irq_desc generic_handle_domain_irq gic_handle_irq call_on_irq_stack do_interrupt_handler el0_interrupt __el0_irq_handler_common el0t_64_irq_handler el0t_64_irq ... and Sebastian correctly points out. Remove IRQF_NO_THREAD as an alternative to switching to raw_spinlock_t, because the latter would limit all potential nested locks to raw_spinlock_t only. Cc: Sebastian Andrzej Siewior Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20251117151314.xwLAZrWY@linutronix.de/ Fixes: a55ebd47f21f ("counter: add IRQ or GPIO based counter") Signed-off-by: Alexander Sverdlin Reviewed-by: Sebastian Andrzej Siewior Reviewed-by: Oleksij Rempel Link: https://lore.kernel.org/r/20251118083603.778626-1-alexander.sverdlin@siemens.com Signed-off-by: William Breathitt Gray --- drivers/counter/interrupt-cnt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c index 6c0c1d2d7027..e6100b5fb082 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -229,8 +229,7 @@ static int interrupt_cnt_probe(struct platform_device *pdev) irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr, - IRQF_TRIGGER_RISING | IRQF_NO_THREAD, - dev_name(dev), counter); + IRQF_TRIGGER_RISING, dev_name(dev), counter); if (ret) return ret; -- cgit v1.2.3 From 9517d76dd160208b7a432301ce7bec8fc1ddc305 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 15 Dec 2025 10:01:14 +0800 Subject: counter: 104-quad-8: Fix incorrect return value in IRQ handler quad8_irq_handler() should return irqreturn_t enum values, but it directly returns negative errno codes from regmap operations on error. Return IRQ_NONE if the interrupt status cannot be read. If clearing the interrupt fails, return IRQ_HANDLED to prevent the kernel from disabling the IRQ line due to a spurious interrupt storm. Also, log these regmap failures with dev_WARN_ONCE. Fixes: 98ffe0252911 ("counter: 104-quad-8: Migrate to the regmap API") Suggested-by: Andy Shevchenko Signed-off-by: Haotian Zhang Link: https://lore.kernel.org/r/20251215020114.1913-1-vulab@iscas.ac.cn Cc: stable@vger.kernel.org Signed-off-by: William Breathitt Gray --- drivers/counter/104-quad-8.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index ce81fc4e1ae7..573b2fe93253 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -1192,6 +1192,7 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) { struct counter_device *counter = private; struct quad8 *const priv = counter_priv(counter); + struct device *dev = counter->parent; unsigned int status; unsigned long irq_status; unsigned long channel; @@ -1200,8 +1201,11 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) int ret; ret = regmap_read(priv->map, QUAD8_INTERRUPT_STATUS, &status); - if (ret) - return ret; + if (ret) { + dev_WARN_ONCE(dev, true, + "Attempt to read Interrupt Status Register failed: %d\n", ret); + return IRQ_NONE; + } if (!status) return IRQ_NONE; @@ -1223,8 +1227,9 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) break; default: /* should never reach this path */ - WARN_ONCE(true, "invalid interrupt trigger function %u configured for channel %lu\n", - flg_pins, channel); + dev_WARN_ONCE(dev, true, + "invalid interrupt trigger function %u configured for channel %lu\n", + flg_pins, channel); continue; } @@ -1232,8 +1237,11 @@ static irqreturn_t quad8_irq_handler(int irq, void *private) } ret = regmap_write(priv->map, QUAD8_CHANNEL_OPERATION, CLEAR_PENDING_INTERRUPTS); - if (ret) - return ret; + if (ret) { + dev_WARN_ONCE(dev, true, + "Attempt to clear pending interrupts by writing to Channel Operation Register failed: %d\n", ret); + return IRQ_HANDLED; + } return IRQ_HANDLED; } -- cgit v1.2.3 From bf4172bd870c3a34d3065cbb39192c22cbd7b18d Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Wed, 10 Dec 2025 22:24:51 -0800 Subject: net: usb: sr9700: support devices with virtual driver CD Some SR9700 devices have an SPI flash chip containing a virtual driver CD, in which case they appear as a device with two interfaces and product ID 0x9702. Interface 0 is the driver CD and interface 1 is the Ethernet device. Link: https://github.com/name-kurniawan/usb-lan Link: https://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=2185 Signed-off-by: Ethan Nelson-Moore Link: https://patch.msgid.link/20251211062451.139036-1-enelsonmoore@gmail.com [pabeni@redhat.com: fixes link tags] Signed-off-by: Paolo Abeni --- drivers/net/usb/sr9700.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 091bc2aca7e8..d8ffb59eaf34 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -539,6 +539,11 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */ .driver_info = (unsigned long)&sr9700_driver_info, }, + { + /* SR9700 with virtual driver CD-ROM - interface 0 is the CD-ROM device */ + USB_DEVICE_INTERFACE_NUMBER(0x0fe6, 0x9702, 1), + .driver_info = (unsigned long)&sr9700_driver_info, + }, {}, /* END */ }; -- cgit v1.2.3 From d1a1a4bade4b20c0858d0b2f81d2611de055f675 Mon Sep 17 00:00:00 2001 From: Jacky Chou Date: Thu, 11 Dec 2025 14:24:58 +0800 Subject: net: mdio: aspeed: add dummy read to avoid read-after-write issue The Aspeed MDIO controller may return incorrect data when a read operation follows immediately after a write. Due to a controller bug, the subsequent read can latch stale data, causing the polling logic to terminate earlier than expected. To work around this hardware issue, insert a dummy read after each write operation. This ensures that the next actual read returns the correct data and prevents premature polling exit. This workaround has been verified to stabilize MDIO transactions on affected Aspeed platforms. Fixes: f160e99462c6 ("net: phy: Add mdio-aspeed") Signed-off-by: Jacky Chou Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251211-aspeed_mdio_add_dummy_read-v3-1-382868869004@aspeedtech.com Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-aspeed.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c index e55be6dc9ae7..d6b9004c61dc 100644 --- a/drivers/net/mdio/mdio-aspeed.c +++ b/drivers/net/mdio/mdio-aspeed.c @@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad, iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); + /* Workaround for read-after-write issue. + * The controller may return stale data if a read follows immediately + * after a write. A dummy read forces the hardware to update its + * internal state, ensuring that the next real read returns correct data. + */ + ioread32(ctx->base + ASPEED_MDIO_CTRL); + return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl, !(ctrl & ASPEED_MDIO_CTRL_FIRE), ASPEED_MDIO_INTERVAL_US, -- cgit v1.2.3 From 15ef641a0c6728d25a400df73922e80ab2cf029c Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 11 Dec 2025 15:37:56 +0800 Subject: fjes: Add missing iounmap in fjes_hw_init() In error paths, add fjes_hw_iounmap() to release the resource acquired by fjes_hw_iomap(). Add a goto label to do so. Fixes: 8cdc3f6c5d22 ("fjes: Hardware initialization routine") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Signed-off-by: Simon Horman Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251211073756.101824-1-lihaoxiang@isrc.iscas.ac.cn Signed-off-by: Paolo Abeni --- drivers/net/fjes/fjes_hw.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index b9b5554ea862..5ad2673f213d 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -334,7 +334,7 @@ int fjes_hw_init(struct fjes_hw *hw) ret = fjes_hw_reset(hw); if (ret) - return ret; + goto err_iounmap; fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); @@ -347,8 +347,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->max_epid = fjes_hw_get_max_epid(hw); hw->my_epid = fjes_hw_get_my_epid(hw); - if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) - return -ENXIO; + if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) { + ret = -ENXIO; + goto err_iounmap; + } ret = fjes_hw_setup(hw); @@ -356,6 +358,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->hw_info.trace_size = FJES_DEBUG_BUFFER_SIZE; return ret; + +err_iounmap: + fjes_hw_iounmap(hw); + return ret; } void fjes_hw_exit(struct fjes_hw *hw) -- cgit v1.2.3 From 1e5a541420b8c6d87d88eb50b6b978cdeafee1c9 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 12:13:13 +0400 Subject: net: phy: mediatek: fix nvmem cell reference leak in mt798x_phy_calibration When nvmem_cell_read() fails in mt798x_phy_calibration(), the function returns without calling nvmem_cell_put(), leaking the cell reference. Move nvmem_cell_put() right after nvmem_cell_read() to ensure the cell reference is always released regardless of the read result. Found via static analysis and code review. Fixes: 98c485eaf509 ("net: phy: add driver for MediaTek SoC built-in GE PHYs") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251211081313.2368460-1-linmq006@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index cd09fbf92ef2..2c4bbc236202 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -1167,9 +1167,9 @@ static int mt798x_phy_calibration(struct phy_device *phydev) } buf = (u32 *)nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); if (IS_ERR(buf)) return PTR_ERR(buf); - nvmem_cell_put(cell); if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { phydev_err(phydev, "invalid efuse data\n"); -- cgit v1.2.3 From e521dc1687834d0e8c7506f1fdf00daab4ebb51d Mon Sep 17 00:00:00 2001 From: Tim Wassink Date: Sun, 21 Dec 2025 19:17:14 +0100 Subject: platform/x86: asus-nb-wmi: Add keymap for display toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Asus Zenbook 14 (UX3405MA), the Fn+F7 key combination emits WMI code 0x2d, which was previously unmapped. Map this code to KEY_DISPLAYTOGGLE. This matches the behavior of the display toggle/projector mode key found on other Asus laptops, allowing userspace to handle multi-monitor switching or screen toggling. Tested on ASUS Zenbook 14 UX3405MA. Signed-off-by: Tim Wassink Reviewed-by: Denis Benato Link: https://patch.msgid.link/20251221181724.19927-1-timwassink.dev@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-nb-wmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 6a62bc5b02fd..a38a65f5c550 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -580,6 +580,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } }, { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */ { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */ + { KE_KEY, 0x2d, { KEY_DISPLAYTOGGLE } }, { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, { KE_KEY, 0x32, { KEY_MUTE } }, -- cgit v1.2.3 From f13bce715d1600698310a4a7832f6a52499d5395 Mon Sep 17 00:00:00 2001 From: Shravan Kumar Ramani Date: Thu, 18 Dec 2025 12:18:13 +0000 Subject: platform/mellanox: mlxbf-pmc: Remove trailing whitespaces from event names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some event names have trailing whitespaces at the end which causes programming of counters using the name for these specific events to fail and hence need to be removed. Fixes: 423c3361855c ("platform/mellanox: mlxbf-pmc: Add support for BlueField-3") Signed-off-by: Shravan Kumar Ramani Reviewed-by: David Thompson Link: https://patch.msgid.link/065cbae0717dcc1169681c4dbb1a6e050b8574b3.1766059953.git.shravankr@nvidia.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxbf-pmc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index 16a2fd9fdd9b..5ec1ad471696 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -801,18 +801,18 @@ static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = { {11, "GDC_MISS_MACHINE_CHI_TXDAT"}, {12, "GDC_MISS_MACHINE_CHI_RXDAT"}, {13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"}, - {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "}, + {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1"}, {15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"}, - {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "}, - {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "}, - {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "}, - {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "}, - {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "}, + {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3"}, + {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0"}, + {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1"}, + {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2"}, + {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3"}, {21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"}, {22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"}, {23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"}, {24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"}, - {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "}, + {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0"}, {26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"}, {27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"}, {28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"}, -- cgit v1.2.3 From a5b9fdd33c59a964a26d12c39b636ef85a25b074 Mon Sep 17 00:00:00 2001 From: Dmytro Bagrii Date: Fri, 28 Nov 2025 18:15:23 +0200 Subject: platform/x86: dell-lis3lv02d: Add Latitude 5400 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add accelerometer address 0x29 for Dell Latitude 5400. The address is verified as below: $ cat /sys/class/dmi/id/product_name Latitude 5400 $ grep -H '' /sys/bus/pci/drivers/i801_smbus/0000\:00*/i2c-*/name /sys/bus/pci/drivers/i801_smbus/0000:00:1f.4/i2c-10/name:SMBus I801 adapter at 0000:00:1f.4 $ i2cdetect 10 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-10. I will probe address range 0x08-0x77. Continue? [Y/n] Y 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: 08 -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- 30: 30 -- -- -- -- 35 UU UU -- -- -- -- -- -- -- -- 40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- 50: UU -- 52 -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- $ xargs -n1 -a /proc/cmdline | grep ^dell_lis3lv02d dell_lis3lv02d.probe_i2c_addr=1 $ dmesg | grep lis3lv02d ... [ 206.012411] i2c i2c-10: Probing for lis3lv02d on address 0x29 [ 206.013727] i2c i2c-10: Detected lis3lv02d on address 0x29, please report this upstream to platform-driver-x86@vger.kernel.org so that a quirk can be added [ 206.240841] lis3lv02d_i2c 10-0029: supply Vdd not found, using dummy regulator [ 206.240868] lis3lv02d_i2c 10-0029: supply Vdd_IO not found, using dummy regulator [ 206.261258] lis3lv02d: 8 bits 3DC sensor found [ 206.346722] input: ST LIS3LV02DL Accelerometer as /devices/faux/lis3lv02d/input/input17 $ cat /sys/class/input/input17/name ST LIS3LV02DL Accelerometer Signed-off-by: Dmytro Bagrii Reviewed-by: Hans de Goede Link: https://patch.msgid.link/20251128161523.6224-1-dimich.dmb@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/dell/dell-lis3lv02d.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell/dell-lis3lv02d.c b/drivers/platform/x86/dell/dell-lis3lv02d.c index 77905a9ddde9..fe52bcd896f7 100644 --- a/drivers/platform/x86/dell/dell-lis3lv02d.c +++ b/drivers/platform/x86/dell/dell-lis3lv02d.c @@ -44,6 +44,7 @@ static const struct dmi_system_id lis3lv02d_devices[] __initconst = { /* * Additional individual entries were added after verification. */ + DELL_LIS3LV02D_DMI_ENTRY("Latitude 5400", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude 5480", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude 5500", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude E6330", 0x29), -- cgit v1.2.3 From 05126063605f26f9228c69b1ff232ac6e78f72ab Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Thu, 27 Nov 2025 15:29:48 -0500 Subject: platform/x86: think-lmi: Add WMI certificate thumbprint support for ThinkCenter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ThinkCenter team are adding WMI certificate thumbprint support. Updating the driver to enable it. They are using the same GUID as Thinkpad/ThinkStation. Tested on M75q Gen 5. Signed-off-by: Mark Pearson Link: https://patch.msgid.link/20251127202959.399040-1-mpearson-lenovo@squebb.ca Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/think-lmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/lenovo/think-lmi.c b/drivers/platform/x86/lenovo/think-lmi.c index 540b472b1bf3..c45f0206b4ab 100644 --- a/drivers/platform/x86/lenovo/think-lmi.c +++ b/drivers/platform/x86/lenovo/think-lmi.c @@ -195,7 +195,7 @@ static const struct tlmi_cert_guids thinkpad_cert_guid = { }; static const struct tlmi_cert_guids thinkcenter_cert_guid = { - .thumbprint = NULL, + .thumbprint = LENOVO_CERT_THUMBPRINT_GUID, /* Same GUID as TP */ .set_bios_setting = LENOVO_TC_SET_BIOS_SETTING_CERT_GUID, .save_bios_setting = LENOVO_TC_SAVE_BIOS_SETTING_CERT_GUID, .cert_to_password = LENOVO_TC_CERT_TO_PASSWORD_GUID, @@ -709,6 +709,10 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count) if (!tlmi_priv.cert_guid->thumbprint) return -EOPNOTSUPP; + /* Older ThinkCenter BIOS may not have support */ + if (!wmi_has_guid(tlmi_priv.cert_guid->thumbprint)) + return -EOPNOTSUPP; + status = wmi_evaluate_method(tlmi_priv.cert_guid->thumbprint, 0, 0, &input, &output); if (ACPI_FAILURE(status)) { kfree(output.pointer); -- cgit v1.2.3 From 1461209cf813b6ee6d40f29b96b544587df6d2b1 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 17 Dec 2025 11:36:13 +0100 Subject: platform/x86: msi-laptop: add missing sysfs_remove_group() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A sysfs group is created in msi_init() when old_ec_model is enabled, but never removed. Remove the msipf_old_attribute_group in that case. Fixes: 03696e51d75a ("msi-laptop: Disable brightness control for new EC") Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20251217103617.27668-2-fourier.thomas@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/msi-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index c4b150fa093f..ddef6b78d2fa 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1130,6 +1130,9 @@ static void __exit msi_cleanup(void) sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); if (!quirks->old_ec_model && threeg_exists) device_remove_file(&msipf_device->dev, &dev_attr_threeg); + if (quirks->old_ec_model) + sysfs_remove_group(&msipf_device->dev.kobj, + &msipf_old_attribute_group); platform_device_unregister(msipf_device); platform_driver_unregister(&msipf_driver); backlight_device_unregister(msibl_device); -- cgit v1.2.3 From 15dd100349b8526cbdf2de0ce3e72e700eb6c208 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Fri, 19 Dec 2025 16:30:29 +0800 Subject: platform/x86: ibm_rtl: fix EBDA signature search pointer arithmetic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ibm_rtl_init() function searches for the signature but has a pointer arithmetic error. The loop counter suggests searching at 4-byte intervals but the implementation only advances by 1 byte per iteration. Fix by properly advancing the pointer by sizeof(unsigned int) bytes each iteration. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: 35f0ce032b0f ("IBM Real-Time "SMI Free" mode driver -v7") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB78812D887A92DE3802D0D06EAFA9A@SYBPR01MB7881.ausprd01.prod.outlook.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/ibm_rtl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 231b37909801..139956168cf9 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -273,7 +273,7 @@ static int __init ibm_rtl_init(void) { /* search for the _RTL_ signature at the start of the table */ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) { struct ibm_rtl_table __iomem * tmp; - tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i); + tmp = (struct ibm_rtl_table __iomem *) (ebda_map + i*sizeof(unsigned int)); if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) { phys_addr_t addr; unsigned int plen; -- cgit v1.2.3 From 932ac51d9953eaf77a1252f79b656d4ca86163c6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 12 Dec 2025 11:29:53 +0100 Subject: team: fix check for port enabled in team_queue_override_port_prio_changed() There has been a syzkaller bug reported recently with the following trace: list_del corruption, ffff888058bea080->prev is LIST_POISON2 (dead000000000122) ------------[ cut here ]------------ kernel BUG at lib/list_debug.c:59! Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 3 UID: 0 PID: 21246 Comm: syz.0.2928 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 RIP: 0010:__list_del_entry_valid_or_report+0x13e/0x200 lib/list_debug.c:59 Code: 48 c7 c7 e0 71 f0 8b e8 30 08 ef fc 90 0f 0b 48 89 ef e8 a5 02 55 fd 48 89 ea 48 89 de 48 c7 c7 40 72 f0 8b e8 13 08 ef fc 90 <0f> 0b 48 89 ef e8 88 02 55 fd 48 89 ea 48 b8 00 00 00 00 00 fc ff RSP: 0018:ffffc9000d49f370 EFLAGS: 00010286 RAX: 000000000000004e RBX: ffff888058bea080 RCX: ffffc9002817d000 RDX: 0000000000000000 RSI: ffffffff819becc6 RDI: 0000000000000005 RBP: dead000000000122 R08: 0000000000000005 R09: 0000000000000000 R10: 0000000080000000 R11: 0000000000000001 R12: ffff888039e9c230 R13: ffff888058bea088 R14: ffff888058bea080 R15: ffff888055461480 FS: 00007fbbcfe6f6c0(0000) GS:ffff8880d6d0a000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000110c3afcb0 CR3: 00000000382c7000 CR4: 0000000000352ef0 Call Trace: __list_del_entry_valid include/linux/list.h:132 [inline] __list_del_entry include/linux/list.h:223 [inline] list_del_rcu include/linux/rculist.h:178 [inline] __team_queue_override_port_del drivers/net/team/team_core.c:826 [inline] __team_queue_override_port_del drivers/net/team/team_core.c:821 [inline] team_queue_override_port_prio_changed drivers/net/team/team_core.c:883 [inline] team_priority_option_set+0x171/0x2f0 drivers/net/team/team_core.c:1534 team_option_set drivers/net/team/team_core.c:376 [inline] team_nl_options_set_doit+0x8ae/0xe60 drivers/net/team/team_core.c:2653 genl_family_rcv_msg_doit+0x209/0x2f0 net/netlink/genetlink.c:1115 genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline] genl_rcv_msg+0x55c/0x800 net/netlink/genetlink.c:1210 netlink_rcv_skb+0x158/0x420 net/netlink/af_netlink.c:2552 genl_rcv+0x28/0x40 net/netlink/genetlink.c:1219 netlink_unicast_kernel net/netlink/af_netlink.c:1320 [inline] netlink_unicast+0x5aa/0x870 net/netlink/af_netlink.c:1346 netlink_sendmsg+0x8c8/0xdd0 net/netlink/af_netlink.c:1896 sock_sendmsg_nosec net/socket.c:727 [inline] __sock_sendmsg net/socket.c:742 [inline] ____sys_sendmsg+0xa98/0xc70 net/socket.c:2630 ___sys_sendmsg+0x134/0x1d0 net/socket.c:2684 __sys_sendmsg+0x16d/0x220 net/socket.c:2716 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f The problem is in this flow: 1) Port is enabled, queue_id != 0, in qom_list 2) Port gets disabled -> team_port_disable() -> team_queue_override_port_del() -> del (removed from list) 3) Port is disabled, queue_id != 0, not in any list 4) Priority changes -> team_queue_override_port_prio_changed() -> checks: port disabled && queue_id != 0 -> calls del - hits the BUG as it is removed already To fix this, change the check in team_queue_override_port_prio_changed() so it returns early if port is not enabled. Reported-by: syzbot+422806e5f4cce722a71f@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=422806e5f4cce722a71f Fixes: 6c31ff366c11 ("team: remove synchronize_rcu() called during queue override change") Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251212102953.167287-1-jiri@resnulli.us Signed-off-by: Paolo Abeni --- drivers/net/team/team_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index 4d5c9ae8f221..c08a5c1bd6e4 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -878,7 +878,7 @@ static void __team_queue_override_enabled_check(struct team *team) static void team_queue_override_port_prio_changed(struct team *team, struct team_port *port) { - if (!port->queue_id || team_port_enabled(port)) + if (!port->queue_id || !team_port_enabled(port)) return; __team_queue_override_port_del(team, port); __team_queue_override_port_add(team, port); -- cgit v1.2.3 From 5e7365b5a1ac8f517a7a84442289d7de242deb76 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 14 Dec 2025 10:30:07 +0100 Subject: net: airoha: Move net_devs registration in a dedicated routine Since airoha_probe() is not executed under rtnl lock, there is small race where a given device is configured by user-space while the remaining ones are not completely loaded from the dts yet. This condition will allow a hw device misconfiguration since there are some conditions (e.g. GDM2 check in airoha_dev_init()) that require all device are properly loaded from the device tree. Fix the issue moving net_devices registration at the end of the airoha_probe routine. Fixes: 9cd451d414f6e ("net: airoha: Add loopback support for GDM2") Signed-off-by: Lorenzo Bianconi Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/airoha/airoha_eth.c | 39 +++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 75893c90a0a1..315d97036ac1 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -2924,19 +2924,26 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, port->id = id; eth->ports[p] = port; - err = airoha_metadata_dst_alloc(port); - if (err) - return err; + return airoha_metadata_dst_alloc(port); +} - err = register_netdev(dev); - if (err) - goto free_metadata_dst; +static int airoha_register_gdm_devices(struct airoha_eth *eth) +{ + int i; - return 0; + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; + int err; -free_metadata_dst: - airoha_metadata_dst_free(port); - return err; + if (!port) + continue; + + err = register_netdev(port->dev); + if (err) + return err; + } + + return 0; } static int airoha_probe(struct platform_device *pdev) @@ -3027,6 +3034,10 @@ static int airoha_probe(struct platform_device *pdev) } } + err = airoha_register_gdm_devices(eth); + if (err) + goto error_napi_stop; + return 0; error_napi_stop: @@ -3040,10 +3051,12 @@ error_hw_cleanup: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; - if (port && port->dev->reg_state == NETREG_REGISTERED) { + if (!port) + continue; + + if (port->dev->reg_state == NETREG_REGISTERED) unregister_netdev(port->dev); - airoha_metadata_dst_free(port); - } + airoha_metadata_dst_free(port); } free_netdev(eth->napi_dev); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From d2d7f5636f0d752a1e0e7eadbbc1839c29177bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 19 Dec 2025 12:32:57 +0100 Subject: drm/xe/svm: Fix a debug printout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid spamming the log with drm_info(). Use drm_dbg() instead. Fixes: cc795e041034 ("drm/xe/svm: Make xe_svm_range_needs_migrate_to_vram() public") Cc: Matthew Brost Cc: Himal Prasad Ghimiray Cc: # v6.17+ Signed-off-by: Thomas Hellström Reviewed-by: Himal Prasad Ghimiray Link: https://patch.msgid.link/20251219113320.183860-2-thomas.hellstrom@linux.intel.com (cherry picked from commit 72aee5f70ba47b939345a0d3414b51b0639c5b88) Signed-off-by: Thomas Hellström --- drivers/gpu/drm/xe/xe_svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 55c5a0eb82e1..894e8f092e3f 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -941,7 +941,7 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm xe_assert(vm->xe, IS_DGFX(vm->xe)); if (xe_svm_range_in_vram(range)) { - drm_info(&vm->xe->drm, "Range is already in VRAM\n"); + drm_dbg(&vm->xe->drm, "Range is already in VRAM\n"); return false; } -- cgit v1.2.3 From 754c23238438600e9236719f7e67aff2c4d02093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= Date: Fri, 19 Dec 2025 12:32:59 +0100 Subject: drm/pagemap, drm/xe: Ensure that the devmem allocation is idle before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In situations where no system memory is migrated to devmem, and in upcoming patches where another GPU is performing the migration to the newly allocated devmem buffer, there is nothing to ensure any ongoing clear to the devmem allocation or async eviction from the devmem allocation is complete. Address that by passing a struct dma_fence down to the copy functions, and ensure it is waited for before migration is marked complete. v3: - New patch. v4: - Update the logic used for determining when to wait for the pre_migrate_fence. - Update the logic used for determining when to warn for the pre_migrate_fence since the scheduler fences apparently can signal out-of-order. v5: - Fix a UAF (CI) - Remove references to source P2P migration (Himal) - Put the pre_migrate_fence after migration. v6: - Pipeline the pre_migrate_fence dependency (Matt Brost) Fixes: c5b3eb5a906c ("drm/xe: Add GPUSVM device memory copy vfunc functions") Cc: Matthew Brost Cc: # v6.15+ Signed-off-by: Thomas Hellström Reviewed-by: Matthew Brost Acked-by: Maarten Lankhorst # For merging through drm-xe. Link: https://patch.msgid.link/20251219113320.183860-4-thomas.hellstrom@linux.intel.com (cherry picked from commit 16b5ad31952476fb925c401897fc171cd37f536b) Signed-off-by: Thomas Hellström --- drivers/gpu/drm/drm_pagemap.c | 17 ++++++++++---- drivers/gpu/drm/xe/xe_migrate.c | 25 ++++++++++++++++----- drivers/gpu/drm/xe/xe_migrate.h | 6 +++-- drivers/gpu/drm/xe/xe_svm.c | 49 +++++++++++++++++++++++++++++++---------- 4 files changed, 74 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index 37d7cfbbb3e8..06c1bd8fc4d1 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -3,6 +3,7 @@ * Copyright © 2024-2025 Intel Corporation */ +#include #include #include #include @@ -408,10 +409,14 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, drm_pagemap_get_devmem_page(page, zdd); } - err = ops->copy_to_devmem(pages, pagemap_addr, npages); + err = ops->copy_to_devmem(pages, pagemap_addr, npages, + devmem_allocation->pre_migrate_fence); if (err) goto err_finalize; + dma_fence_put(devmem_allocation->pre_migrate_fence); + devmem_allocation->pre_migrate_fence = NULL; + /* Upon success bind devmem allocation to range and zdd */ devmem_allocation->timeslice_expiration = get_jiffies_64() + msecs_to_jiffies(timeslice_ms); @@ -596,7 +601,7 @@ retry: for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -732,7 +737,7 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas, for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(migrate.src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -813,11 +818,14 @@ EXPORT_SYMBOL_GPL(drm_pagemap_pagemap_ops_get); * @ops: Pointer to the operations structure for GPU SVM device memory * @dpagemap: The struct drm_pagemap we're allocating from. * @size: Size of device memory allocation + * @pre_migrate_fence: Fence to wait for or pipeline behind before migration starts. + * (May be NULL). */ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, struct device *dev, struct mm_struct *mm, const struct drm_pagemap_devmem_ops *ops, - struct drm_pagemap *dpagemap, size_t size) + struct drm_pagemap *dpagemap, size_t size, + struct dma_fence *pre_migrate_fence) { init_completion(&devmem_allocation->detached); devmem_allocation->dev = dev; @@ -825,6 +833,7 @@ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, devmem_allocation->ops = ops; devmem_allocation->dpagemap = dpagemap; devmem_allocation->size = size; + devmem_allocation->pre_migrate_fence = pre_migrate_fence; } EXPORT_SYMBOL_GPL(drm_pagemap_devmem_init); diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 2184af413b91..5a95b08a4723 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -2062,6 +2062,7 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, unsigned long sram_offset, struct drm_pagemap_addr *sram_addr, u64 vram_addr, + struct dma_fence *deps, const enum xe_migrate_copy_dir dir) { struct xe_gt *gt = m->tile->primary_gt; @@ -2150,6 +2151,14 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, xe_sched_job_add_migrate_flush(job, MI_INVALIDATE_TLB); + if (deps && !dma_fence_is_signaled(deps)) { + dma_fence_get(deps); + err = drm_sched_job_add_dependency(&job->drm, deps); + if (err) + dma_fence_wait(deps, false); + err = 0; + } + mutex_lock(&m->job_mutex); xe_sched_job_arm(job); fence = dma_fence_get(&job->drm.s_fence->finished); @@ -2175,6 +2184,8 @@ err: * @npages: Number of pages to migrate. * @src_addr: Array of DMA information (source of migrate) * @dst_addr: Device physical address of VRAM (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from an array dma addresses to a VRAM device physical address * @@ -2184,10 +2195,11 @@ err: struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr) + u64 dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, src_addr, dst_addr, - XE_MIGRATE_COPY_TO_VRAM); + deps, XE_MIGRATE_COPY_TO_VRAM); } /** @@ -2196,6 +2208,8 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, * @npages: Number of pages to migrate. * @src_addr: Device physical address of VRAM (source of migrate) * @dst_addr: Array of DMA information (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from a VRAM device physical address to an array dma addresses * @@ -2205,10 +2219,11 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr) + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, dst_addr, src_addr, - XE_MIGRATE_COPY_TO_SRAM); + deps, XE_MIGRATE_COPY_TO_SRAM); } static void xe_migrate_dma_unmap(struct xe_device *xe, @@ -2384,7 +2399,7 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, __fence = xe_migrate_vram(m, current_bytes, (unsigned long)buf & ~PAGE_MASK, &pagemap_addr[current_page], - vram_addr, write ? + vram_addr, NULL, write ? XE_MIGRATE_COPY_TO_VRAM : XE_MIGRATE_COPY_TO_SRAM); if (IS_ERR(__fence)) { diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h index 260e298e5dd7..b76441f062b4 100644 --- a/drivers/gpu/drm/xe/xe_migrate.h +++ b/drivers/gpu/drm/xe/xe_migrate.h @@ -116,12 +116,14 @@ int xe_migrate_init(struct xe_migrate *m); struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr); + u64 dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr); + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_copy(struct xe_migrate *m, struct xe_bo *src_bo, diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 894e8f092e3f..f97e0af6a9b0 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -476,7 +476,8 @@ static void xe_svm_copy_us_stats_incr(struct xe_gt *gt, static int xe_svm_copy(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages, const enum xe_svm_copy_dir dir) + unsigned long npages, const enum xe_svm_copy_dir dir, + struct dma_fence *pre_migrate_fence) { struct xe_vram_region *vr = NULL; struct xe_gt *gt = NULL; @@ -565,7 +566,8 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_from_vram(vr->migrate, i - pos + incr, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%ld", @@ -574,13 +576,14 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_to_vram(vr->migrate, i - pos + incr, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -603,20 +606,22 @@ static int xe_svm_copy(struct page **pages, vram_addr, (u64)pagemap_addr[pos].addr, 1); __fence = xe_migrate_from_vram(vr->migrate, 1, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%d", (u64)pagemap_addr[pos].addr, vram_addr, 1); __fence = xe_migrate_to_vram(vr->migrate, 1, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -629,6 +634,8 @@ err_out: dma_fence_wait(fence, false); dma_fence_put(fence); } + if (pre_migrate_fence) + dma_fence_wait(pre_migrate_fence, false); /* * XXX: We can't derive the GT here (or anywhere in this functions, but @@ -645,16 +652,20 @@ err_out: static int xe_svm_copy_to_devmem(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM, + pre_migrate_fence); } static int xe_svm_copy_to_ram(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM, + pre_migrate_fence); } static struct xe_bo *to_xe_bo(struct drm_pagemap_devmem *devmem_allocation) @@ -667,6 +678,7 @@ static void xe_svm_devmem_release(struct drm_pagemap_devmem *devmem_allocation) struct xe_bo *bo = to_xe_bo(devmem_allocation); struct xe_device *xe = xe_bo_device(bo); + dma_fence_put(devmem_allocation->pre_migrate_fence); xe_bo_put_async(bo); xe_pm_runtime_put(xe); } @@ -861,6 +873,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, unsigned long timeslice_ms) { struct xe_vram_region *vr = container_of(dpagemap, typeof(*vr), dpagemap); + struct dma_fence *pre_migrate_fence = NULL; struct xe_device *xe = vr->xe; struct device *dev = xe->drm.dev; struct drm_buddy_block *block; @@ -887,8 +900,20 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, break; } + /* Ensure that any clearing or async eviction will complete before migration. */ + if (!dma_resv_test_signaled(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL)) { + err = dma_resv_get_singleton(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + &pre_migrate_fence); + if (err) + dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + false, MAX_SCHEDULE_TIMEOUT); + else if (pre_migrate_fence) + dma_fence_enable_sw_signaling(pre_migrate_fence); + } + drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm, - &dpagemap_devmem_ops, dpagemap, end - start); + &dpagemap_devmem_ops, dpagemap, end - start, + pre_migrate_fence); blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks; list_for_each_entry(block, blocks, link) -- cgit v1.2.3 From df60c332caf95d70f967aeace826e7e2f0847361 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 15 Dec 2025 20:47:28 +0530 Subject: amd-xgbe: reset retries and mode on RX adapt failures During the stress tests, early RX adaptation handshakes can fail, such as missing the RX_ADAPT ACK or not receiving a coefficient update before block lock is established. Continuing to retry RX adaptation in this state is often ineffective if the current mode selection is not viable. Resetting the RX adaptation retry counter when an RX_ADAPT request fails to receive ACK or a coefficient update prior to block lock, and clearing mode_set so the next bring-up performs a fresh mode selection rather than looping on a likely invalid configuration. Fixes: 4f3b20bfbb75 ("amd-xgbe: add support for rx-adaptation") Signed-off-by: Raju Rangoju Reviewed-by: Simon Horman Reviewed-by: Shyam Sundar S K Link: https://patch.msgid.link/20251215151728.311713-1-Raju.Rangoju@amd.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index a68757e8fd22..c63ddb12237e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1928,6 +1928,7 @@ static void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata, { if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) { pdata->rx_adapt_retries = 0; + pdata->mode_set = false; return; } @@ -1974,6 +1975,7 @@ static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata) */ netif_dbg(pdata, link, pdata->netdev, "Block_lock done"); pdata->rx_adapt_done = true; + pdata->rx_adapt_retries = 0; pdata->mode_set = false; return; } -- cgit v1.2.3 From f54151148b969fb4b62bec8093d255306d20df30 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 19 Dec 2025 16:28:12 +0100 Subject: serial: core: Fix serial device initialization During restoring sysfs fwnode information the information of_node_reused was dropped. This was previously set by device_set_of_node_from_dev(). Add it back manually Fixes: 24ec03cc5512 ("serial: core: Restore sysfs fwnode information") Cc: stable Suggested-by: Cosmin Tanislav Signed-off-by: Alexander Stein Tested-by: Michael Walle Tested-by: Marek Szyprowski Tested-by: Cosmin Tanislav Link: https://patch.msgid.link/20251219152813.1893982-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_base_bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 8e891984cdc0..1e1ad28d83fc 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -74,6 +74,7 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; + dev->of_node_reused = true; device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); -- cgit v1.2.3 From c3ca8a0aac832fe8047608bb2ae2cca314c6d717 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 17 Dec 2025 15:57:59 +0200 Subject: serial: sh-sci: Check that the DMA cookie is valid The driver updates struct sci_port::tx_cookie to zero right before the TX work is scheduled, or to -EINVAL when DMA is disabled. dma_async_is_complete(), called through dma_cookie_status() (and possibly through dmaengine_tx_status()), considers cookies valid only if they have values greater than or equal to 1. Passing zero or -EINVAL to dmaengine_tx_status() before any TX DMA transfer has started leads to an incorrect TX status being reported, as the cookie is invalid for the DMA subsystem. This may cause long wait times when the serial device is opened for configuration before any TX activity has occurred. Check that the TX cookie is valid before passing it to dmaengine_tx_status(). Fixes: 7cc0e0a43a91 ("serial: sh-sci: Check if TX data was written to device in .tx_empty()") Cc: stable Signed-off-by: Claudiu Beznea Link: https://patch.msgid.link/20251217135759.402015-1-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 53edbf1d8963..fbfe5575bd3c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1914,7 +1914,7 @@ static void sci_dma_check_tx_occurred(struct sci_port *s) struct dma_tx_state state; enum dma_status status; - if (!s->chan_tx) + if (!s->chan_tx || s->cookie_tx <= 0) return; status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); -- cgit v1.2.3 From 267ee93c417e685d9f8e079e41c70ba6ee4df5a5 Mon Sep 17 00:00:00 2001 From: "j.turek" Date: Sun, 21 Dec 2025 11:32:21 +0100 Subject: serial: xilinx_uartps: fix rs485 delay_rts_after_send RTS line control with delay should be triggered when there is no more bytes in kfifo and hardware buffer is empty. Without this patch RTS control is scheduled right after feeding hardware buffer and this is too early. RTS line may change state before hardware buffer is empty. With this patch delayed RTS state change is triggered when function cdns_uart_handle_tx is called from cdns_uart_isr on CDNS_UART_IXR_TXEMPTY exactly when hardware completed transmission Fixes: fccc9d9233f9 ("tty: serial: uartps: Add rs485 support to uartps driver") Cc: stable Link: https://patch.msgid.link/20251221103221.1971125-1-jakub.turek@elsta.tech Signed-off-by: Jakub Turek Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index c793fc74c26b..c593d20a1b5b 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -428,10 +428,17 @@ static void cdns_uart_handle_tx(void *dev_id) struct tty_port *tport = &port->state->port; unsigned int numbytes; unsigned char ch; + ktime_t rts_delay; if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); + /* Set RTS line after delay */ + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { + cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; + rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)); + hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL); + } return; } @@ -448,13 +455,6 @@ static void cdns_uart_handle_tx(void *dev_id) /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); - - if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && - (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) { - hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback); - hrtimer_start(&cdns_uart->tx_timer, - ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); - } } /** -- cgit v1.2.3 From d67396c9d697041b385d70ff2fd59cb07ae167e8 Mon Sep 17 00:00:00 2001 From: Mateusz Litwin Date: Thu, 18 Dec 2025 22:33:04 +0100 Subject: spi: cadence-quadspi: Prevent lost complete() call during indirect read A race condition exists between the read loop and IRQ `complete()` call. An interrupt could call the complete() between the inner loop and reinit_completion(), potentially losing the completion event and causing an unnecessary timeout. Moving reinit_completion() before the loop prevents this. A premature signal will only result in a spurious wakeup and another wait cycle, which is preferable to waiting for a timeout. Signed-off-by: Mateusz Litwin Link: https://patch.msgid.link/20251218-cqspi_indirect_read_improve-v2-1-396079972f2a@nokia.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index f8823e83a622..837dd646481f 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -769,6 +769,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { + ret = 0; if (use_irq && !wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) @@ -781,6 +782,14 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, if (cqspi->slow_sram) writel(0x0, reg_base + CQSPI_REG_IRQMASK); + /* + * Prevent lost interrupt and race condition by reinitializing early. + * A spurious wakeup and another wait cycle can occur here, + * which is preferable to waiting until timeout if interrupt is lost. + */ + if (use_irq) + reinit_completion(&cqspi->transfer_complete); + bytes_to_read = cqspi_get_rd_sram_level(cqspi); if (ret && bytes_to_read == 0) { @@ -813,7 +822,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, } if (use_irq && remaining > 0) { - reinit_completion(&cqspi->transfer_complete); if (cqspi->slow_sram) writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); } -- cgit v1.2.3 From 5bfbbf0a49ee4b5dcf46a3bfd4cd860d72cc887d Mon Sep 17 00:00:00 2001 From: Mateusz Litwin Date: Thu, 18 Dec 2025 22:33:05 +0100 Subject: spi: cadence-quadspi: Improve CQSPI_SLOW_SRAM quirk if flash is slow CQSPI_SLOW_SRAM quirk on the Stratix10 platform causes fewer interrupts, but also causes timeouts if a small block is used or if flash devices are slower than or equal in speed to SRAM's read operations. Adding the CQSPI_REG_IRQ_IND_COMP interrupt would resolve the problem for small reads, and removing the disabling of interrupts would resolve the issue with lost interrupts. This marginally increases IRQ count. Tests show that this will cause only a few percent more interrupts. Test: $ dd if=/dev/mtd0 of=/dev/null bs=1M count=64 Results from the Stratix10 platform with mt25qu02g flash. FIFO size in all tests: 128 Serviced interrupt call counts: Without CQSPI_SLOW_SRAM quirk: 16 668 850 With CQSPI_SLOW_SRAM quirk: 204 176 With CQSPI_SLOW_SRAM and this commit: 224 528 Signed-off-by: Mateusz Litwin Link: https://patch.msgid.link/20251218-cqspi_indirect_read_improve-v2-2-396079972f2a@nokia.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 837dd646481f..965b4cea3388 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -300,6 +300,9 @@ struct cqspi_driver_platdata { CQSPI_REG_IRQ_IND_SRAM_FULL | \ CQSPI_REG_IRQ_IND_COMP) +#define CQSPI_IRQ_MASK_RD_SLOW_SRAM (CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_IND_COMP) + #define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ CQSPI_REG_IRQ_WATERMARK | \ CQSPI_REG_IRQ_UNDERFLOW) @@ -381,7 +384,7 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) else if (!cqspi->slow_sram) irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR; else - irq_status &= CQSPI_REG_IRQ_WATERMARK | CQSPI_IRQ_MASK_WR; + irq_status &= CQSPI_IRQ_MASK_RD_SLOW_SRAM | CQSPI_IRQ_MASK_WR; if (irq_status) complete(&cqspi->transfer_complete); @@ -757,7 +760,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, */ if (use_irq && cqspi->slow_sram) - writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); + writel(CQSPI_IRQ_MASK_RD_SLOW_SRAM, reg_base + CQSPI_REG_IRQMASK); else if (use_irq) writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); else @@ -775,13 +778,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) ret = -ETIMEDOUT; - /* - * Disable all read interrupts until - * we are out of "bytes to read" - */ - if (cqspi->slow_sram) - writel(0x0, reg_base + CQSPI_REG_IRQMASK); - /* * Prevent lost interrupt and race condition by reinitializing early. * A spurious wakeup and another wait cycle can occur here, @@ -820,11 +816,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, remaining -= bytes_to_read; bytes_to_read = cqspi_get_rd_sram_level(cqspi); } - - if (use_irq && remaining > 0) { - if (cqspi->slow_sram) - writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); - } } /* Check indirect done status */ -- cgit v1.2.3 From 12cab1191d9890097171156d06bfa8d31f1e39c8 Mon Sep 17 00:00:00 2001 From: Deepakkumar Karn Date: Tue, 16 Dec 2025 20:43:05 +0530 Subject: net: usb: rtl8150: fix memory leak on usb_submit_urb() failure In async_set_registers(), when usb_submit_urb() fails, the allocated async_req structure and URB are not freed, causing a memory leak. The completion callback async_set_reg_cb() is responsible for freeing these allocations, but it is only called after the URB is successfully submitted and completes (successfully or with error). If submission fails, the callback never runs and the memory is leaked. Fix this by freeing both the URB and the request structure in the error path when usb_submit_urb() fails. Reported-by: syzbot+8dd915c7cb0490fc8c52@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=8dd915c7cb0490fc8c52 Fixes: 4d12997a9bb3 ("drivers: net: usb: rtl8150: concurrent URB bugfix") Signed-off-by: Deepakkumar Karn Link: https://patch.msgid.link/20251216151304.59865-2-dkarn@redhat.com Signed-off-by: Paolo Abeni --- drivers/net/usb/rtl8150.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 278e6cb6f4d9..e40b0669d9f4 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -211,6 +211,8 @@ static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg) if (res == -ENODEV) netif_device_detach(dev->netdev); dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res); + kfree(req); + usb_free_urb(async_urb); } return res; } -- cgit v1.2.3 From b94f11af9d9201426f4d6c8a753493fd58d6ac16 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Dec 2025 22:35:42 +0100 Subject: net: wangxun: move PHYLINK dependency The LIBWX library code is what calls into phylink, so any user of it has to select CONFIG_PHYLINK at the moment, with NGBEVF missing this: x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_nway_reset': wx_ethtool.c:(.text+0x613): undefined reference to `phylink_ethtool_nway_reset' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_get_link_ksettings': wx_ethtool.c:(.text+0x62b): undefined reference to `phylink_ethtool_ksettings_get' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_set_link_ksettings': wx_ethtool.c:(.text+0x643): undefined reference to `phylink_ethtool_ksettings_set' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_get_pauseparam': wx_ethtool.c:(.text+0x65b): undefined reference to `phylink_ethtool_get_pauseparam' x86_64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_ethtool.o: in function `wx_set_pauseparam': wx_ethtool.c:(.text+0x677): undefined reference to `phylink_ethtool_set_pauseparam' Add the 'select PHYLINK' line in the libwx option directly so this will always be enabled for all current and future wangxun drivers, and remove the now duplicate lines. Fixes: a0008a3658a3 ("net: wangxun: add ngbevf build") Signed-off-by: Arnd Bergmann Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20251216213547.115026-1-arnd@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index d138dea7d208..ec278f99d295 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -21,6 +21,7 @@ config LIBWX depends on PTP_1588_CLOCK_OPTIONAL select PAGE_POOL select DIMLIB + select PHYLINK help Common library for Wangxun(R) Ethernet drivers. @@ -29,7 +30,6 @@ config NGBE depends on PCI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports Wangxun(R) GbE PCI Express family of adapters. @@ -48,7 +48,6 @@ config TXGBE depends on PTP_1588_CLOCK_OPTIONAL select MARVELL_10G_PHY select REGMAP - select PHYLINK select HWMON if TXGBE=y select SFP select GPIOLIB @@ -71,7 +70,6 @@ config TXGBEVF depends on PCI_MSI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports virtual functions for SP1000A, WX1820AL, WX5XXX, WX5XXXAL. -- cgit v1.2.3 From 00c22b1e84288bf0e17ab1e7e59d75237cf0d0dc Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Tue, 23 Dec 2025 14:10:41 +0530 Subject: platform/x86/intel/pmt: Fix kobject memory leak on init failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When kobject_init_and_add() fails in pmt_features_discovery(), the function returns without calling kobject_put(). This violates the kobject API contract where kobject_put() must be called even on initialization failure to properly release allocated resources. Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver") Signed-off-by: Kaushlendra Kumar Link: https://patch.msgid.link/20251223084041.3832933-1-kaushlendra.kumar@intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmt/discovery.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index 32713a194a55..9c5b4d0e1fae 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -503,8 +503,10 @@ static int pmt_features_discovery(struct pmt_features_priv *priv, ret = kobject_init_and_add(&feature->kobj, ktype, &priv->dev->kobj, "%s", pmt_feature_names[feature->id]); - if (ret) + if (ret) { + kobject_put(&feature->kobj); return ret; + } kobject_uevent(&feature->kobj, KOBJ_ADD); pmt_features_add_feat(feature); -- cgit v1.2.3 From 3d70e0fb0f289b0c778041c5bb04d099e1aa7c1c Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Tue, 23 Dec 2025 18:48:55 +0530 Subject: RDMA/bnxt_re: Fix to use correct page size for PDE table In bnxt_qplib_alloc_init_hwq(), while allocating memory for PDE table driver incorrectly is using the "pg_size" value passed to the function. Fixed to use the right value 4K. Also, fixed the allocation size for PBL table. Fixes: 0c4dcd602817 ("RDMA/bnxt_re: Refactor hardware queue memory allocation") Signed-off-by: Damodharam Ammepalli Signed-off-by: Kalesh AP Link: https://patch.msgid.link/20251223131855.145955-1-kalesh-anakkur.purayil@broadcom.com Reviewed-by: Selvin Xavier Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 875d7b52c06a..d5c12a51aa43 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -237,7 +237,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, if (npbl % BIT(MAX_PDL_LVL_SHIFT)) npde++; /* Alloc PDE pages */ - sginfo.pgsize = npde * pg_size; + sginfo.pgsize = npde * ROCE_PG_SIZE_4K; sginfo.npages = 1; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], &sginfo); if (rc) @@ -245,7 +245,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, /* Alloc PBL pages */ sginfo.npages = npbl; - sginfo.pgsize = PAGE_SIZE; + sginfo.pgsize = ROCE_PG_SIZE_4K; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_1], &sginfo); if (rc) goto fail; -- cgit v1.2.3 From 6402078bd9d1ed46e79465e1faaa42e3458f8a33 Mon Sep 17 00:00:00 2001 From: Yeoreum Yun Date: Wed, 17 Dec 2025 08:51:15 +0000 Subject: smc91x: fix broken irq-context in PREEMPT_RT When smc91x.c is built with PREEMPT_RT, the following splat occurs in FVP_RevC: [ 13.055000] smc91x LNRO0003:00 eth0: link up, 10Mbps, half-duplex, lpa 0x0000 [ 13.062137] BUG: workqueue leaked atomic, lock or RCU: kworker/2:1[106] [ 13.062137] preempt=0x00000000 lock=0->0 RCU=0->1 workfn=mld_ifc_work [ 13.062266] C ** replaying previous printk message ** [ 13.062266] CPU: 2 UID: 0 PID: 106 Comm: kworker/2:1 Not tainted 6.18.0-dirty #179 PREEMPT_{RT,(full)} [ 13.062353] Hardware name: , BIOS [ 13.062382] Workqueue: mld mld_ifc_work [ 13.062469] Call trace: [ 13.062494] show_stack+0x24/0x40 (C) [ 13.062602] __dump_stack+0x28/0x48 [ 13.062710] dump_stack_lvl+0x7c/0xb0 [ 13.062818] dump_stack+0x18/0x34 [ 13.062926] process_scheduled_works+0x294/0x450 [ 13.063043] worker_thread+0x260/0x3d8 [ 13.063124] kthread+0x1c4/0x228 [ 13.063235] ret_from_fork+0x10/0x20 This happens because smc_special_trylock() disables IRQs even on PREEMPT_RT, but smc_special_unlock() does not restore IRQs on PREEMPT_RT. The reason is that smc_special_unlock() calls spin_unlock_irqrestore(), and rcu_read_unlock_bh() in __dev_queue_xmit() cannot invoke rcu_read_unlock() through __local_bh_enable_ip() when current->softirq_disable_cnt becomes zero. To address this issue, replace smc_special_trylock() with spin_trylock_irqsave(). Fixes: 342a93247e08 ("locking/spinlock: Provide RT variant header: ") Signed-off-by: Yeoreum Yun Reviewed-by: Simon Horman Link: https://patch.msgid.link/20251217085115.1730036-1-yeoreum.yun@arm.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/smsc/smc91x.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 9d1a83a5fa7e..d16c178d1034 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -516,15 +516,7 @@ static inline void smc_rcv(struct net_device *dev) * any other concurrent access and C would always interrupt B. But life * isn't that easy in a SMP world... */ -#define smc_special_trylock(lock, flags) \ -({ \ - int __ret; \ - local_irq_save(flags); \ - __ret = spin_trylock(lock); \ - if (!__ret) \ - local_irq_restore(flags); \ - __ret; \ -}) +#define smc_special_trylock(lock, flags) spin_trylock_irqsave(lock, flags) #define smc_special_lock(lock, flags) spin_lock_irqsave(lock, flags) #define smc_special_unlock(lock, flags) spin_unlock_irqrestore(lock, flags) #else -- cgit v1.2.3 From 0831269b5f71594882accfceb02638124f88955d Mon Sep 17 00:00:00 2001 From: Chen Changcheng Date: Thu, 18 Dec 2025 09:23:18 +0800 Subject: usb: usb-storage: Maintain minimal modifications to the bcdDevice range. We cannot determine which models require the NO_ATA_1X and IGNORE_RESIDUE quirks aside from the EL-R12 optical drive device. Fixes: 955a48a5353f ("usb: usb-storage: No additional quirks need to be added to the EL-R12 optical drive.") Signed-off-by: Chen Changcheng Link: https://patch.msgid.link/20251218012318.15978-1-chenchangcheng@kylinos.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_uas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index b695f5ba9a40..939a98c2d3f7 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, US_FL_NO_ATA_1X), /* Reported-by: Benjamin Tissoires */ -UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309, +UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x0309, "Initio Corporation", "INIC-3069", USB_SC_DEVICE, USB_PR_DEVICE, NULL, -- cgit v1.2.3 From 5106dbab44fba8ec6dede3f4e75d17f5aa777ec8 Mon Sep 17 00:00:00 2001 From: Hsin-Te Yuan Date: Thu, 18 Dec 2025 15:37:57 +0800 Subject: usb: typec: ucsi: Get connector status after enable notifications Originally, the notification for connector change will be enabled after the first read of the connector status. Therefore, if the event happens during this window, it will be missing and make the status unsynced. Get the connector status only after enabling the notification for connector change to ensure the status is synced. Fixes: c1b0bc2dabfa ("usb: typec: Add support for UCSI interface") Cc: stable Tested-by: Kenneth R. Crudup Reviewed-by: Heikki Krogerus Signed-off-by: Hsin-Te Yuan Link: https://patch.msgid.link/20251218-ucsi-v7-1-aea83e83fb12@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 133 +++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 7129973f19e7..b153ed5bffb1 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1624,11 +1624,71 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) return NULL; } +static void ucsi_init_port(struct ucsi *ucsi, struct ucsi_connector *con) +{ + enum usb_role u_role = USB_ROLE_NONE; + int ret; + + /* Get the status */ + ret = ucsi_get_connector_status(con, false); + if (ret) { + dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); + return; + } + + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { + case UCSI_CONSTAT_PARTNER_TYPE_UFP: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: + u_role = USB_ROLE_HOST; + fallthrough; + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: + typec_set_data_role(con->port, TYPEC_HOST); + break; + case UCSI_CONSTAT_PARTNER_TYPE_DFP: + u_role = USB_ROLE_DEVICE; + typec_set_data_role(con->port, TYPEC_DEVICE); + break; + default: + break; + } + + /* Check if there is already something connected */ + if (UCSI_CONSTAT(con, CONNECTED)) { + typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); + ucsi_register_partner(con); + ucsi_pwr_opmode_change(con); + ucsi_orientation(con); + ucsi_port_psy_changed(con); + if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) + ucsi_get_partner_identity(con); + if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) + ucsi_check_cable(con); + } + + /* Only notify USB controller if partner supports USB data */ + if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) + u_role = USB_ROLE_NONE; + + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); + if (ret) + dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", + con->num, u_role); + + if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { + ucsi_register_device_pdos(con); + ucsi_get_src_pdos(con); + ucsi_check_altmodes(con); + ucsi_check_connector_capability(con); + } +} + static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) { struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; - enum usb_role u_role = USB_ROLE_NONE; u64 command; char *name; int ret; @@ -1729,63 +1789,6 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) goto out; } - /* Get the status */ - ret = ucsi_get_connector_status(con, false); - if (ret) { - dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); - goto out; - } - - if (ucsi->ops->connector_status) - ucsi->ops->connector_status(con); - - switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { - case UCSI_CONSTAT_PARTNER_TYPE_UFP: - case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: - u_role = USB_ROLE_HOST; - fallthrough; - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: - typec_set_data_role(con->port, TYPEC_HOST); - break; - case UCSI_CONSTAT_PARTNER_TYPE_DFP: - u_role = USB_ROLE_DEVICE; - typec_set_data_role(con->port, TYPEC_DEVICE); - break; - default: - break; - } - - /* Check if there is already something connected */ - if (UCSI_CONSTAT(con, CONNECTED)) { - typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); - ucsi_register_partner(con); - ucsi_pwr_opmode_change(con); - ucsi_orientation(con); - ucsi_port_psy_changed(con); - if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) - ucsi_get_partner_identity(con); - if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) - ucsi_check_cable(con); - } - - /* Only notify USB controller if partner supports USB data */ - if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) - u_role = USB_ROLE_NONE; - - ret = usb_role_switch_set_role(con->usb_role_sw, u_role); - if (ret) { - dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", - con->num, u_role); - ret = 0; - } - - if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { - ucsi_register_device_pdos(con); - ucsi_get_src_pdos(con); - ucsi_check_altmodes(con); - ucsi_check_connector_capability(con); - } - trace_ucsi_register_port(con->num, con); out: @@ -1903,17 +1906,29 @@ static int ucsi_init(struct ucsi *ucsi) goto err_unregister; } + /* Delay other interactions with each connector until ucsi_init_port is done */ + for (i = 0; i < ucsi->cap.num_connectors; i++) + mutex_lock(&connector[i].lock); + /* Enable all supported notifications */ ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, command); - if (ret < 0) + if (ret < 0) { + for (i = 0; i < ucsi->cap.num_connectors; i++) + mutex_unlock(&connector[i].lock); goto err_unregister; + } ucsi->connector = connector; ucsi->ntfy = ntfy; + for (i = 0; i < ucsi->cap.num_connectors; i++) { + ucsi_init_port(ucsi, &connector[i]); + mutex_unlock(&connector[i].lock); + } + mutex_lock(&ucsi->ppm_lock); ret = ucsi->ops->read_cci(ucsi, &cci); mutex_unlock(&ucsi->ppm_lock); -- cgit v1.2.3 From 782be79e4551550d7a82b1957fc0f7347e6d461f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:15 +0100 Subject: usb: gadget: lpc32xx_udc: fix clock imbalance in error path A recent change fixing a device reference leak introduced a clock imbalance by reusing an error path so that the clock may be disabled before having been enabled. Note that the clock framework allows for passing in NULL clocks so there is no risk for a NULL pointer dereference. Also drop the bogus I2C client NULL check added by the offending commit as the pointer has already been verified to be non-NULL. Fixes: c84117912bdd ("USB: lpc32xx_udc: Fix error handling in probe") Cc: stable@vger.kernel.org Cc: Ma Ke Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 73c0f28a8585..a962d4294fbe 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (retval) - goto i2c_fail; + goto err_put_client; udc->board = &lpc32xx_usbddata; @@ -3040,7 +3040,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) udc->udp_irq[i] = platform_get_irq(pdev, i); if (udc->udp_irq[i] < 0) { retval = udc->udp_irq[i]; - goto i2c_fail; + goto err_put_client; } } @@ -3048,7 +3048,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (IS_ERR(udc->udp_baseaddr)) { dev_err(udc->dev, "IO map failure\n"); retval = PTR_ERR(udc->udp_baseaddr); - goto i2c_fail; + goto err_put_client; } /* Get USB device clock */ @@ -3056,14 +3056,14 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (IS_ERR(udc->usb_slv_clk)) { dev_err(udc->dev, "failed to acquire USB device clock\n"); retval = PTR_ERR(udc->usb_slv_clk); - goto i2c_fail; + goto err_put_client; } /* Enable USB device clock */ retval = clk_prepare_enable(udc->usb_slv_clk); if (retval < 0) { dev_err(udc->dev, "failed to start USB device clock\n"); - goto i2c_fail; + goto err_put_client; } /* Setup deferred workqueue data */ @@ -3165,9 +3165,10 @@ dma_alloc_fail: dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); i2c_fail: - if (udc->isp1301_i2c_client) - put_device(&udc->isp1301_i2c_client->dev); clk_disable_unprepare(udc->usb_slv_clk); +err_put_client: + put_device(&udc->isp1301_i2c_client->dev); + dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); return retval; @@ -3195,10 +3196,9 @@ static void lpc32xx_udc_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); - if (udc->isp1301_i2c_client) - put_device(&udc->isp1301_i2c_client->dev); - clk_disable_unprepare(udc->usb_slv_clk); + + put_device(&udc->isp1301_i2c_client->dev); } #ifdef CONFIG_PM -- cgit v1.2.3 From b4b64fda4d30a83a7f00e92a0c8a1d47699609f3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:16 +0100 Subject: usb: phy: isp1301: fix non-OF device reference imbalance A recent change fixing a device reference leak in a UDC driver introduced a potential use-after-free in the non-OF case as the isp1301_get_client() helper only increases the reference count for the returned I2C device in the OF case. Increment the reference count also for non-OF so that the caller can decrement it unconditionally. Note that this is inherently racy just as using the returned I2C device is since nothing is preventing the PHY driver from being unbound while in use. Fixes: c84117912bdd ("USB: lpc32xx_udc: Fix error handling in probe") Cc: stable@vger.kernel.org Cc: Ma Ke Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-isp1301.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index f9b5c411aee4..2940f0c84e1b 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -149,7 +149,12 @@ struct i2c_client *isp1301_get_client(struct device_node *node) return client; /* non-DT: only one ISP1301 chip supported */ - return isp1301_i2c_client; + if (isp1301_i2c_client) { + get_device(&isp1301_i2c_client->dev); + return isp1301_i2c_client; + } + + return NULL; } EXPORT_SYMBOL_GPL(isp1301_get_client); -- cgit v1.2.3 From b4c61e542faf8c9131d69ecfc3ad6de96d1b2ab8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:17 +0100 Subject: usb: ohci-nxp: fix device leak on probe failure Make sure to drop the reference taken when looking up the PHY I2C device during probe on probe failure (e.g. probe deferral) and on driver unbind. Fixes: 73108aa90cbf ("USB: ohci-nxp: Use isp1301 driver") Cc: stable@vger.kernel.org # 3.5 Reported-by: Ma Ke Link: https://lore.kernel.org/lkml/20251117013428.21840-1-make24@iscas.ac.cn/ Signed-off-by: Johan Hovold Acked-by: Alan Stern Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-nxp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 24d5a1dc5056..509ca7d8d513 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -223,6 +223,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) fail_resource: usb_put_hcd(hcd); fail_disable: + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; return ret; } @@ -234,6 +235,7 @@ static void ohci_hcd_nxp_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ohci_nxp_stop_hc(); usb_put_hcd(hcd); + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; } -- cgit v1.2.3 From ad6fb7367eaa87caa15e9be2129d8e8018a33cba Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:18 +0100 Subject: usb: gadget: lpc32xx_udc: clean up probe error labels Error labels should be named after what they do rather than after from where they are jumped to. Rename the probe error labels for consistency and to improve readability. Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index a962d4294fbe..83c7e243dcf9 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3084,7 +3084,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (!udc->udca_v_base) { dev_err(udc->dev, "error getting UDCA region\n"); retval = -ENOMEM; - goto i2c_fail; + goto err_disable_clk; } udc->udca_p_base = dma_handle; dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", @@ -3097,7 +3097,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (!udc->dd_cache) { dev_err(udc->dev, "error getting DD DMA region\n"); retval = -ENOMEM; - goto dma_alloc_fail; + goto err_free_dma; } /* Clear USB peripheral and initialize gadget endpoints */ @@ -3111,14 +3111,14 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "LP request irq %d failed\n", udc->udp_irq[IRQ_USB_LP]); - goto irq_req_fail; + goto err_destroy_pool; } retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, 0, "udc_hp", udc); if (retval < 0) { dev_err(udc->dev, "HP request irq %d failed\n", udc->udp_irq[IRQ_USB_HP]); - goto irq_req_fail; + goto err_destroy_pool; } retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA], @@ -3126,7 +3126,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "DEV request irq %d failed\n", udc->udp_irq[IRQ_USB_DEVDMA]); - goto irq_req_fail; + goto err_destroy_pool; } /* The transceiver interrupt is used for VBUS detection and will @@ -3137,7 +3137,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "VBUS request irq %d failed\n", udc->udp_irq[IRQ_USB_ATX]); - goto irq_req_fail; + goto err_destroy_pool; } /* Initialize wait queue */ @@ -3146,7 +3146,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) retval = usb_add_gadget_udc(dev, &udc->gadget); if (retval < 0) - goto add_gadget_fail; + goto err_destroy_pool; dev_set_drvdata(dev, udc); device_init_wakeup(dev, 1); @@ -3158,13 +3158,12 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); return 0; -add_gadget_fail: -irq_req_fail: +err_destroy_pool: dma_pool_destroy(udc->dd_cache); -dma_alloc_fail: +err_free_dma: dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); -i2c_fail: +err_disable_clk: clk_disable_unprepare(udc->usb_slv_clk); err_put_client: put_device(&udc->isp1301_i2c_client->dev); -- cgit v1.2.3 From 8ff242c04157244020888fa234a6b145415d5a65 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 18 Dec 2025 16:35:19 +0100 Subject: usb: ohci-nxp: clean up probe error labels Error labels should be named after what they do rather than after from where they are jumped to. Rename the probe error labels for consistency and to improve readability. Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251218153519.19453-6-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-nxp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 509ca7d8d513..7663f2aa35e9 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -169,13 +169,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) - goto fail_disable; + goto err_put_client; dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); if (usb_disabled()) { dev_err(&pdev->dev, "USB is disabled\n"); ret = -ENODEV; - goto fail_disable; + goto err_put_client; } /* Enable USB host clock */ @@ -183,7 +183,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) if (IS_ERR(usb_host_clk)) { dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n"); ret = PTR_ERR(usb_host_clk); - goto fail_disable; + goto err_put_client; } isp1301_configure(); @@ -192,13 +192,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) if (!hcd) { dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; - goto fail_disable; + goto err_put_client; } hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); - goto fail_resource; + goto err_put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); @@ -206,7 +206,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENXIO; - goto fail_resource; + goto err_put_hcd; } ohci_nxp_start_hc(); @@ -220,9 +220,9 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) } ohci_nxp_stop_hc(); -fail_resource: +err_put_hcd: usb_put_hcd(hcd); -fail_disable: +err_put_client: put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; return ret; -- cgit v1.2.3 From 0dc580d4a6518b539cbb2877dd9b283df14aac6f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 23 Dec 2025 15:54:06 +0100 Subject: Revert "usb: typec: ucsi: Get connector status after enable notifications" This reverts commit 5106dbab44fba8ec6dede3f4e75d17f5aa777ec8. There are reported issues in this file, so revert the commit for now so that the original offending changes can be reverted and working systems can be restored. This can come back at a later time if it is rebased yet-again (sorry.) Cc: stable Cc: Johan Hovold Link: https://lore.kernel.org/r/20251222152204.2846-1-johan@kernel.org Fixes: 5106dbab44fb ("usb: typec: ucsi: Get connector status after enable notifications") Cc: Kenneth R. Crudup Cc: Heikki Krogerus Cc: Hsin-Te Yuan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 133 +++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index b153ed5bffb1..7129973f19e7 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1624,71 +1624,11 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) return NULL; } -static void ucsi_init_port(struct ucsi *ucsi, struct ucsi_connector *con) -{ - enum usb_role u_role = USB_ROLE_NONE; - int ret; - - /* Get the status */ - ret = ucsi_get_connector_status(con, false); - if (ret) { - dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); - return; - } - - if (ucsi->ops->connector_status) - ucsi->ops->connector_status(con); - - switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { - case UCSI_CONSTAT_PARTNER_TYPE_UFP: - case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: - u_role = USB_ROLE_HOST; - fallthrough; - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: - typec_set_data_role(con->port, TYPEC_HOST); - break; - case UCSI_CONSTAT_PARTNER_TYPE_DFP: - u_role = USB_ROLE_DEVICE; - typec_set_data_role(con->port, TYPEC_DEVICE); - break; - default: - break; - } - - /* Check if there is already something connected */ - if (UCSI_CONSTAT(con, CONNECTED)) { - typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); - ucsi_register_partner(con); - ucsi_pwr_opmode_change(con); - ucsi_orientation(con); - ucsi_port_psy_changed(con); - if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) - ucsi_get_partner_identity(con); - if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) - ucsi_check_cable(con); - } - - /* Only notify USB controller if partner supports USB data */ - if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) - u_role = USB_ROLE_NONE; - - ret = usb_role_switch_set_role(con->usb_role_sw, u_role); - if (ret) - dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", - con->num, u_role); - - if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { - ucsi_register_device_pdos(con); - ucsi_get_src_pdos(con); - ucsi_check_altmodes(con); - ucsi_check_connector_capability(con); - } -} - static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) { struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; + enum usb_role u_role = USB_ROLE_NONE; u64 command; char *name; int ret; @@ -1789,6 +1729,63 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) goto out; } + /* Get the status */ + ret = ucsi_get_connector_status(con, false); + if (ret) { + dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); + goto out; + } + + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { + case UCSI_CONSTAT_PARTNER_TYPE_UFP: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: + u_role = USB_ROLE_HOST; + fallthrough; + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: + typec_set_data_role(con->port, TYPEC_HOST); + break; + case UCSI_CONSTAT_PARTNER_TYPE_DFP: + u_role = USB_ROLE_DEVICE; + typec_set_data_role(con->port, TYPEC_DEVICE); + break; + default: + break; + } + + /* Check if there is already something connected */ + if (UCSI_CONSTAT(con, CONNECTED)) { + typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); + ucsi_register_partner(con); + ucsi_pwr_opmode_change(con); + ucsi_orientation(con); + ucsi_port_psy_changed(con); + if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) + ucsi_get_partner_identity(con); + if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) + ucsi_check_cable(con); + } + + /* Only notify USB controller if partner supports USB data */ + if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) + u_role = USB_ROLE_NONE; + + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); + if (ret) { + dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", + con->num, u_role); + ret = 0; + } + + if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { + ucsi_register_device_pdos(con); + ucsi_get_src_pdos(con); + ucsi_check_altmodes(con); + ucsi_check_connector_capability(con); + } + trace_ucsi_register_port(con->num, con); out: @@ -1906,29 +1903,17 @@ static int ucsi_init(struct ucsi *ucsi) goto err_unregister; } - /* Delay other interactions with each connector until ucsi_init_port is done */ - for (i = 0; i < ucsi->cap.num_connectors; i++) - mutex_lock(&connector[i].lock); - /* Enable all supported notifications */ ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, command); - if (ret < 0) { - for (i = 0; i < ucsi->cap.num_connectors; i++) - mutex_unlock(&connector[i].lock); + if (ret < 0) goto err_unregister; - } ucsi->connector = connector; ucsi->ntfy = ntfy; - for (i = 0; i < ucsi->cap.num_connectors; i++) { - ucsi_init_port(ucsi, &connector[i]); - mutex_unlock(&connector[i].lock); - } - mutex_lock(&ucsi->ppm_lock); ret = ucsi->ops->read_cci(ucsi, &cci); mutex_unlock(&ucsi->ppm_lock); -- cgit v1.2.3 From df3e3169303f7084db3990c999701934af0c04c0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 23 Dec 2025 15:57:16 +0100 Subject: Revert "usb: typec: ucsi: Fix null pointer dereference in ucsi_sync_control_common" This reverts commit 14ad4c10d5bdd413ff9a914260e89b5f54b7a2c7. The originally offending commit will be reverted instead of this fix up at this point in time, so revert this fix. Cc: Heikki Krogerus Cc: Mario Limonciello (AMD) Cc: stable Cc: Johan Hovold Fixes: 14ad4c10d5bd ("usb: typec: ucsi: Fix null pointer dereference in ucsi_sync_control_common") Link: https://lore.kernel.org/r/20251222152204.2846-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 7129973f19e7..9b3df776137a 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -97,7 +97,7 @@ out_clear_bit: if (!ret && cci) ret = ucsi->ops->read_cci(ucsi, cci); - if (!ret && cci && ucsi->message_in_size > 0 && + if (!ret && ucsi->message_in_size > 0 && (*cci & UCSI_CCI_COMMAND_COMPLETE)) ret = ucsi->ops->read_message_in(ucsi, ucsi->message_in, ucsi->message_in_size); -- cgit v1.2.3 From 784b756dde9151b2f44da313f390f25139f1a64e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Dec 2025 16:22:01 +0100 Subject: Revert "usb: typec: ucsi: Add support for SET_PDOS command" This reverts commit 1b474ee01fbb73b1365adbf9b3067f7375e471ee. The new buffer management code that this feature relies on is broken so revert for now. The interface for writing data and support for UCSI_SET_PDOS looks like it could use some more thought as well. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Link: https://patch.msgid.link/20251222152204.2846-2-johan@kernel.org --- drivers/usb/typec/ucsi/debugfs.c | 1 - drivers/usb/typec/ucsi/ucsi.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 174f4d53b777..90d11b79d2c0 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -37,7 +37,6 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_SET_USB: case UCSI_SET_POWER_LEVEL: case UCSI_READ_POWER_LEVEL: - case UCSI_SET_PDOS: ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, val); break; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index f946b728c373..d01b796a8d23 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -137,7 +137,6 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_PD_MESSAGE 0x15 #define UCSI_GET_CAM_CS 0x18 #define UCSI_SET_SINK_PATH 0x1c -#define UCSI_SET_PDOS 0x1d #define UCSI_READ_POWER_LEVEL 0x1e #define UCSI_SET_USB 0x21 #define UCSI_GET_LPM_PPM_INFO 0x22 -- cgit v1.2.3 From 174e7d0f47e5231437bc305277fec7bf4896a8f9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Dec 2025 16:22:02 +0100 Subject: Revert "usb: typec: ucsi: Enable debugfs for message_out data structure" This reverts commit 775fae520e6ae62c393a8daf42dc534f09692f3f. The new buffer management code that this relies on is broken so revert for now. It also looks like the error handling needs some more thought as the message out size is not reset on errors. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Link: https://patch.msgid.link/20251222152204.2846-3-johan@kernel.org --- drivers/usb/typec/ucsi/debugfs.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 90d11b79d2c0..924f93027553 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -110,30 +110,6 @@ static int ucsi_vbus_volt_show(struct seq_file *m, void *v) } DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt); -static ssize_t ucsi_message_out_write(struct file *file, - const char __user *data, size_t count, loff_t *ppos) -{ - struct ucsi *ucsi = file->private_data; - int ret; - - char *buf __free(kfree) = memdup_user_nul(data, count); - if (IS_ERR(buf)) - return PTR_ERR(buf); - - ucsi->message_out_size = min(count / 2, UCSI_MAX_MESSAGE_OUT_LENGTH); - ret = hex2bin(ucsi->message_out, buf, ucsi->message_out_size); - if (ret) - return ret; - - return count; -} - -static const struct file_operations ucsi_message_out_fops = { - .open = simple_open, - .write = ucsi_message_out_write, - .llseek = generic_file_llseek, -}; - void ucsi_debugfs_register(struct ucsi *ucsi) { ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL); @@ -146,8 +122,6 @@ void ucsi_debugfs_register(struct ucsi *ucsi) debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops); debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops); debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops); - debugfs_create_file("message_out", 0200, ucsi->debugfs->dentry, ucsi, - &ucsi_message_out_fops); } void ucsi_debugfs_unregister(struct ucsi *ucsi) -- cgit v1.2.3 From 2e46b4e024ff61d4533b4f07bb3702ec7466479e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Dec 2025 16:22:03 +0100 Subject: Revert "usb: typec: ucsi: Add support for message out data structure" This reverts commit db0028637cc832add6d87564fcc2ebb12781b046. The new buffer management code that this feature relies on is broken so revert for now. As for the in buffer, nothing prevents the out message size and buffer from being modified while the message is being processed due to lack of serialisation. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Link: https://patch.msgid.link/20251222152204.2846-4-johan@kernel.org --- drivers/usb/typec/ucsi/ucsi.c | 14 -------------- drivers/usb/typec/ucsi/ucsi.h | 2 -- drivers/usb/typec/ucsi/ucsi_acpi.c | 16 ---------------- 3 files changed, 32 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 9b3df776137a..819540713150 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -67,20 +67,6 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci) reinit_completion(&ucsi->complete); - if (ucsi->message_out_size > 0) { - if (!ucsi->ops->write_message_out) { - ucsi->message_out_size = 0; - ret = -EOPNOTSUPP; - goto out_clear_bit; - } - - ret = ucsi->ops->write_message_out(ucsi, ucsi->message_out, - ucsi->message_out_size); - ucsi->message_out_size = 0; - if (ret) - goto out_clear_bit; - } - ret = ucsi->ops->async_control(ucsi, command); if (ret) goto out_clear_bit; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index d01b796a8d23..479bf1f69c72 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -69,7 +69,6 @@ struct dentry; * @read_cci: Read CCI register * @poll_cci: Read CCI register while polling with notifications disabled * @read_message_in: Read message data from UCSI - * @write_message_out: Write message data to UCSI * @sync_control: Blocking control operation * @async_control: Non-blocking control operation * @update_altmodes: Squashes duplicate DP altmodes @@ -85,7 +84,6 @@ struct ucsi_operations { int (*read_cci)(struct ucsi *ucsi, u32 *cci); int (*poll_cci)(struct ucsi *ucsi, u32 *cci); int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len); - int (*write_message_out)(struct ucsi *ucsi, void *data, size_t data_len); int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci); int (*async_control)(struct ucsi *ucsi, u64 command); bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient, diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index f9beeb835238..f1d1f6917b09 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -86,21 +86,6 @@ static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_le return 0; } -static int ucsi_acpi_write_message_out(struct ucsi *ucsi, void *data, size_t data_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - - if (!data || !data_len) - return -EINVAL; - - if (ucsi->version <= UCSI_VERSION_1_2) - memcpy(ua->base + UCSI_MESSAGE_OUT, data, data_len); - else - memcpy(ua->base + UCSIv2_MESSAGE_OUT, data, data_len); - - return 0; -} - static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); @@ -116,7 +101,6 @@ static const struct ucsi_operations ucsi_acpi_ops = { .read_cci = ucsi_acpi_read_cci, .poll_cci = ucsi_acpi_poll_cci, .read_message_in = ucsi_acpi_read_message_in, - .write_message_out = ucsi_acpi_write_message_out, .sync_control = ucsi_sync_control_common, .async_control = ucsi_acpi_async_control }; -- cgit v1.2.3 From e7a9f6600166efb889453c524eb644cb798acd22 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 22 Dec 2025 16:22:04 +0100 Subject: Revert "usb: typec: ucsi: Update UCSI structure to have message in and message out fields" This reverts commit 3e082978c33151d576694deac8abde021ea669a8. The new buffer management code has not been tested or reviewed properly and breaks boot of machines like the Lenovo ThinkPad X13s: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 CPU: 0 UID: 0 PID: 813 Comm: kworker/0:3 Not tainted 6.19.0-rc2 #26 PREEMPT Hardware name: LENOVO 21BYZ9SRUS/21BYZ9SRUS, BIOS N3HET87W (1.59 ) 12/05/2023 Workqueue: events ucsi_handle_connector_change [typec_ucsi] Call trace: ucsi_sync_control_common+0xe4/0x1ec [typec_ucsi] (P) ucsi_run_command+0xcc/0x194 [typec_ucsi] ucsi_send_command_common+0x84/0x2a0 [typec_ucsi] ucsi_get_connector_status+0x48/0x78 [typec_ucsi] ucsi_handle_connector_change+0x5c/0x4f4 [typec_ucsi] process_one_work+0x208/0x60c worker_thread+0x244/0x388 The new code completely ignores concurrency so that the message length can be updated while a transaction is ongoing. In the above case, the length ends up being modified by another thread while processing an ack so that the NULL cci pointer is dereferenced. Fixing this will require designing a proper interface for managing these transactions, something which most likely involves reverting most of the offending commit anyway. Revert the broken code to fix the regression and let Intel come up with a properly tested implementation for a later kernel. Fixes: 3e082978c331 ("usb: typec: ucsi: Update UCSI structure to have message in and message out fields") Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman Link: https://patch.msgid.link/20251222152204.2846-5-johan@kernel.org --- drivers/usb/typec/ucsi/cros_ec_ucsi.c | 5 +- drivers/usb/typec/ucsi/debugfs.c | 9 ++- drivers/usb/typec/ucsi/displayport.c | 11 +--- drivers/usb/typec/ucsi/ucsi.c | 104 +++++++++++--------------------- drivers/usb/typec/ucsi/ucsi.h | 19 ++---- drivers/usb/typec/ucsi/ucsi_acpi.c | 9 +-- drivers/usb/typec/ucsi/ucsi_ccg.c | 11 ++-- drivers/usb/typec/ucsi/ucsi_yoga_c630.c | 15 ++--- 8 files changed, 71 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi/cros_ec_ucsi.c index d753f2188e25..eed2a7d0ebc6 100644 --- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c +++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c @@ -105,12 +105,13 @@ static int cros_ucsi_async_control(struct ucsi *ucsi, u64 cmd) return 0; } -static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci) +static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci, + void *data, size_t size) { struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi); int ret; - ret = ucsi_sync_control_common(ucsi, cmd, cci); + ret = ucsi_sync_control_common(ucsi, cmd, cci, data, size); switch (ret) { case -EBUSY: /* EC may return -EBUSY if CCI.busy is set. diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 924f93027553..f3684ab787fe 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -37,8 +37,7 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_SET_USB: case UCSI_SET_POWER_LEVEL: case UCSI_READ_POWER_LEVEL: - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, val); + ret = ucsi_send_command(ucsi, val, NULL, 0); break; case UCSI_GET_CAPABILITY: case UCSI_GET_CONNECTOR_CAPABILITY: @@ -53,9 +52,9 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_GET_ATTENTION_VDO: case UCSI_GET_CAM_CS: case UCSI_GET_LPM_PPM_INFO: - ucsi->message_in_size = sizeof(ucsi->debugfs->response); - ret = ucsi_send_command(ucsi, val); - memcpy(&ucsi->debugfs->response, ucsi->message_in, sizeof(ucsi->debugfs->response)); + ret = ucsi_send_command(ucsi, val, + &ucsi->debugfs->response, + sizeof(ucsi->debugfs->response)); break; default: ret = -EOPNOTSUPP; diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index a09b4900ec76..8aae80b457d7 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -67,14 +67,11 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) } command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(dp->con->num); - ucsi->message_in_size = sizeof(cur); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &cur, sizeof(cur)); if (ret < 0) { if (ucsi->version > 0x0100) goto err_unlock; cur = 0xff; - } else { - memcpy(&cur, ucsi->message_in, ucsi->message_in_size); } if (cur != 0xff) { @@ -129,8 +126,7 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) } command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); - dp->con->ucsi->message_in_size = 0; - ret = ucsi_send_command(dp->con->ucsi, command); + ret = ucsi_send_command(dp->con->ucsi, command, NULL, 0); if (ret < 0) goto out_unlock; @@ -197,8 +193,7 @@ static int ucsi_displayport_configure(struct ucsi_dp *dp) command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); - dp->con->ucsi->message_in_size = 0; - return ucsi_send_command(dp->con->ucsi, command); + return ucsi_send_command(dp->con->ucsi, command, NULL, 0); } static int ucsi_displayport_vdm(struct typec_altmode *alt, diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 819540713150..a7b388dc7fa0 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -55,7 +55,8 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) } EXPORT_SYMBOL_GPL(ucsi_notify_common); -int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci) +int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size) { bool ack = UCSI_COMMAND(command) == UCSI_ACK_CC_CI; int ret; @@ -83,10 +84,9 @@ out_clear_bit: if (!ret && cci) ret = ucsi->ops->read_cci(ucsi, cci); - if (!ret && ucsi->message_in_size > 0 && + if (!ret && data && (*cci & UCSI_CCI_COMMAND_COMPLETE)) - ret = ucsi->ops->read_message_in(ucsi, ucsi->message_in, - ucsi->message_in_size); + ret = ucsi->ops->read_message_in(ucsi, data, size); return ret; } @@ -103,25 +103,23 @@ static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack) ctrl |= UCSI_ACK_CONNECTOR_CHANGE; } - ucsi->message_in_size = 0; - return ucsi->ops->sync_control(ucsi, ctrl, NULL); + return ucsi->ops->sync_control(ucsi, ctrl, NULL, NULL, 0); } -static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, bool conn_ack) +static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size, bool conn_ack) { int ret, err; *cci = 0; - if (ucsi->message_in_size > UCSI_MAX_DATA_LENGTH(ucsi)) + if (size > UCSI_MAX_DATA_LENGTH(ucsi)) return -EINVAL; - ret = ucsi->ops->sync_control(ucsi, command, cci); + ret = ucsi->ops->sync_control(ucsi, command, cci, data, size); - if (*cci & UCSI_CCI_BUSY) { - ucsi->message_in_size = 0; - return ucsi_run_command(ucsi, UCSI_CANCEL, cci, false) ?: -EBUSY; - } + if (*cci & UCSI_CCI_BUSY) + return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY; if (ret) return ret; @@ -153,13 +151,10 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) int ret; command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num); - ucsi->message_in_size = sizeof(error); - ret = ucsi_run_command(ucsi, command, &cci, false); + ret = ucsi_run_command(ucsi, command, &cci, &error, sizeof(error), false); if (ret < 0) return ret; - memcpy(&error, ucsi->message_in, sizeof(error)); - switch (error) { case UCSI_ERROR_INCOMPATIBLE_PARTNER: return -EOPNOTSUPP; @@ -205,7 +200,8 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) return -EIO; } -static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) +static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, + void *data, size_t size, bool conn_ack) { u8 connector_num; u32 cci; @@ -233,7 +229,7 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) mutex_lock(&ucsi->ppm_lock); - ret = ucsi_run_command(ucsi, cmd, &cci, conn_ack); + ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack); if (cci & UCSI_CCI_ERROR) ret = ucsi_read_error(ucsi, connector_num); @@ -242,9 +238,10 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) return ret; } -int ucsi_send_command(struct ucsi *ucsi, u64 command) +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *data, size_t size) { - return ucsi_send_command_common(ucsi, command, false); + return ucsi_send_command_common(ucsi, command, data, size, false); } EXPORT_SYMBOL_GPL(ucsi_send_command); @@ -322,8 +319,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con) int i; command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(cur); - ret = ucsi_send_command(con->ucsi, command); + ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur)); if (ret < 0) { if (con->ucsi->version > 0x0100) { dev_err(con->ucsi->dev, @@ -331,8 +327,6 @@ void ucsi_altmode_update_active(struct ucsi_connector *con) return; } cur = 0xff; - } else { - memcpy(&cur, con->ucsi->message_in, sizeof(cur)); } if (cur < UCSI_MAX_ALTMODES) @@ -516,8 +510,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_OFFSET(i); - ucsi->message_in_size = sizeof(alt); - len = ucsi_send_command(con->ucsi, command); + len = ucsi_send_command(con->ucsi, command, &alt, sizeof(alt)); /* * We are collecting all altmodes first and then registering. * Some type-C device will return zero length data beyond last @@ -526,8 +519,6 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) if (len < 0) return len; - memcpy(&alt, ucsi->message_in, sizeof(alt)); - /* We got all altmodes, now break out and register them */ if (!len || !alt.svid) break; @@ -595,15 +586,12 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_OFFSET(i); - con->ucsi->message_in_size = sizeof(alt); - len = ucsi_send_command(con->ucsi, command); + len = ucsi_send_command(con->ucsi, command, alt, sizeof(alt)); if (len == -EBUSY) continue; if (len <= 0) return len; - memcpy(&alt, con->ucsi->message_in, sizeof(alt)); - /* * This code is requesting one alt mode at a time, but some PPMs * may still return two. If that happens both alt modes need be @@ -671,9 +659,7 @@ static int ucsi_get_connector_status(struct ucsi_connector *con, bool conn_ack) UCSI_MAX_DATA_LENGTH(con->ucsi)); int ret; - con->ucsi->message_in_size = size; - ret = ucsi_send_command_common(con->ucsi, command, conn_ack); - memcpy(&con->status, con->ucsi->message_in, size); + ret = ucsi_send_command_common(con->ucsi, command, &con->status, size, conn_ack); return ret < 0 ? ret : 0; } @@ -696,9 +682,8 @@ static int ucsi_read_pdos(struct ucsi_connector *con, command |= UCSI_GET_PDOS_PDO_OFFSET(offset); command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1); command |= is_source(role) ? UCSI_GET_PDOS_SRC_PDOS : 0; - ucsi->message_in_size = num_pdos * sizeof(u32); - ret = ucsi_send_command(ucsi, command); - memcpy(pdos + offset, ucsi->message_in, num_pdos * sizeof(u32)); + ret = ucsi_send_command(ucsi, command, pdos + offset, + num_pdos * sizeof(u32)); if (ret < 0 && ret != -ETIMEDOUT) dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); @@ -785,9 +770,7 @@ static int ucsi_get_pd_message(struct ucsi_connector *con, u8 recipient, command |= UCSI_GET_PD_MESSAGE_BYTES(len); command |= UCSI_GET_PD_MESSAGE_TYPE(type); - con->ucsi->message_in_size = len; - ret = ucsi_send_command(con->ucsi, command); - memcpy(data + offset, con->ucsi->message_in, len); + ret = ucsi_send_command(con->ucsi, command, data + offset, len); if (ret < 0) return ret; } @@ -952,9 +935,7 @@ static int ucsi_register_cable(struct ucsi_connector *con) int ret; command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(cable_prop); - ret = ucsi_send_command(con->ucsi, command); - memcpy(&cable_prop, con->ucsi->message_in, sizeof(cable_prop)); + ret = ucsi_send_command(con->ucsi, command, &cable_prop, sizeof(cable_prop)); if (ret < 0) { dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", ret); return ret; @@ -1015,9 +996,7 @@ static int ucsi_check_connector_capability(struct ucsi_connector *con) return 0; command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(con->cap); - ret = ucsi_send_command(con->ucsi, command); - memcpy(&con->cap, con->ucsi->message_in, sizeof(con->cap)); + ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) { dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); return ret; @@ -1401,8 +1380,7 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) else if (con->ucsi->version >= UCSI_VERSION_2_0) command |= hard ? 0 : UCSI_CONNECTOR_RESET_DATA_VER_2_0; - con->ucsi->message_in_size = 0; - return ucsi_send_command(con->ucsi, command); + return ucsi_send_command(con->ucsi, command, NULL, 0); } static int ucsi_reset_ppm(struct ucsi *ucsi) @@ -1483,8 +1461,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) { int ret; - con->ucsi->message_in_size = 0; - ret = ucsi_send_command(con->ucsi, command); + ret = ucsi_send_command(con->ucsi, command, NULL, 0); if (ret == -ETIMEDOUT) { u64 c; @@ -1492,8 +1469,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) ucsi_reset_ppm(con->ucsi); c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy; - con->ucsi->message_in_size = 0; - ucsi_send_command(con->ucsi, c); + ucsi_send_command(con->ucsi, c, NULL, 0); ucsi_reset_connector(con, true); } @@ -1646,13 +1622,10 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) /* Get connector capability */ command = UCSI_GET_CONNECTOR_CAPABILITY; command |= UCSI_CONNECTOR_NUMBER(con->num); - ucsi->message_in_size = sizeof(con->cap); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) goto out_unlock; - memcpy(&con->cap, ucsi->message_in, sizeof(con->cap)); - if (UCSI_CONCAP(con, OPMODE_DRP)) cap->data = TYPEC_PORT_DRD; else if (UCSI_CONCAP(con, OPMODE_DFP)) @@ -1849,20 +1822,17 @@ static int ucsi_init(struct ucsi *ucsi) /* Enable basic notifications */ ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) goto err_reset; /* Get PPM capabilities */ command = UCSI_GET_CAPABILITY; - ucsi->message_in_size = BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &ucsi->cap, + BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE)); if (ret < 0) goto err_reset; - memcpy(&ucsi->cap, ucsi->message_in, BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE)); - if (!ucsi->cap.num_connectors) { ret = -ENODEV; goto err_reset; @@ -1892,8 +1862,7 @@ static int ucsi_init(struct ucsi *ucsi) /* Enable all supported notifications */ ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) goto err_unregister; @@ -1944,8 +1913,7 @@ static void ucsi_resume_work(struct work_struct *work) /* Restore UCSI notification enable mask after system resume */ command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) { dev_err(ucsi->dev, "failed to re-enable notifications (%d)\n", ret); return; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 479bf1f69c72..410389ef173a 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -29,10 +29,6 @@ struct dentry; #define UCSI_MESSAGE_OUT 32 #define UCSIv2_MESSAGE_OUT 272 -/* Define maximum lengths for message buffers */ -#define UCSI_MAX_MESSAGE_IN_LENGTH 256 -#define UCSI_MAX_MESSAGE_OUT_LENGTH 256 - /* UCSI versions */ #define UCSI_VERSION_1_0 0x0100 #define UCSI_VERSION_1_1 0x0110 @@ -84,7 +80,8 @@ struct ucsi_operations { int (*read_cci)(struct ucsi *ucsi, u32 *cci); int (*poll_cci)(struct ucsi *ucsi, u32 *cci); int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len); - int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci); + int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size); int (*async_control)(struct ucsi *ucsi, u64 command); bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient, struct ucsi_altmode *orig, @@ -496,12 +493,6 @@ struct ucsi { unsigned long quirks; #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ #define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ - - /* Fixed-size buffers for incoming and outgoing messages */ - u8 message_in[UCSI_MAX_MESSAGE_IN_LENGTH]; - size_t message_in_size; - u8 message_out[UCSI_MAX_MESSAGE_OUT_LENGTH]; - size_t message_out_size; }; #define UCSI_MAX_DATA_LENGTH(u) (((u)->version < UCSI_VERSION_2_0) ? 0x10 : 0xff) @@ -564,13 +555,15 @@ struct ucsi_connector { struct usb_pd_identity cable_identity; }; -int ucsi_send_command(struct ucsi *ucsi, u64 command); +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *retval, size_t size); void ucsi_altmode_update_active(struct ucsi_connector *con); int ucsi_resume(struct ucsi *ucsi); void ucsi_notify_common(struct ucsi *ucsi, u32 cci); -int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci); +int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size); #if IS_ENABLED(CONFIG_POWER_SUPPLY) int ucsi_register_port_psy(struct ucsi_connector *con); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index f1d1f6917b09..6b92f296e985 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -105,14 +105,15 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_control = ucsi_acpi_async_control }; -static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) +static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, + void *val, size_t len) { u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE | UCSI_CONSTAT_PDOS_CHANGE; struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); int ret; - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, val, len); if (ret < 0) return ret; @@ -124,8 +125,8 @@ static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS && ua->check_bogus_event) { /* Clear the bogus change */ - if (*(u16 *)ucsi->message_in == bogus_change) - *(u16 *)ucsi->message_in = 0; + if (*(u16 *)val == bogus_change) + *(u16 *)val = 0; ua->check_bogus_event = false; } diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index ead1b2a25c79..d83a0051c737 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -606,7 +606,8 @@ static int ucsi_ccg_async_control(struct ucsi *ucsi, u64 command) return ccg_write(uc, reg, (u8 *)&command, sizeof(command)); } -static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) +static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); struct ucsi_connector *con; @@ -628,16 +629,16 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) ucsi_ccg_update_set_new_cam_cmd(uc, con, &command); } - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, data, size); switch (UCSI_COMMAND(command)) { case UCSI_GET_CURRENT_CAM: if (uc->has_multiple_dp) - ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)ucsi->message_in); + ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data); break; case UCSI_GET_ALTERNATE_MODES: if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) { - struct ucsi_altmode *alt = (struct ucsi_altmode *)ucsi->message_in; + struct ucsi_altmode *alt = data; if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID) ucsi_ccg_nvidia_altmode(uc, alt, command); @@ -645,7 +646,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) break; case UCSI_GET_CAPABILITY: if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) { - struct ucsi_capability *cap = (struct ucsi_capability *)ucsi->message_in; + struct ucsi_capability *cap = data; cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS; } diff --git a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c index 299081444caa..0187c1c4b21a 100644 --- a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c +++ b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c @@ -88,7 +88,8 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command) static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, u64 command, - u32 *cci) + u32 *cci, + void *data, size_t size) { int ret; @@ -106,8 +107,8 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, }; dev_dbg(ucsi->dev, "faking DP altmode for con1\n"); - memset(ucsi->message_in, 0, ucsi->message_in_size); - memcpy(ucsi->message_in, &alt, min(sizeof(alt), ucsi->message_in_size)); + memset(data, 0, size); + memcpy(data, &alt, min(sizeof(alt), size)); *cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt)); return 0; } @@ -120,18 +121,18 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES && UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) { dev_dbg(ucsi->dev, "ignoring altmodes for con2\n"); - memset(ucsi->message_in, 0, ucsi->message_in_size); + memset(data, 0, size); *cci = UCSI_CCI_COMMAND_COMPLETE; return 0; } - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, data, size); if (ret < 0) return ret; /* UCSI_GET_CURRENT_CAM is off-by-one on all ports */ - if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && ucsi->message_in_size > 0) - ucsi->message_in[0]--; + if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && data) + ((u8 *)data)[0]--; return ret; } -- cgit v1.2.3 From dc85a46928c41423ad89869baf05a589e2975575 Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Thu, 18 Dec 2025 08:16:49 +0000 Subject: vfio/pci: Disable qword access to the PCI ROM bar Commit 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci") enables qword access to the PCI bar resources. However certain devices (e.g. Intel X710) are observed with problem upon qword accesses to the rom bar, e.g. triggering PCI aer errors. This is triggered by Qemu which caches the rom content by simply does a pread() of the remaining size until it gets the full contents. The other bars would only perform operations at the same access width as their guest drivers. Instead of trying to identify all broken devices, universally disable qword access to the rom bar i.e. going back to the old way which worked reliably for years. Reported-by: Farrah Chen Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220740 Fixes: 2b938e3db335 ("vfio/pci: Enable iowrite64 and ioread64 for vfio pci") Cc: stable@vger.kernel.org Signed-off-by: Kevin Tian Tested-by: Farrah Chen Link: https://lore.kernel.org/r/20251218081650.555015-2-kevin.tian@intel.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/nvgrace-gpu/main.c | 4 ++-- drivers/vfio/pci/vfio_pci_rdwr.c | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index 84d142a47ec6..b45a24d00387 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -561,7 +561,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, buf, offset, mem_count, - 0, 0, false); + 0, 0, false, VFIO_PCI_IO_WIDTH_8); } return ret; @@ -693,7 +693,7 @@ nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, (char __user *)buf, pos, mem_count, - 0, 0, true); + 0, 0, true, VFIO_PCI_IO_WIDTH_8); } return ret; diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 6192788c8ba3..25380b7dfe18 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -135,7 +135,8 @@ VFIO_IORDWR(64) ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, void __iomem *io, char __user *buf, loff_t off, size_t count, size_t x_start, - size_t x_end, bool iswrite) + size_t x_end, bool iswrite, + enum vfio_pci_io_width max_width) { ssize_t done = 0; int ret; @@ -150,20 +151,19 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, else fillable = 0; - if (fillable >= 8 && !(off % 8)) { + if (fillable >= 8 && !(off % 8) && max_width >= 8) { ret = vfio_pci_iordwr64(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else - if (fillable >= 4 && !(off % 4)) { + } else if (fillable >= 4 && !(off % 4) && max_width >= 4) { ret = vfio_pci_iordwr32(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else if (fillable >= 2 && !(off % 2)) { + } else if (fillable >= 2 && !(off % 2) && max_width >= 2) { ret = vfio_pci_iordwr16(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) @@ -234,6 +234,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, void __iomem *io; struct resource *res = &vdev->pdev->resource[bar]; ssize_t done; + enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8; if (pci_resource_start(pdev, bar)) end = pci_resource_len(pdev, bar); @@ -262,6 +263,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, if (!io) return -ENOMEM; x_end = end; + + /* + * Certain devices (e.g. Intel X710) don't support qword + * access to the ROM bar. Otherwise PCI AER errors might be + * triggered. + * + * Disable qword access to the ROM bar universally, which + * worked reliably for years before qword access is enabled. + */ + max_width = VFIO_PCI_IO_WIDTH_4; } else { int ret = vfio_pci_core_setup_barmap(vdev, bar); if (ret) { @@ -278,7 +289,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, } done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, - count, x_start, x_end, iswrite); + count, x_start, x_end, iswrite, max_width); if (done >= 0) *ppos += done; @@ -352,7 +363,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, * to the memory enable bit in the command register. */ done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, - 0, 0, iswrite); + 0, 0, iswrite, VFIO_PCI_IO_WIDTH_8); vga_put(vdev->pdev, rsrc); -- cgit v1.2.3 From 8bb808cea3016c11c39e6c7f40a2f772e2eed3fe Mon Sep 17 00:00:00 2001 From: Kevin Tian Date: Thu, 18 Dec 2025 08:16:50 +0000 Subject: vfio/pci: Disable qword access to the VGA region Seems no reason to allow qword access to the old VGA resource. Better restrict it to dword access as before. Suggested-by: Alex Williamson Signed-off-by: Kevin Tian Link: https://lore.kernel.org/r/20251218081650.555015-3-kevin.tian@intel.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_rdwr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 25380b7dfe18..b38627b35c35 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -363,7 +363,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, * to the memory enable bit in the command register. */ done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, - 0, 0, iswrite, VFIO_PCI_IO_WIDTH_8); + 0, 0, iswrite, VFIO_PCI_IO_WIDTH_4); vga_put(vdev->pdev, rsrc); -- cgit v1.2.3 From 1e91505038823e51b98d1a63660606307202d5b6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 18 Dec 2025 21:51:06 +0100 Subject: vfio/xe: Add default handler for .get_region_info_caps New requirement for the vfio drivers was added by the commit f97859503859 ("vfio: Require drivers to implement get_region_info") followed by commit 1b0ecb5baf4a ("vfio/pci: Convert all PCI drivers to get_region_info_caps") that was missed by the new vfio/xe driver. Add handler for .get_region_info_caps to avoid -EINVAL errors. Fixes: 2e38c50ae492 ("vfio/xe: Add device specific vfio_pci driver variant for Intel graphics") Signed-off-by: Michal Wajdeczko Reviewed-by: Marcin Bernatowicz Tested-by: Marcin Bernatowicz Link: https://lore.kernel.org/r/20251218205106.4578-1-michal.wajdeczko@intel.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/xe/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/vfio/pci/xe/main.c b/drivers/vfio/pci/xe/main.c index 0156b53c678b..719ab4660085 100644 --- a/drivers/vfio/pci/xe/main.c +++ b/drivers/vfio/pci/xe/main.c @@ -504,6 +504,7 @@ static const struct vfio_device_ops xe_vfio_pci_ops = { .open_device = xe_vfio_pci_open_device, .close_device = xe_vfio_pci_close_device, .ioctl = vfio_pci_core_ioctl, + .get_region_info_caps = vfio_pci_ioctl_get_region_info, .device_feature = vfio_pci_core_ioctl_feature, .read = vfio_pci_core_read, .write = vfio_pci_core_write, -- cgit v1.2.3 From a50d8777159ad8ec932d5bbe0fe30a3815b63cfc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:20 -0800 Subject: drm/msm/disp: mdp_format: fix all kernel-doc warnings Correct and add kernel-doc comments to eliminate all warnings: Warning: ../drivers/gpu/drm/msm/disp/mdp_format.h:27 This comment starts with '/**', but isn't a kernel-doc comment. Warning: ../drivers/gpu/drm/msm/disp/mdp_format.h:64 struct member 'bpc_a' not described in 'msm_format' Warning: ../drivers/gpu/drm/msm/disp/mdp_format.h:64 struct member 'bpc_b_cb' not described in 'msm_format' Warning: ../drivers/gpu/drm/msm/disp/mdp_format.h:64 struct member 'bpc_g_y' not described in 'msm_format' Warning: ../drivers/gpu/drm/msm/disp/mdp_format.h:64 struct member 'bpc_r_cr' not described in 'msm_format' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695650/ Link: https://lore.kernel.org/r/20251219184638.1813181-2-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/mdp_format.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/mdp_format.h b/drivers/gpu/drm/msm/disp/mdp_format.h index a00d646ff4d4..915954bf5dc7 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.h +++ b/drivers/gpu/drm/msm/disp/mdp_format.h @@ -24,7 +24,7 @@ enum msm_format_flags { #define MSM_FORMAT_FLAG_UNPACK_TIGHT BIT(MSM_FORMAT_FLAG_UNPACK_TIGHT_BIT) #define MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB BIT(MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB_BIT) -/** +/* * DPU HW,Component order color map */ enum { @@ -37,6 +37,10 @@ enum { /** * struct msm_format: defines the format configuration * @pixel_format: format fourcc + * @bpc_g_y: element bit widths: BPC for G or Y + * @bpc_b_cb: element bit widths: BPC for B or Cb + * @bpc_r_cr: element bit widths: BPC for R or Cr + * @bpc_a: element bit widths: BPC for the alpha channel * @element: element color ordering * @fetch_type: how the color components are packed in pixel format * @chroma_sample: chroma sub-samplng type -- cgit v1.2.3 From 23bee889e33d72e8d764b435adc6cc0e8a345e94 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:21 -0800 Subject: drm/msm/dp: fix all kernel-doc warnings Correct and add kernel-doc comments to eliminate all warnings: Warning: ../drivers/gpu/drm/msm/dp/dp_debug.h:31 expecting prototype for msm_dp_debug_get(). Prototype was for msm_dp_debug_init() instead Warning: ../drivers/gpu/drm/msm/dp/dp_drm.c:24 function parameter 'connector' not described in 'msm_dp_bridge_detect' Warning: ../drivers/gpu/drm/msm/dp/dp_link.h:90 expecting prototype for mdss_dp_test_bit_depth_to_bpp(). Prototype was for msm_dp_link_bit_depth_to_bpp() instead Warning: ../drivers/gpu/drm/msm/dp/dp_link.h:126 function parameter 'aux' not described in 'msm_dp_link_get' Warning: ../drivers/gpu/drm/msm/dp/dp_link.h:126 function parameter 'dev' not described in 'msm_dp_link_get' Warning: ../drivers/gpu/drm/msm/dp/dp_panel.h:70 function parameter 'bw_code' not described in 'is_link_rate_valid' Warning: ../drivers/gpu/drm/msm/dp/dp_panel.h:84 expecting prototype for msm_dp_link_is_lane_count_valid(). Prototype was for is_lane_count_valid() instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695647/ Link: https://lore.kernel.org/r/20251219184638.1813181-3-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_debug.h | 2 +- drivers/gpu/drm/msm/dp/dp_drm.c | 1 + drivers/gpu/drm/msm/dp/dp_link.h | 9 +++++---- drivers/gpu/drm/msm/dp/dp_panel.h | 8 ++++---- 4 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 6dc0ff4f0f65..a90083fec856 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -12,7 +12,7 @@ #if defined(CONFIG_DEBUG_FS) /** - * msm_dp_debug_get() - configure and get the DisplayPlot debug module data + * msm_dp_debug_init() - configure and get the DisplayPlot debug module data * * @dev: device instance of the caller * @panel: instance of panel module diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 9a461ab2f32f..fd6443d2b6ce 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -18,6 +18,7 @@ /** * msm_dp_bridge_detect - callback to determine if connector is connected * @bridge: Pointer to drm bridge structure + * @connector: Pointer to drm connector structure * Returns: Bridge's 'is connected' status */ static enum drm_connector_status diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index b1eb2de6d2a7..8460e4ad2d35 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -80,11 +80,11 @@ struct msm_dp_link { }; /** - * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * msm_dp_link_bit_depth_to_bpp() - convert test bit depth to bpp * @tbd: test bit depth * - * Returns the bits per pixel (bpp) to be used corresponding to the - * git bit depth value. This function assumes that bit depth has + * Returns: the bits per pixel (bpp) to be used corresponding to the + * bit depth value. This function assumes that bit depth has * already been validated. */ static inline u32 msm_dp_link_bit_depth_to_bpp(u32 tbd) @@ -120,7 +120,8 @@ bool msm_dp_link_send_edid_checksum(struct msm_dp_link *msm_dp_link, u8 checksum /** * msm_dp_link_get() - get the functionalities of dp test module - * + * @dev: kernel device structure + * @aux: DisplayPort AUX channel * * return: a pointer to msm_dp_link struct */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 921a296852d4..177c1328fd99 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -63,9 +63,9 @@ void msm_dp_panel_disable_vsc_sdp(struct msm_dp_panel *msm_dp_panel); /** * is_link_rate_valid() - validates the link rate - * @lane_rate: link rate requested by the sink + * @bw_code: link rate requested by the sink * - * Returns true if the requested link rate is supported. + * Returns: true if the requested link rate is supported. */ static inline bool is_link_rate_valid(u32 bw_code) { @@ -76,10 +76,10 @@ static inline bool is_link_rate_valid(u32 bw_code) } /** - * msm_dp_link_is_lane_count_valid() - validates the lane count + * is_lane_count_valid() - validates the lane count * @lane_count: lane count requested by the sink * - * Returns true if the requested lane count is supported. + * Returns: true if the requested lane count is supported. */ static inline bool is_lane_count_valid(u32 lane_count) { -- cgit v1.2.3 From ce26953807ee2a7e9f2a70eeaca249f81fd2b473 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:22 -0800 Subject: drm/msm/dpu: dpu_hw_cdm.h: fix all kernel-doc warnings Correct and add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h:91 Incorrect use of kernel-doc format: * Enable the CDM module Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h:97 Incorrect use of kernel-doc format: * Enable/disable the connection with pingpong Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695651/ Link: https://lore.kernel.org/r/20251219184638.1813181-4-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h index 6bb3476a05f8..75e6dae0fcd9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -89,13 +89,13 @@ enum dpu_hw_cdwn_op_mode_method_h_v { */ struct dpu_hw_cdm_ops { /** - * Enable the CDM module + * @enable: Enable the CDM module * @cdm Pointer to chroma down context */ int (*enable)(struct dpu_hw_cdm *cdm, struct dpu_hw_cdm_cfg *cfg); /** - * Enable/disable the connection with pingpong + * @bind_pingpong_blk: Enable/disable the connection with pingpong * @cdm Pointer to chroma down context * @pp pingpong block id. */ -- cgit v1.2.3 From 686f6aafd39f0ea075c3bc69c9991a149e82e73e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:23 -0800 Subject: drm/msm/dpu: dpu_hw_ctl.h: fix all kernel-doc warnings Correct and add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:18 cannot understand function prototype: 'enum dpu_ctl_mode_sel' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:58 struct member 'wb' not described in 'dpu_hw_intf_cfg' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:66 Incorrect use of kernel-doc format: * kickoff hw operation for Sw controlled interfaces Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:73 Incorrect use of kernel-doc format: * check if the ctl is started Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:80 Incorrect use of kernel-doc format: * kickoff prepare is in progress hw operation for sw Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:88 Incorrect use of kernel-doc format: * Clear the value of the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:96 Incorrect use of kernel-doc format: * Query the value of the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:103 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:112 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(wb_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:121 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(cwb_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:130 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(intf_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:139 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(periph_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:148 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:157 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:166 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:175 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:185 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(dsc_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:194 Incorrect use of kernel-doc format: * OR in the given flushbits to the cached pending_(cdm_)flush_mask Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:202 Incorrect use of kernel-doc format: * Write the value of the pending_flush_mask to hardware Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:208 Incorrect use of kernel-doc format: * Read the value of the flush register Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:215 Incorrect use of kernel-doc format: * Setup ctl_path interface config Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:223 Incorrect use of kernel-doc format: * reset ctl_path interface config Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:244 Incorrect use of kernel-doc format: * Set all blend stages to disabled Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:250 Incorrect use of kernel-doc format: * Configure layer mixer to pipe configuration Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:262 Incorrect use of kernel-doc format: * Set active pipes attached to this CTL Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:270 Incorrect use of kernel-doc format: * Set active layer mixers attached to this CTL Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:277 struct member 'trigger_start' not described in 'dpu_hw_ctl_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:277 struct member 'is_started' not described in 'dpu_hw_ctl_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:277 struct member 'trigger_pending' not described in 'dpu_hw_ctl_ops' [many here] Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:319 struct member 'pending_periph_flush_mask' not described in 'dpu_hw_ctl' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:319 struct member 'pending_merge_3d_flush_mask' not described in 'dpu_hw_ctl' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:319 struct member 'pending_dspp_flush_mask' not described in 'dpu_hw_ctl' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h:327 expecting prototype for dpu_hw_ctl(). Prototype was for to_dpu_hw_ctl() instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695649/ Link: https://lore.kernel.org/r/20251219184638.1813181-5-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 84 +++++++++++++++++++----------- 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 15931b22ec94..e535bf013825 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -12,9 +12,9 @@ #include "dpu_hw_sspp.h" /** - * dpu_ctl_mode_sel: Interface mode selection - * DPU_CTL_MODE_SEL_VID: Video mode interface - * DPU_CTL_MODE_SEL_CMD: Command mode interface + * enum dpu_ctl_mode_sel: Interface mode selection + * @DPU_CTL_MODE_SEL_VID: Video mode interface + * @DPU_CTL_MODE_SEL_CMD: Command mode interface */ enum dpu_ctl_mode_sel { DPU_CTL_MODE_SEL_VID = 0, @@ -37,6 +37,7 @@ struct dpu_hw_stage_cfg { * struct dpu_hw_intf_cfg :Describes how the DPU writes data to output interface * @intf : Interface id * @intf_master: Master interface id in the dual pipe topology + * @wb: Writeback mode * @mode_3d: 3d mux configuration * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid @@ -64,21 +65,21 @@ struct dpu_hw_intf_cfg { */ struct dpu_hw_ctl_ops { /** - * kickoff hw operation for Sw controlled interfaces + * @trigger_start: kickoff hw operation for Sw controlled interfaces * DSI cmd mode and WB interface are SW controlled * @ctx : ctl path ctx pointer */ void (*trigger_start)(struct dpu_hw_ctl *ctx); /** - * check if the ctl is started + * @is_started: check if the ctl is started * @ctx : ctl path ctx pointer * @Return: true if started, false if stopped */ bool (*is_started)(struct dpu_hw_ctl *ctx); /** - * kickoff prepare is in progress hw operation for sw + * @trigger_pending: kickoff prepare is in progress hw operation for sw * controlled interfaces: DSI cmd mode and WB interface * are SW controlled * @ctx : ctl path ctx pointer @@ -86,7 +87,7 @@ struct dpu_hw_ctl_ops { void (*trigger_pending)(struct dpu_hw_ctl *ctx); /** - * Clear the value of the cached pending_flush_mask + * @clear_pending_flush: Clear the value of the cached pending_flush_mask * No effect on hardware. * Required to be implemented. * @ctx : ctl path ctx pointer @@ -94,14 +95,15 @@ struct dpu_hw_ctl_ops { void (*clear_pending_flush)(struct dpu_hw_ctl *ctx); /** - * Query the value of the cached pending_flush_mask + * @get_pending_flush: Query the value of the cached pending_flush_mask * No effect on hardware * @ctx : ctl path ctx pointer */ u32 (*get_pending_flush)(struct dpu_hw_ctl *ctx); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush: OR in the given flushbits to the cached + * pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @flushbits : module flushmask @@ -110,7 +112,8 @@ struct dpu_hw_ctl_ops { u32 flushbits); /** - * OR in the given flushbits to the cached pending_(wb_)flush_mask + * @update_pending_flush_wb: OR in the given flushbits to the + * cached pending_(wb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : writeback block index @@ -119,7 +122,8 @@ struct dpu_hw_ctl_ops { enum dpu_wb blk); /** - * OR in the given flushbits to the cached pending_(cwb_)flush_mask + * @update_pending_flush_cwb: OR in the given flushbits to the + * cached pending_(cwb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : concurrent writeback block index @@ -128,7 +132,8 @@ struct dpu_hw_ctl_ops { enum dpu_cwb blk); /** - * OR in the given flushbits to the cached pending_(intf_)flush_mask + * @update_pending_flush_intf: OR in the given flushbits to the + * cached pending_(intf_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -137,7 +142,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(periph_)flush_mask + * @update_pending_flush_periph: OR in the given flushbits to the + * cached pending_(periph_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -146,7 +152,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask + * @update_pending_flush_merge_3d: OR in the given flushbits to the + * cached pending_(merge_3d_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -155,7 +162,8 @@ struct dpu_hw_ctl_ops { enum dpu_merge_3d blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_sspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : SSPP block index @@ -164,7 +172,8 @@ struct dpu_hw_ctl_ops { enum dpu_sspp blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_mixer: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : LM block index @@ -173,7 +182,8 @@ struct dpu_hw_ctl_ops { enum dpu_lm blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_dspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : DSPP block index @@ -183,7 +193,8 @@ struct dpu_hw_ctl_ops { enum dpu_dspp blk, u32 dspp_sub_blk); /** - * OR in the given flushbits to the cached pending_(dsc_)flush_mask + * @update_pending_flush_dsc: OR in the given flushbits to the + * cached pending_(dsc_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @blk: interface block index @@ -192,7 +203,8 @@ struct dpu_hw_ctl_ops { enum dpu_dsc blk); /** - * OR in the given flushbits to the cached pending_(cdm_)flush_mask + * @update_pending_flush_cdm: OR in the given flushbits to the + * cached pending_(cdm_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @cdm_num: idx of cdm to be flushed @@ -200,20 +212,20 @@ struct dpu_hw_ctl_ops { void (*update_pending_flush_cdm)(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num); /** - * Write the value of the pending_flush_mask to hardware + * @trigger_flush: Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ void (*trigger_flush)(struct dpu_hw_ctl *ctx); /** - * Read the value of the flush register + * @get_flush_register: Read the value of the flush register * @ctx : ctl path ctx pointer * @Return: value of the ctl flush register. */ u32 (*get_flush_register)(struct dpu_hw_ctl *ctx); /** - * Setup ctl_path interface config + * @setup_intf_cfg: Setup ctl_path interface config * @ctx * @cfg : interface config structure pointer */ @@ -221,17 +233,20 @@ struct dpu_hw_ctl_ops { struct dpu_hw_intf_cfg *cfg); /** - * reset ctl_path interface config + * @reset_intf_cfg: reset ctl_path interface config * @ctx : ctl path ctx pointer * @cfg : interface config structure pointer */ void (*reset_intf_cfg)(struct dpu_hw_ctl *ctx, struct dpu_hw_intf_cfg *cfg); + /** + * @reset: reset function for this ctl type + */ int (*reset)(struct dpu_hw_ctl *c); - /* - * wait_reset_status - checks ctl reset status + /** + * @wait_reset_status: checks ctl reset status * @ctx : ctl path ctx pointer * * This function checks the ctl reset status bit. @@ -242,13 +257,13 @@ struct dpu_hw_ctl_ops { int (*wait_reset_status)(struct dpu_hw_ctl *ctx); /** - * Set all blend stages to disabled + * @clear_all_blendstages: Set all blend stages to disabled * @ctx : ctl path ctx pointer */ void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : ctl path ctx pointer * @lm : layer mixer enumeration * @cfg : blend stage configuration @@ -256,11 +271,16 @@ struct dpu_hw_ctl_ops { void (*setup_blendstage)(struct dpu_hw_ctl *ctx, enum dpu_lm lm, struct dpu_hw_stage_cfg *cfg); + /** + * @set_active_fetch_pipes: Set active pipes attached to this CTL + * @ctx: ctl path ctx pointer + * @active_pipes: bitmap of enum dpu_sspp + */ void (*set_active_fetch_pipes)(struct dpu_hw_ctl *ctx, unsigned long *fetch_active); /** - * Set active pipes attached to this CTL + * @set_active_pipes: Set active pipes attached to this CTL * @ctx: ctl path ctx pointer * @active_pipes: bitmap of enum dpu_sspp */ @@ -268,13 +288,12 @@ struct dpu_hw_ctl_ops { unsigned long *active_pipes); /** - * Set active layer mixers attached to this CTL + * @set_active_lms: Set active layer mixers attached to this CTL * @ctx: ctl path ctx pointer * @active_lms: bitmap of enum dpu_lm */ void (*set_active_lms)(struct dpu_hw_ctl *ctx, unsigned long *active_lms); - }; /** @@ -289,6 +308,9 @@ struct dpu_hw_ctl_ops { * @pending_intf_flush_mask: pending INTF flush * @pending_wb_flush_mask: pending WB flush * @pending_cwb_flush_mask: pending CWB flush + * @pending_periph_flush_mask: pending PERIPH flush + * @pending_merge_3d_flush_mask: pending MERGE 3D flush + * @pending_dspp_flush_mask: pending DSPP flush * @pending_dsc_flush_mask: pending DSC flush * @pending_cdm_flush_mask: pending CDM flush * @mdss_ver: MDSS revision information @@ -320,7 +342,7 @@ struct dpu_hw_ctl { }; /** - * dpu_hw_ctl - convert base object dpu_hw_base to container + * to_dpu_hw_ctl - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ -- cgit v1.2.3 From 70e66a0c5b1bc1923d6e91c938ed2ce1f12331df Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:24 -0800 Subject: drm/msm/dpu: dpu_hw_cwb.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h:30 Cannot find identifier on line: * Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h:61 expecting prototype for dpu_hw_cwb(). Prototype was for to_dpu_hw_cwb() instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695664/ Link: https://lore.kernel.org/r/20251219184638.1813181-6-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h index 96b6edf6b2bb..ed7bfcee7f1c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h @@ -28,7 +28,6 @@ struct dpu_hw_cwb_setup_cfg { }; /** - * * struct dpu_hw_cwb_ops : Interface to the cwb hw driver functions * @config_cwb: configure CWB mux */ @@ -54,7 +53,7 @@ struct dpu_hw_cwb { }; /** - * dpu_hw_cwb - convert base object dpu_hw_base to container + * to_dpu_hw_cwb - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ -- cgit v1.2.3 From 9d22d53ecb1576f7cadec186eac8b91ccba58da8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:25 -0800 Subject: drm/msm/dpu: dpu_hw_dsc.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:23 Incorrect use of kernel-doc format: * dsc_disable - disable dsc Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:29 Incorrect use of kernel-doc format: * dsc_config - configures dsc encoder Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:41 Incorrect use of kernel-doc format: * dsc_config_thresh - programs panel thresholds Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:50 struct member 'dsc_disable' not described in 'dpu_hw_dsc_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:50 struct member 'dsc_config' not described in 'dpu_hw_dsc_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:50 struct member 'dsc_config_thresh' not described in 'dpu_hw_dsc_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h:50 struct member 'dsc_bind_pingpong_blk' not described in 'dpu_hw_dsc_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695658/ Link: https://lore.kernel.org/r/20251219184638.1813181-7-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index cc7cc6f6f7cd..39d93b9df051 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -21,13 +21,13 @@ struct dpu_hw_dsc; */ struct dpu_hw_dsc_ops { /** - * dsc_disable - disable dsc + * @dsc_disable: disable dsc * @hw_dsc: Pointer to dsc context */ void (*dsc_disable)(struct dpu_hw_dsc *hw_dsc); /** - * dsc_config - configures dsc encoder + * @dsc_config: configures dsc encoder * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters * @mode: dsc topology mode to be set @@ -39,13 +39,17 @@ struct dpu_hw_dsc_ops { u32 initial_lines); /** - * dsc_config_thresh - programs panel thresholds + * @dsc_config_thresh: programs panel thresholds * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters */ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc); + /** + * @dsc_bind_pingpong_blk: binds pixel output from a DSC block + * to a pingpong block + */ void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc, enum dpu_pingpong pp); }; -- cgit v1.2.3 From 399f4345f07a94d9b3841d4eeedb746686eb478f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:26 -0800 Subject: drm/msm/dpu: dpu_hw_dspp.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h:33 expecting prototype for struct dpu_hw_pcc. Prototype was for struct dpu_hw_pcc_cfg instead Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h:42 Incorrect use of kernel-doc format: * setup_pcc - setup dspp pcc Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h:48 struct member 'setup_pcc' not described in 'dpu_hw_dspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h:76 expecting prototype for dpu_hw_dspp(). Prototype was for to_dpu_hw_dspp() instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695652/ Link: https://lore.kernel.org/r/20251219184638.1813181-8-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index 45c26cd49fa3..722b0f482e9b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -22,7 +22,7 @@ struct dpu_hw_pcc_coeff { }; /** - * struct dpu_hw_pcc - pcc feature structure + * struct dpu_hw_pcc_cfg - pcc feature structure * @r: red coefficients. * @g: green coefficients. * @b: blue coefficients. @@ -40,7 +40,7 @@ struct dpu_hw_pcc_cfg { */ struct dpu_hw_dspp_ops { /** - * setup_pcc - setup dspp pcc + * @setup_pcc: setup_pcc - setup dspp pcc * @ctx: Pointer to dspp context * @cfg: Pointer to configuration */ @@ -69,7 +69,7 @@ struct dpu_hw_dspp { }; /** - * dpu_hw_dspp - convert base object dpu_hw_base to container + * to_dpu_hw_dspp - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ -- cgit v1.2.3 From f6d754552b55d06c2d7beb857b1afc56f9004423 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:27 -0800 Subject: drm/msm/dpu: dpu_hw_intf.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:76 duplicate section name 'Return' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:112 Incorrect use of kernel-doc format: * Disable autorefresh if enabled Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'setup_timing_gen' not described in 'dpu_hw_intf_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'setup_prg_fetch' not described in 'dpu_hw_intf_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'enable_timing' not described in 'dpu_hw_intf_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'get_status' not described in 'dpu_hw_intf_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'get_line_count' not described in 'dpu_hw_intf_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h:118 struct member 'disable_autorefresh' not described in 'dpu_hw_intf_ops' dpu_hw_intf.h:119: warning: Excess struct member 'get_vsync_info' description in 'dpu_hw_intf_ops' dpu_hw_intf.h:119: warning: Excess struct member 'setup_autorefresh' description in 'dpu_hw_intf_ops' dpu_hw_intf.h:119: warning: Excess struct member 'get_autorefresh' description in 'dpu_hw_intf_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695646/ Link: https://lore.kernel.org/r/20251219184638.1813181-9-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index f31067a9aaf1..5a19cd74fa94 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -57,11 +57,11 @@ struct dpu_hw_intf_cmd_mode_cfg { /** * struct dpu_hw_intf_ops : Interface to the interface Hw driver functions * Assumption is these functions will be called after clocks are enabled - * @ setup_timing_gen : programs the timing engine - * @ setup_prog_fetch : enables/disables the programmable fetch logic - * @ enable_timing: enable/disable timing engine - * @ get_status: returns if timing engine is enabled or not - * @ get_line_count: reads current vertical line counter + * @setup_timing_gen : programs the timing engine + * @setup_prg_fetch : enables/disables the programmable fetch logic + * @enable_timing: enable/disable timing engine + * @get_status: returns if timing engine is enabled or not + * @get_line_count: reads current vertical line counter * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface * @setup_misr: enable/disable MISR @@ -70,12 +70,9 @@ struct dpu_hw_intf_cmd_mode_cfg { * pointer and programs the tear check configuration * @disable_tearcheck: Disables tearcheck block * @connect_external_te: Read, modify, write to either set or clear listening to external TE - * Return: 1 if TE was originally connected, 0 if not, or -ERROR - * @get_vsync_info: Provides the programmed and current line_count - * @setup_autorefresh: Configure and enable the autorefresh config - * @get_autorefresh: Retrieve autorefresh config from hardware - * Return: 0 on success, -ETIMEDOUT on timeout + * Returns 1 if TE was originally connected, 0 if not, or -ERROR * @vsync_sel: Select vsync signal for tear-effect configuration + * @disable_autorefresh: Disable autorefresh if enabled * @program_intf_cmd_cfg: Program the DPU to interface datapath for command mode */ struct dpu_hw_intf_ops { @@ -109,9 +106,6 @@ struct dpu_hw_intf_ops { void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source); - /** - * Disable autorefresh if enabled - */ void (*disable_autorefresh)(struct dpu_hw_intf *intf, uint32_t encoder_id, u16 vdisplay); void (*program_intf_cmd_cfg)(struct dpu_hw_intf *intf, -- cgit v1.2.3 From 7ce9dd5eca99a236634ad2a105a5ffa2c1d8387c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:28 -0800 Subject: drm/msm/dpu: dpu_hw_lm.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:27 Cannot find identifier on line: * Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:52 Incorrect use of kernel-doc format: * Clear layer mixer to pipe configuration Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:59 Incorrect use of kernel-doc format: * Configure layer mixer to pipe configuration Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:69 Incorrect use of kernel-doc format: * setup_border_color : enable/disable border color Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:76 Incorrect use of kernel-doc format: * setup_misr: Enable/disable MISR Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:81 Incorrect use of kernel-doc format: * collect_misr: Read MISR signature Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_mixer_out' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_blend_config' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_alpha_out' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'clear_all_blendstages' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_blendstage' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_border_color' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'setup_misr' not described in 'dpu_hw_lm_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h:84 struct member 'collect_misr' not described in 'dpu_hw_lm_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695648/ Link: https://lore.kernel.org/r/20251219184638.1813181-10-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 1b9ecd082d7f..ecbb77711d83 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -25,39 +25,38 @@ struct dpu_hw_color3_cfg { }; /** - * * struct dpu_hw_lm_ops : Interface to the mixer Hw driver functions * Assumption is these functions will be called after clocks are enabled */ struct dpu_hw_lm_ops { - /* - * Sets up mixer output width and height + /** + * @setup_mixer_out: Sets up mixer output width and height * and border color if enabled */ void (*setup_mixer_out)(struct dpu_hw_mixer *ctx, struct dpu_hw_mixer_cfg *cfg); - /* - * Alpha blending configuration + /** + * @setup_blend_config: Alpha blending configuration * for the specified stage */ void (*setup_blend_config)(struct dpu_hw_mixer *ctx, uint32_t stage, uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); - /* - * Alpha color component selection from either fg or bg + /** + * @setup_alpha_out: Alpha color component selection from either fg or bg */ void (*setup_alpha_out)(struct dpu_hw_mixer *ctx, uint32_t mixer_op); /** - * Clear layer mixer to pipe configuration + * @clear_all_blendstages: Clear layer mixer to pipe configuration * @ctx : mixer ctx pointer * Returns: 0 on success or -error */ int (*clear_all_blendstages)(struct dpu_hw_mixer *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : mixer ctx pointer * @lm : layer mixer enumeration * @stage_cfg : blend stage configuration @@ -67,19 +66,19 @@ struct dpu_hw_lm_ops { struct dpu_hw_stage_cfg *stage_cfg); /** - * setup_border_color : enable/disable border color + * @setup_border_color : enable/disable border color */ void (*setup_border_color)(struct dpu_hw_mixer *ctx, struct dpu_mdss_color *color, u8 border_en); /** - * setup_misr: Enable/disable MISR + * @setup_misr: Enable/disable MISR */ void (*setup_misr)(struct dpu_hw_mixer *ctx); /** - * collect_misr: Read MISR signature + * @collect_misr: Read MISR signature */ int (*collect_misr)(struct dpu_hw_mixer *ctx, u32 *misr_value); }; -- cgit v1.2.3 From 847c12befab422db8b17f9749d711ba7e2301094 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:29 -0800 Subject: drm/msm/dpu: dpu_hw_merge3d.h: fix all kernel-doc warnings Delete one "empty" kernel-doc line to eliminate a warning: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h:14 Cannot find identifier on line: * Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695673/ Link: https://lore.kernel.org/r/20251219184638.1813181-11-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index 6833c0207523..b57f88187148 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -12,7 +12,6 @@ struct dpu_hw_merge_3d; /** - * * struct dpu_hw_merge_3d_ops : Interface to the merge_3d Hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_3d_mode : enable 3D merge -- cgit v1.2.3 From abc287a76e1c3b641dc2302b658574cf1e660732 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:30 -0800 Subject: drm/msm/dpu: dpu_hw_pingpong.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:36 Cannot find identifier on line: * Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:46 Incorrect use of kernel-doc format: * enables vysnc generation and sets up init value of Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:53 Incorrect use of kernel-doc format: * disables tear check block Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:58 Incorrect use of kernel-doc format: * read, modify, write to either set or clear listening to external TE Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:65 Incorrect use of kernel-doc format: * Obtain current vertical line counter Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:70 Incorrect use of kernel-doc format: * Disable autorefresh if enabled Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:75 Incorrect use of kernel-doc format: * Setup dither matix for pingpong block Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:80 Incorrect use of kernel-doc format: * Enable DSC Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:85 Incorrect use of kernel-doc format: * Disable DSC Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:90 Incorrect use of kernel-doc format: * Setup DSC Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:93 struct member 'connect_external_te' not described in 'dpu_hw_pingpong_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:93 struct member 'disable_autorefresh' not described in 'dpu_hw_pingpong_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:93 struct member 'enable_dsc' not described in 'dpu_hw_pingpong_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:93 struct member 'disable_dsc' not described in 'dpu_hw_pingpong_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h:93 struct member 'setup_dsc' not described in 'dpu_hw_pingpong_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695659/ Link: https://lore.kernel.org/r/20251219184638.1813181-12-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index dd99e1c21a1e..effd012d864a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -34,7 +34,6 @@ struct dpu_hw_dither_cfg { }; /** - * * struct dpu_hw_pingpong_ops : Interface to the pingpong Hw driver functions * Assumption is these functions will be called after clocks are enabled * @enable_tearcheck: program and enable tear check block @@ -44,51 +43,52 @@ struct dpu_hw_dither_cfg { */ struct dpu_hw_pingpong_ops { /** - * enables vysnc generation and sets up init value of + * @enable_tearcheck: enables vysnc generation and sets up init value of * read pointer and programs the tear check cofiguration */ int (*enable_tearcheck)(struct dpu_hw_pingpong *pp, struct dpu_hw_tear_check *cfg); /** - * disables tear check block + * @disable_tearcheck: disables tear check block */ int (*disable_tearcheck)(struct dpu_hw_pingpong *pp); /** - * read, modify, write to either set or clear listening to external TE + * @connect_external_te: read, modify, write to either set or clear + * listening to external TE * @Return: 1 if TE was originally connected, 0 if not, or -ERROR */ int (*connect_external_te)(struct dpu_hw_pingpong *pp, bool enable_external_te); /** - * Obtain current vertical line counter + * @get_line_count: Obtain current vertical line counter */ u32 (*get_line_count)(struct dpu_hw_pingpong *pp); /** - * Disable autorefresh if enabled + * @disable_autorefresh: Disable autorefresh if enabled */ void (*disable_autorefresh)(struct dpu_hw_pingpong *pp, uint32_t encoder_id, u16 vdisplay); /** - * Setup dither matix for pingpong block + * @setup_dither: Setup dither matix for pingpong block */ void (*setup_dither)(struct dpu_hw_pingpong *pp, struct dpu_hw_dither_cfg *cfg); /** - * Enable DSC + * @enable_dsc: Enable DSC */ int (*enable_dsc)(struct dpu_hw_pingpong *pp); /** - * Disable DSC + * @disable_dsc: Disable DSC */ void (*disable_dsc)(struct dpu_hw_pingpong *pp); /** - * Setup DSC + * @setup_dsc: Setup DSC */ int (*setup_dsc)(struct dpu_hw_pingpong *pp); }; -- cgit v1.2.3 From f5a7145d0fb1c0780b0601ef173426fbef8c8a1f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:31 -0800 Subject: drm/msm/dpu: dpu_hw_sspp.h: fix all kernel-doc warnings Modify non-kernel-doc comments to begin with "/*" instead of "/**". Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:17 missing initial short description on line: * Flags Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:19 expecting prototype for Flags(). Prototype was for DPU_SSPP_FLIP_LR() instead Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:26 This comment starts with '/**', but isn't a kernel-doc comment. * Component indices Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:47 cannot understand function prototype: 'enum dpu_sspp_multirect_index' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:152 struct member 'dst_rect' not described in 'dpu_sw_pipe_cfg' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:174 struct member 'multirect_index' not described in 'dpu_sw_pipe' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:174 struct member 'multirect_mode' not described in 'dpu_sw_pipe' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:183 Incorrect use of kernel-doc format: * setup_format - setup pixel format cropping rectangle, flip Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:192 Incorrect use of kernel-doc format: * setup_rects - setup pipe ROI rectangles Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:200 Incorrect use of kernel-doc format: * setup_pe - setup pipe pixel extension Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:208 Incorrect use of kernel-doc format: * setup_sourceaddress - setup pipe source addresses Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:216 Incorrect use of kernel-doc format: * setup_csc - setup color space coversion Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:223 Incorrect use of kernel-doc format: * setup_solidfill - enable/disable colorfill Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:231 Incorrect use of kernel-doc format: * setup_multirect - setup multirect configuration Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:238 Incorrect use of kernel-doc format: * setup_sharpening - setup sharpening Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:247 Incorrect use of kernel-doc format: * setup_qos_lut - setup QoS LUTs Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:255 Incorrect use of kernel-doc format: * setup_qos_ctrl - setup QoS control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:263 Incorrect use of kernel-doc format: * setup_clk_force_ctrl - setup clock force control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:271 Incorrect use of kernel-doc format: * setup_histogram - setup histograms Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:279 Incorrect use of kernel-doc format: * setup_scaler - setup scaler Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:288 Incorrect use of kernel-doc format: * setup_cdp - setup client driven prefetch Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_format' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_rects' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_pe' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_sourceaddress' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_csc' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_solidfill' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_multirect' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_sharpening' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_qos_lut' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_qos_ctrl' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_clk_force_ctrl' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_histogram' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_scaler' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:296 struct member 'setup_cdp' not described in 'dpu_hw_sspp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h:320 struct member 'mdss_ver' not described in 'dpu_hw_sspp' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695661/ Link: https://lore.kernel.org/r/20251219184638.1813181-13-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 47 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index bdac5c04bf79..3822094f85bc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -14,7 +14,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_MAX_PITCH_SIZE 0xffff -/** +/* * Flags */ #define DPU_SSPP_FLIP_LR BIT(0) @@ -23,7 +23,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_ROT_90 BIT(3) #define DPU_SSPP_SOLID_FILL BIT(4) -/** +/* * Component indices */ enum { @@ -36,9 +36,10 @@ enum { }; /** - * DPU_SSPP_RECT_SOLO - multirect disabled - * DPU_SSPP_RECT_0 - rect0 of a multirect pipe - * DPU_SSPP_RECT_1 - rect1 of a multirect pipe + * enum dpu_sspp_multirect_index - multirect mode + * @DPU_SSPP_RECT_SOLO: multirect disabled + * @DPU_SSPP_RECT_0: rect0 of a multirect pipe + * @DPU_SSPP_RECT_1: rect1 of a multirect pipe * * Note: HW supports multirect with either RECT0 or * RECT1. Considering no benefit of such configs over @@ -143,7 +144,7 @@ struct dpu_hw_pixel_ext { * struct dpu_sw_pipe_cfg : software pipe configuration * @src_rect: src ROI, caller takes into account the different operations * such as decimation, flip etc to program this field - * @dest_rect: destination ROI. + * @dst_rect: destination ROI. * @rotation: simplified drm rotation hint */ struct dpu_sw_pipe_cfg { @@ -165,8 +166,8 @@ struct dpu_hw_pipe_ts_cfg { /** * struct dpu_sw_pipe - software pipe description * @sspp: backing SSPP pipe - * @index: index of the rectangle of SSPP - * @mode: parallel or time multiplex multirect mode + * @multirect_index: index of the rectangle of SSPP + * @multirect_mode: parallel or time multiplex multirect mode */ struct dpu_sw_pipe { struct dpu_hw_sspp *sspp; @@ -181,7 +182,7 @@ struct dpu_sw_pipe { */ struct dpu_hw_sspp_ops { /** - * setup_format - setup pixel format cropping rectangle, flip + * @setup_format: setup pixel format cropping rectangle, flip * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure * @flags: Extra flags for format config @@ -190,7 +191,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *fmt, u32 flags); /** - * setup_rects - setup pipe ROI rectangles + * @setup_rects: setup pipe ROI rectangles * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure */ @@ -198,7 +199,7 @@ struct dpu_hw_sspp_ops { struct dpu_sw_pipe_cfg *cfg); /** - * setup_pe - setup pipe pixel extension + * @setup_pe: setup pipe pixel extension * @ctx: Pointer to pipe context * @pe_ext: Pointer to pixel ext settings */ @@ -206,7 +207,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_pixel_ext *pe_ext); /** - * setup_sourceaddress - setup pipe source addresses + * @setup_sourceaddress: setup pipe source addresses * @pipe: Pointer to software pipe context * @layout: format layout information for programming buffer to hardware */ @@ -214,14 +215,14 @@ struct dpu_hw_sspp_ops { struct dpu_hw_fmt_layout *layout); /** - * setup_csc - setup color space coversion + * @setup_csc: setup color space coversion * @ctx: Pointer to pipe context * @data: Pointer to config structure */ void (*setup_csc)(struct dpu_hw_sspp *ctx, const struct dpu_csc_cfg *data); /** - * setup_solidfill - enable/disable colorfill + * @setup_solidfill: enable/disable colorfill * @pipe: Pointer to software pipe context * @const_color: Fill color value * @flags: Pipe flags @@ -229,23 +230,22 @@ struct dpu_hw_sspp_ops { void (*setup_solidfill)(struct dpu_sw_pipe *pipe, u32 color); /** - * setup_multirect - setup multirect configuration + * @setup_multirect: setup multirect configuration * @pipe: Pointer to software pipe context */ void (*setup_multirect)(struct dpu_sw_pipe *pipe); /** - * setup_sharpening - setup sharpening + * @setup_sharpening: setup sharpening * @ctx: Pointer to pipe context * @cfg: Pointer to config structure */ void (*setup_sharpening)(struct dpu_hw_sspp *ctx, struct dpu_hw_sharp_cfg *cfg); - /** - * setup_qos_lut - setup QoS LUTs + * @setup_qos_lut: setup QoS LUTs * @ctx: Pointer to pipe context * @cfg: LUT configuration */ @@ -253,7 +253,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_qos_cfg *cfg); /** - * setup_qos_ctrl - setup QoS control + * @setup_qos_ctrl: setup QoS control * @ctx: Pointer to pipe context * @danger_safe_en: flags controlling enabling of danger/safe QoS/LUT */ @@ -261,7 +261,7 @@ struct dpu_hw_sspp_ops { bool danger_safe_en); /** - * setup_clk_force_ctrl - setup clock force control + * @setup_clk_force_ctrl: setup clock force control * @ctx: Pointer to pipe context * @enable: enable clock force if true */ @@ -269,7 +269,7 @@ struct dpu_hw_sspp_ops { bool enable); /** - * setup_histogram - setup histograms + * @setup_histogram: setup histograms * @ctx: Pointer to pipe context * @cfg: Pointer to histogram configuration */ @@ -277,7 +277,7 @@ struct dpu_hw_sspp_ops { void *cfg); /** - * setup_scaler - setup scaler + * @setup_scaler: setup scaler * @scaler3_cfg: Pointer to scaler configuration * @format: pixel format parameters */ @@ -286,7 +286,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *format); /** - * setup_cdp - setup client driven prefetch + * @setup_cdp: setup client driven prefetch * @pipe: Pointer to software pipe context * @fmt: format used by the sw pipe * @enable: whether the CDP should be enabled for this pipe @@ -303,6 +303,7 @@ struct dpu_hw_sspp_ops { * @ubwc: UBWC configuration data * @idx: pipe index * @cap: pointer to layer_cfg + * @mdss_ver: MDSS version info to use for feature checks * @ops: pointer to operations possible for this pipe */ struct dpu_hw_sspp { -- cgit v1.2.3 From 6e945d518a573db3e257dcdf4c61d1ed1d71c42b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:32 -0800 Subject: drm/msm/dpu: dpu_hw_top.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:93 Incorrect use of kernel-doc format: * setup_traffic_shaper() : Setup traffic shaper control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:101 Incorrect use of kernel-doc format: * setup_clk_force_ctrl - set clock force control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:111 Incorrect use of kernel-doc format: * get_danger_status - get danger status Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:119 Incorrect use of kernel-doc format: * setup_vsync_source - setup vsync source configuration details Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:127 Incorrect use of kernel-doc format: * get_safe_status - get safe status Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:135 Incorrect use of kernel-doc format: * dp_phy_intf_sel - configure intf to phy mapping Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:142 Incorrect use of kernel-doc format: * intf_audio_select - select the external interface for audio Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'setup_clk_force_ctrl' not described in 'dpu_hw_mdp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'get_danger_status' not described in 'dpu_hw_mdp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'setup_vsync_source' not described in 'dpu_hw_mdp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'get_safe_status' not described in 'dpu_hw_mdp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'dp_phy_intf_sel' not described in 'dpu_hw_mdp_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h:146 struct member 'intf_audio_select' not described in 'dpu_hw_mdp_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695669/ Link: https://lore.kernel.org/r/20251219184638.1813181-14-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index 04efdcd21ceb..80279d87c2cd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -77,12 +77,11 @@ enum dpu_dp_phy_sel { /** * struct dpu_hw_mdp_ops - interface to the MDP TOP Hw driver functions * Assumption is these functions will be called after clocks are enabled. - * @setup_split_pipe : Programs the pipe control registers - * @setup_pp_split : Programs the pp split control registers - * @setup_traffic_shaper : programs traffic shaper control */ struct dpu_hw_mdp_ops { - /** setup_split_pipe() : Registers are not double buffered, thisk + /** + * @setup_split_pipe : Programs the pipe control registers. + * Registers are not double buffered, this * function should be called before timing control enable * @mdp : mdp top context driver * @cfg : upper and lower part of pipe configuration @@ -91,7 +90,7 @@ struct dpu_hw_mdp_ops { struct split_pipe_cfg *p); /** - * setup_traffic_shaper() : Setup traffic shaper control + * @setup_traffic_shaper : programs traffic shaper control. * @mdp : mdp top context driver * @cfg : traffic shaper configuration */ @@ -99,7 +98,7 @@ struct dpu_hw_mdp_ops { struct traffic_shaper_cfg *cfg); /** - * setup_clk_force_ctrl - set clock force control + * @setup_clk_force_ctrl: set clock force control * @mdp: mdp top context driver * @clk_ctrl: clock to be controlled * @enable: force on enable @@ -109,7 +108,7 @@ struct dpu_hw_mdp_ops { enum dpu_clk_ctrl_type clk_ctrl, bool enable); /** - * get_danger_status - get danger status + * @get_danger_status: get danger status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -117,7 +116,7 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * setup_vsync_source - setup vsync source configuration details + * @setup_vsync_source: setup vsync source configuration details * @mdp: mdp top context driver * @cfg: vsync source selection configuration */ @@ -125,7 +124,7 @@ struct dpu_hw_mdp_ops { struct dpu_vsync_source_cfg *cfg); /** - * get_safe_status - get safe status + * @get_safe_status: get safe status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -133,14 +132,14 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * dp_phy_intf_sel - configure intf to phy mapping + * @dp_phy_intf_sel: configure intf to phy mapping * @mdp: mdp top context driver * @phys: list of phys the DP interfaces should be connected to. 0 disables the INTF. */ void (*dp_phy_intf_sel)(struct dpu_hw_mdp *mdp, enum dpu_dp_phy_sel phys[2]); /** - * intf_audio_select - select the external interface for audio + * @intf_audio_select: select the external interface for audio * @mdp: mdp top context driver */ void (*intf_audio_select)(struct dpu_hw_mdp *mdp); -- cgit v1.2.3 From 3091c572fefd9f09ae2c54d964e6b6b2756c1ba1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:33 -0800 Subject: drm/msm/dpu: dpu_hw_vbif.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:19 Incorrect use of kernel-doc format: * set_limit_conf - set transaction limit config Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:29 Incorrect use of kernel-doc format: * get_limit_conf - get transaction limit config Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:39 Incorrect use of kernel-doc format: * set_halt_ctrl - set halt control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:48 Incorrect use of kernel-doc format: * get_halt_ctrl - get halt control Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:57 Incorrect use of kernel-doc format: * set_qos_remap - set QoS priority remap Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:67 Incorrect use of kernel-doc format: * set_mem_type - set memory type Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:76 Incorrect use of kernel-doc format: * clear_errors - clear any vbif errors Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:88 Incorrect use of kernel-doc format: * set_write_gather_en - set write_gather enable Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'limit' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'set_limit_conf' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'get_limit_conf' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'set_halt_ctrl' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'get_halt_ctrl' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'set_qos_remap' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'set_mem_type' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 's' not described in 'dpu_hw_vbif_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h:93 struct member 'set_write_gather_en' not described in 'dpu_hw_vbif_ops' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695680/ Link: https://lore.kernel.org/r/20251219184638.1813181-15-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 285121ec804c..9ac49448e432 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -17,7 +17,7 @@ struct dpu_hw_vbif; */ struct dpu_hw_vbif_ops { /** - * set_limit_conf - set transaction limit config + * @set_limit_conf: set transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -27,7 +27,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd, u32 limit); /** - * get_limit_conf - get transaction limit config + * @get_limit_conf: get transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -37,7 +37,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd); /** - * set_halt_ctrl - set halt control + * @set_halt_ctrl: set halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @enable: halt control enable @@ -46,7 +46,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool enable); /** - * get_halt_ctrl - get halt control + * @get_halt_ctrl: get halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @return: halt control enable @@ -55,7 +55,7 @@ struct dpu_hw_vbif_ops { u32 xin_id); /** - * set_qos_remap - set QoS priority remap + * @set_qos_remap: set QoS priority remap * @vbif: vbif context driver * @xin_id: client interface identifier * @level: priority level @@ -65,7 +65,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 level, u32 remap_level); /** - * set_mem_type - set memory type + * @set_mem_type: set memory type * @vbif: vbif context driver * @xin_id: client interface identifier * @value: memory type value @@ -74,7 +74,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 value); /** - * clear_errors - clear any vbif errors + * @clear_errors: clear any vbif errors * This function clears any detected pending/source errors * on the VBIF interface, and optionally returns the detected * error mask(s). @@ -86,7 +86,7 @@ struct dpu_hw_vbif_ops { u32 *pnd_errors, u32 *src_errors); /** - * set_write_gather_en - set write_gather enable + * @set_write_gather_en: set write_gather enable * @vbif: vbif context driver * @xin_id: client interface identifier */ -- cgit v1.2.3 From a6ccad66048aeb75c4e70ad7031ff3c28e249fce Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:34 -0800 Subject: drm/msm/dpu: dpu_hw_wb.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h:24 Cannot find identifier on line: * Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h:57 struct member 'setup_roi' not described in 'dpu_hw_wb_ops' Warning: drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h:75 struct member 'caps' not described in 'dpu_hw_wb' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695672/ Link: https://lore.kernel.org/r/20251219184638.1813181-16-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index ee5e5ab786e1..cfdbb5bb2a0f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -22,11 +22,11 @@ struct dpu_hw_wb_cfg { }; /** - * * struct dpu_hw_wb_ops : Interface to the wb hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_outaddress: setup output address from the writeback job * @setup_outformat: setup output format of writeback block from writeback job + * @setup_roi: setup ROI (Region of Interest) parameters * @setup_qos_lut: setup qos LUT for writeback block based on input * @setup_cdp: setup chroma down prefetch block for writeback block * @setup_clk_force_ctrl: setup clock force control @@ -61,7 +61,7 @@ struct dpu_hw_wb_ops { * struct dpu_hw_wb : WB driver object * @hw: block hardware details * @idx: hardware index number within type - * @wb_hw_caps: hardware capabilities + * @caps: hardware capabilities * @ops: function pointers */ struct dpu_hw_wb { -- cgit v1.2.3 From 4fc510e571615a11e24c2cb20496115ce1a76ba0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:35 -0800 Subject: drm/msm: msm_fence.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/msm_fence.h:27 Incorrect use of kernel-doc format: * last_fence: Warning: drivers/gpu/drm/msm/msm_fence.h:36 Incorrect use of kernel-doc format: * completed_fence: Warning: drivers/gpu/drm/msm/msm_fence.h:44 Incorrect use of kernel-doc format: * fenceptr: Warning: drivers/gpu/drm/msm/msm_fence.h:65 Incorrect use of kernel-doc format: * next_deadline_fence: Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'dev' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'name' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'context' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'index' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'fence' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'there is no remaining pending work */ uint32_t last_fence' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'updated from the CPU after interrupt * from GPU */ uint32_t completed_fence' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'fenceptr' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'spinlock' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'next_deadline' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'next_deadline_fence' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'deadline_timer' not described in 'msm_fence_context' Warning: drivers/gpu/drm/msm/msm_fence.h:74 struct member 'deadline_work' not described in 'msm_fence_context' Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695667/ Link: https://lore.kernel.org/r/20251219184638.1813181-17-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_fence.h | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 148196375a0b..3317a485beef 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -16,34 +16,29 @@ * incrementing fence seqno at the end of each submit */ struct msm_fence_context { + /** @dev: the drm device */ struct drm_device *dev; - /** name: human readable name for fence timeline */ + /** @name: human readable name for fence timeline */ char name[32]; - /** context: see dma_fence_context_alloc() */ + /** @context: see dma_fence_context_alloc() */ unsigned context; - /** index: similar to context, but local to msm_fence_context's */ + /** @index: similar to context, but local to msm_fence_context's */ unsigned index; - /** - * last_fence: - * + * @last_fence: * Last assigned fence, incremented each time a fence is created * on this fence context. If last_fence == completed_fence, * there is no remaining pending work */ uint32_t last_fence; - /** - * completed_fence: - * + * @completed_fence: * The last completed fence, updated from the CPU after interrupt * from GPU */ uint32_t completed_fence; - /** - * fenceptr: - * + * @fenceptr: * The address that the GPU directly writes with completed fence * seqno. This can be ahead of completed_fence. We can peek at * this to see if a fence has already signaled but the CPU hasn't @@ -51,6 +46,9 @@ struct msm_fence_context { */ volatile uint32_t *fenceptr; + /** + * @spinlock: fence context spinlock + */ spinlock_t spinlock; /* @@ -59,18 +57,22 @@ struct msm_fence_context { * don't queue, so maybe that is ok */ - /** next_deadline: Time of next deadline */ + /** @next_deadline: Time of next deadline */ ktime_t next_deadline; - /** - * next_deadline_fence: - * + * @next_deadline_fence: * Fence value for next pending deadline. The deadline timer is * canceled when this fence is signaled. */ uint32_t next_deadline_fence; - + /** + * @deadline_timer: tracks nearest deadline of a fence timeline and + * expires just before it. + */ struct hrtimer deadline_timer; + /** + * @deadline_work: work to do after deadline_timer expires + */ struct kthread_work deadline_work; }; -- cgit v1.2.3 From 010c98df53ced9077eef7a2eab3f8e55d4e9675b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:36 -0800 Subject: drm/msm: msm_gem_vma.c: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: ../drivers/gpu/drm/msm/msm_gem_vma.c:96 expecting prototype for struct msm_vma_op. Prototype was for struct msm_vm_op instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695679/ Link: https://lore.kernel.org/r/20251219184638.1813181-18-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_gem_vma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 71d5238437eb..8f7c90167447 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -65,7 +65,7 @@ struct msm_vm_unmap_op { }; /** - * struct msm_vma_op - A MAP or UNMAP operation + * struct msm_vm_op - A MAP or UNMAP operation */ struct msm_vm_op { /** @op: The operation type */ @@ -798,6 +798,9 @@ static const struct drm_sched_backend_ops msm_vm_bind_ops = { * synchronous operations are supported. In a user managed VM, userspace * handles virtual address allocation, and both async and sync operations * are supported. + * + * Returns: pointer to the created &struct drm_gpuvm on success + * or an ERR_PTR(-errno) on failure. */ struct drm_gpuvm * msm_gem_vm_create(struct drm_device *drm, struct msm_mmu *mmu, const char *name, -- cgit v1.2.3 From cd5697865258d431e261c7a30bfbc43b1ff9bca4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:37 -0800 Subject: drm/msm: msm_gpu.h: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: drivers/gpu/drm/msm/msm_gpu.h:119 Incorrect use of kernel-doc format: * devfreq: devfreq instance Warning: drivers/gpu/drm/msm/msm_gpu.h:125 Incorrect use of kernel-doc format: * idle_freq: Warning: drivers/gpu/drm/msm/msm_gpu.h:136 Incorrect use of kernel-doc format: * boost_constraint: Warning: drivers/gpu/drm/msm/msm_gpu.h:144 Incorrect use of kernel-doc format: * busy_cycles: Last busy counter value, for calculating elapsed busy Warning: drivers/gpu/drm/msm/msm_gpu.h:156 Incorrect use of kernel-doc format: * idle_work: Warning: drivers/gpu/drm/msm/msm_gpu.h:163 Incorrect use of kernel-doc format: * boost_work: Warning: drivers/gpu/drm/msm/msm_gpu.h:170 struct member 'devfreq' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:170 struct member 'boost_freq' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'devfreq' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'lock' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'governor' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'we are continuing to sample busyness and * adjust frequency while the GPU is idle' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'boost_freq' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'busy_cycles' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'time' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'idle_time' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'idle_work' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'boost_work' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:172 struct member 'suspended' not described in 'msm_gpu_devfreq' Warning: drivers/gpu/drm/msm/msm_gpu.h:472 No description found for return value of 'msm_context_is_vmbind' Warning: drivers/gpu/drm/msm/msm_gpu.h:476 struct member 'ref' not described in 'msm_context' Warning: drivers/gpu/drm/msm/msm_gpu.h:476 struct member 'elapsed_ns' not described in 'msm_context' Warning: drivers/gpu/drm/msm/msm_gpu.h:492 expecting prototype for msm_context_is_vm_bind(). Prototype was for msm_context_is_vmbind() instead Warning: drivers/gpu/drm/msm/msm_gpu.h:523 No description found for return value of 'msm_gpu_convert_priority' Warning: drivers/gpu/drm/msm/msm_gpu.h:583 expecting prototype for struct msm_gpu_submitqueues. Prototype was for struct msm_gpu_submitqueue instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695671/ Link: https://lore.kernel.org/r/20251219184638.1813181-19-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_gpu.h | 68 ++++++++++++------------------------------- 1 file changed, 18 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 2894fc118485..666cf499b7ec 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -116,15 +116,12 @@ struct msm_gpu_fault_info { * struct msm_gpu_devfreq - devfreq related state */ struct msm_gpu_devfreq { - /** devfreq: devfreq instance */ + /** @devfreq: devfreq instance */ struct devfreq *devfreq; - - /** lock: lock for "suspended", "busy_cycles", and "time" */ + /** @lock: lock for "suspended", "busy_cycles", and "time" */ struct mutex lock; - /** - * idle_freq: - * + * @idle_freq: * Shadow frequency used while the GPU is idle. From the PoV of * the devfreq governor, we are continuing to sample busyness and * adjust frequency while the GPU is idle, but we use this shadow @@ -132,43 +129,34 @@ struct msm_gpu_devfreq { * it is inactive. */ unsigned long idle_freq; - /** - * boost_constraint: - * + * @boost_freq: * A PM QoS constraint to boost min freq for a period of time * until the boost expires. */ struct dev_pm_qos_request boost_freq; - /** - * busy_cycles: Last busy counter value, for calculating elapsed busy + * @busy_cycles: Last busy counter value, for calculating elapsed busy * cycles since last sampling period. */ u64 busy_cycles; - - /** time: Time of last sampling period. */ + /** @time: Time of last sampling period. */ ktime_t time; - - /** idle_time: Time of last transition to idle: */ + /** @idle_time: Time of last transition to idle. */ ktime_t idle_time; - /** - * idle_work: - * + * @idle_work: * Used to delay clamping to idle freq on active->idle transition. */ struct msm_hrtimer_work idle_work; - /** - * boost_work: - * + * @boost_work: * Used to reset the boost_constraint after the boost period has * elapsed */ struct msm_hrtimer_work boost_work; - /** suspended: tracks if we're suspended */ + /** @suspended: tracks if we're suspended */ bool suspended; }; @@ -358,57 +346,43 @@ struct msm_gpu_perfcntr { struct msm_context { /** @queuelock: synchronizes access to submitqueues list */ rwlock_t queuelock; - /** @submitqueues: list of &msm_gpu_submitqueue created by userspace */ struct list_head submitqueues; - /** * @queueid: - * * Counter incremented each time a submitqueue is created, used to * assign &msm_gpu_submitqueue.id */ int queueid; - /** * @closed: The device file associated with this context has been closed. - * * Once the device is closed, any submits that have not been written * to the ring buffer are no-op'd. */ bool closed; - /** * @userspace_managed_vm: - * * Has userspace opted-in to userspace managed VM (ie. VM_BIND) via * MSM_PARAM_EN_VM_BIND? */ bool userspace_managed_vm; - /** * @vm: - * * The per-process GPU address-space. Do not access directly, use * msm_context_vm(). */ struct drm_gpuvm *vm; - - /** @kref: the reference count */ + /** @ref: the reference count */ struct kref ref; - /** * @seqno: - * * A unique per-process sequence number. Used to detect context * switches, without relying on keeping a, potentially dangling, * pointer to the previous context. */ int seqno; - /** * @sysprof: - * * The value of MSM_PARAM_SYSPROF set by userspace. This is * intended to be used by system profiling tools like Mesa's * pps-producer (perfetto), and restricted to CAP_SYS_ADMIN. @@ -423,40 +397,32 @@ struct msm_context { * file is closed. */ int sysprof; - /** * @comm: Overridden task comm, see MSM_PARAM_COMM * * Accessed under msm_gpu::lock */ char *comm; - /** * @cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE * * Accessed under msm_gpu::lock */ char *cmdline; - /** - * @elapsed: - * + * @elapsed_ns: * The total (cumulative) elapsed time GPU was busy with rendering * from this context in ns. */ uint64_t elapsed_ns; - /** * @cycles: - * * The total (cumulative) GPU cycles elapsed attributed to this * context. */ uint64_t cycles; - /** * @entities: - * * Table of per-priority-level sched entities used by submitqueues * associated with this &drm_file. Because some userspace apps * make assumptions about rendering from multiple gl contexts @@ -466,10 +432,8 @@ struct msm_context { * level. */ struct drm_sched_entity *entities[NR_SCHED_PRIORITIES * MSM_GPU_MAX_RINGS]; - /** * @ctx_mem: - * * Total amount of memory of GEM buffers with handles attached for * this context. */ @@ -479,7 +443,7 @@ struct msm_context { struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx); /** - * msm_context_is_vm_bind() - has userspace opted in to VM_BIND? + * msm_context_is_vmbind() - has userspace opted in to VM_BIND? * * @ctx: the drm_file context * @@ -487,6 +451,8 @@ struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx * do sparse binding including having multiple, potentially partial, * mappings in the VM. Therefore certain legacy uabi (ie. GET_IOVA, * SET_IOVA) are rejected because they don't have a sensible meaning. + * + * Returns: %true if userspace is managing the VM, %false otherwise. */ static inline bool msm_context_is_vmbind(struct msm_context *ctx) @@ -518,6 +484,8 @@ msm_context_is_vmbind(struct msm_context *ctx) * This allows generations without preemption (nr_rings==1) to have some * amount of prioritization, and provides more priority levels for gens * that do have preemption. + * + * Returns: %0 on success, %-errno on error. */ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, unsigned *ring_nr, enum drm_sched_priority *sched_prio) @@ -541,7 +509,7 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, } /** - * struct msm_gpu_submitqueues - Userspace created context. + * struct msm_gpu_submitqueue - Userspace created context. * * A submitqueue is associated with a gl context or vk queue (or equiv) * in userspace. -- cgit v1.2.3 From 7c85da6f63b15b83a7d7ee2565e4020cf904f2e9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 19 Dec 2025 10:46:38 -0800 Subject: drm/msm: msm_iommu.c: fix all kernel-doc warnings Correct or add kernel-doc comments to eliminate all warnings: Warning: ../drivers/gpu/drm/msm/msm_iommu.c:381 expecting prototype for alloc_pt(). Prototype was for msm_iommu_pagetable_alloc_pt() instead Warning: ../drivers/gpu/drm/msm/msm_iommu.c:426 expecting prototype for free_pt(). Prototype was for msm_iommu_pagetable_free_pt() instead Signed-off-by: Randy Dunlap Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695675/ Link: https://lore.kernel.org/r/20251219184638.1813181-20-rdunlap@infradead.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index a188617653e8..d5dede4ff761 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -364,7 +364,7 @@ msm_iommu_pagetable_prealloc_cleanup(struct msm_mmu *mmu, struct msm_mmu_preallo } /** - * alloc_pt() - Custom page table allocator + * msm_iommu_pagetable_alloc_pt() - Custom page table allocator * @cookie: Cookie passed at page table allocation time. * @size: Size of the page table. This size should be fixed, * and determined at creation time based on the granule size. @@ -416,7 +416,7 @@ msm_iommu_pagetable_alloc_pt(void *cookie, size_t size, gfp_t gfp) /** - * free_pt() - Custom page table free function + * msm_iommu_pagetable_free_pt() - Custom page table free function * @cookie: Cookie passed at page table allocation time. * @data: Page table to free. * @size: Size of the page table. This size should be fixed, -- cgit v1.2.3 From 35ab5123bd24dcb082d8e7152536bb2bcda5e054 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 19 Dec 2025 12:39:01 +0200 Subject: Revert "drm/msm/dpu: support plane splitting in quad-pipe case" This reverts commit 5978864e34b66bdae4d7613834c03dd5d0a0c891. At least on Hamoa based devices, there are IOMMU faults: arm-smmu 15000000.iommu: Unhandled context fault: fsr=0x402, iova=0x00000000, fsynr=0x3d0023, cbfrsynra=0x1c00, cb=13 arm-smmu 15000000.iommu: FSR = 00000402 [Format=2 TF], SID=0x1c00 arm-smmu 15000000.iommu: FSYNR0 = 003d0023 [S1CBNDX=61 PNU PLVL=3] While on some of these devices, there are also all sorts of artifacts on eDP. Reverting this fixes these issues. Closes: https://lore.kernel.org/r/z75wnahrp7lrl5yhfdysr3np3qrs6xti2i4otkng4ex3blfgrx@xyiucge3xykb/ Signed-off-by: Abel Vesa Reviewed-by: Marijn Suijten Fixes: 5978864e34b6 ("drm/msm/dpu: support plane splitting in quad-pipe case") Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695549/ Link: https://lore.kernel.org/r/20251219-drm-msm-dpu-revert-quad-pipe-broken-v1-1-654b46505f84@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 11 --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 - drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 137 +++++++++--------------------- 3 files changed, 40 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index c39f1908ea65..011946bbf5a2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1620,17 +1620,6 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } -/** - * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline - * @state: Pointer to drm crtc state object - */ -unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) -{ - struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); - - return cstate->num_mixers; -} - #ifdef CONFIG_DEBUG_FS static int _dpu_debugfs_status_show(struct seq_file *s, void *data) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 455073c7025b..2c83f1578fc3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -267,6 +267,4 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); -unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); - #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index d07a6ab6e7ee..9b7a8b46bfa9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -826,12 +826,8 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_sw_pipe_cfg *pipe_cfg; struct dpu_sw_pipe_cfg *r_pipe_cfg; - struct dpu_sw_pipe_cfg init_pipe_cfg; struct drm_rect fb_rect = { 0 }; - const struct drm_display_mode *mode = &crtc_state->adjusted_mode; uint32_t max_linewidth; - u32 num_lm; - int stage_id, num_stages; min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); max_scale = MAX_DOWNSCALE_RATIO << 16; @@ -854,10 +850,13 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } - num_lm = dpu_crtc_get_num_lm(crtc_state); - + /* move the assignment here, to ease handling to another pairs later */ + pipe_cfg = &pstate->pipe_cfg[0]; + r_pipe_cfg = &pstate->pipe_cfg[1]; /* state->src is 16.16, src_rect is not */ - drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src); + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + + pipe_cfg->dst_rect = new_plane_state->dst; fb_rect.x2 = new_plane_state->fb->width; fb_rect.y2 = new_plane_state->fb->height; @@ -882,94 +881,35 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - drm_rect_rotate(&init_pipe_cfg.src_rect, + drm_rect_rotate(&pipe_cfg->src_rect, new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - /* - * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair - * configs for left and right half screen in case of 4:4:2 topology. - * But we may have 2 rect to split wide plane that exceeds limit with 1 - * config for 2:2:1. So need to handle both wide plane splitting, and - * two halves of screen splitting for quad-pipe case. Check dest - * rectangle left/right clipping first, then check wide rectangle - * splitting in every half next. - */ - num_stages = (num_lm + 1) / 2; - /* iterate mixer configs for this plane, to separate left/right with the id */ - for (stage_id = 0; stage_id < num_stages; stage_id++) { - struct drm_rect mixer_rect = { - .x1 = stage_id * mode->hdisplay / num_stages, - .y1 = 0, - .x2 = (stage_id + 1) * mode->hdisplay / num_stages, - .y2 = mode->vdisplay - }; - int cfg_idx = stage_id * PIPES_PER_STAGE; - - pipe_cfg = &pstate->pipe_cfg[cfg_idx]; - r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; - - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); - pipe_cfg->dst_rect = new_plane_state->dst; - - DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT - " vs clip window " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), - DRM_RECT_ARG(&mixer_rect)); - - /* - * If this plane does not fall into mixer rect, check next - * mixer rect. - */ - if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, - &pipe_cfg->dst_rect, - &mixer_rect)) { - memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); - - continue; + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; } - pipe_cfg->dst_rect.x1 -= mixer_rect.x1; - pipe_cfg->dst_rect.x2 -= mixer_rect.x1; - - DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); - - /* Split wide rect into 2 rect */ - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || - _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { - - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; - } - - memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg)); - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; - DPU_DEBUG_PLANE(pdpu, "Split wide plane into:" - DRM_RECT_FMT " and " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), - DRM_RECT_ARG(&r_pipe_cfg->src_rect)); - } else { - memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); - } + *r_pipe_cfg = *pipe_cfg; + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + } else { + memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); + } - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, - new_plane_state->fb->height, + drm_rect_rotate_inv(&pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, - new_plane_state->fb->width, - new_plane_state->fb->height, - new_plane_state->rotation); - } - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); return 0; @@ -1045,17 +985,20 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, drm_atomic_get_new_plane_state(state, plane); struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe; - struct dpu_sw_pipe_cfg *pipe_cfg; - int ret = 0, i; + struct dpu_sw_pipe *pipe = &pstate->pipe[0]; + struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; + struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; + int ret = 0; - for (i = 0; i < PIPES_PER_PLANE; i++) { - pipe = &pstate->pipe[i]; - pipe_cfg = &pstate->pipe_cfg[i]; - if (!drm_rect_width(&pipe_cfg->src_rect)) - continue; - DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, + &crtc_state->adjusted_mode, + new_plane_state); + if (ret) + return ret; + + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { + ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) -- cgit v1.2.3 From da9168d8ef1cbc5dcd1cee91416bd7b408ca8377 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 19 Dec 2025 12:39:02 +0200 Subject: Revert "drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case" This reverts commit d7ec9366b15cd04508fa015cb94d546b1c01edfb. The dual-DSI dual-DSC scenario seems to be broken by this commit. Reported-by: Marijn Suijten Closes: https://lore.kernel.org/r/aUR2b3FOSisTfDFj@SoMainline.org Signed-off-by: Abel Vesa Fixes: d7ec9366b15c ("drm/msm/dpu: Enable quad-pipe for DSC and dual-DSI case") Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/695550/ Link: https://lore.kernel.org/r/20251219-drm-msm-dpu-revert-quad-pipe-broken-v1-2-654b46505f84@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 27 ++++++---------------- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 6 ++--- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 ++++++++++++++++-------- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 2 +- 6 files changed, 33 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 011946bbf5a2..2d06c950e814 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -200,7 +200,7 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, struct dpu_crtc_state *crtc_state) { struct dpu_crtc_mixer *m; - u32 crcs[CRTC_QUAD_MIXERS]; + u32 crcs[CRTC_DUAL_MIXERS]; int rc = 0; int i; @@ -1328,7 +1328,6 @@ static struct msm_display_topology dpu_crtc_get_topology( struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct msm_display_topology topology = {0}; struct drm_encoder *drm_enc; - u32 num_rt_intf; drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state, @@ -1342,14 +1341,11 @@ static struct msm_display_topology dpu_crtc_get_topology( * Dual display * 2 LM, 2 INTF ( Split display using 2 interfaces) * - * If DSC is enabled, try to use 4:4:2 topology if there is enough - * resource. Otherwise, use 2:2:2 topology. - * * Single display * 1 LM, 1 INTF * 2 LM, 1 INTF (stream merge to support high resolution interfaces) * - * If DSC is enabled, use 2:2:1 topology + * If DSC is enabled, use 2 LMs for 2:2:1 topology * * Add dspps to the reservation requirements if ctm is requested * @@ -1361,23 +1357,14 @@ static struct msm_display_topology dpu_crtc_get_topology( * (mode->hdisplay > MAX_HDISPLAY_SPLIT) check. */ - num_rt_intf = topology.num_intf; - if (topology.cwb_enabled) - num_rt_intf--; - - if (topology.num_dsc) { - if (dpu_kms->catalog->dsc_count >= num_rt_intf * 2) - topology.num_dsc = num_rt_intf * 2; - else - topology.num_dsc = num_rt_intf; - topology.num_lm = topology.num_dsc; - } else if (num_rt_intf == 2) { + if (topology.num_intf == 2 && !topology.cwb_enabled) + topology.num_lm = 2; + else if (topology.num_dsc == 2) topology.num_lm = 2; - } else if (dpu_kms->catalog->caps->has_3d_merge) { + else if (dpu_kms->catalog->caps->has_3d_merge) topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; - } else { + else topology.num_lm = 1; - } if (crtc_state->ctm) topology.num_dspp = topology.num_lm; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 2c83f1578fc3..94392b9b9245 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -210,7 +210,7 @@ struct dpu_crtc_state { bool bw_control; bool bw_split_vote; - struct drm_rect lm_bounds[CRTC_QUAD_MIXERS]; + struct drm_rect lm_bounds[CRTC_DUAL_MIXERS]; uint64_t input_fence_timeout_ns; @@ -218,10 +218,10 @@ struct dpu_crtc_state { /* HW Resources reserved for the crtc */ u32 num_mixers; - struct dpu_crtc_mixer mixers[CRTC_QUAD_MIXERS]; + struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS]; u32 num_ctls; - struct dpu_hw_ctl *hw_ctls[CRTC_QUAD_MIXERS]; + struct dpu_hw_ctl *hw_ctls[CRTC_DUAL_MIXERS]; enum dpu_crtc_crc_source crc_source; int crc_frame_skip_count; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index d1cfe81a3373..9f3957f24c6a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -55,7 +55,7 @@ #define MAX_PHYS_ENCODERS_PER_VIRTUAL \ (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) -#define MAX_CHANNELS_PER_ENC 4 +#define MAX_CHANNELS_PER_ENC 2 #define MAX_CWB_PER_ENC 2 #define IDLE_SHORT_TIMEOUT 1 @@ -661,6 +661,7 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); struct msm_drm_private *priv = dpu_enc->base.dev->dev_private; struct msm_display_info *disp_info = &dpu_enc->disp_info; + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_framebuffer *fb; @@ -674,12 +675,22 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, dsc = dpu_encoder_get_dsc_config(drm_enc); - /* - * Set DSC number as 1 to mark the enabled status, will be adjusted - * in dpu_crtc_get_topology() - */ - if (dsc) - topology->num_dsc = 1; + /* We only support 2 DSC mode (with 2 LM and 1 INTF) */ + if (dsc) { + /* + * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces + * when Display Stream Compression (DSC) is enabled, + * and when enough DSC blocks are available. + * This is power-optimal and can drive up to (including) 4k + * screens. + */ + WARN(topology->num_intf > 2, + "DSC topology cannot support more than 2 interfaces\n"); + if (topology->num_intf >= 2 || dpu_kms->catalog->dsc_count >= 2) + topology->num_dsc = 2; + else + topology->num_dsc = 1; + } connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); if (!connector) @@ -2169,8 +2180,8 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) { int i, num_lm; struct dpu_global_state *global_state; - struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; - struct dpu_hw_mixer *hw_mixer[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_blk *hw_lm[2]; + struct dpu_hw_mixer *hw_mixer[2]; struct dpu_hw_ctl *ctl = phys_enc->hw_ctl; /* reset all mixers for this encoder */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 09395d7910ac..61b22d949454 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -302,7 +302,7 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( /* Use merge_3d unless DSC MERGE topology is used */ if (phys_enc->split_role == ENC_ROLE_SOLO && - (dpu_cstate->num_mixers != 1) && + dpu_cstate->num_mixers == CRTC_DUAL_MIXERS && !dpu_encoder_use_dsc_merge(phys_enc->parent)) return BLEND_3D_H_ROW_INT; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 336757103b5a..4964e70610d1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -24,7 +24,7 @@ #define DPU_MAX_IMG_WIDTH 0x3fff #define DPU_MAX_IMG_HEIGHT 0x3fff -#define CRTC_QUAD_MIXERS 4 +#define CRTC_DUAL_MIXERS 2 #define MAX_XIN_COUNT 16 diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 31451241f083..046b683d4c66 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -34,7 +34,7 @@ #define DPU_MAX_PLANES 4 #endif -#define STAGES_PER_PLANE 2 +#define STAGES_PER_PLANE 1 #define PIPES_PER_STAGE 2 #define PIPES_PER_PLANE (PIPES_PER_STAGE * STAGES_PER_PLANE) #ifndef DPU_MAX_DE_CURVES -- cgit v1.2.3 From 88733a0b64872357e5ecd82b7488121503cb9cc6 Mon Sep 17 00:00:00 2001 From: Nikolay Kuratov Date: Thu, 11 Dec 2025 12:36:30 +0300 Subject: drm/msm/dpu: Add missing NULL pointer check for pingpong interface It is checked almost always in dpu_encoder_phys_wb_setup_ctl(), but in a single place the check is missing. Also use convenient locals instead of phys_enc->* where available. Cc: stable@vger.kernel.org Fixes: d7d0e73f7de33 ("drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback") Signed-off-by: Nikolay Kuratov Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/693860/ Link: https://lore.kernel.org/r/20251211093630.171014-1-kniv@yandex-team.ru Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 46f348972a97..6d28f2281c76 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -247,14 +247,12 @@ static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc) if (hw_cdm) intf_cfg.cdm = hw_cdm->idx; - if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode) - phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, - mode_3d); + if (hw_pp && hw_pp->merge_3d && hw_pp->merge_3d->ops.setup_3d_mode) + hw_pp->merge_3d->ops.setup_3d_mode(hw_pp->merge_3d, mode_3d); /* setup which pp blk will connect to this wb */ - if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk) - phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, - phys_enc->hw_pp->idx); + if (hw_pp && hw_wb->ops.bind_pingpong_blk) + hw_wb->ops.bind_pingpong_blk(hw_wb, hw_pp->idx); phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) { -- cgit v1.2.3 From 60489936aced785ef9e5a865e23a296bd0b470b6 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Tue, 23 Dec 2025 22:51:31 +0100 Subject: regulator: fp9931: fix regulator node pointer Sync the driver with the binding. During review process a regulators subnode was requested but neither driver nor test setup was updated. Fixes: 12d821bd13d4 ("regulator: Add FP9931/JD9930 driver") Signed-off-by: Andreas Kemnade Link: https://patch.msgid.link/20251223-fp9931-fix-v1-1-b19b4c1e7056@kemnade.info Signed-off-by: Mark Brown --- drivers/regulator/fp9931.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c index fef0bb07fd5d..69b3c712e5d5 100644 --- a/drivers/regulator/fp9931.c +++ b/drivers/regulator/fp9931.c @@ -391,6 +391,7 @@ static const struct regulator_desc regulators[] = { { .name = "v3p3", .of_match = of_match_ptr("v3p3"), + .regulators_node = of_match_ptr("regulators"), .id = 0, .ops = &fp9931_v3p3ops, .type = REGULATOR_VOLTAGE, @@ -403,6 +404,7 @@ static const struct regulator_desc regulators[] = { { .name = "vposneg", .of_match = of_match_ptr("vposneg"), + .regulators_node = of_match_ptr("regulators"), .id = 1, .ops = &fp9931_vposneg_ops, .type = REGULATOR_VOLTAGE, @@ -415,6 +417,7 @@ static const struct regulator_desc regulators[] = { { .name = "vcom", .of_match = of_match_ptr("vcom"), + .regulators_node = of_match_ptr("regulators"), .id = 2, .ops = &fp9931_vcom_ops, .type = REGULATOR_VOLTAGE, -- cgit v1.2.3 From d8ee3cfdc89b75dc059dc21c27bef2c1440f67eb Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 26 Nov 2025 14:38:26 +0100 Subject: vhost/vsock: improve RCU read sections around vhost_vsock_get() vhost_vsock_get() uses hash_for_each_possible_rcu() to find the `vhost_vsock` associated with the `guest_cid`. hash_for_each_possible_rcu() should only be called within an RCU read section, as mentioned in the following comment in include/linux/rculist.h: /** * hlist_for_each_entry_rcu - iterate over rcu list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. * @cond: optional lockdep expression if called from non-RCU protection. * * This list-traversal primitive may safely run concurrently with * the _rcu list-mutation primitives such as hlist_add_head_rcu() * as long as the traversal is guarded by rcu_read_lock(). */ Currently, all calls to vhost_vsock_get() are between rcu_read_lock() and rcu_read_unlock() except for calls in vhost_vsock_set_cid() and vhost_vsock_reset_orphans(). In both cases, the current code is safe, but we can make improvements to make it more robust. About vhost_vsock_set_cid(), when building the kernel with CONFIG_PROVE_RCU_LIST enabled, we get the following RCU warning when the user space issues `ioctl(dev, VHOST_VSOCK_SET_GUEST_CID, ...)` : WARNING: suspicious RCU usage 6.18.0-rc7 #62 Not tainted ----------------------------- drivers/vhost/vsock.c:74 RCU-list traversed in non-reader section!! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 1 lock held by rpc-libvirtd/3443: #0: ffffffffc05032a8 (vhost_vsock_mutex){+.+.}-{4:4}, at: vhost_vsock_dev_ioctl+0x2ff/0x530 [vhost_vsock] stack backtrace: CPU: 2 UID: 0 PID: 3443 Comm: rpc-libvirtd Not tainted 6.18.0-rc7 #62 PREEMPT(none) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-7.fc42 06/10/2025 Call Trace: dump_stack_lvl+0x75/0xb0 dump_stack+0x14/0x1a lockdep_rcu_suspicious.cold+0x4e/0x97 vhost_vsock_get+0x8f/0xa0 [vhost_vsock] vhost_vsock_dev_ioctl+0x307/0x530 [vhost_vsock] __x64_sys_ioctl+0x4f2/0xa00 x64_sys_call+0xed0/0x1da0 do_syscall_64+0x73/0xfa0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ... This is not a real problem, because the vhost_vsock_get() caller, i.e. vhost_vsock_set_cid(), holds the `vhost_vsock_mutex` used by the hash table writers. Anyway, to prevent that warning, add lockdep_is_held() condition to hash_for_each_possible_rcu() to verify that either the caller is in an RCU read section or `vhost_vsock_mutex` is held when CONFIG_PROVE_RCU_LIST is enabled; and also clarify the comment for vhost_vsock_get() to better describe the locking requirements and the scope of the returned pointer validity. About vhost_vsock_reset_orphans(), currently this function is only called via vsock_for_each_connected_socket(), which holds the `vsock_table_lock` spinlock (which is also an RCU read-side critical section). However, add an explicit RCU read lock there to make the code more robust and explicit about the RCU requirements, and to prevent issues if the calling context changes in the future or if vhost_vsock_reset_orphans() is called from other contexts. Fixes: 834e772c8db0 ("vhost/vsock: fix use-after-free in network stack callers") Cc: stefanha@redhat.com Signed-off-by: Stefano Garzarella Reviewed-by: Stefan Hajnoczi Message-Id: <20251126133826.142496-1-sgarzare@redhat.com> Message-ID: <20251126210313.GA499503@fedora> Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vsock.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 0298ddc34824..552cfb53498a 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -66,14 +66,15 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -/* Callers that dereference the return value must hold vhost_vsock_mutex or the - * RCU read lock. +/* Callers must be in an RCU read section or hold the vhost_vsock_mutex. + * The return value can only be dereferenced while within the section. */ static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) { + hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid, + lockdep_is_held(&vhost_vsock_mutex)) { u32 other_cid = vsock->guest_cid; /* Skip instances that have no CID yet */ @@ -709,9 +710,15 @@ static void vhost_vsock_reset_orphans(struct sock *sk) * executing. */ + rcu_read_lock(); + /* If the peer is still valid, no need to reset connection */ - if (vhost_vsock_get(vsk->remote_addr.svm_cid)) + if (vhost_vsock_get(vsk->remote_addr.svm_cid)) { + rcu_read_unlock(); return; + } + + rcu_read_unlock(); /* If the close timeout is pending, let it expire. This avoids races * with the timeout callback. -- cgit v1.2.3 From 66691e272e40c91305f1704695e0cb340cd162ff Mon Sep 17 00:00:00 2001 From: Evan Lambert Date: Wed, 24 Dec 2025 12:44:22 +0000 Subject: drm/msm: Replace unsafe snprintf usage with scnprintf The refill_buf function uses snprintf to append to a fixed-size buffer. snprintf returns the length that would have been written, which can exceed the remaining buffer size. If this happens, ptr advances beyond the buffer and rem becomes negative. In the 2nd iteration, rem is treated as a large unsigned integer, causing snprintf to write oob. While this behavior is technically mitigated by num_perfcntrs being locked at 5, it's still unsafe if num_perfcntrs were ever to change/a second source was added. Signed-off-by: Evan Lambert Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/696358/ Link: https://lore.kernel.org/r/20251224124254.17920-3-veyga@veygax.dev Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_perf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index d3c7889aaf26..c369d4acc378 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -65,13 +65,13 @@ static int refill_buf(struct msm_perf_state *perf) if ((perf->cnt++ % 32) == 0) { /* Header line: */ - n = snprintf(ptr, rem, "%%BUSY"); + n = scnprintf(ptr, rem, "%%BUSY"); ptr += n; rem -= n; for (i = 0; i < gpu->num_perfcntrs; i++) { const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; - n = snprintf(ptr, rem, "\t%s", perfcntr->name); + n = scnprintf(ptr, rem, "\t%s", perfcntr->name); ptr += n; rem -= n; } @@ -93,21 +93,21 @@ static int refill_buf(struct msm_perf_state *perf) return ret; val = totaltime ? 1000 * activetime / totaltime : 0; - n = snprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10); + n = scnprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10); ptr += n; rem -= n; for (i = 0; i < ret; i++) { /* cycle counters (I think).. convert to MHz.. */ val = cntrs[i] / 10000; - n = snprintf(ptr, rem, "\t%5d.%02d", + n = scnprintf(ptr, rem, "\t%5d.%02d", val / 100, val % 100); ptr += n; rem -= n; } } - n = snprintf(ptr, rem, "\n"); + n = scnprintf(ptr, rem, "\n"); ptr += n; rem -= n; -- cgit v1.2.3 From 5688e977ed2b98b2f881cdf2b1306a7bb2ba5018 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Dec 2025 11:10:46 +0100 Subject: efi/libstub: gop: Fix EDID support in mixed-mode The efi_edid_discovered_protocol and efi_edid_active_protocol have mixed mode fields. So all their attributes should be accessed through the efi_table_attr() helper. Doing so fixes the upper 32 bits of the 64 bit gop_edid pointer getting set to random values (followed by a crash at boot) when booting a x86_64 kernel on a machine with 32 bit UEFI like the Asus T100TA. Fixes: 17029cdd8f9d ("efi/libstub: gop: Add support for reading EDID") Cc: Thomas Zimmermann Cc: Javier Martinez Canillas Signed-off-by: Hans de Goede Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/libstub/gop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 72d74436a7a4..80dc8cfeb33e 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -513,15 +513,15 @@ efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid) status = efi_bs_call(handle_protocol, handle, &EFI_EDID_ACTIVE_PROTOCOL_GUID, (void **)&active_edid); if (status == EFI_SUCCESS) { - gop_size_of_edid = active_edid->size_of_edid; - gop_edid = active_edid->edid; + gop_size_of_edid = efi_table_attr(active_edid, size_of_edid); + gop_edid = efi_table_attr(active_edid, edid); } else { status = efi_bs_call(handle_protocol, handle, &EFI_EDID_DISCOVERED_PROTOCOL_GUID, (void **)&discovered_edid); if (status == EFI_SUCCESS) { - gop_size_of_edid = discovered_edid->size_of_edid; - gop_edid = discovered_edid->edid; + gop_size_of_edid = efi_table_attr(discovered_edid, size_of_edid); + gop_edid = efi_table_attr(discovered_edid, edid); } } -- cgit v1.2.3 From 61ed08c2fd1db0eb43c8b62ade249a3061e39444 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 23 Dec 2025 02:55:43 -0800 Subject: arm64: efi: Fix NULL pointer dereference by initializing user_ns Linux 6.19-rc2 (9448598b22c5 ("Linux 6.19-rc2")) is crashing with a NULL pointer dereference on arm64 hosts: Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c8 pc : cap_capable (security/commoncap.c:82 security/commoncap.c:128) Call trace: cap_capable (security/commoncap.c:82 security/commoncap.c:128) (P) security_capable (security/security.c:?) ns_capable_noaudit (kernel/capability.c:342 kernel/capability.c:381) __ptrace_may_access (./include/linux/rcupdate.h:895 kernel/ptrace.c:326) ptrace_may_access (kernel/ptrace.c:353) do_task_stat (fs/proc/array.c:467) proc_tgid_stat (fs/proc/array.c:673) proc_single_show (fs/proc/base.c:803) I've bissected the problem to commit a5baf582f4c0 ("arm64/efi: Call EFI runtime services without disabling preemption"). >From my analyzes, the crash occurs because efi_mm lacks a user_ns field initialization. This was previously harmless, but commit a5baf582f4c0 ("arm64/efi: Call EFI runtime services without disabling preemption") changed the EFI runtime call path to use kthread_use_mm(&efi_mm), which temporarily adopts efi_mm as the current mm for the calling kthread. When a thread has an active mm, LSM hooks like cap_capable() expect mm->user_ns to be valid for credential checks. With efi_mm.user_ns being NULL, capability checks during possible /proc access dereference the NULL pointer and crash. Fix by initializing efi_mm.user_ns to &init_user_ns. Fixes: a5baf582f4c0 ("arm64/efi: Call EFI runtime services without disabling preemption") Signed-off-by: Breno Leitao Acked-by: Rik van Riel Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/efi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a9070d00b833..55452e61af31 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -73,6 +73,7 @@ struct mm_struct efi_mm = { MMAP_LOCK_INITIALIZER(efi_mm) .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), + .user_ns = &init_user_ns, .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, #ifdef CONFIG_SCHED_MM_CID .mm_cid.lock = __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock), -- cgit v1.2.3 From 00f6c1b4d15d35fadb7f34768a1831c81aaa8936 Mon Sep 17 00:00:00 2001 From: Li Nan Date: Mon, 15 Dec 2025 20:44:12 +0800 Subject: md: Fix static checker warning in analyze_sbs The following warn is reported: drivers/md/md.c:3912 analyze_sbs() warn: iterator 'i' not incremented Fixes: d8730f0cf4ef ("md: Remove deprecated CONFIG_MD_MULTIPATH") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/linux-raid/7e2e95ce-3740-09d8-a561-af6bfb767f18@huaweicloud.com/T/#t Signed-off-by: Li Nan Link: https://lore.kernel.org/linux-raid/20251215124412.4015572-1-linan666@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index e5922a682953..03433c88fb54 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3882,7 +3882,6 @@ out_free_rdev: static int analyze_sbs(struct mddev *mddev) { - int i; struct md_rdev *rdev, *freshest, *tmp; freshest = NULL; @@ -3909,11 +3908,9 @@ static int analyze_sbs(struct mddev *mddev) super_types[mddev->major_version]. validate_super(mddev, NULL/*freshest*/, freshest); - i = 0; rdev_for_each_safe(rdev, tmp, mddev) { if (mddev->max_disks && - (rdev->desc_nr >= mddev->max_disks || - i > mddev->max_disks)) { + rdev->desc_nr >= mddev->max_disks) { pr_warn("md: %s: %pg: only %d devices permitted\n", mdname(mddev), rdev->bdev, mddev->max_disks); -- cgit v1.2.3 From c48c0fd0e19684b6ecdb4108a429e3a4e73f5e21 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 16 Dec 2025 17:54:18 +0100 Subject: firewire: nosy: Fix dma_free_coherent() size It looks like the buffer allocated and mapped in add_card() is done with size RCV_BUFFER_SIZE which is 16 KB and 4KB. Fixes: 286468210d83 ("firewire: new driver: nosy - IEEE 1394 traffic sniffer") Co-developed-by: Thomas Fourier Signed-off-by: Thomas Fourier Co-developed-by: Christophe JAILLET Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20251216165420.38355-2-fourier.thomas@gmail.com Signed-off-by: Takashi Sakamoto --- drivers/firewire/nosy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index ea31ac7ac1ca..e59053738a43 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -36,6 +36,8 @@ static char driver_name[] = KBUILD_MODNAME; +#define RCV_BUFFER_SIZE (16 * 1024) + /* this is the physical layout of a PCL, its size is 128 bytes */ struct pcl { __le32 next; @@ -517,16 +519,14 @@ remove_card(struct pci_dev *dev) lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, lynx->rcv_buffer, - lynx->rcv_buffer_bus); + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); pci_disable_device(dev); lynx_put(lynx); } -#define RCV_BUFFER_SIZE (16 * 1024) - static int add_card(struct pci_dev *dev, const struct pci_device_id *unused) { @@ -680,7 +680,7 @@ fail_deallocate_buffers: dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); if (lynx->rcv_buffer) - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); -- cgit v1.2.3 From fa917d3d570279dc3d699cbd947d0da0fde2e402 Mon Sep 17 00:00:00 2001 From: Louis-Alexis Eyraud Date: Wed, 3 Dec 2025 12:32:42 +0100 Subject: pinctrl: mediatek: mt8189: restore previous register base name array order In mt8189-pinctrl driver, a previous commit changed the register base name array (mt8189_pinctrl_register_base_names) entry name and order to align it with the same name and order as the "mediatek,mt8189-pinctrl" devicetree bindings. The new order (by ascending register address) now causes an issue with MT8189 pinctrl configuration. MT8189 SoC has multiple base addresses for the pin configuration registers. Several constant data structures, declaring each pin configuration, are using PIN_FIELD_BASE() macro which i_base parameter indicates for a given pin the lookup index in the base register address array of the driver internal data for the configuration register read/write accesses. But in practice, this parameter is given a hardcoded numerical value that corresponds to the expected base register entry index in mt8189_pinctrl_register_base_names array. Since this array reordering, the i_base index matching is no more correct. So, in order to avoid modifying over a thousand of PIN_FIELD_BASE() calls, restore previous mt8189_pinctrl_register_base_names entry order. Fixes: 518919276c41 ("pinctrl: mediatek: mt8189: align register base names to dt-bindings ones") Signed-off-by: Louis-Alexis Eyraud Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mt8189.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8189.c b/drivers/pinctrl/mediatek/pinctrl-mt8189.c index f6a3e584588b..cd4cdff309a1 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8189.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8189.c @@ -1642,7 +1642,7 @@ static const struct mtk_pin_reg_calc mt8189_reg_cals[PINCTRL_PIN_REG_MAX] = { }; static const char * const mt8189_pinctrl_register_base_names[] = { - "base", "lm", "rb0", "rb1", "bm0", "bm1", "bm2", "lt0", "lt1", "rt", + "base", "bm0", "bm1", "bm2", "lm", "lt0", "lt1", "rb0", "rb1", "rt", }; static const struct mtk_eint_hw mt8189_eint_hw = { -- cgit v1.2.3 From 7ad6ef91d8745d04aff9cce7bdbc6320d8e05fe9 Mon Sep 17 00:00:00 2001 From: Tuo Li Date: Thu, 25 Dec 2025 21:03:26 +0800 Subject: md/raid5: fix possible null-pointer dereferences in raid5_store_group_thread_cnt() The variable mddev->private is first assigned to conf and then checked: conf = mddev->private; if (!conf) ... If conf is NULL, then mddev->private is also NULL. In this case, null-pointer dereferences can occur when calling raid5_quiesce(): raid5_quiesce(mddev, true); raid5_quiesce(mddev, false); since mddev->private is assigned to conf again in raid5_quiesce(), and conf is dereferenced in several places, for example: conf->quiesce = 0; wake_up(&conf->wait_for_quiescent); To fix this issue, the function should unlock mddev and return before invoking raid5_quiesce() when conf is NULL, following the existing pattern in raid5_change_consistency_policy(). Fixes: fa1944bbe622 ("md/raid5: Wait sync io to finish before changing group cnt") Signed-off-by: Tuo Li Reviewed-by: Xiao Ni Reviewed-by: Paul Menzel Link: https://lore.kernel.org/linux-raid/20251225130326.67780-1-islituo@gmail.com Signed-off-by: Yu Kuai --- drivers/md/raid5.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e57ce3295292..8dc98f545969 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -7187,12 +7187,14 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) err = mddev_suspend_and_lock(mddev); if (err) return err; + conf = mddev->private; + if (!conf) { + mddev_unlock_and_resume(mddev); + return -ENODEV; + } raid5_quiesce(mddev, true); - conf = mddev->private; - if (!conf) - err = -ENODEV; - else if (new != conf->worker_cnt_per_group) { + if (new != conf->worker_cnt_per_group) { old_groups = conf->worker_groups; if (old_groups) flush_workqueue(raid5_wq); -- cgit v1.2.3 From 2cc583653bbe050bacd1cadcc9776d39bf449740 Mon Sep 17 00:00:00 2001 From: FengWei Shih Date: Fri, 26 Dec 2025 18:18:16 +0800 Subject: md: suspend array while updating raid_disks via sysfs In raid1_reshape(), freeze_array() is called before modifying the r1bio memory pool (conf->r1bio_pool) and conf->raid_disks, and unfreeze_array() is called after the update is completed. However, freeze_array() only waits until nr_sync_pending and (nr_pending - nr_queued) of all buckets reaches zero. When an I/O error occurs, nr_queued is increased and the corresponding r1bio is queued to either retry_list or bio_end_io_list. As a result, freeze_array() may unblock before these r1bios are released. This can lead to a situation where conf->raid_disks and the mempool have already been updated while queued r1bios, allocated with the old raid_disks value, are later released. Consequently, free_r1bio() may access memory out of bounds in put_all_bios() and release r1bios of the wrong size to the new mempool, potentially causing issues with the mempool as well. Since only normal I/O might increase nr_queued while an I/O error occurs, suspending the array avoids this issue. Note: Updating raid_disks via ioctl SET_ARRAY_INFO already suspends the array. Therefore, we suspend the array when updating raid_disks via sysfs to avoid this issue too. Signed-off-by: FengWei Shih Link: https://lore.kernel.org/linux-raid/20251226101816.4506-1-dannyshih@synology.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 03433c88fb54..dda272e87a1b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4404,7 +4404,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) if (err < 0) return err; - err = mddev_lock(mddev); + err = mddev_suspend_and_lock(mddev); if (err) return err; if (mddev->pers) @@ -4429,7 +4429,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) } else mddev->raid_disks = n; out_unlock: - mddev_unlock(mddev); + mddev_unlock_and_resume(mddev); return err ? err : len; } static struct md_sysfs_entry md_raid_disks = -- cgit v1.2.3 From 864466c38c4a0446088a8e866538c83c3f2018cb Mon Sep 17 00:00:00 2001 From: Li Nan Date: Fri, 26 Dec 2025 10:42:20 +0800 Subject: md: Fix logical_block_size configuration being overwritten In super_1_validate(), mddev->logical_block_size is directly overwritten with the value from metadata. This causes the previously configured lbs to be lost, making the configuration ineffective. Fix it. Fixes: 62ed1b582246 ("md: allow configuring logical block size") Signed-off-by: Li Nan Reviewed-by: Yu Kuai Reviewed-by: Xiao Ni Link: https://lore.kernel.org/linux-raid/20251226024221.724201-1-linan666@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index dda272e87a1b..a13f92a64df6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1999,7 +1999,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc mddev->layout = le32_to_cpu(sb->layout); mddev->raid_disks = le32_to_cpu(sb->raid_disks); mddev->dev_sectors = le64_to_cpu(sb->size); - mddev->logical_block_size = le32_to_cpu(sb->logical_block_size); mddev->events = ev1; mddev->bitmap_info.offset = 0; mddev->bitmap_info.space = 0; @@ -2015,6 +2014,9 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc mddev->max_disks = (4096-256)/2; + if (!mddev->logical_block_size) + mddev->logical_block_size = le32_to_cpu(sb->logical_block_size); + if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && mddev->bitmap_info.file == NULL) { mddev->bitmap_info.offset = -- cgit v1.2.3 From a4166f1c4893a9a620507255b9d1ccab44fab189 Mon Sep 17 00:00:00 2001 From: Li Nan Date: Fri, 26 Dec 2025 10:42:21 +0800 Subject: md: Fix forward incompatibility from configurable logical block size Commit 62ed1b582246 ("md: allow configuring logical block size") used reserved pad to add 'logical_block_size' to metadata. RAID rejects non-zero reserved pad, so arrays fail when rolling back to old kernels after booting new ones. Set 'logical_block_size' only for newly created arrays to support rollback to old kernels. Importantly new arrays still won't work on old kernels to prevent data loss issue from LBS changes. For arrays created on old kernels which confirmed not to rollback, configure LBS by echo current LBS (queue/logical_block_size) to md/logical_block_size. Fixes: 62ed1b582246 ("md: allow configuring logical block size") Reported-by: BugReports Closes: https://lore.kernel.org/linux-raid/825e532d-d1e1-44bb-5581-692b7c091796@huaweicloud.com/T/#t Signed-off-by: Li Nan Link: https://lore.kernel.org/linux-raid/20251226024221.724201-2-linan666@huaweicloud.com Signed-off-by: Yu Kuai --- drivers/md/md.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index a13f92a64df6..6d73f6e196a9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5980,13 +5980,33 @@ lbs_store(struct mddev *mddev, const char *buf, size_t len) if (mddev->major_version == 0) return -EINVAL; - if (mddev->pers) - return -EBUSY; - err = kstrtouint(buf, 10, &lbs); if (err < 0) return -EINVAL; + if (mddev->pers) { + unsigned int curr_lbs; + + if (mddev->logical_block_size) + return -EBUSY; + /* + * To fix forward compatibility issues, LBS is not + * configured for arrays from old kernels (<=6.18) by default. + * If the user confirms no rollback to old kernels, + * enable LBS by writing current LBS — to prevent data + * loss from LBS changes. + */ + curr_lbs = queue_logical_block_size(mddev->gendisk->queue); + if (lbs != curr_lbs) + return -EINVAL; + + mddev->logical_block_size = curr_lbs; + set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags); + pr_info("%s: logical block size configured successfully, array will not be assembled in old kernels (<= 6.18)\n", + mdname(mddev)); + return len; + } + err = mddev_lock(mddev); if (err) goto unlock; @@ -6162,7 +6182,27 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim, mdname(mddev)); return -EINVAL; } - mddev->logical_block_size = lim->logical_block_size; + + /* Only 1.x meta needs to set logical block size */ + if (mddev->major_version == 0) + return 0; + + /* + * Fix forward compatibility issue. Only set LBS by default for + * new arrays, mddev->events == 0 indicates the array was just + * created. When assembling an array, read LBS from the superblock + * instead — LBS is 0 in superblocks created by old kernels. + */ + if (!mddev->events) { + pr_info("%s: array will not be assembled in old kernels that lack configurable LBS support (<= 6.18)\n", + mdname(mddev)); + mddev->logical_block_size = lim->logical_block_size; + } + + if (!mddev->logical_block_size) + pr_warn("%s: echo current LBS to md/logical_block_size to prevent data loss issues from LBS changes.\n" + "\tNote: After setting, array will not be assembled in old kernels (<= 6.18)\n", + mdname(mddev)); return 0; } -- cgit v1.2.3 From d5dc28305143f126dc3d8da21e1ad75865b194e2 Mon Sep 17 00:00:00 2001 From: Rajashekar Hudumula Date: Wed, 17 Dec 2025 02:47:48 -0800 Subject: bng_en: update module description The Broadcom BCM57708/800G NIC family is branded as ThorUltra. Update the driver description accordingly. Fixes: 74715c4ab0fa0 ("bng_en: Add PCI interface") Signed-off-by: Rajashekar Hudumula Reviewed-by: Vikas Gupta Reviewed-by: Bhargava Chenna Marreddy Link: https://patch.msgid.link/20251217104748.3004706-1-rajashekar.hudumula@broadcom.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/broadcom/Kconfig | 8 ++++---- drivers/net/ethernet/broadcom/bnge/bnge.h | 2 +- drivers/net/ethernet/broadcom/bnge/bnge_core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 666522d64775..ca565ace6e6a 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -255,14 +255,14 @@ config BNXT_HWMON devices, via the hwmon sysfs interface. config BNGE - tristate "Broadcom Ethernet device support" + tristate "Broadcom ThorUltra Ethernet device support" depends on PCI select NET_DEVLINK select PAGE_POOL help - This driver supports Broadcom 50/100/200/400/800 gigabit Ethernet cards. - The module will be called bng_en. To compile this driver as a module, - choose M here. + This driver supports Broadcom ThorUltra 50/100/200/400/800 gigabit + Ethernet cards. The module will be called bng_en. To compile this + driver as a module, choose M here. config BCMASP tristate "Broadcom ASP 2.0 Ethernet support" diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h index 411744894349..32fc16a37d02 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -5,7 +5,7 @@ #define _BNGE_H_ #define DRV_NAME "bng_en" -#define DRV_SUMMARY "Broadcom 800G Ethernet Linux Driver" +#define DRV_SUMMARY "Broadcom ThorUltra NIC Ethernet Driver" #include #include diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c index c94e132bebc8..b4090283df0f 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c @@ -19,7 +19,7 @@ char bnge_driver_name[] = DRV_NAME; static const struct { char *name; } board_info[] = { - [BCM57708] = { "Broadcom BCM57708 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, + [BCM57708] = { "Broadcom BCM57708 ThorUltra 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, }; static const struct pci_device_id bnge_pci_tbl[] = { -- cgit v1.2.3 From d42bce414d1c5c0b536758466a1f63ac358e613c Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 17 Dec 2025 21:57:56 +0100 Subject: net: dsa: b53: skip multicast entries for fdb_dump() port_fdb_dump() is supposed to only add fdb entries, but we iterate over the full ARL table, which also includes multicast entries. So check if the entry is a multicast entry before passing it on to the callback(). Additionally, the port of those entries is a bitmask, not a port number, so any included entries would have even be for the wrong port. Fixes: 1da6df85c6fb ("net: dsa: b53: Implement ARL add/del/dump operations") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251217205756.172123-1-jonas.gorski@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/dsa/b53/b53_common.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index a1a177713d99..2c4131ed7e30 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2169,6 +2169,9 @@ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, if (!ent->is_valid) return 0; + if (is_multicast_ether_addr(ent->mac)) + return 0; + if (port != ent->port) return 0; -- cgit v1.2.3 From a4f800c4487dc5d6fcc28da89c7cc3c187ccc731 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 17 Dec 2025 13:01:53 -0800 Subject: net: mdio: rtl9300: use scoped for loops Currently in the return path, fwnode_handle_put calls are missing. Just use _scoped to avoid the issue. Fixes: 24e31e474769 ("net: mdio: Add RTL9300 MDIO driver") Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20251217210153.14641-1-rosenp@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/mdio/mdio-realtek-rtl9300.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 33694c3ff9a7..405a07075dd1 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -354,7 +354,6 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri struct fwnode_handle *node) { struct rtl9300_mdio_chan *chan; - struct fwnode_handle *child; struct mii_bus *bus; u32 mdio_bus; int err; @@ -371,7 +370,7 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri * compatible = "ethernet-phy-ieee802.3-c45". This does mean we can't * support both c45 and c22 on the same MDIO bus. */ - fwnode_for_each_child_node(node, child) + fwnode_for_each_child_node_scoped(node, child) if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45")) priv->smi_bus_is_c45[mdio_bus] = true; @@ -409,7 +408,6 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) { struct rtl9300_mdio_priv *priv = dev_get_drvdata(dev); struct device *parent = dev->parent; - struct fwnode_handle *port; int err; struct fwnode_handle *ports __free(fwnode_handle) = @@ -418,7 +416,7 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n", dev_fwnode(parent)); - fwnode_for_each_child_node(ports, port) { + fwnode_for_each_child_node_scoped(ports, port) { struct device_node *mdio_dn; u32 addr; u32 bus; -- cgit v1.2.3 From a1e077a3f76eea0dc671ed6792e7d543946227e8 Mon Sep 17 00:00:00 2001 From: Deepanshu Kartikey Date: Thu, 18 Dec 2025 06:41:56 +0530 Subject: net: usb: asix: validate PHY address before use The ASIX driver reads the PHY address from the USB device via asix_read_phy_addr(). A malicious or faulty device can return an invalid address (>= PHY_MAX_ADDR), which causes a warning in mdiobus_get_phy(): addr 207 out of range WARNING: drivers/net/phy/mdio_bus.c:76 Validate the PHY address in asix_read_phy_addr() and remove the now-redundant check in ax88172a.c. Reported-by: syzbot+3d43c9066a5b54902232@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3d43c9066a5b54902232 Tested-by: syzbot+3d43c9066a5b54902232@syzkaller.appspotmail.com Fixes: 7e88b11a862a ("net: usb: asix: refactor asix_read_phy_addr() and handle errors on return") Link: https://lore.kernel.org/all/20251217085057.270704-1-kartikey406@gmail.com/T/ [v1] Signed-off-by: Deepanshu Kartikey Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20251218011156.276824-1-kartikey406@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/usb/asix_common.c | 5 +++++ drivers/net/usb/ax88172a.c | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 7fd763917ae2..6ab3486072cb 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -335,6 +335,11 @@ int asix_read_phy_addr(struct usbnet *dev, bool internal) offset = (internal ? 1 : 0); ret = buf[offset]; + if (ret >= PHY_MAX_ADDR) { + netdev_err(dev->net, "invalid PHY address: %d\n", ret); + return -ENODEV; + } + netdev_dbg(dev->net, "%s PHY address 0x%x\n", internal ? "internal" : "external", ret); diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index f613e4bc68c8..758a423a459b 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -210,11 +210,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ret = asix_read_phy_addr(dev, priv->use_embdphy); if (ret < 0) goto free; - if (ret >= PHY_MAX_ADDR) { - netdev_err(dev->net, "Invalid PHY address %#x\n", ret); - ret = -ENODEV; - goto free; - } + priv->phy_addr = ret; ax88172a_reset_phy(dev, priv->use_embdphy); -- cgit v1.2.3 From 3387a7ad478b46970ae8254049167d166e398aeb Mon Sep 17 00:00:00 2001 From: Dipayaan Roy Date: Thu, 18 Dec 2025 05:10:54 -0800 Subject: net: mana: Fix use-after-free in reset service rescan path When mana_serv_reset() encounters -ETIMEDOUT or -EPROTO from mana_gd_resume(), it performs a PCI rescan via mana_serv_rescan(). mana_serv_rescan() calls pci_stop_and_remove_bus_device(), which can invoke the driver's remove path and free the gdma_context associated with the device. After returning, mana_serv_reset() currently jumps to the out label and attempts to clear gc->in_service, dereferencing a freed gdma_context. The issue was observed with the following call logs: [ 698.942636] BUG: unable to handle page fault for address: ff6c2b638088508d [ 698.943121] #PF: supervisor write access in kernel mode [ 698.943423] #PF: error_code(0x0002) - not-present page [S[ 698.943793] Pat Dec 6 07:GD5 100000067 P4D 1002f7067 PUD 1002f8067 PMD 101bef067 PTE 0 0:56 2025] hv_[n e 698.944283] Oops: Oops: 0002 [#1] SMP NOPTI tvsc f8615163-00[ 698.944611] CPU: 28 UID: 0 PID: 249 Comm: kworker/28:1 ... [Sat Dec 6 07:50:56 2025] R10: [ 699.121594] mana 7870:00:00.0 enP30832s1: Configured vPort 0 PD 18 DB 16 000000000000001b R11: 0000000000000000 R12: ff44cf3f40270000 [Sat Dec 6 07:50:56 2025] R13: 0000000000000001 R14: ff44cf3f402700c8 R15: ff44cf3f4021b405 [Sat Dec 6 07:50:56 2025] FS: 0000000000000000(0000) GS:ff44cf7e9fcf9000(0000) knlGS:0000000000000000 [Sat Dec 6 07:50:56 2025] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [Sat Dec 6 07:50:56 2025] CR2: ff6c2b638088508d CR3: 000000011fe43001 CR4: 0000000000b73ef0 [Sat Dec 6 07:50:56 2025] Call Trace: [Sat Dec 6 07:50:56 2025] [Sat Dec 6 07:50:56 2025] mana_serv_func+0x24/0x50 [mana] [Sat Dec 6 07:50:56 2025] process_one_work+0x190/0x350 [Sat Dec 6 07:50:56 2025] worker_thread+0x2b7/0x3d0 [Sat Dec 6 07:50:56 2025] kthread+0xf3/0x200 [Sat Dec 6 07:50:56 2025] ? __pfx_worker_thread+0x10/0x10 [Sat Dec 6 07:50:56 2025] ? __pfx_kthread+0x10/0x10 [Sat Dec 6 07:50:56 2025] ret_from_fork+0x21a/0x250 [Sat Dec 6 07:50:56 2025] ? __pfx_kthread+0x10/0x10 [Sat Dec 6 07:50:56 2025] ret_from_fork_asm+0x1a/0x30 [Sat Dec 6 07:50:56 2025] Fix this by returning immediately after mana_serv_rescan() to avoid accessing GC state that may no longer be valid. Fixes: 9bf66036d686 ("net: mana: Handle hardware recovery events when probing the device") Reviewed-by: Simon Horman Reviewed-by: Long Li Signed-off-by: Dipayaan Roy Link: https://patch.msgid.link/20251218131054.GA3173@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microsoft/mana/gdma_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index efb4e412ec7e..0055c231acf6 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -481,7 +481,7 @@ static void mana_serv_reset(struct pci_dev *pdev) /* Perform PCI rescan on device if we failed on HWC */ dev_err(&pdev->dev, "MANA service: resume failed, rescanning\n"); mana_serv_rescan(pdev); - goto out; + return; } if (ret) -- cgit v1.2.3 From 7fc4da6a304bdcd3de14fc946dc2c19437a9cc5a Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 23 Dec 2025 11:27:40 +0800 Subject: ublk: scan partition in async way Implement async partition scan to avoid IO hang when reading partition tables. Similar to nvme_partition_scan_work(), partition scanning is deferred to a work queue to prevent deadlocks. When partition scan happens synchronously during add_disk(), IO errors can cause the partition scan to wait while holding ub->mutex, which can deadlock with other operations that need the mutex. Changes: - Add partition_scan_work to ublk_device structure - Implement ublk_partition_scan_work() to perform async scan - Always suppress sync partition scan during add_disk() - Schedule async work after add_disk() for trusted daemons - Add flush_work() in ublk_stop_dev() before grabbing ub->mutex Reviewed-by: Caleb Sander Mateos Reported-by: Yoav Cohen Closes: https://lore.kernel.org/linux-block/DM4PR12MB63280C5637917C071C2F0D65A9A8A@DM4PR12MB6328.namprd12.prod.outlook.com/ Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- drivers/block/ublk_drv.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 49c208457198..837fedb02e0d 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -237,6 +237,7 @@ struct ublk_device { bool canceling; pid_t ublksrv_tgid; struct delayed_work exit_work; + struct work_struct partition_scan_work; struct ublk_queue *queues[]; }; @@ -254,6 +255,20 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub, u16 q_id, u16 tag, struct ublk_io *io, size_t offset); static inline unsigned int ublk_req_build_flags(struct request *req); +static void ublk_partition_scan_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, partition_scan_work); + + if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, + &ub->ub_disk->state))) + return; + + mutex_lock(&ub->ub_disk->open_mutex); + bdev_disk_changed(ub->ub_disk, false); + mutex_unlock(&ub->ub_disk->open_mutex); +} + static inline struct ublksrv_io_desc * ublk_get_iod(const struct ublk_queue *ubq, unsigned tag) { @@ -2026,6 +2041,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); ublk_stop_dev_unlocked(ub); mutex_unlock(&ub->mutex); + flush_work(&ub->partition_scan_work); ublk_cancel_dev(ub); } @@ -2954,9 +2970,17 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, ublk_apply_params(ub); - /* don't probe partitions if any daemon task is un-trusted */ - if (ub->unprivileged_daemons) - set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); + /* + * Suppress partition scan to avoid potential IO hang. + * + * If ublk server error occurs during partition scan, the IO may + * wait while holding ub->mutex, which can deadlock with other + * operations that need the mutex. Defer partition scan to async + * work. + * For unprivileged daemons, keep GD_SUPPRESS_PART_SCAN set + * permanently. + */ + set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); ublk_get_device(ub); ub->dev_info.state = UBLK_S_DEV_LIVE; @@ -2973,6 +2997,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, set_bit(UB_STATE_USED, &ub->state); + /* Schedule async partition scan for trusted daemons */ + if (!ub->unprivileged_daemons) + schedule_work(&ub->partition_scan_work); + out_put_cdev: if (ret) { ublk_detach_disk(ub); @@ -3138,6 +3166,7 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) mutex_init(&ub->mutex); spin_lock_init(&ub->lock); mutex_init(&ub->cancel_mutex); + INIT_WORK(&ub->partition_scan_work, ublk_partition_scan_work); ret = ublk_alloc_dev_number(ub, header->dev_id); if (ret < 0) -- cgit v1.2.3 From 665077d78dc7941ce6a330c02023a2b469cc8cc7 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 14:31:50 +0000 Subject: vfio/pds: Fix memory leak in pds_vfio_dirty_enable() pds_vfio_dirty_enable() allocates memory for region_info. If interval_tree_iter_first() returns NULL, the function returns -EINVAL immediately without freeing the allocated memory, causing a memory leak. Fix this by jumping to the out_free_region_info label to ensure region_info is freed. Fixes: 2e7c6feb4ef52 ("vfio/pds: Add multi-region support") Signed-off-by: Zilin Guan Link: https://lore.kernel.org/r/20251225143150.1117366-1-zilin@seu.edu.cn Signed-off-by: Alex Williamson --- drivers/vfio/pci/pds/dirty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c index 481992142f79..4915a7c1c491 100644 --- a/drivers/vfio/pci/pds/dirty.c +++ b/drivers/vfio/pci/pds/dirty.c @@ -292,8 +292,11 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio, len = num_ranges * sizeof(*region_info); node = interval_tree_iter_first(ranges, 0, ULONG_MAX); - if (!node) - return -EINVAL; + if (!node) { + err = -EINVAL; + goto out_free_region_info; + } + for (int i = 0; i < num_ranges; i++) { struct pds_lm_dirty_region_info *ri = ®ion_info[i]; u64 region_size = node->last - node->start + 1; -- cgit v1.2.3 From acf44a2361b8d6356b71a970ab016065b5123b0e Mon Sep 17 00:00:00 2001 From: Alper Ak Date: Thu, 25 Dec 2025 18:13:49 +0300 Subject: vfio/xe: Fix use-after-free in xe_vfio_pci_alloc_file() migf->filp is accessed after migf has been freed. Save the error value before calling kfree() to prevent use-after-free. Fixes: 1f5556ec8b9e ("vfio/xe: Add device specific vfio_pci driver variant for Intel graphics") Signed-off-by: Alper Ak Link: https://lore.kernel.org/r/20251225151349.360870-1-alperyasinak1@gmail.com Signed-off-by: Alex Williamson --- drivers/vfio/pci/xe/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vfio/pci/xe/main.c b/drivers/vfio/pci/xe/main.c index 719ab4660085..2a5eb9260ec7 100644 --- a/drivers/vfio/pci/xe/main.c +++ b/drivers/vfio/pci/xe/main.c @@ -250,6 +250,7 @@ xe_vfio_pci_alloc_file(struct xe_vfio_pci_core_device *xe_vdev, struct xe_vfio_pci_migration_file *migf; const struct file_operations *fops; int flags; + int ret; migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT); if (!migf) @@ -259,8 +260,9 @@ xe_vfio_pci_alloc_file(struct xe_vfio_pci_core_device *xe_vdev, flags = type == XE_VFIO_FILE_SAVE ? O_RDONLY : O_WRONLY; migf->filp = anon_inode_getfile("xe_vfio_mig", fops, migf, flags); if (IS_ERR(migf->filp)) { + ret = PTR_ERR(migf->filp); kfree(migf); - return ERR_CAST(migf->filp); + return ERR_PTR(ret); } mutex_init(&migf->lock); -- cgit v1.2.3 From 961ac9d97be72267255f1ed841aabf6694b17454 Mon Sep 17 00:00:00 2001 From: Harshita Bhilwaria Date: Wed, 17 Dec 2025 11:16:06 +0530 Subject: crypto: qat - fix duplicate restarting msg during AER error The restarting message from PF to VF is sent twice during AER error handling: once from adf_error_detected() and again from adf_disable_sriov(). This causes userspace subservices to shutdown unexpectedly when they receive a duplicate restarting message after already being restarted. Avoid calling adf_pf2vf_notify_restarting() and adf_pf2vf_wait_for_restarting_complete() from adf_error_detected() so that the restarting msg is sent only once from PF to VF. Fixes: 9567d3dc760931 ("crypto: qat - improve aer error reset handling") Signed-off-by: Harshita Bhilwaria Reviewed-by: Giovanni Cabiddu Reviewed-by: Ahsan Atta Reviewed-by: Ravikumar PM Reviewed-by: Srikanth Thokala Signed-off-by: Herbert Xu --- drivers/crypto/intel/qat/qat_common/adf_aer.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index 11728cf32653..a5964fd8204c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -41,8 +41,6 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev, adf_error_notifier(accel_dev); adf_pf2vf_notify_fatal_error(accel_dev); adf_dev_restarting_notify(accel_dev); - adf_pf2vf_notify_restarting(accel_dev); - adf_pf2vf_wait_for_restarting_complete(accel_dev); pci_clear_master(pdev); adf_dev_down(accel_dev); -- cgit v1.2.3 From bed2a6bd20681aacfb063015c1edfab6f58a333e Mon Sep 17 00:00:00 2001 From: Jonathan Cavitt Date: Mon, 22 Dec 2025 20:19:59 +0000 Subject: drm/xe/guc: READ/WRITE_ONCE g2h_fence->done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use READ_ONCE and WRITE_ONCE when operating on g2h_fence->done to prevent the compiler from ignoring important modifications to its value. Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs") Suggested-by: Matthew Brost Signed-off-by: Jonathan Cavitt Cc: Rodrigo Vivi Reviewed-by: Matthew Brost Link: https://patch.msgid.link/20251222201957.63245-5-jonathan.cavitt@intel.com Signed-off-by: Rodrigo Vivi (cherry picked from commit b5179dbd1c14743ae80f0aaa28eaaf35c361608f) Signed-off-by: Thomas Hellström --- drivers/gpu/drm/xe/xe_guc_ct.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 4ac434ad216f..a5019d1e741b 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -104,7 +104,9 @@ static void g2h_fence_cancel(struct g2h_fence *g2h_fence) { g2h_fence->cancel = true; g2h_fence->fail = true; - g2h_fence->done = true; + + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); } static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence) @@ -1203,10 +1205,13 @@ retry_same_fence: return ret; } - ret = wait_event_timeout(ct->g2h_fence_wq, g2h_fence.done, HZ); + /* READ_ONCEs pairs with WRITE_ONCEs in parse_g2h_response + * and g2h_fence_cancel. + */ + ret = wait_event_timeout(ct->g2h_fence_wq, READ_ONCE(g2h_fence.done), HZ); if (!ret) { LNL_FLUSH_WORK(&ct->g2h_worker); - if (g2h_fence.done) { + if (READ_ONCE(g2h_fence.done)) { xe_gt_warn(gt, "G2H fence %u, action %04x, done\n", g2h_fence.seqno, action[0]); ret = 1; @@ -1454,7 +1459,8 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); - g2h_fence->done = true; + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); smp_mb(); wake_up_all(&ct->g2h_fence_wq); -- cgit v1.2.3 From 420f423defcf6d0af2263d38da870ca4a20c0990 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 15 Dec 2025 12:59:15 +0200 Subject: mei: me: add nova lake point S DID Add Nova Lake S device id. Cc: stable Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Link: https://patch.msgid.link/20251215105915.1672659-1-alexander.usyskin@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 2 ++ drivers/misc/mei/pci-me.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index a4f75dc36929..fa30899a5fa2 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -122,6 +122,8 @@ #define MEI_DEV_ID_WCL_P 0x4D70 /* Wildcat Lake P */ +#define MEI_DEV_ID_NVL_S 0x6E68 /* Nova Lake Point S */ + /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 73cad914be9f..2a6e569558b9 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -129,6 +129,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_WCL_P, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_NVL_S, MEI_ME_PCH15_CFG)}, + /* required last entry */ {0, } }; -- cgit v1.2.3 From 361e0ff456a8daf9753c18030533256e4133ce7a Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 2 Dec 2025 11:24:24 +0000 Subject: rust_binder: remove spin_lock() in rust_shrink_free_page() When forward-porting Rust Binder to 6.18, I neglected to take commit fb56fdf8b9a2 ("mm/list_lru: split the lock to per-cgroup scope") into account, and apparently I did not end up running the shrinker callback when I sanity tested the driver before submission. This leads to crashes like the following: ============================================ WARNING: possible recursive locking detected 6.18.0-mainline-maybe-dirty #1 Tainted: G IO -------------------------------------------- kswapd0/68 is trying to acquire lock: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: lock_list_lru_of_memcg+0x128/0x230 but task is already holding lock: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: rust_helper_spin_lock+0xd/0x20 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&l->lock); lock(&l->lock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by kswapd0/68: #0: ffffffff90d2e260 (fs_reclaim){+.+.}-{0:0}, at: kswapd+0x597/0x1160 #1: ffff956000fa18b0 (&l->lock){+.+.}-{2:2}, at: rust_helper_spin_lock+0xd/0x20 #2: ffffffff90cf3680 (rcu_read_lock){....}-{1:2}, at: lock_list_lru_of_memcg+0x2d/0x230 To fix this, remove the spin_lock() call from rust_shrink_free_page(). Cc: stable Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Signed-off-by: Alice Ryhl Link: https://patch.msgid.link/20251202-binder-shrink-unspin-v1-1-263efb9ad625@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/page_range.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs index 9379038f61f5..fdd97112ef5c 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -727,8 +727,5 @@ unsafe extern "C" fn rust_shrink_free_page( drop(mm); drop(page); - // SAFETY: We just unlocked the lru lock, but it should be locked when we return. - unsafe { bindings::spin_lock(&raw mut (*lru).lock) }; - LRU_REMOVED_ENTRY } -- cgit v1.2.3 From 305f254727bd379bbed0385afa0162f5bde1f51c Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Fri, 28 Nov 2025 12:17:22 +0800 Subject: pmdomain: mtk-pm-domains: Fix spinlock recursion fix in probe Remove scpsys_get_legacy_regmap(), replacing its usage with of_find_node_with_property(). Explicitly call of_node_get(np) before each of_find_node_with_property() to maintain correct node reference counting. The of_find_node_with_property() function "consumes" its input by calling of_node_put() internally, whether or not it finds a match. Currently, dev->of_node (np) is passed multiple times in sequence without incrementing its reference count, causing it to be decremented multiple times and risking early memory release. Adding of_node_get(np) before each call balances the reference count, preventing premature node release. Fixes: c1bac49fe91f ("pmdomains: mtk-pm-domains: Fix spinlock recursion in probe") Cc: stable@vger.kernel.org Signed-off-by: Macpaul Lin Tested-by: Louis-Alexis Eyraud Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-pm-domains.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 80561d27f2b2..f64f24d520dd 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -984,18 +984,6 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) } } -static struct device_node *scpsys_get_legacy_regmap(struct device_node *np, const char *pn) -{ - struct device_node *local_node; - - for_each_child_of_node(np, local_node) { - if (of_property_present(local_node, pn)) - return local_node; - } - - return NULL; -} - static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *scpsys) { const u8 bp_blocks[3] = { @@ -1017,7 +1005,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s * this makes it then possible to allocate the array of bus_prot * regmaps and convert all to the new style handling. */ - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg"); if (node) { regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); of_node_put(node); @@ -1030,7 +1019,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[0] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,smi"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,smi"); if (node) { smi_np = of_parse_phandle(node, "mediatek,smi", 0); of_node_put(node); @@ -1048,7 +1038,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[1] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg-nao"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg-nao"); if (node) { regmap[2] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); num_regmaps++; -- cgit v1.2.3 From 73cb5f6eafb0ac7aea8cdeb8ff12981aa741d8fb Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 11 Dec 2025 04:02:52 +0000 Subject: pmdomain: imx: Fix reference count leak in imx_gpc_probe() of_get_child_by_name() returns a node pointer with refcount incremented. Use the __free() attribute to manage the pgc_node reference, ensuring automatic of_node_put() cleanup when pgc_node goes out of scope. This eliminates the need for explicit error handling paths and avoids reference count leaks. Fixes: 721cabf6c660 ("soc: imx: move PGC handling to a new GPC driver") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Reviewed-by: Frank Li Signed-off-by: Ulf Hansson --- drivers/pmdomain/imx/gpc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index a34b260274f7..de695f1944ab 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -402,13 +402,12 @@ clk_err: static int imx_gpc_probe(struct platform_device *pdev) { const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev); - struct device_node *pgc_node; + struct device_node *pgc_node __free(device_node) + = of_get_child_by_name(pdev->dev.of_node, "pgc"); struct regmap *regmap; void __iomem *base; int ret; - pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); - /* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) -- cgit v1.2.3 From d37cd54ebeac37a763fbf303ed25f8a6e98328ff Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Sun, 28 Dec 2025 22:41:31 +0100 Subject: platform/x86: samsung-galaxybook: Fix problematic pointer cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user reported that reading the charge threshold on his device results in very strange values (like 78497792) being returned. The reason for this seems to be the fact that the driver casts the int pointer to an u8 pointer, leaving the last 3 bytes of the destination uninitialized. Fix this by using a temporary variable instead. Cc: stable@vger.kernel.org Fixes: 56f529ce4370 ("platform/x86: samsung-galaxybook: Add samsung-galaxybook driver") Reported-by: Gianni Ceccarelli Closes: https://lore.kernel.org/platform-driver-x86/20251228115556.14362d66@thenautilus.net/ Tested-by: Gianni Ceccarelli Signed-off-by: Armin Wolf Link: https://patch.msgid.link/20251228214217.35972-1-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/samsung-galaxybook.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c index 3c13e13d4885..755cb82bdb60 100644 --- a/drivers/platform/x86/samsung-galaxybook.c +++ b/drivers/platform/x86/samsung-galaxybook.c @@ -442,12 +442,13 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, union power_supply_propval *val) { struct samsung_galaxybook *galaxybook = ext_data; + u8 value; int err; if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) return -EINVAL; - err = charge_control_end_threshold_acpi_get(galaxybook, (u8 *)&val->intval); + err = charge_control_end_threshold_acpi_get(galaxybook, &value); if (err) return err; @@ -455,8 +456,10 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, * device stores "no end threshold" as 0 instead of 100; * if device has 0, report 100 */ - if (val->intval == 0) - val->intval = 100; + if (value == 0) + value = 100; + + val->intval = value; return 0; } -- cgit v1.2.3 From cbf3dc32609b9703b87fbd444c271821664478c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hnyk?= Date: Fri, 26 Dec 2025 21:34:54 +0100 Subject: platform/x86: ideapad-laptop: Reassign KEY_CUT to KEY_SELECTIVE_SCREENSHOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per Lenovo documentation, Fn+Print-Screen should "Open the Snipping tool" which corresponds to KEY_SELECTIVE_SCREENSHOT (keycode 0x27a). It is currently assigned to KEY_CUT because keycodes under 248 were preferred due to X11 limitations. Reassign Fn+Print-Screen from KEY_CUT to KEY_SELECTIVE_SCREENSHOT. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220566 Signed-off-by: Tomáš Hnyk Link: https://patch.msgid.link/20251226203454.405520-1-tomashnyk@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/lenovo/ideapad-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c index 5171a077f62c..7d5f7a2f6564 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -1367,7 +1367,7 @@ static const struct key_entry ideapad_keymap[] = { /* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */ { KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } }, /* shift + prtsc */ - { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } }, + { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } }, { KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } }, { KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } }, -- cgit v1.2.3 From 063185ba32747f69159777c66097cd8f428e8b7a Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Thu, 25 Dec 2025 03:38:41 +0100 Subject: platform/x86: asus-armoury: add support for GU605CR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TDP data for laptop model GU605CR. Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251225023841.1970513-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index a1bb2005c3f3..d8814165d480 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -950,6 +950,35 @@ static const struct dmi_system_id power_limits[] = { }, }, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU605CR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 38, + .ppt_pl2_sppt_max = 110, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_def = 90, + .nv_tgp_max = 105, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 38, + .ppt_pl2_sppt_max = 110, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), -- cgit v1.2.3 From a05117150256dd0787f4e6d56b577b41488f28a4 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Thu, 25 Dec 2025 03:53:01 +0100 Subject: platform/x86: asus-armoury: add support for GA403WR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TDP data for laptop model GA403WR. Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251225025301.1980627-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index d8814165d480..1d689e561509 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -822,6 +822,38 @@ static const struct dmi_system_id power_limits[] = { .requires_fan_curve = true, }, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA403WR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 0, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_max = 95, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 35, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), -- cgit v1.2.3 From a22d893f490d9cd517dbf02549701add2318594c Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Thu, 25 Dec 2025 04:03:54 +0100 Subject: platform/x86: asus-armoury: add support for FA608UM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TDP data for laptop model FA608UM. Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251225030354.2315874-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index 1d689e561509..0b7cdae8b442 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -552,6 +552,42 @@ static const struct dmi_system_id power_limits[] = { }, }, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA608UM"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 90, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 90, + .ppt_pl3_fppt_max = 65, + .nv_dynamic_boost_min = 10, + .nv_dynamic_boost_max = 15, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 100, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), -- cgit v1.2.3 From 499d987b65c03bacf3c17f32c2ad1408b751c708 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Thu, 25 Dec 2025 04:10:41 +0100 Subject: platform/x86: asus-armoury: add support for G615LR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TDP data for laptop model G615LR. Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251225031041.2321249-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index 0b7cdae8b442..24977a9da229 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -1357,6 +1357,35 @@ static const struct dmi_system_id power_limits[] = { .requires_fan_curve = true, }, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G615LR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 140, + .ppt_pl1_spl_max = 175, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_tgp_min = 65, + .nv_tgp_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "G634J"), -- cgit v1.2.3 From e44c42c830b7ab36e3a3a86321c619f24def5206 Mon Sep 17 00:00:00 2001 From: Junrui Luo Date: Fri, 26 Dec 2025 19:42:05 +0800 Subject: platform/x86: hp-bioscfg: Fix out-of-bounds array access in ACPI package parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hp_populate_*_elements_from_package() functions in the hp-bioscfg driver contain out-of-bounds array access vulnerabilities. These functions parse ACPI packages into internal data structures using a for loop with index variable 'elem' that iterates through enum_obj/integer_obj/order_obj/password_obj/string_obj arrays. When processing multi-element fields like PREREQUISITES and ENUM_POSSIBLE_VALUES, these functions read multiple consecutive array elements using expressions like 'enum_obj[elem + reqs]' and 'enum_obj[elem + pos_values]' within nested loops. The bug is that the bounds check only validated elem, but did not consider the additional offset when accessing elem + reqs or elem + pos_values. The fix changes the bounds check to validate the actual accessed index. Reported-by: Yuhao Jiang Reported-by: Junrui Luo Fixes: e6c7b3e15559 ("platform/x86: hp-bioscfg: string-attributes") Signed-off-by: Junrui Luo Link: https://patch.msgid.link/SYBPR01MB788173D7DD4EA2CB6383683DAFB0A@SYBPR01MB7881.ausprd01.prod.outlook.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c | 4 ++-- drivers/platform/x86/hp/hp-bioscfg/int-attributes.c | 2 +- drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c | 5 +++++ drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c | 5 +++++ drivers/platform/x86/hp/hp-bioscfg/string-attributes.c | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c index c50ad5880503..f346aad8e9d8 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c @@ -207,7 +207,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum case PREREQUISITES: size = min_t(u32, enum_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= enum_obj_count) { + if (elem + reqs >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } @@ -255,7 +255,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum for (pos_values = 0; pos_values < size && pos_values < MAX_VALUES_SIZE; pos_values++) { - if (elem >= enum_obj_count) { + if (elem + pos_values >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c index 6c7f4d5fa9cb..63b1fda2be4e 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c @@ -227,7 +227,7 @@ static int hp_populate_integer_elements_from_package(union acpi_object *integer_ size = min_t(u32, integer_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= integer_obj_count) { + if (elem + reqs >= integer_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c index c6e57bb9d8b7..6a31f47ce3f5 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c @@ -216,6 +216,11 @@ static int hp_populate_ordered_list_elements_from_package(union acpi_object *ord size = min_t(u32, ordered_list_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= order_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer, order_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c index 187b372123ed..ec79d9d50377 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c @@ -303,6 +303,11 @@ static int hp_populate_password_elements_from_package(union acpi_object *passwor MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= password_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(password_obj[elem + reqs].string.pointer, password_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c index 27758b779b2d..7b885d25650c 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c @@ -217,7 +217,7 @@ static int hp_populate_string_elements_from_package(union acpi_object *string_ob MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= string_obj_count) { + if (elem + reqs >= string_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } -- cgit v1.2.3 From 66e245db16f0175af656cd812b6dc1a5e1f7b80a Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Wed, 24 Dec 2025 01:51:09 -0800 Subject: platform/x86/intel/pmt/discovery: use valid device pointer in dev_err_probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PMT feature probe creates a child device with device_create(). If device creation fail, the code pass priv->dev (which is an ERR_PTR) to dev_err_probe(), which is not a valid device pointer. This patch change the dev_err_probe() call to use the parent auxiliary device (&auxdev->dev) and update the error message to reference the parent device name. It ensure correct error reporting and avoid passing an invalid device pointer. Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver") Signed-off-by: Alok Tiwari Link: https://patch.msgid.link/20251224095133.115678-1-alok.a.tiwari@oracle.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmt/discovery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index 9c5b4d0e1fae..e500aa327d23 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -548,9 +548,9 @@ static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxi priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv, "%s-%s", "features", dev_name(priv->parent)); if (IS_ERR(priv->dev)) - return dev_err_probe(priv->dev, PTR_ERR(priv->dev), + return dev_err_probe(&auxdev->dev, PTR_ERR(priv->dev), "Could not create %s-%s device node\n", - "features", dev_name(priv->dev)); + "features", dev_name(priv->parent)); /* Initialize each feature */ for (i = 0; i < ivdev->num_resources; i++) { -- cgit v1.2.3 From 6a02651c4c4b710ecbaf798eb4feb57c97f2bc14 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Mon, 29 Dec 2025 16:07:55 +0100 Subject: platform/x86: asus-armoury: fix ppt data for FA507R MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PPT data for FA507R was reported to be wrong by a user: change limits to make them equal to Armoury Crate limits. Fixes: 39ae6c50e599 ("platform/x86: asus-armoury: add ppt_* and nv_* tuning knobs") Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251229150755.1351495-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index 24977a9da229..68b174b70a66 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -449,12 +449,27 @@ static const struct dmi_system_id power_limits[] = { .ac_data = &(struct power_limits) { .ppt_pl1_spl_min = 15, .ppt_pl1_spl_max = 80, - .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_min = 35, .ppt_pl2_sppt_max = 80, .ppt_pl3_fppt_min = 35, - .ppt_pl3_fppt_max = 80 + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, }, - .dc_data = NULL, }, }, { -- cgit v1.2.3 From 85f4b0c650d9f9db10bda8d3acfa1af83bf78cf7 Mon Sep 17 00:00:00 2001 From: Anshumali Gaur Date: Fri, 19 Dec 2025 11:52:26 +0530 Subject: octeontx2-pf: fix "UBSAN: shift-out-of-bounds error" This patch ensures that the RX ring size (rx_pending) is not set below the permitted length. This avoids UBSAN shift-out-of-bounds errors when users passes small or zero ring sizes via ethtool -G. Fixes: d45d8979840d ("octeontx2-pf: Add basic ethtool support") Signed-off-by: Anshumali Gaur Link: https://patch.msgid.link/20251219062226.524844-1-agaur@marvell.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index b90e23dc49de..b6449f0a9e7d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -418,6 +418,14 @@ static int otx2_set_ringparam(struct net_device *netdev, */ if (rx_count < pfvf->hw.rq_skid) rx_count = pfvf->hw.rq_skid; + + if (ring->rx_pending < 16) { + netdev_err(netdev, + "rx ring size %u invalid, min is 16\n", + ring->rx_pending); + return -EINVAL; + } + rx_count = Q_COUNT(Q_SIZE(rx_count, 3)); /* Due pipelining impact minimum 2000 unused SQ CQE's -- cgit v1.2.3 From a48e232210009be50591fdea8ba7c07b0f566a13 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Thu, 4 Dec 2025 15:13:32 +0800 Subject: net: stmmac: fix the crash issue for zero copy XDP_TX action There is a crash issue when running zero copy XDP_TX action, the crash log is shown below. [ 216.122464] Unable to handle kernel paging request at virtual address fffeffff80000000 [ 216.187524] Internal error: Oops: 0000000096000144 [#1] SMP [ 216.301694] Call trace: [ 216.304130] dcache_clean_poc+0x20/0x38 (P) [ 216.308308] __dma_sync_single_for_device+0x1bc/0x1e0 [ 216.313351] stmmac_xdp_xmit_xdpf+0x354/0x400 [ 216.317701] __stmmac_xdp_run_prog+0x164/0x368 [ 216.322139] stmmac_napi_poll_rxtx+0xba8/0xf00 [ 216.326576] __napi_poll+0x40/0x218 [ 216.408054] Kernel panic - not syncing: Oops: Fatal exception in interrupt For XDP_TX action, the xdp_buff is converted to xdp_frame by xdp_convert_buff_to_frame(). The memory type of the resulting xdp_frame depends on the memory type of the xdp_buff. For page pool based xdp_buff it produces xdp_frame with memory type MEM_TYPE_PAGE_POOL. For zero copy XSK pool based xdp_buff it produces xdp_frame with memory type MEM_TYPE_PAGE_ORDER0. However, stmmac_xdp_xmit_back() does not check the memory type and always uses the page pool type, this leads to invalid mappings and causes the crash. Therefore, check the xdp_buff memory type in stmmac_xdp_xmit_back() to fix this issue. Fixes: bba2556efad6 ("net: stmmac: Enable RX via AF_XDP zero-copy") Signed-off-by: Wei Fang Reviewed-by: Hariprasad Kelam Link: https://patch.msgid.link/20251204071332.1907111-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index da206b24aaed..b3730312aeed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -89,6 +89,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address"); #define STMMAC_XDP_CONSUMED BIT(0) #define STMMAC_XDP_TX BIT(1) #define STMMAC_XDP_REDIRECT BIT(2) +#define STMMAC_XSK_CONSUMED BIT(3) static int flow_ctrl = 0xdead; module_param(flow_ctrl, int, 0644); @@ -5126,6 +5127,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv, static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, struct xdp_buff *xdp) { + bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL); struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); int cpu = smp_processor_id(); struct netdev_queue *nq; @@ -5142,9 +5144,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, /* Avoids TX time-out as we are sharing with slow path */ txq_trans_cond_update(nq); - res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false); - if (res == STMMAC_XDP_TX) + /* For zero copy XDP_TX action, dma_map is true */ + res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc); + if (res == STMMAC_XDP_TX) { stmmac_flush_tx_descriptors(priv, queue); + } else if (res == STMMAC_XDP_CONSUMED && zc) { + /* xdp has been freed by xdp_convert_buff_to_frame(), + * no need to call xsk_buff_free() again, so return + * STMMAC_XSK_CONSUMED. + */ + res = STMMAC_XSK_CONSUMED; + xdp_return_frame(xdpf); + } __netif_tx_unlock(nq); @@ -5494,6 +5505,8 @@ read_again: break; case STMMAC_XDP_CONSUMED: xsk_buff_free(buf->xdp); + fallthrough; + case STMMAC_XSK_CONSUMED: rx_dropped++; break; case STMMAC_XDP_TX: -- cgit v1.2.3 From 3d970eda003441f66551a91fda16478ac0711617 Mon Sep 17 00:00:00 2001 From: Ankit Garg Date: Fri, 19 Dec 2025 10:29:45 +0000 Subject: gve: defer interrupt enabling until NAPI registration Currently, interrupts are automatically enabled immediately upon request. This allows interrupt to fire before the associated NAPI context is fully initialized and cause failures like below: [ 0.946369] Call Trace: [ 0.946369] [ 0.946369] __napi_poll+0x2a/0x1e0 [ 0.946369] net_rx_action+0x2f9/0x3f0 [ 0.946369] handle_softirqs+0xd6/0x2c0 [ 0.946369] ? handle_edge_irq+0xc1/0x1b0 [ 0.946369] __irq_exit_rcu+0xc3/0xe0 [ 0.946369] common_interrupt+0x81/0xa0 [ 0.946369] [ 0.946369] [ 0.946369] asm_common_interrupt+0x22/0x40 [ 0.946369] RIP: 0010:pv_native_safe_halt+0xb/0x10 Use the `IRQF_NO_AUTOEN` flag when requesting interrupts to prevent auto enablement and explicitly enable the interrupt in NAPI initialization path (and disable it during NAPI teardown). This ensures that interrupt lifecycle is strictly coupled with readiness of NAPI context. Cc: stable@vger.kernel.org Fixes: 1dfc2e46117e ("gve: Refactor napi add and remove functions") Signed-off-by: Ankit Garg Reviewed-by: Jordan Rhee Reviewed-by: Joshua Washington Signed-off-by: Harshitha Ramamurthy Link: https://patch.msgid.link/20251219102945.2193617-1-hramamurthy@google.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/google/gve/gve_main.c | 2 +- drivers/net/ethernet/google/gve/gve_utils.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index a7a088a77f37..7eb64e1e4d85 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -558,7 +558,7 @@ static int gve_alloc_notify_blocks(struct gve_priv *priv) block->priv = priv; err = request_irq(priv->msix_vectors[msix_idx].vector, gve_is_gqi(priv) ? gve_intr : gve_intr_dqo, - 0, block->name, block); + IRQF_NO_AUTOEN, block->name, block); if (err) { dev_err(&priv->pdev->dev, "Failed to receive msix vector %d\n", i); diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index ace9b8698021..b53b7fcdcdaf 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -112,11 +112,13 @@ void gve_add_napi(struct gve_priv *priv, int ntfy_idx, netif_napi_add_locked(priv->dev, &block->napi, gve_poll); netif_napi_set_irq_locked(&block->napi, block->irq); + enable_irq(block->irq); } void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) { struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + disable_irq(block->irq); netif_napi_del_locked(&block->napi); } -- cgit v1.2.3 From e34f0df3d81ad4ae7819f14f7a9dcd2efcfbe8c1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 19 Dec 2025 14:44:59 +0000 Subject: usbnet: avoid a possible crash in dql_completed() syzbot reported a crash [1] in dql_completed() after recent usbnet BQL adoption. The reason for the crash is that netdev_reset_queue() is called too soon. It should be called after cancel_work_sync(&dev->bh_work) to make sure no more TX completion can happen. [1] kernel BUG at lib/dynamic_queue_limits.c:99 ! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 1 UID: 0 PID: 5197 Comm: udevd Tainted: G L syzkaller #0 PREEMPT(full) Tainted: [L]=SOFTLOCKUP Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 RIP: 0010:dql_completed+0xbe1/0xbf0 lib/dynamic_queue_limits.c:99 Call Trace: netdev_tx_completed_queue include/linux/netdevice.h:3864 [inline] netdev_completed_queue include/linux/netdevice.h:3894 [inline] usbnet_bh+0x793/0x1020 drivers/net/usb/usbnet.c:1601 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0xad1/0x1770 kernel/workqueue.c:3340 bh_worker+0x2b1/0x600 kernel/workqueue.c:3611 tasklet_action+0xc/0x70 kernel/softirq.c:952 handle_softirqs+0x27d/0x850 kernel/softirq.c:622 __do_softirq kernel/softirq.c:656 [inline] invoke_softirq kernel/softirq.c:496 [inline] __irq_exit_rcu+0xca/0x1f0 kernel/softirq.c:723 irq_exit_rcu+0x9/0x30 kernel/softirq.c:739 Fixes: 7ff14c52049e ("usbnet: Add support for Byte Queue Limits (BQL)") Reported-by: syzbot+5b55e49f8bbd84631a9c@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6945644f.a70a0220.207337.0113.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Simon Schippers Link: https://patch.msgid.link/20251219144459.692715-1-edumazet@google.com Signed-off-by: Paolo Abeni --- drivers/net/usb/usbnet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1d9faa70ba3b..36742e64cff7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -831,7 +831,6 @@ int usbnet_stop(struct net_device *net) clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue(net); - netdev_reset_queue(net); netif_info(dev, ifdown, dev->net, "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", @@ -875,6 +874,8 @@ int usbnet_stop(struct net_device *net) timer_delete_sync(&dev->delay); cancel_work_sync(&dev->kevent); + netdev_reset_queue(net); + if (!pm) usb_autopm_put_interface(dev->intf); -- cgit v1.2.3 From 3c68cf68233e556e0102f45b69f7448908dc1f44 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Fri, 26 Dec 2025 17:41:12 +0800 Subject: IB/rxe: Fix missing umem_odp->umem_mutex unlock on error path rxe_odp_map_range_and_lock() must release umem_odp->umem_mutex when an error occurs, including cases where rxe_check_pagefault() fails. Fixes: 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP") Signed-off-by: Li Zhijian Link: https://patch.msgid.link/20251226094112.3042583-1-lizhijian@fujitsu.com Reviewed-by: Zhu Yanjun Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/rxe/rxe_odp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c index ae71812bea82..c928cbf2e35f 100644 --- a/drivers/infiniband/sw/rxe/rxe_odp.c +++ b/drivers/infiniband/sw/rxe/rxe_odp.c @@ -179,8 +179,10 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u return err; need_fault = rxe_check_pagefault(umem_odp, iova, length); - if (need_fault) + if (need_fault) { + mutex_unlock(&umem_odp->umem_mutex); return -EFAULT; + } } return 0; -- cgit v1.2.3 From fa0b198be1c6775bc7804731a43be5d899d19e7a Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sun, 21 Dec 2025 00:24:00 -0800 Subject: net: usb: sr9700: fix incorrect command used to write single register This fixes the device failing to initialize with "error reading MAC address" for me, probably because the incorrect write of NCR_RST to SR_NCR is not actually resetting the device. Fixes: c9b37458e95629b1d1171457afdcc1bf1eb7881d ("USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700Device Driver Support") Cc: stable@vger.kernel.org Signed-off-by: Ethan Nelson-Moore Link: https://patch.msgid.link/20251221082400.50688-1-enelsonmoore@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/usb/sr9700.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index d8ffb59eaf34..820c4c506979 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -52,7 +52,7 @@ static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) { - return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, + return usbnet_write_cmd(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } @@ -65,7 +65,7 @@ static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) { - usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, + usbnet_write_cmd_async(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } -- cgit v1.2.3 From 99537d5c476cada9cf75aef9fa75579a31faadb9 Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Mon, 22 Dec 2025 09:56:24 +0800 Subject: net: macb: Relocate mog_init_rings() callback from macb_mac_link_up() to macb_open() In the non-RT kernel, local_bh_disable() merely disables preemption, whereas it maps to an actual spin lock in the RT kernel. Consequently, when attempting to refill RX buffers via netdev_alloc_skb() in macb_mac_link_up(), a deadlock scenario arises as follows: WARNING: possible circular locking dependency detected 6.18.0-08691-g2061f18ad76e #39 Not tainted ------------------------------------------------------ kworker/0:0/8 is trying to acquire lock: ffff00080369bbe0 (&bp->lock){+.+.}-{3:3}, at: macb_start_xmit+0x808/0xb7c but task is already holding lock: ffff000803698e58 (&queue->tx_ptr_lock){+...}-{3:3}, at: macb_start_xmit +0x148/0xb7c which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&queue->tx_ptr_lock){+...}-{3:3}: rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x148/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #2 (_xmit_ETHER#2){+...}-{3:3}: rt_spin_lock+0x50/0x1f0 sch_direct_xmit+0x11c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #1 ((softirq_ctrl.lock)){+.+.}-{3:3}: lock_release+0x250/0x348 __local_bh_enable_ip+0x7c/0x240 __netdev_alloc_skb+0x1b4/0x1d8 gem_rx_refill+0xdc/0x240 gem_init_rings+0xb4/0x108 macb_mac_link_up+0x9c/0x2b4 phylink_resolve+0x170/0x614 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 -> #0 (&bp->lock){+.+.}-{3:3}: __lock_acquire+0x15a8/0x2084 lock_acquire+0x1cc/0x350 rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x808/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 other info that might help us debug this: Chain exists of: &bp->lock --> _xmit_ETHER#2 --> &queue->tx_ptr_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&queue->tx_ptr_lock); lock(_xmit_ETHER#2); lock(&queue->tx_ptr_lock); lock(&bp->lock); *** DEADLOCK *** Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0xa0/0xf0 dump_stack+0x18/0x24 print_circular_bug+0x28c/0x370 check_noncircular+0x198/0x1ac __lock_acquire+0x15a8/0x2084 lock_acquire+0x1cc/0x350 rt_spin_lock+0x50/0x1f0 macb_start_xmit+0x808/0xb7c dev_hard_start_xmit+0x94/0x284 sch_direct_xmit+0x8c/0x37c __dev_queue_xmit+0x708/0x1120 neigh_resolve_output+0x148/0x28c ip6_finish_output2+0x2c0/0xb2c __ip6_finish_output+0x114/0x308 ip6_output+0xc4/0x4a4 mld_sendpack+0x220/0x68c mld_ifc_work+0x2a8/0x4f4 process_one_work+0x20c/0x5f8 worker_thread+0x1b0/0x35c kthread+0x144/0x200 ret_from_fork+0x10/0x20 Notably, invoking the mog_init_rings() callback upon link establishment is unnecessary. Instead, we can exclusively call mog_init_rings() within the ndo_open() callback. This adjustment resolves the deadlock issue. Furthermore, since MACB_CAPS_MACB_IS_EMAC cases do not use mog_init_rings() when opening the network interface via at91ether_open(), moving mog_init_rings() to macb_open() also eliminates the MACB_CAPS_MACB_IS_EMAC check. Fixes: 633e98a711ac ("net: macb: use resolved link config in mac_link_up()") Cc: stable@vger.kernel.org Suggested-by: Kevin Hao Signed-off-by: Xiaolei Wang Link: https://patch.msgid.link/20251222015624.1994551-1-xiaolei.wang@windriver.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cadence/macb_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index e461f5072884..6511ecd5856b 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -708,7 +708,6 @@ static void macb_mac_link_up(struct phylink_config *config, /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. */ - bp->macbgem_ops.mog_init_rings(bp); macb_init_buffers(bp); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) @@ -2954,6 +2953,8 @@ static int macb_open(struct net_device *dev) goto pm_exit; } + bp->macbgem_ops.mog_init_rings(bp); + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { napi_enable(&queue->napi_rx); napi_enable(&queue->napi_tx); -- cgit v1.2.3 From 5939b6dbcda8b0f5f03a8e5179c13dc0195eb6cd Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Mon, 22 Dec 2025 10:26:28 +0800 Subject: net: enetc: do not print error log if addr is 0 A value of 0 for addr indicates that the IEB_LBCR register does not need to be configured, as its default value is 0. However, the driver will print an error log if addr is 0, so this issue needs to be fixed. Fixes: 50bfd9c06f0f ("net: enetc: set external PHY address in IERB for i.MX94 ENETC") Signed-off-by: Wei Fang Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/20251222022628.4016403-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c index 443983fdecd9..7fd39f895290 100644 --- a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c +++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c @@ -577,11 +577,17 @@ static int imx94_enetc_mdio_phyaddr_config(struct netc_blk_ctrl *priv, } addr = netc_get_phy_addr(np); - if (addr <= 0) { + if (addr < 0) { dev_err(dev, "Failed to get PHY address\n"); return addr; } + /* The default value of LaBCR[MDIO_PHYAD_PRTAD] is 0, + * so no need to set the register. + */ + if (!addr) + return 0; + if (phy_mask & BIT(addr)) { dev_err(dev, "Find same PHY address in EMDIO and ENETC node\n"); -- cgit v1.2.3 From 43bd09d5b750f700499ae8ec45fd41a4c48673e6 Mon Sep 17 00:00:00 2001 From: Honggang LI Date: Mon, 29 Dec 2025 10:56:17 +0800 Subject: RDMA/rtrs: Fix clt_path::max_pages_per_mr calculation If device max_mr_size bits in the range [mr_page_shift+31:mr_page_shift] are zero, the `min3` function will set clt_path::max_pages_per_mr to zero. `alloc_path_reqs` will pass zero, which is invalid, as the third parameter to `ib_alloc_mr`. Fixes: 6a98d71daea1 ("RDMA/rtrs: client: main functionality") Signed-off-by: Honggang LI Link: https://patch.msgid.link/20251229025617.13241-1-honggangli@163.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 71387811b281..2b397a544cb9 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1464,6 +1464,7 @@ static void query_fast_reg_mode(struct rtrs_clt_path *clt_path) mr_page_shift = max(12, ffs(ib_dev->attrs.page_size_cap) - 1); max_pages_per_mr = ib_dev->attrs.max_mr_size; do_div(max_pages_per_mr, (1ull << mr_page_shift)); + max_pages_per_mr = min_not_zero((u32)max_pages_per_mr, U32_MAX); clt_path->max_pages_per_mr = min3(clt_path->max_pages_per_mr, (u32)max_pages_per_mr, ib_dev->attrs.max_fast_reg_page_list_len); -- cgit v1.2.3 From c6703f10c8cc36f53b867bdbdd5bacaaa47ce799 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Mon, 29 Dec 2025 21:44:58 +0100 Subject: platform/x86: asus-armoury: add support for G835LW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add TDP data for laptop model G835LW. Signed-off-by: Denis Benato Link: https://patch.msgid.link/20251229204458.2658777-1-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index 68b174b70a66..3ac7aea37838 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -1567,6 +1567,35 @@ static const struct dmi_system_id power_limits[] = { .requires_fan_curve = true, }, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G835LW"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 140, + .ppt_pl1_spl_max = 175, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_max = 150, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "H7606W"), -- cgit v1.2.3 From fcd431a9627f272b4c0bec445eba365fe2232a94 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 30 Dec 2025 09:51:21 +0100 Subject: RDMA/bnxt_re: fix dma_free_coherent() pointer The dma_alloc_coherent() allocates a dma-mapped buffer, pbl->pg_arr[i]. The dma_free_coherent() should pass the same buffer to dma_free_coherent() and not page-aligned. Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver") Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20251230085121.8023-2-fourier.thomas@gmail.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index d5c12a51aa43..4d674a3aee1a 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -64,9 +64,7 @@ static void __free_pbl(struct bnxt_qplib_res *res, struct bnxt_qplib_pbl *pbl, for (i = 0; i < pbl->pg_count; i++) { if (pbl->pg_arr[i]) dma_free_coherent(&pdev->dev, pbl->pg_size, - (void *)((unsigned long) - pbl->pg_arr[i] & - PAGE_MASK), + pbl->pg_arr[i], pbl->pg_map_arr[i]); else dev_warn(&pdev->dev, -- cgit v1.2.3 From 0cc13256b60510936c34098ee7b929098eed823b Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 26 Nov 2025 13:47:18 +0530 Subject: PCI: qcom: Remove ASPM L0s support for MSM8996 SoC Though I couldn't confirm ASPM L0s support with the Qcom hardware team, a bug report from Dmitry suggests that L0s is broken on this legacy SoC. Hence, remove L0s support from the Root Port Link Capabilities in this SoC. Since qcom_pcie_clear_aspm_l0s() is now used by more than one SoC config, call it from qcom_pcie_host_init() instead. Reported-by: Dmitry Baryshkov Closes: https://lore.kernel.org/linux-pci/4cp5pzmlkkht2ni7us6p3edidnk25l45xrp6w3fxguqcvhq2id@wjqqrdpkypkf Signed-off-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20251126081718.8239-1-mani@kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 7b92e7a1c0d9..5a318487b2b3 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1047,7 +1047,6 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) writel(WR_NO_SNOOP_OVERRIDE_EN | RD_NO_SNOOP_OVERRIDE_EN, pcie->parf + PARF_NO_SNOOP_OVERRIDE); - qcom_pcie_clear_aspm_l0s(pcie->pci); qcom_pcie_clear_hpc(pcie->pci); return 0; @@ -1316,6 +1315,8 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp) goto err_disable_phy; } + qcom_pcie_clear_aspm_l0s(pcie->pci); + qcom_ep_reset_deassert(pcie); if (pcie->cfg->ops->config_sid) { @@ -1464,6 +1465,7 @@ static const struct qcom_pcie_cfg cfg_2_1_0 = { static const struct qcom_pcie_cfg cfg_2_3_2 = { .ops = &ops_2_3_2, + .no_l0s = true, }; static const struct qcom_pcie_cfg cfg_2_3_3 = { -- cgit v1.2.3 From 4fe2bd195435e71c117983d87f278112c5ab364c Mon Sep 17 00:00:00 2001 From: Krzysztof Niemiec Date: Tue, 16 Dec 2025 19:09:01 +0100 Subject: drm/i915/gem: Zero-initialize the eb.vma array in i915_gem_do_execbuffer Initialize the eb.vma array with values of 0 when the eb structure is first set up. In particular, this sets the eb->vma[i].vma pointers to NULL, simplifying cleanup and getting rid of the bug described below. During the execution of eb_lookup_vmas(), the eb->vma array is successively filled up with struct eb_vma objects. This process includes calling eb_add_vma(), which might fail; however, even in the event of failure, eb->vma[i].vma is set for the currently processed buffer. If eb_add_vma() fails, eb_lookup_vmas() returns with an error, which prompts a call to eb_release_vmas() to clean up the mess. Since eb_lookup_vmas() might fail during processing any (possibly not first) buffer, eb_release_vmas() checks whether a buffer's vma is NULL to know at what point did the lookup function fail. In eb_lookup_vmas(), eb->vma[i].vma is set to NULL if either the helper function eb_lookup_vma() or eb_validate_vma() fails. eb->vma[i+1].vma is set to NULL in case i915_gem_object_userptr_submit_init() fails; the current one needs to be cleaned up by eb_release_vmas() at this point, so the next one is set. If eb_add_vma() fails, neither the current nor the next vma is set to NULL, which is a source of a NULL deref bug described in the issue linked in the Closes tag. When entering eb_lookup_vmas(), the vma pointers are set to the slab poison value, instead of NULL. This doesn't matter for the actual lookup, since it gets overwritten anyway, however the eb_release_vmas() function only recognizes NULL as the stopping value, hence the pointers are being set to NULL as they go in case of intermediate failure. This patch changes the approach to filling them all with NULL at the start instead, rather than handling that manually during failure. Reported-by: Gangmin Kim Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15062 Fixes: 544460c33821 ("drm/i915: Multi-BB execbuf") Cc: stable@vger.kernel.org # 5.16.x Signed-off-by: Krzysztof Niemiec Reviewed-by: Janusz Krzysztofik Reviewed-by: Krzysztof Karas Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://lore.kernel.org/r/20251216180900.54294-2-krzysztof.niemiec@intel.com (cherry picked from commit 08889b706d4f0b8d2352b7ca29c2d8df4d0787cd) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 37 ++++++++++++-------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index b057c2fa03a4..d49e96f9be51 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -951,13 +951,13 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) vma = eb_lookup_vma(eb, eb->exec[i].handle); if (IS_ERR(vma)) { err = PTR_ERR(vma); - goto err; + return err; } err = eb_validate_vma(eb, &eb->exec[i], vma); if (unlikely(err)) { i915_vma_put(vma); - goto err; + return err; } err = eb_add_vma(eb, ¤t_batch, i, vma); @@ -966,19 +966,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) if (i915_gem_object_is_userptr(vma->obj)) { err = i915_gem_object_userptr_submit_init(vma->obj); - if (err) { - if (i + 1 < eb->buffer_count) { - /* - * Execbuffer code expects last vma entry to be NULL, - * since we already initialized this entry, - * set the next value to NULL or we mess up - * cleanup handling. - */ - eb->vma[i + 1].vma = NULL; - } - + if (err) return err; - } eb->vma[i].flags |= __EXEC_OBJECT_USERPTR_INIT; eb->args->flags |= __EXEC_USERPTR_USED; @@ -986,10 +975,6 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) } return 0; - -err: - eb->vma[i].vma = NULL; - return err; } static int eb_lock_vmas(struct i915_execbuffer *eb) @@ -3375,7 +3360,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.exec = exec; eb.vma = (struct eb_vma *)(exec + args->buffer_count + 1); - eb.vma[0].vma = NULL; + memset(eb.vma, 0, (args->buffer_count + 1) * sizeof(struct eb_vma)); + eb.batch_pool = NULL; eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; @@ -3584,7 +3570,18 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, if (err) return err; - /* Allocate extra slots for use by the command parser */ + /* + * Allocate extra slots for use by the command parser. + * + * Note that this allocation handles two different arrays (the + * exec2_list array, and the eventual eb.vma array introduced in + * i915_gem_do_execbuffer()), that reside in virtually contiguous + * memory. Also note that the allocation intentionally doesn't fill the + * area with zeros, because the exec2_list part doesn't need to be, as + * it's immediately overwritten by user data a few lines below. + * However, the eb.vma part is explicitly zeroed later in + * i915_gem_do_execbuffer(). + */ exec2_list = kvmalloc_array(count + 2, eb_element_size(), __GFP_NOWARN | GFP_KERNEL); if (exec2_list == NULL) { -- cgit v1.2.3 From 0ddd3bb4b14c9102c0267b3fd916c81fe5ab89c1 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 11 Dec 2025 16:33:44 +0400 Subject: drm/pl111: Fix error handling in pl111_amba_probe Jump to the existing dev_put label when devm_request_irq() fails so drm_dev_put() and of_reserved_mem_device_release() run instead of returning early and leaking resources. Found via static analysis and code review. Fixes: bed41005e617 ("drm/pl111: Initial drm/kms driver for pl111") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Javier Martinez Canillas Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251211123345.2392065-1-linmq006@gmail.com --- drivers/gpu/drm/pl111/pl111_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 56ff6a3fb483..d7dc83cf7b00 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -295,7 +295,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, variant->name, priv); if (ret != 0) { dev_err(dev, "%s failed irq %d\n", __func__, ret); - return ret; + goto dev_put; } ret = pl111_modeset_init(drm); -- cgit v1.2.3 From af7809f037e6e56f63a4d66b6a02826ce786af2c Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 30 Dec 2025 20:56:42 -0700 Subject: Revert "wifi: mt76: Strip whitespace from build ddate" This reverts commit f804a5895ebad2b2d4fb8a3688d2115926e993d5. This change introduced the following panic, and mt792x_load_firmware() fails. wifi is dead on systems with mt792x wireless. kern :crit : kernel BUG at lib/string_helpers.c:1043! kern :warn : Oops: invalid opcode: 0000 [#1] SMP NOPTI kern :warn : CPU: 14 UID: 0 PID: 61 Comm: kworker/14:0 Tainted: G W 6.19.0-rc1 #1 PREEMPT(voluntary) kern :warn : Tainted: [W]=WARN kern :warn : Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP07, BIOS 03.16 07/25/2025 kern :warn : Workqueue: events mt7921_init_work [mt7921_common] kern :warn : RIP: 0010:__fortify_panic+0xd/0xf kern :warn : Code: 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 40 0f b6 ff e8 c3 55 71 00 <0f> 0b 48 8b 54 24 10 48 8b 74 24 08 4c 89 e9 48 c7 c7 00 a2 d5 a0 kern :warn : RSP: 0018:ffffa7a5c03a3d10 EFLAGS: 00010246 kern :warn : RAX: ffffffffa0d7aaf2 RBX: 0000000000000000 RCX: ffffffffa0d7aaf2 kern :warn : RDX: 0000000000000011 RSI: ffffffffa0d5a170 RDI: ffffffffa128db10 kern :warn : RBP: ffff91650ae52060 R08: 0000000000000010 R09: ffffa7a5c31b2000 kern :warn : R10: ffffa7a5c03a3bf0 R11: 00000000ffffffff R12: 0000000000000000 kern :warn : R13: ffffa7a5c31b2000 R14: 0000000000001000 R15: 0000000000000000 kern :warn : FS: 0000000000000000(0000) GS:ffff91743e664000(0000) knlGS:0000000000000000 kern :warn : CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 kern :warn : CR2: 00007f10786c241c CR3: 00000003eca24000 CR4: 0000000000f50ef0 kern :warn : PKRU: 55555554 kern :warn : Call Trace: kern :warn : kern :warn : mt76_connac2_load_patch.cold+0x2b/0xa41 [mt76_connac_lib] kern :warn : ? srso_alias_return_thunk+0x5/0xfbef5 kern :warn : mt792x_load_firmware+0x36/0x150 [mt792x_lib] kern :warn : mt7921_run_firmware+0x2c/0x4a0 [mt7921_common] kern :warn : ? srso_alias_return_thunk+0x5/0xfbef5 kern :warn : ? mt7921_rr+0x12/0x30 [mt7921e] kern :warn : ? srso_alias_return_thunk+0x5/0xfbef5 kern :warn : ? ____mt76_poll_msec+0x75/0xb0 [mt76] kern :warn : mt7921e_mcu_init+0x4c/0x7a [mt7921e] kern :warn : mt7921_init_work+0x51/0x190 [mt7921_common] kern :warn : process_one_work+0x18b/0x340 kern :warn : worker_thread+0x256/0x3a0 kern :warn : ? __pfx_worker_thread+0x10/0x10 kern :warn : kthread+0xfc/0x240 kern :warn : ? __pfx_kthread+0x10/0x10 kern :warn : ? __pfx_kthread+0x10/0x10 kern :warn : ret_from_fork+0x254/0x290 kern :warn : ? __pfx_kthread+0x10/0x10 kern :warn : ret_from_fork_asm+0x1a/0x30 kern :warn : Signed-off-by: Shuah Khan Signed-off-by: Linus Torvalds --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ea99167765b0..fba7025ffd3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -3101,7 +3101,6 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; const struct mt76_connac2_patch_hdr *hdr; const struct firmware *fw = NULL; - char build_date[17]; sem = mt76_connac_mcu_patch_sem_ctrl(dev, true); switch (sem) { @@ -3125,11 +3124,8 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) } hdr = (const void *)fw->data; - strscpy(build_date, hdr->build_date, sizeof(build_date)); - build_date[16] = '\0'; - strim(build_date); dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", - be32_to_cpu(hdr->hw_sw_ver), build_date); + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { struct mt76_connac2_patch_sec *sec; -- cgit v1.2.3 From b69053dd3ffbc0d2dedbbc86182cdef6f641fe1b Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 31 Dec 2025 16:46:26 -0700 Subject: wifi: mt76: Remove blank line after mt792x firmware version dmesg An extra blank line gets printed after printing firmware version because the build date is null terminated. Remove the "\n" from dev_info() calls to print firmware version and build date to fix the problem. Reported-by: Mario Limonciello Signed-off-by: Shuah Khan Signed-off-by: Linus Torvalds --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index fba7025ffd3f..0457712286d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -3019,7 +3019,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false); @@ -3048,7 +3048,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", + dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true); @@ -3124,7 +3124,7 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) } hdr = (const void *)fw->data; - dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", + dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { -- cgit v1.2.3 From bc277212b41ade2137b6278db24652d0847e9a91 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Fri, 19 Dec 2025 12:56:31 +0100 Subject: pinctrl: pic64gx-gpio2: Add REGMAP_MMIO dependency In line with other drivers depending on REGMAP_*, select the required symbol to prevent a linker error when building with COMPILE_TEST=y: ld: drivers/pinctrl/pinctrl-pic64gx-gpio2.o: in function `pic64gx_gpio2_probe': pinctrl-pic64gx-gpio2.c:315:(.text+0x198): undefined reference to `__devm_regmap_init_mmio_clk' Fixes: 38cf9d641314 ("pinctrl: add pic64gx "gpio2" pinmux driver") Signed-off-by: Sander Vanheule Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index bc7f37afc48b..7b9f792acb0e 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -491,6 +491,7 @@ config PINCTRL_PIC64GX depends on ARCH_MICROCHIP || COMPILE_TEST depends on OF select GENERIC_PINCONF + select REGMAP_MMIO default y help This selects the pinctrl driver for gpio2 on pic64gx. -- cgit v1.2.3 From ebc18e9854e5a2b62a041fb57b216a903af45b85 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 26 Nov 2025 13:22:19 +0100 Subject: pinctrl: qcom: lpass-lpi: mark the GPIO controller as sleeping The gpio_chip settings in this driver say the controller can't sleep but it actually uses a mutex for synchronization. This triggers the following BUG(): [ 9.233659] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:281 [ 9.233665] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 554, name: (udev-worker) [ 9.233669] preempt_count: 1, expected: 0 [ 9.233673] RCU nest depth: 0, expected: 0 [ 9.233688] Tainted: [W]=WARN [ 9.233690] Hardware name: Dell Inc. Latitude 7455/0FK7MX, BIOS 2.10.1 05/20/2025 [ 9.233694] Call trace: [ 9.233696] show_stack+0x24/0x38 (C) [ 9.233709] dump_stack_lvl+0x40/0x88 [ 9.233716] dump_stack+0x18/0x24 [ 9.233722] __might_resched+0x148/0x160 [ 9.233731] __might_sleep+0x38/0x98 [ 9.233736] mutex_lock+0x30/0xd8 [ 9.233749] lpi_config_set+0x2e8/0x3c8 [pinctrl_lpass_lpi] [ 9.233757] lpi_gpio_direction_output+0x58/0x90 [pinctrl_lpass_lpi] [ 9.233761] gpiod_direction_output_raw_commit+0x110/0x428 [ 9.233772] gpiod_direction_output_nonotify+0x234/0x358 [ 9.233779] gpiod_direction_output+0x38/0xd0 [ 9.233786] gpio_shared_proxy_direction_output+0xb8/0x2a8 [gpio_shared_proxy] [ 9.233792] gpiod_direction_output_raw_commit+0x110/0x428 [ 9.233799] gpiod_direction_output_nonotify+0x234/0x358 [ 9.233806] gpiod_configure_flags+0x2c0/0x580 [ 9.233812] gpiod_find_and_request+0x358/0x4f8 [ 9.233819] gpiod_get_index+0x7c/0x98 [ 9.233826] devm_gpiod_get+0x34/0xb0 [ 9.233829] reset_gpio_probe+0x58/0x128 [reset_gpio] [ 9.233836] auxiliary_bus_probe+0xb0/0xf0 [ 9.233845] really_probe+0x14c/0x450 [ 9.233853] __driver_probe_device+0xb0/0x188 [ 9.233858] driver_probe_device+0x4c/0x250 [ 9.233863] __driver_attach+0xf8/0x2a0 [ 9.233868] bus_for_each_dev+0xf8/0x158 [ 9.233872] driver_attach+0x30/0x48 [ 9.233876] bus_add_driver+0x158/0x2b8 [ 9.233880] driver_register+0x74/0x118 [ 9.233886] __auxiliary_driver_register+0x94/0xe8 [ 9.233893] init_module+0x34/0xfd0 [reset_gpio] [ 9.233898] do_one_initcall+0xec/0x300 [ 9.233903] do_init_module+0x64/0x260 [ 9.233910] load_module+0x16c4/0x1900 [ 9.233915] __arm64_sys_finit_module+0x24c/0x378 [ 9.233919] invoke_syscall+0x4c/0xe8 [ 9.233925] el0_svc_common+0x8c/0xf0 [ 9.233929] do_el0_svc+0x28/0x40 [ 9.233934] el0_svc+0x38/0x100 [ 9.233938] el0t_64_sync_handler+0x84/0x130 [ 9.233943] el0t_64_sync+0x17c/0x180 Mark the controller as sleeping. Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") Cc: stable@vger.kernel.org Reported-by: Val Packett Closes: https://lore.kernel.org/all/98c0f185-b0e0-49ea-896c-f3972dd011ca@packett.cool/ Signed-off-by: Bartosz Golaszewski Reviewed-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 1c97ec44aa5f..78212f992843 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -498,7 +498,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev) pctrl->chip.base = -1; pctrl->chip.ngpio = data->npins; pctrl->chip.label = dev_name(dev); - pctrl->chip.can_sleep = false; + pctrl->chip.can_sleep = true; mutex_init(&pctrl->lock); -- cgit v1.2.3 From 9700b0fccf386b671e6f8401ddea6c5669cd0914 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Dec 2025 11:01:26 +0100 Subject: gpiolib: allow multiple lookup tables per consumer The GPIO machine lookup mechanism dates back to old ARM board files where lookup tables would all be defined in a single place. Since then, lookup tables have also been used to address various DT and ACPI quirks like missing GPIOs and - as of recently - setting up shared GPIO proxy devices. The lookup itself stops when we find the first matching table for a consumer and - if it doesn't contain the right entry - the lookup fails. Since the tables can now be defined in multiple places and we can't know how many there are, effectively limiting a consumer to only a single lookup table is no longer viable. Rework the code to always look through all tables matching the consumer. Link: https://lore.kernel.org/r/20251222-gpio-shared-reset-gpio-proxy-v1-1-8d4bba7d8c14@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 91 +++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 91e0c384f34a..6d583b3b07bb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4508,45 +4508,41 @@ void gpiod_remove_hogs(struct gpiod_hog *hogs) } EXPORT_SYMBOL_GPL(gpiod_remove_hogs); -static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) +static bool gpiod_match_lookup_table(struct device *dev, + const struct gpiod_lookup_table *table) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct gpiod_lookup_table *table; - list_for_each_entry(table, &gpio_lookup_list, list) { - if (table->dev_id && dev_id) { - /* - * Valid strings on both ends, must be identical to have - * a match - */ - if (!strcmp(table->dev_id, dev_id)) - return table; - } else { - /* - * One of the pointers is NULL, so both must be to have - * a match - */ - if (dev_id == table->dev_id) - return table; - } + lockdep_assert_held(&gpio_lookup_lock); + + if (table->dev_id && dev_id) { + /* + * Valid strings on both ends, must be identical to have + * a match + */ + if (!strcmp(table->dev_id, dev_id)) + return true; + } else { + /* + * One of the pointers is NULL, so both must be to have + * a match + */ + if (dev_id == table->dev_id) + return true; } - return NULL; + return false; } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, unsigned long *flags) +static struct gpio_desc *gpio_desc_table_match(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags, + struct gpiod_lookup_table *table) { - struct gpio_desc *desc = ERR_PTR(-ENOENT); - struct gpiod_lookup_table *table; + struct gpio_desc *desc; struct gpiod_lookup *p; struct gpio_chip *gc; - guard(mutex)(&gpio_lookup_lock); - - table = gpiod_find_lookup_table(dev); - if (!table) - return desc; + lockdep_assert_held(&gpio_lookup_lock); for (p = &table->table[0]; p->key; p++) { /* idx must always match exactly */ @@ -4600,6 +4596,29 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } + return NULL; +} + +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + struct gpio_desc *desc = ERR_PTR(-ENOENT); + struct gpiod_lookup_table *table; + + guard(mutex)(&gpio_lookup_lock); + + list_for_each_entry(table, &gpio_lookup_list, list) { + if (!gpiod_match_lookup_table(dev, table)) + continue; + + desc = gpio_desc_table_match(dev, con_id, idx, flags, table); + if (!desc) + continue; + + /* On IS_ERR() or match. */ + return desc; + } + return desc; } @@ -4610,14 +4629,16 @@ static int platform_gpio_count(struct device *dev, const char *con_id) unsigned int count = 0; scoped_guard(mutex, &gpio_lookup_lock) { - table = gpiod_find_lookup_table(dev); - if (!table) - return -ENOENT; + list_for_each_entry(table, &gpio_lookup_list, list) { + if (!gpiod_match_lookup_table(dev, table)) + continue; - for (p = &table->table[0]; p->key; p++) { - if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || - (!con_id && !p->con_id)) - count++; + for (p = &table->table[0]; p->key; p++) { + if ((con_id && p->con_id && + !strcmp(con_id, p->con_id)) || + (!con_id && !p->con_id)) + count++; + } } } -- cgit v1.2.3 From cb0451e33be047fff7137f58d9996370e11fb344 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Dec 2025 11:01:27 +0100 Subject: gpio: shared: verify con_id when adding proxy lookup When matching the firmware node with the potential consumer, we currently omit the con_id string. This can lead to false positives in the unlikely case of the consumer having been assigned more than one shared GPIO. Check the connector ID before proceeding. Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Link: https://lore.kernel.org/r/20251222-gpio-shared-reset-gpio-proxy-v1-2-8d4bba7d8c14@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 7 ++++++- drivers/gpio/gpiolib-shared.h | 4 +++- drivers/gpio/gpiolib.c | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index ba4b718d40a0..f589109590c7 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -365,7 +365,8 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, } #endif /* CONFIG_RESET_GPIO */ -int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) +int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, + unsigned long lflags) { const char *dev_id = dev_name(consumer); struct gpio_shared_entry *entry; @@ -384,6 +385,10 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags) guard(mutex)(&ref->lock); + if ((!con_id && ref->con_id) || (con_id && !ref->con_id) || + (con_id && ref->con_id && strcmp(con_id, ref->con_id) != 0)) + continue; + /* We've already done that on a previous request. */ if (ref->lookup) return 0; diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h index 667dbdff3585..40568ef7364c 100644 --- a/drivers/gpio/gpiolib-shared.h +++ b/drivers/gpio/gpiolib-shared.h @@ -16,7 +16,8 @@ struct device; int gpio_device_setup_shared(struct gpio_device *gdev); void gpio_device_teardown_shared(struct gpio_device *gdev); -int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags); +int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, + unsigned long lflags); #else @@ -28,6 +29,7 @@ static inline int gpio_device_setup_shared(struct gpio_device *gdev) static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { } static inline int gpio_shared_add_proxy_lookup(struct device *consumer, + const char *con_id, unsigned long lflags) { return 0; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6d583b3b07bb..9ccfb7af67cc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4717,7 +4717,8 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer, * lookup table for the proxy device as previously * we only knew the consumer's fwnode. */ - ret = gpio_shared_add_proxy_lookup(consumer, lookupflags); + ret = gpio_shared_add_proxy_lookup(consumer, con_id, + lookupflags); if (ret) return ERR_PTR(ret); -- cgit v1.2.3 From 49416483a953662aa53c6d9bef651757d4a95ba5 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Dec 2025 11:01:28 +0100 Subject: gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib We currently support sharing GPIOs between multiple devices whose drivers use either the GPIOLIB API *OR* the reset control API but not both at the same time. There's an unlikely corner-case where a reset-gpios pin can be shared by one driver using the GPIOLIB API and a second using the reset API. This will currently not work as the reset-gpio consumers are not described in firmware at the time of scanning so the shared GPIO just chooses one of the proxies created for the consumers when the reset-gpio driver performs the lookup. This can of course conflict in the case described above. In order to fix it: if we deal with the "reset-gpios" pin that's shared acconding to the firmware node setup, create a proxy for each described consumer as well as another one for the potential reset-gpio device. To that end: rework the matching to take this into account. Fixes: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case") Link: https://lore.kernel.org/r/20251222-gpio-shared-reset-gpio-proxy-v1-3-8d4bba7d8c14@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 182 ++++++++++++++++++++++++++++++------------ 1 file changed, 129 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index f589109590c7..baf7e07a3bb8 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -76,6 +76,56 @@ gpio_shared_find_entry(struct fwnode_handle *controller_node, return NULL; } +static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode, + const char *con_id, + enum gpiod_flags flags) +{ + char *con_id_cpy __free(kfree) = NULL; + + struct gpio_shared_ref *ref __free(kfree) = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return NULL; + + if (con_id) { + con_id_cpy = kstrdup(con_id, GFP_KERNEL); + if (!con_id_cpy) + return NULL; + } + + ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL); + if (ref->dev_id < 0) + return NULL; + + ref->flags = flags; + ref->con_id = no_free_ptr(con_id_cpy); + ref->fwnode = fwnode; + mutex_init(&ref->lock); + + return no_free_ptr(ref); +} + +static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry, + enum gpiod_flags flags) +{ + struct gpio_shared_ref *ref; + + list_for_each_entry(ref, &entry->refs, list) { + if (!ref->fwnode && ref->con_id && strcmp(ref->con_id, "reset") == 0) + return 0; + } + + ref = gpio_shared_make_ref(NULL, "reset", flags); + if (!ref) + return -ENOMEM; + + list_add_tail(&ref->list, &entry->refs); + + pr_debug("Created a secondary shared GPIO reference for potential reset-gpio device for GPIO %u at %s\n", + entry->offset, fwnode_get_name(entry->fwnode)); + + return 0; +} + /* Handle all special nodes that we should ignore. */ static bool gpio_shared_of_node_ignore(struct device_node *node) { @@ -106,6 +156,7 @@ static int gpio_shared_of_traverse(struct device_node *curr) size_t con_id_len, suffix_len; struct fwnode_handle *fwnode; struct of_phandle_args args; + struct gpio_shared_ref *ref; struct property *prop; unsigned int offset; const char *suffix; @@ -138,6 +189,7 @@ static int gpio_shared_of_traverse(struct device_node *curr) for (i = 0; i < count; i++) { struct device_node *np __free(device_node) = NULL; + char *con_id __free(kfree) = NULL; ret = of_parse_phandle_with_args(curr, prop->name, "#gpio-cells", i, @@ -182,15 +234,6 @@ static int gpio_shared_of_traverse(struct device_node *curr) list_add_tail(&entry->list, &gpio_shared_list); } - struct gpio_shared_ref *ref __free(kfree) = - kzalloc(sizeof(*ref), GFP_KERNEL); - if (!ref) - return -ENOMEM; - - ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr)); - ref->flags = args.args[1]; - mutex_init(&ref->lock); - if (strends(prop->name, "gpios")) suffix = "-gpios"; else if (strends(prop->name, "gpio")) @@ -202,27 +245,32 @@ static int gpio_shared_of_traverse(struct device_node *curr) /* We only set con_id if there's actually one. */ if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) { - ref->con_id = kstrdup(prop->name, GFP_KERNEL); - if (!ref->con_id) + con_id = kstrdup(prop->name, GFP_KERNEL); + if (!con_id) return -ENOMEM; - con_id_len = strlen(ref->con_id); + con_id_len = strlen(con_id); suffix_len = strlen(suffix); - ref->con_id[con_id_len - suffix_len] = '\0'; + con_id[con_id_len - suffix_len] = '\0'; } - ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL); - if (ref->dev_id < 0) { - kfree(ref->con_id); + ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)), + con_id, args.args[1]); + if (!ref) return -ENOMEM; - } if (!list_empty(&entry->refs)) pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n", entry->offset, fwnode_get_name(entry->fwnode)); - list_add_tail(&no_free_ptr(ref)->list, &entry->refs); + list_add_tail(&ref->list, &entry->refs); + + if (strcmp(prop->name, "reset-gpios") == 0) { + ret = gpio_shared_setup_reset_proxy(entry, args.args[1]); + if (ret) + return ret; + } } } @@ -306,20 +354,16 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, struct fwnode_handle *reset_fwnode = dev_fwnode(consumer); struct fwnode_reference_args ref_args, aux_args; struct device *parent = consumer->parent; + struct gpio_shared_ref *real_ref; bool match; int ret; + lockdep_assert_held(&ref->lock); + /* The reset-gpio device must have a parent AND a firmware node. */ if (!parent || !reset_fwnode) return false; - /* - * FIXME: use device_is_compatible() once the reset-gpio drivers gains - * a compatible string which it currently does not have. - */ - if (!strstarts(dev_name(consumer), "reset.gpio.")) - return false; - /* * Parent of the reset-gpio auxiliary device is the GPIO chip whose * fwnode we stored in the entry structure. @@ -328,33 +372,56 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, return false; /* - * The device associated with the shared reference's firmware node is - * the consumer of the reset control exposed by the reset-gpio device. - * It must have a "reset-gpios" property that's referencing the entry's - * firmware node. - * - * The reference args must agree between the real consumer and the - * auxiliary reset-gpio device. + * Now we need to find the actual pin we want to assign to this + * reset-gpio device. To that end: iterate over the list of references + * of this entry and see if there's one, whose reset-gpios property's + * arguments match the ones from this consumer's node. */ - ret = fwnode_property_get_reference_args(ref->fwnode, "reset-gpios", - NULL, 2, 0, &ref_args); - if (ret) - return false; + list_for_each_entry(real_ref, &entry->refs, list) { + if (!real_ref->fwnode) + continue; + + /* + * The device associated with the shared reference's firmware + * node is the consumer of the reset control exposed by the + * reset-gpio device. It must have a "reset-gpios" property + * that's referencing the entry's firmware node. + * + * The reference args must agree between the real consumer and + * the auxiliary reset-gpio device. + */ + ret = fwnode_property_get_reference_args(real_ref->fwnode, + "reset-gpios", + NULL, 2, 0, &ref_args); + if (ret) + continue; + + ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios", + NULL, 2, 0, &aux_args); + if (ret) { + fwnode_handle_put(ref_args.fwnode); + continue; + } + + match = ((ref_args.fwnode == entry->fwnode) && + (aux_args.fwnode == entry->fwnode) && + (ref_args.args[0] == aux_args.args[0])); - ret = fwnode_property_get_reference_args(reset_fwnode, "reset-gpios", - NULL, 2, 0, &aux_args); - if (ret) { fwnode_handle_put(ref_args.fwnode); - return false; - } + fwnode_handle_put(aux_args.fwnode); + + if (!match) + continue; - match = ((ref_args.fwnode == entry->fwnode) && - (aux_args.fwnode == entry->fwnode) && - (ref_args.args[0] == aux_args.args[0])); + /* + * Reuse the fwnode of the real device, next time we'll use it + * in the normal path. + */ + ref->fwnode = fwnode_handle_get(real_ref->fwnode); + return true; + } - fwnode_handle_put(ref_args.fwnode); - fwnode_handle_put(aux_args.fwnode); - return match; + return false; } #else static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, @@ -379,12 +446,20 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { - if (!device_match_fwnode(consumer, ref->fwnode) && - !gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) - continue; - guard(mutex)(&ref->lock); + /* + * FIXME: use device_is_compatible() once the reset-gpio + * drivers gains a compatible string which it currently + * does not have. + */ + if (!ref->fwnode && strstarts(dev_name(consumer), "reset.gpio.")) { + if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) + continue; + } else if (!device_match_fwnode(consumer, ref->fwnode)) { + continue; + } + if ((!con_id && ref->con_id) || (con_id && !ref->con_id) || (con_id && ref->con_id && strcmp(con_id, ref->con_id) != 0)) continue; @@ -471,8 +546,9 @@ int gpio_device_setup_shared(struct gpio_device *gdev) entry->offset, gpio_device_get_label(gdev)); list_for_each_entry(ref, &entry->refs, list) { - pr_debug("Setting up a shared GPIO entry for %s\n", - fwnode_get_name(ref->fwnode)); + pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n", + fwnode_get_name(ref->fwnode) ?: "(no fwnode)", + ref->con_id ?: "(none)"); ret = gpio_shared_make_adev(gdev, entry, ref); if (ret) -- cgit v1.2.3 From a7ac22d53d0990152b108c3f4fe30df45fcb0181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Narewski?= Date: Wed, 24 Dec 2025 09:26:40 +0100 Subject: gpiolib: fix race condition for gdev->srcu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If two drivers were calling gpiochip_add_data_with_key(), one may be traversing the srcu-protected list in gpio_name_to_desc(), meanwhile other has just added its gdev in gpiodev_add_to_list_unlocked(). This creates a non-mutexed and non-protected timeframe, when one instance is dereferencing and using &gdev->srcu, before the other has initialized it, resulting in crash: [ 4.935481] Unable to handle kernel paging request at virtual address ffff800272bcc000 [ 4.943396] Mem abort info: [ 4.943400] ESR = 0x0000000096000005 [ 4.943403] EC = 0x25: DABT (current EL), IL = 32 bits [ 4.943407] SET = 0, FnV = 0 [ 4.943410] EA = 0, S1PTW = 0 [ 4.943413] FSC = 0x05: level 1 translation fault [ 4.943416] Data abort info: [ 4.943418] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 [ 4.946220] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 4.955261] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 4.955268] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000038e6c000 [ 4.961449] [ffff800272bcc000] pgd=0000000000000000 [ 4.969203] , p4d=1000000039739003 [ 4.979730] , pud=0000000000000000 [ 4.980210] phandle (CPU): 0x0000005e, phandle (BE): 0x5e000000 for node "reset" [ 4.991736] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP ... [ 5.121359] pc : __srcu_read_lock+0x44/0x98 [ 5.131091] lr : gpio_name_to_desc+0x60/0x1a0 [ 5.153671] sp : ffff8000833bb430 [ 5.298440] [ 5.298443] Call trace: [ 5.298445] __srcu_read_lock+0x44/0x98 [ 5.309484] gpio_name_to_desc+0x60/0x1a0 [ 5.320692] gpiochip_add_data_with_key+0x488/0xf00 5.946419] ---[ end trace 0000000000000000 ]--- Move initialization code for gdev fields before it is added to gpio_devices, with adjacent initialization code. Adjust goto statements to reflect modified order of operations Fixes: 47d8b4c1d868 ("gpio: add SRCU infrastructure to struct gpio_device") Reviewed-by: Jakub Lewalski Signed-off-by: Paweł Narewski [Bartosz: fixed a build issue, removed stray newline] Link: https://lore.kernel.org/r/20251224082641.10769-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9ccfb7af67cc..c06152b16dbc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1105,6 +1105,18 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gdev->ngpio = gc->ngpio; gdev->can_sleep = gc->can_sleep; + rwlock_init(&gdev->line_state_lock); + RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); + BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); + + ret = init_srcu_struct(&gdev->srcu); + if (ret) + goto err_free_label; + + ret = init_srcu_struct(&gdev->desc_srcu); + if (ret) + goto err_cleanup_gdev_srcu; + scoped_guard(mutex, &gpio_devices_lock) { /* * TODO: this allocates a Linux GPIO number base in the global @@ -1119,7 +1131,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (base < 0) { ret = base; base = 0; - goto err_free_label; + goto err_cleanup_desc_srcu; } /* @@ -1139,22 +1151,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n"); - goto err_free_label; + goto err_cleanup_desc_srcu; } } - rwlock_init(&gdev->line_state_lock); - RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); - BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); - - ret = init_srcu_struct(&gdev->srcu); - if (ret) - goto err_remove_from_list; - - ret = init_srcu_struct(&gdev->desc_srcu); - if (ret) - goto err_cleanup_gdev_srcu; - #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif @@ -1164,11 +1164,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiochip_set_names(gc); if (ret) - goto err_cleanup_desc_srcu; + goto err_remove_from_list; ret = gpiochip_init_valid_mask(gc); if (ret) - goto err_cleanup_desc_srcu; + goto err_remove_from_list; for (desc_index = 0; desc_index < gc->ngpio; desc_index++) { struct gpio_desc *desc = &gdev->descs[desc_index]; @@ -1248,10 +1248,6 @@ err_remove_of_chip: of_gpiochip_remove(gc); err_free_valid_mask: gpiochip_free_valid_mask(gc); -err_cleanup_desc_srcu: - cleanup_srcu_struct(&gdev->desc_srcu); -err_cleanup_gdev_srcu: - cleanup_srcu_struct(&gdev->srcu); err_remove_from_list: scoped_guard(mutex, &gpio_devices_lock) list_del_rcu(&gdev->list); @@ -1261,6 +1257,10 @@ err_remove_from_list: gpio_device_put(gdev); goto err_print_message; } +err_cleanup_desc_srcu: + cleanup_srcu_struct(&gdev->desc_srcu); +err_cleanup_gdev_srcu: + cleanup_srcu_struct(&gdev->srcu); err_free_label: kfree_const(gdev->label); err_free_descs: -- cgit v1.2.3 From 014a17deb41201449f76df2b20c857a9c3294a7c Mon Sep 17 00:00:00 2001 From: Ernest Van Hoecke Date: Wed, 17 Dec 2025 16:30:25 +0100 Subject: gpio: pca953x: handle short interrupt pulses on PCAL devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPIO drivers with latch input support may miss short pulses on input pins even when input latching is enabled. The generic interrupt logic in the pca953x driver reports interrupts by comparing the current input value against the previously sampled one and only signals an event when a level change is observed between two reads. For short pulses, the first edge is captured when the input register is read, but if the signal returns to its previous level before the read, the second edge is not observed. As a result, successive pulses can produce identical input values at read time and no level change is detected, causing interrupts to be missed. Below timing diagram shows this situation where the top signal is the input pin level and the bottom signal indicates the latched value. ─────┐ ┌──*───────────────┐ ┌──*─────────────────┐ ┌──*─── │ │ . │ │ . │ │ . │ │ │ │ │ │ │ │ │ └──*──┘ │ └──*──┘ │ └──*──┘ │ Input │ │ │ │ │ │ ▼ │ ▼ │ ▼ │ IRQ │ IRQ │ IRQ │ . . . ─────┐ .┌──────────────┐ .┌────────────────┐ .┌── │ │ │ │ │ │ │ │ │ │ │ │ └────────*┘ └────────*┘ └────────*┘ Latched │ │ │ ▼ ▼ ▼ READ 0 READ 0 READ 0 NO CHANGE NO CHANGE PCAL variants provide an interrupt status register that records which pins triggered an interrupt, but the status and input registers cannot be read atomically. The interrupt status is only cleared when the input port is read, and the input value must also be read to determine the triggering edge. If another interrupt occurs on a different line after the status register has been read but before the input register is sampled, that event will not be reflected in the earlier status snapshot, so relying solely on the interrupt status register is also insufficient. Support for input latching and interrupt status handling was previously added by [1], but the interrupt status-based logic was reverted by [2] due to these issues. This patch addresses the original problem by combining both sources of information. Events indicated by the interrupt status register are merged with events detected through the existing level-change logic. As a result: * short pulses, whose second edges are invisible, are detected via the interrupt status register, and * interrupts that occur between the status and input reads are still caught by the generic level-change logic. This significantly improves robustness on devices that signal interrupts as short pulses, while avoiding the issues that led to the earlier reversion. In practice, even if only the first edge of a pulse is observable, the interrupt is reliably detected. This fixes missed interrupts from an Ilitek touch controller with its interrupt line connected to a PCAL6416A, where active-low pulses are approximately 200 us long. [1] commit 44896beae605 ("gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2") [2] commit d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Fixes: d6179f6c6204 ("gpio: pca953x: Improve interrupt support") Signed-off-by: Ernest Van Hoecke Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20251217153050.142057-1-ernestvanhoecke@gmail.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 0a3916cc2772..8727ae54bc57 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -943,14 +943,35 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin DECLARE_BITMAP(old_stat, MAX_LINE); DECLARE_BITMAP(cur_stat, MAX_LINE); DECLARE_BITMAP(new_stat, MAX_LINE); + DECLARE_BITMAP(int_stat, MAX_LINE); DECLARE_BITMAP(trigger, MAX_LINE); DECLARE_BITMAP(edges, MAX_LINE); int ret; + if (chip->driver_data & PCA_PCAL) { + /* Read INT_STAT before it is cleared by the input-port read. */ + ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, int_stat); + if (ret) + return false; + } + ret = pca953x_read_regs(chip, chip->regs->input, cur_stat); if (ret) return false; + if (chip->driver_data & PCA_PCAL) { + /* Detect short pulses via INT_STAT. */ + bitmap_and(trigger, int_stat, chip->irq_mask, gc->ngpio); + + /* Apply filter for rising/falling edge selection. */ + bitmap_replace(new_stat, chip->irq_trig_fall, chip->irq_trig_raise, + cur_stat, gc->ngpio); + + bitmap_and(int_stat, new_stat, trigger, gc->ngpio); + } else { + bitmap_zero(int_stat, gc->ngpio); + } + /* Remove output pins from the equation */ pca953x_read_regs(chip, chip->regs->direction, reg_direction); @@ -964,7 +985,8 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin if (bitmap_empty(chip->irq_trig_level_high, gc->ngpio) && bitmap_empty(chip->irq_trig_level_low, gc->ngpio)) { - if (bitmap_empty(trigger, gc->ngpio)) + if (bitmap_empty(trigger, gc->ngpio) && + bitmap_empty(int_stat, gc->ngpio)) return false; } @@ -972,6 +994,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio); bitmap_or(edges, old_stat, cur_stat, gc->ngpio); bitmap_and(pending, edges, trigger, gc->ngpio); + bitmap_or(pending, pending, int_stat, gc->ngpio); bitmap_and(cur_stat, new_stat, chip->irq_trig_level_high, gc->ngpio); bitmap_and(cur_stat, cur_stat, chip->irq_mask, gc->ngpio); -- cgit v1.2.3 From 1e876e5a0875e71e34148c9feb2eedd3bf6b2b43 Mon Sep 17 00:00:00 2001 From: Abdun Nihaal Date: Fri, 26 Dec 2025 11:34:10 +0530 Subject: gpio: mpsse: fix reference leak in gpio_mpsse_probe() error paths The reference obtained by calling usb_get_dev() is not released in the gpio_mpsse_probe() error paths. Fix that by using device managed helper functions. Also remove the usb_put_dev() call in the disconnect function since now it will be released automatically. Cc: stable@vger.kernel.org Fixes: c46a74ff05c0 ("gpio: add support for FTDI's MPSSE as GPIO") Signed-off-by: Abdun Nihaal Link: https://lore.kernel.org/r/20251226060414.20785-1-nihaal@cse.iitm.ac.in Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mpsse.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c index ace652ba4df1..12191aeb6566 100644 --- a/drivers/gpio/gpio-mpsse.c +++ b/drivers/gpio/gpio-mpsse.c @@ -548,6 +548,13 @@ static void gpio_mpsse_ida_remove(void *data) ida_free(&gpio_mpsse_ida, priv->id); } +static void gpio_mpsse_usb_put_dev(void *data) +{ + struct mpsse_priv *priv = data; + + usb_put_dev(priv->udev); +} + static int mpsse_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, unsigned int ngpios) @@ -592,6 +599,10 @@ static int gpio_mpsse_probe(struct usb_interface *interface, INIT_LIST_HEAD(&priv->workers); priv->udev = usb_get_dev(interface_to_usbdev(interface)); + err = devm_add_action_or_reset(dev, gpio_mpsse_usb_put_dev, priv); + if (err) + return err; + priv->intf = interface; priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; @@ -713,7 +724,6 @@ static void gpio_mpsse_disconnect(struct usb_interface *intf) priv->intf = NULL; usb_set_intfdata(intf, NULL); - usb_put_dev(priv->udev); } static struct usb_driver gpio_mpsse_driver = { -- cgit v1.2.3 From 235a1eb8d2dcc49a6cf0a5ee1aa85544a5d0054b Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Wed, 31 Dec 2025 11:49:15 +0000 Subject: of: unittest: Fix memory leak in unittest_data_add() In unittest_data_add(), if of_resolve_phandles() fails, the allocated unittest_data is not freed, leading to a memory leak. Fix this by using scope-based cleanup helper __free(kfree) for automatic resource cleanup. This ensures unittest_data is automatically freed when it goes out of scope in error paths. For the success path, use retain_and_null_ptr() to transfer ownership of the memory to the device tree and prevent double freeing. Fixes: 2eb46da2a760 ("of/selftest: Use the resolver to fixup phandles") Suggested-by: Rob Herring Co-developed-by: Jianhao Xu Signed-off-by: Jianhao Xu Signed-off-by: Zilin Guan Link: https://patch.msgid.link/20251231114915.234638-1-zilin@seu.edu.cn Signed-off-by: Rob Herring (Arm) --- drivers/of/unittest.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 388e9ec2cccf..3b773aaf9d05 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1985,7 +1985,6 @@ static void attach_node_and_children(struct device_node *np) */ static int __init unittest_data_add(void) { - void *unittest_data; void *unittest_data_align; struct device_node *unittest_data_node = NULL, *np; /* @@ -2004,7 +2003,7 @@ static int __init unittest_data_add(void) } /* creating copy */ - unittest_data = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL); + void *unittest_data __free(kfree) = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL); if (!unittest_data) return -ENOMEM; @@ -2014,12 +2013,10 @@ static int __init unittest_data_add(void) ret = of_fdt_unflatten_tree(unittest_data_align, NULL, &unittest_data_node); if (!ret) { pr_warn("%s: unflatten testcases tree failed\n", __func__); - kfree(unittest_data); return -ENODATA; } if (!unittest_data_node) { pr_warn("%s: testcases tree is empty\n", __func__); - kfree(unittest_data); return -ENODATA; } @@ -2038,7 +2035,6 @@ static int __init unittest_data_add(void) /* attach the sub-tree to live tree */ if (!of_root) { pr_warn("%s: no live tree to attach sub-tree\n", __func__); - kfree(unittest_data); rc = -ENODEV; goto unlock; } @@ -2059,6 +2055,8 @@ static int __init unittest_data_add(void) EXPECT_END(KERN_INFO, "Duplicate name in testcase-data, renamed to \"duplicate-name#1\""); + retain_and_null_ptr(unittest_data); + unlock: of_overlay_mutex_unlock(); -- cgit v1.2.3 From c1ef9a6cabb34dbc09e31417b0c0a672fe0de13a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:48 +0200 Subject: Revert "drm/atomic-helper: Re-order bridge chain pre-enable and post-disable" This reverts commit c9b1150a68d9362a0827609fc0dc1664c0d8bfe1. Changing the enable/disable sequence has caused regressions on multiple platforms: R-Car, MCDE, Rockchip. A series (see link below) was sent to fix these, but it was decided that it's better to revert the original patch and change the enable/disable sequence only in the tidss driver. Reverting this commit breaks tidss's DSI and OLDI outputs, which will be fixed in the following commits. Signed-off-by: Tomi Valkeinen Link: https://lore.kernel.org/all/20251202-mcde-drm-regression-thirdfix-v6-0-f1bffd4ec0fa%40kernel.org/ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Cc: stable@vger.kernel.org # v6.17+ Reviewed-by: Aradhya Bhatia Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-1-fda68fa1b3de@ideasonboard.com --- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 10adac9397cf..ef97f37560b2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1341,9 +1341,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *state) { encoder_bridge_disable(dev, state); - crtc_disable(dev, state); - encoder_bridge_post_disable(dev, state); + + crtc_disable(dev, state); } /** @@ -1682,10 +1682,10 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state) { - encoder_bridge_pre_enable(dev, state); - crtc_enable(dev, state); + encoder_bridge_pre_enable(dev, state); + encoder_bridge_enable(dev, state); drm_atomic_helper_commit_writebacks(dev, state); -- cgit v1.2.3 From 33e8150bd32d7dc25c977bb455f1f5d54bfd5241 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:49 +0200 Subject: Revert "drm/mediatek: dsi: Fix DSI host and panel bridge pre-enable order" This reverts commit f5b1819193667bf62c3c99d3921b9429997a14b2. As the original commit (c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable")) causing the issue has been reverted, let's revert the fix for mediatek. Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-2-fda68fa1b3de@ideasonboard.com --- drivers/gpu/drm/mediatek/mtk_dsi.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 0e2bcd5f67b7..d7726091819c 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -1002,12 +1002,6 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host, return PTR_ERR(dsi->next_bridge); } - /* - * set flag to request the DSI host bridge be pre-enabled before device bridge - * in the chain, so the DSI host is ready when the device bridge is pre-enabled - */ - dsi->next_bridge->pre_enable_prev_first = true; - drm_bridge_add(&dsi->bridge); ret = component_add(host->dev, &mtk_dsi_component_ops); -- cgit v1.2.3 From d1c7dc57ff2400b141e6582a8d2dc5170108cf81 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 5 Dec 2025 11:51:50 +0200 Subject: drm/atomic-helper: Export and namespace some functions Export and namespace those not prefixed with drm_* so it becomes possible to write custom commit tail functions in individual drivers using the helper infrastructure. Tested-by: Marek Vasut Reviewed-by: Maxime Ripard Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Aradhya Bhatia Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-3-fda68fa1b3de@ideasonboard.com --- drivers/gpu/drm/drm_atomic_helper.c | 122 +++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ef97f37560b2..5beea645035f 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1162,8 +1162,18 @@ crtc_needs_disable(struct drm_crtc_state *old_state, new_state->self_refresh_active; } -static void -encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_disable - disable bridges and encoder + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the CRTC needs + * it, disables the bridge chain all the way, then disables the encoder + * afterwards. + */ +void +drm_atomic_helper_commit_encoder_bridge_disable(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; @@ -1229,9 +1239,18 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state) } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_disable); -static void -crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_disable - disable CRTSs + * @dev: DRM device + * @state: the driver state object + * + * Loops over all CRTCs in the current state and if the CRTC needs + * it, disables it. + */ +void +drm_atomic_helper_commit_crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; @@ -1282,9 +1301,18 @@ crtc_disable(struct drm_device *dev, struct drm_atomic_state *state) drm_crtc_vblank_put(crtc); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_disable); -static void -encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_post_disable - post-disable encoder bridges + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the CRTC needs + * it, post-disables all encoder bridges. + */ +void +drm_atomic_helper_commit_encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *old_conn_state, *new_conn_state; @@ -1335,15 +1363,16 @@ encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *sta drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_post_disable); static void disable_outputs(struct drm_device *dev, struct drm_atomic_state *state) { - encoder_bridge_disable(dev, state); + drm_atomic_helper_commit_encoder_bridge_disable(dev, state); - encoder_bridge_post_disable(dev, state); + drm_atomic_helper_commit_encoder_bridge_post_disable(dev, state); - crtc_disable(dev, state); + drm_atomic_helper_commit_crtc_disable(dev, state); } /** @@ -1446,8 +1475,17 @@ void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *stat } EXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants); -static void -crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_set_mode - set the new mode + * @dev: DRM device + * @state: the driver state object + * + * Loops over all connectors in the current state and if the mode has + * changed, change the mode of the CRTC, then call down the bridge + * chain and change the mode in all bridges as well. + */ +void +drm_atomic_helper_commit_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; @@ -1508,6 +1546,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_set_mode); /** * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs @@ -1531,12 +1570,21 @@ void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, drm_atomic_helper_update_legacy_modeset_state(dev, state); drm_atomic_helper_calc_timestamping_constants(state); - crtc_set_mode(dev, state); + drm_atomic_helper_commit_crtc_set_mode(dev, state); } EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); -static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, - struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_writebacks - issue writebacks + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over the connectors, checks if the new state requires + * a writeback job to be issued and in that case issues an atomic + * commit on each connector. + */ +void drm_atomic_helper_commit_writebacks(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1555,9 +1603,18 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_writebacks); -static void -encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_pre_enable - pre-enable bridges + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over the connectors and if the CRTC needs it, pre-enables + * the entire bridge chain. + */ +void +drm_atomic_helper_commit_encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1588,9 +1645,18 @@ encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_pre_enable); -static void -crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_crtc_enable - enables the CRTCs + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over CRTCs in the new state, and of the CRTC needs + * it, enables it. + */ +void +drm_atomic_helper_commit_crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; @@ -1619,9 +1685,18 @@ crtc_enable(struct drm_device *dev, struct drm_atomic_state *state) } } } +EXPORT_SYMBOL(drm_atomic_helper_commit_crtc_enable); -static void -encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) +/** + * drm_atomic_helper_commit_encoder_bridge_enable - enables the bridges + * @dev: DRM device + * @state: atomic state object being committed + * + * This loops over all connectors in the new state, and of the CRTC needs + * it, enables the entire bridge chain. + */ +void +drm_atomic_helper_commit_encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_connector *connector; struct drm_connector_state *new_conn_state; @@ -1664,6 +1739,7 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) drm_bridge_put(bridge); } } +EXPORT_SYMBOL(drm_atomic_helper_commit_encoder_bridge_enable); /** * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs @@ -1682,11 +1758,11 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *state) { - crtc_enable(dev, state); + drm_atomic_helper_commit_crtc_enable(dev, state); - encoder_bridge_pre_enable(dev, state); + drm_atomic_helper_commit_encoder_bridge_pre_enable(dev, state); - encoder_bridge_enable(dev, state); + drm_atomic_helper_commit_encoder_bridge_enable(dev, state); drm_atomic_helper_commit_writebacks(dev, state); } -- cgit v1.2.3 From 2fc04340cf30d7960eed2525d26ffb8905aca02b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 5 Dec 2025 11:51:51 +0200 Subject: drm/tidss: Fix enable/disable order TI's OLDI and DSI encoders need to be set up before the crtc is enabled, but the DRM helpers will enable the crtc first. This causes various issues on TI platforms, like visual artifacts or crtc sync lost warnings. Thus drm_atomic_helper_commit_modeset_enables() and drm_atomic_helper_commit_modeset_disables() cannot be used, as they enable the crtc before bridges' pre-enable, and disable the crtc after bridges' post-disable. Open code the drm_atomic_helper_commit_modeset_enables() and drm_atomic_helper_commit_modeset_disables(), and first call the bridges' pre-enables, then crtc enable, then bridges' post-enable (and vice versa for disable). Signed-off-by: Tomi Valkeinen Cc: stable@vger.kernel.org # v6.17+ Fixes: c9b1150a68d9 ("drm/atomic-helper: Re-order bridge chain pre-enable and post-disable") Reviewed-by: Aradhya Bhatia Reviewed-by: Maxime Ripard Reviewed-by: Linus Walleij Tested-by: Linus Walleij Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20251205-drm-seq-fix-v1-4-fda68fa1b3de@ideasonboard.com --- drivers/gpu/drm/tidss/tidss_kms.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index 86eb5d97410b..8bb93194e5ac 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -26,9 +26,33 @@ static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) tidss_runtime_get(tidss); - drm_atomic_helper_commit_modeset_disables(ddev, old_state); - drm_atomic_helper_commit_planes(ddev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY); - drm_atomic_helper_commit_modeset_enables(ddev, old_state); + /* + * TI's OLDI and DSI encoders need to be set up before the crtc is + * enabled. Thus drm_atomic_helper_commit_modeset_enables() and + * drm_atomic_helper_commit_modeset_disables() cannot be used here, as + * they enable the crtc before bridges' pre-enable, and disable the crtc + * after bridges' post-disable. + * + * Open code the functions here and first call the bridges' pre-enables, + * then crtc enable, then bridges' post-enable (and vice versa for + * disable). + */ + + drm_atomic_helper_commit_encoder_bridge_disable(ddev, old_state); + drm_atomic_helper_commit_crtc_disable(ddev, old_state); + drm_atomic_helper_commit_encoder_bridge_post_disable(ddev, old_state); + + drm_atomic_helper_update_legacy_modeset_state(ddev, old_state); + drm_atomic_helper_calc_timestamping_constants(old_state); + drm_atomic_helper_commit_crtc_set_mode(ddev, old_state); + + drm_atomic_helper_commit_planes(ddev, old_state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); + + drm_atomic_helper_commit_encoder_bridge_pre_enable(ddev, old_state); + drm_atomic_helper_commit_crtc_enable(ddev, old_state); + drm_atomic_helper_commit_encoder_bridge_enable(ddev, old_state); + drm_atomic_helper_commit_writebacks(ddev, old_state); drm_atomic_helper_commit_hw_done(old_state); drm_atomic_helper_wait_for_flip_done(ddev, old_state); -- cgit v1.2.3 From e8b3627bec357698f2d4d6dbf27cdcfa0e9d8715 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 2 Jan 2026 14:18:29 +1000 Subject: nouveau: don't attempt fwsec on sb on newer platforms. The changes to always loads fwsec sb causes problems on newer GPUs which don't use this path. Add hooks and pass through the device specific layers. Fixes: da67179e5538 ("drm/nouveau/gsp: Allocate fwsec-sb at boot") Cc: # v6.16+ Cc: Lyude Paul Cc: Timur Tabi Tested-by: Matthew Schwartz Tested-by: Christopher Snowhill Reviewed-by: Lyude Paul Signed-off-by: Dave Airlie Link: https://patch.msgid.link/20260102041829.2748009-1-airlied@gmail.com --- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c | 8 +------- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h | 23 +++++++++++++++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c | 3 +++ 7 files changed, 49 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c index 35d1fcef520b..c456a9626823 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ad102.c @@ -30,6 +30,9 @@ ad102_gsp = { .booter.ctor = ga102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 503760246660..851140e80122 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -337,18 +337,12 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) } int -nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +nvkm_gsp_fwsec_sb_init(struct nvkm_gsp *gsp) { return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); } -void -nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) -{ - nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); -} - int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c index d201e8697226..27a13aeccd3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga100.c @@ -47,6 +47,9 @@ ga100_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c index 917f7e2f6c46..b6b3eb6f4c00 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/ga102.c @@ -158,6 +158,9 @@ ga102_gsp_r535 = { .booter.ctor = ga102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index 86bdd203bc10..9dd66a2e3801 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -7,9 +7,8 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); -int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); -void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); +int nvkm_gsp_fwsec_sb_init(struct nvkm_gsp *gsp); struct nvkm_gsp_fwif { int version; @@ -52,6 +51,11 @@ struct nvkm_gsp_func { struct nvkm_falcon *, struct nvkm_falcon_fw *); } booter; + struct { + int (*ctor)(struct nvkm_gsp *); + void (*dtor)(struct nvkm_gsp *); + } fwsec_sb; + void (*dtor)(struct nvkm_gsp *); int (*oneinit)(struct nvkm_gsp *); int (*init)(struct nvkm_gsp *); @@ -67,6 +71,8 @@ extern const struct nvkm_falcon_func tu102_gsp_flcn; extern const struct nvkm_falcon_fw_func tu102_gsp_fwsec; int tu102_gsp_booter_ctor(struct nvkm_gsp *, const char *, const struct firmware *, struct nvkm_falcon *, struct nvkm_falcon_fw *); +int tu102_gsp_fwsec_sb_ctor(struct nvkm_gsp *); +void tu102_gsp_fwsec_sb_dtor(struct nvkm_gsp *); int tu102_gsp_oneinit(struct nvkm_gsp *); int tu102_gsp_init(struct nvkm_gsp *); int tu102_gsp_fini(struct nvkm_gsp *, bool suspend); @@ -91,5 +97,18 @@ int r535_gsp_fini(struct nvkm_gsp *, bool suspend); int nvkm_gsp_new_(const struct nvkm_gsp_fwif *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_gsp **); +static inline int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + if (gsp->func->fwsec_sb.ctor) + return gsp->func->fwsec_sb.ctor(gsp); + return 0; +} + +static inline void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + if (gsp->func->fwsec_sb.dtor) + gsp->func->fwsec_sb.dtor(gsp); +} + extern const struct nvkm_gsp_func gv100_gsp; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c index 81e56da0474a..04b642a1f730 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu102.c @@ -30,6 +30,18 @@ #include #include +int +tu102_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_sb_init(gsp); +} + +void +tu102_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + static int tu102_gsp_booter_unload(struct nvkm_gsp *gsp, u32 mbox0, u32 mbox1) { @@ -370,6 +382,9 @@ tu102_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c index 97eb046c25d0..58cf25842421 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/tu116.c @@ -30,6 +30,9 @@ tu116_gsp = { .booter.ctor = tu102_gsp_booter_ctor, + .fwsec_sb.ctor = tu102_gsp_fwsec_sb_ctor, + .fwsec_sb.dtor = tu102_gsp_fwsec_sb_dtor, + .dtor = r535_gsp_dtor, .oneinit = tu102_gsp_oneinit, .init = tu102_gsp_init, -- cgit v1.2.3 From a428e0da1248c353557970848994f35fd3f005e2 Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Mon, 29 Dec 2025 21:21:18 -0800 Subject: net: marvell: prestera: fix NULL dereference on devlink_alloc() failure devlink_alloc() may return NULL on allocation failure, but prestera_devlink_alloc() unconditionally calls devlink_priv() on the returned pointer. This leads to a NULL pointer dereference if devlink allocation fails. Add a check for a NULL devlink pointer and return NULL early to avoid the crash. Fixes: 34dd1710f5a3 ("net: marvell: prestera: Add basic devlink support") Signed-off-by: Alok Tiwari Acked-by: Elad Nachman Link: https://patch.msgid.link/20251230052124.897012-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/prestera/prestera_devlink.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c index 2a4c9df4eb79..e63d95c1842f 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c @@ -387,6 +387,8 @@ struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev) dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch), dev->dev); + if (!dl) + return NULL; return devlink_priv(dl); } -- cgit v1.2.3 From d7065436e8a04520f60c18240b775861be7999d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Bl=C3=B6chl?= Date: Sun, 28 Dec 2025 16:52:59 +0100 Subject: net: bnge: add AUXILIARY_BUS to Kconfig dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build can currently fail with ld: drivers/net/ethernet/broadcom/bnge/bnge_auxr.o: in function `bnge_rdma_aux_device_add': bnge_auxr.c:(.text+0x366): undefined reference to `__auxiliary_device_add' ld: drivers/net/ethernet/broadcom/bnge/bnge_auxr.o: in function `bnge_rdma_aux_device_init': bnge_auxr.c:(.text+0x43c): undefined reference to `auxiliary_device_init' if BNGE is enabled but no other driver pulls in AUXILIARY_BUS. Select AUXILIARY_BUS in BNGE like in all other drivers which create an auxiliary_device. Fixes: 8ac050ec3b1c ("bng_en: Add RoCE aux device support") Signed-off-by: Markus Blöchl Reviewed-by: Vikas Gupta Link: https://patch.msgid.link/20251228-bnge_aux_bus-v1-1-82e273ebfdac@blochl.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index ca565ace6e6a..cd7dddeb91dd 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -259,6 +259,7 @@ config BNGE depends on PCI select NET_DEVLINK select PAGE_POOL + select AUXILIARY_BUS help This driver supports Broadcom ThorUltra 50/100/200/400/800 gigabit Ethernet cards. The module will be called bng_en. To compile this -- cgit v1.2.3 From 34f3ff52cb9fa7dbf04f5c734fcc4cb6ed5d1a95 Mon Sep 17 00:00:00 2001 From: Jerry Wu Date: Thu, 25 Dec 2025 20:36:17 +0000 Subject: net: mscc: ocelot: Fix crash when adding interface under a lag Commit 15faa1f67ab4 ("lan966x: Fix crash when adding interface under a lag") fixed a similar issue in the lan966x driver caused by a NULL pointer dereference. The ocelot_set_aggr_pgids() function in the ocelot driver has similar logic and is susceptible to the same crash. This issue specifically affects the ocelot_vsc7514.c frontend, which leaves unused ports as NULL pointers. The felix_vsc9959.c frontend is unaffected as it uses the DSA framework which registers all ports. Fix this by checking if the port pointer is valid before accessing it. Fixes: 528d3f190c98 ("net: mscc: ocelot: drop the use of the "lags" array") Signed-off-by: Jerry Wu Reviewed-by: Vladimir Oltean Link: https://patch.msgid.link/tencent_75EF812B305E26B0869C673DD1160866C90A@qq.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mscc/ocelot.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 08bee56aea35..c345d9b17c89 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2307,14 +2307,16 @@ static void ocelot_set_aggr_pgids(struct ocelot *ocelot) /* Now, set PGIDs for each active LAG */ for (lag = 0; lag < ocelot->num_phys_ports; lag++) { - struct net_device *bond = ocelot->ports[lag]->bond; + struct ocelot_port *ocelot_port = ocelot->ports[lag]; int num_active_ports = 0; + struct net_device *bond; unsigned long bond_mask; u8 aggr_idx[16]; - if (!bond || (visited & BIT(lag))) + if (!ocelot_port || !ocelot_port->bond || (visited & BIT(lag))) continue; + bond = ocelot_port->bond; bond_mask = ocelot_get_bond_mask(ocelot, bond); for_each_set_bit(port, &bond_mask, ocelot->num_phys_ports) { -- cgit v1.2.3 From 62f7edd59964eb588e96fce1ad35a2327ea54424 Mon Sep 17 00:00:00 2001 From: Stefano Radaelli Date: Tue, 23 Dec 2025 13:09:39 +0100 Subject: net: phy: mxl-86110: Add power management and soft reset support Implement soft_reset, suspend, and resume callbacks using genphy_soft_reset(), genphy_suspend(), and genphy_resume() to fix PHY initialization and power management issues. The soft_reset callback is needed to properly recover the PHY after an ifconfig down/up cycle. Without it, the PHY can remain in power-down state, causing MDIO register access failures during config_init(). The soft reset ensures the PHY is operational before configuration. The suspend/resume callbacks enable proper power management during system suspend/resume cycles. Fixes: b2908a989c59 ("net: phy: add driver for MaxLinear MxL86110 PHY") Signed-off-by: Stefano Radaelli Link: https://patch.msgid.link/20251223120940.407195-1-stefano.r@variscite.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mxl-86110.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/mxl-86110.c b/drivers/net/phy/mxl-86110.c index e5d137a37a1d..42a5fe3f115f 100644 --- a/drivers/net/phy/mxl-86110.c +++ b/drivers/net/phy/mxl-86110.c @@ -938,6 +938,9 @@ static struct phy_driver mxl_phy_drvs[] = { PHY_ID_MATCH_EXACT(PHY_ID_MXL86110), .name = "MXL86110 Gigabit Ethernet", .config_init = mxl86110_config_init, + .suspend = genphy_suspend, + .resume = genphy_resume, + .soft_reset = genphy_soft_reset, .get_wol = mxl86110_get_wol, .set_wol = mxl86110_set_wol, .led_brightness_set = mxl86110_led_brightness_set, -- cgit v1.2.3 From 31057979cdadfee9f934746fd84046b43506ba61 Mon Sep 17 00:00:00 2001 From: Patrisious Haddad Date: Thu, 25 Dec 2025 15:27:13 +0200 Subject: net/mlx5: Lag, multipath, give priority for routes with smaller network prefix Today multipath offload is controlled by a single route and the route controlling is selected if it meets one of the following criteria: 1. No controlling route is set. 2. New route destination is the same as old one. 3. New route metric is lower than old route metric. This can cause unwanted behaviour in case a new route is added with a smaller network prefix which should get the priority. Fix this by adding a new criteria to give priority to new route with a smaller network prefix. Fixes: ad11c4f1d8fd ("net/mlx5e: Lag, Only handle events from highest priority multipath entry") Signed-off-by: Patrisious Haddad Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-2-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c index aee17fcf3b36..cdc99fe5c956 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c @@ -173,10 +173,15 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event, } /* Handle multipath entry with lower priority value */ - if (mp->fib.mfi && mp->fib.mfi != fi && + if (mp->fib.mfi && (mp->fib.dst != fen_info->dst || mp->fib.dst_len != fen_info->dst_len) && - fi->fib_priority >= mp->fib.priority) + mp->fib.dst_len <= fen_info->dst_len && + !(mp->fib.dst_len == fen_info->dst_len && + fi->fib_priority < mp->fib.priority)) { + mlx5_core_dbg(ldev->pf[idx].dev, + "Multipath entry with lower priority was rejected\n"); return; + } nh_dev0 = mlx5_lag_get_next_fib_dev(ldev, fi, NULL); nh_dev1 = mlx5_lag_get_next_fib_dev(ldev, fi, nh_dev0); -- cgit v1.2.3 From 6c75dc9de40ff91ec2b621b78f6cd9031762067c Mon Sep 17 00:00:00 2001 From: Alexei Lazar Date: Thu, 25 Dec 2025 15:27:14 +0200 Subject: net/mlx5e: Don't gate FEC histograms on ppcnt_statistical_group Currently, the ppcnt_statistical_group capability check incorrectly gates access to FEC histogram statistics. This capability applies only to statistical and physical counter groups, not for histogram data. Restrict the ppcnt_statistical_group check to the Physical_Layer_Counters and Physical_Layer_Statistical_Counters groups. Histogram statistics access remains gated by the pphcr capability. The issue is harmless as of today, as it happens that ppcnt_statistical_group is set on all existing devices that have pphcr set. Fixes: 6b81b8a0b197 ("net/mlx5e: Don't query FEC statistics when FEC is disabled") Signed-off-by: Alexei Lazar Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-3-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index a2802cfc9b98..a8af84fc9763 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -1608,12 +1608,13 @@ void mlx5e_stats_fec_get(struct mlx5e_priv *priv, { int mode = fec_active_mode(priv->mdev); - if (mode == MLX5E_FEC_NOFEC || - !MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group)) + if (mode == MLX5E_FEC_NOFEC) return; - fec_set_corrected_bits_total(priv, fec_stats); - fec_set_block_stats(priv, mode, fec_stats); + if (MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group)) { + fec_set_corrected_bits_total(priv, fec_stats); + fec_set_block_stats(priv, mode, fec_stats); + } if (MLX5_CAP_PCAM_REG(priv->mdev, pphcr)) fec_set_histograms_stats(priv, mode, hist); -- cgit v1.2.3 From 7d36a4a8bf62dc508bc6bb4b59727aec25064ca5 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 25 Dec 2025 15:27:15 +0200 Subject: net/mlx5e: Fix NULL pointer dereference in ioctl module EEPROM query The mlx5_query_mcia() function unconditionally dereferences the status pointer to store the MCIA register status value. However, mlx5e_get_module_id() passes NULL since it doesn't need the status value. Add a NULL check before dereferencing the status pointer to prevent a NULL pointer dereference. Fixes: 2e4c44b12f4d ("net/mlx5: Refactor EEPROM query error handling to return status separately") Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Reviewed-by: Dragos Tatulea Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-4-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 85a9e534f442..8f36454dd196 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -393,9 +393,11 @@ static int mlx5_query_mcia(struct mlx5_core_dev *dev, if (err) return err; - *status = MLX5_GET(mcia_reg, out, status); - if (*status) + if (MLX5_GET(mcia_reg, out, status)) { + if (status) + *status = MLX5_GET(mcia_reg, out, status); return -EIO; + } ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); memcpy(data, ptr, size); -- cgit v1.2.3 From 144297e2a24e3e54aee1180ec21120ea38822b97 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 25 Dec 2025 15:27:16 +0200 Subject: net/mlx5e: Don't print error message due to invalid module Dumping module EEPROM on newer modules is supported through the netlink interface only. Querying with old userspace ethtool (or other tools, such as 'lshw') which still uses the ioctl interface results in an error message that could flood dmesg (in addition to the expected error return value). The original message was added under the assumption that the driver should be able to handle all module types, but now that such flows are easily triggered from userspace, it doesn't serve its purpose. Change the log level of the print in mlx5_query_module_eeprom() to debug. Fixes: bb64143eee8c ("net/mlx5e: Add ethtool support for dump module EEPROM") Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-5-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 8f36454dd196..7f8bed353e67 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -431,7 +431,8 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset); break; default: - mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id); + mlx5_core_dbg(dev, "Module ID not recognized: 0x%x\n", + module_id); return -EINVAL; } -- cgit v1.2.3 From 0462a15d2d1fafd3d48cf3c7c67393e42d03908c Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Thu, 25 Dec 2025 15:27:17 +0200 Subject: net/mlx5e: Dealloc forgotten PSP RX modify header The commit which added RX steering rules for PSP forgot to free a modify header HW object on the cleanup path, which lead to health errors when reloading the driver and uninitializing the device: mlx5_core 0000:08:00.0: poll_health:803:(pid 3021): Fatal error 3 detected Fix that by saving the modify header pointer in the PSP steering struct and deallocating it after freeing the rule which references it. Fixes: 9536fbe10c9d ("net/mlx5e: Add PSP steering in local NIC RX") Signed-off-by: Cosmin Ratiu Reviewed-by: Dragos Tatulea Reviewed-by: Tariq Toukan Signed-off-by: Mark Bloch Link: https://patch.msgid.link/20251225132717.358820-6-mbloch@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c index 38e7c77cc851..9a74438ce10a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c @@ -44,6 +44,7 @@ struct mlx5e_accel_fs_psp_prot { struct mlx5_flow_table *ft; struct mlx5_flow_group *miss_group; struct mlx5_flow_handle *miss_rule; + struct mlx5_modify_hdr *rx_modify_hdr; struct mlx5_flow_destination default_dest; struct mlx5e_psp_rx_err rx_err; u32 refcnt; @@ -286,13 +287,19 @@ out_err: return err; } -static void accel_psp_fs_rx_fs_destroy(struct mlx5e_accel_fs_psp_prot *fs_prot) +static void accel_psp_fs_rx_fs_destroy(struct mlx5e_psp_fs *fs, + struct mlx5e_accel_fs_psp_prot *fs_prot) { if (fs_prot->def_rule) { mlx5_del_flow_rules(fs_prot->def_rule); fs_prot->def_rule = NULL; } + if (fs_prot->rx_modify_hdr) { + mlx5_modify_header_dealloc(fs->mdev, fs_prot->rx_modify_hdr); + fs_prot->rx_modify_hdr = NULL; + } + if (fs_prot->miss_rule) { mlx5_del_flow_rules(fs_prot->miss_rule); fs_prot->miss_rule = NULL; @@ -396,6 +403,7 @@ static int accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs *fs, modify_hdr = NULL; goto out_err; } + fs_prot->rx_modify_hdr = modify_hdr; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT | @@ -416,7 +424,7 @@ static int accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs *fs, goto out; out_err: - accel_psp_fs_rx_fs_destroy(fs_prot); + accel_psp_fs_rx_fs_destroy(fs, fs_prot); out: kvfree(flow_group_in); kvfree(spec); @@ -433,7 +441,7 @@ static int accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs, enum accel_fs_psp_ty /* The netdev unreg already happened, so all offloaded rule are already removed */ fs_prot = &accel_psp->fs_prot[type]; - accel_psp_fs_rx_fs_destroy(fs_prot); + accel_psp_fs_rx_fs_destroy(fs, fs_prot); accel_psp_fs_rx_err_destroy_ft(fs, &fs_prot->rx_err); -- cgit v1.2.3 From 8da901ffe497a53fa4ecc3ceed0e6d771586f88e Mon Sep 17 00:00:00 2001 From: Frank Liang Date: Wed, 31 Dec 2025 22:58:08 +0800 Subject: net/ena: fix missing lock when update devlink params Fix assert lock warning while calling devl_param_driverinit_value_set() in ena. WARNING: net/devlink/core.c:261 at devl_assert_locked+0x62/0x90, CPU#0: kworker/0:0/9 CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.19.0-rc2+ #1 PREEMPT(lazy) Hardware name: Amazon EC2 m8i-flex.4xlarge/, BIOS 1.0 10/16/2017 Workqueue: events work_for_cpu_fn RIP: 0010:devl_assert_locked+0x62/0x90 Call Trace: devl_param_driverinit_value_set+0x15/0x1c0 ena_devlink_alloc+0x18c/0x220 [ena] ? __pfx_ena_devlink_alloc+0x10/0x10 [ena] ? trace_hardirqs_on+0x18/0x140 ? lockdep_hardirqs_on+0x8c/0x130 ? __raw_spin_unlock_irqrestore+0x5d/0x80 ? __raw_spin_unlock_irqrestore+0x46/0x80 ? devm_ioremap_wc+0x9a/0xd0 ena_probe+0x4d2/0x1b20 [ena] ? __lock_acquire+0x56a/0xbd0 ? __pfx_ena_probe+0x10/0x10 [ena] ? local_clock+0x15/0x30 ? __lock_release.isra.0+0x1c9/0x340 ? mark_held_locks+0x40/0x70 ? lockdep_hardirqs_on_prepare.part.0+0x92/0x170 ? trace_hardirqs_on+0x18/0x140 ? lockdep_hardirqs_on+0x8c/0x130 ? __raw_spin_unlock_irqrestore+0x5d/0x80 ? __raw_spin_unlock_irqrestore+0x46/0x80 ? __pfx_ena_probe+0x10/0x10 [ena] ...... Fixes: 816b52624cf6 ("net: ena: Control PHC enable through devlink") Signed-off-by: Frank Liang Reviewed-by: David Arinzon Reviewed-by: Jiri Pirko Link: https://patch.msgid.link/20251231145808.6103-1-xiliang@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amazon/ena/ena_devlink.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_devlink.c b/drivers/net/ethernet/amazon/ena/ena_devlink.c index ac81c24016dd..4772185e669d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_devlink.c +++ b/drivers/net/ethernet/amazon/ena/ena_devlink.c @@ -53,10 +53,12 @@ void ena_devlink_disable_phc_param(struct devlink *devlink) { union devlink_param_value value; + devl_lock(devlink); value.vbool = false; devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC, value); + devl_unlock(devlink); } static void ena_devlink_port_register(struct devlink *devlink) @@ -145,10 +147,12 @@ static int ena_devlink_configure_params(struct devlink *devlink) return rc; } + devl_lock(devlink); value.vbool = ena_phc_is_enabled(adapter); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC, value); + devl_unlock(devlink); return 0; } -- cgit v1.2.3 From 92e6e0a87f6860a4710f9494f8c704d498ae60f8 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Tue, 30 Dec 2025 07:18:53 +0000 Subject: net: wwan: iosm: Fix memory leak in ipc_mux_deinit() Commit 1f52d7b62285 ("net: wwan: iosm: Enable M.2 7360 WWAN card support") allocated memory for pp_qlt in ipc_mux_init() but did not free it in ipc_mux_deinit(). This results in a memory leak when the driver is unloaded. Free the allocated memory in ipc_mux_deinit() to fix the leak. Fixes: 1f52d7b62285 ("net: wwan: iosm: Enable M.2 7360 WWAN card support") Co-developed-by: Jianhao Xu Signed-off-by: Jianhao Xu Signed-off-by: Zilin Guan Reviewed-by: Loic Poulain Link: https://patch.msgid.link/20251230071853.1062223-1-zilin@seu.edu.cn Signed-off-by: Jakub Kicinski --- drivers/net/wwan/iosm/iosm_ipc_mux.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.c b/drivers/net/wwan/iosm/iosm_ipc_mux.c index fc928b298a98..b846889fcb09 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_mux.c +++ b/drivers/net/wwan/iosm/iosm_ipc_mux.c @@ -456,6 +456,7 @@ void ipc_mux_deinit(struct iosm_mux *ipc_mux) struct sk_buff_head *free_list; union mux_msg mux_msg; struct sk_buff *skb; + int i; if (!ipc_mux->initialized) return; @@ -479,5 +480,10 @@ void ipc_mux_deinit(struct iosm_mux *ipc_mux) ipc_mux->channel->dl_pipe.is_open = false; } + if (ipc_mux->protocol != MUX_LITE) { + for (i = 0; i < IPC_MEM_MUX_IP_SESSION_ENTRIES; i++) + kfree(ipc_mux->ul_adb.pp_qlt[i]); + } + kfree(ipc_mux); } -- cgit v1.2.3 From ffeafa65b2b26df2f5b5a6118d3174f17bd12ec5 Mon Sep 17 00:00:00 2001 From: Srijit Bose Date: Wed, 31 Dec 2025 00:36:25 -0800 Subject: bnxt_en: Fix potential data corruption with HW GRO/LRO Fix the max number of bits passed to find_first_zero_bit() in bnxt_alloc_agg_idx(). We were incorrectly passing the number of long words. find_first_zero_bit() may fail to find a zero bit and cause a wrong ID to be used. If the wrong ID is already in use, this can cause data corruption. Sometimes an error like this can also be seen: bnxt_en 0000:83:00.0 enp131s0np0: TPA end agg_buf 2 != expected agg_bufs 1 Fix it by passing the correct number of bits MAX_TPA_P5. Use DECLARE_BITMAP() to more cleanly define the bitmap. Add a sanity check to warn if a bit cannot be found and reset the ring [MChan]. Fixes: ec4d8e7cf024 ("bnxt_en: Add TPA ID mapping logic for 57500 chips.") Reviewed-by: Ray Jui Signed-off-by: Srijit Bose Signed-off-by: Michael Chan Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20251231083625.3911652-1-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 15 ++++++++++++--- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +--- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d17d0ea89c36..d160e54ac121 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1482,9 +1482,11 @@ static u16 bnxt_alloc_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id) struct bnxt_tpa_idx_map *map = rxr->rx_tpa_idx_map; u16 idx = agg_id & MAX_TPA_P5_MASK; - if (test_bit(idx, map->agg_idx_bmap)) - idx = find_first_zero_bit(map->agg_idx_bmap, - BNXT_AGG_IDX_BMAP_SIZE); + if (test_bit(idx, map->agg_idx_bmap)) { + idx = find_first_zero_bit(map->agg_idx_bmap, MAX_TPA_P5); + if (idx >= MAX_TPA_P5) + return INVALID_HW_RING_ID; + } __set_bit(idx, map->agg_idx_bmap); map->agg_id_tbl[agg_id] = idx; return idx; @@ -1548,6 +1550,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { agg_id = TPA_START_AGG_ID_P5(tpa_start); agg_id = bnxt_alloc_agg_idx(rxr, agg_id); + if (unlikely(agg_id == INVALID_HW_RING_ID)) { + netdev_warn(bp->dev, "Unable to allocate agg ID for ring %d, agg 0x%x\n", + rxr->bnapi->index, + TPA_START_AGG_ID_P5(tpa_start)); + bnxt_sched_reset_rxr(bp, rxr); + return; + } } else { agg_id = TPA_START_AGG_ID(tpa_start); } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index f5f07a7e6b29..f88e7769a838 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1080,11 +1080,9 @@ struct bnxt_tpa_info { struct rx_agg_cmp *agg_arr; }; -#define BNXT_AGG_IDX_BMAP_SIZE (MAX_TPA_P5 / BITS_PER_LONG) - struct bnxt_tpa_idx_map { u16 agg_id_tbl[1024]; - unsigned long agg_idx_bmap[BNXT_AGG_IDX_BMAP_SIZE]; + DECLARE_BITMAP(agg_idx_bmap, MAX_TPA_P5); }; struct bnxt_rx_ring_info { -- cgit v1.2.3 From acb4bc6e1ba34ae1a34a9334a1ce8474c909466e Mon Sep 17 00:00:00 2001 From: Kommula Shiva Shankar Date: Fri, 2 Jan 2026 15:49:00 +0530 Subject: virtio_net: fix device mismatch in devm_kzalloc/devm_kfree Initial rss_hdr allocation uses virtio_device->device, but virtnet_set_queues() frees using net_device->device. This device mismatch causing below devres warning [ 3788.514041] ------------[ cut here ]------------ [ 3788.514044] WARNING: drivers/base/devres.c:1095 at devm_kfree+0x84/0x98, CPU#16: vdpa/1463 [ 3788.514054] Modules linked in: octep_vdpa virtio_net virtio_vdpa [last unloaded: virtio_vdpa] [ 3788.514064] CPU: 16 UID: 0 PID: 1463 Comm: vdpa Tainted: G W 6.18.0 #10 PREEMPT [ 3788.514067] Tainted: [W]=WARN [ 3788.514069] Hardware name: Marvell CN106XX board (DT) [ 3788.514071] pstate: 63400009 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) [ 3788.514074] pc : devm_kfree+0x84/0x98 [ 3788.514076] lr : devm_kfree+0x54/0x98 [ 3788.514079] sp : ffff800084e2f220 [ 3788.514080] x29: ffff800084e2f220 x28: ffff0003b2366000 x27: 000000000000003f [ 3788.514085] x26: 000000000000003f x25: ffff000106f17c10 x24: 0000000000000080 [ 3788.514089] x23: ffff00045bb8ab08 x22: ffff00045bb8a000 x21: 0000000000000018 [ 3788.514093] x20: ffff0004355c3080 x19: ffff00045bb8aa00 x18: 0000000000080000 [ 3788.514098] x17: 0000000000000040 x16: 000000000000001f x15: 000000000007ffff [ 3788.514102] x14: 0000000000000488 x13: 0000000000000005 x12: 00000000000fffff [ 3788.514106] x11: ffffffffffffffff x10: 0000000000000005 x9 : ffff800080c8c05c [ 3788.514110] x8 : ffff800084e2eeb8 x7 : 0000000000000000 x6 : 000000000000003f [ 3788.514115] x5 : ffff8000831bafe0 x4 : ffff800080c8b010 x3 : ffff0004355c3080 [ 3788.514119] x2 : ffff0004355c3080 x1 : 0000000000000000 x0 : 0000000000000000 [ 3788.514123] Call trace: [ 3788.514125] devm_kfree+0x84/0x98 (P) [ 3788.514129] virtnet_set_queues+0x134/0x2e8 [virtio_net] [ 3788.514135] virtnet_probe+0x9c0/0xe00 [virtio_net] [ 3788.514139] virtio_dev_probe+0x1e0/0x338 [ 3788.514144] really_probe+0xc8/0x3a0 [ 3788.514149] __driver_probe_device+0x84/0x170 [ 3788.514152] driver_probe_device+0x44/0x120 [ 3788.514155] __device_attach_driver+0xc4/0x168 [ 3788.514158] bus_for_each_drv+0x8c/0xf0 [ 3788.514161] __device_attach+0xa4/0x1c0 [ 3788.514164] device_initial_probe+0x1c/0x30 [ 3788.514168] bus_probe_device+0xb4/0xc0 [ 3788.514170] device_add+0x614/0x828 [ 3788.514173] register_virtio_device+0x214/0x258 [ 3788.514175] virtio_vdpa_probe+0xa0/0x110 [virtio_vdpa] [ 3788.514179] vdpa_dev_probe+0xa8/0xd8 [ 3788.514183] really_probe+0xc8/0x3a0 [ 3788.514186] __driver_probe_device+0x84/0x170 [ 3788.514189] driver_probe_device+0x44/0x120 [ 3788.514192] __device_attach_driver+0xc4/0x168 [ 3788.514195] bus_for_each_drv+0x8c/0xf0 [ 3788.514197] __device_attach+0xa4/0x1c0 [ 3788.514200] device_initial_probe+0x1c/0x30 [ 3788.514203] bus_probe_device+0xb4/0xc0 [ 3788.514206] device_add+0x614/0x828 [ 3788.514209] _vdpa_register_device+0x58/0x88 [ 3788.514211] octep_vdpa_dev_add+0x104/0x228 [octep_vdpa] [ 3788.514215] vdpa_nl_cmd_dev_add_set_doit+0x2d0/0x3c0 [ 3788.514218] genl_family_rcv_msg_doit+0xe4/0x158 [ 3788.514222] genl_rcv_msg+0x218/0x298 [ 3788.514225] netlink_rcv_skb+0x64/0x138 [ 3788.514229] genl_rcv+0x40/0x60 [ 3788.514233] netlink_unicast+0x32c/0x3b0 [ 3788.514237] netlink_sendmsg+0x170/0x3b8 [ 3788.514241] __sys_sendto+0x12c/0x1c0 [ 3788.514246] __arm64_sys_sendto+0x30/0x48 [ 3788.514249] invoke_syscall.constprop.0+0x58/0xf8 [ 3788.514255] do_el0_svc+0x48/0xd0 [ 3788.514259] el0_svc+0x48/0x210 [ 3788.514264] el0t_64_sync_handler+0xa0/0xe8 [ 3788.514268] el0t_64_sync+0x198/0x1a0 [ 3788.514271] ---[ end trace 0000000000000000 ]--- Fix by using virtio_device->device consistently for allocation and deallocation Fixes: 4944be2f5ad8c ("virtio_net: Allocate rss_hdr with devres") Signed-off-by: Kommula Shiva Shankar Acked-by: Michael S. Tsirkin Acked-by: Jason Wang Reviewed-by: Xuan Zhuo Link: https://patch.msgid.link/20260102101900.692770-1-kshankar@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1bb3aeca66c6..22d894101c01 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3791,7 +3791,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) if (vi->has_rss && !netif_is_rxfh_configured(dev)) { old_rss_hdr = vi->rss_hdr; old_rss_trailer = vi->rss_trailer; - vi->rss_hdr = devm_kzalloc(&dev->dev, virtnet_rss_hdr_size(vi), GFP_KERNEL); + vi->rss_hdr = devm_kzalloc(&vi->vdev->dev, virtnet_rss_hdr_size(vi), GFP_KERNEL); if (!vi->rss_hdr) { vi->rss_hdr = old_rss_hdr; return -ENOMEM; @@ -3802,7 +3802,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) if (!virtnet_commit_rss_command(vi)) { /* restore ctrl_rss if commit_rss_command failed */ - devm_kfree(&dev->dev, vi->rss_hdr); + devm_kfree(&vi->vdev->dev, vi->rss_hdr); vi->rss_hdr = old_rss_hdr; vi->rss_trailer = old_rss_trailer; @@ -3810,7 +3810,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) queue_pairs); return -EINVAL; } - devm_kfree(&dev->dev, old_rss_hdr); + devm_kfree(&vi->vdev->dev, old_rss_hdr); goto succ; } -- cgit v1.2.3 From df27c03b9e3ef2baa9e9c9f56a771d463a84489d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 3 Nov 2025 16:19:26 -0600 Subject: PCI: meson: Report that link is up while in ASPM L0s and L1 states Previously meson_pcie_link_up() only returned true if the link was in the L0 state. This was incorrect because hardware autonomously manages transitions between L0, L0s, and L1 while both components on the link stay in D0. Those states should all be treated as "link is active". Returning false when the device was in L0s or L1 broke config accesses because dw_pcie_other_conf_map_bus() fails if the link is down, which caused errors like this: meson-pcie fc000000.pcie: error: wait linkup timeout pci 0000:01:00.0: BAR 0: error updating (0xfc700004 != 0xffffffff) Remove the LTSSM state check, timeout, speed check, and error message from meson_pcie_link_up(), the dw_pcie_ops.link_up() method, so it is a simple boolean check of whether the link is active. Timeouts and error messages are handled at a higher level, e.g., dw_pcie_wait_for_link(). Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Reported-by: Linnaea Lavia Closes: https://lore.kernel.org/r/DM4PR05MB102707B8CDF84D776C39F22F2C7F0A@DM4PR05MB10270.namprd05.prod.outlook.com [bhelgaas: squash removal of unused WAIT_LINKUP_TIMEOUT by Martin Blumenstingl : https://patch.msgid.link/20260105125625.239497-1-martin.blumenstingl@googlemail.com] Signed-off-by: Bjorn Helgaas Tested-by: Linnaea Lavia Tested-by: Neil Armstrong # on BananaPi M2S Reviewed-by: Neil Armstrong Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251103221930.1831376-1-helgaas@kernel.org Link: https://patch.msgid.link/20260105125625.239497-1-martin.blumenstingl@googlemail.com --- drivers/pci/controller/dwc/pci-meson.c | 39 ++++------------------------------ 1 file changed, 4 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 54b6a4196f17..0694084f612b 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -37,7 +37,6 @@ #define PCIE_CFG_STATUS17 0x44 #define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1) -#define WAIT_LINKUP_TIMEOUT 4000 #define PORT_CLK_RATE 100000000UL #define MAX_PAYLOAD_SIZE 256 #define MAX_READ_REQ_SIZE 256 @@ -350,40 +349,10 @@ static struct pci_ops meson_pci_ops = { static bool meson_pcie_link_up(struct dw_pcie *pci) { struct meson_pcie *mp = to_meson_pcie(pci); - struct device *dev = pci->dev; - u32 speed_okay = 0; - u32 cnt = 0; - u32 state12, state17, smlh_up, ltssm_up, rdlh_up; - - do { - state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12); - state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17); - smlh_up = IS_SMLH_LINK_UP(state12); - rdlh_up = IS_RDLH_LINK_UP(state12); - ltssm_up = IS_LTSSM_UP(state12); - - if (PM_CURRENT_STATE(state17) < PCIE_GEN3) - speed_okay = 1; - - if (smlh_up) - dev_dbg(dev, "smlh_link_up is on\n"); - if (rdlh_up) - dev_dbg(dev, "rdlh_link_up is on\n"); - if (ltssm_up) - dev_dbg(dev, "ltssm_up is on\n"); - if (speed_okay) - dev_dbg(dev, "speed_okay\n"); - - if (smlh_up && rdlh_up && ltssm_up && speed_okay) - return true; - - cnt++; - - udelay(10); - } while (cnt < WAIT_LINKUP_TIMEOUT); - - dev_err(dev, "error: wait linkup timeout\n"); - return false; + u32 state12; + + state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12); + return IS_SMLH_LINK_UP(state12) && IS_RDLH_LINK_UP(state12); } static int meson_pcie_host_init(struct dw_pcie_rp *pp) -- cgit v1.2.3 From 1ca8677d9f3491e51395b0e6b9a2b7a75089dc6f Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 5 Jan 2026 11:17:05 +0100 Subject: ACPI: PCI: IRQ: Fix INTx GSIs signedness In ACPI Global System Interrupts (GSIs) are described using a 32-bit value. ACPI/PCI legacy interrupts (INTx) parsing code treats GSIs as 'int', which poses issues if the GSI interrupt value is a 32-bit value with the MSB set (as required in some interrupt configurations - eg ARM64 GICv5 systems) because acpi_pci_link_allocate_irq() treats a negative gsi return value as a failed GSI allocation (and acpi_irq_get_penalty() would trigger an out-of-bounds array dereference if the 'irq' param is a negative value). Fix ACPI/PCI legacy INTx parsing by converting variables representing GSIs from 'int' to 'u32' bringing the code in line with the ACPI specification and fixing the current parsing issue. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Helgaas Link: https://patch.msgid.link/20260105101705.36703-1-lpieralisi@kernel.org Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_irq.c | 19 +++++++++++-------- drivers/acpi/pci_link.c | 39 +++++++++++++++++++++++++-------------- drivers/xen/acpi.c | 13 +++++++------ 3 files changed, 43 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index ad81aa03fe2f..c416942ff3e2 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -188,7 +188,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - pr_debug("%04x:%02x:%02x[%c] -> %s[%d]\n", + pr_debug("%04x:%02x:%02x[%c] -> %s[%u]\n", entry->id.segment, entry->id.bus, entry->id.device, pin_name(entry->pin), prt->source, entry->index); @@ -384,7 +384,7 @@ static inline bool acpi_pci_irq_valid(struct pci_dev *dev, u8 pin) int acpi_pci_irq_enable(struct pci_dev *dev) { struct acpi_prt_entry *entry; - int gsi; + u32 gsi; u8 pin; int triggering = ACPI_LEVEL_SENSITIVE; /* @@ -422,18 +422,21 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } + rc = -ENODEV; + if (entry) { if (entry->link) - gsi = acpi_pci_link_allocate_irq(entry->link, + rc = acpi_pci_link_allocate_irq(entry->link, entry->index, &triggering, &polarity, - &link); - else + &link, &gsi); + else { gsi = entry->index; - } else - gsi = -1; + rc = 0; + } + } - if (gsi < 0) { + if (rc < 0) { /* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index bed7dc85612e..b91b039a3d20 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -448,7 +448,7 @@ static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = { /* >IRQ15 */ }; -static int acpi_irq_pci_sharing_penalty(int irq) +static int acpi_irq_pci_sharing_penalty(u32 irq) { struct acpi_pci_link *link; int penalty = 0; @@ -474,7 +474,7 @@ static int acpi_irq_pci_sharing_penalty(int irq) return penalty; } -static int acpi_irq_get_penalty(int irq) +static int acpi_irq_get_penalty(u32 irq) { int penalty = 0; @@ -528,7 +528,7 @@ static int acpi_irq_balance = -1; /* 0: static, 1: balance */ static int acpi_pci_link_allocate(struct acpi_pci_link *link) { acpi_handle handle = link->device->handle; - int irq; + u32 irq; int i; if (link->irq.initialized) { @@ -598,44 +598,53 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) return 0; } -/* - * acpi_pci_link_allocate_irq - * success: return IRQ >= 0 - * failure: return -1 +/** + * acpi_pci_link_allocate_irq(): Retrieve a link device GSI + * + * @handle: Handle for the link device + * @index: GSI index + * @triggering: pointer to store the GSI trigger + * @polarity: pointer to store GSI polarity + * @name: pointer to store link device name + * @gsi: pointer to store GSI number + * + * Returns: + * 0 on success with @triggering, @polarity, @name, @gsi initialized. + * -ENODEV on failure */ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, - int *polarity, char **name) + int *polarity, char **name, u32 *gsi) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); struct acpi_pci_link *link; if (!device) { acpi_handle_err(handle, "Invalid link device\n"); - return -1; + return -ENODEV; } link = acpi_driver_data(device); if (!link) { acpi_handle_err(handle, "Invalid link context\n"); - return -1; + return -ENODEV; } /* TBD: Support multiple index (IRQ) entries per Link Device */ if (index) { acpi_handle_err(handle, "Invalid index %d\n", index); - return -1; + return -ENODEV; } mutex_lock(&acpi_link_lock); if (acpi_pci_link_allocate(link)) { mutex_unlock(&acpi_link_lock); - return -1; + return -ENODEV; } if (!link->irq.active) { mutex_unlock(&acpi_link_lock); acpi_handle_err(handle, "Link active IRQ is 0!\n"); - return -1; + return -ENODEV; } link->refcnt++; mutex_unlock(&acpi_link_lock); @@ -647,7 +656,9 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, if (name) *name = acpi_device_bid(link->device); acpi_handle_debug(handle, "Link is referenced\n"); - return link->irq.active; + *gsi = link->irq.active; + + return 0; } /* diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c index d2ee605c5ca1..eab28cfe9939 100644 --- a/drivers/xen/acpi.c +++ b/drivers/xen/acpi.c @@ -89,11 +89,11 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev, int *trigger_out, int *polarity_out) { - int gsi; + u32 gsi; u8 pin; struct acpi_prt_entry *entry; int trigger = ACPI_LEVEL_SENSITIVE; - int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ? + int ret, polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ? ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW; if (!dev || !gsi_out || !trigger_out || !polarity_out) @@ -105,17 +105,18 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev, entry = acpi_pci_irq_lookup(dev, pin); if (entry) { + ret = 0; if (entry->link) - gsi = acpi_pci_link_allocate_irq(entry->link, + ret = acpi_pci_link_allocate_irq(entry->link, entry->index, &trigger, &polarity, - NULL); + NULL, &gsi); else gsi = entry->index; } else - gsi = -1; + ret = -ENODEV; - if (gsi < 0) + if (ret < 0) return -EINVAL; *gsi_out = gsi; -- cgit v1.2.3 From 70740454377f1ba3ff32f5df4acd965db99d055b Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 13 Dec 2025 15:16:43 +0900 Subject: drm/amd/display: Apply e4479aecf658 to dml After an innocuous optimization change in clang-22, allmodconfig (which enables CONFIG_KASAN and CONFIG_WERROR) breaks with: drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_32.c:1724:6: error: stack frame size (3144) exceeds limit (3072) in 'dml32_ModeSupportAndSystemConfigurationFull' [-Werror,-Wframe-larger-than] 1724 | void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ With clang-21, this function was already pretty close to the existing limit of 3072 bytes. drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_32.c:1724:6: error: stack frame size (2904) exceeds limit (2048) in 'dml32_ModeSupportAndSystemConfigurationFull' [-Werror,-Wframe-larger-than] 1724 | void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ A similar situation occurred in dml2, which was resolved by commit e4479aecf658 ("drm/amd/display: Increase sanitizer frame larger than limit when compile testing with clang") by increasing the limit for clang when compile testing with certain sanitizer enabled, so that allmodconfig (an easy testing target) continues to work. Apply that same change to the dml folder to clear up the warning for allmodconfig, unbreaking the build. Closes: https://github.com/ClangBuiltLinux/linux/issues/2135 Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher (cherry picked from commit 25314b453cf812150e9951a32007a32bba85707e) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index b357683b4255..268b5fbdb48b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -30,7 +30,11 @@ dml_rcflags := $(CC_FLAGS_NO_FPU) ifneq ($(CONFIG_FRAME_WARN),0) ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) - frame_warn_limit := 3072 + ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) + frame_warn_limit := 4096 + else + frame_warn_limit := 3072 + endif else frame_warn_limit := 2048 endif -- cgit v1.2.3 From f54a91f5337cd918eb86cf600320d25b6cfd8209 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 13 Dec 2025 19:58:10 +0900 Subject: drm/amd/display: Reduce number of arguments of dcn30's CalculatePrefetchSchedule() After an innocuous optimization change in clang-22, dml30_ModeSupportAndSystemConfigurationFull() is over the 2048 byte stack limit for display_mode_vba_30.c. drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (2096) exceeds limit (2048) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than] 3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ With clang-21, this function was already close to the limit: drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (1912) exceeds limit (1586) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than] 3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) | ^ CalculatePrefetchSchedule() has a large number of parameters, which must be passed on the stack. Most of the parameters between the two callsites are the same, so they can be accessed through the existing mode_lib pointer, instead of being passed as explicit arguments. Doing this reduces the stack size of dml30_ModeSupportAndSystemConfigurationFull() from 2096 bytes to 1912 bytes with clang-22. Closes: https://github.com/ClangBuiltLinux/linux/issues/2117 Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher (cherry picked from commit b20b3fc4210f83089f835cdb91deec4b0778761a) --- .../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 258 ++++++--------------- 1 file changed, 73 insertions(+), 185 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 8d24763938ea..2d19bb8de59c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -77,32 +77,14 @@ static unsigned int dscceComputeDelay( static unsigned int dscComputeDelay( enum output_format_class pixelFormat, enum output_encoder_class Output); -// Super monster function with some 45 argument static bool CalculatePrefetchSchedule( struct display_mode_lib *mode_lib, - double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, - double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + unsigned int k, Pipe *myPipe, unsigned int DSCDelay, - double DPPCLKDelaySubtotalPlusCNVCFormater, - double DPPCLKDelaySCL, - double DPPCLKDelaySCLLBOnly, - double DPPCLKDelayCNVCCursor, - double DISPCLKDelaySubtotal, unsigned int DPP_RECOUT_WIDTH, - enum output_format_class OutputFormat, - unsigned int MaxInterDCNTileRepeaters, unsigned int VStartup, unsigned int MaxVStartup, - unsigned int GPUVMPageTableLevels, - bool GPUVMEnable, - bool HostVMEnable, - unsigned int HostVMMaxNonCachedPageTableLevels, - double HostVMMinPageSize, - bool DynamicMetadataEnable, - bool DynamicMetadataVMEnabled, - int DynamicMetadataLinesBeforeActiveRequired, - unsigned int DynamicMetadataTransmittedBytes, double UrgentLatency, double UrgentExtraLatency, double TCalc, @@ -116,7 +98,6 @@ static bool CalculatePrefetchSchedule( unsigned int MaxNumSwathY, double PrefetchSourceLinesC, unsigned int SwathWidthC, - int BytePerPixelC, double VInitPreFillC, unsigned int MaxNumSwathC, long swath_width_luma_ub, @@ -124,9 +105,6 @@ static bool CalculatePrefetchSchedule( unsigned int SwathHeightY, unsigned int SwathHeightC, double TWait, - bool ProgressiveToInterlaceUnitInOPP, - double *DSTXAfterScaler, - double *DSTYAfterScaler, double *DestinationLinesForPrefetch, double *PrefetchBandwidth, double *DestinationLinesToRequestVMInVBlank, @@ -135,14 +113,7 @@ static bool CalculatePrefetchSchedule( double *VRatioPrefetchC, double *RequiredPrefetchPixDataBWLuma, double *RequiredPrefetchPixDataBWChroma, - bool *NotEnoughTimeForDynamicMetadata, - double *Tno_bw, - double *prefetch_vmrow_bw, - double *Tdmdl_vm, - double *Tdmdl, - unsigned int *VUpdateOffsetPix, - double *VUpdateWidthPix, - double *VReadyOffsetPix); + bool *NotEnoughTimeForDynamicMetadata); static double RoundToDFSGranularityUp(double Clock, double VCOSpeed); static double RoundToDFSGranularityDown(double Clock, double VCOSpeed); static void CalculateDCCConfiguration( @@ -810,29 +781,12 @@ static unsigned int dscComputeDelay(enum output_format_class pixelFormat, enum o static bool CalculatePrefetchSchedule( struct display_mode_lib *mode_lib, - double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, - double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + unsigned int k, Pipe *myPipe, unsigned int DSCDelay, - double DPPCLKDelaySubtotalPlusCNVCFormater, - double DPPCLKDelaySCL, - double DPPCLKDelaySCLLBOnly, - double DPPCLKDelayCNVCCursor, - double DISPCLKDelaySubtotal, unsigned int DPP_RECOUT_WIDTH, - enum output_format_class OutputFormat, - unsigned int MaxInterDCNTileRepeaters, unsigned int VStartup, unsigned int MaxVStartup, - unsigned int GPUVMPageTableLevels, - bool GPUVMEnable, - bool HostVMEnable, - unsigned int HostVMMaxNonCachedPageTableLevels, - double HostVMMinPageSize, - bool DynamicMetadataEnable, - bool DynamicMetadataVMEnabled, - int DynamicMetadataLinesBeforeActiveRequired, - unsigned int DynamicMetadataTransmittedBytes, double UrgentLatency, double UrgentExtraLatency, double TCalc, @@ -846,7 +800,6 @@ static bool CalculatePrefetchSchedule( unsigned int MaxNumSwathY, double PrefetchSourceLinesC, unsigned int SwathWidthC, - int BytePerPixelC, double VInitPreFillC, unsigned int MaxNumSwathC, long swath_width_luma_ub, @@ -854,9 +807,6 @@ static bool CalculatePrefetchSchedule( unsigned int SwathHeightY, unsigned int SwathHeightC, double TWait, - bool ProgressiveToInterlaceUnitInOPP, - double *DSTXAfterScaler, - double *DSTYAfterScaler, double *DestinationLinesForPrefetch, double *PrefetchBandwidth, double *DestinationLinesToRequestVMInVBlank, @@ -865,15 +815,10 @@ static bool CalculatePrefetchSchedule( double *VRatioPrefetchC, double *RequiredPrefetchPixDataBWLuma, double *RequiredPrefetchPixDataBWChroma, - bool *NotEnoughTimeForDynamicMetadata, - double *Tno_bw, - double *prefetch_vmrow_bw, - double *Tdmdl_vm, - double *Tdmdl, - unsigned int *VUpdateOffsetPix, - double *VUpdateWidthPix, - double *VReadyOffsetPix) + bool *NotEnoughTimeForDynamicMetadata) { + struct vba_vars_st *v = &mode_lib->vba; + double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater; bool MyError = false; unsigned int DPPCycles = 0, DISPCLKCycles = 0; double DSTTotalPixelsAfterScaler = 0; @@ -905,26 +850,26 @@ static bool CalculatePrefetchSchedule( double Tdmec = 0; double Tdmsks = 0; - if (GPUVMEnable == true && HostVMEnable == true) { - HostVMInefficiencyFactor = PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; - HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels; + if (v->GPUVMEnable == true && v->HostVMEnable == true) { + HostVMInefficiencyFactor = v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; + HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels; } else { HostVMInefficiencyFactor = 1; HostVMDynamicLevelsTrips = 0; } CalculateDynamicMetadataParameters( - MaxInterDCNTileRepeaters, + v->MaxInterDCNTileRepeaters, myPipe->DPPCLK, myPipe->DISPCLK, myPipe->DCFCLKDeepSleep, myPipe->PixelClock, myPipe->HTotal, myPipe->VBlank, - DynamicMetadataTransmittedBytes, - DynamicMetadataLinesBeforeActiveRequired, + v->DynamicMetadataTransmittedBytes[k], + v->DynamicMetadataLinesBeforeActiveRequired[k], myPipe->InterlaceEnable, - ProgressiveToInterlaceUnitInOPP, + v->ProgressiveToInterlaceUnitInOPP, &Tsetup, &Tdmbf, &Tdmec, @@ -932,16 +877,16 @@ static bool CalculatePrefetchSchedule( LineTime = myPipe->HTotal / myPipe->PixelClock; trip_to_mem = UrgentLatency; - Tvm_trips = UrgentExtraLatency + trip_to_mem * (GPUVMPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1); + Tvm_trips = UrgentExtraLatency + trip_to_mem * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1); - if (DynamicMetadataVMEnabled == true && GPUVMEnable == true) { - *Tdmdl = TWait + Tvm_trips + trip_to_mem; + if (v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true) { + v->Tdmdl[k] = TWait + Tvm_trips + trip_to_mem; } else { - *Tdmdl = TWait + UrgentExtraLatency; + v->Tdmdl[k] = TWait + UrgentExtraLatency; } - if (DynamicMetadataEnable == true) { - if (VStartup * LineTime < Tsetup + *Tdmdl + Tdmbf + Tdmec + Tdmsks) { + if (v->DynamicMetadataEnable[k] == true) { + if (VStartup * LineTime < Tsetup + v->Tdmdl[k] + Tdmbf + Tdmec + Tdmsks) { *NotEnoughTimeForDynamicMetadata = true; } else { *NotEnoughTimeForDynamicMetadata = false; @@ -949,39 +894,39 @@ static bool CalculatePrefetchSchedule( dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf); dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec); dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks); - dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl); + dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]); } } else { *NotEnoughTimeForDynamicMetadata = false; } - *Tdmdl_vm = (DynamicMetadataEnable == true && DynamicMetadataVMEnabled == true && GPUVMEnable == true ? TWait + Tvm_trips : 0); + v->Tdmdl_vm[k] = (v->DynamicMetadataEnable[k] == true && v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true ? TWait + Tvm_trips : 0); if (myPipe->ScalerEnabled) - DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCL; + DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCL; else - DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCLLBOnly; + DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCLLBOnly; - DPPCycles = DPPCycles + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor; + DPPCycles = DPPCycles + myPipe->NumberOfCursors * v->DPPCLKDelayCNVCCursor; - DISPCLKCycles = DISPCLKDelaySubtotal; + DISPCLKCycles = v->DISPCLKDelaySubtotal; if (myPipe->DPPCLK == 0.0 || myPipe->DISPCLK == 0.0) return true; - *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK + v->DSTXAfterScaler[k] = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK + DSCDelay; - *DSTXAfterScaler = *DSTXAfterScaler + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH; + v->DSTXAfterScaler[k] = v->DSTXAfterScaler[k] + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH; - if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && ProgressiveToInterlaceUnitInOPP)) - *DSTYAfterScaler = 1; + if (v->OutputFormat[k] == dm_420 || (myPipe->InterlaceEnable && v->ProgressiveToInterlaceUnitInOPP)) + v->DSTYAfterScaler[k] = 1; else - *DSTYAfterScaler = 0; + v->DSTYAfterScaler[k] = 0; - DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler; - *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1); - *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal)); + DSTTotalPixelsAfterScaler = v->DSTYAfterScaler[k] * myPipe->HTotal + v->DSTXAfterScaler[k]; + v->DSTYAfterScaler[k] = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1); + v->DSTXAfterScaler[k] = DSTTotalPixelsAfterScaler - ((double) (v->DSTYAfterScaler[k] * myPipe->HTotal)); MyError = false; @@ -990,33 +935,33 @@ static bool CalculatePrefetchSchedule( Tvm_trips_rounded = dml_ceil(4.0 * Tvm_trips / LineTime, 1) / 4 * LineTime; Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1) / 4 * LineTime; - if (GPUVMEnable) { - if (GPUVMPageTableLevels >= 3) { - *Tno_bw = UrgentExtraLatency + trip_to_mem * ((GPUVMPageTableLevels - 2) - 1); + if (v->GPUVMEnable) { + if (v->GPUVMMaxPageTableLevels >= 3) { + v->Tno_bw[k] = UrgentExtraLatency + trip_to_mem * ((v->GPUVMMaxPageTableLevels - 2) - 1); } else - *Tno_bw = 0; + v->Tno_bw[k] = 0; } else if (!myPipe->DCCEnable) - *Tno_bw = LineTime; + v->Tno_bw[k] = LineTime; else - *Tno_bw = LineTime / 4; + v->Tno_bw[k] = LineTime / 4; - dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime - - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal); + dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, v->Tdmdl[k])) / LineTime + - (v->DSTYAfterScaler[k] + v->DSTXAfterScaler[k] / myPipe->HTotal); dst_y_prefetch_equ = dml_min(dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH Lsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC); Tsw_oto = Lsw_oto * LineTime; - prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC) / Tsw_oto; + prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k]) / Tsw_oto; - if (GPUVMEnable == true) { - Tvm_oto = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto, + if (v->GPUVMEnable == true) { + Tvm_oto = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto, Tvm_trips, LineTime / 4.0); } else Tvm_oto = LineTime / 4.0; - if ((GPUVMEnable == true || myPipe->DCCEnable == true)) { + if ((v->GPUVMEnable == true || myPipe->DCCEnable == true)) { Tr0_oto = dml_max3( (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto, LineTime - Tvm_oto, LineTime / 4); @@ -1042,10 +987,10 @@ static bool CalculatePrefetchSchedule( dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf); dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec); dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks); - dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", *Tdmdl_vm); - dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl); - dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", *DSTXAfterScaler); - dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)*DSTYAfterScaler); + dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", v->Tdmdl_vm[k]); + dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]); + dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", v->DSTXAfterScaler[k]); + dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)v->DSTYAfterScaler[k]); *PrefetchBandwidth = 0; *DestinationLinesToRequestVMInVBlank = 0; @@ -1059,26 +1004,26 @@ static bool CalculatePrefetchSchedule( double PrefetchBandwidth3 = 0; double PrefetchBandwidth4 = 0; - if (Tpre_rounded - *Tno_bw > 0) + if (Tpre_rounded - v->Tno_bw[k] > 0) PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor + PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY - + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC) - / (Tpre_rounded - *Tno_bw); + + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k]) + / (Tpre_rounded - v->Tno_bw[k]); else PrefetchBandwidth1 = 0; - if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw) > 0) { - PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw); + if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]) > 0) { + PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]); } - if (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded > 0) + if (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded > 0) PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * - BytePerPixelC) / - (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded); + v->BytePerPixelC[k]) / + (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded); else PrefetchBandwidth2 = 0; @@ -1086,7 +1031,7 @@ static bool CalculatePrefetchSchedule( PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor + PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * - swath_width_chroma_ub * BytePerPixelC) / (Tpre_rounded - + swath_width_chroma_ub * v->BytePerPixelC[k]) / (Tpre_rounded - Tvm_trips_rounded); else PrefetchBandwidth3 = 0; @@ -1096,7 +1041,7 @@ static bool CalculatePrefetchSchedule( } if (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded > 0) - PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC) + PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k]) / (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded); else PrefetchBandwidth4 = 0; @@ -1107,7 +1052,7 @@ static bool CalculatePrefetchSchedule( bool Case3OK; if (PrefetchBandwidth1 > 0) { - if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1 + if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1 >= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth1 >= Tr0_trips_rounded) { Case1OK = true; } else { @@ -1118,7 +1063,7 @@ static bool CalculatePrefetchSchedule( } if (PrefetchBandwidth2 > 0) { - if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2 + if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2 >= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth2 < Tr0_trips_rounded) { Case2OK = true; } else { @@ -1129,7 +1074,7 @@ static bool CalculatePrefetchSchedule( } if (PrefetchBandwidth3 > 0) { - if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3 + if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3 < Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth3 >= Tr0_trips_rounded) { Case3OK = true; } else { @@ -1152,13 +1097,13 @@ static bool CalculatePrefetchSchedule( dml_print("DML: prefetch_bw_equ: %f\n", prefetch_bw_equ); if (prefetch_bw_equ > 0) { - if (GPUVMEnable) { - Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4); + if (v->GPUVMEnable) { + Tvm_equ = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4); } else { Tvm_equ = LineTime / 4; } - if ((GPUVMEnable || myPipe->DCCEnable)) { + if ((v->GPUVMEnable || myPipe->DCCEnable)) { Tr0_equ = dml_max4( (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_equ, Tr0_trips, @@ -1227,7 +1172,7 @@ static bool CalculatePrefetchSchedule( } *RequiredPrefetchPixDataBWLuma = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData * BytePerPixelY * swath_width_luma_ub / LineTime; - *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * BytePerPixelC * swath_width_chroma_ub / LineTime; + *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * v->BytePerPixelC[k] * swath_width_chroma_ub / LineTime; } else { MyError = true; dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); @@ -1243,9 +1188,9 @@ static bool CalculatePrefetchSchedule( dml_print("DML: Tr0: %fus - time to fetch first row of data pagetables and first row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank); dml_print("DML: Tr1: %fus - time to fetch second row of data pagetables and second row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank); dml_print("DML: Tsw: %fus = time to fetch enough pixel data and cursor data to feed the scalers init position and detile\n", (double)LinesToRequestPrefetchPixelData * LineTime); - dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime); + dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime); dml_print("DML: Tvstartup - Tsetup - Tcalc - Twait - Tpre - To > 0\n"); - dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup); + dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup); dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n", PixelPTEBytesPerRow); } else { @@ -1276,7 +1221,7 @@ static bool CalculatePrefetchSchedule( dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__); } - *prefetch_vmrow_bw = dml_max(prefetch_vm_bw, prefetch_row_bw); + v->prefetch_vmrow_bw[k] = dml_max(prefetch_vm_bw, prefetch_row_bw); } if (MyError) { @@ -2437,30 +2382,12 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->ErrorResult[k] = CalculatePrefetchSchedule( mode_lib, - v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, - v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + k, &myPipe, v->DSCDelay[k], - v->DPPCLKDelaySubtotal - + v->DPPCLKDelayCNVCFormater, - v->DPPCLKDelaySCL, - v->DPPCLKDelaySCLLBOnly, - v->DPPCLKDelayCNVCCursor, - v->DISPCLKDelaySubtotal, (unsigned int) (v->SwathWidthY[k] / v->HRatio[k]), - v->OutputFormat[k], - v->MaxInterDCNTileRepeaters, dml_min(v->VStartupLines, v->MaxVStartupLines[k]), v->MaxVStartupLines[k], - v->GPUVMMaxPageTableLevels, - v->GPUVMEnable, - v->HostVMEnable, - v->HostVMMaxNonCachedPageTableLevels, - v->HostVMMinPageSize, - v->DynamicMetadataEnable[k], - v->DynamicMetadataVMEnabled, - v->DynamicMetadataLinesBeforeActiveRequired[k], - v->DynamicMetadataTransmittedBytes[k], v->UrgentLatency, v->UrgentExtraLatency, v->TCalc, @@ -2474,7 +2401,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->MaxNumSwathY[k], v->PrefetchSourceLinesC[k], v->SwathWidthC[k], - v->BytePerPixelC[k], v->VInitPreFillC[k], v->MaxNumSwathC[k], v->swath_width_luma_ub[k], @@ -2482,9 +2408,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->SwathHeightY[k], v->SwathHeightC[k], TWait, - v->ProgressiveToInterlaceUnitInOPP, - &v->DSTXAfterScaler[k], - &v->DSTYAfterScaler[k], &v->DestinationLinesForPrefetch[k], &v->PrefetchBandwidth[k], &v->DestinationLinesToRequestVMInVBlank[k], @@ -2493,14 +2416,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman &v->VRatioPrefetchC[k], &v->RequiredPrefetchPixDataBWLuma[k], &v->RequiredPrefetchPixDataBWChroma[k], - &v->NotEnoughTimeForDynamicMetadata[k], - &v->Tno_bw[k], - &v->prefetch_vmrow_bw[k], - &v->Tdmdl_vm[k], - &v->Tdmdl[k], - &v->VUpdateOffsetPix[k], - &v->VUpdateWidthPix[k], - &v->VReadyOffsetPix[k]); + &v->NotEnoughTimeForDynamicMetadata[k]); if (v->BlendingAndTiming[k] == k) { double TotalRepeaterDelayTime = v->MaxInterDCNTileRepeaters * (2 / v->DPPCLK[k] + 3 / v->DISPCLK); v->VUpdateWidthPix[k] = (14 / v->DCFCLKDeepSleep + 12 / v->DPPCLK[k] + TotalRepeaterDelayTime) * v->PixelClock[k]; @@ -4770,29 +4686,12 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->NoTimeForPrefetch[i][j][k] = CalculatePrefetchSchedule( mode_lib, - v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, - v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + k, &myPipe, v->DSCDelayPerState[i][k], - v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater, - v->DPPCLKDelaySCL, - v->DPPCLKDelaySCLLBOnly, - v->DPPCLKDelayCNVCCursor, - v->DISPCLKDelaySubtotal, v->SwathWidthYThisState[k] / v->HRatio[k], - v->OutputFormat[k], - v->MaxInterDCNTileRepeaters, dml_min(v->MaxVStartup, v->MaximumVStartup[i][j][k]), v->MaximumVStartup[i][j][k], - v->GPUVMMaxPageTableLevels, - v->GPUVMEnable, - v->HostVMEnable, - v->HostVMMaxNonCachedPageTableLevels, - v->HostVMMinPageSize, - v->DynamicMetadataEnable[k], - v->DynamicMetadataVMEnabled, - v->DynamicMetadataLinesBeforeActiveRequired[k], - v->DynamicMetadataTransmittedBytes[k], v->UrgLatency[i], v->ExtraLatency, v->TimeCalc, @@ -4806,7 +4705,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->MaxNumSwY[k], v->PrefetchLinesC[i][j][k], v->SwathWidthCThisState[k], - v->BytePerPixelC[k], v->PrefillC[k], v->MaxNumSwC[k], v->swath_width_luma_ub_this_state[k], @@ -4814,9 +4712,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->SwathHeightYThisState[k], v->SwathHeightCThisState[k], v->TWait, - v->ProgressiveToInterlaceUnitInOPP, - &v->DSTXAfterScaler[k], - &v->DSTYAfterScaler[k], &v->LineTimesForPrefetch[k], &v->PrefetchBW[k], &v->LinesForMetaPTE[k], @@ -4825,14 +4720,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l &v->VRatioPreC[i][j][k], &v->RequiredPrefetchPixelDataBWLuma[i][j][k], &v->RequiredPrefetchPixelDataBWChroma[i][j][k], - &v->NoTimeForDynamicMetadata[i][j][k], - &v->Tno_bw[k], - &v->prefetch_vmrow_bw[k], - &v->Tdmdl_vm[k], - &v->Tdmdl[k], - &v->VUpdateOffsetPix[k], - &v->VUpdateWidthPix[k], - &v->VReadyOffsetPix[k]); + &v->NoTimeForDynamicMetadata[i][j][k]); } for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { -- cgit v1.2.3 From 6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 13 Dec 2025 19:58:11 +0900 Subject: drm/amd/display: Reduce number of arguments of dcn30's CalculateWatermarksAndDRAMSpeedChangeSupport() CalculateWatermarksAndDRAMSpeedChangeSupport() has a large number of parameters, which must be passed on the stack. Most of the parameters between the two callsites are the same, so they can be accessed through the existing mode_lib pointer, instead of being passed as explicit arguments. Doing this reduces the stack size of dml30_ModeSupportAndSystemConfigurationFull() from 1912 bytes to 1840 bytes building for x86_64 with clang-22, helping stay under the 2048 byte limit for display_mode_vba_30.c. Additionally, now that there is a pointer to mode_lib->vba available, use 'v' consistently throughout the entire function. Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher (cherry picked from commit 563dfbefdf633c8d958398ddfa3955f9f40e47d9) --- .../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 287 +++++---------------- 1 file changed, 66 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 2d19bb8de59c..1df3412be346 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -265,62 +265,23 @@ static void CalculateDynamicMetadataParameters( static void CalculateWatermarksAndDRAMSpeedChangeSupport( struct display_mode_lib *mode_lib, unsigned int PrefetchMode, - unsigned int NumberOfActivePlanes, - unsigned int MaxLineBufferLines, - unsigned int LineBufferSize, - unsigned int DPPOutputBufferPixels, - unsigned int DETBufferSizeInKByte, - unsigned int WritebackInterfaceBufferSize, double DCFCLK, double ReturnBW, - bool GPUVMEnable, - unsigned int dpte_group_bytes[], - unsigned int MetaChunkSize, double UrgentLatency, double ExtraLatency, - double WritebackLatency, - double WritebackChunkSize, double SOCCLK, - double DRAMClockChangeLatency, - double SRExitTime, - double SREnterPlusExitTime, double DCFCLKDeepSleep, unsigned int DPPPerPlane[], - bool DCCEnable[], double DPPCLK[], unsigned int DETBufferSizeY[], unsigned int DETBufferSizeC[], unsigned int SwathHeightY[], unsigned int SwathHeightC[], - unsigned int LBBitPerPixel[], double SwathWidthY[], double SwathWidthC[], - double HRatio[], - double HRatioChroma[], - unsigned int vtaps[], - unsigned int VTAPsChroma[], - double VRatio[], - double VRatioChroma[], - unsigned int HTotal[], - double PixelClock[], - unsigned int BlendingAndTiming[], double BytePerPixelDETY[], double BytePerPixelDETC[], - double DSTXAfterScaler[], - double DSTYAfterScaler[], - bool WritebackEnable[], - enum source_format_class WritebackPixelFormat[], - double WritebackDestinationWidth[], - double WritebackDestinationHeight[], - double WritebackSourceHeight[], - enum clock_change_support *DRAMClockChangeSupport, - double *UrgentWatermark, - double *WritebackUrgentWatermark, - double *DRAMClockChangeWatermark, - double *WritebackDRAMClockChangeWatermark, - double *StutterExitWatermark, - double *StutterEnterPlusExitWatermark, - double *MinActiveDRAMClockChangeLatencySupported); + enum clock_change_support *DRAMClockChangeSupport); static void CalculateDCFCLKDeepSleep( struct display_mode_lib *mode_lib, unsigned int NumberOfActivePlanes, @@ -2646,62 +2607,23 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman CalculateWatermarksAndDRAMSpeedChangeSupport( mode_lib, PrefetchMode, - v->NumberOfActivePlanes, - v->MaxLineBufferLines, - v->LineBufferSize, - v->DPPOutputBufferPixels, - v->DETBufferSizeInKByte[0], - v->WritebackInterfaceBufferSize, v->DCFCLK, v->ReturnBW, - v->GPUVMEnable, - v->dpte_group_bytes, - v->MetaChunkSize, v->UrgentLatency, v->UrgentExtraLatency, - v->WritebackLatency, - v->WritebackChunkSize, v->SOCCLK, - v->FinalDRAMClockChangeLatency, - v->SRExitTime, - v->SREnterPlusExitTime, v->DCFCLKDeepSleep, v->DPPPerPlane, - v->DCCEnable, v->DPPCLK, v->DETBufferSizeY, v->DETBufferSizeC, v->SwathHeightY, v->SwathHeightC, - v->LBBitPerPixel, v->SwathWidthY, v->SwathWidthC, - v->HRatio, - v->HRatioChroma, - v->vtaps, - v->VTAPsChroma, - v->VRatio, - v->VRatioChroma, - v->HTotal, - v->PixelClock, - v->BlendingAndTiming, v->BytePerPixelDETY, v->BytePerPixelDETC, - v->DSTXAfterScaler, - v->DSTYAfterScaler, - v->WritebackEnable, - v->WritebackPixelFormat, - v->WritebackDestinationWidth, - v->WritebackDestinationHeight, - v->WritebackSourceHeight, - &DRAMClockChangeSupport, - &v->UrgentWatermark, - &v->WritebackUrgentWatermark, - &v->DRAMClockChangeWatermark, - &v->WritebackDRAMClockChangeWatermark, - &v->StutterExitWatermark, - &v->StutterEnterPlusExitWatermark, - &v->MinActiveDRAMClockChangeLatencySupported); + &DRAMClockChangeSupport); for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (v->WritebackEnable[k] == true) { @@ -4895,62 +4817,23 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l CalculateWatermarksAndDRAMSpeedChangeSupport( mode_lib, v->PrefetchModePerState[i][j], - v->NumberOfActivePlanes, - v->MaxLineBufferLines, - v->LineBufferSize, - v->DPPOutputBufferPixels, - v->DETBufferSizeInKByte[0], - v->WritebackInterfaceBufferSize, v->DCFCLKState[i][j], v->ReturnBWPerState[i][j], - v->GPUVMEnable, - v->dpte_group_bytes, - v->MetaChunkSize, v->UrgLatency[i], v->ExtraLatency, - v->WritebackLatency, - v->WritebackChunkSize, v->SOCCLKPerState[i], - v->FinalDRAMClockChangeLatency, - v->SRExitTime, - v->SREnterPlusExitTime, v->ProjectedDCFCLKDeepSleep[i][j], v->NoOfDPPThisState, - v->DCCEnable, v->RequiredDPPCLKThisState, v->DETBufferSizeYThisState, v->DETBufferSizeCThisState, v->SwathHeightYThisState, v->SwathHeightCThisState, - v->LBBitPerPixel, v->SwathWidthYThisState, v->SwathWidthCThisState, - v->HRatio, - v->HRatioChroma, - v->vtaps, - v->VTAPsChroma, - v->VRatio, - v->VRatioChroma, - v->HTotal, - v->PixelClock, - v->BlendingAndTiming, v->BytePerPixelInDETY, v->BytePerPixelInDETC, - v->DSTXAfterScaler, - v->DSTYAfterScaler, - v->WritebackEnable, - v->WritebackPixelFormat, - v->WritebackDestinationWidth, - v->WritebackDestinationHeight, - v->WritebackSourceHeight, - &v->DRAMClockChangeSupport[i][j], - &v->UrgentWatermark, - &v->WritebackUrgentWatermark, - &v->DRAMClockChangeWatermark, - &v->WritebackDRAMClockChangeWatermark, - &v->StutterExitWatermark, - &v->StutterEnterPlusExitWatermark, - &v->MinActiveDRAMClockChangeLatencySupported); + &v->DRAMClockChangeSupport[i][j]); } } @@ -5067,63 +4950,25 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l static void CalculateWatermarksAndDRAMSpeedChangeSupport( struct display_mode_lib *mode_lib, unsigned int PrefetchMode, - unsigned int NumberOfActivePlanes, - unsigned int MaxLineBufferLines, - unsigned int LineBufferSize, - unsigned int DPPOutputBufferPixels, - unsigned int DETBufferSizeInKByte, - unsigned int WritebackInterfaceBufferSize, double DCFCLK, double ReturnBW, - bool GPUVMEnable, - unsigned int dpte_group_bytes[], - unsigned int MetaChunkSize, double UrgentLatency, double ExtraLatency, - double WritebackLatency, - double WritebackChunkSize, double SOCCLK, - double DRAMClockChangeLatency, - double SRExitTime, - double SREnterPlusExitTime, double DCFCLKDeepSleep, unsigned int DPPPerPlane[], - bool DCCEnable[], double DPPCLK[], unsigned int DETBufferSizeY[], unsigned int DETBufferSizeC[], unsigned int SwathHeightY[], unsigned int SwathHeightC[], - unsigned int LBBitPerPixel[], double SwathWidthY[], double SwathWidthC[], - double HRatio[], - double HRatioChroma[], - unsigned int vtaps[], - unsigned int VTAPsChroma[], - double VRatio[], - double VRatioChroma[], - unsigned int HTotal[], - double PixelClock[], - unsigned int BlendingAndTiming[], double BytePerPixelDETY[], double BytePerPixelDETC[], - double DSTXAfterScaler[], - double DSTYAfterScaler[], - bool WritebackEnable[], - enum source_format_class WritebackPixelFormat[], - double WritebackDestinationWidth[], - double WritebackDestinationHeight[], - double WritebackSourceHeight[], - enum clock_change_support *DRAMClockChangeSupport, - double *UrgentWatermark, - double *WritebackUrgentWatermark, - double *DRAMClockChangeWatermark, - double *WritebackDRAMClockChangeWatermark, - double *StutterExitWatermark, - double *StutterEnterPlusExitWatermark, - double *MinActiveDRAMClockChangeLatencySupported) + enum clock_change_support *DRAMClockChangeSupport) { + struct vba_vars_st *v = &mode_lib->vba; double EffectiveLBLatencyHidingY = 0; double EffectiveLBLatencyHidingC = 0; double LinesInDETY[DC__NUM_DPP__MAX] = { 0 }; @@ -5142,101 +4987,101 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( double WritebackDRAMClockChangeLatencyHiding = 0; unsigned int k, j; - mode_lib->vba.TotalActiveDPP = 0; - mode_lib->vba.TotalDCCActiveDPP = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP + DPPPerPlane[k]; - if (DCCEnable[k] == true) { - mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP + DPPPerPlane[k]; + v->TotalActiveDPP = 0; + v->TotalDCCActiveDPP = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + v->TotalActiveDPP = v->TotalActiveDPP + DPPPerPlane[k]; + if (v->DCCEnable[k] == true) { + v->TotalDCCActiveDPP = v->TotalDCCActiveDPP + DPPPerPlane[k]; } } - *UrgentWatermark = UrgentLatency + ExtraLatency; + v->UrgentWatermark = UrgentLatency + ExtraLatency; - *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark; + v->DRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->UrgentWatermark; - mode_lib->vba.TotalActiveWriteback = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (WritebackEnable[k] == true) { - mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1; + v->TotalActiveWriteback = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->WritebackEnable[k] == true) { + v->TotalActiveWriteback = v->TotalActiveWriteback + 1; } } - if (mode_lib->vba.TotalActiveWriteback <= 1) { - *WritebackUrgentWatermark = WritebackLatency; + if (v->TotalActiveWriteback <= 1) { + v->WritebackUrgentWatermark = v->WritebackLatency; } else { - *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + v->WritebackUrgentWatermark = v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; } - if (mode_lib->vba.TotalActiveWriteback <= 1) { - *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency; + if (v->TotalActiveWriteback <= 1) { + v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency; } else { - *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; } - for (k = 0; k < NumberOfActivePlanes; ++k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { - mode_lib->vba.LBLatencyHidingSourceLinesY = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1); + v->LBLatencyHidingSourceLinesY = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1); - mode_lib->vba.LBLatencyHidingSourceLinesC = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1); + v->LBLatencyHidingSourceLinesC = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1); - EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]); + EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]); - EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]); + EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]); LinesInDETY[k] = (double) DETBufferSizeY[k] / BytePerPixelDETY[k] / SwathWidthY[k]; LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]); - FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k]; + FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k]; if (BytePerPixelDETC[k] > 0) { - LinesInDETC = mode_lib->vba.DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k]; + LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k]; LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]); - FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k]; + FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (v->HTotal[k] / v->PixelClock[k]) / v->VRatioChroma[k]; } else { LinesInDETC = 0; FullDETBufferingTimeC = 999999; } - ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark; + ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark; - if (NumberOfActivePlanes > 1) { - ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k]; + if (v->NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightY[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatio[k]; } if (BytePerPixelDETC[k] > 0) { - ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark; + ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark; - if (NumberOfActivePlanes > 1) { - ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k]; + if (v->NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightC[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatioChroma[k]; } - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC); + v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC); } else { - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY; + v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY; } - if (WritebackEnable[k] == true) { + if (v->WritebackEnable[k] == true) { - WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024 / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4); - if (WritebackPixelFormat[k] == dm_444_64) { + WritebackDRAMClockChangeLatencyHiding = v->WritebackInterfaceBufferSize * 1024 / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4); + if (v->WritebackPixelFormat[k] == dm_444_64) { WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2; } - if (mode_lib->vba.WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) { + if (v->WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) { WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding * 2; } - WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - mode_lib->vba.WritebackDRAMClockChangeWatermark; - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin); + WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark; + v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(v->ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin); } } - mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999; + v->MinActiveDRAMClockChangeMargin = 999999; PlaneWithMinActiveDRAMClockChangeMargin = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < mode_lib->vba.MinActiveDRAMClockChangeMargin) { - mode_lib->vba.MinActiveDRAMClockChangeMargin = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; - if (BlendingAndTiming[k] == k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) { + v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k]; + if (v->BlendingAndTiming[k] == k) { PlaneWithMinActiveDRAMClockChangeMargin = k; } else { - for (j = 0; j < NumberOfActivePlanes; ++j) { - if (BlendingAndTiming[k] == j) { + for (j = 0; j < v->NumberOfActivePlanes; ++j) { + if (v->BlendingAndTiming[k] == j) { PlaneWithMinActiveDRAMClockChangeMargin = j; } } @@ -5244,40 +5089,40 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport( } } - *MinActiveDRAMClockChangeLatencySupported = mode_lib->vba.MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency; + v->MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + v->FinalDRAMClockChangeLatency; SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) { - SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (v->BlendingAndTiming[k] == k)) && !(v->BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) { + SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k]; } } - mode_lib->vba.TotalNumberOfActiveOTG = 0; - for (k = 0; k < NumberOfActivePlanes; ++k) { - if (BlendingAndTiming[k] == k) { - mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG + 1; + v->TotalNumberOfActiveOTG = 0; + for (k = 0; k < v->NumberOfActivePlanes; ++k) { + if (v->BlendingAndTiming[k] == k) { + v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1; } } - if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) { + if (v->MinActiveDRAMClockChangeMargin > 0) { *DRAMClockChangeSupport = dm_dram_clock_change_vactive; - } else if (((mode_lib->vba.SynchronizedVBlank == true || mode_lib->vba.TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) { + } else if (((v->SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) { *DRAMClockChangeSupport = dm_dram_clock_change_vblank; } else { *DRAMClockChangeSupport = dm_dram_clock_change_unsupported; } FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[0]; - for (k = 0; k < NumberOfActivePlanes; ++k) { + for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (FullDETBufferingTimeY[k] <= FullDETBufferingTimeYStutterCriticalPlane) { FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[k]; - TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (HTotal[k] / PixelClock[k]) / VRatio[k]; + TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k]; } } - *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep; - *StutterEnterPlusExitWatermark = dml_max(SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane); + v->StutterExitWatermark = v->SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep; + v->StutterEnterPlusExitWatermark = dml_max(v->SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane); } -- cgit v1.2.3 From 19158c7332468bc28572bdca428e89c7954ee1b1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 30 Jun 2025 10:47:09 -0400 Subject: drm/radeon: Remove __counted_by from ClockInfoArray.clockInfo[] clockInfo[] is a generic uchar pointer to variable sized structures which vary from ASIC to ASIC. Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4374 Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit dc135aa73561b5acc74eadf776e48530996529a3) Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/pptable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/pptable.h b/drivers/gpu/drm/radeon/pptable.h index 969a8fb0ee9e..f4e71046dc91 100644 --- a/drivers/gpu/drm/radeon/pptable.h +++ b/drivers/gpu/drm/radeon/pptable.h @@ -450,7 +450,7 @@ typedef struct _ClockInfoArray{ //sizeof(ATOM_PPLIB_CLOCK_INFO) UCHAR ucEntrySize; - UCHAR clockInfo[] __counted_by(ucNumEntries); + UCHAR clockInfo[] /*__counted_by(ucNumEntries)*/; }ClockInfoArray; typedef struct _NonClockInfoArray{ -- cgit v1.2.3 From 4f74c2dd970611d3ec3bb0d58215e73af5cd7214 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Thu, 11 Dec 2025 10:47:18 +0800 Subject: drm/amd/pm: fix wrong pcie parameter on navi1x fix wrong pcie dpm parameter on navi1x Fixes: 1a18607c07bb ("drm/amd/pm: override pcie dpm parameters only if it is necessary") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4671 Signed-off-by: Yang Wang Co-developed-by: Kenneth Feng Signed-off-by: Kenneth Feng Acked-by: Alex Deucher Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit 5c5189cf4b0cc0a22bac74a40743ee711cff07f8) --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 7c9f77124ab2..16e3cc10891d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2464,8 +2464,8 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, pptable->PcieLaneCount[i] > pcie_width_cap ? pcie_width_cap : pptable->PcieLaneCount[i]; smu_pcie_arg = i << 16; - smu_pcie_arg |= pcie_gen_cap << 8; - smu_pcie_arg |= pcie_width_cap; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_OverridePcieParameters, smu_pcie_arg, -- cgit v1.2.3 From dc8a887de1a7d397ab4131f45676e89565417aa8 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 15 Dec 2025 17:51:11 +0800 Subject: drm/amd/pm: force send pcie parmater on navi1x v1: the PMFW didn't initialize the PCIe DPM parameters and requires the KMD to actively provide these parameters. v2: clean & remove unused code logic (lijo) Fixes: 1a18607c07bb ("drm/amd/pm: override pcie dpm parameters only if it is necessary") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4671 Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher (cherry picked from commit b0dbd5db7cf1f81e4aaedd25cb5e72ce369387b2) --- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 33 +++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 16e3cc10891d..c4966dcc6875 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -2455,24 +2455,21 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, } for (i = 0; i < NUM_LINK_LEVELS; i++) { - if (pptable->PcieGenSpeed[i] > pcie_gen_cap || - pptable->PcieLaneCount[i] > pcie_width_cap) { - dpm_context->dpm_tables.pcie_table.pcie_gen[i] = - pptable->PcieGenSpeed[i] > pcie_gen_cap ? - pcie_gen_cap : pptable->PcieGenSpeed[i]; - dpm_context->dpm_tables.pcie_table.pcie_lane[i] = - pptable->PcieLaneCount[i] > pcie_width_cap ? - pcie_width_cap : pptable->PcieLaneCount[i]; - smu_pcie_arg = i << 16; - smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; - smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg, - NULL); - if (ret) - break; - } + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = + pptable->PcieGenSpeed[i] > pcie_gen_cap ? + pcie_gen_cap : pptable->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = + pptable->PcieLaneCount[i] > pcie_width_cap ? + pcie_width_cap : pptable->PcieLaneCount[i]; + smu_pcie_arg = i << 16; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_gen[i] << 8; + smu_pcie_arg |= dpm_context->dpm_tables.pcie_table.pcie_lane[i]; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + if (ret) + return ret; } return ret; -- cgit v1.2.3 From 9fc27cbabee6d2e63b0268ca709ad3129b3ac50d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Nov 2025 13:24:10 -0500 Subject: drm/amdgpu: don't reemit ring contents more than once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we cancel a bad job and reemit the ring contents, and we get another timeout, cancel everything rather than reemitting. The wptr markers are only relevant for the original emit. If we reemit, the wptr markers are no longer correct. Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit fb62a2067ca4555a6572d911e05919a311c010aa) --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 22 +++++++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index c7843e336310..4f74a02a9a05 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -709,6 +709,7 @@ void amdgpu_fence_driver_guilty_force_completion(struct amdgpu_fence *af) struct amdgpu_ring *ring = af->ring; unsigned long flags; u32 seq, last_seq; + bool reemitted = false; last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask; seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask; @@ -726,7 +727,9 @@ void amdgpu_fence_driver_guilty_force_completion(struct amdgpu_fence *af) if (unprocessed && !dma_fence_is_signaled_locked(unprocessed)) { fence = container_of(unprocessed, struct amdgpu_fence, base); - if (fence == af) + if (fence->reemitted > 1) + reemitted = true; + else if (fence == af) dma_fence_set_error(&fence->base, -ETIME); else if (fence->context == af->context) dma_fence_set_error(&fence->base, -ECANCELED); @@ -734,9 +737,16 @@ void amdgpu_fence_driver_guilty_force_completion(struct amdgpu_fence *af) rcu_read_unlock(); } while (last_seq != seq); spin_unlock_irqrestore(&ring->fence_drv.lock, flags); - /* signal the guilty fence */ - amdgpu_fence_write(ring, (u32)af->base.seqno); - amdgpu_fence_process(ring); + + if (reemitted) { + /* if we've already reemitted once then just cancel everything */ + amdgpu_fence_driver_force_completion(af->ring); + af->ring->ring_backup_entries_to_copy = 0; + } else { + /* signal the guilty fence */ + amdgpu_fence_write(ring, (u32)af->base.seqno); + amdgpu_fence_process(ring); + } } void amdgpu_fence_save_wptr(struct amdgpu_fence *af) @@ -784,10 +794,12 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring, /* save everything if the ring is not guilty, otherwise * just save the content from other contexts. */ - if (!guilty_fence || (fence->context != guilty_fence->context)) + if (!fence->reemitted && + (!guilty_fence || (fence->context != guilty_fence->context))) amdgpu_ring_backup_unprocessed_command(ring, wptr, fence->wptr); wptr = fence->wptr; + fence->reemitted++; } rcu_read_unlock(); } while (last_seq != seq); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 7a27c6c4bb44..5044cf9e45fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -148,6 +148,8 @@ struct amdgpu_fence { u64 wptr; /* fence context for resets */ u64 context; + /* has this fence been reemitted */ + unsigned int reemitted; }; extern const struct drm_sched_backend_ops amdgpu_sched_ops; -- cgit v1.2.3 From 531b43260928a53f4190f3e61de788551af6157e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Nov 2025 14:12:10 -0500 Subject: drm/amdgpu: always backup and reemit fences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If when we backup the ring contents for reemit before a ring reset, we skip jobs associated with the bad context, however, we need to make sure the fences are reemited as unprocessed submissions may depend on them. v2: clean up fence handling, make helpers static Reviewed-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit 155a748f14bc0b72783994dea7c5a12276730342) --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 24 +++++++++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 5 ++++- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 4f74a02a9a05..06c333b2213b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -89,6 +89,16 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring) return seq; } +static void amdgpu_fence_save_fence_wptr_start(struct amdgpu_fence *af) +{ + af->fence_wptr_start = af->ring->wptr; +} + +static void amdgpu_fence_save_fence_wptr_end(struct amdgpu_fence *af) +{ + af->fence_wptr_end = af->ring->wptr; +} + /** * amdgpu_fence_emit - emit a fence on the requested ring * @@ -116,8 +126,10 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct amdgpu_fence *af, &ring->fence_drv.lock, adev->fence_context + ring->idx, seq); + amdgpu_fence_save_fence_wptr_start(af); amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, seq, flags | AMDGPU_FENCE_FLAG_INT); + amdgpu_fence_save_fence_wptr_end(af); amdgpu_fence_save_wptr(af); pm_runtime_get_noresume(adev_to_drm(adev)->dev); ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; @@ -742,10 +754,6 @@ void amdgpu_fence_driver_guilty_force_completion(struct amdgpu_fence *af) /* if we've already reemitted once then just cancel everything */ amdgpu_fence_driver_force_completion(af->ring); af->ring->ring_backup_entries_to_copy = 0; - } else { - /* signal the guilty fence */ - amdgpu_fence_write(ring, (u32)af->base.seqno); - amdgpu_fence_process(ring); } } @@ -795,9 +803,15 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring, * just save the content from other contexts. */ if (!fence->reemitted && - (!guilty_fence || (fence->context != guilty_fence->context))) + (!guilty_fence || (fence->context != guilty_fence->context))) { amdgpu_ring_backup_unprocessed_command(ring, wptr, fence->wptr); + } else if (!fence->reemitted) { + /* always save the fence */ + amdgpu_ring_backup_unprocessed_command(ring, + fence->fence_wptr_start, + fence->fence_wptr_end); + } wptr = fence->wptr; fence->reemitted++; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 5044cf9e45fb..055437d4edf9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -144,12 +144,15 @@ struct amdgpu_fence { struct amdgpu_ring *ring; ktime_t start_timestamp; - /* wptr for the fence for resets */ + /* wptr for the total submission for resets */ u64 wptr; /* fence context for resets */ u64 context; /* has this fence been reemitted */ unsigned int reemitted; + /* wptr for the fence for the submission */ + u64 fence_wptr_start; + u64 fence_wptr_end; }; extern const struct drm_sched_backend_ops amdgpu_sched_ops; -- cgit v1.2.3 From 7ed51e3a1381422278933d0d3ebda0268b6825de Mon Sep 17 00:00:00 2001 From: Pratap Nirujogi Date: Tue, 9 Dec 2025 20:22:15 -0500 Subject: drm/amd/amdgpu: Fix SMU warning during isp suspend-resume ISP mfd child devices are using genpd and the system suspend-resume operations between genpd and amdgpu parent device which uses only runtime suspend-resume are not in sync. Linux power manager during suspend-resume resuming the genpd devices earlier than the amdgpu parent device. This is resulting in the below warning as SMU is in suspended state when genpd attempts to resume ISP. WARNING: CPU: 13 PID: 5435 at drivers/gpu/drm/amd/amdgpu/../pm/swsmu/amdgpu_smu.c:398 smu_dpm_set_power_gate+0x36f/0x380 [amdgpu] To fix this warning isp suspend-resume is handled as part of amdgpu parent device suspend-resume instead of genpd sequence. Each ISP MFD child device is marked as dev_pm_syscore_device to skip genpd suspend-resume and use pm_runtime_force api's to suspend-resume the devices when callbacks from amdgpu are received. Co-developed-by: Gjorgji Rosikopulos Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Bin Du Signed-off-by: Pratap Nirujogi Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher (cherry picked from commit 0288a345f19b2162546352161509bb24614729e1) --- drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c | 24 +++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h | 2 ++ drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c | 41 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c index 37270c4dab8d..532f83d783d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c @@ -318,12 +318,36 @@ void isp_kernel_buffer_free(void **buf_obj, u64 *gpu_addr, void **cpu_addr) } EXPORT_SYMBOL(isp_kernel_buffer_free); +static int isp_resume(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_isp *isp = &adev->isp; + + if (isp->funcs->hw_resume) + return isp->funcs->hw_resume(isp); + + return -ENODEV; +} + +static int isp_suspend(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_isp *isp = &adev->isp; + + if (isp->funcs->hw_suspend) + return isp->funcs->hw_suspend(isp); + + return -ENODEV; +} + static const struct amd_ip_funcs isp_ip_funcs = { .name = "isp_ip", .early_init = isp_early_init, .hw_init = isp_hw_init, .hw_fini = isp_hw_fini, .is_idle = isp_is_idle, + .suspend = isp_suspend, + .resume = isp_resume, .set_clockgating_state = isp_set_clockgating_state, .set_powergating_state = isp_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h index d6f4ffa4c97c..9a5d2b1dff9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.h @@ -38,6 +38,8 @@ struct amdgpu_isp; struct isp_funcs { int (*hw_init)(struct amdgpu_isp *isp); int (*hw_fini)(struct amdgpu_isp *isp); + int (*hw_suspend)(struct amdgpu_isp *isp); + int (*hw_resume)(struct amdgpu_isp *isp); }; struct amdgpu_isp { diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c index 4258d3e0b706..0002bcc6c4ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c +++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c @@ -26,6 +26,7 @@ */ #include +#include #include "amdgpu.h" #include "isp_v4_1_1.h" @@ -145,6 +146,9 @@ static int isp_genpd_add_device(struct device *dev, void *data) return -ENODEV; } + /* The devices will be managed by the pm ops from the parent */ + dev_pm_syscore_device(dev, true); + exit: /* Continue to add */ return 0; @@ -177,12 +181,47 @@ static int isp_genpd_remove_device(struct device *dev, void *data) drm_err(&adev->ddev, "Failed to remove dev from genpd %d\n", ret); return -ENODEV; } + dev_pm_syscore_device(dev, false); exit: /* Continue to remove */ return 0; } +static int isp_suspend_device(struct device *dev, void *data) +{ + return pm_runtime_force_suspend(dev); +} + +static int isp_resume_device(struct device *dev, void *data) +{ + return pm_runtime_force_resume(dev); +} + +static int isp_v4_1_1_hw_suspend(struct amdgpu_isp *isp) +{ + int r; + + r = device_for_each_child(isp->parent, NULL, + isp_suspend_device); + if (r) + dev_err(isp->parent, "failed to suspend hw devices (%d)\n", r); + + return r; +} + +static int isp_v4_1_1_hw_resume(struct amdgpu_isp *isp) +{ + int r; + + r = device_for_each_child(isp->parent, NULL, + isp_resume_device); + if (r) + dev_err(isp->parent, "failed to resume hw device (%d)\n", r); + + return r; +} + static int isp_v4_1_1_hw_init(struct amdgpu_isp *isp) { const struct software_node *amd_camera_node, *isp4_node; @@ -369,6 +408,8 @@ static int isp_v4_1_1_hw_fini(struct amdgpu_isp *isp) static const struct isp_funcs isp_v4_1_1_funcs = { .hw_init = isp_v4_1_1_hw_init, .hw_fini = isp_v4_1_1_hw_fini, + .hw_suspend = isp_v4_1_1_hw_suspend, + .hw_resume = isp_v4_1_1_hw_resume, }; void isp_v4_1_1_set_isp_funcs(struct amdgpu_isp *isp) -- cgit v1.2.3 From fd40c146c8ed7f7e8ae36922dcc583bd0ca70b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Sat, 6 Dec 2025 03:31:03 +0100 Subject: drm/amd/display: Correct color depth for SelectCRTC_Source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the correct enum values as expected by the VBIOS. Previously the actual bit depth integer value was passed, which was a mistake. Fixes: 7fb4f254c8eb ("drm/amd/display: Add SelectCRTC_Source to BIOS parser") Reviewed-by: Alex Deucher Signed-off-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit cdf6e4c0cdab129ffc4e41a8ac53a0738f805072) --- .../gpu/drm/amd/display/dc/bios/command_table.c | 25 ++++++++++++++++++- .../drm/amd/display/dc/hwss/dce110/dce110_hwseq.c | 28 +--------------------- .../drm/amd/display/include/bios_parser_types.h | 2 +- 3 files changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index 22457f417e65..d56c0d3763dd 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -1797,7 +1797,30 @@ static enum bp_result select_crtc_source_v3( ¶ms.ucEncodeMode)) return BP_RESULT_BADINPUT; - params.ucDstBpc = bp_params->bit_depth; + switch (bp_params->color_depth) { + case COLOR_DEPTH_UNDEFINED: + params.ucDstBpc = PANEL_BPC_UNDEFINE; + break; + case COLOR_DEPTH_666: + params.ucDstBpc = PANEL_6BIT_PER_COLOR; + break; + default: + case COLOR_DEPTH_888: + params.ucDstBpc = PANEL_8BIT_PER_COLOR; + break; + case COLOR_DEPTH_101010: + params.ucDstBpc = PANEL_10BIT_PER_COLOR; + break; + case COLOR_DEPTH_121212: + params.ucDstBpc = PANEL_12BIT_PER_COLOR; + break; + case COLOR_DEPTH_141414: + dm_error("14-bit color not supported by SelectCRTC_Source v3\n"); + break; + case COLOR_DEPTH_161616: + params.ucDstBpc = PANEL_16BIT_PER_COLOR; + break; + } if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params)) result = BP_RESULT_OK; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 0cdd8c74abdf..ebd74b43e935 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1610,38 +1610,12 @@ dce110_select_crtc_source(struct pipe_ctx *pipe_ctx) struct dc_bios *bios = link->ctx->dc_bios; struct bp_crtc_source_select crtc_source_select = {0}; enum engine_id engine_id = link->link_enc->preferred_engine; - uint8_t bit_depth; if (dc_is_rgb_signal(pipe_ctx->stream->signal)) engine_id = link->link_enc->analog_engine; - switch (pipe_ctx->stream->timing.display_color_depth) { - case COLOR_DEPTH_UNDEFINED: - bit_depth = 0; - break; - case COLOR_DEPTH_666: - bit_depth = 6; - break; - default: - case COLOR_DEPTH_888: - bit_depth = 8; - break; - case COLOR_DEPTH_101010: - bit_depth = 10; - break; - case COLOR_DEPTH_121212: - bit_depth = 12; - break; - case COLOR_DEPTH_141414: - bit_depth = 14; - break; - case COLOR_DEPTH_161616: - bit_depth = 16; - break; - } - crtc_source_select.controller_id = CONTROLLER_ID_D0 + pipe_ctx->stream_res.tg->inst; - crtc_source_select.bit_depth = bit_depth; + crtc_source_select.color_depth = pipe_ctx->stream->timing.display_color_depth; crtc_source_select.engine_id = engine_id; crtc_source_select.sink_signal = pipe_ctx->stream->signal; diff --git a/drivers/gpu/drm/amd/display/include/bios_parser_types.h b/drivers/gpu/drm/amd/display/include/bios_parser_types.h index 973b6bdbac63..f40dc612ec73 100644 --- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h +++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h @@ -136,7 +136,7 @@ struct bp_crtc_source_select { enum engine_id engine_id; enum controller_id controller_id; enum signal_type sink_signal; - uint8_t bit_depth; + enum dc_color_depth color_depth; }; struct bp_transmitter_control { -- cgit v1.2.3 From e0d20a7658129fc681e392ba27edea99b77c2e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timur=20Krist=C3=B3f?= Date: Sat, 6 Dec 2025 03:31:04 +0100 Subject: drm/amd/display: Add missing encoder setup to DACnEncoderControl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently the DAC encoder needs to be set up before use. The BIOS parser in DC did not support this so I assumed it was not necessary, but the DAC doesn't work without it on some GPUs. Fixes: 69b29b894660 ("drm/amd/display: Hook up DAC to bios_parser_encoder_control") Reviewed-by: Alex Deucher Signed-off-by: Timur Kristóf Signed-off-by: Alex Deucher (cherry picked from commit bb5dfe2f5630ce344c654c705d28b4e20cb9d334) --- drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 4 ++-- drivers/gpu/drm/amd/display/dc/bios/command_table.c | 19 +++++++++++-------- drivers/gpu/drm/amd/display/dc/bios/command_table.h | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index d1471f34e419..9f11e6ca4051 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -763,14 +763,14 @@ static enum bp_result bios_parser_encoder_control( return BP_RESULT_FAILURE; return bp->cmd_tbl.dac1_encoder_control( - bp, cntl->action == ENCODER_CONTROL_ENABLE, + bp, cntl->action, cntl->pixel_clock, ATOM_DAC1_PS2); } else if (cntl->engine_id == ENGINE_ID_DACB) { if (!bp->cmd_tbl.dac2_encoder_control) return BP_RESULT_FAILURE; return bp->cmd_tbl.dac2_encoder_control( - bp, cntl->action == ENCODER_CONTROL_ENABLE, + bp, cntl->action, cntl->pixel_clock, ATOM_DAC1_PS2); } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index d56c0d3763dd..76a3559f0ddc 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -1838,12 +1838,12 @@ static enum bp_result select_crtc_source_v3( static enum bp_result dac1_encoder_control_v1( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard); static enum bp_result dac2_encoder_control_v1( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard); @@ -1869,12 +1869,15 @@ static void init_dac_encoder_control(struct bios_parser *bp) static void dac_encoder_control_prepare_params( DAC_ENCODER_CONTROL_PS_ALLOCATION *params, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard) { params->ucDacStandard = dac_standard; - if (enable) + if (action == ENCODER_CONTROL_SETUP || + action == ENCODER_CONTROL_INIT) + params->ucAction = ATOM_ENCODER_INIT; + else if (action == ENCODER_CONTROL_ENABLE) params->ucAction = ATOM_ENABLE; else params->ucAction = ATOM_DISABLE; @@ -1887,7 +1890,7 @@ static void dac_encoder_control_prepare_params( static enum bp_result dac1_encoder_control_v1( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard) { @@ -1896,7 +1899,7 @@ static enum bp_result dac1_encoder_control_v1( dac_encoder_control_prepare_params( ¶ms, - enable, + action, pixel_clock, dac_standard); @@ -1908,7 +1911,7 @@ static enum bp_result dac1_encoder_control_v1( static enum bp_result dac2_encoder_control_v1( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard) { @@ -1917,7 +1920,7 @@ static enum bp_result dac2_encoder_control_v1( dac_encoder_control_prepare_params( ¶ms, - enable, + action, pixel_clock, dac_standard); diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.h b/drivers/gpu/drm/amd/display/dc/bios/command_table.h index e89b1ba0048b..78bdbcaa61c8 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.h @@ -57,12 +57,12 @@ struct cmd_tbl { struct bp_crtc_source_select *bp_params); enum bp_result (*dac1_encoder_control)( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard); enum bp_result (*dac2_encoder_control)( struct bios_parser *bp, - bool enable, + enum bp_encoder_control_action action, uint32_t pixel_clock, uint8_t dac_standard); enum bp_result (*dac1_output_control)( -- cgit v1.2.3 From 72d7f4573660287f1b66c30319efecd6fcde92ee Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Mon, 22 Dec 2025 12:26:35 +0800 Subject: drm/amdgpu: Fix query for VPE block_type and ip_count [Why] Query for VPE block_type and ip_count is missing. [How] Add VPE case in ip_block_type and hw_ip_count query. Reviewed-by: Lang Yu Signed-off-by: Alan Liu Signed-off-by: Alex Deucher (cherry picked from commit a6ea0a430aca5932b9c75d8e38deeb45665dd2ae) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 6ee77f431d56..f65edd80cabf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -201,6 +201,9 @@ static enum amd_ip_block_type type = (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_JPEG)) ? AMD_IP_BLOCK_TYPE_JPEG : AMD_IP_BLOCK_TYPE_VCN; break; + case AMDGPU_HW_IP_VPE: + type = AMD_IP_BLOCK_TYPE_VPE; + break; default: type = AMD_IP_BLOCK_TYPE_NUM; break; @@ -721,6 +724,9 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case AMD_IP_BLOCK_TYPE_UVD: count = adev->uvd.num_uvd_inst; break; + case AMD_IP_BLOCK_TYPE_VPE: + count = adev->vpe.num_instances; + break; /* For all other IP block types not listed in the switch statement * the ip status is valid here and the instance count is one. */ -- cgit v1.2.3 From fd390ff144513eb0310c350b1cf5fa8d6ddd0c53 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Mon, 5 Jan 2026 22:46:38 -0600 Subject: PCI/VGA: Don't assume the only VGA device on a system is `boot_vga` Some systems ship with multiple display class devices but not all of them are VGA devices. If the "only" VGA device on the system is not used for displaying the image on the screen marking it as `boot_vga` because nothing was found is totally wrong. This behavior actually leads to mistakes of the wrong device being advertised to userspace and then userspace can make incorrect decisions. As there is an accurate `boot_display` sysfs file stop lying about `boot_vga` by assuming if nothing is found it's the right device. Reported-by: Aaron Erhardt Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220712 Tested-by: Aaron Erhardt Acked-by: Thomas Zimmermann Fixes: ad90860bd10ee ("fbcon: Use screen info to find primary device") Tested-by: Luke D. Jones Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260106044638.52906-1-superm1@kernel.org --- drivers/pci/vgaarb.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 436fa7f4c387..baa242b14099 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -652,13 +652,6 @@ static bool vga_is_boot_device(struct vga_device *vgadev) return true; } - /* - * Vgadev has neither IO nor MEM enabled. If we haven't found any - * other VGA devices, it is the best candidate so far. - */ - if (!boot_vga) - return true; - return false; } -- cgit v1.2.3 From d5bdf88d1f9d1e4808177f03d89de3d0ba6c6e84 Mon Sep 17 00:00:00 2001 From: Chengjun Yao Date: Mon, 15 Dec 2025 16:18:21 +0800 Subject: drm/fb-helper: Fix vblank timeout during suspend/reset During GPU reset, VBlank interrupts are disabled which causes drm_fb_helper_fb_dirty() to wait for VBlank timeout. This will create call traces like (seen on an RX7900 series dGPU): [ 101.313646] ------------[ cut here ]------------ [ 101.313648] amdgpu 0000:03:00.0: [drm] vblank wait timed out on crtc 0 [ 101.313657] WARNING: CPU: 0 PID: 461 at drivers/gpu/drm/drm_vblank.c:1320 drm_wait_one_vblank+0x176/0x220 [ 101.313663] Modules linked in: amdgpu amdxcp drm_panel_backlight_quirks gpu_sched drm_buddy drm_ttm_helper ttm drm_exec drm_suballoc_helper drm_display_helper cec rc_core i2c_algo_bit nf_conntrack_netlink xt_nat xt_tcpudp veth xt_conntrack xt_MASQUERADE bridge stp llc xfrm_user xfrm_algo xt_set ip_set nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 xt_addrtype nft_compat x_tables nf_tables overlay qrtr sunrpc snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic snd_hda_codec_atihdmi snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hda_core snd_intel_dspcfg snd_intel_sdw_acpi snd_hwdep snd_pcm amd_atl intel_rapl_msr snd_seq_midi intel_rapl_common asus_ec_sensors snd_seq_midi_event snd_rawmidi snd_seq eeepc_wmi snd_seq_device edac_mce_amd asus_wmi polyval_clmulni ghash_clmulni_intel snd_timer platform_profile aesni_intel wmi_bmof sparse_keymap joydev snd rapl input_leds i2c_piix4 soundcore ccp k10temp i2c_smbus gpio_amdpt mac_hid binfmt_misc sch_fq_codel msr parport_pc ppdev lp parport [ 101.313745] efi_pstore nfnetlink dmi_sysfs autofs4 hid_generic usbhid hid r8169 realtek ahci libahci video wmi [ 101.313760] CPU: 0 UID: 0 PID: 461 Comm: kworker/0:2 Not tainted 6.18.0-rc6-174403b3b920 #1 PREEMPT(voluntary) [ 101.313763] Hardware name: ASUS System Product Name/TUF GAMING X670E-PLUS, BIOS 0821 11/15/2022 [ 101.313765] Workqueue: events drm_fb_helper_damage_work [ 101.313769] RIP: 0010:drm_wait_one_vblank+0x176/0x220 [ 101.313772] Code: 7c 24 08 4c 8b 77 50 4d 85 f6 0f 84 a1 00 00 00 e8 2f 11 03 00 44 89 e9 4c 89 f2 48 c7 c7 d0 ad 0d a8 48 89 c6 e8 2a e0 4a ff <0f> 0b e9 f2 fe ff ff 48 85 ff 74 04 4c 8b 67 08 4d 8b 6c 24 50 4d [ 101.313774] RSP: 0018:ffffc99c00d47d68 EFLAGS: 00010246 [ 101.313777] RAX: 0000000000000000 RBX: 000000000200038a RCX: 0000000000000000 [ 101.313778] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 101.313779] RBP: ffffc99c00d47dc0 R08: 0000000000000000 R09: 0000000000000000 [ 101.313781] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8948c4280010 [ 101.313782] R13: 0000000000000000 R14: ffff894883263a50 R15: ffff89488c384830 [ 101.313784] FS: 0000000000000000(0000) GS:ffff895424692000(0000) knlGS:0000000000000000 [ 101.313785] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 101.313787] CR2: 00007773650ee200 CR3: 0000000588e40000 CR4: 0000000000f50ef0 [ 101.313788] PKRU: 55555554 [ 101.313790] Call Trace: [ 101.313791] [ 101.313795] ? __pfx_autoremove_wake_function+0x10/0x10 [ 101.313800] drm_crtc_wait_one_vblank+0x17/0x30 [ 101.313802] drm_client_modeset_wait_for_vblank+0x61/0x80 [ 101.313805] drm_fb_helper_damage_work+0x46/0x1a0 [ 101.313808] process_one_work+0x1a1/0x3f0 [ 101.313812] worker_thread+0x2ba/0x3d0 [ 101.313816] kthread+0x107/0x220 [ 101.313818] ? __pfx_worker_thread+0x10/0x10 [ 101.313821] ? __pfx_kthread+0x10/0x10 [ 101.313823] ret_from_fork+0x202/0x230 [ 101.313826] ? __pfx_kthread+0x10/0x10 [ 101.313828] ret_from_fork_asm+0x1a/0x30 [ 101.313834] [ 101.313835] ---[ end trace 0000000000000000 ]--- Cancel pending damage work synchronously before console_lock() to ensure any in-flight framebuffer damage operations complete before suspension. Also check for FBINFO_STATE_RUNNING in drm_fb_helper_damage_work() to avoid executing damage work if it is rescheduled while the device is suspended. Fixes: d8c4bddcd8bc ("drm/fb-helper: Synchronize dirty worker with vblank") Signed-off-by: Aurabindo Pillai Signed-off-by: Chengjun Yao Signed-off-by: Thomas Zimmermann Reviewed-by: Thomas Zimmermann Link: https://patch.msgid.link/20251215081822.432005-1-Chengjun.Yao@amd.com --- drivers/gpu/drm/drm_fb_helper.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 4a7f72044ab8..4b47aa0dab35 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -366,6 +366,9 @@ static void drm_fb_helper_damage_work(struct work_struct *work) { struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, damage_work); + if (helper->info->state != FBINFO_STATE_RUNNING) + return; + drm_fb_helper_fb_dirty(helper); } @@ -732,6 +735,13 @@ void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper, if (fb_helper->info->state != FBINFO_STATE_RUNNING) return; + /* + * Cancel pending damage work. During GPU reset, VBlank + * interrupts are disabled and drm_fb_helper_fb_dirty() + * would wait for VBlank timeout otherwise. + */ + cancel_work_sync(&fb_helper->damage_work); + console_lock(); } else { -- cgit v1.2.3 From 08e136ebd193eae7d5eff4c66d576c4a2dabdc3f Mon Sep 17 00:00:00 2001 From: Raphael Pinsonneault-Thibeault Date: Wed, 17 Dec 2025 14:00:40 -0500 Subject: loop: don't change loop device under exclusive opener in loop_set_status loop_set_status() is allowed to change the loop device while there are other openers of the device, even exclusive ones. In this case, it causes a KASAN: slab-out-of-bounds Read in ext4_search_dir(), since when looking for an entry in an inlined directory, e_value_offs is changed underneath the filesystem by loop_set_status(). Fix the problem by forbidding loop_set_status() from modifying the loop device while there are exclusive openers of the device. This is similar to the fix in loop_configure() by commit 33ec3e53e7b1 ("loop: Don't change loop device under exclusive opener") alongside commit ecbe6bc0003b ("block: use bd_prepare_to_claim directly in the loop driver"). Reported-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3ee481e21fd75e14c397 Tested-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com Tested-by: Yongpeng Yang Signed-off-by: Raphael Pinsonneault-Thibeault Reviewed-by: Jan Kara Signed-off-by: Jens Axboe --- drivers/block/loop.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 32a3a5b13802..ca74cc31bf07 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1225,13 +1225,24 @@ static int loop_clr_fd(struct loop_device *lo) } static int -loop_set_status(struct loop_device *lo, const struct loop_info64 *info) +loop_set_status(struct loop_device *lo, blk_mode_t mode, + struct block_device *bdev, const struct loop_info64 *info) { int err; bool partscan = false; bool size_changed = false; unsigned int memflags; + /* + * If we don't hold exclusive handle for the device, upgrade to it + * here to avoid changing device under exclusive owner. + */ + if (!(mode & BLK_OPEN_EXCL)) { + err = bd_prepare_to_claim(bdev, loop_set_status, NULL); + if (err) + goto out_reread_partitions; + } + err = mutex_lock_killable(&lo->lo_mutex); if (err) return err; @@ -1273,6 +1284,9 @@ out_unfreeze: } out_unlock: mutex_unlock(&lo->lo_mutex); + if (!(mode & BLK_OPEN_EXCL)) + bd_abort_claiming(bdev, loop_set_status); +out_reread_partitions: if (partscan) loop_reread_partitions(lo); @@ -1352,7 +1366,9 @@ loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) } static int -loop_set_status_old(struct loop_device *lo, const struct loop_info __user *arg) +loop_set_status_old(struct loop_device *lo, blk_mode_t mode, + struct block_device *bdev, + const struct loop_info __user *arg) { struct loop_info info; struct loop_info64 info64; @@ -1360,17 +1376,19 @@ loop_set_status_old(struct loop_device *lo, const struct loop_info __user *arg) if (copy_from_user(&info, arg, sizeof (struct loop_info))) return -EFAULT; loop_info64_from_old(&info, &info64); - return loop_set_status(lo, &info64); + return loop_set_status(lo, mode, bdev, &info64); } static int -loop_set_status64(struct loop_device *lo, const struct loop_info64 __user *arg) +loop_set_status64(struct loop_device *lo, blk_mode_t mode, + struct block_device *bdev, + const struct loop_info64 __user *arg) { struct loop_info64 info64; if (copy_from_user(&info64, arg, sizeof (struct loop_info64))) return -EFAULT; - return loop_set_status(lo, &info64); + return loop_set_status(lo, mode, bdev, &info64); } static int @@ -1549,14 +1567,14 @@ static int lo_ioctl(struct block_device *bdev, blk_mode_t mode, case LOOP_SET_STATUS: err = -EPERM; if ((mode & BLK_OPEN_WRITE) || capable(CAP_SYS_ADMIN)) - err = loop_set_status_old(lo, argp); + err = loop_set_status_old(lo, mode, bdev, argp); break; case LOOP_GET_STATUS: return loop_get_status_old(lo, argp); case LOOP_SET_STATUS64: err = -EPERM; if ((mode & BLK_OPEN_WRITE) || capable(CAP_SYS_ADMIN)) - err = loop_set_status64(lo, argp); + err = loop_set_status64(lo, mode, bdev, argp); break; case LOOP_GET_STATUS64: return loop_get_status64(lo, argp); @@ -1650,8 +1668,9 @@ loop_info64_to_compat(const struct loop_info64 *info64, } static int -loop_set_status_compat(struct loop_device *lo, - const struct compat_loop_info __user *arg) +loop_set_status_compat(struct loop_device *lo, blk_mode_t mode, + struct block_device *bdev, + const struct compat_loop_info __user *arg) { struct loop_info64 info64; int ret; @@ -1659,7 +1678,7 @@ loop_set_status_compat(struct loop_device *lo, ret = loop_info64_from_compat(arg, &info64); if (ret < 0) return ret; - return loop_set_status(lo, &info64); + return loop_set_status(lo, mode, bdev, &info64); } static int @@ -1685,7 +1704,7 @@ static int lo_compat_ioctl(struct block_device *bdev, blk_mode_t mode, switch(cmd) { case LOOP_SET_STATUS: - err = loop_set_status_compat(lo, + err = loop_set_status_compat(lo, mode, bdev, (const struct compat_loop_info __user *)arg); break; case LOOP_GET_STATUS: -- cgit v1.2.3 From 083029bd8b445595222a3cd14076b880781c1765 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:14 -0800 Subject: idpf: keep the netdev when a reset fails During a successful reset the driver would re-allocate vport resources while keeping the netdevs intact. However, in case of an error in the init task, the netdev of the failing vport will be unregistered, effectively removing the network interface: [ 121.211076] idpf 0000:83:00.0: enabling device (0100 -> 0102) [ 121.221976] idpf 0000:83:00.0: Device HW Reset initiated [ 124.161229] idpf 0000:83:00.0 ens801f0: renamed from eth0 [ 124.163364] idpf 0000:83:00.0 ens801f0d1: renamed from eth1 [ 125.934656] idpf 0000:83:00.0 ens801f0d2: renamed from eth2 [ 128.218429] idpf 0000:83:00.0 ens801f0d3: renamed from eth3 ip -br a ens801f0 UP ens801f0d1 UP ens801f0d2 UP ens801f0d3 UP echo 1 > /sys/class/net/ens801f0/device/reset [ 145.885537] idpf 0000:83:00.0: resetting [ 145.990280] idpf 0000:83:00.0: reset done [ 146.284766] idpf 0000:83:00.0: HW reset detected [ 146.296610] idpf 0000:83:00.0: Device HW Reset initiated [ 211.556719] idpf 0000:83:00.0: Transaction timed-out (op:526 cookie:7700 vc_op:526 salt:77 timeout:60000ms) [ 272.996705] idpf 0000:83:00.0: Transaction timed-out (op:502 cookie:7800 vc_op:502 salt:78 timeout:60000ms) ip -br a ens801f0d1 DOWN ens801f0d2 DOWN ens801f0d3 DOWN Re-shuffle the logic in the error path of the init task to make sure the netdevs remain intact. This will allow the driver to attempt recovery via subsequent resets, provided the FW is still functional. The main change is to make sure that idpf_decfg_netdev() is not called should the init task fail during a reset. The error handling is consolidated under unwind_vports, as the removed labels had the same cleanup logic split depending on the point of failure. Fixes: ce1b75d0635c ("idpf: add ptypes and MAC filter support") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 7ce4eb71a433..313803c08847 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1579,6 +1579,10 @@ void idpf_init_task(struct work_struct *work) goto unwind_vports; } + err = idpf_send_get_rx_ptype_msg(vport); + if (err) + goto unwind_vports; + index = vport->idx; vport_config = adapter->vport_config[index]; @@ -1590,15 +1594,11 @@ void idpf_init_task(struct work_struct *work) err = idpf_check_supported_desc_ids(vport); if (err) { dev_err(&pdev->dev, "failed to get required descriptor ids\n"); - goto cfg_netdev_err; + goto unwind_vports; } if (idpf_cfg_netdev(vport)) - goto cfg_netdev_err; - - err = idpf_send_get_rx_ptype_msg(vport); - if (err) - goto handle_err; + goto unwind_vports; /* Once state is put into DOWN, driver is ready for dev_open */ np = netdev_priv(vport->netdev); @@ -1645,11 +1645,6 @@ void idpf_init_task(struct work_struct *work) return; -handle_err: - idpf_decfg_netdev(vport); -cfg_netdev_err: - idpf_vport_rel(vport); - adapter->vports[index] = NULL; unwind_vports: if (default_vport) { for (index = 0; index < adapter->max_vports; index++) { -- cgit v1.2.3 From 2e281e1155fc476c571c0bd2ffbfe28ab829a5c3 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:15 -0800 Subject: idpf: detach and close netdevs while handling a reset Protect the reset path from callbacks by setting the netdevs to detached state and close any netdevs in UP state until the reset handling has completed. During a reset, the driver will de-allocate resources for the vport, and there is no guarantee that those will recover, which is why the existing vport_ctrl_lock does not provide sufficient protection. idpf_detach_and_close() is called right before reset handling. If the reset handling succeeds, the netdevs state is recovered via call to idpf_attach_and_open(). If the reset handling fails the netdevs remain down. The detach/down calls are protected with RTNL lock to avoid racing with callbacks. On the recovery side the attach can be done without holding the RTNL lock as there are no callbacks expected at that point, due to detach/close always being done first in that flow. The previous logic restoring the netdevs state based on the IDPF_VPORT_UP_REQUESTED flag in the init task is not needed anymore, hence the removal of idpf_set_vport_state(). The IDPF_VPORT_UP_REQUESTED is still being used to restore the state of the netdevs following the reset, but has no use outside of the reset handling flow. idpf_init_hard_reset() is converted to void, since it was used as such and there is no error handling being done based on its return value. Before this change, invoking hard and soft resets simultaneously will cause the driver to lose the vport state: ip -br a UP echo 1 > /sys/class/net/ens801f0/device/reset& \ ethtool -L ens801f0 combined 8 ip -br a DOWN ip link set up ip -br a DOWN Also in case of a failure in the reset path, the netdev is left exposed to external callbacks, while vport resources are not initialized, leading to a crash on subsequent ifup/down: [408471.398966] idpf 0000:83:00.0: HW reset detected [408471.411744] idpf 0000:83:00.0: Device HW Reset initiated [408472.277901] idpf 0000:83:00.0: The driver was unable to contact the device's firmware. Check that the FW is running. Driver state= 0x2 [408508.125551] BUG: kernel NULL pointer dereference, address: 0000000000000078 [408508.126112] #PF: supervisor read access in kernel mode [408508.126687] #PF: error_code(0x0000) - not-present page [408508.127256] PGD 2aae2f067 P4D 0 [408508.127824] Oops: Oops: 0000 [#1] SMP NOPTI ... [408508.130871] RIP: 0010:idpf_stop+0x39/0x70 [idpf] ... [408508.139193] Call Trace: [408508.139637] [408508.140077] __dev_close_many+0xbb/0x260 [408508.140533] __dev_change_flags+0x1cf/0x280 [408508.140987] netif_change_flags+0x26/0x70 [408508.141434] dev_change_flags+0x3d/0xb0 [408508.141878] devinet_ioctl+0x460/0x890 [408508.142321] inet_ioctl+0x18e/0x1d0 [408508.142762] ? _copy_to_user+0x22/0x70 [408508.143207] sock_do_ioctl+0x3d/0xe0 [408508.143652] sock_ioctl+0x10e/0x330 [408508.144091] ? find_held_lock+0x2b/0x80 [408508.144537] __x64_sys_ioctl+0x96/0xe0 [408508.144979] do_syscall_64+0x79/0x3d0 [408508.145415] entry_SYSCALL_64_after_hwframe+0x76/0x7e [408508.145860] RIP: 0033:0x7f3e0bb4caff Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Signed-off-by: Emil Tantilov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 121 +++++++++++++++++------------ 1 file changed, 72 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 313803c08847..a964e0f5891e 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -729,6 +729,65 @@ static int idpf_init_mac_addr(struct idpf_vport *vport, return 0; } +static void idpf_detach_and_close(struct idpf_adapter *adapter) +{ + int max_vports = adapter->max_vports; + + for (int i = 0; i < max_vports; i++) { + struct net_device *netdev = adapter->netdevs[i]; + + /* If the interface is in detached state, that means the + * previous reset was not handled successfully for this + * vport. + */ + if (!netif_device_present(netdev)) + continue; + + /* Hold RTNL to protect racing with callbacks */ + rtnl_lock(); + netif_device_detach(netdev); + if (netif_running(netdev)) { + set_bit(IDPF_VPORT_UP_REQUESTED, + adapter->vport_config[i]->flags); + dev_close(netdev); + } + rtnl_unlock(); + } +} + +static void idpf_attach_and_open(struct idpf_adapter *adapter) +{ + int max_vports = adapter->max_vports; + + for (int i = 0; i < max_vports; i++) { + struct idpf_vport *vport = adapter->vports[i]; + struct idpf_vport_config *vport_config; + struct net_device *netdev; + + /* In case of a critical error in the init task, the vport + * will be freed. Only continue to restore the netdevs + * if the vport is allocated. + */ + if (!vport) + continue; + + /* No need for RTNL on attach as this function is called + * following detach and dev_close(). We do take RTNL for + * dev_open() below as it can race with external callbacks + * following the call to netif_device_attach(). + */ + netdev = adapter->netdevs[i]; + netif_device_attach(netdev); + vport_config = adapter->vport_config[vport->idx]; + if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, + vport_config->flags)) { + rtnl_lock(); + dev_open(netdev, NULL); + rtnl_unlock(); + } + } +} + /** * idpf_cfg_netdev - Allocate, configure and register a netdev * @vport: main vport structure @@ -1041,10 +1100,11 @@ static void idpf_vport_dealloc(struct idpf_vport *vport) idpf_idc_deinit_vport_aux_device(vport->vdev_info); idpf_deinit_mac_addr(vport); - idpf_vport_stop(vport, true); - if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) + if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) { + idpf_vport_stop(vport, true); idpf_decfg_netdev(vport); + } if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) idpf_del_all_mac_filters(vport); @@ -1544,7 +1604,6 @@ void idpf_init_task(struct work_struct *work) struct idpf_vport_config *vport_config; struct idpf_vport_max_q max_q; struct idpf_adapter *adapter; - struct idpf_netdev_priv *np; struct idpf_vport *vport; u16 num_default_vports; struct pci_dev *pdev; @@ -1600,12 +1659,6 @@ void idpf_init_task(struct work_struct *work) if (idpf_cfg_netdev(vport)) goto unwind_vports; - /* Once state is put into DOWN, driver is ready for dev_open */ - np = netdev_priv(vport->netdev); - clear_bit(IDPF_VPORT_UP, np->state); - if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags)) - idpf_vport_open(vport, true); - /* Spawn and return 'idpf_init_task' work queue until all the * default vports are created */ @@ -1781,27 +1834,6 @@ static int idpf_check_reset_complete(struct idpf_hw *hw, return -EBUSY; } -/** - * idpf_set_vport_state - Set the vport state to be after the reset - * @adapter: Driver specific private structure - */ -static void idpf_set_vport_state(struct idpf_adapter *adapter) -{ - u16 i; - - for (i = 0; i < adapter->max_vports; i++) { - struct idpf_netdev_priv *np; - - if (!adapter->netdevs[i]) - continue; - - np = netdev_priv(adapter->netdevs[i]); - if (test_bit(IDPF_VPORT_UP, np->state)) - set_bit(IDPF_VPORT_UP_REQUESTED, - adapter->vport_config[i]->flags); - } -} - /** * idpf_init_hard_reset - Initiate a hardware reset * @adapter: Driver specific private structure @@ -1810,28 +1842,17 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter) * reallocate. Also reinitialize the mailbox. Return 0 on success, * negative on failure. */ -static int idpf_init_hard_reset(struct idpf_adapter *adapter) +static void idpf_init_hard_reset(struct idpf_adapter *adapter) { struct idpf_reg_ops *reg_ops = &adapter->dev_ops.reg_ops; struct device *dev = &adapter->pdev->dev; - struct net_device *netdev; int err; - u16 i; + idpf_detach_and_close(adapter); mutex_lock(&adapter->vport_ctrl_lock); dev_info(dev, "Device HW Reset initiated\n"); - /* Avoid TX hangs on reset */ - for (i = 0; i < adapter->max_vports; i++) { - netdev = adapter->netdevs[i]; - if (!netdev) - continue; - - netif_carrier_off(netdev); - netif_tx_disable(netdev); - } - /* Prepare for reset */ if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD); @@ -1840,7 +1861,6 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter) idpf_idc_issue_reset_event(adapter->cdev_info); - idpf_set_vport_state(adapter); idpf_vc_core_deinit(adapter); if (!is_reset) reg_ops->trigger_reset(adapter, IDPF_HR_FUNC_RESET); @@ -1887,11 +1907,14 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter) unlock_mutex: mutex_unlock(&adapter->vport_ctrl_lock); - /* Wait until all vports are created to init RDMA CORE AUX */ - if (!err) - err = idpf_idc_init(adapter); - - return err; + /* Attempt to restore netdevs and initialize RDMA CORE AUX device, + * provided vc_core_init succeeded. It is still possible that + * vports are not allocated at this point if the init task failed. + */ + if (!err) { + idpf_attach_and_open(adapter); + idpf_idc_init(adapter); + } } /** -- cgit v1.2.3 From f6242b354605faff263ca45882b148200915a3f6 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:16 -0800 Subject: idpf: fix memory leak in idpf_vport_rel() Free vport->rx_ptype_lkup in idpf_vport_rel() to avoid leaking memory during a reset. Reported by kmemleak: unreferenced object 0xff450acac838a000 (size 4096): comm "kworker/u258:5", pid 7732, jiffies 4296830044 hex dump (first 32 bytes): 00 00 00 00 00 10 00 00 00 10 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ backtrace (crc 3da81902): __kmalloc_cache_noprof+0x469/0x7a0 idpf_send_get_rx_ptype_msg+0x90/0x570 [idpf] idpf_init_task+0x1ec/0x8d0 [idpf] process_one_work+0x226/0x6d0 worker_thread+0x19e/0x340 kthread+0x10f/0x250 ret_from_fork+0x251/0x2b0 ret_from_fork_asm+0x1a/0x30 Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index a964e0f5891e..04af10cfaa8c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1082,6 +1082,8 @@ static void idpf_vport_rel(struct idpf_vport *vport) kfree(adapter->vport_config[idx]->req_qs_chunks); adapter->vport_config[idx]->req_qs_chunks = NULL; } + kfree(vport->rx_ptype_lkup); + vport->rx_ptype_lkup = NULL; kfree(vport); adapter->num_alloc_vports--; } -- cgit v1.2.3 From e111cbc4adf9f9974eed040aeece7e17460f6bff Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:17 -0800 Subject: idpf: fix memory leak in idpf_vc_core_deinit() Make sure to free hw->lan_regs. Reported by kmemleak during reset: unreferenced object 0xff1b913d02a936c0 (size 96): comm "kworker/u258:14", pid 2174, jiffies 4294958305 hex dump (first 32 bytes): 00 00 00 c0 a8 ba 2d ff 00 00 00 00 00 00 00 00 ......-......... 00 00 40 08 00 00 00 00 00 00 25 b3 a8 ba 2d ff ..@.......%...-. backtrace (crc 36063c4f): __kmalloc_noprof+0x48f/0x890 idpf_vc_core_init+0x6ce/0x9b0 [idpf] idpf_vc_event_task+0x1fb/0x350 [idpf] process_one_work+0x226/0x6d0 worker_thread+0x19e/0x340 kthread+0x10f/0x250 ret_from_fork+0x251/0x2b0 ret_from_fork_asm+0x1a/0x30 Fixes: 6aa53e861c1a ("idpf: implement get LAN MMIO memory regions") Signed-off-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Joshua Hay Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 5bbe7d9294c1..01bbd12a642a 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3570,6 +3570,7 @@ init_failed: */ void idpf_vc_core_deinit(struct idpf_adapter *adapter) { + struct idpf_hw *hw = &adapter->hw; bool remove_in_prog; if (!test_bit(IDPF_VC_CORE_INIT, adapter->flags)) @@ -3593,6 +3594,9 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter) idpf_vport_params_buf_rel(adapter); + kfree(hw->lan_regs); + hw->lan_regs = NULL; + kfree(adapter->vports); adapter->vports = NULL; -- cgit v1.2.3 From 4d792219fe6f891b5b557a607ac8a0a14eda6e38 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Nov 2025 16:12:18 -0800 Subject: idpf: fix error handling in the init_task on load If the init_task fails during a driver load, we end up without vports and netdevs, effectively failing the entire process. In that state a subsequent reset will result in a crash as the service task attempts to access uninitialized resources. Following trace is from an error in the init_task where the CREATE_VPORT (op 501) is rejected by the FW: [40922.763136] idpf 0000:83:00.0: Device HW Reset initiated [40924.449797] idpf 0000:83:00.0: Transaction failed (op 501) [40958.148190] idpf 0000:83:00.0: HW reset detected [40958.161202] BUG: kernel NULL pointer dereference, address: 00000000000000a8 ... [40958.168094] Workqueue: idpf-0000:83:00.0-vc_event idpf_vc_event_task [idpf] [40958.168865] RIP: 0010:idpf_vc_event_task+0x9b/0x350 [idpf] ... [40958.177932] Call Trace: [40958.178491] [40958.179040] process_one_work+0x226/0x6d0 [40958.179609] worker_thread+0x19e/0x340 [40958.180158] ? __pfx_worker_thread+0x10/0x10 [40958.180702] kthread+0x10f/0x250 [40958.181238] ? __pfx_kthread+0x10/0x10 [40958.181774] ret_from_fork+0x251/0x2b0 [40958.182307] ? __pfx_kthread+0x10/0x10 [40958.182834] ret_from_fork_asm+0x1a/0x30 [40958.183370] Fix the error handling in the init_task to make sure the service and mailbox tasks are disabled if the error happens during load. These are started in idpf_vc_core_init(), which spawns the init_task and has no way of knowing if it failed. If the error happens on reset, following successful driver load, the tasks can still run, as that will allow the netdevs to attempt recovery through another reset. Stop the PTP callbacks either way as those will be restarted by the call to idpf_vc_core_init() during a successful reset. Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration") Reported-by: Vivek Kumar Signed-off-by: Emil Tantilov Reviewed-by: Madhu Chittim Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 04af10cfaa8c..e2ee8b137421 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1690,10 +1690,9 @@ void idpf_init_task(struct work_struct *work) set_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags); } - /* As all the required vports are created, clear the reset flag - * unconditionally here in case we were in reset and the link was down. - */ + /* Clear the reset and load bits as all vports are created */ clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); + clear_bit(IDPF_HR_DRV_LOAD, adapter->flags); /* Start the statistics task now */ queue_delayed_work(adapter->stats_wq, &adapter->stats_task, msecs_to_jiffies(10 * (pdev->devfn & 0x07))); @@ -1707,6 +1706,15 @@ unwind_vports: idpf_vport_dealloc(adapter->vports[index]); } } + /* Cleanup after vc_core_init, which has no way of knowing the + * init task failed on driver load. + */ + if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { + cancel_delayed_work_sync(&adapter->serv_task); + cancel_delayed_work_sync(&adapter->mbx_task); + } + idpf_ptp_release(adapter); + clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); } @@ -1856,7 +1864,7 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter) dev_info(dev, "Device HW Reset initiated\n"); /* Prepare for reset */ - if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { + if (test_bit(IDPF_HR_DRV_LOAD, adapter->flags)) { reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD); } else if (test_and_clear_bit(IDPF_HR_FUNC_RESET, adapter->flags)) { bool is_reset = idpf_is_reset_detected(adapter); -- cgit v1.2.3 From f9841bd28b600526ca4f6713b0ca49bf7bb98452 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Tue, 30 Sep 2025 16:23:51 -0500 Subject: idpf: fix memory leak of flow steer list on rmmod The flow steering list maintains entries that are added and removed as ethtool creates and deletes flow steering rules. Module removal with active entries causes memory leak as the list is not properly cleaned up. Prevent this by iterating through the remaining entries in the list and freeing the associated memory during module removal. Add a spinlock (flow_steer_list_lock) to protect the list access from multiple threads. Fixes: ada3e24b84a0 ("idpf: add flow steering support") Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Signed-off-by: Sreedevi Joshi Reviewed-by: Simon Horman Tested-by: Mina Almasry Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 2 ++ drivers/net/ethernet/intel/idpf/idpf_ethtool.c | 15 ++++++++++++-- drivers/net/ethernet/intel/idpf/idpf_lib.c | 28 +++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 8cfc68cbfa06..a61821333f5d 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -558,6 +558,7 @@ struct idpf_vector_lifo { * @max_q: Maximum possible queues * @req_qs_chunks: Queue chunk data for requested queues * @mac_filter_list_lock: Lock to protect mac filters + * @flow_steer_list_lock: Lock to protect fsteer filters * @flags: See enum idpf_vport_config_flags */ struct idpf_vport_config { @@ -565,6 +566,7 @@ struct idpf_vport_config { struct idpf_vport_max_q max_q; struct virtchnl2_add_queues *req_qs_chunks; spinlock_t mac_filter_list_lock; + spinlock_t flow_steer_list_lock; DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS); }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 2589e124e41c..00481fec8179 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -37,6 +37,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, { struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_vport_user_config_data *user_config; + struct idpf_vport_config *vport_config; struct idpf_fsteer_fltr *f; struct idpf_vport *vport; unsigned int cnt = 0; @@ -44,7 +45,8 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, idpf_vport_ctrl_lock(netdev); vport = idpf_netdev_to_vport(netdev); - user_config = &np->adapter->vport_config[np->vport_idx]->user_config; + vport_config = np->adapter->vport_config[np->vport_idx]; + user_config = &vport_config->user_config; switch (cmd->cmd) { case ETHTOOL_GRXCLSRLCNT: @@ -53,15 +55,18 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, break; case ETHTOOL_GRXCLSRULE: err = -EINVAL; + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) if (f->loc == cmd->fs.location) { cmd->fs.ring_cookie = f->q_index; err = 0; break; } + spin_unlock_bh(&vport_config->flow_steer_list_lock); break; case ETHTOOL_GRXCLSRLALL: cmd->data = idpf_fsteer_max_rules(vport); + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) { if (cnt == cmd->rule_cnt) { err = -EMSGSIZE; @@ -72,6 +77,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, } if (!err) cmd->rule_cnt = user_config->num_fsteer_fltrs; + spin_unlock_bh(&vport_config->flow_steer_list_lock); break; default: break; @@ -240,6 +246,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, fltr->loc = fsp->location; fltr->q_index = q_index; + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) { if (f->loc >= fltr->loc) break; @@ -250,6 +257,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, list_add(&fltr->list, &user_config->flow_steer_list); user_config->num_fsteer_fltrs++; + spin_unlock_bh(&vport_config->flow_steer_list_lock); out: kfree(rule); @@ -302,17 +310,20 @@ static int idpf_del_flow_steer(struct net_device *netdev, goto out; } + spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry_safe(f, iter, &user_config->flow_steer_list, list) { if (f->loc == fsp->location) { list_del(&f->list); kfree(f); user_config->num_fsteer_fltrs--; - goto out; + goto out_unlock; } } err = -EINVAL; +out_unlock: + spin_unlock_bh(&vport_config->flow_steer_list_lock); out: kfree(rule); return err; diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index e2ee8b137421..d56366e676cf 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -442,6 +442,29 @@ send_dealloc_vecs: return err; } +/** + * idpf_del_all_flow_steer_filters - Delete all flow steer filters in list + * @vport: main vport struct + * + * Takes flow_steer_list_lock spinlock. Deletes all filters + */ +static void idpf_del_all_flow_steer_filters(struct idpf_vport *vport) +{ + struct idpf_vport_config *vport_config; + struct idpf_fsteer_fltr *f, *ftmp; + + vport_config = vport->adapter->vport_config[vport->idx]; + + spin_lock_bh(&vport_config->flow_steer_list_lock); + list_for_each_entry_safe(f, ftmp, &vport_config->user_config.flow_steer_list, + list) { + list_del(&f->list); + kfree(f); + } + vport_config->user_config.num_fsteer_fltrs = 0; + spin_unlock_bh(&vport_config->flow_steer_list_lock); +} + /** * idpf_find_mac_filter - Search filter list for specific mac filter * @vconfig: Vport config structure @@ -1107,8 +1130,10 @@ static void idpf_vport_dealloc(struct idpf_vport *vport) idpf_vport_stop(vport, true); idpf_decfg_netdev(vport); } - if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) + if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) { idpf_del_all_mac_filters(vport); + idpf_del_all_flow_steer_filters(vport); + } if (adapter->netdevs[i]) { struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]); @@ -1648,6 +1673,7 @@ void idpf_init_task(struct work_struct *work) vport_config = adapter->vport_config[index]; spin_lock_init(&vport_config->mac_filter_list_lock); + spin_lock_init(&vport_config->flow_steer_list_lock); INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list); INIT_LIST_HEAD(&vport_config->user_config.flow_steer_list); -- cgit v1.2.3 From 36aae2ea6bd76b8246caa50e34a4f4824f0a3be8 Mon Sep 17 00:00:00 2001 From: Erik Gabriel Carrillo Date: Tue, 30 Sep 2025 16:23:52 -0500 Subject: idpf: fix issue with ethtool -n command display When ethtool -n is executed on an interface to display the flow steering rules, "rxclass: Unknown flow type" error is generated. The flow steering list maintained in the driver currently stores only the location and q_index but other fields of the ethtool_rx_flow_spec are not stored. This may be enough for the virtchnl command to delete the entry. However, when the ethtool -n command is used to query the flow steering rules, the ethtool_rx_flow_spec returned is not complete causing the error below. Resolve this by storing the flow spec (fsp) when rules are added and returning the complete flow spec when rules are queried. Also, change the return value from EINVAL to ENOENT when flow steering entry is not found during query by location or when deleting an entry. Add logic to detect and reject duplicate filter entries at the same location and change logic to perform upfront validation of all error conditions before adding flow rules through virtchnl. This avoids the need for additional virtchnl delete messages when subsequent operations fail, which was missing in the original upstream code. Example: Before the fix: ethtool -n eth1 2 RX rings available Total 2 rules rxclass: Unknown flow type rxclass: Unknown flow type After the fix: ethtool -n eth1 2 RX rings available Total 2 rules Filter: 0 Rule Type: TCP over IPv4 Src IP addr: 10.0.0.1 mask: 0.0.0.0 Dest IP addr: 0.0.0.0 mask: 255.255.255.255 TOS: 0x0 mask: 0xff Src port: 0 mask: 0xffff Dest port: 0 mask: 0xffff Action: Direct to queue 0 Filter: 1 Rule Type: UDP over IPv4 Src IP addr: 10.0.0.1 mask: 0.0.0.0 Dest IP addr: 0.0.0.0 mask: 255.255.255.255 TOS: 0x0 mask: 0xff Src port: 0 mask: 0xffff Dest port: 0 mask: 0xffff Action: Direct to queue 0 Fixes: ada3e24b84a0 ("idpf: add flow steering support") Signed-off-by: Erik Gabriel Carrillo Co-developed-by: Sreedevi Joshi Signed-off-by: Sreedevi Joshi Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Tested-by: Mina Almasry Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 3 +- drivers/net/ethernet/intel/idpf/idpf_ethtool.c | 59 +++++++++++++++++--------- 2 files changed, 40 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index a61821333f5d..dab36c0c3cdc 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -284,8 +284,7 @@ struct idpf_port_stats { struct idpf_fsteer_fltr { struct list_head list; - u32 loc; - u32 q_index; + struct ethtool_rx_flow_spec fs; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 00481fec8179..7000f6283a33 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -54,11 +54,15 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, cmd->data = idpf_fsteer_max_rules(vport); break; case ETHTOOL_GRXCLSRULE: - err = -EINVAL; + err = -ENOENT; spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry(f, &user_config->flow_steer_list, list) - if (f->loc == cmd->fs.location) { - cmd->fs.ring_cookie = f->q_index; + if (f->fs.location == cmd->fs.location) { + /* Avoid infoleak from padding: zero first, + * then assign fields + */ + memset(&cmd->fs, 0, sizeof(cmd->fs)); + cmd->fs = f->fs; err = 0; break; } @@ -72,7 +76,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, err = -EMSGSIZE; break; } - rule_locs[cnt] = f->loc; + rule_locs[cnt] = f->fs.location; cnt++; } if (!err) @@ -174,7 +178,7 @@ static int idpf_add_flow_steer(struct net_device *netdev, struct idpf_vport *vport; u32 flow_type, q_index; u16 num_rxq; - int err; + int err = 0; vport = idpf_netdev_to_vport(netdev); vport_config = vport->adapter->vport_config[np->vport_idx]; @@ -200,6 +204,29 @@ static int idpf_add_flow_steer(struct net_device *netdev, if (!rule) return -ENOMEM; + fltr = kzalloc(sizeof(*fltr), GFP_KERNEL); + if (!fltr) { + err = -ENOMEM; + goto out_free_rule; + } + + /* detect duplicate entry and reject before adding rules */ + spin_lock_bh(&vport_config->flow_steer_list_lock); + list_for_each_entry(f, &user_config->flow_steer_list, list) { + if (f->fs.location == fsp->location) { + err = -EEXIST; + break; + } + + if (f->fs.location > fsp->location) + break; + parent = f; + } + spin_unlock_bh(&vport_config->flow_steer_list_lock); + + if (err) + goto out; + rule->vport_id = cpu_to_le32(vport->vport_id); rule->count = cpu_to_le32(1); info = &rule->rule_info[0]; @@ -238,28 +265,20 @@ static int idpf_add_flow_steer(struct net_device *netdev, goto out; } - fltr = kzalloc(sizeof(*fltr), GFP_KERNEL); - if (!fltr) { - err = -ENOMEM; - goto out; - } + /* Save a copy of the user's flow spec so ethtool can later retrieve it */ + fltr->fs = *fsp; - fltr->loc = fsp->location; - fltr->q_index = q_index; spin_lock_bh(&vport_config->flow_steer_list_lock); - list_for_each_entry(f, &user_config->flow_steer_list, list) { - if (f->loc >= fltr->loc) - break; - parent = f; - } - parent ? list_add(&fltr->list, &parent->list) : list_add(&fltr->list, &user_config->flow_steer_list); user_config->num_fsteer_fltrs++; spin_unlock_bh(&vport_config->flow_steer_list_lock); + goto out_free_rule; out: + kfree(fltr); +out_free_rule: kfree(rule); return err; } @@ -313,14 +332,14 @@ static int idpf_del_flow_steer(struct net_device *netdev, spin_lock_bh(&vport_config->flow_steer_list_lock); list_for_each_entry_safe(f, iter, &user_config->flow_steer_list, list) { - if (f->loc == fsp->location) { + if (f->fs.location == fsp->location) { list_del(&f->list); kfree(f); user_config->num_fsteer_fltrs--; goto out_unlock; } } - err = -EINVAL; + err = -ENOENT; out_unlock: spin_unlock_bh(&vport_config->flow_steer_list_lock); -- cgit v1.2.3 From 83f38f210b85676f40ba8586b5a8edae19b56995 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:48 -0600 Subject: idpf: Fix RSS LUT NULL pointer crash on early ethtool operations The RSS LUT is not initialized until the interface comes up, causing the following NULL pointer crash when ethtool operations like rxhash on/off are performed before the interface is brought up for the first time. Move RSS LUT initialization from ndo_open to vport creation to ensure LUT is always available. This enables RSS configuration via ethtool before bringing the interface up. Simplify LUT management by maintaining all changes in the driver's soft copy and programming zeros to the indirection table when rxhash is disabled. Defer HW programming until the interface comes up if it is down during rxhash and LUT configuration changes. Steps to reproduce: ** Load idpf driver; interfaces will be created modprobe idpf ** Before bringing the interfaces up, turn rxhash off ethtool -K eth2 rxhash off [89408.371875] BUG: kernel NULL pointer dereference, address: 0000000000000000 [89408.371908] #PF: supervisor read access in kernel mode [89408.371924] #PF: error_code(0x0000) - not-present page [89408.371940] PGD 0 P4D 0 [89408.371953] Oops: Oops: 0000 [#1] SMP NOPTI [89408.372052] RIP: 0010:memcpy_orig+0x16/0x130 [89408.372310] Call Trace: [89408.372317] [89408.372326] ? idpf_set_features+0xfc/0x180 [idpf] [89408.372363] __netdev_update_features+0x295/0xde0 [89408.372384] ethnl_set_features+0x15e/0x460 [89408.372406] genl_family_rcv_msg_doit+0x11f/0x180 [89408.372429] genl_rcv_msg+0x1ad/0x2b0 [89408.372446] ? __pfx_ethnl_set_features+0x10/0x10 [89408.372465] ? __pfx_genl_rcv_msg+0x10/0x10 [89408.372482] netlink_rcv_skb+0x58/0x100 [89408.372502] genl_rcv+0x2c/0x50 [89408.372516] netlink_unicast+0x289/0x3e0 [89408.372533] netlink_sendmsg+0x215/0x440 [89408.372551] __sys_sendto+0x234/0x240 [89408.372571] __x64_sys_sendto+0x28/0x30 [89408.372585] x64_sys_call+0x1909/0x1da0 [89408.372604] do_syscall_64+0x7a/0xfa0 [89408.373140] ? clear_bhb_loop+0x60/0xb0 [89408.373647] entry_SYSCALL_64_after_hwframe+0x76/0x7e [89408.378887] Fixes: a251eee62133 ("idpf: add SRIOV support and other ndo_ops") Signed-off-by: Sreedevi Joshi Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Reviewed-by: Aleksandr Loktionov Reviewed-by: Paul Menzel Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf.h | 2 - drivers/net/ethernet/intel/idpf/idpf_lib.c | 94 +++++++++++-------------- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 36 ++++------ drivers/net/ethernet/intel/idpf/idpf_txrx.h | 4 +- drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 9 ++- 5 files changed, 66 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index dab36c0c3cdc..1bf7934d4e28 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -423,14 +423,12 @@ enum idpf_user_flags { * @rss_key: RSS hash key * @rss_lut_size: Size of RSS lookup table * @rss_lut: RSS lookup table - * @cached_lut: Used to restore previously init RSS lut */ struct idpf_rss_data { u16 rss_key_size; u8 *rss_key; u16 rss_lut_size; u32 *rss_lut; - u32 *cached_lut; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index d56366e676cf..51716e5a84ef 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1073,7 +1073,7 @@ static void idpf_vport_rel(struct idpf_vport *vport) u16 idx = vport->idx; vport_config = adapter->vport_config[vport->idx]; - idpf_deinit_rss(vport); + idpf_deinit_rss_lut(vport); rss_data = &vport_config->user_config.rss_data; kfree(rss_data->rss_key); rss_data->rss_key = NULL; @@ -1226,6 +1226,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, u16 idx = adapter->next_vport; struct idpf_vport *vport; u16 num_max_q; + int err; if (idx == IDPF_NO_FREE_SLOT) return NULL; @@ -1276,10 +1277,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, idpf_vport_init(vport, max_q); - /* This alloc is done separate from the LUT because it's not strictly - * dependent on how many queues we have. If we change number of queues - * and soft reset we'll need a new LUT but the key can remain the same - * for as long as the vport exists. + /* LUT and key are both initialized here. Key is not strictly dependent + * on how many queues we have. If we change number of queues and soft + * reset is initiated, LUT will be freed and a new LUT will be allocated + * as per the updated number of queues during vport bringup. However, + * the key remains the same for as long as the vport exists. */ rss_data = &adapter->vport_config[idx]->user_config.rss_data; rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL); @@ -1289,6 +1291,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, /* Initialize default rss key */ netdev_rss_key_fill((void *)rss_data->rss_key, rss_data->rss_key_size); + /* Initialize default rss LUT */ + err = idpf_init_rss_lut(vport); + if (err) + goto free_rss_key; + /* fill vport slot in the adapter struct */ adapter->vports[idx] = vport; adapter->vport_ids[idx] = idpf_get_vport_id(vport); @@ -1299,6 +1306,8 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, return vport; +free_rss_key: + kfree(rss_data->rss_key); free_vector_idxs: kfree(vport->q_vector_idxs); free_vport: @@ -1476,6 +1485,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) struct idpf_netdev_priv *np = netdev_priv(vport->netdev); struct idpf_adapter *adapter = vport->adapter; struct idpf_vport_config *vport_config; + struct idpf_rss_data *rss_data; int err; if (test_bit(IDPF_VPORT_UP, np->state)) @@ -1570,12 +1580,21 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) idpf_restore_features(vport); vport_config = adapter->vport_config[vport->idx]; - if (vport_config->user_config.rss_data.rss_lut) - err = idpf_config_rss(vport); - else - err = idpf_init_rss(vport); + rss_data = &vport_config->user_config.rss_data; + + if (!rss_data->rss_lut) { + err = idpf_init_rss_lut(vport); + if (err) { + dev_err(&adapter->pdev->dev, + "Failed to initialize RSS LUT for vport %u: %d\n", + vport->vport_id, err); + goto disable_vport; + } + } + + err = idpf_config_rss(vport); if (err) { - dev_err(&adapter->pdev->dev, "Failed to initialize RSS for vport %u: %d\n", + dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n", vport->vport_id, err); goto disable_vport; } @@ -1584,7 +1603,7 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) if (err) { dev_err(&adapter->pdev->dev, "Failed to complete interface up for vport %u: %d\n", vport->vport_id, err); - goto deinit_rss; + goto disable_vport; } if (rtnl) @@ -1592,8 +1611,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) return 0; -deinit_rss: - idpf_deinit_rss(vport); disable_vport: idpf_send_disable_vport_msg(vport); disable_queues: @@ -2051,7 +2068,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, idpf_vport_stop(vport, false); } - idpf_deinit_rss(vport); + idpf_deinit_rss_lut(vport); /* We're passing in vport here because we need its wait_queue * to send a message and it should be getting all the vport * config data out of the adapter but we need to be careful not @@ -2219,40 +2236,6 @@ static void idpf_set_rx_mode(struct net_device *netdev) dev_err(dev, "Failed to set promiscuous mode: %d\n", err); } -/** - * idpf_vport_manage_rss_lut - disable/enable RSS - * @vport: the vport being changed - * - * In the event of disable request for RSS, this function will zero out RSS - * LUT, while in the event of enable request for RSS, it will reconfigure RSS - * LUT with the default LUT configuration. - */ -static int idpf_vport_manage_rss_lut(struct idpf_vport *vport) -{ - bool ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); - struct idpf_rss_data *rss_data; - u16 idx = vport->idx; - int lut_size; - - rss_data = &vport->adapter->vport_config[idx]->user_config.rss_data; - lut_size = rss_data->rss_lut_size * sizeof(u32); - - if (ena) { - /* This will contain the default or user configured LUT */ - memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size); - } else { - /* Save a copy of the current LUT to be restored later if - * requested. - */ - memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size); - - /* Zero out the current LUT to disable */ - memset(rss_data->rss_lut, 0, lut_size); - } - - return idpf_config_rss(vport); -} - /** * idpf_set_features - set the netdev feature flags * @netdev: ptr to the netdev being adjusted @@ -2278,10 +2261,19 @@ static int idpf_set_features(struct net_device *netdev, } if (changed & NETIF_F_RXHASH) { + struct idpf_netdev_priv *np = netdev_priv(netdev); + netdev->features ^= NETIF_F_RXHASH; - err = idpf_vport_manage_rss_lut(vport); - if (err) - goto unlock_mutex; + + /* If the interface is not up when changing the rxhash, update + * to the HW is skipped. The updated LUT will be committed to + * the HW when the interface is brought up. + */ + if (test_bit(IDPF_VPORT_UP, np->state)) { + err = idpf_config_rss(vport); + if (err) + goto unlock_mutex; + } } if (changed & NETIF_F_GRO_HW) { diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 1d91c56f7469..8991a891a440 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -4650,57 +4650,47 @@ static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - for (i = 0; i < rss_data->rss_lut_size; i++) { + for (i = 0; i < rss_data->rss_lut_size; i++) rss_data->rss_lut[i] = i % num_active_rxq; - rss_data->cached_lut[i] = rss_data->rss_lut[i]; - } } /** - * idpf_init_rss - Allocate and initialize RSS resources + * idpf_init_rss_lut - Allocate and initialize RSS LUT * @vport: virtual port * - * Return 0 on success, negative on failure + * Return: 0 on success, negative on failure */ -int idpf_init_rss(struct idpf_vport *vport) +int idpf_init_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; struct idpf_rss_data *rss_data; - u32 lut_size; rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; + if (!rss_data->rss_lut) { + u32 lut_size; - lut_size = rss_data->rss_lut_size * sizeof(u32); - rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL); - if (!rss_data->rss_lut) - return -ENOMEM; - - rss_data->cached_lut = kzalloc(lut_size, GFP_KERNEL); - if (!rss_data->cached_lut) { - kfree(rss_data->rss_lut); - rss_data->rss_lut = NULL; - - return -ENOMEM; + lut_size = rss_data->rss_lut_size * sizeof(u32); + rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL); + if (!rss_data->rss_lut) + return -ENOMEM; } /* Fill the default RSS lut values */ idpf_fill_dflt_rss_lut(vport); - return idpf_config_rss(vport); + return 0; } /** - * idpf_deinit_rss - Release RSS resources + * idpf_deinit_rss_lut - Release RSS LUT * @vport: virtual port */ -void idpf_deinit_rss(struct idpf_vport *vport) +void idpf_deinit_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; struct idpf_rss_data *rss_data; rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - kfree(rss_data->cached_lut); - rss_data->cached_lut = NULL; kfree(rss_data->rss_lut); rss_data->rss_lut = NULL; } diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 75b977094741..7d20593bd877 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -1086,8 +1086,8 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport); int idpf_vport_intr_init(struct idpf_vport *vport); void idpf_vport_intr_ena(struct idpf_vport *vport); int idpf_config_rss(struct idpf_vport *vport); -int idpf_init_rss(struct idpf_vport *vport); -void idpf_deinit_rss(struct idpf_vport *vport); +int idpf_init_rss_lut(struct idpf_vport *vport); +void idpf_deinit_rss_lut(struct idpf_vport *vport); int idpf_rx_bufs_init_all(struct idpf_vport *vport); struct idpf_q_vector *idpf_find_rxq_vec(const struct idpf_vport *vport, diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 01bbd12a642a..cb702eac86c8 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -2804,6 +2804,10 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport) * @vport: virtual port data structure * @get: flag to set or get rss look up table * + * When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash + * is enabled, the LUT values stored in driver's soft copy will be used to setup + * the HW. + * * Returns 0 on success, negative on failure. */ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) @@ -2814,10 +2818,12 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) struct idpf_rss_data *rss_data; int buf_size, lut_buf_size; ssize_t reply_sz; + bool rxhash_ena; int i; rss_data = &vport->adapter->vport_config[vport->idx]->user_config.rss_data; + rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); buf_size = struct_size(rl, lut, rss_data->rss_lut_size); rl = kzalloc(buf_size, GFP_KERNEL); if (!rl) @@ -2839,7 +2845,8 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get) } else { rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size); for (i = 0; i < rss_data->rss_lut_size; i++) - rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]); + rl->lut[i] = rxhash_ena ? + cpu_to_le32(rss_data->rss_lut[i]) : 0; xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT; } -- cgit v1.2.3 From 445b49d13787da2fe8d51891ee196e5077feef44 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:49 -0600 Subject: idpf: Fix RSS LUT configuration on down interfaces RSS LUT provisioning and queries on a down interface currently return silently without effect. Users should be able to configure RSS settings even when the interface is down. Fix by maintaining RSS configuration changes in the driver's soft copy and deferring HW programming until the interface comes up. Fixes: 02cbfba1add5 ("idpf: add ethtool callbacks") Signed-off-by: Sreedevi Joshi Reviewed-by: Aleksandr Loktionov Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_ethtool.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 7000f6283a33..2efa3c08aba5 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -411,7 +411,10 @@ static u32 idpf_get_rxfh_indir_size(struct net_device *netdev) * @netdev: network interface device structure * @rxfh: pointer to param struct (indir, key, hfunc) * - * Reads the indirection table directly from the hardware. Always returns 0. + * RSS LUT and Key information are read from driver's cached + * copy. When rxhash is off, rss lut will be displayed as zeros. + * + * Return: 0 on success, -errno otherwise. */ static int idpf_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) @@ -419,10 +422,13 @@ static int idpf_get_rxfh(struct net_device *netdev, struct idpf_netdev_priv *np = netdev_priv(netdev); struct idpf_rss_data *rss_data; struct idpf_adapter *adapter; + struct idpf_vport *vport; + bool rxhash_ena; int err = 0; u16 i; idpf_vport_ctrl_lock(netdev); + vport = idpf_netdev_to_vport(netdev); adapter = np->adapter; @@ -432,9 +438,8 @@ static int idpf_get_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data; - if (!test_bit(IDPF_VPORT_UP, np->state)) - goto unlock_mutex; + rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); rxfh->hfunc = ETH_RSS_HASH_TOP; if (rxfh->key) @@ -442,7 +447,7 @@ static int idpf_get_rxfh(struct net_device *netdev, if (rxfh->indir) { for (i = 0; i < rss_data->rss_lut_size; i++) - rxfh->indir[i] = rss_data->rss_lut[i]; + rxfh->indir[i] = rxhash_ena ? rss_data->rss_lut[i] : 0; } unlock_mutex: @@ -482,8 +487,6 @@ static int idpf_set_rxfh(struct net_device *netdev, } rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data; - if (!test_bit(IDPF_VPORT_UP, np->state)) - goto unlock_mutex; if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP) { @@ -499,7 +502,8 @@ static int idpf_set_rxfh(struct net_device *netdev, rss_data->rss_lut[lut] = rxfh->indir[lut]; } - err = idpf_config_rss(vport); + if (test_bit(IDPF_VPORT_UP, np->state)) + err = idpf_config_rss(vport); unlock_mutex: idpf_vport_ctrl_unlock(netdev); -- cgit v1.2.3 From ebecca5b093895da801b3eba1a55b4ec4027d196 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Mon, 24 Nov 2025 12:47:50 -0600 Subject: idpf: Fix RSS LUT NULL ptr issue after soft reset During soft reset, the RSS LUT is freed and not restored unless the interface is up. If an ethtool command that accesses the rss lut is attempted immediately after reset, it will result in NULL ptr dereference. Also, there is no need to reset the rss lut if the soft reset does not involve queue count change. After soft reset, set the RSS LUT to default values based on the updated queue count only if the reset was a result of a queue count change and the LUT was not configured by the user. In all other cases, don't touch the LUT. Steps to reproduce: ** Bring the interface down (if up) ifconfig eth1 down ** update the queue count (eg., 27->20) ethtool -L eth1 combined 20 ** display the RSS LUT ethtool -x eth1 [82375.558338] BUG: kernel NULL pointer dereference, address: 0000000000000000 [82375.558373] #PF: supervisor read access in kernel mode [82375.558391] #PF: error_code(0x0000) - not-present page [82375.558408] PGD 0 P4D 0 [82375.558421] Oops: Oops: 0000 [#1] SMP NOPTI [82375.558516] RIP: 0010:idpf_get_rxfh+0x108/0x150 [idpf] [82375.558786] Call Trace: [82375.558793] [82375.558804] rss_prepare.isra.0+0x187/0x2a0 [82375.558827] rss_prepare_data+0x3a/0x50 [82375.558845] ethnl_default_doit+0x13d/0x3e0 [82375.558863] genl_family_rcv_msg_doit+0x11f/0x180 [82375.558886] genl_rcv_msg+0x1ad/0x2b0 [82375.558902] ? __pfx_ethnl_default_doit+0x10/0x10 [82375.558920] ? __pfx_genl_rcv_msg+0x10/0x10 [82375.558937] netlink_rcv_skb+0x58/0x100 [82375.558957] genl_rcv+0x2c/0x50 [82375.558971] netlink_unicast+0x289/0x3e0 [82375.558988] netlink_sendmsg+0x215/0x440 [82375.559005] __sys_sendto+0x234/0x240 [82375.559555] __x64_sys_sendto+0x28/0x30 [82375.560068] x64_sys_call+0x1909/0x1da0 [82375.560576] do_syscall_64+0x7a/0xfa0 [82375.561076] ? clear_bhb_loop+0x60/0xb0 [82375.561567] entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 02cbfba1add5 ("idpf: add ethtool callbacks") Signed-off-by: Sreedevi Joshi Reviewed-by: Aleksandr Loktionov Reviewed-by: Sridhar Samudrala Reviewed-by: Emil Tantilov Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 20 ++++---------------- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 1 + 3 files changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 51716e5a84ef..003bab3ce5ae 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1484,8 +1484,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) { struct idpf_netdev_priv *np = netdev_priv(vport->netdev); struct idpf_adapter *adapter = vport->adapter; - struct idpf_vport_config *vport_config; - struct idpf_rss_data *rss_data; int err; if (test_bit(IDPF_VPORT_UP, np->state)) @@ -1579,19 +1577,6 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) idpf_restore_features(vport); - vport_config = adapter->vport_config[vport->idx]; - rss_data = &vport_config->user_config.rss_data; - - if (!rss_data->rss_lut) { - err = idpf_init_rss_lut(vport); - if (err) { - dev_err(&adapter->pdev->dev, - "Failed to initialize RSS LUT for vport %u: %d\n", - vport->vport_id, err); - goto disable_vport; - } - } - err = idpf_config_rss(vport); if (err) { dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n", @@ -2068,7 +2053,6 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, idpf_vport_stop(vport, false); } - idpf_deinit_rss_lut(vport); /* We're passing in vport here because we need its wait_queue * to send a message and it should be getting all the vport * config data out of the adapter but we need to be careful not @@ -2094,6 +2078,10 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, if (err) goto err_open; + if (reset_cause == IDPF_SR_Q_CHANGE && + !netif_is_rxfh_configured(vport->netdev)) + idpf_fill_dflt_rss_lut(vport); + if (vport_is_up) err = idpf_vport_open(vport, false); diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 8991a891a440..f51d52297e1e 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -4641,7 +4641,7 @@ int idpf_config_rss(struct idpf_vport *vport) * idpf_fill_dflt_rss_lut - Fill the indirection table with the default values * @vport: virtual port structure */ -static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) +void idpf_fill_dflt_rss_lut(struct idpf_vport *vport) { struct idpf_adapter *adapter = vport->adapter; u16 num_active_rxq = vport->num_rxq; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 7d20593bd877..0472698ca192 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -1085,6 +1085,7 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector); void idpf_vport_intr_deinit(struct idpf_vport *vport); int idpf_vport_intr_init(struct idpf_vport *vport); void idpf_vport_intr_ena(struct idpf_vport *vport); +void idpf_fill_dflt_rss_lut(struct idpf_vport *vport); int idpf_config_rss(struct idpf_vport *vport); int idpf_init_rss_lut(struct idpf_vport *vport); void idpf_deinit_rss_lut(struct idpf_vport *vport); -- cgit v1.2.3 From 87b8ee64685bc096a087af833d4594b2332bfdb1 Mon Sep 17 00:00:00 2001 From: Sreedevi Joshi Date: Tue, 2 Dec 2025 17:12:46 -0600 Subject: idpf: Fix error handling in idpf_vport_open() Fix error handling to properly cleanup interrupts when idpf_vport_queue_ids_init() or idpf_rx_bufs_init_all() fail. Jump to 'intr_deinit' instead of 'queues_rel' to ensure interrupts are cleaned up before releasing other resources. Fixes: d4d558718266 ("idpf: initialize interrupts and enable vport") Signed-off-by: Sreedevi Joshi Reviewed-by: Madhu Chittim Reviewed-by: Aleksandr Loktionov Reviewed-by: Simon Horman Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 003bab3ce5ae..131a8121839b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1524,14 +1524,14 @@ static int idpf_vport_open(struct idpf_vport *vport, bool rtnl) if (err) { dev_err(&adapter->pdev->dev, "Failed to initialize queue registers for vport %u: %d\n", vport->vport_id, err); - goto queues_rel; + goto intr_deinit; } err = idpf_rx_bufs_init_all(vport); if (err) { dev_err(&adapter->pdev->dev, "Failed to initialize RX buffers for vport %u: %d\n", vport->vport_id, err); - goto queues_rel; + goto intr_deinit; } idpf_rx_init_buf_tail(vport); -- cgit v1.2.3 From 086efe0a1ecc36cffe46640ce12649a4cd3ff171 Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Mon, 3 Nov 2025 13:20:36 -0800 Subject: idpf: cap maximum Rx buffer size The HW only supports a maximum Rx buffer size of 16K-128. On systems using large pages, the libeth logic can configure the buffer size to be larger than this. The upper bound is PAGE_SIZE while the lower bound is MTU rounded up to the nearest power of 2. For example, ARM systems with a 64K page size and an mtu of 9000 will set the Rx buffer size to 16K, which will cause the config Rx queues message to fail. Initialize the bufq/fill queue buf_len field to the maximum supported size. This will trigger the libeth logic to cap the maximum Rx buffer size by reducing the upper bound. Fixes: 74d1412ac8f37 ("idpf: use libeth Rx buffer management for payload buffer") Signed-off-by: Joshua Hay Acked-by: Alexander Lobakin Reviewed-by: Madhu Chittim Reviewed-by: Jacob Keller Reviewed-by: Aleksandr Loktionov Reviewed-by: David Decotigny Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 8 +++++--- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index f51d52297e1e..7f3933ca9edc 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -695,9 +695,10 @@ err: static int idpf_rx_bufs_init_singleq(struct idpf_rx_queue *rxq) { struct libeth_fq fq = { - .count = rxq->desc_count, - .type = LIBETH_FQE_MTU, - .nid = idpf_q_vector_to_mem(rxq->q_vector), + .count = rxq->desc_count, + .type = LIBETH_FQE_MTU, + .buf_len = IDPF_RX_MAX_BUF_SZ, + .nid = idpf_q_vector_to_mem(rxq->q_vector), }; int ret; @@ -754,6 +755,7 @@ static int idpf_rx_bufs_init(struct idpf_buf_queue *bufq, .truesize = bufq->truesize, .count = bufq->desc_count, .type = type, + .buf_len = IDPF_RX_MAX_BUF_SZ, .hsplit = idpf_queue_has(HSPLIT_EN, bufq), .xdp = idpf_xdp_enabled(bufq->q_vector->vport), .nid = idpf_q_vector_to_mem(bufq->q_vector), diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 0472698ca192..423cc9486dce 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -101,6 +101,7 @@ do { \ idx = 0; \ } while (0) +#define IDPF_RX_MAX_BUF_SZ (16384 - 128) #define IDPF_RX_BUF_STRIDE 32 #define IDPF_RX_BUF_POST_STRIDE 16 #define IDPF_LOW_WATERMARK 64 -- cgit v1.2.3 From 4648fb2f2e7210c53b85220ee07d42d1e4bae3f9 Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Mon, 17 Nov 2025 08:03:49 +0100 Subject: idpf: fix aux device unplugging when rdma is not supported by vport If vport flags do not contain VIRTCHNL2_VPORT_ENABLE_RDMA, driver does not allocate vdev_info for this vport. This leads to kernel NULL pointer dereference in idpf_idc_vport_dev_down(), which references vdev_info for every vport regardless. Check, if vdev_info was ever allocated before unplugging aux device. Fixes: be91128c579c ("idpf: implement RDMA vport auxiliary dev create, init, and destroy") Reviewed-by: Madhu Chittim Signed-off-by: Larysa Zaremba Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Tested-by: Krishneil Singh Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_idc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c index 7e20a07e98e5..6dad0593f7f2 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c @@ -322,7 +322,7 @@ static void idpf_idc_vport_dev_down(struct idpf_adapter *adapter) for (i = 0; i < adapter->num_alloc_vports; i++) { struct idpf_vport *vport = adapter->vports[i]; - if (!vport) + if (!vport || !vport->vdev_info) continue; idpf_unplug_aux_dev(vport->vdev_info->adev); -- cgit v1.2.3 From 7801edc9badd972cb62cf11c0427e70b6dca239d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 4 Jan 2026 11:39:52 +0200 Subject: Revert "dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable" This reverts commit 926eae604403acfa27ba5b072af458e87e634a50, which never could have produced the intended effect: https://lore.kernel.org/netdev/AM0PR06MB10396BBF8B568D77556FC46F8F7DEA@AM0PR06MB10396.eurprd06.prod.outlook.com/ The reason why it is broken beyond repair in this form is that the mv88e6xxx driver outsources its "tx-p2p-microvolt" property to the OF node of an external Ethernet PHY. This: (a) does not work if there is no external PHY (chip-to-chip connection, or SFP module) (b) pollutes the OF property namespace / bindings of said external PHY ("tx-p2p-microvolt" could have meaning for the Ethernet PHY's SerDes interface as well) We can revisit the idea of making SerDes amplitude configurable once we have proper bindings for the mv88e6xxx SerDes. Until then, remove the code that leaves us with unnecessary baggage. Fixes: 926eae604403 ("dsa: mv88e6xxx: make serdes SGMII/Fiber tx amplitude configurable") Cc: Holger Brunck Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260104093952.486606-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 23 ------------------- drivers/net/dsa/mv88e6xxx/chip.h | 4 ---- drivers/net/dsa/mv88e6xxx/serdes.c | 46 -------------------------------------- drivers/net/dsa/mv88e6xxx/serdes.h | 5 ----- 4 files changed, 78 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b4d48997bf46..09002c853b78 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3364,13 +3364,10 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { - struct device_node *phy_handle = NULL; struct fwnode_handle *ports_fwnode; struct fwnode_handle *port_fwnode; struct dsa_switch *ds = chip->ds; struct mv88e6xxx_port *p; - struct dsa_port *dp; - int tx_amp; int err; u16 reg; u32 val; @@ -3582,23 +3579,6 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; } - if (chip->info->ops->serdes_set_tx_amplitude) { - dp = dsa_to_port(ds, port); - if (dp) - phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0); - - if (phy_handle && !of_property_read_u32(phy_handle, - "tx-p2p-microvolt", - &tx_amp)) - err = chip->info->ops->serdes_set_tx_amplitude(chip, - port, tx_amp); - if (phy_handle) { - of_node_put(phy_handle); - if (err) - return err; - } - } - /* Port based VLAN map: give each port the same default address * database, and allow bidirectional communication between the * CPU and DSA port(s), and the other ports. @@ -4768,7 +4748,6 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .gpio_ops = &mv88e6352_gpio_ops, .phylink_get_caps = mv88e6352_phylink_get_caps, .pcs_ops = &mv88e6352_pcs_ops, @@ -5044,7 +5023,6 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, @@ -5481,7 +5459,6 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .serdes_get_stats = mv88e6352_serdes_get_stats, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, - .serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude, .phylink_get_caps = mv88e6352_phylink_get_caps, .pcs_ops = &mv88e6352_pcs_ops, }; diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 2f211e55cb47..e073446ee7d0 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -642,10 +642,6 @@ struct mv88e6xxx_ops { void (*serdes_get_regs)(struct mv88e6xxx_chip *chip, int port, void *_p); - /* SERDES SGMII/Fiber Output Amplitude */ - int (*serdes_set_tx_amplitude)(struct mv88e6xxx_chip *chip, int port, - int val); - /* Address Translation Unit operations */ int (*atu_get_hash)(struct mv88e6xxx_chip *chip, u8 *hash); int (*atu_set_hash)(struct mv88e6xxx_chip *chip, u8 hash); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index b3330211edbc..a936ee80ce00 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -25,14 +25,6 @@ static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, reg, val); } -static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, - u16 val) -{ - return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, - MV88E6352_SERDES_PAGE_FIBER, - reg, val); -} - static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip, int lane, int device, int reg, u16 *val) { @@ -506,41 +498,3 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) p[i] = reg; } } - -static const int mv88e6352_serdes_p2p_to_reg[] = { - /* Index of value in microvolts corresponds to the register value */ - 14000, 112000, 210000, 308000, 406000, 504000, 602000, 700000, -}; - -int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port, - int val) -{ - bool found = false; - u16 ctrl, reg; - int err; - int i; - - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; - - for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_p2p_to_reg); ++i) { - if (mv88e6352_serdes_p2p_to_reg[i] == val) { - reg = i; - found = true; - break; - } - } - - if (!found) - return -EINVAL; - - err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_SPEC_CTRL2, &ctrl); - if (err) - return err; - - ctrl &= ~MV88E6352_SERDES_OUT_AMP_MASK; - ctrl |= reg; - - return mv88e6352_serdes_write(chip, MV88E6352_SERDES_SPEC_CTRL2, ctrl); -} diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index ad887d8601bc..17a3e85fabaa 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -29,8 +29,6 @@ struct phylink_link_state; #define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4) #define MV88E6352_SERDES_INT_STATUS 0x13 -#define MV88E6352_SERDES_SPEC_CTRL2 0x1a -#define MV88E6352_SERDES_OUT_AMP_MASK 0x0007 #define MV88E6341_PORT5_LANE 0x15 @@ -140,9 +138,6 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port); void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); -int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port, - int val); - /* Return the (first) SERDES lane address a port is using, -errno otherwise. */ static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) -- cgit v1.2.3 From 13ff3e724207f579d3c814ee05516fefcb4f32e8 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Mon, 5 Jan 2026 16:18:39 +0100 Subject: net: sfp: return the number of written bytes for smbus single byte access We expect the SFP write accessors to return the number of written bytes. We fail to do so for single-byte smbus accesses, which may cause errors when setting a module's high-power state and for some cotsworks modules. Let's return the amount of written bytes, as expected. Fixes: 7662abf4db94 ("net: phy: sfp: Add support for SMBus module access") Signed-off-by: Maxime Chevallier Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20260105151840.144552-1-maxime.chevallier@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 6166e9196364..84bef5099dda 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -765,7 +765,7 @@ static int sfp_smbus_byte_write(struct sfp *sfp, bool a2, u8 dev_addr, dev_addr++; } - return 0; + return data - (u8 *)buf; } static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) -- cgit v1.2.3 From d83dddffe1904e4a576d11a541878850a8e64cd2 Mon Sep 17 00:00:00 2001 From: Yohei Kojima Date: Tue, 6 Jan 2026 00:17:32 +0900 Subject: net: netdevsim: fix inconsistent carrier state after link/unlink This patch fixes the edge case behavior on ifup/ifdown and linking/unlinking two netdevsim interfaces: 1. unlink two interfaces netdevsim1 and netdevsim2 2. ifdown netdevsim1 3. ifup netdevsim1 4. link two interfaces netdevsim1 and netdevsim2 5. (Now two interfaces are linked in terms of netdevsim peer, but carrier state of the two interfaces remains DOWN.) This inconsistent behavior is caused by the current implementation, which only cares about the "link, then ifup" order, not "ifup, then link" order. This patch fixes the inconsistency by calling netif_carrier_on() when two netdevsim interfaces are linked. This patch fixes buggy behavior on NetworkManager-based systems which causes the netdevsim test to fail with the following error: # timeout set to 600 # selftests: drivers/net/netdevsim: peer.sh # 2025/12/25 00:54:03 socat[9115] W address is opened in read-write mode but only supports read-only # 2025/12/25 00:56:17 socat[9115] W connect(7, AF=2 192.168.1.1:1234, 16): Connection timed out # 2025/12/25 00:56:17 socat[9115] E TCP:192.168.1.1:1234: Connection timed out # expected 3 bytes, got 0 # 2025/12/25 00:56:17 socat[9109] W exiting on signal 15 not ok 13 selftests: drivers/net/netdevsim: peer.sh # exit=1 This patch also solves timeout on TCP Fast Open (TFO) test in NetworkManager-based systems because it also depends on netdevsim's carrier consistency. Fixes: 1a8fed52f7be ("netdevsim: set the carrier when the device goes up") Signed-off-by: Yohei Kojima Reviewed-by: Breno Leitao Link: https://patch.msgid.link/602c9e1ba5bb2ee1997bb38b1d866c9c3b807ae9.1767624906.git.yk@y-koj.net Signed-off-by: Jakub Kicinski --- drivers/net/netdevsim/bus.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 70e8c38ddad6..d16b95304aa7 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -332,6 +332,11 @@ static ssize_t link_device_store(const struct bus_type *bus, const char *buf, si rcu_assign_pointer(nsim_a->peer, nsim_b); rcu_assign_pointer(nsim_b->peer, nsim_a); + if (netif_running(dev_a) && netif_running(dev_b)) { + netif_carrier_on(dev_a); + netif_carrier_on(dev_b); + } + out_err: put_net(ns_b); put_net(ns_a); @@ -381,6 +386,9 @@ static ssize_t unlink_device_store(const struct bus_type *bus, const char *buf, if (!peer) goto out_put_netns; + netif_carrier_off(dev); + netif_carrier_off(peer->netdev); + err = 0; RCU_INIT_POINTER(nsim->peer, NULL); RCU_INIT_POINTER(peer->peer, NULL); -- cgit v1.2.3 From 20cf2aed89ac6d78a0122e31c875228e15247194 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 6 Jan 2026 10:00:11 +0100 Subject: gpio: rockchip: mark the GPIO controller as sleeping The GPIO controller is configured as non-sleeping but it uses generic pinctrl helpers which use a mutex for synchronization. This can cause the following lockdep splat with shared GPIOs enabled on boards which have multiple devices using the same GPIO: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 12, name: kworker/u16:0 preempt_count: 1, expected: 0 RCU nest depth: 0, expected: 0 6 locks held by kworker/u16:0/12: #0: ffff0001f0018d48 ((wq_completion)events_unbound#2){+.+.}-{0:0}, at: process_one_work+0x18c/0x604 #1: ffff8000842dbdf0 (deferred_probe_work){+.+.}-{0:0}, at: process_one_work+0x1b4/0x604 #2: ffff0001f18498f8 (&dev->mutex){....}-{4:4}, at: __device_attach+0x38/0x1b0 #3: ffff0001f75f1e90 (&gdev->srcu){.+.?}-{0:0}, at: gpiod_direction_output_raw_commit+0x0/0x360 #4: ffff0001f46e3db8 (&shared_desc->spinlock){....}-{3:3}, at: gpio_shared_proxy_direction_output+0xd0/0x144 [gpio_shared_proxy] #5: ffff0001f180ee90 (&gdev->srcu){.+.?}-{0:0}, at: gpiod_direction_output_raw_commit+0x0/0x360 irq event stamp: 81450 hardirqs last enabled at (81449): [] _raw_spin_unlock_irqrestore+0x74/0x78 hardirqs last disabled at (81450): [] _raw_spin_lock_irqsave+0x84/0x88 softirqs last enabled at (79616): [] __alloc_skb+0x17c/0x1e8 softirqs last disabled at (79614): [] __alloc_skb+0x17c/0x1e8 CPU: 2 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.0-rc4-next-20260105+ #11975 PREEMPT Hardware name: Hardkernel ODROID-M1 (DT) Workqueue: events_unbound deferred_probe_work_func Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0x90/0xd0 dump_stack+0x18/0x24 __might_resched+0x144/0x248 __might_sleep+0x48/0x98 __mutex_lock+0x5c/0x894 mutex_lock_nested+0x24/0x30 pinctrl_get_device_gpio_range+0x44/0x128 pinctrl_gpio_direction+0x3c/0xe0 pinctrl_gpio_direction_output+0x14/0x20 rockchip_gpio_direction_output+0xb8/0x19c gpiochip_direction_output+0x38/0x94 gpiod_direction_output_raw_commit+0x1d8/0x360 gpiod_direction_output_nonotify+0x7c/0x230 gpiod_direction_output+0x34/0xf8 gpio_shared_proxy_direction_output+0xec/0x144 [gpio_shared_proxy] gpiochip_direction_output+0x38/0x94 gpiod_direction_output_raw_commit+0x1d8/0x360 gpiod_direction_output_nonotify+0x7c/0x230 gpiod_configure_flags+0xbc/0x480 gpiod_find_and_request+0x1a0/0x574 gpiod_get_index+0x58/0x84 devm_gpiod_get_index+0x20/0xb4 devm_gpiod_get_optional+0x18/0x30 rockchip_pcie_probe+0x98/0x380 platform_probe+0x5c/0xac really_probe+0xbc/0x298 Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio") Cc: stable@vger.kernel.org Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/d035fc29-3b03-4cd6-b8ec-001f93540bc6@samsung.com/ Acked-by: Heiko Stuebner Link: https://lore.kernel.org/r/20260106090011.21603-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rockchip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 47174eb3ba76..bae2061f15fc 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -593,6 +593,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) gc->ngpio = bank->nr_pins; gc->label = bank->name; gc->parent = bank->dev; + gc->can_sleep = true; ret = gpiochip_add_data(gc, bank); if (ret) { -- cgit v1.2.3 From 0fe50631791bd3504dc7f32af6421bd4041f14aa Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 6 Jan 2026 10:34:21 +0100 Subject: gpio: shared: assign the correct firmware node for reset-gpio use-case When we defer probe due to unlucky timing of adding the lookup table, we assign the matching firmware node to the shared reference for the future probing. However, the fwnode we assign is wrong so fix it and assign the one associated with the reset-gpio device. Fixes: 49416483a953 ("gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib") Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/00107523-7737-4b92-a785-14ce4e93b8cb@samsung.com/ Tested-by: Mark Brown Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-1-c7091d2f7581@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index baf7e07a3bb8..a68af06a6cc4 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -417,7 +417,7 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, * Reuse the fwnode of the real device, next time we'll use it * in the normal path. */ - ref->fwnode = fwnode_handle_get(real_ref->fwnode); + ref->fwnode = fwnode_handle_get(reset_fwnode); return true; } -- cgit v1.2.3 From 476e44d06fc107f8cd99695d8e4f1c792dfc3379 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 6 Jan 2026 10:34:22 +0100 Subject: gpio: shared: fix a race condition When matching the reset-gpio reference with the actual firmware node consuming the GPIO, we also need to lock the structure associated with the latter as it can change while we're doing it. Due to triggering lockdep false-positives, we need to use a per-reference lockdep class but accidentally, this also allows us to remove the previous lockdep workaround for cleaner code. Fixes: 49416483a953 ("gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib") Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/00107523-7737-4b92-a785-14ce4e93b8cb@samsung.com/ Tested-by: Mark Brown Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-2-c7091d2f7581@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index a68af06a6cc4..4c57b0928760 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -38,6 +38,7 @@ struct gpio_shared_ref { int dev_id; /* Protects the auxiliary device struct and the lookup table. */ struct mutex lock; + struct lock_class_key lock_key; struct auxiliary_device adev; struct gpiod_lookup_table *lookup; }; @@ -99,7 +100,8 @@ static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode ref->flags = flags; ref->con_id = no_free_ptr(con_id_cpy); ref->fwnode = fwnode; - mutex_init(&ref->lock); + lockdep_register_key(&ref->lock_key); + mutex_init_with_key(&ref->lock, &ref->lock_key); return no_free_ptr(ref); } @@ -378,6 +380,11 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, * arguments match the ones from this consumer's node. */ list_for_each_entry(real_ref, &entry->refs, list) { + if (real_ref == ref) + continue; + + guard(mutex)(&real_ref->lock); + if (!real_ref->fwnode) continue; @@ -568,15 +575,6 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; - /* - * For some reason if we call synchronize_srcu() in GPIO core, - * descent here and take this mutex and then recursively call - * synchronize_srcu() again from gpiochip_remove() (which is - * totally fine) called after gpio_shared_remove_adev(), - * lockdep prints a false positive deadlock splat. Disable - * lockdep here. - */ - lockdep_off(); list_for_each_entry(ref, &entry->refs, list) { guard(mutex)(&ref->lock); @@ -589,7 +587,6 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) gpio_shared_remove_adev(&ref->adev); } - lockdep_on(); } } @@ -685,6 +682,7 @@ static void gpio_shared_drop_ref(struct gpio_shared_ref *ref) { list_del(&ref->list); mutex_destroy(&ref->lock); + lockdep_unregister_key(&ref->lock_key); kfree(ref->con_id); ida_free(&gpio_shared_ida, ref->dev_id); fwnode_handle_put(ref->fwnode); -- cgit v1.2.3 From a80208072df8f4ceb53cd905c1f4362f84ce397f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 6 Jan 2026 10:34:23 +0100 Subject: gpio: shared: don't allocate the lookup table until we really need it We allocate memory for the GPIO lookup table at the top of gpio_shared_add_proxy_lookup() but we don't use it until the very end. Depending on the timing, we may return earlier. Move the allocation towards the end. Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Tested-by: Mark Brown Link: https://lore.kernel.org/r/20260106-gpio-shared-fixes-v2-3-c7091d2f7581@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 4c57b0928760..076d8642675c 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -443,14 +443,10 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, unsigned long lflags) { const char *dev_id = dev_name(consumer); + struct gpiod_lookup_table *lookup; struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; - struct gpiod_lookup_table *lookup __free(kfree) = - kzalloc(struct_size(lookup, table, 2), GFP_KERNEL); - if (!lookup) - return -ENOMEM; - list_for_each_entry(entry, &gpio_shared_list, list) { list_for_each_entry(ref, &entry->refs, list) { guard(mutex)(&ref->lock); @@ -482,6 +478,10 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, if (!key) return -ENOMEM; + lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL); + if (!lookup) + return -ENOMEM; + pr_debug("Adding machine lookup entry for a shared GPIO for consumer %s, with key '%s' and con_id '%s'\n", dev_id, key, ref->con_id ?: "none"); @@ -489,7 +489,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0, ref->con_id, lflags); - ref->lookup = no_free_ptr(lookup); + ref->lookup = lookup; gpiod_add_lookup_table(ref->lookup); return 0; -- cgit v1.2.3 From 8e6ad0dac6266c5e13874e816b016759d7145500 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 4 Nov 2025 12:29:23 +0100 Subject: drm/exynos: hdmi: replace use of system_wq with system_percpu_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. This patch continues the effort to refactor worqueue APIs, which has begun with the change introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") system_wq should be the per-cpu workqueue, yet in this name nothing makes that clear, so replace system_wq with system_percpu_wq. The old wq (system_wq) will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 01813e11e6c6..8e76ac8ee4e2 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1692,7 +1692,7 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) { struct hdmi_context *hdata = arg; - mod_delayed_work(system_wq, &hdata->hotplug_work, + mod_delayed_work(system_percpu_wq, &hdata->hotplug_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); return IRQ_HANDLED; -- cgit v1.2.3 From b7666c891cc7e1a157cd99bca737631c8be07504 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 6 Jan 2026 16:30:54 +0100 Subject: HID: bpf: fix bpf compilation with -fms-extensions Similar to commit 835a50753579 ("selftests/bpf: Add -fms-extensions to bpf build flags") and commit 639f58a0f480 ("bpftool: Fix build warnings due to MS extensions") The kernel is now built with -fms-extensions, therefore generated vmlinux.h contains types like: struct slab { .. struct freelist_counters; }; Use -fms-extensions and -Wno-microsoft-anon-tag flags to build bpf programs that #include "vmlinux.h" Signed-off-by: Benjamin Tissoires --- drivers/hid/bpf/progs/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/bpf/progs/Makefile b/drivers/hid/bpf/progs/Makefile index ec1fc642fd63..66b8f38e591d 100644 --- a/drivers/hid/bpf/progs/Makefile +++ b/drivers/hid/bpf/progs/Makefile @@ -56,8 +56,10 @@ clean: %.bpf.o: %.bpf.c vmlinux.h $(BPFOBJ) | $(OUTPUT) $(call msg,BPF,$@) - $(Q)$(CLANG) -g -O2 --target=bpf -Wall -Werror $(INCLUDES) \ - -c $(filter %.c,$^) -o $@ && \ + $(Q)$(CLANG) -g -O2 --target=bpf -Wall -Werror $(INCLUDES) \ + -Wno-microsoft-anon-tag \ + -fms-extensions \ + -c $(filter %.c,$^) -o $@ && \ $(LLVM_STRIP) -g $@ vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR) -- cgit v1.2.3 From dd76788f9ec4f33f0f43838cac1304265d944328 Mon Sep 17 00:00:00 2001 From: Tim Zimmermann Date: Fri, 28 Nov 2025 08:54:22 +0100 Subject: hid: intel-thc-hid: Select SGL_ALLOC intel-thc-dma.c uses sgl_alloc() resulting in a build failure if CONFIG_SGL_ALLOC is not enabled Signed-off-by: Tim Zimmermann Reviewed-by: Even Xu Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-thc-hid/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/intel-thc-hid/Kconfig b/drivers/hid/intel-thc-hid/Kconfig index 0351d1137607..9d74e53b8c62 100644 --- a/drivers/hid/intel-thc-hid/Kconfig +++ b/drivers/hid/intel-thc-hid/Kconfig @@ -7,6 +7,7 @@ menu "Intel THC HID Support" config INTEL_THC_HID tristate "Intel Touch Host Controller" depends on ACPI + select SGL_ALLOC help THC (Touch Host Controller) is the name of the IP block in PCH that interfaces with Touch Devices (ex: touchscreen, touchpad etc.). It -- cgit v1.2.3 From a9a917998d172ec117f9e9de1919174153c0ace4 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Fri, 26 Dec 2025 11:39:53 +0800 Subject: HID: Intel-thc-hid: Intel-thc: Add safety check for reading DMA buffer Add DMA buffer readiness check before reading DMA buffer to avoid unexpected NULL pointer accessing. Signed-off-by: Even Xu Tested-by: Rui Zhang Signed-off-by: Benjamin Tissoires --- drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c index a0c368aa7979..6ee675e0a738 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c @@ -575,6 +575,11 @@ static int read_dma_buffer(struct thc_device *dev, return -EINVAL; } + if (!read_config->prd_tbls || !read_config->sgls[prd_table_index]) { + dev_err_once(dev->dev, "PRD tables are not ready yet\n"); + return -EINVAL; + } + prd_tbl = &read_config->prd_tbls[prd_table_index]; mes_len = calc_message_len(prd_tbl, &nent); if (mes_len > read_config->max_packet_size) { -- cgit v1.2.3 From c06bc3557542307b9658fbd43cc946a14250347b Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Fri, 2 Jan 2026 06:56:43 +0000 Subject: HID: quirks: Add another Chicony HP 5MP Cameras to hid_ignore_list Another Chicony Electronics HP 5MP Camera with USB ID 04F2:B882 reports a HID sensor interface that is not actually implemented. Add the device to the HID ignore list so the bogus sensor is never exposed to userspace. Then the system won't hang when runtime PM tries to wake the unresponsive device. Signed-off-by: Chris Chiu Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d31711f1aaec..e8a1a86313b7 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -317,6 +317,7 @@ #define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421 #define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA 0xb824 #define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2 0xb82c +#define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA3 0xb882 #define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index c89a015686c0..3cf7971d4974 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -769,6 +769,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA3) }, { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) }, -- cgit v1.2.3 From 2b29a90131bbb3d404e5bf5102af5ce98ccf96fe Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 22 Dec 2025 09:43:34 +1000 Subject: HID: multitouch: set INPUT_PROP_PRESSUREPAD based on Digitizer/Button Type A Digitizer/Button Type value of 1 indicates the device is a pressurepad, see https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchpad-windows-precision-touchpad-collection#device-capabilities-feature-report Signed-off-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-multitouch.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index a0c1ad5acb67..b1c3ef129058 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -81,6 +81,7 @@ MODULE_LICENSE("GPL"); #define MT_INPUTMODE_TOUCHPAD 0x03 #define MT_BUTTONTYPE_CLICKPAD 0 +#define MT_BUTTONTYPE_PRESSUREPAD 1 enum latency_mode { HID_LATENCY_NORMAL = 0, @@ -179,6 +180,7 @@ struct mt_device { __u8 inputmode_value; /* InputMode HID feature value */ __u8 maxcontacts; bool is_buttonpad; /* is this device a button pad? */ + bool is_pressurepad; /* is this device a pressurepad? */ bool is_haptic_touchpad; /* is this device a haptic touchpad? */ bool serial_maybe; /* need to check for serial protocol */ @@ -531,8 +533,14 @@ static void mt_feature_mapping(struct hid_device *hdev, } mt_get_feature(hdev, field->report); - if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) + switch (field->value[usage->usage_index]) { + case MT_BUTTONTYPE_CLICKPAD: td->is_buttonpad = true; + break; + case MT_BUTTONTYPE_PRESSUREPAD: + td->is_pressurepad = true; + break; + } break; case 0xff0000c5: @@ -1394,6 +1402,8 @@ static int mt_touch_input_configured(struct hid_device *hdev, if (td->is_buttonpad) __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + if (td->is_pressurepad) + __set_bit(INPUT_PROP_PRESSUREPAD, input->propbit); app->pending_palm_slots = devm_kcalloc(&hi->input->dev, BITS_TO_LONGS(td->maxcontacts), -- cgit v1.2.3 From 2704024d83fa9eb8e5f16925aae340fd9d246694 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 7 Jan 2026 19:41:43 +0900 Subject: loop: add missing bd_abort_claiming in loop_set_status Commit 08e136ebd193 ("loop: don't change loop device under exclusive opener in loop_set_status") forgot to call bd_abort_claiming() when mutex_lock_killable() failed. Fixes: 08e136ebd193 ("loop: don't change loop device under exclusive opener in loop_set_status") Signed-off-by: Tetsuo Handa Signed-off-by: Jens Axboe --- drivers/block/loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ca74cc31bf07..bd59c0e9508b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1245,7 +1245,8 @@ loop_set_status(struct loop_device *lo, blk_mode_t mode, err = mutex_lock_killable(&lo->lo_mutex); if (err) - return err; + goto out_abort_claiming; + if (lo->lo_state != Lo_bound) { err = -ENXIO; goto out_unlock; @@ -1284,6 +1285,7 @@ out_unfreeze: } out_unlock: mutex_unlock(&lo->lo_mutex); +out_abort_claiming: if (!(mode & BLK_OPEN_EXCL)) bd_abort_claiming(bdev, loop_set_status); out_reread_partitions: -- cgit v1.2.3 From 2497ff38c530b1af0df5130ca9f5ab22c5e92f29 Mon Sep 17 00:00:00 2001 From: Kwok Kin Ming Date: Thu, 1 Jan 2026 02:18:26 +0800 Subject: HID: i2c-hid: fix potential buffer overflow in i2c_hid_get_report() `i2c_hid_xfer` is used to read `recv_len + sizeof(__le16)` bytes of data into `ihid->rawbuf`. The former can come from the userspace in the hidraw driver and is only bounded by HID_MAX_BUFFER_SIZE(16384) by default (unless we also set `max_buffer_size` field of `struct hid_ll_driver` which we do not). The latter has size determined at runtime by the maximum size of different report types you could receive on any particular device and can be a much smaller value. Fix this by truncating `recv_len` to `ihid->bufsize - sizeof(__le16)`. The impact is low since access to hidraw devices requires root. Signed-off-by: Kwok Kin Ming Signed-off-by: Benjamin Tissoires --- drivers/hid/i2c-hid/i2c-hid-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 63f46a2e5788..5a183af3d5c6 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -286,6 +286,7 @@ static int i2c_hid_get_report(struct i2c_hid *ihid, * In addition to report data device will supply data length * in the first 2 bytes of the response, so adjust . */ + recv_len = min(recv_len, ihid->bufsize - sizeof(__le16)); error = i2c_hid_xfer(ihid, ihid->cmdbuf, length, ihid->rawbuf, recv_len + sizeof(__le16)); if (error) { -- cgit v1.2.3 From 0de604d0357d0d22cbf03af1077d174b641707b6 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Thu, 25 Dec 2025 16:43:49 +0800 Subject: drm/amd/pm: Disable MMIO access during SMU Mode 1 reset During Mode 1 reset, the ASIC undergoes a reset cycle and becomes temporarily inaccessible via PCIe. Any attempt to access MMIO registers during this window (e.g., from interrupt handlers or other driver threads) can result in uncompleted PCIe transactions, leading to NMI panics or system hangs. To prevent this, set the `no_hw_access` flag to true immediately after triggering the reset. This signals other driver components to skip register accesses while the device is offline. A memory barrier `smp_mb()` is added to ensure the flag update is globally visible to all cores before the driver enters the sleep/wait state. Signed-off-by: Perry Yuan Reviewed-by: Yifan Zhang Signed-off-by: Alex Deucher (cherry picked from commit 7edb503fe4b6d67f47d8bb0dfafb8e699bb0f8a4) --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 7 ++++++- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 9 +++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 12201b8e99b3..25f49be4d0bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5867,6 +5867,9 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) if (ret) goto mode1_reset_failed; + /* enable mmio access after mode 1 reset completed */ + adev->no_hw_access = false; + amdgpu_device_load_pci_state(adev->pdev); ret = amdgpu_psp_wait_for_bootloader(adev); if (ret) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 677781060246..eaeff6a9bc50 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -2923,8 +2923,13 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu) break; } - if (!ret) + if (!ret) { + /* disable mmio access while doing mode 1 reset*/ + smu->adev->no_hw_access = true; + /* ensure no_hw_access is globally visible before any MMIO */ + smp_mb(); msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS); + } return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 2cea688c604f..33c3cd2e1e24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2143,10 +2143,15 @@ static int smu_v14_0_2_mode1_reset(struct smu_context *smu) ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset); if (!ret) { - if (amdgpu_emu_mode == 1) + if (amdgpu_emu_mode == 1) { msleep(50000); - else + } else { + /* disable mmio access while doing mode 1 reset*/ + smu->adev->no_hw_access = true; + /* ensure no_hw_access is globally visible before any MMIO */ + smp_mb(); msleep(1000); + } } return ret; -- cgit v1.2.3 From eb236fb911ca0f4243124d8a285ec0453a99a8b4 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Mon, 8 Dec 2025 12:11:43 -0700 Subject: drm/amd/display: Check NULL before calling dac_load_detection dac_load_detection can be NULL in some scenario, so checking it before calling. Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Chenyu Chen Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 179176134b535246f0b368b30e8ecad50066f896) --- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 6d31f4967f1a..e1940b8e5bc3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -932,7 +932,7 @@ static bool link_detect_dac_load_detect(struct dc_link *link) struct link_encoder *link_enc = link->link_enc; enum engine_id engine_id = link_enc->preferred_engine; enum dal_device_type device_type = DEVICE_TYPE_CRT; - enum bp_result bp_result; + enum bp_result bp_result = BP_RESULT_UNSUPPORTED; uint32_t enum_id; switch (engine_id) { @@ -946,7 +946,9 @@ static bool link_detect_dac_load_detect(struct dc_link *link) break; } - bp_result = bios->funcs->dac_load_detection(bios, engine_id, device_type, enum_id); + if (bios->funcs->dac_load_detection) + bp_result = bios->funcs->dac_load_detection(bios, engine_id, device_type, enum_id); + return bp_result == BP_RESULT_OK; } -- cgit v1.2.3 From 6b2989ac5e8c496c1814d7961bee6f2d05382b3e Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Sat, 29 Nov 2025 19:46:31 -0600 Subject: Reapply "Revert "drm/amd: Skip power ungate during suspend for VPE"" Skipping power ungate exposed some scenarios that will fail like below: ``` amdgpu: Register(0) [regVPEC_QUEUE_RESET_REQ] failed to reach value 0x00000000 != 0x00000001n amdgpu 0000:c1:00.0: amdgpu: VPE queue reset failed ... amdgpu: [drm] *ERROR* wait_for_completion_timeout timeout! ``` The underlying s2idle issue that prompted this commit is going to be fixed in BIOS. This reverts commit 2a6c826cfeedd7714611ac115371a959ead55bda. This was lost in the 6.19 merge so reapply it. Fixes: 2a6c826cfeed ("drm/amd: Skip power ungate during suspend for VPE") Signed-off-by: Mario Limonciello (AMD) Acked-by: Alex Deucher Reported-by: Konstantin Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220812 Reported-by: Matthew Schwartz Signed-off-by: Alex Deucher (cherry picked from commit 3925683515e93844be204381d2d5a1df5de34f31) --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 25f49be4d0bd..d5c44bd34d45 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3445,11 +3445,10 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev, (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; - /* skip CG for VCE/UVD/VPE, it's handled specially */ + /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && - adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VPE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && adev->ip_blocks[i].version->funcs->set_powergating_state) { /* enable powergating to save power */ -- cgit v1.2.3 From 85a866809333cd2bf8ddac93d9a3e3ba8e4f807d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Lugathe=20da=20Concei=C3=A7=C3=A3o=20Alves?= Date: Thu, 27 Nov 2025 19:03:57 -0300 Subject: HID: Apply quirk HID_QUIRK_ALWAYS_POLL to Edifier QR30 (2d99:a101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The USB speaker has a bug that causes it to reboot when changing the brightness using the physical knob. Add a new vendor and product ID entry in hid-ids.h, and register the corresponding device in hid-quirks.c with the required quirk. Signed-off-by: Rodrigo Lugathe da Conceição Alves Reviewed-by: Terry Junge Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e8a1a86313b7..10cb1bc717c1 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -439,6 +439,9 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002 0xc002 +#define USB_VENDOR_ID_EDIFIER 0x2d99 +#define USB_DEVICE_ID_EDIFIER_QR30 0xa101 /* EDIFIER Hal0 2.0 SE */ + #define USB_VENDOR_ID_ELAN 0x04f3 #define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401 #define USB_DEVICE_ID_HP_X2 0x074d diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 3cf7971d4974..d6e42125d918 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -81,6 +81,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_EDIFIER, USB_DEVICE_ID_EDIFIER_QR30), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II), HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3 From c7fabe4ad9219866c203164a214c474c95b36bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rebe?= Date: Fri, 28 Nov 2025 13:46:41 +0100 Subject: HID: quirks: work around VID/PID conflict for appledisplay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For years I wondered why the Apple Cinema Display driver would not just work for me. Turns out the hidraw driver instantly takes it over. Fix by adding appledisplay VID/PIDs to hid_have_special_driver. Fixes: 069e8a65cd79 ("Driver for Apple Cinema Display") Signed-off-by: René Rebe Signed-off-by: Jiri Kosina --- drivers/hid/hid-quirks.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index d6e42125d918..31b2a5d1cd98 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -233,6 +233,15 @@ static const struct hid_device_id hid_quirks[] = { * used as a driver. See hid_scan_report(). */ static const struct hid_device_id hid_have_special_driver[] = { +#if IS_ENABLED(CONFIG_APPLEDISPLAY) + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9218) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9219) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921c) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x921d) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9222) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9226) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, 0x9236) }, +#endif #if IS_ENABLED(CONFIG_HID_A4TECH) { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, -- cgit v1.2.3 From 12adb969658ec39265eb8c7ea9e1856867fb9ceb Mon Sep 17 00:00:00 2001 From: Arnoud Willemsen Date: Sun, 7 Dec 2025 03:43:19 +0100 Subject: HID: Elecom: Add support for ELECOM M-XT3DRBK (018C) Wireless/new version of the Elecom trackball mouse M-XT3DRBK has a product id that differs from the existing M-XT3DRBK. The report descriptor format also seems to have changed and matches other (newer?) models instead (except for six buttons instead of eight). This patch follows the same format as the patch for the M-XT3URBK (018F) by Naoki Ueki (Nov 3rd 2025) to enable the sixth mouse button. dmesg output: [ 292.074664] usb 1-2: new full-speed USB device number 7 using xhci_hcd [ 292.218667] usb 1-2: New USB device found, idVendor=056e, idProduct=018c, bcdDevice= 1.00 [ 292.218676] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 292.218679] usb 1-2: Product: ELECOM TrackBall Mouse [ 292.218681] usb 1-2: Manufacturer: ELECOM usbhid-dump output: 001:006:000:DESCRIPTOR 1765072638.050578 05 01 09 02 A1 01 09 01 A1 00 85 01 05 09 19 01 29 05 15 00 25 01 95 08 75 01 81 02 95 01 75 00 81 01 05 01 09 30 09 31 16 00 80 26 FF 7F 75 10 95 02 81 06 C0 A1 00 05 01 09 38 15 81 25 7F 75 08 95 01 81 06 C0 A1 00 05 0C 0A 38 02 95 01 75 08 15 81 25 7F 81 06 C0 C0 06 01 FF 09 00 A1 01 85 02 09 00 15 00 26 FF 00 75 08 95 07 81 02 C0 05 0C 09 01 A1 01 85 05 15 00 26 3C 02 19 00 2A 3C 02 75 10 95 01 81 00 C0 05 01 09 80 A1 01 85 03 19 81 29 83 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 01 C0 06 BC FF 09 88 A1 01 85 04 95 01 75 08 15 00 26 FF 00 19 00 2A FF 00 81 00 C0 06 02 FF 09 02 A1 01 85 06 09 02 15 00 26 FF 00 75 08 95 07 B1 02 C0 Signed-off-by: Arnoud Willemsen Signed-off-by: Jiri Kosina --- drivers/hid/hid-elecom.c | 15 +++++++++++++-- drivers/hid/hid-ids.h | 3 ++- drivers/hid/hid-quirks.c | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 981d1b6e9658..2003d2dcda7c 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -77,7 +77,7 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, break; case USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB: case USB_DEVICE_ID_ELECOM_M_XT3URBK_018F: - case USB_DEVICE_ID_ELECOM_M_XT3DRBK: + case USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC: case USB_DEVICE_ID_ELECOM_M_XT4DRBK: /* * Report descriptor format: @@ -102,6 +102,16 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, */ mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); break; + case USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C: + /* + * Report descriptor format: + * 22: button bit count + * 30: padding bit count + * 24: button report size + * 16: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 6); + break; case USB_DEVICE_ID_ELECOM_M_DT2DRBK: case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C: /* @@ -122,7 +132,8 @@ static const struct hid_device_id elecom_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 10cb1bc717c1..9c2bf584d9f6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -455,7 +455,8 @@ #define USB_DEVICE_ID_ELECOM_M_XGL20DLBK 0x00e6 #define USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB 0x00fb #define USB_DEVICE_ID_ELECOM_M_XT3URBK_018F 0x018f -#define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc +#define USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC 0x00fc +#define USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C 0x018c #define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd #define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe #define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 31b2a5d1cd98..11438039cdb7 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -422,7 +422,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, -- cgit v1.2.3 From 6abcf751bc084804a9e5b3051442e8a2ce67f48a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 5 Jan 2026 09:43:31 +0100 Subject: net: airoha: Fix schedule while atomic in airoha_ppe_deinit() airoha_ppe_deinit() runs airoha_npu_ppe_deinit() in atomic context. airoha_npu_ppe_deinit routine allocates ppe_data buffer with GFP_KERNEL flag. Rely on rcu_replace_pointer in airoha_ppe_deinit routine in order to fix schedule while atomic issue in airoha_npu_ppe_deinit() since we do not need atomic context there. Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20260105-airoha-fw-ethtool-v2-1-3b32b158cc31@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/airoha/airoha_ppe.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 0caabb0c3aa0..2221bafaf7c9 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -1547,13 +1547,16 @@ void airoha_ppe_deinit(struct airoha_eth *eth) { struct airoha_npu *npu; - rcu_read_lock(); - npu = rcu_dereference(eth->npu); + mutex_lock(&flow_offload_mutex); + + npu = rcu_replace_pointer(eth->npu, NULL, + lockdep_is_held(&flow_offload_mutex)); if (npu) { npu->ops.ppe_deinit(npu); airoha_npu_put(npu); } - rcu_read_unlock(); + + mutex_unlock(&flow_offload_mutex); rhashtable_destroy(ð->ppe->l2_flows); rhashtable_destroy(ð->flow_table); -- cgit v1.2.3 From d7f6629bffdcb962d383ef8c9a30afef81e997fe Mon Sep 17 00:00:00 2001 From: Dennis Marttinen Date: Sun, 4 Jan 2026 13:00:51 +0000 Subject: HID: logitech: add HID++ support for Logitech MX Anywhere 3S I've acquired a Logitech MX Anywhere 3S mouse, which supports HID++ over Bluetooth. Adding its PID 0xb037 to the allowlist enables the additional features, such as high-resolution scrolling. Tested working across multiple machines, with a mix of Intel and Mediatek Bluetooth chips. [jkosina@suse.com: standardize shortlog] Signed-off-by: Dennis Marttinen Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index d5011a5d0890..e871f1729d4b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4662,6 +4662,8 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb025) }, { /* MX Master 3S mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, + { /* MX Anywhere 3S mouse over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb037) }, { /* MX Anywhere 3SB mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, {} -- cgit v1.2.3 From 333418872bfecf4843f1ded7a4151685dfcf07d5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 7 Jan 2026 14:36:51 +0100 Subject: wifi: mac80211_hwsim: fix typo in frequency notification The NAN notification is for 5745 MHz which corresponds to channel 149 and not 5475 which is not actually a valid channel. This could result in a NULL pointer dereference in cfg80211_next_nan_dw_notif. Fixes: a37a6f54439b ("wifi: mac80211_hwsim: Add simulation support for NAN device") Signed-off-by: Benjamin Berg Reviewed-by: Ilan Peer Reviewed-by: Miriam Rachel Korenblit Link: https://patch.msgid.link/20260107143652.7dab2035836f.Iacbaf7bb94ed5c14a0928a625827e4137d8bfede@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 551f5eb4e747..92427f527286 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4040,7 +4040,7 @@ mac80211_hwsim_nan_dw_start(struct hrtimer *timer) ieee80211_vif_to_wdev(data->nan_device_vif); if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) - ch = ieee80211_get_channel(hw->wiphy, 5475); + ch = ieee80211_get_channel(hw->wiphy, 5745); else ch = ieee80211_get_channel(hw->wiphy, 2437); -- cgit v1.2.3 From 6f385937160174b31a5e4105e759406f0b128494 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 7 Jan 2026 14:38:05 +0100 Subject: wifi: mac80211_hwsim: disable BHs for hwsim_radio_lock The hwsim_radio_lock spinlock expects bottom-half to be disabled, fix the call in mac80211_hwsim_nan_stop to ensure BHs are disabled. Signed-off-by: Benjamin Berg Link: https://patch.msgid.link/20260107143805.ce7406511608.I688f8b19346e94c1f8de0cdadde072054d4b861c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 92427f527286..79cc63272134 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4112,14 +4112,14 @@ static int mac80211_hwsim_stop_nan(struct ieee80211_hw *hw, hrtimer_cancel(&data->nan_timer); data->nan_device_vif = NULL; - spin_lock(&hwsim_radio_lock); + spin_lock_bh(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { if (data2->nan_device_vif) { nan_cluster_running = true; break; } } - spin_unlock(&hwsim_radio_lock); + spin_unlock_bh(&hwsim_radio_lock); if (!nan_cluster_running) memset(hwsim_nan_cluster_id, 0, ETH_ALEN); -- cgit v1.2.3 From 36f597bba049928004a050c132ab787ba0eba524 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 8 Jan 2026 11:23:14 +0100 Subject: gpiolib: fix lookup table matching If on any iteration in gpiod_find(), gpio_desc_table_match() returns NULL (which is normal and expected), we never reinitialize desc back to ERR_PTR(-ENOENT) and if we don't find a match later on, we will return NULL causing a NULL-pointer dereference in users not expecting it. Don't initialize desc, but return ERR_PTR(-ENOENT) explicitly at the end of the function. Fixes: 9700b0fccf38 ("gpiolib: allow multiple lookup tables per consumer") Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/00107523-7737-4b92-a785-14ce4e93b8cb@samsung.com/ Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20260108102314.18816-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c06152b16dbc..dcf427d3cf43 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4602,8 +4602,8 @@ static struct gpio_desc *gpio_desc_table_match(struct device *dev, const char *c static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, unsigned int idx, unsigned long *flags) { - struct gpio_desc *desc = ERR_PTR(-ENOENT); struct gpiod_lookup_table *table; + struct gpio_desc *desc; guard(mutex)(&gpio_lookup_lock); @@ -4619,7 +4619,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } - return desc; + return ERR_PTR(-ENOENT); } static int platform_gpio_count(struct device *dev, const char *con_id) -- cgit v1.2.3 From a4e305ed60f7c41bbf9aabc16dd75267194e0de3 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 6 Jan 2026 10:47:21 +0100 Subject: net: 3com: 3c59x: fix possible null dereference in vortex_probe1() pdev can be null and free_ring: can be called in 1297 with a null pdev. Fixes: 55c82617c3e8 ("3c59x: convert to generic DMA API") Cc: Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20260106094731.25819-2-fourier.thomas@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/3com/3c59x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 8c9cc97efd4e..4fe4efdb3737 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1473,7 +1473,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, return 0; free_ring: - dma_free_coherent(&pdev->dev, + dma_free_coherent(gendev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, vp->rx_ring, vp->rx_ring_dma); -- cgit v1.2.3 From afa27621a28af317523e0836dad430bec551eb54 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Tue, 6 Jan 2026 10:48:21 +0200 Subject: net: usb: pegasus: fix memory leak in update_eth_regs_async() When asynchronously writing to the device registers and if usb_submit_urb() fail, the code fail to release allocated to this point resources. Fixes: 323b34963d11 ("drivers: net: usb: pegasus: fix control urb submission") Signed-off-by: Petko Manolov Link: https://patch.msgid.link/20260106084821.3746677-1-petko.manolov@konsulko.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/pegasus.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 81ca64debc5b..c514483134f0 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -168,6 +168,8 @@ static int update_eth_regs_async(pegasus_t *pegasus) netif_device_detach(pegasus->net); netif_err(pegasus, drv, pegasus->net, "%s returned %d\n", __func__, ret); + usb_free_urb(async_urb); + kfree(req); } return ret; } -- cgit v1.2.3 From 3358995b1a7f9dcb52a56ec8251570d71024dad0 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 6 Jan 2026 06:31:14 -0800 Subject: bnxt_en: Fix NULL pointer crash in bnxt_ptp_enable during error cleanup When bnxt_init_one() fails during initialization (e.g., bnxt_init_int_mode returns -ENODEV), the error path calls bnxt_free_hwrm_resources() which destroys the DMA pool and sets bp->hwrm_dma_pool to NULL. Subsequently, bnxt_ptp_clear() is called, which invokes ptp_clock_unregister(). Since commit a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events"), ptp_clock_unregister() now calls ptp_disable_all_events(), which in turn invokes the driver's .enable() callback (bnxt_ptp_enable()) to disable PTP events before completing the unregistration. bnxt_ptp_enable() attempts to send HWRM commands via bnxt_ptp_cfg_pin() and bnxt_ptp_cfg_event(), both of which call hwrm_req_init(). This function tries to allocate from bp->hwrm_dma_pool, causing a NULL pointer dereference: bnxt_en 0000:01:00.0 (unnamed net_device) (uninitialized): bnxt_init_int_mode err: ffffffed KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f] Call Trace: __hwrm_req_init (drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c:72) bnxt_ptp_enable (drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:323 drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:517) ptp_disable_all_events (drivers/ptp/ptp_chardev.c:66) ptp_clock_unregister (drivers/ptp/ptp_clock.c:518) bnxt_ptp_clear (drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c:1134) bnxt_init_one (drivers/net/ethernet/broadcom/bnxt/bnxt.c:16889) Lines are against commit f8f9c1f4d0c7 ("Linux 6.19-rc3") Fix this by clearing and unregistering ptp (bnxt_ptp_clear()) before freeing HWRM resources. Suggested-by: Pavan Chebbi Signed-off-by: Breno Leitao Fixes: a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events") Cc: stable@vger.kernel.org Reviewed-by: Pavan Chebbi Link: https://patch.msgid.link/20260106-bnxt-v3-1-71f37e11446a@debian.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d160e54ac121..8419d1eb4035 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -16891,12 +16891,12 @@ init_err_dl: init_err_pci_clean: bnxt_hwrm_func_drv_unrgtr(bp); - bnxt_free_hwrm_resources(bp); - bnxt_hwmon_uninit(bp); - bnxt_ethtool_free(bp); bnxt_ptp_clear(bp); kfree(bp->ptp_cfg); bp->ptp_cfg = NULL; + bnxt_free_hwrm_resources(bp); + bnxt_hwmon_uninit(bp); + bnxt_ethtool_free(bp); kfree(bp->fw_health); bp->fw_health = NULL; bnxt_cleanup_pci(bp); -- cgit v1.2.3 From 4d984b0574ff708e66152763fbfdef24ea40933f Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 7 Jan 2026 10:01:36 +0100 Subject: atm: Fix dma_free_coherent() size The size of the buffer is not the same when alloc'd with dma_alloc_coherent() in he_init_tpdrq() and freed. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20260107090141.80900-2-fourier.thomas@gmail.com Signed-off-by: Jakub Kicinski --- drivers/atm/he.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/atm/he.c b/drivers/atm/he.c index ad91cc6a34fc..92a041d5387b 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1587,7 +1587,8 @@ he_stop(struct he_dev *he_dev) he_dev->tbrq_base, he_dev->tbrq_phys); if (he_dev->tpdrq_base) - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + dma_free_coherent(&he_dev->pci_dev->dev, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), he_dev->tpdrq_base, he_dev->tpdrq_phys); dma_pool_destroy(he_dev->tpd_pool); -- cgit v1.2.3 From 4b5bdabb5449b652122e43f507f73789041d4abe Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Wed, 7 Jan 2026 17:12:04 +0800 Subject: net: enetc: fix build warning when PAGE_SIZE is greater than 128K The max buffer size of ENETC RX BD is 0xFFFF bytes, so if the PAGE_SIZE is greater than 128K, ENETC_RXB_DMA_SIZE and ENETC_RXB_DMA_SIZE_XDP will be greater than 0xFFFF, thus causing a build warning. This will not cause any practical issues because ENETC is currently only used on the ARM64 platform, and the max PAGE_SIZE is 64K. So this patch is only for fixing the build warning that occurs when compiling ENETC drivers for other platforms. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202601050637.kHEKKOG7-lkp@intel.com/ Fixes: e59bc32df2e9 ("net: enetc: correct the value of ENETC_RXB_TRUESIZE") Signed-off-by: Wei Fang Reviewed-by: Frank Li Link: https://patch.msgid.link/20260107091204.1980222-1-wei.fang@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/enetc/enetc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index dce27bd67a7d..aecd40aeef9c 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -79,9 +79,9 @@ struct enetc_lso_t { #define ENETC_RXB_TRUESIZE (PAGE_SIZE >> 1) #define ENETC_RXB_PAD NET_SKB_PAD /* add extra space if needed */ #define ENETC_RXB_DMA_SIZE \ - (SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - ENETC_RXB_PAD) + min(SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - ENETC_RXB_PAD, 0xffff) #define ENETC_RXB_DMA_SIZE_XDP \ - (SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - XDP_PACKET_HEADROOM) + min(SKB_WITH_OVERHEAD(ENETC_RXB_TRUESIZE) - XDP_PACKET_HEADROOM, 0xffff) struct enetc_rx_swbd { dma_addr_t dma; -- cgit v1.2.3 From c2803bd580db226008aabf2fb2f0c9a7d3b5d0de Mon Sep 17 00:00:00 2001 From: Ben Horgan Date: Fri, 19 Dec 2025 18:11:03 +0000 Subject: arm_mpam: Stop using uninitialized variables in __ris_msmon_read() Dan has reported two uses of uninitialized variables in __ris_msmon_read(). If an unknown monitor type is encountered then the local variable, now, is used uninitialized. Fix this by returning early on error. If a non-mbwu monitor is being read then the local variable, overflow, is not initialized but still read. Initialize it to false as overflow is not relevant for csu monitors. Fixes: 823e7c3712c5 ("arm_mpam: Add mpam_msmon_read() to read monitor value") Fixes: 9e5afb7c3283 ("arm_mpam: Use long MBWU counters if supported") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202512091519.RBwiJcSq-lkp@intel.com/ Closes: https://lore.kernel.org/r/202512100547.N7QPYgfb-lkp@intel.com/ Signed-off-by: Ben Horgan Reviewed-by: Jonathan Cameron Signed-off-by: Catalin Marinas --- drivers/resctrl/mpam_devices.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c index 0b5b158e1aaf..b495d5291868 100644 --- a/drivers/resctrl/mpam_devices.c +++ b/drivers/resctrl/mpam_devices.c @@ -1072,7 +1072,7 @@ static void __ris_msmon_read(void *arg) u64 now; bool nrdy = false; bool config_mismatch; - bool overflow; + bool overflow = false; struct mon_read *m = arg; struct mon_cfg *ctx = m->ctx; bool reset_on_next_read = false; @@ -1176,10 +1176,11 @@ static void __ris_msmon_read(void *arg) } mpam_mon_sel_unlock(msc); - if (nrdy) { + if (nrdy) m->err = -EBUSY; + + if (m->err) return; - } *m->val += now; } -- cgit v1.2.3 From d578b31856cec31315f27b3ba97b212e4c6989b3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 8 Jan 2026 14:39:19 +0100 Subject: gpio: shared: fix a false-positive sharing detection with reset-gpios After scanning the devicetree, we remove all entries that have only one reference, while creating GPIO shared proxies for the remaining, shared entries. However: for the reset-gpio corner-case, we will have two references for a "reset-gpios" pin that's not really shared. In this case one will come from the actual consumer fwnode and the other from the potential auxiliary reset-gpio device. This causes the GPIO core to create unnecessary GPIO shared proxy devices for pins that are not really shared. Add a function that can detect this situation and remove entries that have exactly two references but one of them is a reset-gpio. Fixes: 7b78b26757e0 ("gpio: shared: handle the reset-gpios corner case") Link: https://lore.kernel.org/r/20260108-gpio-shared-false-positive-v1-1-5dbf8d1b2f7d@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 076d8642675c..17343fdc9758 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -41,6 +41,7 @@ struct gpio_shared_ref { struct lock_class_key lock_key; struct auxiliary_device adev; struct gpiod_lookup_table *lookup; + bool is_reset_gpio; }; /* Represents a single GPIO pin. */ @@ -112,7 +113,8 @@ static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry, struct gpio_shared_ref *ref; list_for_each_entry(ref, &entry->refs, list) { - if (!ref->fwnode && ref->con_id && strcmp(ref->con_id, "reset") == 0) + if (ref->is_reset_gpio) + /* Already set-up. */ return 0; } @@ -120,6 +122,8 @@ static int gpio_shared_setup_reset_proxy(struct gpio_shared_entry *entry, if (!ref) return -ENOMEM; + ref->is_reset_gpio = true; + list_add_tail(&ref->list, &entry->refs); pr_debug("Created a secondary shared GPIO reference for potential reset-gpio device for GPIO %u at %s\n", @@ -714,12 +718,38 @@ static void __init gpio_shared_teardown(void) } } +static bool gpio_shared_entry_is_really_shared(struct gpio_shared_entry *entry) +{ + size_t num_nodes = list_count_nodes(&entry->refs); + struct gpio_shared_ref *ref; + + if (num_nodes <= 1) + return false; + + if (num_nodes > 2) + return true; + + /* Exactly two references: */ + list_for_each_entry(ref, &entry->refs, list) { + /* + * Corner-case: the second reference comes from the potential + * reset-gpio instance. However, this pin is not really shared + * as it would have three references in this case. Avoid + * creating unnecessary proxies. + */ + if (ref->is_reset_gpio) + return false; + } + + return true; +} + static void gpio_shared_free_exclusive(void) { struct gpio_shared_entry *entry, *epos; list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) { - if (list_count_nodes(&entry->refs) > 1) + if (gpio_shared_entry_is_really_shared(entry)) continue; gpio_shared_drop_ref(list_first_entry(&entry->refs, -- cgit v1.2.3 From f0d385f6689f37a2828c686fb279121df006b4cb Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 9 Jan 2026 20:14:54 +0800 Subject: ublk: fix use-after-free in ublk_partition_scan_work A race condition exists between the async partition scan work and device teardown that can lead to a use-after-free of ub->ub_disk: 1. ublk_ctrl_start_dev() schedules partition_scan_work after add_disk() 2. ublk_stop_dev() calls ublk_stop_dev_unlocked() which does: - del_gendisk(ub->ub_disk) - ublk_detach_disk() sets ub->ub_disk = NULL - put_disk() which may free the disk 3. The worker ublk_partition_scan_work() then dereferences ub->ub_disk leading to UAF Fix this by using ublk_get_disk()/ublk_put_disk() in the worker to hold a reference to the disk during the partition scan. The spinlock in ublk_get_disk() synchronizes with ublk_detach_disk() ensuring the worker either gets a valid reference or sees NULL and exits early. Also change flush_work() to cancel_work_sync() to avoid running the partition scan work unnecessarily when the disk is already detached. Fixes: 7fc4da6a304b ("ublk: scan partition in async way") Reported-by: Ruikai Peng Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- drivers/block/ublk_drv.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 837fedb02e0d..f6e5a0766721 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -255,20 +255,6 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub, u16 q_id, u16 tag, struct ublk_io *io, size_t offset); static inline unsigned int ublk_req_build_flags(struct request *req); -static void ublk_partition_scan_work(struct work_struct *work) -{ - struct ublk_device *ub = - container_of(work, struct ublk_device, partition_scan_work); - - if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, - &ub->ub_disk->state))) - return; - - mutex_lock(&ub->ub_disk->open_mutex); - bdev_disk_changed(ub->ub_disk, false); - mutex_unlock(&ub->ub_disk->open_mutex); -} - static inline struct ublksrv_io_desc * ublk_get_iod(const struct ublk_queue *ubq, unsigned tag) { @@ -1597,6 +1583,27 @@ static void ublk_put_disk(struct gendisk *disk) put_device(disk_to_dev(disk)); } +static void ublk_partition_scan_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, partition_scan_work); + /* Hold disk reference to prevent UAF during concurrent teardown */ + struct gendisk *disk = ublk_get_disk(ub); + + if (!disk) + return; + + if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, + &disk->state))) + goto out; + + mutex_lock(&disk->open_mutex); + bdev_disk_changed(disk, false); + mutex_unlock(&disk->open_mutex); +out: + ublk_put_disk(disk); +} + /* * Use this function to ensure that ->canceling is consistently set for * the device and all queues. Do not set these flags directly. @@ -2041,7 +2048,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); ublk_stop_dev_unlocked(ub); mutex_unlock(&ub->mutex); - flush_work(&ub->partition_scan_work); + cancel_work_sync(&ub->partition_scan_work); ublk_cancel_dev(ub); } -- cgit v1.2.3 From 1690eeb0cb2bb77096cb6c826b6849ef05013e34 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 22 Dec 2025 11:22:50 +0100 Subject: irqchip/gic-v5: Fix gicv5_its_map_event() ITTE read endianness Kbuild bot (through sparse) reported that the ITTE read to carry out a valid check in gicv5_its_map_event() lacks proper endianness handling. Add the missing endianess conversion. Fixes: 57d72196dfc8 ("irqchip/gic-v5: Add GICv5 ITS support") Reported-by: kernel test robot Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Acked-by: Marc Zyngier Link: https://patch.msgid.link/20251222102250.435460-1-lpieralisi@kernel.org Closes: https://lore.kernel.org/oe-kbuild-all/202512131849.30ZRTBeR-lkp@intel.com/ --- drivers/irqchip/irq-gic-v5-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v5-its.c b/drivers/irqchip/irq-gic-v5-its.c index 554485f0be1f..8e22134b9f48 100644 --- a/drivers/irqchip/irq-gic-v5-its.c +++ b/drivers/irqchip/irq-gic-v5-its.c @@ -849,7 +849,7 @@ static int gicv5_its_map_event(struct gicv5_its_dev *its_dev, u16 event_id, u32 itte = gicv5_its_device_get_itte_ref(its_dev, event_id); - if (FIELD_GET(GICV5_ITTL2E_VALID, *itte)) + if (FIELD_GET(GICV5_ITTL2E_VALID, le64_to_cpu(*itte))) return -EEXIST; itt_entry = FIELD_PREP(GICV5_ITTL2E_LPI_ID, lpi) | -- cgit v1.2.3 From a33d16dc874a9512c02b1f1a3e08c26a82b4be5e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 23 Dec 2025 20:05:44 +0530 Subject: Revert "irqchip/riscv-imsic: Embed the vector array in lpriv" The __alloc_percpu() fails when the number of IDs are greater than 959 because size parameter of __alloc_percpu() must be less than 32768 (aka PCPU_MIN_UNIT_SIZE). This failure is observed with KVMTOOL when AIA is trap-n-emulated by in-kernel KVM because in this case KVM guest has 2047 interrupt IDs. To address this issue, don't embed vector array in struct imsic_local_priv until __alloc_percpu() support size parameter greater than 32768. This reverts commit 79eaabc61dfb ("irqchip/riscv-imsic: Embed the vector array in lpriv"). Signed-off-by: Anup Patel Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251223143544.1504217-1-anup.patel@oss.qualcomm.com --- drivers/irqchip/irq-riscv-imsic-state.c | 10 ++++++++-- drivers/irqchip/irq-riscv-imsic-state.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index 385368052d5c..b6cebfee9461 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -477,6 +477,7 @@ static void __init imsic_local_cleanup(void) lpriv = per_cpu_ptr(imsic->lpriv, cpu); bitmap_free(lpriv->dirty_bitmap); + kfree(lpriv->vectors); } free_percpu(imsic->lpriv); @@ -490,8 +491,7 @@ static int __init imsic_local_init(void) int cpu, i; /* Allocate per-CPU private state */ - imsic->lpriv = __alloc_percpu(struct_size(imsic->lpriv, vectors, global->nr_ids + 1), - __alignof__(*imsic->lpriv)); + imsic->lpriv = alloc_percpu(typeof(*imsic->lpriv)); if (!imsic->lpriv) return -ENOMEM; @@ -511,6 +511,12 @@ static int __init imsic_local_init(void) timer_setup(&lpriv->timer, imsic_local_timer_callback, TIMER_PINNED); #endif + /* Allocate vector array */ + lpriv->vectors = kcalloc(global->nr_ids + 1, sizeof(*lpriv->vectors), + GFP_KERNEL); + if (!lpriv->vectors) + goto fail_local_cleanup; + /* Setup vector array */ for (i = 0; i <= global->nr_ids; i++) { vec = &lpriv->vectors[i]; diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 6332501dcbd8..c42ee180b305 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -40,7 +40,7 @@ struct imsic_local_priv { #endif /* Local vector table */ - struct imsic_vector vectors[]; + struct imsic_vector *vectors; }; struct imsic_priv { -- cgit v1.2.3 From cefd81e76a8c0dc4aa2bacd884acca44e7b61e5b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 6 Jan 2026 15:22:10 -0400 Subject: iommupt: Fix the kunit building The kunit doesn't work since the below commit made GENERIC_PT unselectable: $ make ARCH=x86_64 O=build_kunit_x86_64 olddefconfig ERROR:root:Not all Kconfig options selected in kunitconfig were in the generated .config. This is probably due to unsatisfied dependencies. Missing: CONFIG_DEBUG_GENERIC_PT=y, CONFIG_IOMMUFD_TEST=y, CONFIG_IOMMU_PT_X86_64=y, CONFIG_GENERIC_PT=y, CONFIG_IOMMU_PT_AMDV1=y, CONFIG_IOMMU_PT_VTDSS=y, CONFIG_IOMMU_PT=y, CONFIG_IOMMU_PT_KUNIT_TEST=y Also remove the unneeded CONFIG_IOMMUFD_TEST reference as the iommupt kunit doesn't interact with iommufd, and it doesn't currently build for the kunit due problems with DMA_SHARED buffer either. Fixes: 01569c216dde ("genpt: Make GENERIC_PT invisible") Fixes: 1dd4187f53c3 ("iommupt: Add a kunit test for Generic Page Table") Signed-off-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Joerg Roedel --- drivers/iommu/generic_pt/.kunitconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/generic_pt/.kunitconfig b/drivers/iommu/generic_pt/.kunitconfig index 52ac9e661ffd..a78b295f264d 100644 --- a/drivers/iommu/generic_pt/.kunitconfig +++ b/drivers/iommu/generic_pt/.kunitconfig @@ -1,4 +1,5 @@ CONFIG_KUNIT=y +CONFIG_COMPILE_TEST=y CONFIG_GENERIC_PT=y CONFIG_DEBUG_GENERIC_PT=y CONFIG_IOMMU_PT=y @@ -11,4 +12,3 @@ CONFIG_IOMMUFD=y CONFIG_DEBUG_KERNEL=y CONFIG_FAULT_INJECTION=y CONFIG_RUNTIME_TESTING_MENU=y -CONFIG_IOMMUFD_TEST=y -- cgit v1.2.3 From faa37ff3bf18d5242fe3d54f5462b1c3254c2567 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 6 Jan 2026 15:22:11 -0400 Subject: iommufd/selftest: Add missing kconfig for DMA_SHARED_BUFFER The test doesn't build without it, dma-buf.h does not provide stub functions if it is not enabled. Compilation can fail with: ERROR:root:ld: vmlinux.o: in function `iommufd_test': (.text+0x3b1cdd): undefined reference to `dma_buf_get' ld: (.text+0x3b1d08): undefined reference to `dma_buf_put' ld: (.text+0x3b2105): undefined reference to `dma_buf_export' ld: (.text+0x3b211f): undefined reference to `dma_buf_fd' ld: (.text+0x3b2e47): undefined reference to `dma_buf_move_notify' Add the missing select. Fixes: d2041f1f11dd ("iommufd/selftest: Add some tests for the dmabuf flow") Signed-off-by: Jason Gunthorpe Signed-off-by: Joerg Roedel --- drivers/iommu/iommufd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iommu/iommufd/Kconfig b/drivers/iommu/iommufd/Kconfig index eae3f03629b0..7e41e3ccea75 100644 --- a/drivers/iommu/iommufd/Kconfig +++ b/drivers/iommu/iommufd/Kconfig @@ -42,6 +42,7 @@ config IOMMUFD_TEST depends on FAULT_INJECTION depends on RUNTIME_TESTING_MENU depends on IOMMU_PT_AMDV1 + select DMA_SHARED_BUFFER select IOMMUFD_DRIVER default n help -- cgit v1.2.3 From 7adfd682745a41fdf0279e4457d11fffab145a8f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 6 Jan 2026 15:22:12 -0400 Subject: iommufd/selftest: Prevent module/builtin conflicts in kconfig The selftest now depends on the AMDv1 page table, however the selftest kconfig itself is just an sub-option of the main IOMMUFD module kconfig. This means it cannot be modular and so kconfig allowed a modular IOMMU_PT_AMDV1 with a built in IOMMUFD. This causes link failures: ld: vmlinux.o: in function `mock_domain_alloc_pgtable.isra.0': selftest.c:(.text+0x12e8ad3): undefined reference to `pt_iommu_amdv1_init' ld: vmlinux.o: in function `BSWAP_SHUFB_CTL': sha1-avx2-asm.o:(.rodata+0xaa36a8): undefined reference to `pt_iommu_amdv1_read_and_clear_dirty' ld: sha1-avx2-asm.o:(.rodata+0xaa36f0): undefined reference to `pt_iommu_amdv1_map_pages' ld: sha1-avx2-asm.o:(.rodata+0xaa36f8): undefined reference to `pt_iommu_amdv1_unmap_pages' ld: sha1-avx2-asm.o:(.rodata+0xaa3720): undefined reference to `pt_iommu_amdv1_iova_to_phys' Adjust the kconfig to disable IOMMUFD_TEST if IOMMU_PT_AMDV1 is incompatible. Fixes: e93d5945ed5b ("iommufd: Change the selftest to use iommupt instead of xarray") Suggested-by: Arnd Bergmann Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512210135.freQWpxa-lkp@intel.com/ Signed-off-by: Jason Gunthorpe Signed-off-by: Joerg Roedel --- drivers/iommu/iommufd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/iommufd/Kconfig b/drivers/iommu/iommufd/Kconfig index 7e41e3ccea75..455bac0351f2 100644 --- a/drivers/iommu/iommufd/Kconfig +++ b/drivers/iommu/iommufd/Kconfig @@ -41,7 +41,7 @@ config IOMMUFD_TEST depends on DEBUG_KERNEL depends on FAULT_INJECTION depends on RUNTIME_TESTING_MENU - depends on IOMMU_PT_AMDV1 + depends on IOMMU_PT_AMDV1=y || IOMMUFD=IOMMU_PT_AMDV1 select DMA_SHARED_BUFFER select IOMMUFD_DRIVER default n -- cgit v1.2.3 From 6a3d5fda2ce464a80a9af9e358dfbab6a989ab5d Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 9 Jan 2026 10:29:52 -0400 Subject: iommupt: Make pt_feature() always_inline gcc 8.5 on powerpc does not automatically inline these functions even though they evaluate to constants in key cases. Since the constant propagation is essential for some code elimination and built-time checks this causes a build failure: ERROR: modpost: "__pt_no_sw_bit" [drivers/iommu/generic_pt/fmt/iommu_amdv1.ko] undefined! Caused by this: if (pts_feature(&pts, PT_FEAT_DMA_INCOHERENT) && !pt_test_sw_bit_acquire(&pts, SW_BIT_CACHE_FLUSH_DONE)) flush_writes_item(&pts); Where pts_feature() evaluates to a constant false. Mark them as __always_inline to force it to evaluate to a constant and trigger the code elimination. Fixes: 7c5b184db714 ("genpt: Generic Page Table base API") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512230720.9y9DtWIo-lkp@intel.com/ Signed-off-by: Jason Gunthorpe --- drivers/iommu/generic_pt/pt_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/generic_pt/pt_defs.h b/drivers/iommu/generic_pt/pt_defs.h index c25544d72f97..707b3b0282fa 100644 --- a/drivers/iommu/generic_pt/pt_defs.h +++ b/drivers/iommu/generic_pt/pt_defs.h @@ -202,7 +202,7 @@ static inline bool pt_table_install32(struct pt_state *pts, u32 table_entry) #define PT_SUPPORTED_FEATURE(feature_nr) (PT_SUPPORTED_FEATURES & BIT(feature_nr)) -static inline bool pt_feature(const struct pt_common *common, +static __always_inline bool pt_feature(const struct pt_common *common, unsigned int feature_nr) { if (PT_FORCE_ENABLED_FEATURES & BIT(feature_nr)) @@ -212,7 +212,7 @@ static inline bool pt_feature(const struct pt_common *common, return common->features & BIT(feature_nr); } -static inline bool pts_feature(const struct pt_state *pts, +static __always_inline bool pts_feature(const struct pt_state *pts, unsigned int feature_nr) { return pt_feature(pts->range->common, feature_nr); -- cgit v1.2.3 From 2e4b28c48f88ce9e263957b1d944cf5349952f88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 11 Jan 2026 16:53:48 +0100 Subject: treewide: Update email address In a vain attempt to consolidate the email zoo switch everything to the kernel.org account. Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- drivers/mtd/nand/ecc-sw-hamming.c | 2 +- drivers/mtd/nand/raw/diskonchip.c | 2 +- drivers/mtd/nand/raw/nand_base.c | 4 ++-- drivers/mtd/nand/raw/nand_bbt.c | 2 +- drivers/mtd/nand/raw/nand_ids.c | 2 +- drivers/mtd/nand/raw/nand_jedec.c | 2 +- drivers/mtd/nand/raw/nand_legacy.c | 2 +- drivers/mtd/nand/raw/nand_onfi.c | 2 +- drivers/mtd/nand/raw/ndfc.c | 2 +- drivers/uio/uio.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/ecc-sw-hamming.c b/drivers/mtd/nand/ecc-sw-hamming.c index f2d0effad9d2..bc62a71f9fdd 100644 --- a/drivers/mtd/nand/ecc-sw-hamming.c +++ b/drivers/mtd/nand/ecc-sw-hamming.c @@ -8,7 +8,7 @@ * * Completely replaces the previous ECC implementation which was written by: * Steven J. Hill (sjhill@realitydiluted.com) - * Thomas Gleixner (tglx@linutronix.de) + * Thomas Gleixner (tglx@kernel.org) * * Information on how this algorithm works and how it was developed * can be found in Documentation/driver-api/mtd/nand_ecc.rst diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 70d6c2250f32..540b6baf8bb1 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -11,7 +11,7 @@ * Error correction code lifted from the old docecc code * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. - * converted to the generic Reed-Solomon library by Thomas Gleixner + * converted to the generic Reed-Solomon library by Thomas Gleixner * * Interface to generic NAND code for M-Systems DiskOnChip devices */ diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index ad6d66309597..f2322de93ab4 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -8,7 +8,7 @@ * http://www.linux-mtd.infradead.org/doc/nand.html * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * 2002-2006 Thomas Gleixner (tglx@kernel.org) * * Credits: * David Woodhouse for adding multichip support @@ -6594,5 +6594,5 @@ EXPORT_SYMBOL_GPL(nand_cleanup); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steven J. Hill "); -MODULE_AUTHOR("Thomas Gleixner "); +MODULE_AUTHOR("Thomas Gleixner "); MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index a8fba5f39f59..3050ab7e6eb6 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -3,7 +3,7 @@ * Overview: * Bad block table support for the NAND driver * - * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) + * Copyright © 2004 Thomas Gleixner (tglx@kernel.org) * * Description: * diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index 650351c62af6..62a8cf86d9e2 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) + * Copyright (C) 2002 Thomas Gleixner (tglx@kernel.org) */ #include diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index b3cc8f360529..89e6dd8ed1a8 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * 2002-2006 Thomas Gleixner (tglx@kernel.org) * * Credits: * David Woodhouse for adding multichip support diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index 743792edf98d..97700f80d5b8 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * 2002-2006 Thomas Gleixner (tglx@kernel.org) * * Credits: * David Woodhouse for adding multichip support diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 861975e44b55..11954440e4de 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * 2002-2006 Thomas Gleixner (tglx@kernel.org) * * Credits: * David Woodhouse for adding multichip support diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 13365128194d..7ad8bc04be1a 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -272,5 +272,5 @@ static struct platform_driver ndfc_driver = { module_platform_driver(ndfc_driver); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Gleixner "); +MODULE_AUTHOR("Thomas Gleixner "); MODULE_DESCRIPTION("OF Platform driver for NDFC"); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index d93ed4e86a17..fa0d4e6aee16 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -3,7 +3,7 @@ * drivers/uio/uio.c * * Copyright(C) 2005, Benedikt Spranger - * Copyright(C) 2005, Thomas Gleixner + * Copyright(C) 2005, Linutronix GmbH, Thomas Gleixner * Copyright(C) 2006, Hans J. Koch * Copyright(C) 2006, Greg Kroah-Hartman * -- cgit v1.2.3