Commit 942741da authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

wifi: mac80211: switch airtime fairness back to deficit round-robin scheduling



This reverts commits 6a789ba6 and
2433647b.

The virtual time scheduler code has a number of issues:
- queues slowed down by hardware/firmware powersave handling were not properly
  handled.
- on ath10k in push-pull mode, tx queues that the driver tries to pull from
  were starved, causing excessive latency
- delay between tx enqueue and reported airtime use were causing excessively
  bursty tx behavior

The bursty behavior may also be present on the round-robin scheduler, but there
it is much easier to fix without introducing additional regressions

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Acked-by: default avatarToke Høiland-Jørgensen <toke@toke.dk>
Link: https://lore.kernel.org/r/20220625212411.36675-1-nbd@nbd.name


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7f884baa
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -6832,6 +6832,9 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
{
}

void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
			      struct ieee80211_txq *txq, bool force);

/**
 * ieee80211_schedule_txq - schedule a TXQ for transmission
 *
@@ -6844,7 +6847,11 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
 * The driver may call this function if it has buffered packets for
 * this TXQ internally.
 */
void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
static inline void
ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
{
	__ieee80211_schedule_txq(hw, txq, true);
}

/**
 * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
@@ -6856,8 +6863,12 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
 * The driver may set force=true if it has buffered packets for this TXQ
 * internally.
 */
void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
			  bool force);
static inline void
ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
		     bool force)
{
	__ieee80211_schedule_txq(hw, txq, force);
}

/**
 * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
+1 −34
Original line number Diff line number Diff line
@@ -1581,38 +1581,6 @@ static void sta_apply_mesh_params(struct ieee80211_local *local,
#endif
}

static void sta_apply_airtime_params(struct ieee80211_local *local,
				     struct sta_info *sta,
				     struct station_parameters *params)
{
	u8 ac;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		struct airtime_sched_info *air_sched = &local->airtime[ac];
		struct airtime_info *air_info = &sta->airtime[ac];
		struct txq_info *txqi;
		u8 tid;

		spin_lock_bh(&air_sched->lock);
		for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
			if (air_info->weight == params->airtime_weight ||
			    !sta->sta.txq[tid] ||
			    ac != ieee80211_ac_from_tid(tid))
				continue;

			airtime_weight_set(air_info, params->airtime_weight);

			txqi = to_txq_info(sta->sta.txq[tid]);
			if (RB_EMPTY_NODE(&txqi->schedule_order))
				continue;

			ieee80211_update_airtime_weight(local, air_sched,
							0, true);
		}
		spin_unlock_bh(&air_sched->lock);
	}
}

static int sta_apply_parameters(struct ieee80211_local *local,
				struct sta_info *sta,
				struct station_parameters *params)
@@ -1811,8 +1779,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
		sta_apply_mesh_params(local, sta, params);

	if (params->airtime_weight)
		sta_apply_airtime_params(local, sta, params);

		sta->airtime_weight = params->airtime_weight;

	/* set the STA state after all sta info from usermode has been set */
	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
+13 −57
Original line number Diff line number Diff line
@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct file *file,
			"VI	%u		%u\n"
			"BE	%u		%u\n"
			"BK	%u		%u\n",
			local->airtime[IEEE80211_AC_VO].aql_txq_limit_low,
			local->airtime[IEEE80211_AC_VO].aql_txq_limit_high,
			local->airtime[IEEE80211_AC_VI].aql_txq_limit_low,
			local->airtime[IEEE80211_AC_VI].aql_txq_limit_high,
			local->airtime[IEEE80211_AC_BE].aql_txq_limit_low,
			local->airtime[IEEE80211_AC_BE].aql_txq_limit_high,
			local->airtime[IEEE80211_AC_BK].aql_txq_limit_low,
			local->airtime[IEEE80211_AC_BK].aql_txq_limit_high);
			local->aql_txq_limit_low[IEEE80211_AC_VO],
			local->aql_txq_limit_high[IEEE80211_AC_VO],
			local->aql_txq_limit_low[IEEE80211_AC_VI],
			local->aql_txq_limit_high[IEEE80211_AC_VI],
			local->aql_txq_limit_low[IEEE80211_AC_BE],
			local->aql_txq_limit_high[IEEE80211_AC_BE],
			local->aql_txq_limit_low[IEEE80211_AC_BK],
			local->aql_txq_limit_high[IEEE80211_AC_BK]);
	return simple_read_from_buffer(user_buf, count, ppos,
				       buf, len);
}
@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struct file *file,
	if (ac >= IEEE80211_NUM_ACS)
		return -EINVAL;

	q_limit_low_old = local->airtime[ac].aql_txq_limit_low;
	q_limit_high_old = local->airtime[ac].aql_txq_limit_high;
	q_limit_low_old = local->aql_txq_limit_low[ac];
	q_limit_high_old = local->aql_txq_limit_high[ac];

	local->airtime[ac].aql_txq_limit_low = q_limit_low;
	local->airtime[ac].aql_txq_limit_high = q_limit_high;
	local->aql_txq_limit_low[ac] = q_limit_low;
	local->aql_txq_limit_high[ac] = q_limit_high;

	mutex_lock(&local->sta_mtx);
	list_for_each_entry(sta, &local->sta_list, list) {
@@ -382,46 +382,6 @@ static const struct file_operations force_tx_status_ops = {
	.llseek = default_llseek,
};

static ssize_t airtime_read(struct file *file,
			    char __user *user_buf,
			    size_t count,
			    loff_t *ppos)
{
	struct ieee80211_local *local = file->private_data;
	char buf[200];
	u64 v_t[IEEE80211_NUM_ACS];
	u64 wt[IEEE80211_NUM_ACS];
	int len = 0, ac;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		spin_lock_bh(&local->airtime[ac].lock);
		v_t[ac] = local->airtime[ac].v_t;
		wt[ac] = local->airtime[ac].weight_sum;
		spin_unlock_bh(&local->airtime[ac].lock);
	}
	len = scnprintf(buf, sizeof(buf),
			"\tVO         VI         BE         BK\n"
			"Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
			"Weight\t%-10llu %-10llu %-10llu %-10llu\n",
			v_t[0],
			v_t[1],
			v_t[2],
			v_t[3],
			wt[0],
			wt[1],
			wt[2],
			wt[3]);

	return simple_read_from_buffer(user_buf, count, ppos,
				       buf, len);
}

