| From c21cbc5f70b521cf05abb63c63d9a753076adb24 Mon Sep 17 00:00:00 2001 |
| From: Howard Hsu <howard-yh.hsu@mediatek.com> |
| Date: Tue, 2 Jul 2024 10:06:26 +0800 |
| Subject: [PATCH 189/199] mtk: mt76: mt7996: Add Triggered Uplink Access |
| Optimization support |
| |
| Add TUAO feature, which is a subset of SCS procedure support. |
| |
| Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com> |
| --- |
| mt7996/init.c | 25 ++++++++++----- |
| mt7996/mt7996.h | 3 ++ |
| mt7996/mtk_mcu.c | 49 ++++++++++++++++++++++++++++++ |
| mt7996/mtk_mcu.h | 7 +++++ |
| mt7996/vendor.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ |
| mt7996/vendor.h | 17 +++++++++++ |
| 6 files changed, 173 insertions(+), 7 deletions(-) |
| |
| diff --git a/mt7996/init.c b/mt7996/init.c |
| index f1b9b0e0..2f43c0ff 100644 |
| --- a/mt7996/init.c |
| +++ b/mt7996/init.c |
| @@ -62,7 +62,14 @@ static const struct ieee80211_iface_combination if_comb_7992[] = { |
| } |
| }; |
| |
| -static const u8 mt7996_if_types_ext_capa[] = { |
| +static const u8 mt7996_if_types_ext_capa_ap[] = { |
| + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, |
| + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, |
| + [6] = WLAN_EXT_CAPA7_SCS_SUPPORT, |
| + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, |
| +}; |
| + |
| +static const u8 mt7996_if_types_ext_capa_sta[] = { |
| [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, |
| [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, |
| [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, |
| @@ -71,16 +78,16 @@ static const u8 mt7996_if_types_ext_capa[] = { |
| static const struct wiphy_iftype_ext_capab mt7996_iftypes_ext_capa[] = { |
| { |
| .iftype = NL80211_IFTYPE_STATION, |
| - .extended_capabilities = mt7996_if_types_ext_capa, |
| - .extended_capabilities_mask = mt7996_if_types_ext_capa, |
| - .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa), |
| + .extended_capabilities = mt7996_if_types_ext_capa_sta, |
| + .extended_capabilities_mask = mt7996_if_types_ext_capa_sta, |
| + .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa_sta), |
| .mld_capa_and_ops = 2, |
| }, |
| { |
| .iftype = NL80211_IFTYPE_AP, |
| - .extended_capabilities = mt7996_if_types_ext_capa, |
| - .extended_capabilities_mask = mt7996_if_types_ext_capa, |
| - .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa), |
| + .extended_capabilities = mt7996_if_types_ext_capa_ap, |
| + .extended_capabilities_mask = mt7996_if_types_ext_capa_ap, |
| + .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa_ap), |
| .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP, |
| .mld_capa_and_ops = 2, |
| /* the max number of simultaneous links is defined as the |
| @@ -1573,6 +1580,10 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, |
| u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, |
| IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); |
| |
| + if (iftype == NL80211_IFTYPE_AP) |
| + eht_cap_elem->mac_cap_info[0] |= |
| + IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC; |
| + |
| eht_cap_elem->phy_cap_info[0] = |
| IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | |
| IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index 67ac7a91..fa884316 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -524,6 +524,9 @@ struct csi_data { |
| }; |
| |
| int mt7996_set_coding_type(struct ieee80211_hw *hw, u8 coding_type, u8 link_id); |
| + |
| +int mt7996_mcu_set_muru_qos_cfg(struct mt7996_dev *dev, u16 wlan_idx, u8 dir, |
| + u8 scs_id, u8 req_type, u8 *qos_ie, u8 qos_ie_len); |
| #endif |
| |
| struct mt7996_rro_ba_session { |
| diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c |
| index 8bacf29d..9ec4bc9a 100644 |
| --- a/mt7996/mtk_mcu.c |
| +++ b/mt7996/mtk_mcu.c |
| @@ -1429,4 +1429,53 @@ int mt7996_set_coding_type(struct ieee80211_hw *hw, u8 coding_type, u8 link_id) |
| |
| return 0; |
| } |
| + |
| +int mt7996_mcu_set_muru_qos_cfg(struct mt7996_dev *dev, u16 wlan_idx, u8 dir, |
| + u8 scs_id, u8 req_type, u8 *qos_ie, u8 qos_ie_len) |
| +{ |
| +#define QOS_FLAG_UPDATE 20 |
| +#define QOS_FLAG_DELETE 21 |
| + |
| + struct { |
| + u8 _rsv[4]; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + |
| + __le32 qos_flag; |
| + __le16 wlan_idx; |
| + u8 __rsv2[12]; |
| + u8 dir; |
| + u8 _rsv3[4]; |
| + u8 scs_id; |
| + u8 qos_ie[44]; |
| + } __packed req = { |
| + .tag = cpu_to_le16(UNI_CMD_MURU_SET_QOS_CFG), |
| + .len = cpu_to_le16(sizeof(req) - 4), |
| + .wlan_idx = cpu_to_le16(wlan_idx), |
| + .scs_id = scs_id, |
| + }; |
| + |
| + switch (req_type) { |
| + case SCS_REQ_TYPE_ADD: |
| + case SCS_REQ_TYPE_CHANGE: |
| + req.qos_flag = cpu_to_le32(QOS_FLAG_UPDATE); |
| + req.dir = dir; |
| + |
| + if (qos_ie_len > sizeof(req.qos_ie)) |
| + return -EINVAL; |
| + |
| + memcpy(req.qos_ie, qos_ie, qos_ie_len); |
| + break; |
| + case SCS_REQ_TYPE_REMOVE: |
| + req.qos_flag = cpu_to_le32(QOS_FLAG_DELETE); |
| + break; |
| + default: |
| + dev_err(dev->mt76.dev, "Unsupported req_type %u\n", req_type); |
| + return -EINVAL; |
| + } |
| + |
| + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &req, |
| + sizeof(req), true); |
| +} |
| #endif |
| diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h |
| index 8ba261a7..711903e0 100644 |
| --- a/mt7996/mtk_mcu.h |
| +++ b/mt7996/mtk_mcu.h |
| @@ -134,6 +134,7 @@ enum { |
| UNI_CMD_MURU_PROT_FRAME_THR = 0xCC, |
| UNI_CMD_MURU_SET_CERT_MU_EDCA_OVERRIDE, |
| UNI_CMD_MURU_SET_TRIG_VARIANT = 0xD5, |
| + UNI_CMD_MURU_SET_QOS_CFG = 0xFE, |
| }; |
| |
| struct bf_pfmu_tag { |
| @@ -1165,4 +1166,10 @@ enum { |
| VOW_DRR_DBG_PRN) |
| #endif |
| |
| +enum { |
| + SCS_REQ_TYPE_ADD, |
| + SCS_REQ_TYPE_REMOVE, |
| + SCS_REQ_TYPE_CHANGE, |
| +}; |
| + |
| #endif |
| diff --git a/mt7996/vendor.c b/mt7996/vendor.c |
| index e75c163e..e13a148a 100644 |
| --- a/mt7996/vendor.c |
| +++ b/mt7996/vendor.c |
| @@ -132,6 +132,17 @@ eml_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EML_CTRL] = { |
| [MTK_VENDOR_ATTR_EML_CTRL_STRUCT] = { .type = NLA_BINARY }, |
| }; |
| |
| + |
| +static const struct nla_policy |
| +scs_ctrl_policy[NUM_MTK_VENDOR_ATTRS_SCS_CTRL] = { |
| + [MTK_VENDOR_ATTR_SCS_ID] = { .type = NLA_U8 }, |
| + [MTK_VENDOR_ATTR_SCS_REQ_TYPE] = { .type = NLA_U8 }, |
| + [MTK_VENDOR_ATTR_SCS_DIR] = { .type = NLA_U8 }, |
| + [MTK_VENDOR_ATTR_SCS_QOS_IE] = { .type = NLA_BINARY }, |
| + [MTK_VENDOR_ATTR_SCS_MAC_ADDR] = NLA_POLICY_ETH_ADDR, |
| + [MTK_VENDOR_ATTR_SCS_LINK_ID] = { .type = NLA_U8 }, |
| +}; |
| + |
| static const struct nla_policy |
| csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = { |
| [MTK_VENDOR_ATTR_CSI_CTRL_BAND_IDX] = { .type = NLA_U8 }, |
| @@ -1164,6 +1175,63 @@ static int mt7996_vendor_eml_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev |
| |
| return err; |
| } |
| +static int mt7996_vendor_scs_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev, |
| + const void *data, int data_len) |
| +{ |
| + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); |
| + struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| + struct ieee80211_sta *sta; |
| + struct mt7996_sta *msta; |
| + struct mt7996_link_sta *mlink; |
| + struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_SCS_CTRL]; |
| + u8 sta_addr[ETH_ALEN]; |
| + u8 scs_id, req_type, dir, link_id, qos_ie_len; |
| + u8 *qos_ie = NULL; |
| + int err; |
| + |
| + err = nla_parse(tb, MTK_VENDOR_ATTR_SCS_CTRL_MAX, data, data_len, |
| + scs_ctrl_policy, NULL); |
| + if (err) |
| + return err; |
| + |
| + if (!tb[MTK_VENDOR_ATTR_SCS_ID] || !tb[MTK_VENDOR_ATTR_SCS_REQ_TYPE] || |
| + !tb[MTK_VENDOR_ATTR_SCS_MAC_ADDR] || !tb[MTK_VENDOR_ATTR_SCS_LINK_ID]) |
| + return -EINVAL; |
| + |
| + scs_id = nla_get_u8(tb[MTK_VENDOR_ATTR_SCS_ID]); |
| + req_type = nla_get_u8(tb[MTK_VENDOR_ATTR_SCS_REQ_TYPE]); |
| + nla_memcpy(sta_addr, tb[MTK_VENDOR_ATTR_SCS_MAC_ADDR], ETH_ALEN); |
| + link_id = nla_get_u8(tb[MTK_VENDOR_ATTR_SCS_LINK_ID]); |
| + |
| + sta = ieee80211_find_sta_by_ifaddr(hw, sta_addr, NULL); |
| + if (!sta) |
| + return -EINVAL; |
| + |
| + msta = (struct mt7996_sta *)sta->drv_priv; |
| + mlink = mlink_dereference_protected(msta, link_id); |
| + if (!mlink) |
| + return -EINVAL; |
| + |
| + if (req_type == SCS_REQ_TYPE_ADD || req_type == SCS_REQ_TYPE_CHANGE) { |
| + if (!tb[MTK_VENDOR_ATTR_SCS_DIR] || !tb[MTK_VENDOR_ATTR_SCS_QOS_IE]) |
| + return -EINVAL; |
| + |
| + dir = nla_get_u8(tb[MTK_VENDOR_ATTR_SCS_DIR]); |
| + qos_ie_len = nla_len(tb[MTK_VENDOR_ATTR_SCS_QOS_IE]); |
| + qos_ie = kzalloc(qos_ie_len, GFP_KERNEL); |
| + if (!qos_ie) |
| + return -ENOMEM; |
| + |
| + nla_memcpy(qos_ie, tb[MTK_VENDOR_ATTR_SCS_QOS_IE], qos_ie_len); |
| + } |
| + |
| + err = mt7996_mcu_set_muru_qos_cfg(dev, mlink->wcid.idx, dir, scs_id, |
| + req_type, qos_ie, qos_ie_len); |
| + |
| + kfree(qos_ie); |
| + |
| + return err; |
| +} |
| |
| static int mt7996_vendor_csi_ctrl(struct wiphy *wiphy, |
| struct wireless_dev *wdev, |
| @@ -1644,6 +1712,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = { |
| .policy = txpower_ctrl_policy, |
| .maxattr = MTK_VENDOR_ATTR_TXPOWER_CTRL_MAX, |
| }, |
| + { |
| + .info = { |
| + .vendor_id = MTK_NL80211_VENDOR_ID, |
| + .subcmd = MTK_NL80211_VENDOR_SUBCMD_SCS_CTRL, |
| + }, |
| + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | |
| + WIPHY_VENDOR_CMD_NEED_RUNNING, |
| + .doit = mt7996_vendor_scs_ctrl, |
| + .policy = scs_ctrl_policy, |
| + .maxattr = MTK_VENDOR_ATTR_SCS_CTRL_MAX, |
| + }, |
| }; |
| |
| static const struct nl80211_vendor_cmd_info mt7996_vendor_events[] = { |
| diff --git a/mt7996/vendor.h b/mt7996/vendor.h |
| index 515f77a6..71800590 100644 |
| --- a/mt7996/vendor.h |
| +++ b/mt7996/vendor.h |
| @@ -19,6 +19,7 @@ enum mtk_nl80211_vendor_subcmds { |
| MTK_NL80211_VENDOR_SUBCMD_PP_CTRL = 0xcc, |
| MTK_NL80211_VENDOR_SUBCMD_BEACON_CTRL = 0xcd, |
| MTK_NL80211_VENDOR_SUBCMD_TXPOWER_CTRL = 0xce, |
| + MTK_NL80211_VENDOR_SUBCMD_SCS_CTRL = 0xd0, |
| MTK_NL80211_VENDOR_SUBCMD_EML_CTRL = 0xd3, |
| }; |
| |
| @@ -262,6 +263,22 @@ enum mtk_vendor_attr_eml_ctrl { |
| NUM_MTK_VENDOR_ATTRS_EML_CTRL - 1 |
| }; |
| |
| +enum mtk_vendor_attr_scs_ctrl { |
| + MTK_VENDOR_ATTR_SCS_CTRL_UNSPEC, |
| + |
| + MTK_VENDOR_ATTR_SCS_ID, |
| + MTK_VENDOR_ATTR_SCS_REQ_TYPE, |
| + MTK_VENDOR_ATTR_SCS_DIR, |
| + MTK_VENDOR_ATTR_SCS_QOS_IE, |
| + MTK_VENDOR_ATTR_SCS_MAC_ADDR, |
| + MTK_VENDOR_ATTR_SCS_LINK_ID, |
| + |
| + /* keep last */ |
| + NUM_MTK_VENDOR_ATTRS_SCS_CTRL, |
| + MTK_VENDOR_ATTR_SCS_CTRL_MAX = |
| + NUM_MTK_VENDOR_ATTRS_SCS_CTRL - 1 |
| +}; |
| + |
| enum mtk_vendor_attr_csi_ctrl { |
| MTK_VENDOR_ATTR_CSI_CTRL_UNSPEC, |
| |
| -- |
| 2.18.0 |
| |