blob: 16d8cae4320d235e9f1d416c5ffaa934053842cf [file] [log] [blame]
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