]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mt76: mt7915: clean up station stats polling and rate control update
authorFelix Fietkau <nbd@nbd.name>
Sun, 26 Jul 2020 18:45:58 +0000 (20:45 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 24 Sep 2020 16:10:14 +0000 (18:10 +0200)
Queueing a per-sta work item from the tx free path can become very expensive
under load. This work is only supposed to pull rate control stats every
second and deal with rate control changes.

Additionally, the rate control update code was wrong, because it was
confusing bit masks and bit numbers in test_bit.

Fix this by introducing a dedicated device work item for rate control
updates, and by polling station stats from the phy mac work.
Stations requiring polling or rate control updates are added to lists
protected by dev->sta_poll_lock.

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

index 38f473d587c91461251be22d0481ec15d4cbf80e..47cce0e4c8a54d681ea6e2422afba88963fe1e3e 100644 (file)
@@ -400,7 +400,7 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
        struct ieee80211_sta *sta = data;
        struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
 
-       return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate);
+       return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate);
 }
 
 DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
index e90d0087e377c16791a653aa10250ea3087ab8df..8431fda391083daf5aaf14c60ff2f5d88de59bb5 100644 (file)
@@ -612,6 +612,7 @@ int mt7915_register_ext_phy(struct mt7915_dev *dev)
        mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
        mt7915_init_wiphy(mphy->hw);
 
+       INIT_LIST_HEAD(&phy->stats_list);
        INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
 
        /*
@@ -652,7 +653,10 @@ int mt7915_register_device(struct mt7915_dev *dev)
        dev->phy.dev = dev;
        dev->phy.mt76 = &dev->mt76.phy;
        dev->mt76.phy.priv = &dev->phy;
+       INIT_LIST_HEAD(&dev->phy.stats_list);
+       INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
        INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work);
+       INIT_LIST_HEAD(&dev->sta_rc_list);
        INIT_LIST_HEAD(&dev->sta_poll_list);
        spin_lock_init(&dev->sta_poll_lock);
 
index 99ab5fca0f6df1fb87c66d4e1b62f0728578f369..64089a8a01c939e1bcfc2f8b9e472ec6011e0b25 100644 (file)
@@ -881,6 +881,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
                 */
                if (info & MT_TX_FREE_PAIR) {
                        struct mt7915_sta *msta;
+                       struct mt7915_phy *phy;
                        struct mt76_wcid *wcid;
                        u16 idx;
 
@@ -892,8 +893,13 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
                                continue;
 
                        msta = container_of(wcid, struct mt7915_sta, wcid);
-                       ieee80211_queue_work(mt76_hw(dev), &msta->stats_work);
-                       continue;
+                       phy = msta->vif->phy;
+                       spin_lock_bh(&dev->sta_poll_lock);
+                       if (list_empty(&msta->stats_list))
+                               list_add_tail(&msta->stats_list, &phy->stats_list);
+                       if (list_empty(&msta->poll_list))
+                               list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+                       spin_unlock_bh(&dev->sta_poll_lock);
                }
 
                msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
@@ -1282,39 +1288,63 @@ mt7915_mac_update_mib_stats(struct mt7915_phy *phy)
        }
 }
 
-void mt7915_mac_sta_stats_work(struct work_struct *work)
+static void
+mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
+{
+       struct mt7915_dev *dev = phy->dev;
+       struct mt7915_sta *msta;
+       LIST_HEAD(list);
+
+       spin_lock_bh(&dev->sta_poll_lock);
+       list_splice_init(&phy->stats_list, &list);
+
+       while (!list_empty(&list)) {
+               msta = list_first_entry(&list, struct mt7915_sta, stats_list);
+               list_del_init(&msta->stats_list);
+               spin_unlock_bh(&dev->sta_poll_lock);
+
+               /* use MT_TX_FREE_RATE to report Tx rate for further devices */
+               mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
+
+               spin_lock_bh(&dev->sta_poll_lock);
+       }
+
+       spin_unlock_bh(&dev->sta_poll_lock);
+}
+
+void mt7915_mac_sta_rc_work(struct work_struct *work)
 {
+       struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
        struct ieee80211_sta *sta;
        struct ieee80211_vif *vif;
-       struct mt7915_sta_stats *stats;
        struct mt7915_sta *msta;
-       struct mt7915_dev *dev;
+       u32 changed;
+       LIST_HEAD(list);
 
-       msta = container_of(work, struct mt7915_sta, stats_work);
-       sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
-       vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
-       dev = msta->vif->dev;
-       stats = &msta->stats;
+       spin_lock_bh(&dev->sta_poll_lock);
+       list_splice_init(&dev->sta_rc_list, &list);
 
-       /* use MT_TX_FREE_RATE to report Tx rate for further devices */
-       if (time_after(jiffies, stats->jiffies + HZ)) {
-               mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO,
-                                        msta->wcid.idx);
+       while (!list_empty(&list)) {
+               msta = list_first_entry(&list, struct mt7915_sta, rc_list);
+               list_del_init(&msta->rc_list);
+               changed = msta->stats.changed;
+               msta->stats.changed = 0;
+               spin_unlock_bh(&dev->sta_poll_lock);
 
-               stats->jiffies = jiffies;
-       }
+               sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+               vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
 
-       if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED |
+               if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
                               IEEE80211_RC_NSS_CHANGED |
-                              IEEE80211_RC_BW_CHANGED, &stats->changed))
-               mt7915_mcu_add_rate_ctrl(dev, vif, sta);
+                              IEEE80211_RC_BW_CHANGED))
+                       mt7915_mcu_add_rate_ctrl(dev, vif, sta);
 
