mt76: mt7915: query station rx rate from firmware
authorFelix Fietkau <nbd@nbd.name>
Wed, 30 Sep 2020 09:39:04 +0000 (11:39 +0200)
committerFelix Fietkau <nbd@nbd.name>
Fri, 4 Dec 2020 12:46:15 +0000 (13:46 +0100)
When per-packet rate reporting is enabled, the hardware can get stuck under
some conditions. It self-recovers quickly, but in practice this leads to
reduced performance.
In order to avoid running into this issue, disable per-packet rate reporting
by default and query the rx rate from firmware instead, unless monitor mode
is enabled.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/init.c
drivers/net/wireless/mediatek/mt76/mt7915/main.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h

index 5884c0ce45e501b382bb879f4072c9dc74e84c35..5f238bc63c2ae8a7366ecd39e13368ab9d7c22a8 100644 (file)
@@ -43,8 +43,8 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
 
        mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536);
        mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
-       /* enable rx rate report */
-       mt76_set(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN);
+       /* disable rx rate report by default due to hw issues */
+       mt76_clear(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN);
        /* disable hardware de-agg */
        mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
 
index 5d4bffbe07f998e507e681e660fc8eb24086f262..b53f04fc05341b5a36c32e61835508ae3454975a 100644 (file)
@@ -362,11 +362,14 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
        mutex_lock(&dev->mt76.mutex);
 
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-               if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
+               bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
+
+               if (!enabled)
                        phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
                else
                        phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
 
+               mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN, enabled);
                mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
        }
 
@@ -794,9 +797,13 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
                                  struct ieee80211_sta *sta,
                                  struct station_info *sinfo)
 {
+       struct mt7915_phy *phy = mt7915_hw_phy(hw);
        struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
        struct mt7915_sta_stats *stats = &msta->stats;
 
+       if (mt7915_mcu_get_rx_rate(phy, vif, sta, &sinfo->rxrate) == 0)
+               sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+
        if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
                return;
 
index a87b10e8fda718023a47f62992c01fed57ed48f2..dde053a7626147fcc80f0b96ce535418bb877e29 100644 (file)
@@ -3404,3 +3404,97 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
        return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SPR, &req,
                                 sizeof(req), true);
 }
+
+int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta, struct rate_info *rate)
+{
+       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+       struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+       struct mt7915_dev *dev = phy->dev;
+       struct mt76_phy *mphy = phy->mt76;
+       struct {
+               u8 category;
+               u8 band;
+               __le16 wcid;
+       } __packed req = {
+               .category = MCU_PHY_STATE_CONTENTION_RX_RATE,
+               .band = mvif->band_idx,
+               .wcid = cpu_to_le16(msta->wcid.idx),
+       };
+       struct ieee80211_supported_band *sband;
+       struct mt7915_mcu_phy_rx_info *res;
+       struct sk_buff *skb;
+       u16 flags = 0;
+       int ret;
+       int i;
+
+       ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_PHY_STAT_INFO,
+                                       &req, sizeof(req), true, &skb);
+       if (ret)
+               return ret;
+
+       res = (struct mt7915_mcu_phy_rx_info *)skb->data;
+
+       rate->mcs = res->rate;
+       rate->nss = res->nsts + 1;
+
+       switch (res->mode) {
+       case MT_PHY_TYPE_CCK:
+       case MT_PHY_TYPE_OFDM:
+               if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+                       sband = &mphy->sband_5g.sband;
+               else
+                       sband = &mphy->sband_2g.sband;
+
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if (rate->mcs != (sband->bitrates[i].hw_value & 0xf))
+                               continue;
+
+                       rate->legacy = sband->bitrates[i].bitrate;
+                       break;
+               }
+               break;
+       case MT_PHY_TYPE_HT:
+       case MT_PHY_TYPE_HT_GF:
+               rate->mcs += (rate->nss - 1) * 8;
+               flags |= RATE_INFO_FLAGS_MCS;
+
+               if (res->gi)
+                       flags |= RATE_INFO_FLAGS_SHORT_GI;
+               break;
+       case MT_PHY_TYPE_VHT:
+               flags |= RATE_INFO_FLAGS_VHT_MCS;
+
+               if (res->gi)
+                       flags |= RATE_INFO_FLAGS_SHORT_GI;
+               break;
+       case MT_PHY_TYPE_HE_SU:
+       case MT_PHY_TYPE_HE_EXT_SU:
+       case MT_PHY_TYPE_HE_TB:
+       case MT_PHY_TYPE_HE_MU:
+               rate->he_gi = res->gi;
+
+               flags |= RATE_INFO_FLAGS_HE_MCS;
+               break;
+       default:
+               break;
+       }
+       rate->flags = flags;
+
+       switch (res->bw) {
+       case IEEE80211_STA_RX_BW_160:
+               rate->bw = RATE_INFO_BW_160;
+               break;
+       case IEEE80211_STA_RX_BW_80:
+               rate->bw = RATE_INFO_BW_80;
+               break;
+       case IEEE80211_STA_RX_BW_40:
+               rate->bw = RATE_INFO_BW_40;
+               break;
+       default:
+               rate->bw = RATE_INFO_BW_20;
+               break;
+       }
+
+       return 0;
+}
index 49ff60509a722b9e672c9f2242d6f2654ac002bf..5f23f27f9f6cfcbdd277cd49233d2231b447f800 100644 (file)
@@ -153,6 +153,18 @@ struct mt7915_mcu_ra_info {
        u8 prob_down_pending;
 } __packed;
 
+
+struct mt7915_mcu_phy_rx_info {
+       u8 category;
+       u8 rate;
+       u8 mode;
+       u8 nsts;
+       u8 gi;
+       u8 coding;
+       u8 stbc;
+       u8 bw;
+};
+
 #define MT_RA_RATE_NSS                 GENMASK(8, 6)
 #define MT_RA_RATE_MCS                 GENMASK(3, 0)
 #define MT_RA_RATE_TX_MODE             GENMASK(12, 9)
@@ -217,6 +229,7 @@ enum {
        MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
        MCU_EXT_CMD_SET_RDD_TH = 0x9d,
        MCU_EXT_CMD_SET_SPR = 0xa8,
+       MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
 };
 
 enum {
@@ -250,6 +263,14 @@ enum {
        EE_FORMAT_MULTIPLE,
 };
 
+enum {
+       MCU_PHY_STATE_TX_RATE,
+       MCU_PHY_STATE_RX_RATE,
+       MCU_PHY_STATE_RSSI,
+       MCU_PHY_STATE_CONTENTION_RX_RATE,
+       MCU_PHY_STATE_OFDMLQ_CNINFO,
+};
+
 #define STA_TYPE_STA                   BIT(0)
 #define STA_TYPE_AP                    BIT(1)
 #define STA_TYPE_ADHOC                 BIT(2)
index 292075d3f0dad84581d9a3ee392b5c76df7184a5..0ea3965c28f56fd6584ac95ed4c794cadefe14ae 100644 (file)
@@ -321,6 +321,8 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
                            const struct mt7915_dfs_pattern *pattern);
 int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
 int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index);
+int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta, struct rate_info *rate);
 int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
                       u8 index, u8 rx_sel, u8 val);
 int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl);