wifi: rtw89: pause/proceed MCC for ROC and HW scan
authorZong-Zhe Yang <kevin_yang@realtek.com>
Thu, 21 Sep 2023 00:35:57 +0000 (08:35 +0800)
committerKalle Valo <kvalo@kernel.org>
Thu, 28 Sep 2023 16:25:04 +0000 (19:25 +0300)
During (TDMA-based) MCC (multi-channel concurrency), the below two
cases might not have a good behavior on channel usage.
* ROC (remain on channel)
* HW scan
So, we tend to separate them from MCC.

The two cases would expect to operate the channel to which they want.
However, during MCC, channels are scheduled by FW MCC state mechanism.
So, channels cannot be controlled explicitly. To avoid the two cases
from operating wrong channels with chance, we pause MCC (essentially
stop FW MCC) once the two cases are coming. And then, we proceed MCC
again (essentially restart FW MCC) once the two cases finish.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230921003559.11588-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/chan.c
drivers/net/wireless/realtek/rtw89/chan.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c

index e03c84953fb81c3eebc74f4e9c0c9deb9274ba27..cbf6821af6b8ae2ccca8a51e159e473a5c5d5804 100644 (file)
@@ -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)
 {
index 9fd46f5c37b9106847d0d3654818c707164a8b6c..9b98d8f4ee9dab417c16fcac93e01afcb0c7edc9 100644 (file)
 
 #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,
index 03704c4752a5b6f28f15f38506f791a28764bf6e..50854b63e11b32e767a2912bbf8ec7bcbd5f619c 100644 (file)
@@ -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,
index ac09785c21a603c3794bb03eb59932ac6cf1a522..56cf47f2ae2b6e22e729531eb4c359caa1efe0ad 100644 (file)
@@ -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;
index f5e7475af38172e85a861e3b1f11332167a25b85..7cfcf536d6fe7692f855555861d8a7317d2bd3a0 100644 (file)
@@ -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)