-       if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed))
-               mt7915_mcu_add_smps(dev, vif, sta);
+               if (changed & IEEE80211_RC_SMPS_CHANGED)
+                       mt7915_mcu_add_smps(dev, vif, sta);
+
+               spin_lock_bh(&dev->sta_poll_lock);
+       }
 
-       spin_lock_bh(&dev->sta_poll_lock);
-       if (list_empty(&msta->poll_list))
-               list_add_tail(&msta->poll_list, &dev->sta_poll_list);
        spin_unlock_bh(&dev->sta_poll_lock);
 }
 
@@ -1336,6 +1366,11 @@ void mt7915_mac_work(struct work_struct *work)
                mt7915_mac_update_mib_stats(phy);
        }
 
+       if (++phy->sta_work_count == 10) {
+               phy->sta_work_count = 0;
+               mt7915_mac_sta_stats_work(phy);
+       };
+
        mutex_unlock(&mdev->mutex);
 
        ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
index f95a0b55c4a2b1b307b57241a9494985d95fc94b..0b2dbf1fd4e13f10ab47848848383d981bf1d8c4 100644 (file)
@@ -137,7 +137,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
        mvif->omac_idx = idx;
-       mvif->dev = dev;
+       mvif->phy = phy;
        mvif->band_idx = ext_phy;
 
        if (ext_phy)
@@ -155,6 +155,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
 
        idx = MT7915_WTBL_RESERVED - mvif->idx;
 
+       INIT_LIST_HEAD(&mvif->sta.rc_list);
+       INIT_LIST_HEAD(&mvif->sta.stats_list);
        INIT_LIST_HEAD(&mvif->sta.poll_list);
        mvif->sta.wcid.idx = idx;
        mvif->sta.wcid.ext_phy = mvif->band_idx;
@@ -493,8 +495,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
        if (idx < 0)
                return -ENOSPC;
 
+       INIT_LIST_HEAD(&msta->rc_list);
+       INIT_LIST_HEAD(&msta->stats_list);
        INIT_LIST_HEAD(&msta->poll_list);
-       INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work);
        spin_lock_init(&msta->ampdu_lock);
        msta->vif = mvif;
        msta->wcid.sta = 1;
@@ -528,6 +531,10 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
        spin_lock_bh(&dev->sta_poll_lock);
        if (!list_empty(&msta->poll_list))
                list_del_init(&msta->poll_list);
+       if (!list_empty(&msta->stats_list))
+               list_del_init(&msta->stats_list);
+       if (!list_empty(&msta->rc_list))
+               list_del_init(&msta->rc_list);
        spin_unlock_bh(&dev->sta_poll_lock);
 }
 
@@ -789,18 +796,16 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
                     struct ieee80211_sta *sta,
                     u32 changed)
 {
+       struct mt7915_dev *dev = mt7915_hw_dev(hw);
        struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
 
-       rcu_read_lock();
-       sta = ieee80211_find_sta(vif, sta->addr);
-       if (!sta) {
-               rcu_read_unlock();
-               return;
-       }
-       rcu_read_unlock();
+       spin_lock_bh(&dev->sta_poll_lock);
+       msta->stats.changed |= changed;
+       if (list_empty(&msta->rc_list))
+               list_add_tail(&msta->rc_list, &dev->sta_rc_list);
+       spin_unlock_bh(&dev->sta_poll_lock);
 
-       set_bit(changed, &msta->stats.changed);
-       ieee80211_queue_work(hw, &msta->stats_work);
+       ieee80211_queue_work(hw, &dev->rc_work);
 }
 
 const struct ieee80211_ops mt7915_ops = {
index d8a13b4a23599b66279039bc20038afd1a1e16d7..eaccd76be05016d75ed116a1b0fee9c2fc5dfc22 100644 (file)
@@ -83,11 +83,12 @@ struct mt7915_sta {
 
        struct mt7915_vif *vif;
 
+       struct list_head stats_list;
        struct list_head poll_list;
+       struct list_head rc_list;
        u32 airtime_ac[8];
 
        struct mt7915_sta_stats stats;
-       struct work_struct stats_work;
 
        spinlock_t ampdu_lock;
        enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS];
@@ -100,7 +101,7 @@ struct mt7915_vif {
        u8 wmm_idx;
 
        struct mt7915_sta sta;
-       struct mt7915_dev *dev;
+       struct mt7915_phy *phy;
 
        struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
 };
@@ -135,9 +136,11 @@ struct mt7915_phy {
        u32 ampdu_ref;
 
        struct mib_stats mib;
+       struct list_head stats_list;
 
        struct delayed_work mac_work;
        u8 mac_work_count;
+       u8 sta_work_count;
 };
 
 struct mt7915_dev {
@@ -151,10 +154,12 @@ struct mt7915_dev {
        u16 chainmask;
 
        struct work_struct init_work;
+       struct work_struct rc_work;
        struct work_struct reset_work;
        wait_queue_head_t reset_wait;
        u32 reset_state;
 
+       struct list_head sta_rc_list;
        struct list_head sta_poll_list;
        spinlock_t sta_poll_lock;
 
@@ -461,7 +466,7 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
                           struct ieee80211_sta *sta);
 void mt7915_mac_work(struct work_struct *work);
 void mt7915_mac_reset_work(struct work_struct *work);
-void mt7915_mac_sta_stats_work(struct work_struct *work);
+void mt7915_mac_sta_rc_work(struct work_struct *work);
 int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
                          enum mt76_txq_id qid, struct mt76_wcid *wcid,
                          struct ieee80211_sta *sta,