]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: rtw89: introduce rtw89_query_mr_chanctx_info() for multi-role chanctx info
authorZong-Zhe Yang <kevin_yang@realtek.com>
Wed, 11 Jun 2025 03:55:14 +0000 (11:55 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Mon, 16 Jun 2025 05:49:28 +0000 (13:49 +0800)
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
drivers/net/wireless/realtek/rtw89/chan.c
drivers/net/wireless/realtek/rtw89/chan.h

index 2d4d730c8195d4568cc465d573a60a125dd254d2..6f10235647a170e7bc07760738b6d6ddd0e8f785 100644 (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;
index e0e1fb844304a77cc7a03a2469c8a349e65fb991..57355cb3d765d01062d7e30f5fb42c99c8ad8c40 100644 (file)
 
 #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);