static const struct file_operations airtime_ops = {
	.read = airtime_read,
	.open = simple_open,
	.llseek = default_llseek,
};

#ifdef CONFIG_PM
static ssize_t reset_write(struct file *file, const char __user *user_buf,
			   size_t count, loff_t *ppos)
@@ -675,11 +635,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
	if (local->ops->wake_tx_queue)
		DEBUGFS_ADD_MODE(aqm, 0600);

	if (wiphy_ext_feature_isset(local->hw.wiphy,
				    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
		DEBUGFS_ADD_MODE(airtime, 0600);
	DEBUGFS_ADD_MODE(airtime_flags, 0600);
	}

	DEBUGFS_ADD(aql_txq_limit);
	debugfs_create_u32("aql_threshold", 0600,
+1 −31
Original line number Diff line number Diff line
@@ -510,34 +510,6 @@ static ssize_t ieee80211_if_fmt_aqm(
}
IEEE80211_IF_FILE_R(aqm);

static ssize_t ieee80211_if_fmt_airtime(
	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_txq *txq = sdata->vif.txq;
	struct airtime_info *air_info;
	int len;

	if (!txq)
		return 0;

	spin_lock_bh(&local->airtime[txq->ac].lock);
	air_info = to_airtime_info(txq);
	len = scnprintf(buf,
			buflen,
			"RX: %llu us\nTX: %llu us\nWeight: %u\n"
			"Virt-T: %lld us\n",
			air_info->rx_airtime,
			air_info->tx_airtime,
			air_info->weight,
			air_info->v_t);
	spin_unlock_bh(&local->airtime[txq->ac].lock);

	return len;
}

IEEE80211_IF_FILE_R(airtime);

IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);

/* IBSS attributes */
@@ -683,10 +655,8 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)

	if (sdata->local->ops->wake_tx_queue &&
	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
	    sdata->vif.type != NL80211_IFTYPE_NAN) {
	    sdata->vif.type != NL80211_IFTYPE_NAN)
		DEBUGFS_ADD(aqm);
		DEBUGFS_ADD(airtime);
	}
}

static void add_sta_files(struct ieee80211_sub_if_data *sdata)
+12 −12
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
	size_t bufsz = 400;
	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
	u64 rx_airtime = 0, tx_airtime = 0;
	u64 v_t[IEEE80211_NUM_ACS];
	s64 deficit[IEEE80211_NUM_ACS];
	ssize_t rv;
	int ac;

@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
		return -ENOMEM;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		spin_lock_bh(&local->airtime[ac].lock);
		spin_lock_bh(&local->active_txq_lock[ac]);
		rx_airtime += sta->airtime[ac].rx_airtime;
		tx_airtime += sta->airtime[ac].tx_airtime;
		v_t[ac] = sta->airtime[ac].v_t;
		spin_unlock_bh(&local->airtime[ac].lock);
		deficit[ac] = sta->airtime[ac].deficit;
		spin_unlock_bh(&local->active_txq_lock[ac]);
	}

	p += scnprintf(p, bufsz + buf - p,
		"RX: %llu us\nTX: %llu us\nWeight: %u\n"
		"Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
		rx_airtime, tx_airtime, sta->airtime[0].weight,
		v_t[0], v_t[1], v_t[2], v_t[3]);
		"Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
		rx_airtime, tx_airtime, sta->airtime_weight,
		deficit[0], deficit[1], deficit[2], deficit[3]);

	rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
	kfree(buf);
@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
	int ac;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		spin_lock_bh(&local->airtime[ac].lock);
		spin_lock_bh(&local->active_txq_lock[ac]);
		sta->airtime[ac].rx_airtime = 0;
		sta->airtime[ac].tx_airtime = 0;
		sta->airtime[ac].v_t = 0;
		spin_unlock_bh(&local->airtime[ac].lock);
		sta->airtime[ac].deficit = sta->airtime_weight;
		spin_unlock_bh(&local->active_txq_lock[ac]);
	}

	return count;
@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file *file, char __user *userbuf,
		return -ENOMEM;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		spin_lock_bh(&local->airtime[ac].lock);
		spin_lock_bh(&local->active_txq_lock[ac]);
		q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
		q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
		spin_unlock_bh(&local->airtime[ac].lock);
		spin_unlock_bh(&local->active_txq_lock[ac]);
		q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
	}

Loading