Commit ea565833 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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 {
+2 −0
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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);
+86 −0
Original line number Diff line number Diff line
@@ -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;

Loading