[PATCH] wifi: iwlwifi: use unique thermal zone type

From: Jiajia Liu

Date: Wed Mar 11 2026 - 21:41:12 EST


Unloading iwlmld or iwlmvm can trigger hung task when two devices
using iwlmvm and iwlmld respectively on one setup. Their thermal
zones have the same type and share the same hwmon device created
by the first zone. The second zone indirectly holds the first zone
through hwmon and prevents the first zone from unregistering.
Tested with AX211 (8086:7af0) and BE200 (8086:272b).

INFO: task modprobe:5295 blocked for more than 120 seconds.
Not tainted 7.0.0-rc2-up1 #2
Call Trace:
__schedule+0x4df/0xfd0
schedule+0x27/0xd0
schedule_timeout+0xbd/0x100
__wait_for_common+0x97/0x1b0
? __pfx_schedule_timeout+0x10/0x10
thermal_zone_device_unregister+0x173/0x1c0
iwl_mld_thermal_exit+0xbb/0xd0 [iwlmld]
iwl_op_mode_mld_stop+0x37/0x120 [iwlmld]
iwl_opmode_deregister+0xc0/0x160 [iwlwifi]
__do_sys_delete_module+0x1b5/0x320

Signed-off-by: Jiajia Liu <liujiajia@xxxxxxxxxx>
---
drivers/net/wireless/intel/iwlwifi/iwl-utils.c | 10 ++++++++++
drivers/net/wireless/intel/iwlwifi/iwl-utils.h | 4 ++++
drivers/net/wireless/intel/iwlwifi/mld/thermal.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 6 ++++--
4 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
index d503544fda40..fe5fa5e59664 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
@@ -193,3 +193,13 @@ s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len)
return clamp(average_magnitude - i, -128, 0);
}
IWL_EXPORT_SYMBOL(iwl_average_neg_dbm);
+
+#ifdef CONFIG_THERMAL
+u8 iwl_thermal_zone_get_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(0);
+
+ return atomic_inc_return(&counter) & 0xFF;
+}
+IWL_EXPORT_SYMBOL(iwl_thermal_zone_get_id);
+#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
index 5172035e4d26..84a4543fd290 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
@@ -55,4 +55,8 @@ u32 iwl_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)

s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len);

+#ifdef CONFIG_THERMAL
+u8 iwl_thermal_zone_get_id(void);
+#endif
+
#endif /* __iwl_utils_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
index f8a8c35066be..500028a4dbd3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
@@ -5,6 +5,7 @@
#ifdef CONFIG_THERMAL
#include <linux/sort.h>
#include <linux/thermal.h>
+#include "iwl-utils.h"
#endif

#include "fw/api/phy.h"
@@ -243,7 +244,6 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)
{
int ret;
char name[16];
- static atomic_t counter = ATOMIC_INIT(0);
struct thermal_trip trips[IWL_MAX_DTS_TRIPS] = {
[0 ... IWL_MAX_DTS_TRIPS - 1] = {
.temperature = THERMAL_TEMP_INVALID,
@@ -254,7 +254,7 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)

BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);

- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
+ sprintf(name, "iwlwifi_%u", iwl_thermal_zone_get_id());
mld->tzone =
thermal_zone_device_register_with_trips(name, trips,
IWL_MAX_DTS_TRIPS,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index 53bab21ebae2..ea8e616174db 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -7,6 +7,9 @@
#include <linux/sort.h>

#include "mvm.h"
+#ifdef CONFIG_THERMAL
+#include "iwl-utils.h"
+#endif

#define IWL_MVM_NUM_CTDP_STEPS 20
#define IWL_MVM_MIN_CTDP_BUDGET_MW 150
@@ -652,7 +655,6 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
{
int i, ret;
char name[16];
- static atomic_t counter = ATOMIC_INIT(0);

if (!iwl_mvm_is_tt_in_fw(mvm)) {
mvm->tz_device.tzone = NULL;
@@ -662,7 +664,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)

BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);

- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
+ sprintf(name, "iwlwifi_%u", iwl_thermal_zone_get_id());
/*
* 0 is a valid temperature,
* so initialize the array with S16_MIN which invalid temperature
--
2.53.0