From nobody Mon Sep 28 23:07:55 2026 Received: from mail-lj1-f181.google.com (mail-lj1-f181.google.com [209.85.208.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1424C3DD85C for ; Sat, 15 Aug 2026 10:28:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786789696; cv=none; b=NPJ7F8pxJVBWXEXTW2p3hhooN+vbdMMm0pPmTloyByiTzdkTHst4P0Tj/m0PjqUmUbjUeDNlGDFLITmdjPydEyYtfRblbEllQeXNAtP1ODMG+UK+/BJweidqdWZXmn2xwGdaHV1C5RSPJ1uaHcBsrmGDOONxKn6gC7OS2+LUuys= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786789696; c=relaxed/simple; bh=eG9vOCi6dz2LS9h7tb35pxRgJtlauzumDhyiULGGUUo=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=kauH5ffwFGWzRgL7Dbd+6IfpjEVss/dW5rulaVUcc74NlVUR8De/z01jT23614loUM6SpiHexZirT2fuOd6XPjcQdzDxvZH2lEx4fwY+8seYafMGUhlFmHKz8iWIabYGg8NSUF8ApnvGdIPwMFwOegOoUA+ItSqTfmE8kGq2koI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=oaysjGrK; arc=none smtp.client-ip=209.85.208.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="oaysjGrK" Received: by mail-lj1-f181.google.com with SMTP id 38308e7fff4ca-3a148d4509bso3238351fa.1 for ; Sat, 15 Aug 2026 03:28:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786789693; x=1787394493; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=PT2DE6cl5YPBMy2m9I9NSThkbJzai5L9OY2FPvGH160=; b=oaysjGrK5idLYiuVONxCPxEC9y6qqmeK0obJmkCTq9C8n2U4WeDnbR/yVjuYOatHFb TM4nyivuKH2G+6vuhY14CXXKyosbCeTCvsdfPeKIFZWVTPEpgkS8HMyn66dP7uXhOYEO +Z8FJ2v7qZXXjtjjy3puERT9vQ6Hst709SiNoW5jQGxx0gJM6HKq6gT1ff8zLodCJ718 Pus9R4ZIu3i/byqYgVNUTobcgKuM4rZUDxOzXv0Z7jvrdV9plPwKZmamrJB2ThnjfFmS WAupDVUV4Yq9EKsXkDCi1q3ZfWTwG20XQI6xH5E231yv3PxIE6UmMASLH5OdpWSNGHPh Zeow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786789693; x=1787394493; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=PT2DE6cl5YPBMy2m9I9NSThkbJzai5L9OY2FPvGH160=; b=fFhqeELZvmDrjmNRF81QQ/kHYVBRWPs9l9tlmLZSKd+1lOR0zNtnF/S6NnyzY1+E4O ru9lrXUrgjFh9We7PbF8k880VlAyjPNZkFd8ZaaWmxBQB7VIhyXnWqo5j4ewrRcVmdqD jtNqzE/emoUeETfWP27Y9k6uubFJwC8n9ZbCH+VWdgpbewq0nc2kuv+qE7BCokBugrFr qFL2Gm+raFf5wCcFpDuW0RqApQBDv4aELEOmZcOLcv9cgQsIlWA4ECjwjI0+LzlBeg4y GPZvp1M3EiHXgUBRCjOFDuoefcqpEcrI/cKf1yq4NVTWsSMfPAOCj6WnLVI+PyZtL0z6 VarQ== X-Forwarded-Encrypted: i=1; AHgh+RoTZzpD/N5E4Mc86HfgBiQl8GyIgAtPYPnO76LK3UWmKRpMiqEM1t3CSSNPQHGD5/+I5J78Oj6Yk5IEDR8=@vger.kernel.org X-Gm-Message-State: AOJu0YyXjNULG1ILaRcPrA1VXI0I2AOUvK5ZKaBr9YQnPePztpP2Goln MtJT2an7nvmYWS/RDNQ0OIwmUSk1v7G8xiqJsaSM8DjYdsw4k+pcNYAL X-Gm-Gg: AR+sD13Nvzlc+15XEep1QsFaDeM+s2Ap+pgE59dpzh8V0L+hXTTAigVHtx2k11zThwf eu5Cal1fkZF9irPQh9Hr2wi2gOVRH3K8eMR66I5roE3iOgGKeidUNrLz7NN+e6f3ULjWUhZnhq4 rNdLatbe5s+phSLU/w6K9yv3buICGEjOuVVzXG73W9eObsG9MTCBlRxxO+t8mDOxamyKSsiRxLQ kI+QX1Tjv0tw1aObZJeM2/CfqnI1DCQKFt+yankblWlI0XMunCW9LMfqIYOq27ZRnhZK+WjdmuZ wyx6uFPkK9ppEI5YRx0fQ6RYiKxCbphULy5zwrTAVTNVah1HO3jjbyZxvI/gz1e7H5FRaqwfYI4 Gk7RqtRqLAda6ONa5OQeYlpbq8dNgalii9wJUxEiSCIFe7FUxGwVjvNJTLN3/uO41hhJGkp4AAH f9CrOb6fubzNx97Po/kCCQEkWIpK856/nFM4F3JuO25Yq2KtaJcN3JGsfmZ40gBrgKJDmUGzY0S TCPj3LnGn+fzK6WIY8Uas63JFljLWyIlNEotqcC3AzDqkmnh8GCY4ujpRzn X-Received: by 2002:a05:651c:43cc:10b0:3a1:5c6:b533 with SMTP id 38308e7fff4ca-3a13283bfcemr7273131fa.30.1786789692757; Sat, 15 Aug 2026 03:28:12 -0700 (PDT) Received: from localhost ([188.234.148.119]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-3a1308d1cdcsm10996531fa.18.2026.08.15.03.28.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Aug 2026 03:28:12 -0700 (PDT) From: Mikhail Gavrilov To: Felix Fietkau , Lorenzo Bianconi , Ryder Lee , Shayne Chen , Sean Wang Cc: JB Tsai , linux-wireless@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org, regressions@lists.linux.dev, Mikhail Gavrilov Subject: [PATCH wireless] wifi: mt76: mt7921: fix deadlock on 6 GHz association Date: Sat, 15 Aug 2026 15:28:06 +0500 Message-ID: <20260815102806.32722-1-mikhail.v.gavrilov@gmail.com> X-Mailer: git-send-email 2.55.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" mt7921_mcu_regd_update() acquires &dev->mt76.mutex, but two of its callers already hold it: mt76_sta_state() takes the mutex and calls into the driver with it held, on both the add and the remove path. mt76_sta_state <- takes &dev->mutex mt7921_mac_sta_add mt7921_regd_set_6ghz_power_type(vif, true) mt7921_mcu_regd_update <- takes &dev->mutex again mt76_sta_state <- takes &dev->mutex mt7921_mac_sta_remove mt7921_regd_set_6ghz_power_type(vif, false) mt7921_mcu_regd_update <- takes &dev->mutex again Both acquisitions are of the same lock instance, so this is a hard self-deadlock rather than a missing nesting annotation: WARNING: possible recursive locking detected wpa_supplicant/5319 is trying to acquire lock: ffff88879cd94050 (&dev->mutex#3){+.+.}-{4:4}, at: mt7921_mcu_regd_update+= 0xc0/0x7a0 [mt7921_common] but task is already holding lock: ffff88879cd94050 (&dev->mutex#3){+.+.}-{4:4}, at: mt76_sta_state+0x2d4/0x= b30 [mt76] Call Trace: mt7921_mcu_regd_update+0xc0/0x7a0 [mt7921_common] mt7921_regd_set_6ghz_power_type+0x25b/0x2e0 [mt7921_common] mt7921_mac_sta_add+0x33f/0x480 [mt7921_common] mt76_sta_state+0x335/0xb30 [mt76] drv_sta_state+0x284/0x740 [mac80211] sta_info_insert_finish+0x4dc/0x1070 [mac80211] ieee80211_prep_connection+0xaf3/0x1740 [mac80211] ieee80211_mgd_auth+0xcba/0x1a00 [mac80211] cfg80211_mlme_auth+0x47b/0xab0 [cfg80211] nl80211_authenticate+0xa34/0xdf0 [cfg80211] The kernel then says it outright: INFO: task wpa_supplicant:5319 is blocked on a mutex likely owned by task wpa_supplicant:5319. The damage is not confined to Wi-Fi. wpa_supplicant blocks while holding wiphy.mtx, NetworkManager then blocks on wiphy.mtx while holding rtnl, and everything needing rtnl queues up behind it: rtnl_dumpit, ethtool ioctls, cleanup_net. The machine is left with no working network stack and needs sysrq to reboot. Since NetworkManager retries the saved profile on every boot, an affected kernel stops reaching a usable state at all once a 6 GHz profile exists. Before commit e88098133ed4 ("wifi: mt76: mt7921: refactor regulatory notifier flow") the function was lock-free by contract and its callers supplied the lock: the sta_add and sta_remove paths already held it, and mt7921_regd_notifier() took it explicitly. That commit moved mt792x_mutex_acquire() inside the function, which is what mt7921_pci_resume() needed - it had been calling in with no lock at all - but it left the two mac80211 paths taking the mutex twice. That those paths run with the mutex held is not incidental: each ends with a hand-rolled mt76_connac_power_save_sched(), the half of mt792x_mutex_release() that the core's plain mutex_lock() does not provide. The lock-free contract was deliberate. Split the function: keep a lock-free __mt7921_mcu_regd_update() for callers that already hold the mutex, and a thin locking wrapper for those that do not. The regulatory notifier and the PCI resume path are unchanged. The deadlock is gated on the band. mt7921_regd_set_6ghz_power_type() only issues the update when vif->bss_conf.chanreq.oper.chan->band =3D=3D NL80211_BAND_6GHZ so it takes a 6 GHz association to reach it, which is likely why this survived seven -rc rounds unreported. Fixes: e88098133ed4 ("wifi: mt76: mt7921: refactor regulatory notifier flow= ") Signed-off-by: Mikhail Gavrilov --- #regzbot introduced: e88098133ed4 Not addressed here: the "if (!dev->regd_change) goto err" gate combined with clearing regd_change on exit makes the sta_add/sta_remove call a no-op in the common case. That call site may want removing rather than relocking, but that is a behavioural decision for you. Tested on an MT7922 (mt7921e) on v7.2-rc7 with a lockdep and UBSAN build: association with a 6 GHz AP completes (channel 37, 6135 MHz, 160 MHz), roaming between a 5 GHz and a 6 GHz BSS exercises both the sta_add and the sta_remove call site, "iw reg set NL" and back still reaches the regulatory notifier, and a deep suspend/resume cycle reconnects to the 6 GHz BSS. dmesg is clean. v7.1 is unaffected. .../net/wireless/mediatek/mt76/mt7921/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/regd.c | 20 +++++++++++++++---- .../net/wireless/mediatek/mt76/mt7921/regd.h | 2 ++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net= /wireless/mediatek/mt76/mt7921/main.c index 3480205d5fb9..68a059504e83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -802,7 +802,7 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *v= if, bool is_add) =20 out: if (vif->bss_conf.chanreq.oper.chan->band =3D=3D NL80211_BAND_6GHZ) - mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env); + __mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env); } =20 int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net= /wireless/mediatek/mt76/mt7921/regd.c index c0e2b48a50bf..43193c436ddc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -71,17 +71,18 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct = mt792x_dev *dev) } } =20 -int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, - enum environment_cap country_ie_env) +int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) { struct mt76_dev *mdev =3D &dev->mt76; struct ieee80211_hw *hw =3D mdev->hw; struct wiphy *wiphy =3D hw->wiphy; int ret =3D 0; =20 + lockdep_assert_held(&mdev->mutex); + dev->regd_in_progress =3D true; =20 - mt792x_mutex_acquire(dev); if (!dev->regd_change) goto err; =20 @@ -100,13 +101,24 @@ int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8= *alpha2, goto err; =20 err: - mt792x_mutex_release(dev); dev->regd_change =3D false; dev->regd_in_progress =3D false; wake_up(&dev->wait); =20 return ret; } + +int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) +{ + int ret; + + mt792x_mutex_acquire(dev); + ret =3D __mt7921_mcu_regd_update(dev, alpha2, country_ie_env); + mt792x_mutex_release(dev); + + return ret; +} EXPORT_SYMBOL_GPL(mt7921_mcu_regd_update); =20 void mt7921_regd_notifier(struct wiphy *wiphy, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net= /wireless/mediatek/mt76/mt7921/regd.h index 571f31629e9e..2ea12d3861fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -8,6 +8,8 @@ struct mt792x_dev; struct wiphy; struct regulatory_request; =20 +int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env); int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap country_ie_env); void mt7921_regd_notifier(struct wiphy *wiphy, --=20 2.55.0