18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/******************************************************************************
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Contact Information:
78c2ecf20Sopenharmony_ci *  Intel Linux Wireless <ilw@linux.intel.com>
88c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *****************************************************************************/
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <net/mac80211.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
198c2ecf20Sopenharmony_ci#include <linux/delay.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "commands.h"
248c2ecf20Sopenharmony_ci#include "3945.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define RS_NAME "iwl-3945-rs"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic s32 il3945_expected_tpt_g[RATE_COUNT_3945] = {
298c2ecf20Sopenharmony_ci	7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic s32 il3945_expected_tpt_g_prot[RATE_COUNT_3945] = {
338c2ecf20Sopenharmony_ci	7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic s32 il3945_expected_tpt_a[RATE_COUNT_3945] = {
378c2ecf20Sopenharmony_ci	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic s32 il3945_expected_tpt_b[RATE_COUNT_3945] = {
418c2ecf20Sopenharmony_ci	7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct il3945_tpt_entry {
458c2ecf20Sopenharmony_ci	s8 min_rssi;
468c2ecf20Sopenharmony_ci	u8 idx;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic struct il3945_tpt_entry il3945_tpt_table_a[] = {
508c2ecf20Sopenharmony_ci	{-60, RATE_54M_IDX},
518c2ecf20Sopenharmony_ci	{-64, RATE_48M_IDX},
528c2ecf20Sopenharmony_ci	{-72, RATE_36M_IDX},
538c2ecf20Sopenharmony_ci	{-80, RATE_24M_IDX},
548c2ecf20Sopenharmony_ci	{-84, RATE_18M_IDX},
558c2ecf20Sopenharmony_ci	{-85, RATE_12M_IDX},
568c2ecf20Sopenharmony_ci	{-87, RATE_9M_IDX},
578c2ecf20Sopenharmony_ci	{-89, RATE_6M_IDX}
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic struct il3945_tpt_entry il3945_tpt_table_g[] = {
618c2ecf20Sopenharmony_ci	{-60, RATE_54M_IDX},
628c2ecf20Sopenharmony_ci	{-64, RATE_48M_IDX},
638c2ecf20Sopenharmony_ci	{-68, RATE_36M_IDX},
648c2ecf20Sopenharmony_ci	{-80, RATE_24M_IDX},
658c2ecf20Sopenharmony_ci	{-84, RATE_18M_IDX},
668c2ecf20Sopenharmony_ci	{-85, RATE_12M_IDX},
678c2ecf20Sopenharmony_ci	{-86, RATE_11M_IDX},
688c2ecf20Sopenharmony_ci	{-88, RATE_5M_IDX},
698c2ecf20Sopenharmony_ci	{-90, RATE_2M_IDX},
708c2ecf20Sopenharmony_ci	{-92, RATE_1M_IDX}
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define RATE_MAX_WINDOW		62
748c2ecf20Sopenharmony_ci#define RATE_FLUSH		(3*HZ)
758c2ecf20Sopenharmony_ci#define RATE_WIN_FLUSH		(HZ/2)
768c2ecf20Sopenharmony_ci#define IL39_RATE_HIGH_TH	11520
778c2ecf20Sopenharmony_ci#define IL_SUCCESS_UP_TH	8960
788c2ecf20Sopenharmony_ci#define IL_SUCCESS_DOWN_TH	10880
798c2ecf20Sopenharmony_ci#define RATE_MIN_FAILURE_TH	6
808c2ecf20Sopenharmony_ci#define RATE_MIN_SUCCESS_TH	8
818c2ecf20Sopenharmony_ci#define RATE_DECREASE_TH	1920
828c2ecf20Sopenharmony_ci#define RATE_RETRY_TH		15
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic u8
858c2ecf20Sopenharmony_ciil3945_get_rate_idx_by_rssi(s32 rssi, enum nl80211_band band)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	u32 idx = 0;
888c2ecf20Sopenharmony_ci	u32 table_size = 0;
898c2ecf20Sopenharmony_ci	struct il3945_tpt_entry *tpt_table = NULL;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (rssi < IL_MIN_RSSI_VAL || rssi > IL_MAX_RSSI_VAL)
928c2ecf20Sopenharmony_ci		rssi = IL_MIN_RSSI_VAL;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	switch (band) {
958c2ecf20Sopenharmony_ci	case NL80211_BAND_2GHZ:
968c2ecf20Sopenharmony_ci		tpt_table = il3945_tpt_table_g;
978c2ecf20Sopenharmony_ci		table_size = ARRAY_SIZE(il3945_tpt_table_g);
988c2ecf20Sopenharmony_ci		break;
998c2ecf20Sopenharmony_ci	case NL80211_BAND_5GHZ:
1008c2ecf20Sopenharmony_ci		tpt_table = il3945_tpt_table_a;
1018c2ecf20Sopenharmony_ci		table_size = ARRAY_SIZE(il3945_tpt_table_a);
1028c2ecf20Sopenharmony_ci		break;
1038c2ecf20Sopenharmony_ci	default:
1048c2ecf20Sopenharmony_ci		BUG();
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	while (idx < table_size && rssi < tpt_table[idx].min_rssi)
1098c2ecf20Sopenharmony_ci		idx++;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	idx = min(idx, table_size - 1);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return tpt_table[idx].idx;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic void
1178c2ecf20Sopenharmony_ciil3945_clear_win(struct il3945_rate_scale_data *win)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	win->data = 0;
1208c2ecf20Sopenharmony_ci	win->success_counter = 0;
1218c2ecf20Sopenharmony_ci	win->success_ratio = -1;
1228c2ecf20Sopenharmony_ci	win->counter = 0;
1238c2ecf20Sopenharmony_ci	win->average_tpt = IL_INVALID_VALUE;
1248c2ecf20Sopenharmony_ci	win->stamp = 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * il3945_rate_scale_flush_wins - flush out the rate scale wins
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * Returns the number of wins that have gathered data but were
1318c2ecf20Sopenharmony_ci * not flushed.  If there were any that were not flushed, then
1328c2ecf20Sopenharmony_ci * reschedule the rate flushing routine.
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistatic int
1358c2ecf20Sopenharmony_ciil3945_rate_scale_flush_wins(struct il3945_rs_sta *rs_sta)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	int unflushed = 0;
1388c2ecf20Sopenharmony_ci	int i;
1398c2ecf20Sopenharmony_ci	unsigned long flags;
1408c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/*
1438c2ecf20Sopenharmony_ci	 * For each rate, if we have collected data on that rate
1448c2ecf20Sopenharmony_ci	 * and it has been more than RATE_WIN_FLUSH
1458c2ecf20Sopenharmony_ci	 * since we flushed, clear out the gathered stats
1468c2ecf20Sopenharmony_ci	 */
1478c2ecf20Sopenharmony_ci	for (i = 0; i < RATE_COUNT_3945; i++) {
1488c2ecf20Sopenharmony_ci		if (!rs_sta->win[i].counter)
1498c2ecf20Sopenharmony_ci			continue;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		spin_lock_irqsave(&rs_sta->lock, flags);
1528c2ecf20Sopenharmony_ci		if (time_after(jiffies, rs_sta->win[i].stamp + RATE_WIN_FLUSH)) {
1538c2ecf20Sopenharmony_ci			D_RATE("flushing %d samples of rate " "idx %d\n",
1548c2ecf20Sopenharmony_ci			       rs_sta->win[i].counter, i);
1558c2ecf20Sopenharmony_ci			il3945_clear_win(&rs_sta->win[i]);
1568c2ecf20Sopenharmony_ci		} else
1578c2ecf20Sopenharmony_ci			unflushed++;
1588c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rs_sta->lock, flags);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return unflushed;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci#define RATE_FLUSH_MAX              5000	/* msec */
1658c2ecf20Sopenharmony_ci#define RATE_FLUSH_MIN              50	/* msec */
1668c2ecf20Sopenharmony_ci#define IL_AVERAGE_PACKETS             1500
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void
1698c2ecf20Sopenharmony_ciil3945_bg_rate_scale_flush(struct timer_list *t)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta = from_timer(rs_sta, t, rate_scale_flush);
1728c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
1738c2ecf20Sopenharmony_ci	int unflushed = 0;
1748c2ecf20Sopenharmony_ci	unsigned long flags;
1758c2ecf20Sopenharmony_ci	u32 packet_count, duration, pps;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	D_RATE("enter\n");
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	unflushed = il3945_rate_scale_flush_wins(rs_sta);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Number of packets Rx'd since last time this timer ran */
1848c2ecf20Sopenharmony_ci	packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	rs_sta->last_tx_packets = rs_sta->tx_packets + 1;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (unflushed) {
1898c2ecf20Sopenharmony_ci		duration =
1908c2ecf20Sopenharmony_ci		    jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		D_RATE("Tx'd %d packets in %dms\n", packet_count, duration);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		/* Determine packets per second */
1958c2ecf20Sopenharmony_ci		if (duration)
1968c2ecf20Sopenharmony_ci			pps = (packet_count * 1000) / duration;
1978c2ecf20Sopenharmony_ci		else
1988c2ecf20Sopenharmony_ci			pps = 0;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		if (pps) {
2018c2ecf20Sopenharmony_ci			duration = (IL_AVERAGE_PACKETS * 1000) / pps;
2028c2ecf20Sopenharmony_ci			if (duration < RATE_FLUSH_MIN)
2038c2ecf20Sopenharmony_ci				duration = RATE_FLUSH_MIN;
2048c2ecf20Sopenharmony_ci			else if (duration > RATE_FLUSH_MAX)
2058c2ecf20Sopenharmony_ci				duration = RATE_FLUSH_MAX;
2068c2ecf20Sopenharmony_ci		} else
2078c2ecf20Sopenharmony_ci			duration = RATE_FLUSH_MAX;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		rs_sta->flush_time = msecs_to_jiffies(duration);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		D_RATE("new flush period: %d msec ave %d\n", duration,
2128c2ecf20Sopenharmony_ci		       packet_count);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		mod_timer(&rs_sta->rate_scale_flush,
2158c2ecf20Sopenharmony_ci			  jiffies + rs_sta->flush_time);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		rs_sta->last_partial_flush = jiffies;
2188c2ecf20Sopenharmony_ci	} else {
2198c2ecf20Sopenharmony_ci		rs_sta->flush_time = RATE_FLUSH;
2208c2ecf20Sopenharmony_ci		rs_sta->flush_pending = 0;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	/* If there weren't any unflushed entries, we don't schedule the timer
2238c2ecf20Sopenharmony_ci	 * to run again */
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	rs_sta->last_flush = jiffies;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	D_RATE("leave\n");
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/*
2338c2ecf20Sopenharmony_ci * il3945_collect_tx_data - Update the success/failure sliding win
2348c2ecf20Sopenharmony_ci *
2358c2ecf20Sopenharmony_ci * We keep a sliding win of the last 64 packets transmitted
2368c2ecf20Sopenharmony_ci * at this rate.  win->data contains the bitmask of successful
2378c2ecf20Sopenharmony_ci * packets.
2388c2ecf20Sopenharmony_ci */
2398c2ecf20Sopenharmony_cistatic void
2408c2ecf20Sopenharmony_ciil3945_collect_tx_data(struct il3945_rs_sta *rs_sta,
2418c2ecf20Sopenharmony_ci		       struct il3945_rate_scale_data *win, int success,
2428c2ecf20Sopenharmony_ci		       int retries, int idx)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	unsigned long flags;
2458c2ecf20Sopenharmony_ci	s32 fail_count;
2468c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (!retries) {
2498c2ecf20Sopenharmony_ci		D_RATE("leave: retries == 0 -- should be at least 1\n");
2508c2ecf20Sopenharmony_ci		return;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/*
2568c2ecf20Sopenharmony_ci	 * Keep track of only the latest 62 tx frame attempts in this rate's
2578c2ecf20Sopenharmony_ci	 * history win; anything older isn't really relevant any more.
2588c2ecf20Sopenharmony_ci	 * If we have filled up the sliding win, drop the oldest attempt;
2598c2ecf20Sopenharmony_ci	 * if the oldest attempt (highest bit in bitmap) shows "success",
2608c2ecf20Sopenharmony_ci	 * subtract "1" from the success counter (this is the main reason
2618c2ecf20Sopenharmony_ci	 * we keep these bitmaps!).
2628c2ecf20Sopenharmony_ci	 * */
2638c2ecf20Sopenharmony_ci	while (retries > 0) {
2648c2ecf20Sopenharmony_ci		if (win->counter >= RATE_MAX_WINDOW) {
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci			/* remove earliest */
2678c2ecf20Sopenharmony_ci			win->counter = RATE_MAX_WINDOW - 1;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci			if (win->data & (1ULL << (RATE_MAX_WINDOW - 1))) {
2708c2ecf20Sopenharmony_ci				win->data &= ~(1ULL << (RATE_MAX_WINDOW - 1));
2718c2ecf20Sopenharmony_ci				win->success_counter--;
2728c2ecf20Sopenharmony_ci			}
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		/* Increment frames-attempted counter */
2768c2ecf20Sopenharmony_ci		win->counter++;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		/* Shift bitmap by one frame (throw away oldest history),
2798c2ecf20Sopenharmony_ci		 * OR in "1", and increment "success" if this
2808c2ecf20Sopenharmony_ci		 * frame was successful. */
2818c2ecf20Sopenharmony_ci		win->data <<= 1;
2828c2ecf20Sopenharmony_ci		if (success > 0) {
2838c2ecf20Sopenharmony_ci			win->success_counter++;
2848c2ecf20Sopenharmony_ci			win->data |= 0x1;
2858c2ecf20Sopenharmony_ci			success--;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		retries--;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* Calculate current success ratio, avoid divide-by-0! */
2928c2ecf20Sopenharmony_ci	if (win->counter > 0)
2938c2ecf20Sopenharmony_ci		win->success_ratio =
2948c2ecf20Sopenharmony_ci		    128 * (100 * win->success_counter) / win->counter;
2958c2ecf20Sopenharmony_ci	else
2968c2ecf20Sopenharmony_ci		win->success_ratio = IL_INVALID_VALUE;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	fail_count = win->counter - win->success_counter;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* Calculate average throughput, if we have enough history. */
3018c2ecf20Sopenharmony_ci	if (fail_count >= RATE_MIN_FAILURE_TH ||
3028c2ecf20Sopenharmony_ci	    win->success_counter >= RATE_MIN_SUCCESS_TH)
3038c2ecf20Sopenharmony_ci		win->average_tpt =
3048c2ecf20Sopenharmony_ci		    ((win->success_ratio * rs_sta->expected_tpt[idx] +
3058c2ecf20Sopenharmony_ci		      64) / 128);
3068c2ecf20Sopenharmony_ci	else
3078c2ecf20Sopenharmony_ci		win->average_tpt = IL_INVALID_VALUE;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	/* Tag this win as having been updated */
3108c2ecf20Sopenharmony_ci	win->stamp = jiffies;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/*
3168c2ecf20Sopenharmony_ci * Called after adding a new station to initialize rate scaling
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_civoid
3198c2ecf20Sopenharmony_ciil3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = il->hw;
3228c2ecf20Sopenharmony_ci	struct ieee80211_conf *conf = &il->hw->conf;
3238c2ecf20Sopenharmony_ci	struct il3945_sta_priv *psta;
3248c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
3258c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
3268c2ecf20Sopenharmony_ci	int i;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	D_INFO("enter\n");
3298c2ecf20Sopenharmony_ci	if (sta_id == il->hw_params.bcast_id)
3308c2ecf20Sopenharmony_ci		goto out;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	psta = (struct il3945_sta_priv *)sta->drv_priv;
3338c2ecf20Sopenharmony_ci	rs_sta = &psta->rs_sta;
3348c2ecf20Sopenharmony_ci	sband = hw->wiphy->bands[conf->chandef.chan->band];
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	rs_sta->il = il;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	rs_sta->start_rate = RATE_INVALID;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* default to just 802.11b */
3418c2ecf20Sopenharmony_ci	rs_sta->expected_tpt = il3945_expected_tpt_b;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	rs_sta->last_partial_flush = jiffies;
3448c2ecf20Sopenharmony_ci	rs_sta->last_flush = jiffies;
3458c2ecf20Sopenharmony_ci	rs_sta->flush_time = RATE_FLUSH;
3468c2ecf20Sopenharmony_ci	rs_sta->last_tx_packets = 0;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	for (i = 0; i < RATE_COUNT_3945; i++)
3498c2ecf20Sopenharmony_ci		il3945_clear_win(&rs_sta->win[i]);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* TODO: what is a good starting rate for STA? About middle? Maybe not
3528c2ecf20Sopenharmony_ci	 * the lowest or the highest rate.. Could consider using RSSI from
3538c2ecf20Sopenharmony_ci	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
3548c2ecf20Sopenharmony_ci	 * after assoc.. */
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	for (i = sband->n_bitrates - 1; i >= 0; i--) {
3578c2ecf20Sopenharmony_ci		if (sta->supp_rates[sband->band] & (1 << i)) {
3588c2ecf20Sopenharmony_ci			rs_sta->last_txrate_idx = i;
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	il->_3945.sta_supp_rates = sta->supp_rates[sband->band];
3648c2ecf20Sopenharmony_ci	/* For 5 GHz band it start at IL_FIRST_OFDM_RATE */
3658c2ecf20Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ) {
3668c2ecf20Sopenharmony_ci		rs_sta->last_txrate_idx += IL_FIRST_OFDM_RATE;
3678c2ecf20Sopenharmony_ci		il->_3945.sta_supp_rates <<= IL_FIRST_OFDM_RATE;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciout:
3718c2ecf20Sopenharmony_ci	il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	D_INFO("leave\n");
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic void *
3778c2ecf20Sopenharmony_ciil3945_rs_alloc(struct ieee80211_hw *hw)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	return hw->priv;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/* rate scale requires free function to be implemented */
3838c2ecf20Sopenharmony_cistatic void
3848c2ecf20Sopenharmony_ciil3945_rs_free(void *il)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic void *
3898c2ecf20Sopenharmony_ciil3945_rs_alloc_sta(void *il_priv, struct ieee80211_sta *sta, gfp_t gfp)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
3928c2ecf20Sopenharmony_ci	struct il3945_sta_priv *psta = (void *)sta->drv_priv;
3938c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = il_priv;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	D_RATE("enter\n");
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	rs_sta = &psta->rs_sta;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	spin_lock_init(&rs_sta->lock);
4008c2ecf20Sopenharmony_ci	timer_setup(&rs_sta->rate_scale_flush, il3945_bg_rate_scale_flush, 0);
4018c2ecf20Sopenharmony_ci	D_RATE("leave\n");
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return rs_sta;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic void
4078c2ecf20Sopenharmony_ciil3945_rs_free_sta(void *il_priv, struct ieee80211_sta *sta, void *il_sta)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/*
4128c2ecf20Sopenharmony_ci	 * Be careful not to use any members of il3945_rs_sta (like trying
4138c2ecf20Sopenharmony_ci	 * to use il_priv to print out debugging) since it may not be fully
4148c2ecf20Sopenharmony_ci	 * initialized at this point.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	del_timer_sync(&rs_sta->rate_scale_flush);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/*
4208c2ecf20Sopenharmony_ci * il3945_rs_tx_status - Update rate control values based on Tx results
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * NOTE: Uses il_priv->retry_rate for the # of retries attempted by
4238c2ecf20Sopenharmony_ci * the hardware for each rate.
4248c2ecf20Sopenharmony_ci */
4258c2ecf20Sopenharmony_cistatic void
4268c2ecf20Sopenharmony_ciil3945_rs_tx_status(void *il_rate, struct ieee80211_supported_band *sband,
4278c2ecf20Sopenharmony_ci		    struct ieee80211_sta *sta, void *il_sta,
4288c2ecf20Sopenharmony_ci		    struct sk_buff *skb)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	s8 retries = 0, current_count;
4318c2ecf20Sopenharmony_ci	int scale_rate_idx, first_idx, last_idx;
4328c2ecf20Sopenharmony_ci	unsigned long flags;
4338c2ecf20Sopenharmony_ci	struct il_priv *il = (struct il_priv *)il_rate;
4348c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
4358c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	D_RATE("enter\n");
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	retries = info->status.rates[0].count;
4408c2ecf20Sopenharmony_ci	/* Sanity Check for retries */
4418c2ecf20Sopenharmony_ci	if (retries > RATE_RETRY_TH)
4428c2ecf20Sopenharmony_ci		retries = RATE_RETRY_TH;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	first_idx = sband->bitrates[info->status.rates[0].idx].hw_value;
4458c2ecf20Sopenharmony_ci	if (first_idx < 0 || first_idx >= RATE_COUNT_3945) {
4468c2ecf20Sopenharmony_ci		D_RATE("leave: Rate out of bounds: %d\n", first_idx);
4478c2ecf20Sopenharmony_ci		return;
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (!il_sta) {
4518c2ecf20Sopenharmony_ci		D_RATE("leave: No STA il data to update!\n");
4528c2ecf20Sopenharmony_ci		return;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Treat uninitialized rate scaling data same as non-existing. */
4568c2ecf20Sopenharmony_ci	if (!rs_sta->il) {
4578c2ecf20Sopenharmony_ci		D_RATE("leave: STA il data uninitialized!\n");
4588c2ecf20Sopenharmony_ci		return;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	rs_sta->tx_packets++;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	scale_rate_idx = first_idx;
4648c2ecf20Sopenharmony_ci	last_idx = first_idx;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * Update the win for each rate.  We determine which rates
4688c2ecf20Sopenharmony_ci	 * were Tx'd based on the total number of retries vs. the number
4698c2ecf20Sopenharmony_ci	 * of retries configured for each rate -- currently set to the
4708c2ecf20Sopenharmony_ci	 * il value 'retry_rate' vs. rate specific
4718c2ecf20Sopenharmony_ci	 *
4728c2ecf20Sopenharmony_ci	 * On exit from this while loop last_idx indicates the rate
4738c2ecf20Sopenharmony_ci	 * at which the frame was finally transmitted (or failed if no
4748c2ecf20Sopenharmony_ci	 * ACK)
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci	while (retries > 1) {
4778c2ecf20Sopenharmony_ci		if ((retries - 1) < il->retry_rate) {
4788c2ecf20Sopenharmony_ci			current_count = (retries - 1);
4798c2ecf20Sopenharmony_ci			last_idx = scale_rate_idx;
4808c2ecf20Sopenharmony_ci		} else {
4818c2ecf20Sopenharmony_ci			current_count = il->retry_rate;
4828c2ecf20Sopenharmony_ci			last_idx = il3945_rs_next_rate(il, scale_rate_idx);
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		/* Update this rate accounting for as many retries
4868c2ecf20Sopenharmony_ci		 * as was used for it (per current_count) */
4878c2ecf20Sopenharmony_ci		il3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_idx], 0,
4888c2ecf20Sopenharmony_ci				       current_count, scale_rate_idx);
4898c2ecf20Sopenharmony_ci		D_RATE("Update rate %d for %d retries.\n", scale_rate_idx,
4908c2ecf20Sopenharmony_ci		       current_count);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		retries -= current_count;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		scale_rate_idx = last_idx;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* Update the last idx win with success/failure based on ACK */
4988c2ecf20Sopenharmony_ci	D_RATE("Update rate %d with %s.\n", last_idx,
4998c2ecf20Sopenharmony_ci	       (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure");
5008c2ecf20Sopenharmony_ci	il3945_collect_tx_data(rs_sta, &rs_sta->win[last_idx],
5018c2ecf20Sopenharmony_ci			       info->flags & IEEE80211_TX_STAT_ACK, 1,
5028c2ecf20Sopenharmony_ci			       last_idx);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/* We updated the rate scale win -- if its been more than
5058c2ecf20Sopenharmony_ci	 * flush_time since the last run, schedule the flush
5068c2ecf20Sopenharmony_ci	 * again */
5078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (!rs_sta->flush_pending &&
5108c2ecf20Sopenharmony_ci	    time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) {
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		rs_sta->last_partial_flush = jiffies;
5138c2ecf20Sopenharmony_ci		rs_sta->flush_pending = 1;
5148c2ecf20Sopenharmony_ci		mod_timer(&rs_sta->rate_scale_flush,
5158c2ecf20Sopenharmony_ci			  jiffies + rs_sta->flush_time);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	D_RATE("leave\n");
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic u16
5248c2ecf20Sopenharmony_ciil3945_get_adjacent_rate(struct il3945_rs_sta *rs_sta, u8 idx, u16 rate_mask,
5258c2ecf20Sopenharmony_ci			 enum nl80211_band band)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	u8 high = RATE_INVALID;
5288c2ecf20Sopenharmony_ci	u8 low = RATE_INVALID;
5298c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* 802.11A walks to the next literal adjacent rate in
5328c2ecf20Sopenharmony_ci	 * the rate table */
5338c2ecf20Sopenharmony_ci	if (unlikely(band == NL80211_BAND_5GHZ)) {
5348c2ecf20Sopenharmony_ci		int i;
5358c2ecf20Sopenharmony_ci		u32 mask;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		/* Find the previous rate that is in the rate mask */
5388c2ecf20Sopenharmony_ci		i = idx - 1;
5398c2ecf20Sopenharmony_ci		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
5408c2ecf20Sopenharmony_ci			if (rate_mask & mask) {
5418c2ecf20Sopenharmony_ci				low = i;
5428c2ecf20Sopenharmony_ci				break;
5438c2ecf20Sopenharmony_ci			}
5448c2ecf20Sopenharmony_ci		}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		/* Find the next rate that is in the rate mask */
5478c2ecf20Sopenharmony_ci		i = idx + 1;
5488c2ecf20Sopenharmony_ci		for (mask = (1 << i); i < RATE_COUNT_3945; i++, mask <<= 1) {
5498c2ecf20Sopenharmony_ci			if (rate_mask & mask) {
5508c2ecf20Sopenharmony_ci				high = i;
5518c2ecf20Sopenharmony_ci				break;
5528c2ecf20Sopenharmony_ci			}
5538c2ecf20Sopenharmony_ci		}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		return (high << 8) | low;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	low = idx;
5598c2ecf20Sopenharmony_ci	while (low != RATE_INVALID) {
5608c2ecf20Sopenharmony_ci		if (rs_sta->tgg)
5618c2ecf20Sopenharmony_ci			low = il3945_rates[low].prev_rs_tgg;
5628c2ecf20Sopenharmony_ci		else
5638c2ecf20Sopenharmony_ci			low = il3945_rates[low].prev_rs;
5648c2ecf20Sopenharmony_ci		if (low == RATE_INVALID)
5658c2ecf20Sopenharmony_ci			break;
5668c2ecf20Sopenharmony_ci		if (rate_mask & (1 << low))
5678c2ecf20Sopenharmony_ci			break;
5688c2ecf20Sopenharmony_ci		D_RATE("Skipping masked lower rate: %d\n", low);
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	high = idx;
5728c2ecf20Sopenharmony_ci	while (high != RATE_INVALID) {
5738c2ecf20Sopenharmony_ci		if (rs_sta->tgg)
5748c2ecf20Sopenharmony_ci			high = il3945_rates[high].next_rs_tgg;
5758c2ecf20Sopenharmony_ci		else
5768c2ecf20Sopenharmony_ci			high = il3945_rates[high].next_rs;
5778c2ecf20Sopenharmony_ci		if (high == RATE_INVALID)
5788c2ecf20Sopenharmony_ci			break;
5798c2ecf20Sopenharmony_ci		if (rate_mask & (1 << high))
5808c2ecf20Sopenharmony_ci			break;
5818c2ecf20Sopenharmony_ci		D_RATE("Skipping masked higher rate: %d\n", high);
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return (high << 8) | low;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci/*
5888c2ecf20Sopenharmony_ci * il3945_rs_get_rate - find the rate for the requested packet
5898c2ecf20Sopenharmony_ci *
5908c2ecf20Sopenharmony_ci * Returns the ieee80211_rate structure allocated by the driver.
5918c2ecf20Sopenharmony_ci *
5928c2ecf20Sopenharmony_ci * The rate control algorithm has no internal mapping between hw_mode's
5938c2ecf20Sopenharmony_ci * rate ordering and the rate ordering used by the rate control algorithm.
5948c2ecf20Sopenharmony_ci *
5958c2ecf20Sopenharmony_ci * The rate control algorithm uses a single table of rates that goes across
5968c2ecf20Sopenharmony_ci * the entire A/B/G spectrum vs. being limited to just one particular
5978c2ecf20Sopenharmony_ci * hw_mode.
5988c2ecf20Sopenharmony_ci *
5998c2ecf20Sopenharmony_ci * As such, we can't convert the idx obtained below into the hw_mode's
6008c2ecf20Sopenharmony_ci * rate table and must reference the driver allocated rate table
6018c2ecf20Sopenharmony_ci *
6028c2ecf20Sopenharmony_ci */
6038c2ecf20Sopenharmony_cistatic void
6048c2ecf20Sopenharmony_ciil3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
6058c2ecf20Sopenharmony_ci		   struct ieee80211_tx_rate_control *txrc)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband = txrc->sband;
6088c2ecf20Sopenharmony_ci	struct sk_buff *skb = txrc->skb;
6098c2ecf20Sopenharmony_ci	u8 low = RATE_INVALID;
6108c2ecf20Sopenharmony_ci	u8 high = RATE_INVALID;
6118c2ecf20Sopenharmony_ci	u16 high_low;
6128c2ecf20Sopenharmony_ci	int idx;
6138c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
6148c2ecf20Sopenharmony_ci	struct il3945_rate_scale_data *win = NULL;
6158c2ecf20Sopenharmony_ci	int current_tpt = IL_INVALID_VALUE;
6168c2ecf20Sopenharmony_ci	int low_tpt = IL_INVALID_VALUE;
6178c2ecf20Sopenharmony_ci	int high_tpt = IL_INVALID_VALUE;
6188c2ecf20Sopenharmony_ci	u32 fail_count;
6198c2ecf20Sopenharmony_ci	s8 scale_action = 0;
6208c2ecf20Sopenharmony_ci	unsigned long flags;
6218c2ecf20Sopenharmony_ci	u16 rate_mask;
6228c2ecf20Sopenharmony_ci	s8 max_rate_idx = -1;
6238c2ecf20Sopenharmony_ci	struct il_priv *il __maybe_unused = (struct il_priv *)il_r;
6248c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	D_RATE("enter\n");
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/* Treat uninitialized rate scaling data same as non-existing. */
6298c2ecf20Sopenharmony_ci	if (rs_sta && !rs_sta->il) {
6308c2ecf20Sopenharmony_ci		D_RATE("Rate scaling information not initialized yet.\n");
6318c2ecf20Sopenharmony_ci		il_sta = NULL;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	rate_mask = sta->supp_rates[sband->band];
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* get user max rate if set */
6378c2ecf20Sopenharmony_ci	max_rate_idx = fls(txrc->rate_idx_mask) - 1;
6388c2ecf20Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ && max_rate_idx != -1)
6398c2ecf20Sopenharmony_ci		max_rate_idx += IL_FIRST_OFDM_RATE;
6408c2ecf20Sopenharmony_ci	if (max_rate_idx < 0 || max_rate_idx >= RATE_COUNT)
6418c2ecf20Sopenharmony_ci		max_rate_idx = -1;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	idx = min(rs_sta->last_txrate_idx & 0xffff, RATE_COUNT_3945 - 1);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ)
6468c2ecf20Sopenharmony_ci		rate_mask = rate_mask << IL_FIRST_OFDM_RATE;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	/* for recent assoc, choose best rate regarding
6518c2ecf20Sopenharmony_ci	 * to rssi value
6528c2ecf20Sopenharmony_ci	 */
6538c2ecf20Sopenharmony_ci	if (rs_sta->start_rate != RATE_INVALID) {
6548c2ecf20Sopenharmony_ci		if (rs_sta->start_rate < idx &&
6558c2ecf20Sopenharmony_ci		    (rate_mask & (1 << rs_sta->start_rate)))
6568c2ecf20Sopenharmony_ci			idx = rs_sta->start_rate;
6578c2ecf20Sopenharmony_ci		rs_sta->start_rate = RATE_INVALID;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* force user max rate if set by user */
6618c2ecf20Sopenharmony_ci	if (max_rate_idx != -1 && max_rate_idx < idx) {
6628c2ecf20Sopenharmony_ci		if (rate_mask & (1 << max_rate_idx))
6638c2ecf20Sopenharmony_ci			idx = max_rate_idx;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	win = &(rs_sta->win[idx]);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	fail_count = win->counter - win->success_counter;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (fail_count < RATE_MIN_FAILURE_TH &&
6718c2ecf20Sopenharmony_ci	    win->success_counter < RATE_MIN_SUCCESS_TH) {
6728c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rs_sta->lock, flags);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci		D_RATE("Invalid average_tpt on rate %d: "
6758c2ecf20Sopenharmony_ci		       "counter: %d, success_counter: %d, "
6768c2ecf20Sopenharmony_ci		       "expected_tpt is %sNULL\n", idx, win->counter,
6778c2ecf20Sopenharmony_ci		       win->success_counter,
6788c2ecf20Sopenharmony_ci		       rs_sta->expected_tpt ? "not " : "");
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		/* Can't calculate this yet; not enough history */
6818c2ecf20Sopenharmony_ci		win->average_tpt = IL_INVALID_VALUE;
6828c2ecf20Sopenharmony_ci		goto out;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	current_tpt = win->average_tpt;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	high_low =
6898c2ecf20Sopenharmony_ci	    il3945_get_adjacent_rate(rs_sta, idx, rate_mask, sband->band);
6908c2ecf20Sopenharmony_ci	low = high_low & 0xff;
6918c2ecf20Sopenharmony_ci	high = (high_low >> 8) & 0xff;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	/* If user set max rate, dont allow higher than user constrain */
6948c2ecf20Sopenharmony_ci	if (max_rate_idx != -1 && max_rate_idx < high)
6958c2ecf20Sopenharmony_ci		high = RATE_INVALID;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/* Collect Measured throughputs of adjacent rates */
6988c2ecf20Sopenharmony_ci	if (low != RATE_INVALID)
6998c2ecf20Sopenharmony_ci		low_tpt = rs_sta->win[low].average_tpt;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (high != RATE_INVALID)
7028c2ecf20Sopenharmony_ci		high_tpt = rs_sta->win[high].average_tpt;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	scale_action = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Low success ratio , need to drop the rate */
7098c2ecf20Sopenharmony_ci	if (win->success_ratio < RATE_DECREASE_TH || !current_tpt) {
7108c2ecf20Sopenharmony_ci		D_RATE("decrease rate because of low success_ratio\n");
7118c2ecf20Sopenharmony_ci		scale_action = -1;
7128c2ecf20Sopenharmony_ci		/* No throughput measured yet for adjacent rates,
7138c2ecf20Sopenharmony_ci		 * try increase */
7148c2ecf20Sopenharmony_ci	} else if (low_tpt == IL_INVALID_VALUE && high_tpt == IL_INVALID_VALUE) {
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		if (high != RATE_INVALID &&
7178c2ecf20Sopenharmony_ci		    win->success_ratio >= RATE_INCREASE_TH)
7188c2ecf20Sopenharmony_ci			scale_action = 1;
7198c2ecf20Sopenharmony_ci		else if (low != RATE_INVALID)
7208c2ecf20Sopenharmony_ci			scale_action = 0;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci		/* Both adjacent throughputs are measured, but neither one has
7238c2ecf20Sopenharmony_ci		 * better throughput; we're using the best rate, don't change
7248c2ecf20Sopenharmony_ci		 * it! */
7258c2ecf20Sopenharmony_ci	} else if (low_tpt != IL_INVALID_VALUE && high_tpt != IL_INVALID_VALUE
7268c2ecf20Sopenharmony_ci		   && low_tpt < current_tpt && high_tpt < current_tpt) {
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		D_RATE("No action -- low [%d] & high [%d] < "
7298c2ecf20Sopenharmony_ci		       "current_tpt [%d]\n", low_tpt, high_tpt, current_tpt);
7308c2ecf20Sopenharmony_ci		scale_action = 0;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		/* At least one of the rates has better throughput */
7338c2ecf20Sopenharmony_ci	} else {
7348c2ecf20Sopenharmony_ci		if (high_tpt != IL_INVALID_VALUE) {
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci			/* High rate has better throughput, Increase
7378c2ecf20Sopenharmony_ci			 * rate */
7388c2ecf20Sopenharmony_ci			if (high_tpt > current_tpt &&
7398c2ecf20Sopenharmony_ci			    win->success_ratio >= RATE_INCREASE_TH)
7408c2ecf20Sopenharmony_ci				scale_action = 1;
7418c2ecf20Sopenharmony_ci			else {
7428c2ecf20Sopenharmony_ci				D_RATE("decrease rate because of high tpt\n");
7438c2ecf20Sopenharmony_ci				scale_action = 0;
7448c2ecf20Sopenharmony_ci			}
7458c2ecf20Sopenharmony_ci		} else if (low_tpt != IL_INVALID_VALUE) {
7468c2ecf20Sopenharmony_ci			if (low_tpt > current_tpt) {
7478c2ecf20Sopenharmony_ci				D_RATE("decrease rate because of low tpt\n");
7488c2ecf20Sopenharmony_ci				scale_action = -1;
7498c2ecf20Sopenharmony_ci			} else if (win->success_ratio >= RATE_INCREASE_TH) {
7508c2ecf20Sopenharmony_ci				/* Lower rate has better
7518c2ecf20Sopenharmony_ci				 * throughput,decrease rate */
7528c2ecf20Sopenharmony_ci				scale_action = 1;
7538c2ecf20Sopenharmony_ci			}
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* Sanity check; asked for decrease, but success rate or throughput
7588c2ecf20Sopenharmony_ci	 * has been good at old rate.  Don't change it. */
7598c2ecf20Sopenharmony_ci	if (scale_action == -1 && low != RATE_INVALID &&
7608c2ecf20Sopenharmony_ci	    (win->success_ratio > RATE_HIGH_TH ||
7618c2ecf20Sopenharmony_ci	     current_tpt > 100 * rs_sta->expected_tpt[low]))
7628c2ecf20Sopenharmony_ci		scale_action = 0;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	switch (scale_action) {
7658c2ecf20Sopenharmony_ci	case -1:
7668c2ecf20Sopenharmony_ci		/* Decrease rate */
7678c2ecf20Sopenharmony_ci		if (low != RATE_INVALID)
7688c2ecf20Sopenharmony_ci			idx = low;
7698c2ecf20Sopenharmony_ci		break;
7708c2ecf20Sopenharmony_ci	case 1:
7718c2ecf20Sopenharmony_ci		/* Increase rate */
7728c2ecf20Sopenharmony_ci		if (high != RATE_INVALID)
7738c2ecf20Sopenharmony_ci			idx = high;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		break;
7768c2ecf20Sopenharmony_ci	case 0:
7778c2ecf20Sopenharmony_ci	default:
7788c2ecf20Sopenharmony_ci		/* No change */
7798c2ecf20Sopenharmony_ci		break;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	D_RATE("Selected %d (action %d) - low %d high %d\n", idx, scale_action,
7838c2ecf20Sopenharmony_ci	       low, high);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ciout:
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ) {
7888c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(idx < IL_FIRST_OFDM_RATE))
7898c2ecf20Sopenharmony_ci			idx = IL_FIRST_OFDM_RATE;
7908c2ecf20Sopenharmony_ci		rs_sta->last_txrate_idx = idx;
7918c2ecf20Sopenharmony_ci		info->control.rates[0].idx = idx - IL_FIRST_OFDM_RATE;
7928c2ecf20Sopenharmony_ci	} else {
7938c2ecf20Sopenharmony_ci		rs_sta->last_txrate_idx = idx;
7948c2ecf20Sopenharmony_ci		info->control.rates[0].idx = rs_sta->last_txrate_idx;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci	info->control.rates[0].count = 1;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	D_RATE("leave: %d\n", idx);
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic ssize_t
8048c2ecf20Sopenharmony_ciil3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf,
8058c2ecf20Sopenharmony_ci				  size_t count, loff_t *ppos)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	char *buff;
8088c2ecf20Sopenharmony_ci	int desc = 0;
8098c2ecf20Sopenharmony_ci	int j;
8108c2ecf20Sopenharmony_ci	ssize_t ret;
8118c2ecf20Sopenharmony_ci	struct il3945_rs_sta *lq_sta = file->private_data;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	buff = kmalloc(1024, GFP_KERNEL);
8148c2ecf20Sopenharmony_ci	if (!buff)
8158c2ecf20Sopenharmony_ci		return -ENOMEM;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	desc +=
8188c2ecf20Sopenharmony_ci	    sprintf(buff + desc,
8198c2ecf20Sopenharmony_ci		    "tx packets=%d last rate idx=%d\n"
8208c2ecf20Sopenharmony_ci		    "rate=0x%X flush time %d\n", lq_sta->tx_packets,
8218c2ecf20Sopenharmony_ci		    lq_sta->last_txrate_idx, lq_sta->start_rate,
8228c2ecf20Sopenharmony_ci		    jiffies_to_msecs(lq_sta->flush_time));
8238c2ecf20Sopenharmony_ci	for (j = 0; j < RATE_COUNT_3945; j++) {
8248c2ecf20Sopenharmony_ci		desc +=
8258c2ecf20Sopenharmony_ci		    sprintf(buff + desc, "counter=%d success=%d %%=%d\n",
8268c2ecf20Sopenharmony_ci			    lq_sta->win[j].counter,
8278c2ecf20Sopenharmony_ci			    lq_sta->win[j].success_counter,
8288c2ecf20Sopenharmony_ci			    lq_sta->win[j].success_ratio);
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
8318c2ecf20Sopenharmony_ci	kfree(buff);
8328c2ecf20Sopenharmony_ci	return ret;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_cistatic const struct file_operations rs_sta_dbgfs_stats_table_ops = {
8368c2ecf20Sopenharmony_ci	.read = il3945_sta_dbgfs_stats_table_read,
8378c2ecf20Sopenharmony_ci	.open = simple_open,
8388c2ecf20Sopenharmony_ci	.llseek = default_llseek,
8398c2ecf20Sopenharmony_ci};
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic void
8428c2ecf20Sopenharmony_ciil3945_add_debugfs(void *il, void *il_sta, struct dentry *dir)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	struct il3945_rs_sta *lq_sta = il_sta;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	debugfs_create_file("rate_stats_table", 0600, dir, lq_sta,
8478c2ecf20Sopenharmony_ci			    &rs_sta_dbgfs_stats_table_ops);
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci#endif
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci/*
8528c2ecf20Sopenharmony_ci * Initialization of rate scaling information is done by driver after
8538c2ecf20Sopenharmony_ci * the station is added. Since mac80211 calls this function before a
8548c2ecf20Sopenharmony_ci * station is added we ignore it.
8558c2ecf20Sopenharmony_ci */
8568c2ecf20Sopenharmony_cistatic void
8578c2ecf20Sopenharmony_ciil3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
8588c2ecf20Sopenharmony_ci			 struct cfg80211_chan_def *chandef,
8598c2ecf20Sopenharmony_ci			 struct ieee80211_sta *sta, void *il_sta)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic const struct rate_control_ops rs_ops = {
8648c2ecf20Sopenharmony_ci	.name = RS_NAME,
8658c2ecf20Sopenharmony_ci	.tx_status = il3945_rs_tx_status,
8668c2ecf20Sopenharmony_ci	.get_rate = il3945_rs_get_rate,
8678c2ecf20Sopenharmony_ci	.rate_init = il3945_rs_rate_init_stub,
8688c2ecf20Sopenharmony_ci	.alloc = il3945_rs_alloc,
8698c2ecf20Sopenharmony_ci	.free = il3945_rs_free,
8708c2ecf20Sopenharmony_ci	.alloc_sta = il3945_rs_alloc_sta,
8718c2ecf20Sopenharmony_ci	.free_sta = il3945_rs_free_sta,
8728c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
8738c2ecf20Sopenharmony_ci	.add_sta_debugfs = il3945_add_debugfs,
8748c2ecf20Sopenharmony_ci#endif
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci};
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_civoid
8798c2ecf20Sopenharmony_ciil3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	struct il_priv *il = hw->priv;
8828c2ecf20Sopenharmony_ci	s32 rssi = 0;
8838c2ecf20Sopenharmony_ci	unsigned long flags;
8848c2ecf20Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
8858c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
8868c2ecf20Sopenharmony_ci	struct il3945_sta_priv *psta;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	D_RATE("enter\n");
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	rcu_read_lock();
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	sta = ieee80211_find_sta(il->vif, il->stations[sta_id].sta.sta.addr);
8938c2ecf20Sopenharmony_ci	if (!sta) {
8948c2ecf20Sopenharmony_ci		D_RATE("Unable to find station to initialize rate scaling.\n");
8958c2ecf20Sopenharmony_ci		rcu_read_unlock();
8968c2ecf20Sopenharmony_ci		return;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	psta = (void *)sta->drv_priv;
9008c2ecf20Sopenharmony_ci	rs_sta = &psta->rs_sta;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	rs_sta->tgg = 0;
9058c2ecf20Sopenharmony_ci	switch (il->band) {
9068c2ecf20Sopenharmony_ci	case NL80211_BAND_2GHZ:
9078c2ecf20Sopenharmony_ci		/* TODO: this always does G, not a regression */
9088c2ecf20Sopenharmony_ci		if (il->active.flags & RXON_FLG_TGG_PROTECT_MSK) {
9098c2ecf20Sopenharmony_ci			rs_sta->tgg = 1;
9108c2ecf20Sopenharmony_ci			rs_sta->expected_tpt = il3945_expected_tpt_g_prot;
9118c2ecf20Sopenharmony_ci		} else
9128c2ecf20Sopenharmony_ci			rs_sta->expected_tpt = il3945_expected_tpt_g;
9138c2ecf20Sopenharmony_ci		break;
9148c2ecf20Sopenharmony_ci	case NL80211_BAND_5GHZ:
9158c2ecf20Sopenharmony_ci		rs_sta->expected_tpt = il3945_expected_tpt_a;
9168c2ecf20Sopenharmony_ci		break;
9178c2ecf20Sopenharmony_ci	default:
9188c2ecf20Sopenharmony_ci		BUG();
9198c2ecf20Sopenharmony_ci		break;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	rssi = il->_3945.last_rx_rssi;
9258c2ecf20Sopenharmony_ci	if (rssi == 0)
9268c2ecf20Sopenharmony_ci		rssi = IL_MIN_RSSI_VAL;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	D_RATE("Network RSSI: %d\n", rssi);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	rs_sta->start_rate = il3945_get_rate_idx_by_rssi(rssi, il->band);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	D_RATE("leave: rssi %d assign rate idx: " "%d (plcp 0x%x)\n", rssi,
9338c2ecf20Sopenharmony_ci	       rs_sta->start_rate, il3945_rates[rs_sta->start_rate].plcp);
9348c2ecf20Sopenharmony_ci	rcu_read_unlock();
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ciint
9388c2ecf20Sopenharmony_ciil3945_rate_control_register(void)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	return ieee80211_rate_control_register(&rs_ops);
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_civoid
9448c2ecf20Sopenharmony_ciil3945_rate_control_unregister(void)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	ieee80211_rate_control_unregister(&rs_ops);
9478c2ecf20Sopenharmony_ci}
948