wifi: rtw89: introduce rtw89_query_mr_chanctx_info() for multi-role chanctx info

Add Wi-Fi 7 MLO related multi-role (MR) chanctx descriptors and query
function. They are designed for other components, e.g. coex, which are
interested in the following info.
 * whether a MLD exists and how many active link
 * the number of AP mode and station mode respectively
 * how many chanctx and the number of 2/5/6 GHz respectively

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250611035523.36432-2-pkshih@realtek.com
This commit is contained in:
Zong-Zhe Yang 2025-06-11 11:55:14 +08:00 committed by Ping-Ke Shih
parent 3db8563bac
commit cbaf1110af
2 changed files with 240 additions and 0 deletions

View File

@ -2714,6 +2714,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;

View File

@ -44,6 +44,49 @@
#define NUM_OF_RTW89_MCC_ROLES 2
enum rtw89_mr_wtype {
RTW89_MR_WTYPE_NONE,
RTW89_MR_WTYPE_NONMLD,
RTW89_MR_WTYPE_MLD1L1R,
RTW89_MR_WTYPE_MLD2L1R,
RTW89_MR_WTYPE_MLD2L2R,
RTW89_MR_WTYPE_NONMLD_NONMLD,
RTW89_MR_WTYPE_MLD1L1R_NONMLD,
RTW89_MR_WTYPE_MLD2L1R_NONMLD,
RTW89_MR_WTYPE_MLD2L2R_NONMLD,
RTW89_MR_WTYPE_UNKNOWN,
};
enum rtw89_mr_wmode {
RTW89_MR_WMODE_NONE,
RTW89_MR_WMODE_1CLIENT,
RTW89_MR_WMODE_1AP,
RTW89_MR_WMODE_1AP_1CLIENT,
RTW89_MR_WMODE_2CLIENTS,
RTW89_MR_WMODE_2APS,
RTW89_MR_WMODE_UNKNOWN,
};
enum rtw89_mr_ctxtype {
RTW89_MR_CTX_NONE,
RTW89_MR_CTX1_2GHZ,
RTW89_MR_CTX1_5GHZ,
RTW89_MR_CTX1_6GHZ,
RTW89_MR_CTX2_2GHZ,
RTW89_MR_CTX2_5GHZ,
RTW89_MR_CTX2_6GHZ,
RTW89_MR_CTX2_2GHZ_5GHZ,
RTW89_MR_CTX2_2GHZ_6GHZ,
RTW89_MR_CTX2_5GHZ_6GHZ,
RTW89_MR_CTX_UNKNOWN,
};
struct rtw89_mr_chanctx_info {
enum rtw89_mr_wtype wtype;
enum rtw89_mr_wmode wmode;
enum rtw89_mr_ctxtype ctxtype;
};
enum rtw89_chanctx_pause_reasons {
RTW89_CHANCTX_PAUSE_REASON_HW_SCAN,
RTW89_CHANCTX_PAUSE_REASON_ROC,
@ -120,6 +163,8 @@ void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work);
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_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx,
struct rtw89_mr_chanctx_info *info);
void rtw89_chanctx_track(struct rtw89_dev *rtwdev);
void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
const struct rtw89_chanctx_pause_parm *parm);