162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Contact Information:
762306a36Sopenharmony_ci *  Intel Linux Wireless <ilw@linux.intel.com>
862306a36Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *****************************************************************************/
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/skbuff.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <net/mac80211.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/netdevice.h>
1862306a36Sopenharmony_ci#include <linux/etherdevice.h>
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/workqueue.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "commands.h"
2462306a36Sopenharmony_ci#include "3945.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define RS_NAME "iwl-3945-rs"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic s32 il3945_expected_tpt_g[RATE_COUNT_3945] = {
2962306a36Sopenharmony_ci	7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic s32 il3945_expected_tpt_g_prot[RATE_COUNT_3945] = {
3362306a36Sopenharmony_ci	7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic s32 il3945_expected_tpt_a[RATE_COUNT_3945] = {
3762306a36Sopenharmony_ci	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic s32 il3945_expected_tpt_b[RATE_COUNT_3945] = {
4162306a36Sopenharmony_ci	7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct il3945_tpt_entry {
4562306a36Sopenharmony_ci	s8 min_rssi;
4662306a36Sopenharmony_ci	u8 idx;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct il3945_tpt_entry il3945_tpt_table_a[] = {
5062306a36Sopenharmony_ci	{-60, RATE_54M_IDX},
5162306a36Sopenharmony_ci	{-64, RATE_48M_IDX},
5262306a36Sopenharmony_ci	{-72, RATE_36M_IDX},
5362306a36Sopenharmony_ci	{-80, RATE_24M_IDX},
5462306a36Sopenharmony_ci	{-84, RATE_18M_IDX},
5562306a36Sopenharmony_ci	{-85, RATE_12M_IDX},
5662306a36Sopenharmony_ci	{-87, RATE_9M_IDX},
5762306a36Sopenharmony_ci	{-89, RATE_6M_IDX}
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic struct il3945_tpt_entry il3945_tpt_table_g[] = {
6162306a36Sopenharmony_ci	{-60, RATE_54M_IDX},
6262306a36Sopenharmony_ci	{-64, RATE_48M_IDX},
6362306a36Sopenharmony_ci	{-68, RATE_36M_IDX},
6462306a36Sopenharmony_ci	{-80, RATE_24M_IDX},
6562306a36Sopenharmony_ci	{-84, RATE_18M_IDX},
6662306a36Sopenharmony_ci	{-85, RATE_12M_IDX},
6762306a36Sopenharmony_ci	{-86, RATE_11M_IDX},
6862306a36Sopenharmony_ci	{-88, RATE_5M_IDX},
6962306a36Sopenharmony_ci	{-90, RATE_2M_IDX},
7062306a36Sopenharmony_ci	{-92, RATE_1M_IDX}
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define RATE_MAX_WINDOW		62
7462306a36Sopenharmony_ci#define RATE_FLUSH		(3*HZ)
7562306a36Sopenharmony_ci#define RATE_WIN_FLUSH		(HZ/2)
7662306a36Sopenharmony_ci#define IL39_RATE_HIGH_TH	11520
7762306a36Sopenharmony_ci#define IL_SUCCESS_UP_TH	8960
7862306a36Sopenharmony_ci#define IL_SUCCESS_DOWN_TH	10880
7962306a36Sopenharmony_ci#define RATE_MIN_FAILURE_TH	6
8062306a36Sopenharmony_ci#define RATE_MIN_SUCCESS_TH	8
8162306a36Sopenharmony_ci#define RATE_DECREASE_TH	1920
8262306a36Sopenharmony_ci#define RATE_RETRY_TH		15
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic u8
8562306a36Sopenharmony_ciil3945_get_rate_idx_by_rssi(s32 rssi, enum nl80211_band band)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	u32 idx = 0;
8862306a36Sopenharmony_ci	u32 table_size = 0;
8962306a36Sopenharmony_ci	struct il3945_tpt_entry *tpt_table = NULL;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (rssi < IL_MIN_RSSI_VAL || rssi > IL_MAX_RSSI_VAL)
9262306a36Sopenharmony_ci		rssi = IL_MIN_RSSI_VAL;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	switch (band) {
9562306a36Sopenharmony_ci	case NL80211_BAND_2GHZ:
9662306a36Sopenharmony_ci		tpt_table = il3945_tpt_table_g;
9762306a36Sopenharmony_ci		table_size = ARRAY_SIZE(il3945_tpt_table_g);
9862306a36Sopenharmony_ci		break;
9962306a36Sopenharmony_ci	case NL80211_BAND_5GHZ:
10062306a36Sopenharmony_ci		tpt_table = il3945_tpt_table_a;
10162306a36Sopenharmony_ci		table_size = ARRAY_SIZE(il3945_tpt_table_a);
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci	default:
10462306a36Sopenharmony_ci		BUG();
10562306a36Sopenharmony_ci		break;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	while (idx < table_size && rssi < tpt_table[idx].min_rssi)
10962306a36Sopenharmony_ci		idx++;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	idx = min(idx, table_size - 1);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return tpt_table[idx].idx;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void
11762306a36Sopenharmony_ciil3945_clear_win(struct il3945_rate_scale_data *win)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	win->data = 0;
12062306a36Sopenharmony_ci	win->success_counter = 0;
12162306a36Sopenharmony_ci	win->success_ratio = -1;
12262306a36Sopenharmony_ci	win->counter = 0;
12362306a36Sopenharmony_ci	win->average_tpt = IL_INVALID_VALUE;
12462306a36Sopenharmony_ci	win->stamp = 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci * il3945_rate_scale_flush_wins - flush out the rate scale wins
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Returns the number of wins that have gathered data but were
13162306a36Sopenharmony_ci * not flushed.  If there were any that were not flushed, then
13262306a36Sopenharmony_ci * reschedule the rate flushing routine.
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_cistatic int
13562306a36Sopenharmony_ciil3945_rate_scale_flush_wins(struct il3945_rs_sta *rs_sta)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	int unflushed = 0;
13862306a36Sopenharmony_ci	int i;
13962306a36Sopenharmony_ci	unsigned long flags;
14062306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * For each rate, if we have collected data on that rate
14462306a36Sopenharmony_ci	 * and it has been more than RATE_WIN_FLUSH
14562306a36Sopenharmony_ci	 * since we flushed, clear out the gathered stats
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	for (i = 0; i < RATE_COUNT_3945; i++) {
14862306a36Sopenharmony_ci		if (!rs_sta->win[i].counter)
14962306a36Sopenharmony_ci			continue;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		spin_lock_irqsave(&rs_sta->lock, flags);
15262306a36Sopenharmony_ci		if (time_after(jiffies, rs_sta->win[i].stamp + RATE_WIN_FLUSH)) {
15362306a36Sopenharmony_ci			D_RATE("flushing %d samples of rate " "idx %d\n",
15462306a36Sopenharmony_ci			       rs_sta->win[i].counter, i);
15562306a36Sopenharmony_ci			il3945_clear_win(&rs_sta->win[i]);
15662306a36Sopenharmony_ci		} else
15762306a36Sopenharmony_ci			unflushed++;
15862306a36Sopenharmony_ci		spin_unlock_irqrestore(&rs_sta->lock, flags);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return unflushed;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define RATE_FLUSH_MAX              5000	/* msec */
16562306a36Sopenharmony_ci#define RATE_FLUSH_MIN              50	/* msec */
16662306a36Sopenharmony_ci#define IL_AVERAGE_PACKETS             1500
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void
16962306a36Sopenharmony_ciil3945_bg_rate_scale_flush(struct timer_list *t)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta = from_timer(rs_sta, t, rate_scale_flush);
17262306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
17362306a36Sopenharmony_ci	int unflushed = 0;
17462306a36Sopenharmony_ci	unsigned long flags;
17562306a36Sopenharmony_ci	u32 packet_count, duration, pps;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	D_RATE("enter\n");
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	unflushed = il3945_rate_scale_flush_wins(rs_sta);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Number of packets Rx'd since last time this timer ran */
18462306a36Sopenharmony_ci	packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	rs_sta->last_tx_packets = rs_sta->tx_packets + 1;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (unflushed) {
18962306a36Sopenharmony_ci		duration =
19062306a36Sopenharmony_ci		    jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		D_RATE("Tx'd %d packets in %dms\n", packet_count, duration);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		/* Determine packets per second */
19562306a36Sopenharmony_ci		if (duration)
19662306a36Sopenharmony_ci			pps = (packet_count * 1000) / duration;
19762306a36Sopenharmony_ci		else
19862306a36Sopenharmony_ci			pps = 0;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		if (pps) {
20162306a36Sopenharmony_ci			duration = (IL_AVERAGE_PACKETS * 1000) / pps;
20262306a36Sopenharmony_ci			if (duration < RATE_FLUSH_MIN)
20362306a36Sopenharmony_ci				duration = RATE_FLUSH_MIN;
20462306a36Sopenharmony_ci			else if (duration > RATE_FLUSH_MAX)
20562306a36Sopenharmony_ci				duration = RATE_FLUSH_MAX;
20662306a36Sopenharmony_ci		} else
20762306a36Sopenharmony_ci			duration = RATE_FLUSH_MAX;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		rs_sta->flush_time = msecs_to_jiffies(duration);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		D_RATE("new flush period: %d msec ave %d\n", duration,
21262306a36Sopenharmony_ci		       packet_count);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		mod_timer(&rs_sta->rate_scale_flush,
21562306a36Sopenharmony_ci			  jiffies + rs_sta->flush_time);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		rs_sta->last_partial_flush = jiffies;
21862306a36Sopenharmony_ci	} else {
21962306a36Sopenharmony_ci		rs_sta->flush_time = RATE_FLUSH;
22062306a36Sopenharmony_ci		rs_sta->flush_pending = 0;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci	/* If there weren't any unflushed entries, we don't schedule the timer
22362306a36Sopenharmony_ci	 * to run again */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	rs_sta->last_flush = jiffies;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	D_RATE("leave\n");
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * il3945_collect_tx_data - Update the success/failure sliding win
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci * We keep a sliding win of the last 64 packets transmitted
23662306a36Sopenharmony_ci * at this rate.  win->data contains the bitmask of successful
23762306a36Sopenharmony_ci * packets.
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void
24062306a36Sopenharmony_ciil3945_collect_tx_data(struct il3945_rs_sta *rs_sta,
24162306a36Sopenharmony_ci		       struct il3945_rate_scale_data *win, int success,
24262306a36Sopenharmony_ci		       int retries, int idx)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	unsigned long flags;
24562306a36Sopenharmony_ci	s32 fail_count;
24662306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (!retries) {
24962306a36Sopenharmony_ci		D_RATE("leave: retries == 0 -- should be at least 1\n");
25062306a36Sopenharmony_ci		return;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/*
25662306a36Sopenharmony_ci	 * Keep track of only the latest 62 tx frame attempts in this rate's
25762306a36Sopenharmony_ci	 * history win; anything older isn't really relevant any more.
25862306a36Sopenharmony_ci	 * If we have filled up the sliding win, drop the oldest attempt;
25962306a36Sopenharmony_ci	 * if the oldest attempt (highest bit in bitmap) shows "success",
26062306a36Sopenharmony_ci	 * subtract "1" from the success counter (this is the main reason
26162306a36Sopenharmony_ci	 * we keep these bitmaps!).
26262306a36Sopenharmony_ci	 * */
26362306a36Sopenharmony_ci	while (retries > 0) {
26462306a36Sopenharmony_ci		if (win->counter >= RATE_MAX_WINDOW) {
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci			/* remove earliest */
26762306a36Sopenharmony_ci			win->counter = RATE_MAX_WINDOW - 1;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci			if (win->data & (1ULL << (RATE_MAX_WINDOW - 1))) {
27062306a36Sopenharmony_ci				win->data &= ~(1ULL << (RATE_MAX_WINDOW - 1));
27162306a36Sopenharmony_ci				win->success_counter--;
27262306a36Sopenharmony_ci			}
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		/* Increment frames-attempted counter */
27662306a36Sopenharmony_ci		win->counter++;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		/* Shift bitmap by one frame (throw away oldest history),
27962306a36Sopenharmony_ci		 * OR in "1", and increment "success" if this
28062306a36Sopenharmony_ci		 * frame was successful. */
28162306a36Sopenharmony_ci		win->data <<= 1;
28262306a36Sopenharmony_ci		if (success > 0) {
28362306a36Sopenharmony_ci			win->success_counter++;
28462306a36Sopenharmony_ci			win->data |= 0x1;
28562306a36Sopenharmony_ci			success--;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		retries--;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* Calculate current success ratio, avoid divide-by-0! */
29262306a36Sopenharmony_ci	if (win->counter > 0)
29362306a36Sopenharmony_ci		win->success_ratio =
29462306a36Sopenharmony_ci		    128 * (100 * win->success_counter) / win->counter;
29562306a36Sopenharmony_ci	else
29662306a36Sopenharmony_ci		win->success_ratio = IL_INVALID_VALUE;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	fail_count = win->counter - win->success_counter;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Calculate average throughput, if we have enough history. */
30162306a36Sopenharmony_ci	if (fail_count >= RATE_MIN_FAILURE_TH ||
30262306a36Sopenharmony_ci	    win->success_counter >= RATE_MIN_SUCCESS_TH)
30362306a36Sopenharmony_ci		win->average_tpt =
30462306a36Sopenharmony_ci		    ((win->success_ratio * rs_sta->expected_tpt[idx] +
30562306a36Sopenharmony_ci		      64) / 128);
30662306a36Sopenharmony_ci	else
30762306a36Sopenharmony_ci		win->average_tpt = IL_INVALID_VALUE;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Tag this win as having been updated */
31062306a36Sopenharmony_ci	win->stamp = jiffies;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/*
31662306a36Sopenharmony_ci * Called after adding a new station to initialize rate scaling
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_civoid
31962306a36Sopenharmony_ciil3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct ieee80211_hw *hw = il->hw;
32262306a36Sopenharmony_ci	struct ieee80211_conf *conf = &il->hw->conf;
32362306a36Sopenharmony_ci	struct il3945_sta_priv *psta;
32462306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
32562306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
32662306a36Sopenharmony_ci	int i;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	D_INFO("enter\n");
32962306a36Sopenharmony_ci	if (sta_id == il->hw_params.bcast_id)
33062306a36Sopenharmony_ci		goto out;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	psta = (struct il3945_sta_priv *)sta->drv_priv;
33362306a36Sopenharmony_ci	rs_sta = &psta->rs_sta;
33462306a36Sopenharmony_ci	sband = hw->wiphy->bands[conf->chandef.chan->band];
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	rs_sta->il = il;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	rs_sta->start_rate = RATE_INVALID;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* default to just 802.11b */
34162306a36Sopenharmony_ci	rs_sta->expected_tpt = il3945_expected_tpt_b;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	rs_sta->last_partial_flush = jiffies;
34462306a36Sopenharmony_ci	rs_sta->last_flush = jiffies;
34562306a36Sopenharmony_ci	rs_sta->flush_time = RATE_FLUSH;
34662306a36Sopenharmony_ci	rs_sta->last_tx_packets = 0;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	for (i = 0; i < RATE_COUNT_3945; i++)
34962306a36Sopenharmony_ci		il3945_clear_win(&rs_sta->win[i]);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* TODO: what is a good starting rate for STA? About middle? Maybe not
35262306a36Sopenharmony_ci	 * the lowest or the highest rate.. Could consider using RSSI from
35362306a36Sopenharmony_ci	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
35462306a36Sopenharmony_ci	 * after assoc.. */
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	for (i = sband->n_bitrates - 1; i >= 0; i--) {
35762306a36Sopenharmony_ci		if (sta->deflink.supp_rates[sband->band] & (1 << i)) {
35862306a36Sopenharmony_ci			rs_sta->last_txrate_idx = i;
35962306a36Sopenharmony_ci			break;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	il->_3945.sta_supp_rates = sta->deflink.supp_rates[sband->band];
36462306a36Sopenharmony_ci	/* For 5 GHz band it start at IL_FIRST_OFDM_RATE */
36562306a36Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ) {
36662306a36Sopenharmony_ci		rs_sta->last_txrate_idx += IL_FIRST_OFDM_RATE;
36762306a36Sopenharmony_ci		il->_3945.sta_supp_rates <<= IL_FIRST_OFDM_RATE;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ciout:
37162306a36Sopenharmony_ci	il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	D_INFO("leave\n");
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic void *
37762306a36Sopenharmony_ciil3945_rs_alloc(struct ieee80211_hw *hw)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	return hw->priv;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci/* rate scale requires free function to be implemented */
38362306a36Sopenharmony_cistatic void
38462306a36Sopenharmony_ciil3945_rs_free(void *il)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic void *
38962306a36Sopenharmony_ciil3945_rs_alloc_sta(void *il_priv, struct ieee80211_sta *sta, gfp_t gfp)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
39262306a36Sopenharmony_ci	struct il3945_sta_priv *psta = (void *)sta->drv_priv;
39362306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = il_priv;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	D_RATE("enter\n");
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rs_sta = &psta->rs_sta;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	spin_lock_init(&rs_sta->lock);
40062306a36Sopenharmony_ci	timer_setup(&rs_sta->rate_scale_flush, il3945_bg_rate_scale_flush, 0);
40162306a36Sopenharmony_ci	D_RATE("leave\n");
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return rs_sta;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic void
40762306a36Sopenharmony_ciil3945_rs_free_sta(void *il_priv, struct ieee80211_sta *sta, void *il_sta)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/*
41262306a36Sopenharmony_ci	 * Be careful not to use any members of il3945_rs_sta (like trying
41362306a36Sopenharmony_ci	 * to use il_priv to print out debugging) since it may not be fully
41462306a36Sopenharmony_ci	 * initialized at this point.
41562306a36Sopenharmony_ci	 */
41662306a36Sopenharmony_ci	del_timer_sync(&rs_sta->rate_scale_flush);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/*
42062306a36Sopenharmony_ci * il3945_rs_tx_status - Update rate control values based on Tx results
42162306a36Sopenharmony_ci *
42262306a36Sopenharmony_ci * NOTE: Uses il_priv->retry_rate for the # of retries attempted by
42362306a36Sopenharmony_ci * the hardware for each rate.
42462306a36Sopenharmony_ci */
42562306a36Sopenharmony_cistatic void
42662306a36Sopenharmony_ciil3945_rs_tx_status(void *il_rate, struct ieee80211_supported_band *sband,
42762306a36Sopenharmony_ci		    struct ieee80211_sta *sta, void *il_sta,
42862306a36Sopenharmony_ci		    struct sk_buff *skb)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	s8 retries = 0, current_count;
43162306a36Sopenharmony_ci	int scale_rate_idx, first_idx, last_idx;
43262306a36Sopenharmony_ci	unsigned long flags;
43362306a36Sopenharmony_ci	struct il_priv *il = (struct il_priv *)il_rate;
43462306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
43562306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	D_RATE("enter\n");
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	retries = info->status.rates[0].count;
44062306a36Sopenharmony_ci	/* Sanity Check for retries */
44162306a36Sopenharmony_ci	if (retries > RATE_RETRY_TH)
44262306a36Sopenharmony_ci		retries = RATE_RETRY_TH;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	first_idx = sband->bitrates[info->status.rates[0].idx].hw_value;
44562306a36Sopenharmony_ci	if (first_idx < 0 || first_idx >= RATE_COUNT_3945) {
44662306a36Sopenharmony_ci		D_RATE("leave: Rate out of bounds: %d\n", first_idx);
44762306a36Sopenharmony_ci		return;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (!il_sta) {
45162306a36Sopenharmony_ci		D_RATE("leave: No STA il data to update!\n");
45262306a36Sopenharmony_ci		return;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* Treat uninitialized rate scaling data same as non-existing. */
45662306a36Sopenharmony_ci	if (!rs_sta->il) {
45762306a36Sopenharmony_ci		D_RATE("leave: STA il data uninitialized!\n");
45862306a36Sopenharmony_ci		return;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	rs_sta->tx_packets++;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	scale_rate_idx = first_idx;
46462306a36Sopenharmony_ci	last_idx = first_idx;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/*
46762306a36Sopenharmony_ci	 * Update the win for each rate.  We determine which rates
46862306a36Sopenharmony_ci	 * were Tx'd based on the total number of retries vs. the number
46962306a36Sopenharmony_ci	 * of retries configured for each rate -- currently set to the
47062306a36Sopenharmony_ci	 * il value 'retry_rate' vs. rate specific
47162306a36Sopenharmony_ci	 *
47262306a36Sopenharmony_ci	 * On exit from this while loop last_idx indicates the rate
47362306a36Sopenharmony_ci	 * at which the frame was finally transmitted (or failed if no
47462306a36Sopenharmony_ci	 * ACK)
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci	while (retries > 1) {
47762306a36Sopenharmony_ci		if ((retries - 1) < il->retry_rate) {
47862306a36Sopenharmony_ci			current_count = (retries - 1);
47962306a36Sopenharmony_ci			last_idx = scale_rate_idx;
48062306a36Sopenharmony_ci		} else {
48162306a36Sopenharmony_ci			current_count = il->retry_rate;
48262306a36Sopenharmony_ci			last_idx = il3945_rs_next_rate(il, scale_rate_idx);
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		/* Update this rate accounting for as many retries
48662306a36Sopenharmony_ci		 * as was used for it (per current_count) */
48762306a36Sopenharmony_ci		il3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_idx], 0,
48862306a36Sopenharmony_ci				       current_count, scale_rate_idx);
48962306a36Sopenharmony_ci		D_RATE("Update rate %d for %d retries.\n", scale_rate_idx,
49062306a36Sopenharmony_ci		       current_count);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		retries -= current_count;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		scale_rate_idx = last_idx;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* Update the last idx win with success/failure based on ACK */
49862306a36Sopenharmony_ci	D_RATE("Update rate %d with %s.\n", last_idx,
49962306a36Sopenharmony_ci	       (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure");
50062306a36Sopenharmony_ci	il3945_collect_tx_data(rs_sta, &rs_sta->win[last_idx],
50162306a36Sopenharmony_ci			       info->flags & IEEE80211_TX_STAT_ACK, 1,
50262306a36Sopenharmony_ci			       last_idx);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* We updated the rate scale win -- if its been more than
50562306a36Sopenharmony_ci	 * flush_time since the last run, schedule the flush
50662306a36Sopenharmony_ci	 * again */
50762306a36Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (!rs_sta->flush_pending &&
51062306a36Sopenharmony_ci	    time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) {
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		rs_sta->last_partial_flush = jiffies;
51362306a36Sopenharmony_ci		rs_sta->flush_pending = 1;
51462306a36Sopenharmony_ci		mod_timer(&rs_sta->rate_scale_flush,
51562306a36Sopenharmony_ci			  jiffies + rs_sta->flush_time);
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	D_RATE("leave\n");
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic u16
52462306a36Sopenharmony_ciil3945_get_adjacent_rate(struct il3945_rs_sta *rs_sta, u8 idx, u16 rate_mask,
52562306a36Sopenharmony_ci			 enum nl80211_band band)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	u8 high = RATE_INVALID;
52862306a36Sopenharmony_ci	u8 low = RATE_INVALID;
52962306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = rs_sta->il;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* 802.11A walks to the next literal adjacent rate in
53262306a36Sopenharmony_ci	 * the rate table */
53362306a36Sopenharmony_ci	if (unlikely(band == NL80211_BAND_5GHZ)) {
53462306a36Sopenharmony_ci		int i;
53562306a36Sopenharmony_ci		u32 mask;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* Find the previous rate that is in the rate mask */
53862306a36Sopenharmony_ci		i = idx - 1;
53962306a36Sopenharmony_ci		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
54062306a36Sopenharmony_ci			if (rate_mask & mask) {
54162306a36Sopenharmony_ci				low = i;
54262306a36Sopenharmony_ci				break;
54362306a36Sopenharmony_ci			}
54462306a36Sopenharmony_ci		}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		/* Find the next rate that is in the rate mask */
54762306a36Sopenharmony_ci		i = idx + 1;
54862306a36Sopenharmony_ci		for (mask = (1 << i); i < RATE_COUNT_3945; i++, mask <<= 1) {
54962306a36Sopenharmony_ci			if (rate_mask & mask) {
55062306a36Sopenharmony_ci				high = i;
55162306a36Sopenharmony_ci				break;
55262306a36Sopenharmony_ci			}
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		return (high << 8) | low;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	low = idx;
55962306a36Sopenharmony_ci	while (low != RATE_INVALID) {
56062306a36Sopenharmony_ci		if (rs_sta->tgg)
56162306a36Sopenharmony_ci			low = il3945_rates[low].prev_rs_tgg;
56262306a36Sopenharmony_ci		else
56362306a36Sopenharmony_ci			low = il3945_rates[low].prev_rs;
56462306a36Sopenharmony_ci		if (low == RATE_INVALID)
56562306a36Sopenharmony_ci			break;
56662306a36Sopenharmony_ci		if (rate_mask & (1 << low))
56762306a36Sopenharmony_ci			break;
56862306a36Sopenharmony_ci		D_RATE("Skipping masked lower rate: %d\n", low);
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	high = idx;
57262306a36Sopenharmony_ci	while (high != RATE_INVALID) {
57362306a36Sopenharmony_ci		if (rs_sta->tgg)
57462306a36Sopenharmony_ci			high = il3945_rates[high].next_rs_tgg;
57562306a36Sopenharmony_ci		else
57662306a36Sopenharmony_ci			high = il3945_rates[high].next_rs;
57762306a36Sopenharmony_ci		if (high == RATE_INVALID)
57862306a36Sopenharmony_ci			break;
57962306a36Sopenharmony_ci		if (rate_mask & (1 << high))
58062306a36Sopenharmony_ci			break;
58162306a36Sopenharmony_ci		D_RATE("Skipping masked higher rate: %d\n", high);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return (high << 8) | low;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci/*
58862306a36Sopenharmony_ci * il3945_rs_get_rate - find the rate for the requested packet
58962306a36Sopenharmony_ci *
59062306a36Sopenharmony_ci * Returns the ieee80211_rate structure allocated by the driver.
59162306a36Sopenharmony_ci *
59262306a36Sopenharmony_ci * The rate control algorithm has no internal mapping between hw_mode's
59362306a36Sopenharmony_ci * rate ordering and the rate ordering used by the rate control algorithm.
59462306a36Sopenharmony_ci *
59562306a36Sopenharmony_ci * The rate control algorithm uses a single table of rates that goes across
59662306a36Sopenharmony_ci * the entire A/B/G spectrum vs. being limited to just one particular
59762306a36Sopenharmony_ci * hw_mode.
59862306a36Sopenharmony_ci *
59962306a36Sopenharmony_ci * As such, we can't convert the idx obtained below into the hw_mode's
60062306a36Sopenharmony_ci * rate table and must reference the driver allocated rate table
60162306a36Sopenharmony_ci *
60262306a36Sopenharmony_ci */
60362306a36Sopenharmony_cistatic void
60462306a36Sopenharmony_ciil3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
60562306a36Sopenharmony_ci		   struct ieee80211_tx_rate_control *txrc)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct ieee80211_supported_band *sband = txrc->sband;
60862306a36Sopenharmony_ci	struct sk_buff *skb = txrc->skb;
60962306a36Sopenharmony_ci	u8 low = RATE_INVALID;
61062306a36Sopenharmony_ci	u8 high = RATE_INVALID;
61162306a36Sopenharmony_ci	u16 high_low;
61262306a36Sopenharmony_ci	int idx;
61362306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta = il_sta;
61462306a36Sopenharmony_ci	struct il3945_rate_scale_data *win = NULL;
61562306a36Sopenharmony_ci	int current_tpt = IL_INVALID_VALUE;
61662306a36Sopenharmony_ci	int low_tpt = IL_INVALID_VALUE;
61762306a36Sopenharmony_ci	int high_tpt = IL_INVALID_VALUE;
61862306a36Sopenharmony_ci	u32 fail_count;
61962306a36Sopenharmony_ci	s8 scale_action = 0;
62062306a36Sopenharmony_ci	unsigned long flags;
62162306a36Sopenharmony_ci	u16 rate_mask;
62262306a36Sopenharmony_ci	s8 max_rate_idx = -1;
62362306a36Sopenharmony_ci	struct il_priv *il __maybe_unused = (struct il_priv *)il_r;
62462306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	D_RATE("enter\n");
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Treat uninitialized rate scaling data same as non-existing. */
62962306a36Sopenharmony_ci	if (rs_sta && !rs_sta->il) {
63062306a36Sopenharmony_ci		D_RATE("Rate scaling information not initialized yet.\n");
63162306a36Sopenharmony_ci		il_sta = NULL;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	rate_mask = sta->deflink.supp_rates[sband->band];
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* get user max rate if set */
63762306a36Sopenharmony_ci	max_rate_idx = fls(txrc->rate_idx_mask) - 1;
63862306a36Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ && max_rate_idx != -1)
63962306a36Sopenharmony_ci		max_rate_idx += IL_FIRST_OFDM_RATE;
64062306a36Sopenharmony_ci	if (max_rate_idx < 0 || max_rate_idx >= RATE_COUNT)
64162306a36Sopenharmony_ci		max_rate_idx = -1;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	idx = min(rs_sta->last_txrate_idx & 0xffff, RATE_COUNT_3945 - 1);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ)
64662306a36Sopenharmony_ci		rate_mask = rate_mask << IL_FIRST_OFDM_RATE;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* for recent assoc, choose best rate regarding
65162306a36Sopenharmony_ci	 * to rssi value
65262306a36Sopenharmony_ci	 */
65362306a36Sopenharmony_ci	if (rs_sta->start_rate != RATE_INVALID) {
65462306a36Sopenharmony_ci		if (rs_sta->start_rate < idx &&
65562306a36Sopenharmony_ci		    (rate_mask & (1 << rs_sta->start_rate)))
65662306a36Sopenharmony_ci			idx = rs_sta->start_rate;
65762306a36Sopenharmony_ci		rs_sta->start_rate = RATE_INVALID;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* force user max rate if set by user */
66162306a36Sopenharmony_ci	if (max_rate_idx != -1 && max_rate_idx < idx) {
66262306a36Sopenharmony_ci		if (rate_mask & (1 << max_rate_idx))
66362306a36Sopenharmony_ci			idx = max_rate_idx;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	win = &(rs_sta->win[idx]);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	fail_count = win->counter - win->success_counter;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (fail_count < RATE_MIN_FAILURE_TH &&
67162306a36Sopenharmony_ci	    win->success_counter < RATE_MIN_SUCCESS_TH) {
67262306a36Sopenharmony_ci		spin_unlock_irqrestore(&rs_sta->lock, flags);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		D_RATE("Invalid average_tpt on rate %d: "
67562306a36Sopenharmony_ci		       "counter: %d, success_counter: %d, "
67662306a36Sopenharmony_ci		       "expected_tpt is %sNULL\n", idx, win->counter,
67762306a36Sopenharmony_ci		       win->success_counter,
67862306a36Sopenharmony_ci		       rs_sta->expected_tpt ? "not " : "");
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		/* Can't calculate this yet; not enough history */
68162306a36Sopenharmony_ci		win->average_tpt = IL_INVALID_VALUE;
68262306a36Sopenharmony_ci		goto out;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	current_tpt = win->average_tpt;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	high_low =
68962306a36Sopenharmony_ci	    il3945_get_adjacent_rate(rs_sta, idx, rate_mask, sband->band);
69062306a36Sopenharmony_ci	low = high_low & 0xff;
69162306a36Sopenharmony_ci	high = (high_low >> 8) & 0xff;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* If user set max rate, dont allow higher than user constrain */
69462306a36Sopenharmony_ci	if (max_rate_idx != -1 && max_rate_idx < high)
69562306a36Sopenharmony_ci		high = RATE_INVALID;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	/* Collect Measured throughputs of adjacent rates */
69862306a36Sopenharmony_ci	if (low != RATE_INVALID)
69962306a36Sopenharmony_ci		low_tpt = rs_sta->win[low].average_tpt;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (high != RATE_INVALID)
70262306a36Sopenharmony_ci		high_tpt = rs_sta->win[high].average_tpt;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	scale_action = 0;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Low success ratio , need to drop the rate */
70962306a36Sopenharmony_ci	if (win->success_ratio < RATE_DECREASE_TH || !current_tpt) {
71062306a36Sopenharmony_ci		D_RATE("decrease rate because of low success_ratio\n");
71162306a36Sopenharmony_ci		scale_action = -1;
71262306a36Sopenharmony_ci		/* No throughput measured yet for adjacent rates,
71362306a36Sopenharmony_ci		 * try increase */
71462306a36Sopenharmony_ci	} else if (low_tpt == IL_INVALID_VALUE && high_tpt == IL_INVALID_VALUE) {
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		if (high != RATE_INVALID &&
71762306a36Sopenharmony_ci		    win->success_ratio >= RATE_INCREASE_TH)
71862306a36Sopenharmony_ci			scale_action = 1;
71962306a36Sopenharmony_ci		else if (low != RATE_INVALID)
72062306a36Sopenharmony_ci			scale_action = 0;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		/* Both adjacent throughputs are measured, but neither one has
72362306a36Sopenharmony_ci		 * better throughput; we're using the best rate, don't change
72462306a36Sopenharmony_ci		 * it! */
72562306a36Sopenharmony_ci	} else if (low_tpt != IL_INVALID_VALUE && high_tpt != IL_INVALID_VALUE
72662306a36Sopenharmony_ci		   && low_tpt < current_tpt && high_tpt < current_tpt) {
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		D_RATE("No action -- low [%d] & high [%d] < "
72962306a36Sopenharmony_ci		       "current_tpt [%d]\n", low_tpt, high_tpt, current_tpt);
73062306a36Sopenharmony_ci		scale_action = 0;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		/* At least one of the rates has better throughput */
73362306a36Sopenharmony_ci	} else {
73462306a36Sopenharmony_ci		if (high_tpt != IL_INVALID_VALUE) {
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci			/* High rate has better throughput, Increase
73762306a36Sopenharmony_ci			 * rate */
73862306a36Sopenharmony_ci			if (high_tpt > current_tpt &&
73962306a36Sopenharmony_ci			    win->success_ratio >= RATE_INCREASE_TH)
74062306a36Sopenharmony_ci				scale_action = 1;
74162306a36Sopenharmony_ci			else {
74262306a36Sopenharmony_ci				D_RATE("decrease rate because of high tpt\n");
74362306a36Sopenharmony_ci				scale_action = 0;
74462306a36Sopenharmony_ci			}
74562306a36Sopenharmony_ci		} else if (low_tpt != IL_INVALID_VALUE) {
74662306a36Sopenharmony_ci			if (low_tpt > current_tpt) {
74762306a36Sopenharmony_ci				D_RATE("decrease rate because of low tpt\n");
74862306a36Sopenharmony_ci				scale_action = -1;
74962306a36Sopenharmony_ci			} else if (win->success_ratio >= RATE_INCREASE_TH) {
75062306a36Sopenharmony_ci				/* Lower rate has better
75162306a36Sopenharmony_ci				 * throughput,decrease rate */
75262306a36Sopenharmony_ci				scale_action = 1;
75362306a36Sopenharmony_ci			}
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Sanity check; asked for decrease, but success rate or throughput
75862306a36Sopenharmony_ci	 * has been good at old rate.  Don't change it. */
75962306a36Sopenharmony_ci	if (scale_action == -1 && low != RATE_INVALID &&
76062306a36Sopenharmony_ci	    (win->success_ratio > RATE_HIGH_TH ||
76162306a36Sopenharmony_ci	     current_tpt > 100 * rs_sta->expected_tpt[low]))
76262306a36Sopenharmony_ci		scale_action = 0;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	switch (scale_action) {
76562306a36Sopenharmony_ci	case -1:
76662306a36Sopenharmony_ci		/* Decrease rate */
76762306a36Sopenharmony_ci		if (low != RATE_INVALID)
76862306a36Sopenharmony_ci			idx = low;
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci	case 1:
77162306a36Sopenharmony_ci		/* Increase rate */
77262306a36Sopenharmony_ci		if (high != RATE_INVALID)
77362306a36Sopenharmony_ci			idx = high;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		break;
77662306a36Sopenharmony_ci	case 0:
77762306a36Sopenharmony_ci	default:
77862306a36Sopenharmony_ci		/* No change */
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	D_RATE("Selected %d (action %d) - low %d high %d\n", idx, scale_action,
78362306a36Sopenharmony_ci	       low, high);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ciout:
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (sband->band == NL80211_BAND_5GHZ) {
78862306a36Sopenharmony_ci		if (WARN_ON_ONCE(idx < IL_FIRST_OFDM_RATE))
78962306a36Sopenharmony_ci			idx = IL_FIRST_OFDM_RATE;
79062306a36Sopenharmony_ci		rs_sta->last_txrate_idx = idx;
79162306a36Sopenharmony_ci		info->control.rates[0].idx = idx - IL_FIRST_OFDM_RATE;
79262306a36Sopenharmony_ci	} else {
79362306a36Sopenharmony_ci		rs_sta->last_txrate_idx = idx;
79462306a36Sopenharmony_ci		info->control.rates[0].idx = rs_sta->last_txrate_idx;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	info->control.rates[0].count = 1;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	D_RATE("leave: %d\n", idx);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic ssize_t
80462306a36Sopenharmony_ciil3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf,
80562306a36Sopenharmony_ci				  size_t count, loff_t *ppos)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	char *buff;
80862306a36Sopenharmony_ci	int desc = 0;
80962306a36Sopenharmony_ci	int j;
81062306a36Sopenharmony_ci	ssize_t ret;
81162306a36Sopenharmony_ci	struct il3945_rs_sta *lq_sta = file->private_data;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	buff = kmalloc(1024, GFP_KERNEL);
81462306a36Sopenharmony_ci	if (!buff)
81562306a36Sopenharmony_ci		return -ENOMEM;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	desc +=
81862306a36Sopenharmony_ci	    sprintf(buff + desc,
81962306a36Sopenharmony_ci		    "tx packets=%d last rate idx=%d\n"
82062306a36Sopenharmony_ci		    "rate=0x%X flush time %d\n", lq_sta->tx_packets,
82162306a36Sopenharmony_ci		    lq_sta->last_txrate_idx, lq_sta->start_rate,
82262306a36Sopenharmony_ci		    jiffies_to_msecs(lq_sta->flush_time));
82362306a36Sopenharmony_ci	for (j = 0; j < RATE_COUNT_3945; j++) {
82462306a36Sopenharmony_ci		desc +=
82562306a36Sopenharmony_ci		    sprintf(buff + desc, "counter=%d success=%d %%=%d\n",
82662306a36Sopenharmony_ci			    lq_sta->win[j].counter,
82762306a36Sopenharmony_ci			    lq_sta->win[j].success_counter,
82862306a36Sopenharmony_ci			    lq_sta->win[j].success_ratio);
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
83162306a36Sopenharmony_ci	kfree(buff);
83262306a36Sopenharmony_ci	return ret;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic const struct file_operations rs_sta_dbgfs_stats_table_ops = {
83662306a36Sopenharmony_ci	.read = il3945_sta_dbgfs_stats_table_read,
83762306a36Sopenharmony_ci	.open = simple_open,
83862306a36Sopenharmony_ci	.llseek = default_llseek,
83962306a36Sopenharmony_ci};
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic void
84262306a36Sopenharmony_ciil3945_add_debugfs(void *il, void *il_sta, struct dentry *dir)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct il3945_rs_sta *lq_sta = il_sta;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	debugfs_create_file("rate_stats_table", 0600, dir, lq_sta,
84762306a36Sopenharmony_ci			    &rs_sta_dbgfs_stats_table_ops);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci#endif
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci/*
85262306a36Sopenharmony_ci * Initialization of rate scaling information is done by driver after
85362306a36Sopenharmony_ci * the station is added. Since mac80211 calls this function before a
85462306a36Sopenharmony_ci * station is added we ignore it.
85562306a36Sopenharmony_ci */
85662306a36Sopenharmony_cistatic void
85762306a36Sopenharmony_ciil3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
85862306a36Sopenharmony_ci			 struct cfg80211_chan_def *chandef,
85962306a36Sopenharmony_ci			 struct ieee80211_sta *sta, void *il_sta)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic const struct rate_control_ops rs_ops = {
86462306a36Sopenharmony_ci	.name = RS_NAME,
86562306a36Sopenharmony_ci	.tx_status = il3945_rs_tx_status,
86662306a36Sopenharmony_ci	.get_rate = il3945_rs_get_rate,
86762306a36Sopenharmony_ci	.rate_init = il3945_rs_rate_init_stub,
86862306a36Sopenharmony_ci	.alloc = il3945_rs_alloc,
86962306a36Sopenharmony_ci	.free = il3945_rs_free,
87062306a36Sopenharmony_ci	.alloc_sta = il3945_rs_alloc_sta,
87162306a36Sopenharmony_ci	.free_sta = il3945_rs_free_sta,
87262306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
87362306a36Sopenharmony_ci	.add_sta_debugfs = il3945_add_debugfs,
87462306a36Sopenharmony_ci#endif
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_civoid
87962306a36Sopenharmony_ciil3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct il_priv *il = hw->priv;
88262306a36Sopenharmony_ci	s32 rssi = 0;
88362306a36Sopenharmony_ci	unsigned long flags;
88462306a36Sopenharmony_ci	struct il3945_rs_sta *rs_sta;
88562306a36Sopenharmony_ci	struct ieee80211_sta *sta;
88662306a36Sopenharmony_ci	struct il3945_sta_priv *psta;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	D_RATE("enter\n");
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	rcu_read_lock();
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	sta = ieee80211_find_sta(il->vif, il->stations[sta_id].sta.sta.addr);
89362306a36Sopenharmony_ci	if (!sta) {
89462306a36Sopenharmony_ci		D_RATE("Unable to find station to initialize rate scaling.\n");
89562306a36Sopenharmony_ci		rcu_read_unlock();
89662306a36Sopenharmony_ci		return;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	psta = (void *)sta->drv_priv;
90062306a36Sopenharmony_ci	rs_sta = &psta->rs_sta;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	spin_lock_irqsave(&rs_sta->lock, flags);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	rs_sta->tgg = 0;
90562306a36Sopenharmony_ci	switch (il->band) {
90662306a36Sopenharmony_ci	case NL80211_BAND_2GHZ:
90762306a36Sopenharmony_ci		/* TODO: this always does G, not a regression */
90862306a36Sopenharmony_ci		if (il->active.flags & RXON_FLG_TGG_PROTECT_MSK) {
90962306a36Sopenharmony_ci			rs_sta->tgg = 1;
91062306a36Sopenharmony_ci			rs_sta->expected_tpt = il3945_expected_tpt_g_prot;
91162306a36Sopenharmony_ci		} else
91262306a36Sopenharmony_ci			rs_sta->expected_tpt = il3945_expected_tpt_g;
91362306a36Sopenharmony_ci		break;
91462306a36Sopenharmony_ci	case NL80211_BAND_5GHZ:
91562306a36Sopenharmony_ci		rs_sta->expected_tpt = il3945_expected_tpt_a;
91662306a36Sopenharmony_ci		break;
91762306a36Sopenharmony_ci	default:
91862306a36Sopenharmony_ci		BUG();
91962306a36Sopenharmony_ci		break;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	spin_unlock_irqrestore(&rs_sta->lock, flags);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	rssi = il->_3945.last_rx_rssi;
92562306a36Sopenharmony_ci	if (rssi == 0)
92662306a36Sopenharmony_ci		rssi = IL_MIN_RSSI_VAL;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	D_RATE("Network RSSI: %d\n", rssi);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	rs_sta->start_rate = il3945_get_rate_idx_by_rssi(rssi, il->band);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	D_RATE("leave: rssi %d assign rate idx: " "%d (plcp 0x%x)\n", rssi,
93362306a36Sopenharmony_ci	       rs_sta->start_rate, il3945_rates[rs_sta->start_rate].plcp);
93462306a36Sopenharmony_ci	rcu_read_unlock();
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ciint
93862306a36Sopenharmony_ciil3945_rate_control_register(void)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	return ieee80211_rate_control_register(&rs_ops);
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_civoid
94462306a36Sopenharmony_ciil3945_rate_control_unregister(void)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	ieee80211_rate_control_unregister(&rs_ops);
94762306a36Sopenharmony_ci}
948