From ea565833fd7848208eb63fc653d32a6ad3a86d87 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 20:50:14 +0200 Subject: [PATCH] mt76: mt7603: track tx airtime for airtime fairness and survey Poll per-station hardware counters after tx status events Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 + drivers/net/wireless/mediatek/mt76/mt76.h | 2 + .../net/wireless/mediatek/mt76/mt7603/dma.c | 2 + .../net/wireless/mediatek/mt76/mt7603/init.c | 3 + .../net/wireless/mediatek/mt76/mt7603/mac.c | 86 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7603/main.c | 15 +++- .../wireless/mediatek/mt76/mt7603/mt7603.h | 7 ++ 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c6076c66cd37..38db311b3ca8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -481,6 +481,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; + survey->filled |= dev->drv->survey_flags; if (chan == dev->main_chan) { survey->filled |= SURVEY_INFO_IN_USE; @@ -492,6 +493,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); + survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 048b7ebbc46d..322595f4e84e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -286,6 +286,7 @@ struct mt76_hw_cap { struct mt76_driver_ops { u32 drv_flags; + u32 survey_flags; u16 txwi_size; void (*update_survey)(struct mt76_dev *dev); @@ -322,6 +323,7 @@ struct mt76_channel_state { u64 cc_active; u64 cc_busy; u64 cc_bss_rx; + u64 cc_tx; }; struct mt76_sband { diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 24d82a20d046..a6ab73060aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) for (i = MT_TXQ_MCU; i >= 0; i--) mt76_queue_tx_cleanup(dev, i, false); + mt7603_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index a68533684b18..3a2927a524c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -8,6 +8,7 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, @@ -525,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev) bus_ops->rmw = mt7603_rmw; dev->mt76.bus = bus_ops; + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->ps_lock); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 0212384d0d56..caa1456adc50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -160,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, addr = mt7603_wtbl4_addr(idx); for (i = 0; i < MT_WTBL4_SIZE; i += 4) mt76_wr(dev, addr + i, 0); + + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } static void @@ -380,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); } +void mt7603_mac_sta_poll(struct mt7603_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt7603_sta *msta; + u32 total_airtime = 0; + u32 airtime[4]; + u32 addr; + int i; + + rcu_read_lock(); + + while (1) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + + msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta, + poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7603_wtbl4_addr(msta->wcid.idx); + for (i = 0; i < 4; i++) { + u32 airtime_last = msta->tx_airtime_ac[i]; + + msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); + airtime[i] = msta->tx_airtime_ac[i] - airtime_last; + airtime[i] *= 32; + total_airtime += airtime[i]; + + if (msta->tx_airtime_ac[i] & BIT(22)) + clear = true; + } + + if (clear) { + mt7603_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->tx_airtime_ac, 0, + sizeof(msta->tx_airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + for (i = 0; i < 4; i++) { + struct mt76_queue *q = dev->mt76.q_tx[i].q; + u8 qidx = q->hw_idx; + u8 tid = ac_to_tid[i]; + u32 txtime = airtime[qidx]; + + if (!txtime) + continue; + + ieee80211_sta_register_airtime(sta, tid, txtime, 0); + } + } + + rcu_read_unlock(); + + if (!total_airtime) + return; + + spin_lock_bh(&dev->mt76.cc_lock); + dev->mt76.chan_state->cc_tx += total_airtime; + spin_unlock_bh(&dev->mt76.cc_lock); +} + static struct mt76_wcid * mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) { @@ -1159,6 +1239,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) msta = container_of(wcid, struct mt7603_sta, wcid); sta = wcid_to_sta(wcid); + if (list_empty(&msta->poll_list)) { + spin_lock_bh(&dev->sta_poll_lock); + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 9c378f017877..31cce1c005c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -66,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; dev->vif_mask |= BIT(mvif->idx); + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -87,8 +88,9 @@ static void mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; + struct mt7603_sta *msta = &mvif->sta; struct mt7603_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0); @@ -99,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mt76_txq_remove(&dev->mt76, vif->txq); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mutex_lock(&dev->mt76.mutex); dev->vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); @@ -325,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); __skb_queue_head_init(&msta->psq); msta->ps = ~0; msta->smps = ~0; @@ -361,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7603_filter_tx(dev, wcid->idx, true); spin_unlock_bh(&dev->ps_lock); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mt7603_wtbl_clear(dev, wcid->idx); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 01b933538c25..ab54b0612e98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -61,6 +61,9 @@ struct mt7603_sta { struct mt7603_vif *vif; + struct list_head poll_list; + u32 tx_airtime_ac[4]; + struct sk_buff_head psq; struct ieee80211_tx_rate rates[4]; @@ -103,6 +106,9 @@ struct mt7603_dev { u8 vif_mask; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct mt7603_sta global_sta; u32 agc0, agc3; @@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size); +void mt7603_mac_sta_poll(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev);