From: Charlie-cy Wu Split mt7921_mcu_regd_update() into two functions to prevent recursive mutex acquisition. Introduce __mt7921_mcu_regd_update() as the internal implementation that assumes the mutex is already held by the caller, while mt7921_mcu_regd_update() remains as the external interface that handles mutex acquisition and release. This fixes a deadlock issue when mt7921_regd_set_6ghz_power_type() is called with the device mutex already held. Without this change, calling mt7921_mcu_regd_update() would attempt to acquire the same mutex again, causing a recursive lock deadlock. The __mt7921_mcu_regd_update() function can be safely called when the caller has already acquired the device mutex, avoiding the deadlock while maintaining proper synchronization for regulatory domain updates. Fixes: dc2608cf5224 ("wifi: mt76: mt7921: refactor regulatory notifier flow") Signed-off-by: Charlie-cy Wu --- .../net/wireless/mediatek/mt76/mt7921/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/regd.c | 30 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7921/regd.h | 2 ++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index af5d16055396..b3f29ebf4015 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -808,7 +808,7 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) out: if (vif->bss_conf.chanreq.oper.chan->band == 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); } 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 f122e418d825..f923af1440d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -71,36 +71,44 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) } } -int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, - enum environment_cap country_ie_env) +/* Internal version that assumes mutex is already held by caller */ +int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) { struct mt76_dev *mdev = &dev->mt76; struct ieee80211_hw *hw = mdev->hw; struct wiphy *wiphy = hw->wiphy; int ret = 0; - dev->regd_in_progress = true; - - mt792x_mutex_acquire(dev); if (!dev->regd_change) - goto err; + return 0; ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env); if (ret < 0) - goto err; + return ret; mt7921_regd_channel_update(wiphy, dev); ret = mt76_connac_mcu_set_channel_domain(hw->priv); if (ret < 0) - goto err; + return ret; ret = mt7921_set_tx_sar_pwr(hw, NULL); - if (ret < 0) - goto err; -err: + return ret; +} + +int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) +{ + int ret = 0; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + ret = __mt7921_mcu_regd_update(dev, alpha2, country_ie_env); mt792x_mutex_release(dev); + dev->regd_change = false; dev->regd_in_progress = false; wake_up(&dev->wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h index 571f31629e9e..5b24d0902c36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -10,6 +10,8 @@ struct regulatory_request; 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, struct regulatory_request *request); bool mt7921_regd_clc_supported(struct mt792x_dev *dev); -- 2.45.2