@@ -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;
}
@@ -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);
@@ -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) + \
Introduce mbss mcu APIs to enable 802.11ax multi-bss AP support for mt7915 devices Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> --- 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(-)