This is a note to let you know that I've just added the patch titled wifi: rtw89: chan: manage active interfaces to the 6.12-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: wifi-rtw89-chan-manage-active-interfaces.patch and it can be found in the queue-6.12 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit f3a00b47abfb5da3ccd68c258c60f61077ac77aa Author: Zong-Zhe Yang <kevin_yang@xxxxxxxxxxx> Date: Tue Oct 22 16:31:04 2024 +0800 wifi: rtw89: chan: manage active interfaces [ Upstream commit 68ec751b288178de7d19b71ea61648269a35b8cd ] To set channel well for combination of MCC (multi-channel concurrency) and impending MLO support, we need a method to manage relation between active interfaces and channel contexts. If an interface owns at least one active link, we call it an active interface. We add a list to manage active ones. Basically, the list follows the active order except for the below case. To be compatible with legacy behavior, the first interface that owns the first channel context will put at the first entry in the list when recalculating. Besides, MCC can also select and fill roles based on the above active list. Signed-off-by: Zong-Zhe Yang <kevin_yang@xxxxxxxxxxx> Signed-off-by: Ping-Ke Shih <pkshih@xxxxxxxxxxx> Link: https://patch.msgid.link/20241022083106.149252-4-pkshih@xxxxxxxxxxx Stable-dep-of: e47f0a589854 ("wifi: rtw89: fix proceeding MCC with wrong scanning state after sequence changes") Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index ba6332da8019c..2b7e6921ff9c6 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -10,6 +10,10 @@ #include "ps.h" #include "util.h" +static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx1, + enum rtw89_chanctx_idx idx2); + static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band, u8 center_chan) { @@ -226,11 +230,15 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) void rtw89_entity_init(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; hal->entity_pause = false; bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX); bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE); + + INIT_LIST_HEAD(&mgnt->active_list); + rtw89_config_default_chandef(rtwdev); } @@ -272,6 +280,71 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, } } +static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_vif_link *cur; + + if (unlikely(!rtwvif_link->chanctx_assigned)) + return; + + cur = rtw89_vif_get_link_inst(rtwvif, 0); + if (!cur || !cur->chanctx_assigned) + return; + + if (cur == rtwvif_link) + return; + + rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx); +} + +static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + struct rtw89_vif_link *link; + struct rtw89_vif *role; + u8 pos = 0; + int i; + + lockdep_assert_held(&rtwdev->mutex); + + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) + mgnt->active_roles[i] = NULL; + + /* To be consistent with legacy behavior, expect the first active role + * which uses RTW89_CHANCTX_0 to put at position 0, and make its first + * link instance take RTW89_CHANCTX_0. (normalizing) + */ + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + for (i = 0; i < role->links_inst_valid_num; i++) { + link = rtw89_vif_get_link_inst(role, i); + if (!link || !link->chanctx_assigned) + continue; + + if (link->chanctx_idx == RTW89_CHANCTX_0) { + rtw89_normalize_link_chanctx(rtwdev, link); + + list_del(&role->mgnt_entry); + list_add(&role->mgnt_entry, &mgnt->active_list); + break; + } + } + } + + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) { + rtw89_warn(rtwdev, + "%s: active roles are over max iface num\n", + __func__); + break; + } + + mgnt->active_roles[pos++] = role; + } +} + enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) { DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {}; @@ -327,6 +400,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) rtw89_assign_entity_chan(rtwdev, idx, &chan); } + rtw89_entity_recalc_mgnt_roles(rtwdev); + if (hal->entity_pause) return rtw89_get_entity_mode(rtwdev); @@ -716,6 +791,7 @@ struct rtw89_mcc_fill_role_selector { }; static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES); +static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES); static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role, @@ -745,14 +821,18 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_mcc_fill_role_selector sel = {}; struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; int ret; + int i; - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (!rtw89_vif_is_active_role(rtwvif)) - continue; + for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) { + rtwvif = mgnt->active_roles[i]; + if (!rtwvif) + break; rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); if (unlikely(!rtwvif_link)) { @@ -760,14 +840,7 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) continue; } - if (sel.bind_vif[rtwvif_link->chanctx_idx]) { - rtw89_warn(rtwdev, - "MCC skip extra vif <macid %d> on chanctx[%d]\n", - rtwvif_link->mac_id, rtwvif_link->chanctx_idx); - continue; - } - - sel.bind_vif[rtwvif_link->chanctx_idx] = rtwvif_link; + sel.bind_vif[i] = rtwvif_link; } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -2501,12 +2574,18 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_entity_weight w = {}; rtwvif_link->chanctx_idx = cfg->idx; rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (list_empty(&rtwvif->mgnt_entry)) + list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); + if (cfg->idx == RTW89_CHANCTX_0) goto out; @@ -2526,6 +2605,7 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_chanctx_idx roll; enum rtw89_entity_mode cur; @@ -2536,6 +2616,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (!rtw89_vif_is_active_role(rtwvif)) + list_del_init(&rtwvif->mgnt_entry); + if (cfg->ref_count != 0) goto out; diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 37d2bcba1b315..e864da4d37519 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -192,13 +192,13 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = { { .limits = rtw89_iface_limits, .n_limits = ARRAY_SIZE(rtw89_iface_limits), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 1, }, { .limits = rtw89_iface_limits_mcc, .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 2, }, }; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 0ed31b37d10fe..65ad3d03d0530 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4628,6 +4628,14 @@ enum rtw89_entity_mode { RTW89_ENTITY_MODE_UNHANDLED = -ESRCH, }; +#define RTW89_MAX_INTERFACE_NUM 2 + +/* only valid when running with chanctx_ops */ +struct rtw89_entity_mgnt { + struct list_head active_list; + struct rtw89_vif *active_roles[RTW89_MAX_INTERFACE_NUM]; +}; + struct rtw89_chanctx { struct cfg80211_chan_def chandef; struct rtw89_chan chan; @@ -4671,6 +4679,7 @@ struct rtw89_hal { bool entity_active[RTW89_PHY_MAX]; bool entity_pause; enum rtw89_entity_mode entity_mode; + struct rtw89_entity_mgnt entity_mgnt; struct rtw89_edcca_bak edcca_bak; u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ @@ -5607,6 +5616,7 @@ struct rtw89_dev { struct rtw89_vif { struct rtw89_dev *rtwdev; struct list_head list; + struct list_head mgnt_entry; u8 mac_addr[ETH_ALEN]; __be32 ip_addr; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 13fb3cac27016..299566e2f612d 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -192,6 +192,8 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); + INIT_LIST_HEAD(&rtwvif->mgnt_entry); + ether_addr_copy(rtwvif->mac_addr, vif->addr); rtwvif->offchan = false;