This is the last patchset to support MCC. It includes patch 1/4 to correct
start time of NoA, and patch 2/4 is to treat remain-on-channel and hardware
scan, which are also to set/switch channels. To prevent interference,
stop firmware MCC switching when driver receive these two kinds of request.
Then, we declare 8852c can support two channel context, and update
interface combination to support MCC of STA + P2P.
<<< Below commit message is kept as first patchset for reference >>>
TDMA-based MCC (STA+P2P) is a kind of multiple interfaces concurrence.
Basically, driver is to calculate timeslot pattern and firmware follows
the pattern to switch channels. Since BT-coexistence is also a TDMA-based
mechanism, also consider BT timeslot into pattern if BT devices present.
To easier to review these 20+ patches, I summary basic purpose of these
patches below by group, and submit them by small patchset one by one.
Group 1. [DONE] get BT timeslot from coex mechanism
Group 2. [DONE] adjust some stuff related to driver channel context
Group 3. [DONE] P2P NoA infrastructure to add the IE to beacon when playing GO
Group 4. [DONE] adjust driver to support 2 channel context
Group 5. [DONE] calculate timeslot patterns and trigger firmware to switch
channels followed the patterns
Group 6. [DONE] disable some dynamic tracking mechanism of RF calibration when
MCC is running.
Group 7. [DONE] monitor states and adjust timeslot patterns. For example, if
BT device leaves, we can reassign the slot to WiFi.
Group 8. [CURRNET] Remain-on-channel and hardware scan are related to channel
context, so need some treatments to work with MCC properly.
Group 9. [CURRENT] Finally, we declare 8852C to support MCC
Zong-Zhe Yang (4):
wifi: rtw89: mcc: fix NoA start time when GO is auxiliary
wifi: rtw89: pause/proceed MCC for ROC and HW scan
wifi: rtw89: 8852c: declare to support two chanctx
wifi: rtw89: declare MCC in interface combination
drivers/net/wireless/realtek/rtw89/chan.c | 74 +++++++++++++++++++
drivers/net/wireless/realtek/rtw89/chan.h | 8 ++
drivers/net/wireless/realtek/rtw89/core.c | 29 +++++++-
drivers/net/wireless/realtek/rtw89/core.h | 1 +
drivers/net/wireless/realtek/rtw89/fw.c | 4 +-
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +-
6 files changed, 113 insertions(+), 5 deletions(-)
--
2.25.1
From: Zong-Zhe Yang <[email protected]>
Under TDMA-based MCC (multi-channel concurrency), there are two roles,
reference and auxiliary. We arrange MCC timeline based on time domain
of reference role. Then, we calculate NoA start time according to MCC
timeline.
Besides, when MCC runs GO+STA mode, we plan an offset between GO time
domain and STA time domain to make their TBTTs have a time gap.
However, if GO is auxiliary role instead of reference role, NoA start
time is described by STA time domain instead of GO time domain. To fix
this, we apply the offset mentioned above to NoA start time to convert
time domain from STA to GO.
Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/chan.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index fb68d7f8ec3a..5564067c45cc 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -1430,6 +1430,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_sync *sync = &config->sync;
struct ieee80211_p2p_noa_desc noa_desc = {};
u64 start_time = config->start_tsf;
u32 interval = config->mcc_interval;
@@ -1449,6 +1450,9 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
ieee80211_tu_to_usec(config->beacon_offset) +
ieee80211_tu_to_usec(pattern->toa_aux);
duration = config->mcc_interval - aux->duration;
+
+ /* convert time domain from sta(ref) to GO(aux) */
+ start_time += ieee80211_tu_to_usec(sync->offset);
} else {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC find no GO: skip updating beacon NoA\n");
--
2.25.1
From: Zong-Zhe Yang <[email protected]>
MCC (multi-channel concurrency) supports two combinations as below.
* P2P-GO + STA
* P2P-GC + STA
We add the corresponding ieee80211_iface_limit for it into
ieee80211_iface_combination.
Besides, for multiple channels, it must run with mac80211 chanctx.
So, only with it, ieee80211_iface_combination can allow MCC case.
Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/core.c | 26 +++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index ac5a4b0d8282..27770064f1b0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -172,13 +172,31 @@ static const struct ieee80211_iface_limit rtw89_iface_limits[] = {
},
};
+static const struct ieee80211_iface_limit rtw89_iface_limits_mcc[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+};
+
static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
{
.limits = rtw89_iface_limits,
.n_limits = ARRAY_SIZE(rtw89_iface_limits),
.max_interfaces = 2,
.num_different_channels = 1,
- }
+ },
+ {
+ .limits = rtw89_iface_limits_mcc,
+ .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc),
+ .max_interfaces = 2,
+ .num_different_channels = 2,
+ },
};
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate)
@@ -4279,7 +4297,11 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
goto err;
hw->wiphy->iface_combinations = rtw89_iface_combs;
- hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw89_iface_combs);
+
+ if (no_chanctx || chip->support_chanctx_num == 1)
+ hw->wiphy->n_iface_combinations = 1;
+ else
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw89_iface_combs);
rtwdev = hw->priv;
rtwdev->hw = hw;
--
2.25.1
From: Zong-Zhe Yang <[email protected]>
We are going to allow RTL8852C to support MCC (multi-channel concurrency).
So, we increase 8852c::support_chanctx_num up to 2.
Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 9c38612eb068..7eba44a0b4e5 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2853,7 +2853,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.dig_table = NULL,
.dig_regs = &rtw8852c_dig_regs,
.tssi_dbw_table = &rtw89_8852c_tssi_dbw_table,
- .support_chanctx_num = 1,
+ .support_chanctx_num = 2,
.support_bands = BIT(NL80211_BAND_2GHZ) |
BIT(NL80211_BAND_5GHZ) |
BIT(NL80211_BAND_6GHZ),
--
2.25.1
From: Zong-Zhe Yang <[email protected]>
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 <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/chan.c | 70 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/chan.h | 8 +++
drivers/net/wireless/realtek/rtw89/core.c | 3 +-
drivers/net/wireless/realtek/rtw89/core.h | 1 +
drivers/net/wireless/realtek/rtw89/fw.c | 4 +-
5 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 5564067c45cc..5ef250439bf9 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -190,6 +190,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);
@@ -206,6 +207,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:
@@ -240,6 +243,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;
}
@@ -1721,6 +1727,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);
@@ -1801,10 +1812,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:
@@ -1815,6 +1830,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 362aa0922339..ac5a4b0d8282 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 08fa83995e17..d5c67708d639 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3889,6 +3889,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 0f6ac26870b5..33ebe2721fd2 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -3932,6 +3932,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,
@@ -3963,7 +3965,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)
--
2.25.1
Ping-Ke Shih <[email protected]> wrote:
> From: Zong-Zhe Yang <[email protected]>
>
> Under TDMA-based MCC (multi-channel concurrency), there are two roles,
> reference and auxiliary. We arrange MCC timeline based on time domain
> of reference role. Then, we calculate NoA start time according to MCC
> timeline.
>
> Besides, when MCC runs GO+STA mode, we plan an offset between GO time
> domain and STA time domain to make their TBTTs have a time gap.
>
> However, if GO is auxiliary role instead of reference role, NoA start
> time is described by STA time domain instead of GO time domain. To fix
> this, we apply the offset mentioned above to NoA start time to convert
> time domain from STA to GO.
>
> Signed-off-by: Zong-Zhe Yang <[email protected]>
> Signed-off-by: Ping-Ke Shih <[email protected]>
4 patches applied to wireless-next.git, thanks.
a4d7c872eb87 wifi: rtw89: mcc: fix NoA start time when GO is auxiliary
5f499ce69b8d wifi: rtw89: pause/proceed MCC for ROC and HW scan
0f93824ed720 wifi: rtw89: 8852c: declare to support two chanctx
8e73c0455b12 wifi: rtw89: declare MCC in interface combination
--
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches