mt76: add U-APSD support on AP side
authorLorenzo Bianconi <lorenzo@kernel.org>
Fri, 12 Jun 2020 11:46:31 +0000 (13:46 +0200)
committerFelix Fietkau <nbd@nbd.name>
Tue, 21 Jul 2020 17:01:15 +0000 (19:01 +0200)
Introduce U-APSD support in mt76 driver for AP interface

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mac80211.c
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
drivers/net/wireless/mediatek/mt76/mt7615/mcu.h

index 4c10c8164aee2f0af7fd83890c3eed5182c458c0..d8533d0c6e81725adb96e7c9ff8c07a5fa58cb38 100644 (file)
@@ -282,7 +282,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
 
        wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
        wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
-                       WIPHY_FLAG_SUPPORTS_TDLS;
+                       WIPHY_FLAG_SUPPORTS_TDLS |
+                       WIPHY_FLAG_AP_UAPSD;
 
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
@@ -292,6 +293,7 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
        wiphy->available_antennas_rx = dev->phy.antenna_mask;
 
        hw->txq_data_size = sizeof(struct mt76_txq);
+       hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
 
        if (!hw->max_tx_fragments)
                hw->max_tx_fragments = 16;
index b76ecc24f33306f59801514e7db2c66bee887acb..d3a8ada3b779c4c3f87b4630341b595b8a3c005f 100644 (file)
@@ -926,6 +926,38 @@ mt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
        }
 }
 
+static void
+mt7615_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif,
+                    struct ieee80211_sta *sta)
+{
+       struct sta_rec_uapsd *uapsd;
+       struct tlv *tlv;
+
+       if (vif->type != NL80211_IFTYPE_AP || !sta->wme)
+               return;
+
+       tlv = mt7615_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));
+       uapsd = (struct sta_rec_uapsd *)tlv;
+
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) {
+               uapsd->dac_map |= BIT(3);
+               uapsd->tac_map |= BIT(3);
+       }
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) {
+               uapsd->dac_map |= BIT(2);
+               uapsd->tac_map |= BIT(2);
+       }
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) {
+               uapsd->dac_map |= BIT(1);
+               uapsd->tac_map |= BIT(1);
+       }
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) {
+               uapsd->dac_map |= BIT(0);
+               uapsd->tac_map |= BIT(0);
+       }
+       uapsd->max_sp = sta->max_sp;
+}
+
 static void
 mt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb,
                       struct ieee80211_ampdu_params *params,
@@ -1188,8 +1220,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif,
                return PTR_ERR(sskb);
 
        mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable);
-       if (enable && sta)
+       if (enable && sta) {
                mt7615_mcu_sta_ht_tlv(sskb, sta);
+               mt7615_mcu_sta_uapsd(sskb, vif, sta);
+       }
 
        wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET,
                                             NULL, &wskb);
@@ -1285,8 +1319,10 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif,
                return PTR_ERR(skb);
 
        mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable);
-       if (enable && sta)
+       if (enable && sta) {
                mt7615_mcu_sta_ht_tlv(skb, sta);
+               mt7615_mcu_sta_uapsd(skb, vif, sta);
+       }
 
        sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
 
@@ -1429,6 +1465,7 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
                        u8 pad[3];
                } __packed hdr;
                struct mt7615_bss_basic_tlv basic;
+               struct mt7615_bss_qos_tlv qos;
        } basic_req = {
                .hdr = {
                        .bss_idx = mvif->idx,
@@ -1444,6 +1481,11 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
                        .active = true, /* keep bss deactivated */
                        .phymode = 0x38,
                },
+               .qos = {
+                       .tag = cpu_to_le16(UNI_BSS_INFO_QBSS),
+                       .len = cpu_to_le16(sizeof(struct mt7615_bss_qos_tlv)),
+                       .qos = vif->bss_conf.qos,
+               },
        };
        struct {
                struct {
index 64f7471a57bb83a22360fd158807d7abf145bfe1..4f70c4de69a43a47eea466fb81d0531f4d8a8c5f 100644 (file)
@@ -454,6 +454,13 @@ struct mt7615_bss_basic_tlv {
        u8 pad[3];
 } __packed;
 
+struct mt7615_bss_qos_tlv {
+       __le16 tag;
+       __le16 len;
+       u8 qos;
+       u8 pad[3];
+} __packed;
+
 struct mt7615_wow_ctrl_tlv {
        __le16 tag;
        __le16 len;
@@ -578,6 +585,8 @@ enum {
        UNI_BSS_INFO_BASIC = 0,
        UNI_BSS_INFO_RLM = 2,
        UNI_BSS_INFO_BCN_CONTENT = 7,
+       UNI_BSS_INFO_QBSS = 15,
+       UNI_BSS_INFO_UAPSD = 19,
 };
 
 enum {
@@ -891,6 +900,7 @@ struct wtbl_raw {
                                         sizeof(struct sta_rec_basic) + \
                                         sizeof(struct sta_rec_ht) +    \
                                         sizeof(struct sta_rec_vht) +   \
+                                        sizeof(struct sta_rec_uapsd) + \
                                         sizeof(struct tlv) +   \
                                         MT7615_WTBL_UPDATE_MAX_SIZE)
 
@@ -980,6 +990,17 @@ struct sta_rec_ba {
        __le16 winsize;
 } __packed;
 
+struct sta_rec_uapsd {
+       __le16 tag;
+       __le16 len;
+       u8 dac_map;
+       u8 tac_map;
+       u8 max_sp;
+       u8 rsv0;
+       __le16 listen_interval;
+       u8 rsv1[2];
+} __packed;
+
 enum {
        STA_REC_BASIC,
        STA_REC_RA,