summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.c124
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.h5
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c68
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h27
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.c14
6 files changed, 219 insertions, 23 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 4663db4ce2f6..e1bc3606f9ae 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -4,6 +4,8 @@
#include "chan.h"
#include "debug.h"
+#include "fw.h"
+#include "ps.h"
#include "util.h"
static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
@@ -116,6 +118,7 @@ bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
rcd->prev_primary_channel = chan->primary_channel;
rcd->prev_band_type = chan->band_type;
band_changed = new->band_type != chan->band_type;
+ rcd->band_changed = band_changed;
*chan = *new;
return band_changed;
@@ -193,8 +196,12 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev)
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
+ const struct cfg80211_chan_def *chandef;
enum rtw89_entity_mode mode;
+ struct rtw89_chan chan;
u8 weight;
+ u8 last;
+ u8 idx;
weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
switch (weight) {
@@ -206,14 +213,121 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
rtw89_config_default_chandef(rtwdev);
fallthrough;
case 1:
+ last = RTW89_SUB_ENTITY_0;
mode = RTW89_ENTITY_MODE_SCC;
break;
+ case 2:
+ last = RTW89_SUB_ENTITY_1;
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ break;
+
+ mode = RTW89_ENTITY_MODE_MCC_PREPARE;
+ break;
+ }
+
+ for (idx = 0; idx <= last; idx++) {
+ chandef = rtw89_chandef_get(rtwdev, idx);
+ rtw89_get_channel_params(chandef, &chan);
+ if (chan.channel == 0) {
+ WARN(1, "Invalid channel on chanctx %d\n", idx);
+ return RTW89_ENTITY_MODE_INVALID;
+ }
+
+ rtw89_assign_entity_chan(rtwdev, idx, &chan);
}
rtw89_set_entity_mode(rtwdev, mode);
return mode;
}
+static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_state state)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
+ int i;
+
+ if (!listener)
+ return;
+
+ for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
+ if (!listener->callbacks[i])
+ continue;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "chanctx notify listener: cb %d, state %d\n",
+ i, state);
+
+ listener->callbacks[i](rtwdev, state);
+ }
+}
+
+static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
+{
+ if (rtwdev->scanning)
+ rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
+ rtw89_leave_lps(rtwdev);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n");
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);
+ return 0;
+}
+
+static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n");
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
+}
+
+void rtw89_chanctx_work(struct work_struct *work)
+{
+ struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
+ chanctx_work.work);
+ enum rtw89_entity_mode mode;
+ int ret;
+
+ mutex_lock(&rtwdev->mutex);
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC);
+ rtw89_set_channel(rtwdev);
+
+ ret = rtw89_mcc_start(rtwdev);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_entity_mode mode;
+ u32 delay;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ default:
+ return;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
+ break;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "queue chanctx work for mode %d with delay %d us\n",
+ mode, delay);
+ ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work,
+ usecs_to_jiffies(delay));
+}
+
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx)
{
@@ -238,6 +352,7 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ enum rtw89_entity_mode mode;
struct rtw89_vif *rtwvif;
u8 drop, roll;
@@ -267,6 +382,15 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
drop = roll;
out:
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC:
+ rtw89_mcc_stop(rtwdev);
+ break;
+ default:
+ break;
+ }
+
clear_bit(drop, hal->entity_map);
rtw89_set_channel(rtwdev);
}
diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h
index bdf369db5041..448e6c5df9f1 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.h
+++ b/drivers/net/wireless/realtek/rtw89/chan.h
@@ -7,6 +7,9 @@
#include "core.h"
+/* The dwell time in TU before doing rtw89_chanctx_work(). */
+#define RTW89_CHANCTX_TIME_MCC_PREPARE 100
+
static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -50,6 +53,8 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
const struct cfg80211_chan_def *chandef);
void rtw89_entity_init(struct rtw89_dev *rtwdev);
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev);
+void rtw89_chanctx_work(struct work_struct *work);
+void rtw89_queue_chanctx_work(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 91f9a587220b..92fbbcd5dd3f 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -256,8 +256,8 @@ void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef)
NL80211_CHAN_NO_HT);
}
-static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
- struct rtw89_chan *chan)
+void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
+ struct rtw89_chan *chan)
{
struct ieee80211_channel *channel = chandef->chan;
enum nl80211_chan_width width = chandef->width;
@@ -318,9 +318,11 @@ static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_chan *chan;
enum rtw89_sub_entity_idx sub_entity_idx;
+ enum rtw89_sub_entity_idx roc_idx;
enum rtw89_phy_idx phy_idx;
enum rtw89_entity_mode mode;
bool entity_active;
@@ -330,10 +332,23 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
return;
mode = rtw89_get_entity_mode(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
+ switch (mode) {
+ case RTW89_ENTITY_MODE_SCC:
+ case RTW89_ENTITY_MODE_MCC:
+ sub_entity_idx = RTW89_SUB_ENTITY_0;
+ break;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ sub_entity_idx = RTW89_SUB_ENTITY_1;
+ break;
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
return;
+ }
+
+ roc_idx = atomic_read(&hal->roc_entity_idx);
+ if (roc_idx != RTW89_SUB_ENTITY_IDLE)
+ sub_entity_idx = roc_idx;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
phy_idx = RTW89_PHY_0;
chan = rtw89_chan_get(rtwdev, sub_entity_idx);
chip->ops->set_txpwr(rtwdev, chan, phy_idx);
@@ -341,43 +356,54 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
void rtw89_set_channel(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct cfg80211_chan_def *chandef;
+ const struct rtw89_chan_rcd *chan_rcd;
+ const struct rtw89_chan *chan;
enum rtw89_sub_entity_idx sub_entity_idx;
+ enum rtw89_sub_entity_idx roc_idx;
enum rtw89_mac_idx mac_idx;
enum rtw89_phy_idx phy_idx;
- struct rtw89_chan chan;
struct rtw89_channel_help_params bak;
enum rtw89_entity_mode mode;
- bool band_changed;
bool entity_active;
entity_active = rtw89_get_entity_state(rtwdev);
mode = rtw89_entity_recalc(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
+ switch (mode) {
+ case RTW89_ENTITY_MODE_SCC:
+ case RTW89_ENTITY_MODE_MCC:
+ sub_entity_idx = RTW89_SUB_ENTITY_0;
+ break;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ sub_entity_idx = RTW89_SUB_ENTITY_1;
+ break;
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
return;
+ }
+
+ roc_idx = atomic_read(&hal->roc_entity_idx);
+ if (roc_idx != RTW89_SUB_ENTITY_IDLE)
+ sub_entity_idx = roc_idx;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
mac_idx = RTW89_MAC_0;
phy_idx = RTW89_PHY_0;
- chandef = rtw89_chandef_get(rtwdev, sub_entity_idx);
- rtw89_get_channel_params(chandef, &chan);
- if (WARN(chan.channel == 0, "Invalid channel\n"))
- return;
- band_changed = rtw89_assign_entity_chan(rtwdev, sub_entity_idx, &chan);
+ chan = rtw89_chan_get(rtwdev, sub_entity_idx);
+ chan_rcd = rtw89_chan_rcd_get(rtwdev, sub_entity_idx);
- rtw89_chip_set_channel_prepare(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx);
- chip->ops->set_channel(rtwdev, &chan, mac_idx, phy_idx);
+ chip->ops->set_channel(rtwdev, chan, mac_idx, phy_idx);
- chip->ops->set_txpwr(rtwdev, &chan, phy_idx);
+ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
- rtw89_chip_set_channel_done(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ rtw89_chip_set_channel_done(rtwdev, &bak, chan, mac_idx, phy_idx);
- if (!entity_active || band_changed) {
- rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan.band_type);
+ if (!entity_active || chan_rcd->band_changed) {
+ rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan->band_type);
rtw89_chip_rfk_band_changed(rtwdev, phy_idx);
}
@@ -3562,6 +3588,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
cancel_work_sync(&btc->icmp_notify_work);
cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
cancel_delayed_work_sync(&rtwdev->track_work);
+ cancel_delayed_work_sync(&rtwdev->chanctx_work);
cancel_delayed_work_sync(&rtwdev->coex_act1_work);
cancel_delayed_work_sync(&rtwdev->coex_bt_devinfo_work);
cancel_delayed_work_sync(&rtwdev->coex_rfk_chk_work);
@@ -3598,6 +3625,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work);
+ INIT_DELAYED_WORK(&rtwdev->chanctx_work, rtw89_chanctx_work);
INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
INIT_DELAYED_WORK(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work);
INIT_DELAYED_WORK(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 431b0d3daa2a..284d8f7a7a0c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -789,6 +789,7 @@ enum rtw89_phy_idx {
enum rtw89_sub_entity_idx {
RTW89_SUB_ENTITY_0 = 0,
+ RTW89_SUB_ENTITY_1 = 1,
NUM_OF_RTW89_SUB_ENTITY,
RTW89_SUB_ENTITY_IDLE = NUM_OF_RTW89_SUB_ENTITY,
@@ -900,6 +901,7 @@ struct rtw89_chan {
struct rtw89_chan_rcd {
u8 prev_primary_channel;
enum rtw89_band prev_band_type;
+ bool band_changed;
};
struct rtw89_channel_help_params {
@@ -3413,6 +3415,22 @@ struct rtw89_antdiv_info {
bool get_stats;
};
+enum rtw89_chanctx_state {
+ RTW89_CHANCTX_STATE_MCC_START,
+ RTW89_CHANCTX_STATE_MCC_STOP,
+};
+
+enum rtw89_chanctx_callbacks {
+ RTW89_CHANCTX_CALLBACK_PLACEHOLDER,
+
+ NUM_OF_RTW89_CHANCTX_CALLBACKS,
+};
+
+struct rtw89_chanctx_listener {
+ void (*callbacks[NUM_OF_RTW89_CHANCTX_CALLBACKS])
+ (struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state);
+};
+
struct rtw89_chip_info {
enum rtw89_core_chip_id chip_id;
enum rtw89_chip_gen chip_gen;
@@ -3472,6 +3490,7 @@ struct rtw89_chip_info {
/* NULL if no rfe-specific, or a null-terminated array by rfe_parms */
const struct rtw89_rfe_parms_conf *rfe_parms_conf;
const struct rtw89_rfe_parms *dflt_parms;
+ const struct rtw89_chanctx_listener *chanctx_listener;
u8 txpwr_factor_rf;
u8 txpwr_factor_mac;
@@ -3751,6 +3770,11 @@ struct rtw89_chanctx_cfg {
enum rtw89_entity_mode {
RTW89_ENTITY_MODE_SCC,
+ RTW89_ENTITY_MODE_MCC_PREPARE,
+ RTW89_ENTITY_MODE_MCC,
+
+ NUM_OF_RTW89_ENTITY_MODE,
+ RTW89_ENTITY_MODE_INVALID = NUM_OF_RTW89_ENTITY_MODE,
};
struct rtw89_sub_entity {
@@ -4407,6 +4431,7 @@ struct rtw89_dev {
struct rtw89_antdiv_info antdiv;
struct delayed_work track_work;
+ struct delayed_work chanctx_work;
struct delayed_work coex_act1_work;
struct delayed_work coex_bt_devinfo_work;
struct delayed_work coex_rfk_chk_work;
@@ -5341,6 +5366,8 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev);
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev);
void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef);
+void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
+ struct rtw89_chan *chan);
void rtw89_set_channel(struct rtw89_dev *rtwdev);
void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_chan *chan);
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 7c3066c0a550..c9ed369015fe 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -414,6 +414,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif);
rtw89_mac_port_update(rtwdev, rtwvif);
rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif);
+
+ rtw89_queue_chanctx_work(rtwdev);
} else {
/* Abort ongoing scan if cancel_scan isn't issued
* when disconnected by peer
@@ -477,6 +479,8 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
rtw89_chip_rfk_channel(rtwdev);
+
+ rtw89_queue_chanctx_work(rtwdev);
mutex_unlock(&rtwdev->mutex);
return 0;
diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c
index b98ec178abe1..917c01e5e9ed 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.c
+++ b/drivers/net/wireless/realtek/rtw89/ps.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include "chan.h"
#include "coex.h"
#include "core.h"
#include "debug.h"
@@ -257,8 +258,13 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
{
struct ieee80211_vif *vif, *found_vif = NULL;
struct rtw89_vif *rtwvif;
+ enum rtw89_entity_mode mode;
int count = 0;
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ goto disable_lps;
+
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
@@ -273,10 +279,12 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
if (count == 1 && found_vif->cfg.ps) {
rtwdev->lps_enabled = true;
- } else {
- rtw89_leave_lps(rtwdev);
- rtwdev->lps_enabled = false;
+ return;
}
+
+disable_lps:
+ rtw89_leave_lps(rtwdev);
+ rtwdev->lps_enabled = false;
}
void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)