diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index e03c84953fb8..cbf6821af6b8 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -205,6 +205,7 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; + hal->entity_pause = false; bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); atomic_set(&hal->roc_entity_idx, RTW89_SUB_ENTITY_IDLE); @@ -221,6 +222,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) u8 last; u8 idx; + lockdep_assert_held(&rtwdev->mutex); + weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); switch (weight) { default: @@ -255,6 +258,9 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) rtw89_assign_entity_chan(rtwdev, idx, &chan); } + if (hal->entity_pause) + return rtw89_get_entity_mode(rtwdev); + rtw89_set_entity_mode(rtwdev, mode); return mode; } @@ -1736,6 +1742,11 @@ void rtw89_chanctx_work(struct work_struct *work) mutex_lock(&rtwdev->mutex); + if (hal->entity_pause) { + mutex_unlock(&rtwdev->mutex); + return; + } + for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) { if (test_and_clear_bit(i, hal->changes)) changed |= BIT(i); @@ -1816,10 +1827,14 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) void rtw89_chanctx_track(struct rtw89_dev *rtwdev) { + struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_entity_mode mode; lockdep_assert_held(&rtwdev->mutex); + if (hal->entity_pause) + return; + mode = rtw89_get_entity_mode(rtwdev); switch (mode) { case RTW89_ENTITY_MODE_MCC: @@ -1830,6 +1845,61 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev) } } +void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_pause_reasons rsn) +{ + struct rtw89_hal *hal = &rtwdev->hal; + enum rtw89_entity_mode mode; + + lockdep_assert_held(&rtwdev->mutex); + + if (hal->entity_pause) + return; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", rsn); + + mode = rtw89_get_entity_mode(rtwdev); + switch (mode) { + case RTW89_ENTITY_MODE_MCC: + rtw89_mcc_stop(rtwdev); + break; + default: + break; + } + + hal->entity_pause = true; +} + +void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + enum rtw89_entity_mode mode; + int ret; + + lockdep_assert_held(&rtwdev->mutex); + + if (!hal->entity_pause) + return; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx proceed\n"); + + hal->entity_pause = false; + rtw89_set_channel(rtwdev); + + mode = rtw89_get_entity_mode(rtwdev); + switch (mode) { + case RTW89_ENTITY_MODE_MCC: + ret = rtw89_mcc_start(rtwdev); + if (ret) + rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret); + break; + default: + break; + } + + rtw89_queue_chanctx_work(rtwdev); +} + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 9fd46f5c37b9..9b98d8f4ee9d 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -33,6 +33,11 @@ #define NUM_OF_RTW89_MCC_ROLES 2 +enum rtw89_chanctx_pause_reasons { + RTW89_CHANCTX_PAUSE_REASON_HW_SCAN, + RTW89_CHANCTX_PAUSE_REASON_ROC, +}; + static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -81,6 +86,9 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev); void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, enum rtw89_chanctx_changes change); void rtw89_chanctx_track(struct rtw89_dev *rtwdev); +void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_pause_reasons rsn); +void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev); int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 03704c4752a5..50854b63e11b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2706,6 +2706,7 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); + rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC); ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true); if (ret) @@ -2748,7 +2749,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) roc->state = RTW89_ROC_IDLE; rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, NULL); - rtw89_set_channel(rtwdev); + rtw89_chanctx_proceed(rtwdev); ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ac09785c21a6..56cf47f2ae2b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4018,6 +4018,7 @@ struct rtw89_hal { struct cfg80211_chan_def roc_chandef; bool entity_active; + bool entity_pause; enum rtw89_entity_mode entity_mode; u32 edcca_bak; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f5e7475af381..7cfcf536d6fe 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4011,6 +4011,8 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), B_AX_RX_FLTR_CFG_MASK, rx_fltr); + + rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN); } void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, @@ -4042,7 +4044,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, scan_info->last_chan_idx = 0; scan_info->scanning_vif = NULL; - rtw89_set_channel(rtwdev); + rtw89_chanctx_proceed(rtwdev); } void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)