*/
                if (info & MT_TX_FREE_PAIR) {
                        struct mt7915_sta *msta;
+                       struct mt7915_phy *phy;
                        struct mt76_wcid *wcid;
                        u16 idx;
 
                                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);
        }
 }
 
-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);
 }
 
                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,
 
                goto out;
        }
        mvif->omac_idx = idx;
-       mvif->dev = dev;
+       mvif->phy = phy;
        mvif->band_idx = ext_phy;
 
        if (ext_phy)
 
        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;
        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;
        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);
 }
 
                     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 = {
 
 
        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];
        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];
 };
        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 {
        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;
 
                           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,