Introduce mbss mcu APIs to enable 802.11ax multi-bss AP support for mt7915 devices Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> --- This patch is based on "mt76: mt7915: introduce bss coloring support" https://patchwork.kernel.org/patch/11782149/ --- .../net/wireless/mediatek/mt76/mt7915/init.c | 2 + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 81 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 140222c083dd..21cdb5c8fcd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -265,6 +265,8 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID_AP); hw->max_tx_fragments = 4; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 6cedee285e25..4b9dddba7228 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -755,11 +755,22 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct tlv *tlv; tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); + bss = (struct bss_info_basic *)tlv; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_AP: break; + case NL80211_IFTYPE_AP: { + /* mbss */ + int max_bss_id = fls(vif->bss_conf.multiple_bssid.count); + + if (max_bss_id > 8) + return -EINVAL; + + bss->non_tx_bssid = vif->bss_conf.multiple_bssid.index; + bss->max_bssid = max_bss_id; + break; + } case NL80211_IFTYPE_STATION: /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ if (enable) { @@ -786,7 +797,6 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, break; } - bss = (struct bss_info_basic *)tlv; memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); bss->network_type = cpu_to_le32(type); @@ -1075,6 +1085,29 @@ mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, &req, sizeof(req), true); } +static int +mt7915_mcu_mbss_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct bss_info_mbss *mbss; + struct tlv *tlv; + int max_bss_id; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + max_bss_id = fls(vif->bss_conf.multiple_bssid.count); + if (max_bss_id > 8) + return -EINVAL; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_11V_MBSSID, sizeof(*mbss)); + mbss = (struct bss_info_mbss *)tlv; + + mbss->bssid_index = vif->bss_conf.multiple_bssid.index; + mbss->max_bssid = max_bss_id; + + return 0; +} + int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, int enable) { @@ -1100,6 +1133,7 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, mt7915_mcu_bss_bmc_tlv(skb, phy); mt7915_mcu_bss_ra_tlv(skb, vif, phy); mt7915_mcu_bss_hw_amsdu_tlv(skb); + mt7915_mcu_mbss_tlv(skb, vif); if (vif->bss_conf.he_support) mt7915_mcu_bss_he_tlv(skb, vif, phy); @@ -2497,6 +2531,43 @@ mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; } +static void +mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, + struct ieee80211_vif *vif, struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) +{ + struct bss_info_bcn_mbss *mbss; + const struct element *elem; + struct tlv *tlv; + int i = 1; + + if (!vif->bss_conf.multiple_bssid.count) + return; + + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID, + sizeof(*mbss), &bcn->sub_ntlv, + &bcn->len); + mbss = (struct bss_info_bcn_mbss *)tlv; + mbss->offset[0] = cpu_to_le16(offs->tim_offset); + mbss->bitmap = cpu_to_le32(1); + + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, + &skb->data[offs->multiple_bssid_offset], + offs->multiple_bssid_offset) { + const struct element *sub_elem; + + for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) { + if (sub_elem->id) + continue; + + mbss->offset[i] = + cpu_to_le16((u8 *)sub_elem - skb->data); + mbss->bitmap |= cpu_to_le32(1 << i); + i++; + } + } +} + static void mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct sk_buff *rskb, struct sk_buff *skb, @@ -2545,6 +2616,10 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct bss_info_bcn *bcn; int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE; + if (vif->bss_conf.multiple_bssid.count && + vif->bss_conf.multiple_bssid.parent) + return 0; + skb = ieee80211_beacon_get_template(hw, vif, &offs); if (!skb) return -EINVAL; @@ -2570,8 +2645,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; } - /* TODO: subtag - 11v MBSSID */ mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs); + mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs); mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); dev_kfree_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index e4cfbd26e565..da0d1fb769f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -367,6 +367,14 @@ struct bss_info_sync_mode { u8 rsv[8]; } __packed; +struct bss_info_mbss { + __le16 tag; + __le16 len; + u8 max_bssid; + u8 bssid_index; + u8 rsv[2]; +} __packed; + struct bss_info_bmc_rate { __le16 tag; __le16 len; @@ -1013,7 +1021,8 @@ enum { sizeof(struct bss_info_he) + \ sizeof(struct bss_info_bmc_rate) +\ sizeof(struct bss_info_ext_bss) +\ - sizeof(struct bss_info_sync_mode)) + sizeof(struct bss_info_sync_mode) + \ + sizeof(struct bss_info_mbss)) #define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct bss_info_bcn_cntdwn) + \ -- 2.26.2