MCC needs to wait at most 300ms to start. Additionally, if
scanning happens before MCC starts, it will miss some beacons,
which might cause beacon loss. Therefore, we reset beacon
filter when MCC start to let hardware reset beacon loss counter.
Additionally, GO is forbid to enter courtesy mode might cause
STA beacon loss. Therefore, disable beacon filter when GO+STA.
However, In WiFi 7 chip, even when GC+STA enable courtesy mode, the
beacon might loss because switching to courtesy timeslot will disable
TX/RX. If the TOB(time offset behind) or TOA(time offset ahead) is
too close to the edge of timeslot, the beacon might not be received.
Therefore, disable beacon filter when GC+STA in WiFi 7 chip.
Because disabling the beacon filter might prevent disconnection
when the AP power-off without sending a deauth. Therefore, driver
TX QOS nulldata periodically to detect the AP status, and the
connection is terminated if no ACK is received for 6 seconds.
Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250610130034.14692-5-pkshih@realtek.com
rtw89_mcc_handle_beacon_noa(rtwdev, false);
}
+static bool rtw89_mcc_ignore_bcn(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
+{
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+
+ if (role->is_go)
+ return true;
+ else if (chip_gen == RTW89_CHIP_BE && role->is_gc)
+ return true;
+ else
+ return false;
+}
+
static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
else
mcc->mode = RTW89_MCC_MODE_GC_STA;
+ if (rtw89_mcc_ignore_bcn(rtwdev, ref)) {
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false);
+ } else if (rtw89_mcc_ignore_bcn(rtwdev, aux)) {
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false);
+ } else {
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true);
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true);
+ }
+
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode);
mcc->group = RTW89_MCC_DFLT_GROUP;
return 0;
}
+static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *role)
+{
+ struct ieee80211_vif *vif;
+ int ret;
+
+ ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false,
+ RTW89_MCC_PROBE_TIMEOUT);
+ if (ret)
+ role->probe_count++;
+ else
+ role->probe_count = 0;
+
+ if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC <macid %d> can not detect AP\n", role->rtwvif_link->mac_id);
+ vif = rtwvif_link_to_vif(role->rtwvif_link);
+ ieee80211_connection_loss(vif);
+}
+
static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
u16 tolerance;
u16 bcn_ofst;
u16 diff;
+ if (rtw89_mcc_ignore_bcn(rtwdev, ref))
+ rtw89_mcc_detect_connection(rtwdev, aux);
+ else if (rtw89_mcc_ignore_bcn(rtwdev, aux))
+ rtw89_mcc_detect_connection(rtwdev, ref);
+
if (mcc->mode != RTW89_MCC_MODE_GC_STA)
return;
#define RTW89_MCC_MIN_RX_BCN_TIME 10
#define RTW89_MCC_DFLT_BCN_OFST_TIME 40
+#define RTW89_MCC_PROBE_TIMEOUT 100
+#define RTW89_MCC_PROBE_MAX_TRIES 3
+
#define RTW89_MCC_MIN_GO_DURATION \
(RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME)
rtwvif_link);
}
-static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
- struct rtw89_vif_link *rtwvif_link, bool qos, bool ps)
+int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ bool qos, bool ps, int timeout)
{
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
rcu_read_unlock();
return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
- RTW89_ROC_TX_TIMEOUT);
+ timeout);
out:
rcu_read_unlock();
pause_parm.trigger = rtwvif_link;
rtw89_chanctx_pause(rtwdev, &pause_parm);
- ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true);
+ ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true,
+ RTW89_ROC_TX_TIMEOUT);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"roc send null-1 failed: %d\n", ret);
roc->state = RTW89_ROC_IDLE;
rtw89_config_roc_chandef(rtwdev, rtwvif_link, NULL);
rtw89_chanctx_proceed(rtwdev, NULL);
- ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false);
+ ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false,
+ RTW89_ROC_TX_TIMEOUT);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"roc send null-0 failed: %d\n", ret);
/* byte-array in LE order for FW */
u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)];
+ u8 probe_count;
u16 duration; /* TU */
u16 beacon_interval; /* TU */
void rtw89_core_stop(struct rtw89_dev *rtwdev);
void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work);
void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work);
+int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ bool qos, bool ps, int timeout);
void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work);
void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);