Commit ea565833 authored by Felix Fietkau's avatar Felix Fietkau

mt76: mt7603: track tx airtime for airtime fairness and survey

Poll per-station hardware counters after tx status events
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 5ce09c1a
...@@ -481,6 +481,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, ...@@ -481,6 +481,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
memset(survey, 0, sizeof(*survey)); memset(survey, 0, sizeof(*survey));
survey->channel = chan; survey->channel = chan;
survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
survey->filled |= dev->drv->survey_flags;
if (chan == dev->main_chan) { if (chan == dev->main_chan) {
survey->filled |= SURVEY_INFO_IN_USE; survey->filled |= SURVEY_INFO_IN_USE;
...@@ -492,6 +493,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, ...@@ -492,6 +493,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
survey->time = div_u64(state->cc_active, 1000); survey->time = div_u64(state->cc_active, 1000);
survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_busy = div_u64(state->cc_busy, 1000);
survey->time_bss_rx = div_u64(state->cc_bss_rx, 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); spin_unlock_bh(&dev->cc_lock);
return ret; return ret;
......
...@@ -286,6 +286,7 @@ struct mt76_hw_cap { ...@@ -286,6 +286,7 @@ struct mt76_hw_cap {
struct mt76_driver_ops { struct mt76_driver_ops {
u32 drv_flags; u32 drv_flags;
u32 survey_flags;
u16 txwi_size; u16 txwi_size;
void (*update_survey)(struct mt76_dev *dev); void (*update_survey)(struct mt76_dev *dev);
...@@ -322,6 +323,7 @@ struct mt76_channel_state { ...@@ -322,6 +323,7 @@ struct mt76_channel_state {
u64 cc_active; u64 cc_active;
u64 cc_busy; u64 cc_busy;
u64 cc_bss_rx; u64 cc_bss_rx;
u64 cc_tx;
}; };
struct mt76_sband { struct mt76_sband {
......
...@@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) ...@@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
for (i = MT_TXQ_MCU; i >= 0; i--) for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false); mt76_queue_tx_cleanup(dev, i, false);
mt7603_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet); tasklet_schedule(&dev->mt76.tx_tasklet);
return 0; return 0;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
const struct mt76_driver_ops mt7603_drv_ops = { const struct mt76_driver_ops mt7603_drv_ops = {
.txwi_size = MT_TXD_SIZE, .txwi_size = MT_TXD_SIZE,
.drv_flags = MT_DRV_SW_RX_AIRTIME, .drv_flags = MT_DRV_SW_RX_AIRTIME,
.survey_flags = SURVEY_INFO_TIME_TX,
.tx_prepare_skb = mt7603_tx_prepare_skb, .tx_prepare_skb = mt7603_tx_prepare_skb,
.tx_complete_skb = mt7603_tx_complete_skb, .tx_complete_skb = mt7603_tx_complete_skb,
.rx_skb = mt7603_queue_rx_skb, .rx_skb = mt7603_queue_rx_skb,
...@@ -525,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev) ...@@ -525,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
bus_ops->rmw = mt7603_rmw; bus_ops->rmw = mt7603_rmw;
dev->mt76.bus = bus_ops; 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); spin_lock_init(&dev->ps_lock);
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work);
......
...@@ -160,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, ...@@ -160,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
addr = mt7603_wtbl4_addr(idx); addr = mt7603_wtbl4_addr(idx);
for (i = 0; i < MT_WTBL4_SIZE; i += 4) for (i = 0; i < MT_WTBL4_SIZE; i += 4)
mt76_wr(dev, addr + i, 0); mt76_wr(dev, addr + i, 0);
mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
} }
static void static void
...@@ -380,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, ...@@ -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); 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 * static struct mt76_wcid *
mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) 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) ...@@ -1159,6 +1239,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
msta = container_of(wcid, struct mt7603_sta, wcid); msta = container_of(wcid, struct mt7603_sta, wcid);
sta = wcid_to_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)) if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
goto out; goto out;
......
...@@ -66,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ...@@ -66,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
dev->vif_mask |= BIT(mvif->idx); dev->vif_mask |= BIT(mvif->idx);
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx; mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.hw_key_idx = -1;
...@@ -87,8 +88,9 @@ static void ...@@ -87,8 +88,9 @@ static void
mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ {
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct mt7603_sta *msta = &mvif->sta;
struct mt7603_dev *dev = hw->priv; 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_ADDR0(mvif->idx), 0);
mt76_wr(dev, MT_MAC_ADDR1(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) ...@@ -99,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
rcu_assign_pointer(dev->mt76.wcid[idx], NULL); rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mt76_txq_remove(&dev->mt76, vif->txq); 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); mutex_lock(&dev->mt76.mutex);
dev->vif_mask &= ~BIT(mvif->idx); dev->vif_mask &= ~BIT(mvif->idx);
mutex_unlock(&dev->mt76.mutex); mutex_unlock(&dev->mt76.mutex);
...@@ -325,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, ...@@ -325,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0) if (idx < 0)
return -ENOSPC; return -ENOSPC;
INIT_LIST_HEAD(&msta->poll_list);
__skb_queue_head_init(&msta->psq); __skb_queue_head_init(&msta->psq);
msta->ps = ~0; msta->ps = ~0;
msta->smps = ~0; msta->smps = ~0;
...@@ -361,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, ...@@ -361,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7603_filter_tx(dev, wcid->idx, true); mt7603_filter_tx(dev, wcid->idx, true);
spin_unlock_bh(&dev->ps_lock); 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); mt7603_wtbl_clear(dev, wcid->idx);
} }
......
...@@ -61,6 +61,9 @@ struct mt7603_sta { ...@@ -61,6 +61,9 @@ struct mt7603_sta {
struct mt7603_vif *vif; struct mt7603_vif *vif;
struct list_head poll_list;
u32 tx_airtime_ac[4];
struct sk_buff_head psq; struct sk_buff_head psq;
struct ieee80211_tx_rate rates[4]; struct ieee80211_tx_rate rates[4];
...@@ -103,6 +106,9 @@ struct mt7603_dev { ...@@ -103,6 +106,9 @@ struct mt7603_dev {
u8 vif_mask; u8 vif_mask;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
struct mt7603_sta global_sta; struct mt7603_sta global_sta;
u32 agc0, agc3; u32 agc0, agc3;
...@@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); ...@@ -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_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, void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
int ba_size); int ba_size);
void mt7603_mac_sta_poll(struct mt7603_dev *dev);
void mt7603_pse_client_reset(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment