From: Sasha Levin Date: Wed, 27 Nov 2024 18:04:20 +0000 (-0500) Subject: Fixes for 6.1 X-Git-Tag: v4.19.325~131 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=833a14293473182ce323f8cf7349797667e8a90a;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.1 Signed-off-by: Sasha Levin --- diff --git a/queue-6.1/bluetooth-hci_sync-add-helper-functions-to-manipulat.patch b/queue-6.1/bluetooth-hci_sync-add-helper-functions-to-manipulat.patch new file mode 100644 index 00000000000..76bdcab234e --- /dev/null +++ b/queue-6.1/bluetooth-hci_sync-add-helper-functions-to-manipulat.patch @@ -0,0 +1,211 @@ +From ed0ffcf4f5cbff66a101156715dfa534496f0bab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 14:25:36 +0800 +Subject: Bluetooth: hci_sync: Add helper functions to manipulate cmd_sync + queue + +From: Luiz Augusto von Dentz + +[ Upstream commit 505ea2b295929e7be2b4e1bc86ee31cb7862fb01 ] + +This adds functions to queue, dequeue and lookup into the cmd_sync +list. + +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + include/net/bluetooth/hci_sync.h | 12 +++ + net/bluetooth/hci_sync.c | 132 +++++++++++++++++++++++++++++-- + 2 files changed, 136 insertions(+), 8 deletions(-) + +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 7accd5ff0760b..3a7658d660224 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -47,6 +47,18 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, + void *data, hci_cmd_sync_work_destroy_t destroy); + int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, + void *data, hci_cmd_sync_work_destroy_t destroy); ++struct hci_cmd_sync_work_entry * ++hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy); ++int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy); ++void hci_cmd_sync_cancel_entry(struct hci_dev *hdev, ++ struct hci_cmd_sync_work_entry *entry); ++bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy); ++bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev, ++ hci_cmd_sync_work_func_t func, void *data, ++ hci_cmd_sync_work_destroy_t destroy); + + int hci_update_eir_sync(struct hci_dev *hdev); + int hci_update_class_sync(struct hci_dev *hdev); +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 862ac5e1f4b49..b7a7b2afaa049 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -650,6 +650,17 @@ void hci_cmd_sync_init(struct hci_dev *hdev) + INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire); + } + ++static void _hci_cmd_sync_cancel_entry(struct hci_dev *hdev, ++ struct hci_cmd_sync_work_entry *entry, ++ int err) ++{ ++ if (entry->destroy) ++ entry->destroy(hdev, entry->data, err); ++ ++ list_del(&entry->list); ++ kfree(entry); ++} ++ + void hci_cmd_sync_clear(struct hci_dev *hdev) + { + struct hci_cmd_sync_work_entry *entry, *tmp; +@@ -658,13 +669,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev) + cancel_work_sync(&hdev->reenable_adv_work); + + mutex_lock(&hdev->cmd_sync_work_lock); +- list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) { +- if (entry->destroy) +- entry->destroy(hdev, entry->data, -ECANCELED); +- +- list_del(&entry->list); +- kfree(entry); +- } ++ list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) ++ _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED); + mutex_unlock(&hdev->cmd_sync_work_lock); + } + +@@ -756,6 +762,115 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, + } + EXPORT_SYMBOL(hci_cmd_sync_queue); + ++static struct hci_cmd_sync_work_entry * ++_hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy) ++{ ++ struct hci_cmd_sync_work_entry *entry, *tmp; ++ ++ list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) { ++ if (func && entry->func != func) ++ continue; ++ ++ if (data && entry->data != data) ++ continue; ++ ++ if (destroy && entry->destroy != destroy) ++ continue; ++ ++ return entry; ++ } ++ ++ return NULL; ++} ++ ++/* Queue HCI command entry once: ++ * ++ * - Lookup if an entry already exist and only if it doesn't creates a new entry ++ * and queue it. ++ */ ++int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy) ++{ ++ if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) ++ return 0; ++ ++ return hci_cmd_sync_queue(hdev, func, data, destroy); ++} ++EXPORT_SYMBOL(hci_cmd_sync_queue_once); ++ ++/* Lookup HCI command entry: ++ * ++ * - Return first entry that matches by function callback or data or ++ * destroy callback. ++ */ ++struct hci_cmd_sync_work_entry * ++hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy) ++{ ++ struct hci_cmd_sync_work_entry *entry; ++ ++ mutex_lock(&hdev->cmd_sync_work_lock); ++ entry = _hci_cmd_sync_lookup_entry(hdev, func, data, destroy); ++ mutex_unlock(&hdev->cmd_sync_work_lock); ++ ++ return entry; ++} ++EXPORT_SYMBOL(hci_cmd_sync_lookup_entry); ++ ++/* Cancel HCI command entry */ ++void hci_cmd_sync_cancel_entry(struct hci_dev *hdev, ++ struct hci_cmd_sync_work_entry *entry) ++{ ++ mutex_lock(&hdev->cmd_sync_work_lock); ++ _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED); ++ mutex_unlock(&hdev->cmd_sync_work_lock); ++} ++EXPORT_SYMBOL(hci_cmd_sync_cancel_entry); ++ ++/* Dequeue one HCI command entry: ++ * ++ * - Lookup and cancel first entry that matches. ++ */ ++bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev, ++ hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy) ++{ ++ struct hci_cmd_sync_work_entry *entry; ++ ++ entry = hci_cmd_sync_lookup_entry(hdev, func, data, destroy); ++ if (!entry) ++ return false; ++ ++ hci_cmd_sync_cancel_entry(hdev, entry); ++ ++ return true; ++} ++EXPORT_SYMBOL(hci_cmd_sync_dequeue_once); ++ ++/* Dequeue HCI command entry: ++ * ++ * - Lookup and cancel any entry that matches by function callback or data or ++ * destroy callback. ++ */ ++bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, ++ void *data, hci_cmd_sync_work_destroy_t destroy) ++{ ++ struct hci_cmd_sync_work_entry *entry; ++ bool ret = false; ++ ++ mutex_lock(&hdev->cmd_sync_work_lock); ++ while ((entry = _hci_cmd_sync_lookup_entry(hdev, func, data, ++ destroy))) { ++ _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED); ++ ret = true; ++ } ++ mutex_unlock(&hdev->cmd_sync_work_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(hci_cmd_sync_dequeue); ++ + int hci_update_eir_sync(struct hci_dev *hdev) + { + struct hci_cp_write_eir cp; +@@ -3023,7 +3138,8 @@ int hci_update_passive_scan(struct hci_dev *hdev) + hci_dev_test_flag(hdev, HCI_UNREGISTER)) + return 0; + +- return hci_cmd_sync_queue(hdev, update_passive_scan_sync, NULL, NULL); ++ return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL, ++ NULL); + } + + int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val) +-- +2.43.0 + diff --git a/queue-6.1/bluetooth-mgmt-fix-possible-crash-on-mgmt_index_remo.patch b/queue-6.1/bluetooth-mgmt-fix-possible-crash-on-mgmt_index_remo.patch new file mode 100644 index 00000000000..fad6c28af1b --- /dev/null +++ b/queue-6.1/bluetooth-mgmt-fix-possible-crash-on-mgmt_index_remo.patch @@ -0,0 +1,97 @@ +From cf80c87802b865261181061184253e7f3bbb19f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 14:25:37 +0800 +Subject: Bluetooth: MGMT: Fix possible crash on mgmt_index_removed + +From: Luiz Augusto von Dentz + +[ Upstream commit f53e1c9c726d83092167f2226f32bd3b73f26c21 ] + +If mgmt_index_removed is called while there are commands queued on +cmd_sync it could lead to crashes like the bellow trace: + +0x0000053D: __list_del_entry_valid_or_report+0x98/0xdc +0x0000053D: mgmt_pending_remove+0x18/0x58 [bluetooth] +0x0000053E: mgmt_remove_adv_monitor_complete+0x80/0x108 [bluetooth] +0x0000053E: hci_cmd_sync_work+0xbc/0x164 [bluetooth] + +So while handling mgmt_index_removed this attempts to dequeue +commands passed as user_data to cmd_sync. + +Fixes: 7cf5c2978f23 ("Bluetooth: hci_sync: Refactor remove Adv Monitor") +Reported-by: jiaymao +Signed-off-by: Luiz Augusto von Dentz +[Xiangyu: BP to fix CVE: CVE-2024-49951, Minor conflict resolution] +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + net/bluetooth/mgmt.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 5a1015ccc0635..82edd9981ab07 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -1457,10 +1457,15 @@ static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) + + static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) + { +- if (cmd->cmd_complete) { +- u8 *status = data; ++ struct cmd_lookup *match = data; ++ ++ /* dequeue cmd_sync entries using cmd as data as that is about to be ++ * removed/freed. ++ */ ++ hci_cmd_sync_dequeue(match->hdev, NULL, cmd, NULL); + +- cmd->cmd_complete(cmd, *status); ++ if (cmd->cmd_complete) { ++ cmd->cmd_complete(cmd, match->mgmt_status); + mgmt_pending_remove(cmd); + + return; +@@ -9424,14 +9429,14 @@ void mgmt_index_added(struct hci_dev *hdev) + void mgmt_index_removed(struct hci_dev *hdev) + { + struct mgmt_ev_ext_index ev; +- u8 status = MGMT_STATUS_INVALID_INDEX; ++ struct cmd_lookup match = { NULL, hdev, MGMT_STATUS_INVALID_INDEX }; + + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return; + + switch (hdev->dev_type) { + case HCI_PRIMARY: +- mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); ++ mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); + + if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { + mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, +@@ -9489,7 +9494,7 @@ void mgmt_power_on(struct hci_dev *hdev, int err) + void __mgmt_power_off(struct hci_dev *hdev) + { + struct cmd_lookup match = { NULL, hdev }; +- u8 status, zero_cod[] = { 0, 0, 0 }; ++ u8 zero_cod[] = { 0, 0, 0 }; + + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); + +@@ -9501,11 +9506,11 @@ void __mgmt_power_off(struct hci_dev *hdev) + * status responses. + */ + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) +- status = MGMT_STATUS_INVALID_INDEX; ++ match.mgmt_status = MGMT_STATUS_INVALID_INDEX; + else +- status = MGMT_STATUS_NOT_POWERED; ++ match.mgmt_status = MGMT_STATUS_NOT_POWERED; + +- mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); ++ mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); + + if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { + mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-add-null-check-for-function-pointer-.patch b/queue-6.1/drm-amd-display-add-null-check-for-function-pointer-.patch new file mode 100644 index 00000000000..f1956272e26 --- /dev/null +++ b/queue-6.1/drm-amd-display-add-null-check-for-function-pointer-.patch @@ -0,0 +1,54 @@ +From 7c763d769a19b2f029a8c8c8a278e85d91a0775f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 18:10:51 +0800 +Subject: drm/amd/display: Add NULL check for function pointer in + dcn32_set_output_transfer_func + +From: Srinivasan Shanmugam + +[ Upstream commit 28574b08c70e56d34d6f6379326a860b96749051 ] + +This commit adds a null check for the set_output_gamma function pointer +in the dcn32_set_output_transfer_func function. Previously, +set_output_gamma was being checked for null, but then it was being +dereferenced without any null check. This could lead to a null pointer +dereference if set_output_gamma is null. + +To fix this, we now ensure that set_output_gamma is not null before +dereferencing it. We do this by adding a null check for set_output_gamma +before the call to set_output_gamma. + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +index bd75d3cba0980..d3ad13bf35c85 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +@@ -667,7 +667,9 @@ bool dcn32_set_output_transfer_func(struct dc *dc, + } + } + +- mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ if (mpc->funcs->set_output_gamma) ++ mpc->funcs->set_output_gamma(mpc, mpcc_id, params); ++ + return ret; + } + +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-check-null-initialized-variables.patch b/queue-6.1/drm-amd-display-check-null-initialized-variables.patch new file mode 100644 index 00000000000..5b6a868968a --- /dev/null +++ b/queue-6.1/drm-amd-display-check-null-initialized-variables.patch @@ -0,0 +1,57 @@ +From 2b6a747ef15334df62fbdacd4896b1cf9eccf2a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 19:23:25 +0800 +Subject: drm/amd/display: Check null-initialized variables + +From: Alex Hung + +[ Upstream commit 367cd9ceba1933b63bc1d87d967baf6d9fd241d2 ] + +[WHAT & HOW] +drr_timing and subvp_pipe are initialized to null and they are not +always assigned new values. It is necessary to check for null before +dereferencing. + +This fixes 2 FORWARD_NULL issues reported by Coverity. + +Reviewed-by: Nevenko Stupar +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +[Xiangyu: BP to fix CVE: CVE-2024-49898, Minor conflict resolution] +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +index 85e0d1c2a9085..9d8917f72d184 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +@@ -900,8 +900,9 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struc + * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time, + * and the max of (VBLANK blanking time, MALL region)). + */ +- if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 && +- subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0) ++ if (drr_timing && ++ stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 && ++ subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0) + schedulable = true; + + return schedulable; +@@ -966,7 +967,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) + if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) { + // SUBVP + DRR case + schedulable = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[vblank_index]); +- } else if (found) { ++ } else if (found && subvp_pipe) { + main_timing = &subvp_pipe->stream->timing; + phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; + vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing; +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-initialize-denominators-default-to-1.patch b/queue-6.1/drm-amd-display-initialize-denominators-default-to-1.patch new file mode 100644 index 00000000000..c931c5a52ec --- /dev/null +++ b/queue-6.1/drm-amd-display-initialize-denominators-default-to-1.patch @@ -0,0 +1,58 @@ +From 679aac3e7cea9f5dd3457b913b99a46e561bf958 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 17:36:04 +0800 +Subject: drm/amd/display: Initialize denominators' default to 1 + +From: Alex Hung + +[ Upstream commit b995c0a6de6c74656a0c39cd57a0626351b13e3c ] + +[WHAT & HOW] +Variables used as denominators and maybe not assigned to other values, +should not be 0. Change their default to 1 so they are never 0. + +This fixes 10 DIVIDE_BY_ZERO issues reported by Coverity. + +Reviewed-by: Harry Wentland +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +[Xiangyu: Bp to fix CVE: CVE-2024-49899 +Discard the dml2_core/dml2_core_shared.c due to this file no exists] +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c | 2 +- + drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c +index 548cdef8a8ade..543ce9a08cfd3 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c +@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +index 3df559c591f89..70df992f859d7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +@@ -39,7 +39,7 @@ + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +-- +2.43.0 + diff --git a/queue-6.1/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch b/queue-6.1/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch new file mode 100644 index 00000000000..db278fffbb2 --- /dev/null +++ b/queue-6.1/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch @@ -0,0 +1,77 @@ +From 88a9a3abde940034e61c4dc272317380d91f2185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 10:39:00 +0800 +Subject: fbdev: efifb: Register sysfs groups through driver core +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 95cdd538e0e5677efbdf8aade04ec098ab98f457 ] + +The driver core can register and cleanup sysfs groups already. +Make use of that functionality to simplify the error handling and +cleanup. + +Also avoid a UAF race during unregistering where the sysctl attributes +were usable after the info struct was freed. + +Signed-off-by: Thomas Weißschuh +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/efifb.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c +index 16c1aaae9afa4..53944bcc990c5 100644 +--- a/drivers/video/fbdev/efifb.c ++++ b/drivers/video/fbdev/efifb.c +@@ -570,15 +570,10 @@ static int efifb_probe(struct platform_device *dev) + break; + } + +- err = sysfs_create_groups(&dev->dev.kobj, efifb_groups); +- if (err) { +- pr_err("efifb: cannot add sysfs attrs\n"); +- goto err_unmap; +- } + err = fb_alloc_cmap(&info->cmap, 256, 0); + if (err < 0) { + pr_err("efifb: cannot allocate colormap\n"); +- goto err_groups; ++ goto err_unmap; + } + + if (efifb_pci_dev) +@@ -597,8 +592,6 @@ static int efifb_probe(struct platform_device *dev) + pm_runtime_put(&efifb_pci_dev->dev); + + fb_dealloc_cmap(&info->cmap); +-err_groups: +- sysfs_remove_groups(&dev->dev.kobj, efifb_groups); + err_unmap: + if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) + iounmap(info->screen_base); +@@ -618,7 +611,6 @@ static int efifb_remove(struct platform_device *pdev) + + /* efifb_destroy takes care of info cleanup */ + unregister_framebuffer(info); +- sysfs_remove_groups(&pdev->dev.kobj, efifb_groups); + + return 0; + } +@@ -626,6 +618,7 @@ static int efifb_remove(struct platform_device *pdev) + static struct platform_driver efifb_driver = { + .driver = { + .name = "efi-framebuffer", ++ .dev_groups = efifb_groups, + }, + .probe = efifb_probe, + .remove = efifb_remove, +-- +2.43.0 + diff --git a/queue-6.1/fpga-bridge-add-owner-module-and-take-its-refcount.patch b/queue-6.1/fpga-bridge-add-owner-module-and-take-its-refcount.patch new file mode 100644 index 00000000000..0be0f4ee01e --- /dev/null +++ b/queue-6.1/fpga-bridge-add-owner-module-and-take-its-refcount.patch @@ -0,0 +1,253 @@ +From 14897baa9becf6b5a718188c2681d54ac0bdc535 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 13:38:15 +0800 +Subject: fpga: bridge: add owner module and take its refcount + +From: Marco Pagani + +[ Upstream commit 1da11f822042eb6ef4b6064dc048f157a7852529 ] + +The current implementation of the fpga bridge assumes that the low-level +module registers a driver for the parent device and uses its owner pointer +to take the module's refcount. This approach is problematic since it can +lead to a null pointer dereference while attempting to get the bridge if +the parent device does not have a driver. + +To address this problem, add a module owner pointer to the fpga_bridge +struct and use it to take the module's refcount. Modify the function for +registering a bridge to take an additional owner module parameter and +rename it to avoid conflicts. Use the old function name for a helper macro +that automatically sets the module that registers the bridge as the owner. +This ensures compatibility with existing low-level control modules and +reduces the chances of registering a bridge without setting the owner. + +Also, update the documentation to keep it consistent with the new interface +for registering an fpga bridge. + +Other changes: opportunistically move put_device() from __fpga_bridge_get() +to fpga_bridge_get() and of_fpga_bridge_get() to improve code clarity since +the bridge device is taken in these functions. + +Fixes: 21aeda950c5f ("fpga: add fpga bridge framework") +Suggested-by: Greg Kroah-Hartman +Suggested-by: Xu Yilun +Reviewed-by: Russ Weight +Signed-off-by: Marco Pagani +Acked-by: Xu Yilun +Link: https://lore.kernel.org/r/20240322171839.233864-1-marpagan@redhat.com +Signed-off-by: Xu Yilun +Signed-off-by: Sasha Levin +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + Documentation/driver-api/fpga/fpga-bridge.rst | 7 ++- + drivers/fpga/fpga-bridge.c | 57 ++++++++++--------- + include/linux/fpga/fpga-bridge.h | 10 +++- + 3 files changed, 43 insertions(+), 31 deletions(-) + +diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst +index 6042085340953..833f68fb07008 100644 +--- a/Documentation/driver-api/fpga/fpga-bridge.rst ++++ b/Documentation/driver-api/fpga/fpga-bridge.rst +@@ -6,9 +6,12 @@ API to implement a new FPGA bridge + + * struct fpga_bridge - The FPGA Bridge structure + * struct fpga_bridge_ops - Low level Bridge driver ops +-* fpga_bridge_register() - Create and register a bridge ++* __fpga_bridge_register() - Create and register a bridge + * fpga_bridge_unregister() - Unregister a bridge + ++The helper macro ``fpga_bridge_register()`` automatically sets ++the module that registers the FPGA bridge as the owner. ++ + .. kernel-doc:: include/linux/fpga/fpga-bridge.h + :functions: fpga_bridge + +@@ -16,7 +19,7 @@ API to implement a new FPGA bridge + :functions: fpga_bridge_ops + + .. kernel-doc:: drivers/fpga/fpga-bridge.c +- :functions: fpga_bridge_register ++ :functions: __fpga_bridge_register + + .. kernel-doc:: drivers/fpga/fpga-bridge.c + :functions: fpga_bridge_unregister +diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c +index 833ce13ff6f86..698d6cbf782a4 100644 +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -55,33 +55,26 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) + } + EXPORT_SYMBOL_GPL(fpga_bridge_disable); + +-static struct fpga_bridge *__fpga_bridge_get(struct device *dev, ++static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, + struct fpga_image_info *info) + { + struct fpga_bridge *bridge; +- int ret = -ENODEV; + +- bridge = to_fpga_bridge(dev); ++ bridge = to_fpga_bridge(bridge_dev); + + bridge->info = info; + +- if (!mutex_trylock(&bridge->mutex)) { +- ret = -EBUSY; +- goto err_dev; +- } ++ if (!mutex_trylock(&bridge->mutex)) ++ return ERR_PTR(-EBUSY); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_ll_mod; ++ if (!try_module_get(bridge->br_ops_owner)) { ++ mutex_unlock(&bridge->mutex); ++ return ERR_PTR(-ENODEV); ++ } + + dev_dbg(&bridge->dev, "get\n"); + + return bridge; +- +-err_ll_mod: +- mutex_unlock(&bridge->mutex); +-err_dev: +- put_device(dev); +- return ERR_PTR(ret); + } + + /** +@@ -97,13 +90,18 @@ static struct fpga_bridge *__fpga_bridge_get(struct device *dev, + struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, + struct fpga_image_info *info) + { +- struct device *dev; ++ struct fpga_bridge *bridge; ++ struct device *bridge_dev; + +- dev = class_find_device_by_of_node(fpga_bridge_class, np); +- if (!dev) ++ bridge_dev = class_find_device_by_of_node(fpga_bridge_class, np); ++ if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(of_fpga_bridge_get); + +@@ -124,6 +122,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) + struct fpga_bridge *fpga_bridge_get(struct device *dev, + struct fpga_image_info *info) + { ++ struct fpga_bridge *bridge; + struct device *bridge_dev; + + bridge_dev = class_find_device(fpga_bridge_class, NULL, dev, +@@ -131,7 +130,11 @@ struct fpga_bridge *fpga_bridge_get(struct device *dev, + if (!bridge_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_bridge_get(bridge_dev, info); ++ bridge = __fpga_bridge_get(bridge_dev, info); ++ if (IS_ERR(bridge)) ++ put_device(bridge_dev); ++ ++ return bridge; + } + EXPORT_SYMBOL_GPL(fpga_bridge_get); + +@@ -145,7 +148,7 @@ void fpga_bridge_put(struct fpga_bridge *bridge) + dev_dbg(&bridge->dev, "put\n"); + + bridge->info = NULL; +- module_put(bridge->dev.parent->driver->owner); ++ module_put(bridge->br_ops_owner); + mutex_unlock(&bridge->mutex); + put_device(&bridge->dev); + } +@@ -312,18 +315,19 @@ static struct attribute *fpga_bridge_attrs[] = { + ATTRIBUTE_GROUPS(fpga_bridge); + + /** +- * fpga_bridge_register - create and register an FPGA Bridge device ++ * __fpga_bridge_register - create and register an FPGA Bridge device + * @parent: FPGA bridge device from pdev + * @name: FPGA bridge name + * @br_ops: pointer to structure of fpga bridge ops + * @priv: FPGA bridge private data ++ * @owner: owner module containing the br_ops + * + * Return: struct fpga_bridge pointer or ERR_PTR() + */ + struct fpga_bridge * +-fpga_bridge_register(struct device *parent, const char *name, +- const struct fpga_bridge_ops *br_ops, +- void *priv) ++__fpga_bridge_register(struct device *parent, const char *name, ++ const struct fpga_bridge_ops *br_ops, ++ void *priv, struct module *owner) + { + struct fpga_bridge *bridge; + int id, ret; +@@ -353,6 +357,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + bridge->name = name; + bridge->br_ops = br_ops; ++ bridge->br_ops_owner = owner; + bridge->priv = priv; + + bridge->dev.groups = br_ops->groups; +@@ -382,7 +387,7 @@ fpga_bridge_register(struct device *parent, const char *name, + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_bridge_register); ++EXPORT_SYMBOL_GPL(__fpga_bridge_register); + + /** + * fpga_bridge_unregister - unregister an FPGA bridge +diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h +index 223da48a6d18b..94c4edd047e54 100644 +--- a/include/linux/fpga/fpga-bridge.h ++++ b/include/linux/fpga/fpga-bridge.h +@@ -45,6 +45,7 @@ struct fpga_bridge_info { + * @dev: FPGA bridge device + * @mutex: enforces exclusive reference to bridge + * @br_ops: pointer to struct of FPGA bridge ops ++ * @br_ops_owner: module containing the br_ops + * @info: fpga image specific information + * @node: FPGA bridge list node + * @priv: low level driver private date +@@ -54,6 +55,7 @@ struct fpga_bridge { + struct device dev; + struct mutex mutex; /* for exclusive reference to bridge */ + const struct fpga_bridge_ops *br_ops; ++ struct module *br_ops_owner; + struct fpga_image_info *info; + struct list_head node; + void *priv; +@@ -79,10 +81,12 @@ int of_fpga_bridge_get_to_list(struct device_node *np, + struct fpga_image_info *info, + struct list_head *bridge_list); + ++#define fpga_bridge_register(parent, name, br_ops, priv) \ ++ __fpga_bridge_register(parent, name, br_ops, priv, THIS_MODULE) + struct fpga_bridge * +-fpga_bridge_register(struct device *parent, const char *name, +- const struct fpga_bridge_ops *br_ops, +- void *priv); ++__fpga_bridge_register(struct device *parent, const char *name, ++ const struct fpga_bridge_ops *br_ops, void *priv, ++ struct module *owner); + void fpga_bridge_unregister(struct fpga_bridge *br); + + #endif /* _LINUX_FPGA_BRIDGE_H */ +-- +2.43.0 + diff --git a/queue-6.1/fpga-manager-add-owner-module-and-take-its-refcount.patch b/queue-6.1/fpga-manager-add-owner-module-and-take-its-refcount.patch new file mode 100644 index 00000000000..a2c4adf9150 --- /dev/null +++ b/queue-6.1/fpga-manager-add-owner-module-and-take-its-refcount.patch @@ -0,0 +1,410 @@ +From 7303f13cb313f1b2defba430f98a392e8b2e5009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 13:38:16 +0800 +Subject: fpga: manager: add owner module and take its refcount + +From: Marco Pagani + +[ Upstream commit 4d4d2d4346857bf778fafaa97d6f76bb1663e3c9 ] + +The current implementation of the fpga manager assumes that the low-level +module registers a driver for the parent device and uses its owner pointer +to take the module's refcount. This approach is problematic since it can +lead to a null pointer dereference while attempting to get the manager if +the parent device does not have a driver. + +To address this problem, add a module owner pointer to the fpga_manager +struct and use it to take the module's refcount. Modify the functions for +registering the manager to take an additional owner module parameter and +rename them to avoid conflicts. Use the old function names for helper +macros that automatically set the module that registers the manager as the +owner. This ensures compatibility with existing low-level control modules +and reduces the chances of registering a manager without setting the owner. + +Also, update the documentation to keep it consistent with the new interface +for registering an fpga manager. + +Other changes: opportunistically move put_device() from __fpga_mgr_get() to +fpga_mgr_get() and of_fpga_mgr_get() to improve code clarity since the +manager device is taken in these functions. + +Fixes: 654ba4cc0f3e ("fpga manager: ensure lifetime with of_fpga_mgr_get") +Suggested-by: Greg Kroah-Hartman +Suggested-by: Xu Yilun +Signed-off-by: Marco Pagani +Acked-by: Xu Yilun +Link: https://lore.kernel.org/r/20240305192926.84886-1-marpagan@redhat.com +Signed-off-by: Xu Yilun +Signed-off-by: Sasha Levin +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + Documentation/driver-api/fpga/fpga-mgr.rst | 34 +++++---- + drivers/fpga/fpga-mgr.c | 82 +++++++++++++--------- + include/linux/fpga/fpga-mgr.h | 26 +++++-- + 3 files changed, 89 insertions(+), 53 deletions(-) + +diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst +index 49c0a95126532..8d2b79f696c1f 100644 +--- a/Documentation/driver-api/fpga/fpga-mgr.rst ++++ b/Documentation/driver-api/fpga/fpga-mgr.rst +@@ -24,7 +24,8 @@ How to support a new FPGA device + -------------------------------- + + To add another FPGA manager, write a driver that implements a set of ops. The +-probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: ++probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``, ++such as:: + + static const struct fpga_manager_ops socfpga_fpga_ops = { + .write_init = socfpga_fpga_ops_configure_init, +@@ -69,10 +70,11 @@ probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: + } + + Alternatively, the probe function could call one of the resource managed +-register functions, devm_fpga_mgr_register() or devm_fpga_mgr_register_full(). +-When these functions are used, the parameter syntax is the same, but the call +-to fpga_mgr_unregister() should be removed. In the above example, the +-socfpga_fpga_remove() function would not be required. ++register functions, ``devm_fpga_mgr_register()`` or ++``devm_fpga_mgr_register_full()``. When these functions are used, the ++parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be ++removed. In the above example, the ``socfpga_fpga_remove()`` function would not be ++required. + + The ops will implement whatever device specific register writes are needed to + do the programming sequence for this particular FPGA. These ops return 0 for +@@ -125,15 +127,19 @@ API for implementing a new FPGA Manager driver + * struct fpga_manager - the FPGA manager struct + * struct fpga_manager_ops - Low level FPGA manager driver ops + * struct fpga_manager_info - Parameter structure for fpga_mgr_register_full() +-* fpga_mgr_register_full() - Create and register an FPGA manager using the ++* __fpga_mgr_register_full() - Create and register an FPGA manager using the + fpga_mgr_info structure to provide the full flexibility of options +-* fpga_mgr_register() - Create and register an FPGA manager using standard ++* __fpga_mgr_register() - Create and register an FPGA manager using standard + arguments +-* devm_fpga_mgr_register_full() - Resource managed version of +- fpga_mgr_register_full() +-* devm_fpga_mgr_register() - Resource managed version of fpga_mgr_register() ++* __devm_fpga_mgr_register_full() - Resource managed version of ++ __fpga_mgr_register_full() ++* __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register() + * fpga_mgr_unregister() - Unregister an FPGA manager + ++Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``, ++``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available ++to ease the registration. ++ + .. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + +@@ -147,16 +153,16 @@ API for implementing a new FPGA Manager driver + :functions: fpga_manager_info + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register_full ++ :functions: __fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: fpga_mgr_register ++ :functions: __fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register_full ++ :functions: __devm_fpga_mgr_register_full + + .. kernel-doc:: drivers/fpga/fpga-mgr.c +- :functions: devm_fpga_mgr_register ++ :functions: __devm_fpga_mgr_register + + .. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_unregister +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +index 8efa67620e216..0c71d91ba7f6e 100644 +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = { + }; + ATTRIBUTE_GROUPS(fpga_mgr); + +-static struct fpga_manager *__fpga_mgr_get(struct device *dev) ++static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev) + { + struct fpga_manager *mgr; + +- mgr = to_fpga_manager(dev); ++ mgr = to_fpga_manager(mgr_dev); + +- if (!try_module_get(dev->parent->driver->owner)) +- goto err_dev; ++ if (!try_module_get(mgr->mops_owner)) ++ mgr = ERR_PTR(-ENODEV); + + return mgr; +- +-err_dev: +- put_device(dev); +- return ERR_PTR(-ENODEV); + } + + static int fpga_mgr_dev_match(struct device *dev, const void *data) +@@ -693,12 +689,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) + */ + struct fpga_manager *fpga_mgr_get(struct device *dev) + { +- struct device *mgr_dev = class_find_device(fpga_mgr_class, NULL, dev, +- fpga_mgr_dev_match); ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; ++ ++ mgr_dev = class_find_device(fpga_mgr_class, NULL, dev, fpga_mgr_dev_match); + if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(mgr_dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(fpga_mgr_get); + +@@ -711,13 +713,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get); + */ + struct fpga_manager *of_fpga_mgr_get(struct device_node *node) + { +- struct device *dev; ++ struct fpga_manager *mgr; ++ struct device *mgr_dev; + +- dev = class_find_device_by_of_node(fpga_mgr_class, node); +- if (!dev) ++ mgr_dev = class_find_device_by_of_node(fpga_mgr_class, node); ++ if (!mgr_dev) + return ERR_PTR(-ENODEV); + +- return __fpga_mgr_get(dev); ++ mgr = __fpga_mgr_get(mgr_dev); ++ if (IS_ERR(mgr)) ++ put_device(mgr_dev); ++ ++ return mgr; + } + EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + +@@ -727,7 +734,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + */ + void fpga_mgr_put(struct fpga_manager *mgr) + { +- module_put(mgr->dev.parent->driver->owner); ++ module_put(mgr->mops_owner); + put_device(&mgr->dev); + } + EXPORT_SYMBOL_GPL(fpga_mgr_put); +@@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr) + EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + + /** +- * fpga_mgr_register_full - create and register an FPGA Manager device ++ * __fpga_mgr_register_full - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register_full() instead is recommended. +@@ -776,7 +784,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + const struct fpga_manager_ops *mops = info->mops; + struct fpga_manager *mgr; +@@ -804,6 +813,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + mutex_init(&mgr->ref_mutex); + ++ mgr->mops_owner = owner; ++ + mgr->name = info->name; + mgr->mops = info->mops; + mgr->priv = info->priv; +@@ -841,14 +852,15 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in + + return ERR_PTR(ret); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register_full); + + /** +- * fpga_mgr_register - create and register an FPGA Manager device ++ * __fpga_mgr_register - create and register an FPGA Manager device + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * The caller of this function is responsible for calling fpga_mgr_unregister(). + * Using devm_fpga_mgr_register() instead is recommended. This simple +@@ -859,8 +871,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_register_full); + * Return: pointer to struct fpga_manager pointer or ERR_PTR() + */ + struct fpga_manager * +-fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return fpga_mgr_register_full(parent, &info); ++ return __fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__fpga_mgr_register); + + /** + * fpga_mgr_unregister - unregister an FPGA manager +@@ -900,9 +912,10 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + } + + /** +- * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @info: parameters for fpga manager ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -910,7 +923,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res) + * function will be called automatically when the managing device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info) ++__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner) + { + struct fpga_mgr_devres *dr; + struct fpga_manager *mgr; +@@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + if (!dr) + return ERR_PTR(-ENOMEM); + +- mgr = fpga_mgr_register_full(parent, info); ++ mgr = __fpga_mgr_register_full(parent, info, owner); + if (IS_ERR(mgr)) { + devres_free(dr); + return mgr; +@@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf + + return mgr; + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register_full); + + /** +- * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() ++ * __devm_fpga_mgr_register - resource managed variant of fpga_mgr_register() + * @parent: fpga manager device from pdev + * @name: fpga manager name + * @mops: pointer to structure of fpga manager ops + * @priv: fpga manager private data ++ * @owner: owner module containing the ops + * + * Return: fpga manager pointer on success, negative error code otherwise. + * +@@ -946,8 +961,9 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full); + * device is detached. + */ + struct fpga_manager * +-devm_fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv) ++__devm_fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, ++ struct module *owner) + { + struct fpga_manager_info info = { 0 }; + +@@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name, + info.mops = mops; + info.priv = priv; + +- return devm_fpga_mgr_register_full(parent, &info); ++ return __devm_fpga_mgr_register_full(parent, &info, owner); + } +-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register); ++EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register); + + static void fpga_mgr_dev_release(struct device *dev) + { +diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h +index 54f63459efd6e..0d4fe068f3d8a 100644 +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -201,6 +201,7 @@ struct fpga_manager_ops { + * @state: state of fpga manager + * @compat_id: FPGA manager id for compatibility check. + * @mops: pointer to struct of fpga manager ops ++ * @mops_owner: module containing the mops + * @priv: low level driver private date + */ + struct fpga_manager { +@@ -210,6 +211,7 @@ struct fpga_manager { + enum fpga_mgr_states state; + struct fpga_compat_id *compat_id; + const struct fpga_manager_ops *mops; ++ struct module *mops_owner; + void *priv; + }; + +@@ -230,18 +232,30 @@ struct fpga_manager *fpga_mgr_get(struct device *dev); + + void fpga_mgr_put(struct fpga_manager *mgr); + ++#define fpga_mgr_register_full(parent, info) \ ++ __fpga_mgr_register_full(parent, info, THIS_MODULE) + struct fpga_manager * +-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); ++__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner); + ++#define fpga_mgr_register(parent, name, mops, priv) \ ++ __fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) + struct fpga_manager * +-fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv); ++__fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, struct module *owner); ++ + void fpga_mgr_unregister(struct fpga_manager *mgr); + ++#define devm_fpga_mgr_register_full(parent, info) \ ++ __devm_fpga_mgr_register_full(parent, info, THIS_MODULE) + struct fpga_manager * +-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info); ++__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, ++ struct module *owner); ++#define devm_fpga_mgr_register(parent, name, mops, priv) \ ++ __devm_fpga_mgr_register(parent, name, mops, priv, THIS_MODULE) + struct fpga_manager * +-devm_fpga_mgr_register(struct device *parent, const char *name, +- const struct fpga_manager_ops *mops, void *priv); ++__devm_fpga_mgr_register(struct device *parent, const char *name, ++ const struct fpga_manager_ops *mops, void *priv, ++ struct module *owner); + + #endif /*_LINUX_FPGA_MGR_H */ +-- +2.43.0 + diff --git a/queue-6.1/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch b/queue-6.1/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch new file mode 100644 index 00000000000..e681f556496 --- /dev/null +++ b/queue-6.1/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch @@ -0,0 +1,140 @@ +From e54306dd89ec3429bd973d17cc055c3e12c19577 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 16:04:01 +0800 +Subject: fs/inode: Prevent dump_mapping() accessing invalid dentry.d_name.name + +From: Li Zhijian + +[ Upstream commit 7f7b850689ac06a62befe26e1fd1806799e7f152 ] + +It's observed that a crash occurs during hot-remove a memory device, +in which user is accessing the hugetlb. See calltrace as following: + +------------[ cut here ]------------ +WARNING: CPU: 1 PID: 14045 at arch/x86/mm/fault.c:1278 do_user_addr_fault+0x2a0/0x790 +Modules linked in: kmem device_dax cxl_mem cxl_pmem cxl_port cxl_pci dax_hmem dax_pmem nd_pmem cxl_acpi nd_btt cxl_core crc32c_intel nvme virtiofs fuse nvme_core nfit libnvdimm dm_multipath scsi_dh_rdac scsi_dh_emc s +mirror dm_region_hash dm_log dm_mod +CPU: 1 PID: 14045 Comm: daxctl Not tainted 6.10.0-rc2-lizhijian+ #492 +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 +RIP: 0010:do_user_addr_fault+0x2a0/0x790 +Code: 48 8b 00 a8 04 0f 84 b5 fe ff ff e9 1c ff ff ff 4c 89 e9 4c 89 e2 be 01 00 00 00 bf 02 00 00 00 e8 b5 ef 24 00 e9 42 fe ff ff <0f> 0b 48 83 c4 08 4c 89 ea 48 89 ee 4c 89 e7 5b 5d 41 5c 41 5d 41 +RSP: 0000:ffffc90000a575f0 EFLAGS: 00010046 +RAX: ffff88800c303600 RBX: 0000000000000000 RCX: 0000000000000000 +RDX: 0000000000001000 RSI: ffffffff82504162 RDI: ffffffff824b2c36 +RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000000 R12: ffffc90000a57658 +R13: 0000000000001000 R14: ffff88800bc2e040 R15: 0000000000000000 +FS: 00007f51cb57d880(0000) GS:ffff88807fd00000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000001000 CR3: 00000000072e2004 CR4: 00000000001706f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +Call Trace: + + ? __warn+0x8d/0x190 + ? do_user_addr_fault+0x2a0/0x790 + ? report_bug+0x1c3/0x1d0 + ? handle_bug+0x3c/0x70 + ? exc_invalid_op+0x14/0x70 + ? asm_exc_invalid_op+0x16/0x20 + ? do_user_addr_fault+0x2a0/0x790 + ? exc_page_fault+0x31/0x200 + exc_page_fault+0x68/0x200 +<...snip...> +BUG: unable to handle page fault for address: 0000000000001000 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0 + Oops: Oops: 0000 [#1] PREEMPT SMP PTI + ---[ end trace 0000000000000000 ]--- + BUG: unable to handle page fault for address: 0000000000001000 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0 + Oops: Oops: 0000 [#1] PREEMPT SMP PTI + CPU: 1 PID: 14045 Comm: daxctl Kdump: loaded Tainted: G W 6.10.0-rc2-lizhijian+ #492 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 + RIP: 0010:dentry_name+0x1f4/0x440 +<...snip...> +? dentry_name+0x2fa/0x440 +vsnprintf+0x1f3/0x4f0 +vprintk_store+0x23a/0x540 +vprintk_emit+0x6d/0x330 +_printk+0x58/0x80 +dump_mapping+0x10b/0x1a0 +? __pfx_free_object_rcu+0x10/0x10 +__dump_page+0x26b/0x3e0 +? vprintk_emit+0xe0/0x330 +? _printk+0x58/0x80 +? dump_page+0x17/0x50 +dump_page+0x17/0x50 +do_migrate_range+0x2f7/0x7f0 +? do_migrate_range+0x42/0x7f0 +? offline_pages+0x2f4/0x8c0 +offline_pages+0x60a/0x8c0 +memory_subsys_offline+0x9f/0x1c0 +? lockdep_hardirqs_on+0x77/0x100 +? _raw_spin_unlock_irqrestore+0x38/0x60 +device_offline+0xe3/0x110 +state_store+0x6e/0xc0 +kernfs_fop_write_iter+0x143/0x200 +vfs_write+0x39f/0x560 +ksys_write+0x65/0xf0 +do_syscall_64+0x62/0x130 + +Previously, some sanity check have been done in dump_mapping() before +the print facility parsing '%pd' though, it's still possible to run into +an invalid dentry.d_name.name. + +Since dump_mapping() only needs to dump the filename only, retrieve it +by itself in a safer way to prevent an unnecessary crash. + +Note that either retrieving the filename with '%pd' or +strncpy_from_kernel_nofault(), the filename could be unreliable. + +Signed-off-by: Li Zhijian +Link: https://lore.kernel.org/r/20240826055503.1522320-1-lizhijian@fujitsu.com +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +[Xiangyu: Bp to fix CVE: CVE-2024-49934, modified strscpy step due to 6.1/6.6 need pass +the max len to strscpy] +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + fs/inode.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/fs/inode.c b/fs/inode.c +index 5dd0f81e9721e..0036d5c68fd41 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -593,6 +593,7 @@ void dump_mapping(const struct address_space *mapping) + struct hlist_node *dentry_first; + struct dentry *dentry_ptr; + struct dentry dentry; ++ char fname[64] = {}; + unsigned long ino; + + /* +@@ -628,11 +629,14 @@ void dump_mapping(const struct address_space *mapping) + return; + } + ++ if (strncpy_from_kernel_nofault(fname, dentry.d_name.name, 63) < 0) ++ strscpy(fname, "", 63); + /* +- * if dentry is corrupted, the %pd handler may still crash, +- * but it's unlikely that we reach here with a corrupt mapping ++ * Even if strncpy_from_kernel_nofault() succeeded, ++ * the fname could be unreliable + */ +- pr_warn("aops:%ps ino:%lx dentry name:\"%pd\"\n", a_ops, ino, &dentry); ++ pr_warn("aops:%ps ino:%lx dentry name(?):\"%s\"\n", ++ a_ops, ino, fname); + } + + void clear_inode(struct inode *inode) +-- +2.43.0 + diff --git a/queue-6.1/mptcp-fix-possible-integer-overflow-in-mptcp_reset_t.patch b/queue-6.1/mptcp-fix-possible-integer-overflow-in-mptcp_reset_t.patch new file mode 100644 index 00000000000..94b71a97f51 --- /dev/null +++ b/queue-6.1/mptcp-fix-possible-integer-overflow-in-mptcp_reset_t.patch @@ -0,0 +1,46 @@ +From 26051fa21c6024fef118065f2a2f04d0fcc5b468 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 15:05:25 +0100 +Subject: mptcp: fix possible integer overflow in mptcp_reset_tout_timer + +From: Dmitry Kandybka + +commit b169e76ebad22cbd055101ee5aa1a7bed0e66606 upstream. + +In 'mptcp_reset_tout_timer', promote 'probe_timestamp' to unsigned long +to avoid possible integer overflow. Compile tested only. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Signed-off-by: Dmitry Kandybka +Link: https://patch.msgid.link/20241107103657.1560536-1-d.kandybka@gmail.com +Signed-off-by: Jakub Kicinski +[ Conflict in this version because commit d866ae9aaa43 ("mptcp: add a + new sysctl for make after break timeout") is not in this version, and + replaced TCP_TIMEWAIT_LEN in the expression. The fix can still be + applied the same way: by forcing a cast to unsigned long for the first + item. ] +Signed-off-by: Matthieu Baerts (NGI0) +Signed-off-by: Sasha Levin +--- + net/mptcp/protocol.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 1acd4e37a0ea6..370afcac26234 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -2708,8 +2708,8 @@ void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout) + if (!fail_tout && !inet_csk(sk)->icsk_mtup.probe_timestamp) + return; + +- close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies + +- TCP_TIMEWAIT_LEN; ++ close_timeout = (unsigned long)inet_csk(sk)->icsk_mtup.probe_timestamp - ++ tcp_jiffies32 + jiffies + TCP_TIMEWAIT_LEN; + + /* the close timeout takes precedence on the fail one, and here at least one of + * them is active +-- +2.43.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 6587f8c2d55..e3dfe9f8d71 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -31,3 +31,14 @@ net-fix-crash-when-config-small-gso_max_size-gso_ipv.patch serial-sc16is7xx-fix-invalid-fifo-access-with-specia.patch x86-stackprotector-work-around-strict-clang-tls-symb.patch cifs-fix-buffer-overflow-when-parsing-nfs-reparse-po.patch +fpga-bridge-add-owner-module-and-take-its-refcount.patch +fpga-manager-add-owner-module-and-take-its-refcount.patch +drm-amd-display-add-null-check-for-function-pointer-.patch +drm-amd-display-check-null-initialized-variables.patch +bluetooth-hci_sync-add-helper-functions-to-manipulat.patch +bluetooth-mgmt-fix-possible-crash-on-mgmt_index_remo.patch +fbdev-efifb-register-sysfs-groups-through-driver-cor.patch +mptcp-fix-possible-integer-overflow-in-mptcp_reset_t.patch +wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch +drm-amd-display-initialize-denominators-default-to-1.patch +fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch diff --git a/queue-6.1/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch b/queue-6.1/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch new file mode 100644 index 00000000000..3ab7acc779c --- /dev/null +++ b/queue-6.1/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch @@ -0,0 +1,126 @@ +From fb201fc522d9f55803df657129b1c537b2412df4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 14:25:49 +0800 +Subject: wifi: rtw89: avoid to add interface to list twice when SER + +From: Chih-Kang Chang + +[ Upstream commit 7dd5d2514a8ea58f12096e888b0bd050d7eae20a ] + +If SER L2 occurs during the WoWLAN resume flow, the add interface flow +is triggered by ieee80211_reconfig(). However, due to +rtw89_wow_resume() return failure, it will cause the add interface flow +to be executed again, resulting in a double add list and causing a kernel +panic. Therefore, we have added a check to prevent double adding of the +list. + +list_add double add: new=ffff99d6992e2010, prev=ffff99d6992e2010, next=ffff99d695302628. +------------[ cut here ]------------ +kernel BUG at lib/list_debug.c:37! +invalid opcode: 0000 [#1] PREEMPT SMP NOPTI +CPU: 0 PID: 9 Comm: kworker/0:1 Tainted: G W O 6.6.30-02659-gc18865c4dfbd #1 770df2933251a0e3c888ba69d1053a817a6376a7 +Hardware name: HP Grunt/Grunt, BIOS Google_Grunt.11031.169.0 06/24/2021 +Workqueue: events_freezable ieee80211_restart_work [mac80211] +RIP: 0010:__list_add_valid_or_report+0x5e/0xb0 +Code: c7 74 18 48 39 ce 74 13 b0 01 59 5a 5e 5f 41 58 41 59 41 5a 5d e9 e2 d6 03 00 cc 48 c7 c7 8d 4f 17 83 48 89 c2 e8 02 c0 00 00 <0f> 0b 48 c7 c7 aa 8c 1c 83 e8 f4 bf 00 00 0f 0b 48 c7 c7 c8 bc 12 +RSP: 0018:ffffa91b8007bc50 EFLAGS: 00010246 +RAX: 0000000000000058 RBX: ffff99d6992e0900 RCX: a014d76c70ef3900 +RDX: ffffa91b8007bae8 RSI: 00000000ffffdfff RDI: 0000000000000001 +RBP: ffffa91b8007bc88 R08: 0000000000000000 R09: ffffa91b8007bae0 +R10: 00000000ffffdfff R11: ffffffff83a79800 R12: ffff99d695302060 +R13: ffff99d695300900 R14: ffff99d6992e1be0 R15: ffff99d6992e2010 +FS: 0000000000000000(0000) GS:ffff99d6aac00000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000078fbdba43480 CR3: 000000010e464000 CR4: 00000000001506f0 +Call Trace: + + ? __die_body+0x1f/0x70 + ? die+0x3d/0x60 + ? do_trap+0xa4/0x110 + ? __list_add_valid_or_report+0x5e/0xb0 + ? do_error_trap+0x6d/0x90 + ? __list_add_valid_or_report+0x5e/0xb0 + ? handle_invalid_op+0x30/0x40 + ? __list_add_valid_or_report+0x5e/0xb0 + ? exc_invalid_op+0x3c/0x50 + ? asm_exc_invalid_op+0x16/0x20 + ? __list_add_valid_or_report+0x5e/0xb0 + rtw89_ops_add_interface+0x309/0x310 [rtw89_core 7c32b1ee6854761c0321027c8a58c5160e41f48f] + drv_add_interface+0x5c/0x130 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc] + ieee80211_reconfig+0x241/0x13d0 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc] + ? finish_wait+0x3e/0x90 + ? synchronize_rcu_expedited+0x174/0x260 + ? sync_rcu_exp_done_unlocked+0x50/0x50 + ? wake_bit_function+0x40/0x40 + ieee80211_restart_work+0xf0/0x140 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc] + process_scheduled_works+0x1e5/0x480 + worker_thread+0xea/0x1e0 + kthread+0xdb/0x110 + ? move_linked_works+0x90/0x90 + ? kthread_associate_blkcg+0xa0/0xa0 + ret_from_fork+0x3b/0x50 + ? kthread_associate_blkcg+0xa0/0xa0 + ret_from_fork_asm+0x11/0x20 + +Modules linked in: dm_integrity async_xor xor async_tx lz4 lz4_compress zstd zstd_compress zram zsmalloc rfcomm cmac uinput algif_hash algif_skcipher af_alg btusb btrtl iio_trig_hrtimer industrialio_sw_trigger btmtk industrialio_configfs btbcm btintel uvcvideo videobuf2_vmalloc iio_trig_sysfs videobuf2_memops videobuf2_v4l2 videobuf2_common uvc snd_hda_codec_hdmi veth snd_hda_intel snd_intel_dspcfg acpi_als snd_hda_codec industrialio_triggered_buffer kfifo_buf snd_hwdep industrialio i2c_piix4 snd_hda_core designware_i2s ip6table_nat snd_soc_max98357a xt_MASQUERADE xt_cgroup snd_soc_acp_rt5682_mach fuse rtw89_8922ae(O) rtw89_8922a(O) rtw89_pci(O) rtw89_core(O) 8021q mac80211(O) bluetooth ecdh_generic ecc cfg80211 r8152 mii joydev +gsmi: Log Shutdown Reason 0x03 +---[ end trace 0000000000000000 ]--- + +Signed-off-by: Chih-Kang Chang +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20240731070506.46100-4-pkshih@realtek.com +Signed-off-by: Sasha Levin +Signed-off-by: Xiangyu Chen +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/mac80211.c | 4 +++- + drivers/net/wireless/realtek/rtw89/util.h | 18 ++++++++++++++++++ + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c +index 3a108b13aa596..f7880499aeb09 100644 +--- a/drivers/net/wireless/realtek/rtw89/mac80211.c ++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c +@@ -105,7 +105,9 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, + + mutex_lock(&rtwdev->mutex); + rtwvif->rtwdev = rtwdev; +- list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); ++ if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) ++ list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); ++ + INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); + rtw89_leave_ps_mode(rtwdev); + +diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h +index 1ae80b7561daa..f9f52b5b63b94 100644 +--- a/drivers/net/wireless/realtek/rtw89/util.h ++++ b/drivers/net/wireless/realtek/rtw89/util.h +@@ -14,6 +14,24 @@ + #define rtw89_for_each_rtwvif(rtwdev, rtwvif) \ + list_for_each_entry(rtwvif, &(rtwdev)->rtwvifs_list, list) + ++/* Before adding rtwvif to list, we need to check if it already exist, beacase ++ * in some case such as SER L2 happen during WoWLAN flow, calling reconfig ++ * twice cause the list to be added twice. ++ */ ++static inline bool rtw89_rtwvif_in_list(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *new) ++{ ++ struct rtw89_vif *rtwvif; ++ ++ lockdep_assert_held(&rtwdev->mutex); ++ ++ rtw89_for_each_rtwvif(rtwdev, rtwvif) ++ if (rtwvif == new) ++ return true; ++ ++ return false; ++} ++ + /* The result of negative dividend and positive divisor is undefined, but it + * should be one case of round-down or round-up. So, make it round-down if the + * result is round-up. +-- +2.43.0 +