diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/chan.c')
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/chan.c | 557 |
1 files changed, 544 insertions, 13 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 806f42429a29..f7d1c5d3b92e 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -7,6 +7,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "phy.h" #include "ps.h" #include "sar.h" #include "util.h" @@ -128,6 +129,48 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, bandwidth); } +static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_chan_def *chandef) +{ + struct ieee80211_bss_conf *bss_conf; + + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->eht_support) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured); +} + +static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx, + const struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned || + rtwvif_link->chanctx_idx != idx) + continue; + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef); + } + } +} + bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct rtw89_chan *new) @@ -170,22 +213,26 @@ int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev, static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, - const struct cfg80211_chan_def *chandef, - bool from_stack) + const struct cfg80211_chan_def *chandef) { struct rtw89_hal *hal = &rtwdev->hal; hal->chanctx[idx].chandef = *chandef; - - if (from_stack) - set_bit(idx, hal->entity_map); } void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct cfg80211_chan_def *chandef) { - __rtw89_config_entity_chandef(rtwdev, idx, chandef, true); + struct rtw89_hal *hal = &rtwdev->hal; + + if (!chandef) { + clear_bit(idx, hal->entity_map); + return; + } + + __rtw89_config_entity_chandef(rtwdev, idx, chandef); + set_bit(idx, hal->entity_map); } void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, @@ -227,7 +274,7 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) struct cfg80211_chan_def chandef = {0}; rtw89_get_default_chandef(&chandef); - __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef, false); + __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef); } void rtw89_entity_init(struct rtw89_dev *rtwdev) @@ -265,6 +312,8 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif; int idx; + w->registered_chanctxs = bitmap_weight(hal->entity_map, NUM_OF_RTW89_CHANCTX); + for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) { cfg = hal->chanctx[idx].cfg; if (!cfg) { @@ -473,7 +522,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX); fallthrough; case 0: - rtw89_config_default_chandef(rtwdev); + if (!w.registered_chanctxs) + rtw89_config_default_chandef(rtwdev); set_bit(RTW89_CHANCTX_0, recalc_map); fallthrough; case 1: @@ -953,6 +1003,7 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) } sel.bind_vif[i] = rtwvif_link; + rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, NULL); } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -991,6 +1042,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, *pattern = *new; memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc) + aux->ignore_bcn = true; + else + aux->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) { crtz = &pattern->courtesy.ref; ref->crtz = crtz; @@ -1005,6 +1061,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, ref->crtz = NULL; } + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc) + ref->ignore_bcn = true; + else + ref->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) { crtz = &pattern->courtesy.aux; aux->crtz = crtz; @@ -1107,7 +1168,7 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ref = &mcc->role_ref; struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config *config = &mcc->config; - u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME; + u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME; u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME; u16 bcn_ofst = config->beacon_offset; s16 upper_toa_ref, lower_toa_ref; @@ -1263,9 +1324,11 @@ static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, u16 bcn_ofst = config->beacon_offset; bool small_bcn_ofst; - if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) + small_bcn_ofst = true; + else if (bcn_ofst < aux->duration - aux->limit.max_toa) small_bcn_ofst = true; - else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = false; else return -EPERM; @@ -1595,6 +1658,35 @@ static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev) return false; } +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + mcc_prepare_done_work.work); + + lockdep_assert_wiphy(wiphy); + + ieee80211_wake_queues(rtwdev->hw); +} + +static void rtw89_mcc_prepare(struct rtw89_dev *rtwdev, bool start) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_config *config = &mcc->config; + + if (start) { + ieee80211_stop_queues(rtwdev->hw); + + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, + usecs_to_jiffies(config->prepare_delay)); + } else { + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, 0); + wiphy_delayed_work_flush(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work); + } +} + static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1630,6 +1722,8 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) config->start_tsf = start_tsf; config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf; + config->prepare_delay = start_tsf - tsf; + return 0; } @@ -2129,6 +2223,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) rtw89_p2p_noa_renew(rtwvif_go); if (enable) { + duration += RTW89_MCC_SWITCH_CH_TIME; noa_desc.start_time = cpu_to_le32(start_time); noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval)); noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration)); @@ -2177,6 +2272,18 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev) 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; @@ -2208,6 +2315,15 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) if (ret) return ret; + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); + } else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) { + 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); + } + if (rtw89_concurrent_via_mrc(rtwdev)) ret = __mrc_fw_start(rtwdev, false); else @@ -2219,6 +2335,9 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START); rtw89_mcc_start_beacon_noa(rtwdev); + rtw89_phy_dig_suspend(rtwdev); + + rtw89_mcc_prepare(rtwdev, true); return 0; } @@ -2269,9 +2388,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_stop_sel sel = { .hint.target = pause ? pause->trigger : NULL, }; + bool rsn_scan; int ret; if (!pause) { @@ -2279,6 +2400,12 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); } + rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN; + if (rsn_scan && ref->is_go) + sel.hint.target = ref->rtwvif_link; + else if (rsn_scan && aux->is_go) + sel.hint.target = aux->rtwvif_link; + /* by default, stop at ref */ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel); if (!sel.filled) @@ -2307,12 +2434,20 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); rtw89_mcc_stop_beacon_noa(rtwdev); + rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); + rtw89_phy_dig_resume(rtwdev, true); + + rtw89_mcc_prepare(rtwdev, false); } static int rtw89_mcc_update(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; + bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn; + bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn; struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config old_cfg = *config; bool courtesy_changed; bool sync_changed; @@ -2327,6 +2462,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) if (ret) return ret; + if (old_ref_ignore_bcn != ref->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn); + else if (old_aux_ignore_bcn != aux->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn); + if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy, sizeof(old_cfg.pattern.courtesy)) == 0) courtesy_changed = false; @@ -2362,15 +2502,144 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_role **role = data; + + if (mcc_role->is_gc) + *role = mcc_role; + + return 0; +} + +static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *role = NULL; + + if (mcc->mode != RTW89_MCC_MODE_GC_STA) + return NULL; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role); + + return role; +} + +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + mcc_gc_detect_beacon_work.work); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + enum rtw89_entity_mode mode; + struct rtw89_dev *rtwdev; + + lockdep_assert_wiphy(wiphy); + + rtwdev = rtwvif_link->rtwvif->rtwdev; + + mode = rtw89_get_entity_mode(rtwdev); + if (mode != RTW89_ENTITY_MODE_MCC) + return; + + if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf) + rtwvif_link->detect_bcn_count = 0; + else + rtwvif_link->detect_bcn_count++; + + if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES) + rtw89_chanctx_proceed(rtwdev, NULL); + else + ieee80211_connection_loss(vif); +} + +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); + struct rtw89_chanctx_pause_parm pause_parm = { + .rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, + .trigger = rtwvif_link, + }; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_mcc_role *role; + u16 bcn_int; + + if (mode != RTW89_ENTITY_MODE_MCC) + return false; + + role = rtw89_mcc_get_gc_role(rtwdev); + if (!role) + return false; + + if (role->rtwvif_link != rtwvif_link) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC GC beacon loss, pause MCC to detect GO beacon\n"); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bcn_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + rtw89_chanctx_pause(rtwdev, &pause_parm); + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work, + usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int))); + + return true; +} + +static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *role) +{ + struct ieee80211_vif *vif; + bool start_detect; + 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/GO\n", role->rtwvif_link->mac_id); + + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link); + if (start_detect) + return; + + 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) || aux->ignore_bcn) + rtw89_mcc_detect_connection(rtwdev, aux); + else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) + rtw89_mcc_detect_connection(rtwdev, ref); + if (mcc->mode != RTW89_MCC_MODE_GC_STA) return; @@ -2527,6 +2796,30 @@ static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev) rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL); } +static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_links_info *info = data; + + info->links[ordered_idx] = mcc_role->rtwvif_link; + return 0; +} + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info) +{ + enum rtw89_entity_mode mode; + + memset(info, 0, sizeof(*info)); + + mode = rtw89_get_entity_mode(rtwdev); + if (unlikely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info); +} + void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, @@ -2595,6 +2888,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, return; case RTW89_ENTITY_MODE_MCC_PREPARE: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); + rtw89_phy_dig_suspend(rtwdev); break; case RTW89_ENTITY_MODE_MCC: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC); @@ -2619,6 +2913,201 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT); } +static enum rtw89_mr_wtype __rtw89_query_mr_wtype(struct rtw89_dev *rtwdev) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int num_mld = 0; + unsigned int num_ml = 0; + unsigned int cnt = 0; + u8 role_idx; + u8 idx; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + rtwvif = mgnt->active_roles[role_idx]; + if (!rtwvif) + continue; + + cnt++; + + vif = rtwvif_to_vif(rtwvif); + if (!ieee80211_vif_is_mld(vif)) + continue; + + num_mld++; + + for (idx = 0; idx < __RTW89_MLD_MAX_LINK_NUM; idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][idx]; + if (chanctx_idx != RTW89_CHANCTX_IDLE) + num_ml++; + } + } + + if (num_mld > 1) + goto err; + + switch (cnt) { + case 0: + return RTW89_MR_WTYPE_NONE; + case 1: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R; + case 2: + return RTW89_MR_WTYPE_MLD2L1R; + default: + break; + } + break; + case 2: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R_NONMLD; + case 2: + return RTW89_MR_WTYPE_MLD2L1R_NONMLD; + default: + break; + } + break; + default: + break; + } + +err: + rtw89_warn(rtwdev, "%s: unhandled cnt %u mld %u ml %u\n", __func__, + cnt, num_mld, num_ml); + return RTW89_MR_WTYPE_UNKNOWN; +} + +static enum rtw89_mr_wmode __rtw89_query_mr_wmode(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + unsigned int num[NUM_NL80211_IFTYPES] = {}; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_WMODE_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + rtwvif = mgnt->active_roles[role_idx]; + if (unlikely(!rtwvif)) + continue; + + vif = rtwvif_to_vif(rtwvif); + num[vif->type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_WMODE_NONE; + case 1: + if (num[NL80211_IFTYPE_STATION]) + return RTW89_MR_WMODE_1CLIENT; + if (num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP; + break; + case 2: + if (num[NL80211_IFTYPE_STATION] == 2) + return RTW89_MR_WMODE_2CLIENTS; + if (num[NL80211_IFTYPE_AP] == 2) + return RTW89_MR_WMODE_2APS; + if (num[NL80211_IFTYPE_STATION] && num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP_1CLIENT; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_WMODE_UNKNOWN; +} + +static enum rtw89_mr_ctxtype __rtw89_query_mr_ctxtype(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + DECLARE_BITMAP(map, NUM_OF_RTW89_CHANCTX) = {}; + unsigned int num[RTW89_BAND_NUM] = {}; + enum rtw89_chanctx_idx chanctx_idx; + const struct rtw89_chan *chan; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_CTX_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + if (__test_and_set_bit(chanctx_idx, map)) + continue; + + chan = rtw89_chan_get(rtwdev, chanctx_idx); + num[chan->band_type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_CTX_NONE; + case 1: + if (num[RTW89_BAND_2G]) + return RTW89_MR_CTX1_2GHZ; + if (num[RTW89_BAND_5G]) + return RTW89_MR_CTX1_5GHZ; + if (num[RTW89_BAND_6G]) + return RTW89_MR_CTX1_6GHZ; + break; + case 2: + if (num[RTW89_BAND_2G] == 2) + return RTW89_MR_CTX2_2GHZ; + if (num[RTW89_BAND_5G] == 2) + return RTW89_MR_CTX2_5GHZ; + if (num[RTW89_BAND_6G] == 2) + return RTW89_MR_CTX2_6GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_5G]) + return RTW89_MR_CTX2_2GHZ_5GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_2GHZ_6GHZ; + if (num[RTW89_BAND_5G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_5GHZ_6GHZ; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_CTX_UNKNOWN; +} + +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, + struct rtw89_mr_chanctx_info *info) +{ + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + info->wtype = __rtw89_query_mr_wtype(rtwdev); + info->wmode = __rtw89_query_mr_wmode(rtwdev, inst_idx); + info->ctxtype = __rtw89_query_mr_ctxtype(rtwdev, inst_idx); +} + void rtw89_chanctx_track(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -2782,10 +3271,9 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { - struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; - clear_bit(cfg->idx, hal->entity_map); + rtw89_config_entity_chandef(rtwdev, cfg->idx, NULL); } void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, @@ -2799,6 +3287,9 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); rtw89_set_channel(rtwdev); } + + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + rtw89_chan_update_punctured(rtwdev, idx, &ctx->def); } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, @@ -2816,6 +3307,9 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (list_empty(&rtwvif->mgnt_entry)) list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); @@ -2855,6 +3349,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (!rtw89_vif_is_active_role(rtwvif)) list_del_init(&rtwvif->mgnt_entry); @@ -2906,3 +3403,37 @@ out: break; } } + +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_chanctx_conf *old_ctx, + struct ieee80211_chanctx_conf *new_ctx, + bool replace) +{ + int ret; + + rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx); + + if (!replace) + goto assign; + + rtw89_chanctx_ops_remove(rtwdev, old_ctx); + ret = rtw89_chanctx_ops_add(rtwdev, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n", + __func__, ret); + return ret; + } + +assign: + ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n", + __func__, ret); + return ret; + } + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def); + + return 0; +} |