xref: /linux/drivers/net/wireless/intel/iwlegacy/3945-rs.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
116da78b7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ac9a364SKalle Valo /******************************************************************************
37ac9a364SKalle Valo  *
47ac9a364SKalle Valo  * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
57ac9a364SKalle Valo  *
67ac9a364SKalle Valo  * Contact Information:
77ac9a364SKalle Valo  *  Intel Linux Wireless <ilw@linux.intel.com>
87ac9a364SKalle Valo  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
97ac9a364SKalle Valo  *
107ac9a364SKalle Valo  *****************************************************************************/
117ac9a364SKalle Valo 
127ac9a364SKalle Valo #include <linux/kernel.h>
137ac9a364SKalle Valo #include <linux/skbuff.h>
147ac9a364SKalle Valo #include <linux/slab.h>
157ac9a364SKalle Valo #include <net/mac80211.h>
167ac9a364SKalle Valo 
177ac9a364SKalle Valo #include <linux/netdevice.h>
187ac9a364SKalle Valo #include <linux/etherdevice.h>
197ac9a364SKalle Valo #include <linux/delay.h>
207ac9a364SKalle Valo 
217ac9a364SKalle Valo #include <linux/workqueue.h>
227ac9a364SKalle Valo 
237ac9a364SKalle Valo #include "commands.h"
247ac9a364SKalle Valo #include "3945.h"
257ac9a364SKalle Valo 
267ac9a364SKalle Valo #define RS_NAME "iwl-3945-rs"
277ac9a364SKalle Valo 
287ac9a364SKalle Valo static s32 il3945_expected_tpt_g[RATE_COUNT_3945] = {
297ac9a364SKalle Valo 	7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
307ac9a364SKalle Valo };
317ac9a364SKalle Valo 
327ac9a364SKalle Valo static s32 il3945_expected_tpt_g_prot[RATE_COUNT_3945] = {
337ac9a364SKalle Valo 	7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
347ac9a364SKalle Valo };
357ac9a364SKalle Valo 
367ac9a364SKalle Valo static s32 il3945_expected_tpt_a[RATE_COUNT_3945] = {
377ac9a364SKalle Valo 	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
387ac9a364SKalle Valo };
397ac9a364SKalle Valo 
407ac9a364SKalle Valo static s32 il3945_expected_tpt_b[RATE_COUNT_3945] = {
417ac9a364SKalle Valo 	7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
427ac9a364SKalle Valo };
437ac9a364SKalle Valo 
447ac9a364SKalle Valo struct il3945_tpt_entry {
457ac9a364SKalle Valo 	s8 min_rssi;
467ac9a364SKalle Valo 	u8 idx;
477ac9a364SKalle Valo };
487ac9a364SKalle Valo 
497ac9a364SKalle Valo static struct il3945_tpt_entry il3945_tpt_table_a[] = {
507ac9a364SKalle Valo 	{-60, RATE_54M_IDX},
517ac9a364SKalle Valo 	{-64, RATE_48M_IDX},
527ac9a364SKalle Valo 	{-72, RATE_36M_IDX},
537ac9a364SKalle Valo 	{-80, RATE_24M_IDX},
547ac9a364SKalle Valo 	{-84, RATE_18M_IDX},
557ac9a364SKalle Valo 	{-85, RATE_12M_IDX},
567ac9a364SKalle Valo 	{-87, RATE_9M_IDX},
577ac9a364SKalle Valo 	{-89, RATE_6M_IDX}
587ac9a364SKalle Valo };
597ac9a364SKalle Valo 
607ac9a364SKalle Valo static struct il3945_tpt_entry il3945_tpt_table_g[] = {
617ac9a364SKalle Valo 	{-60, RATE_54M_IDX},
627ac9a364SKalle Valo 	{-64, RATE_48M_IDX},
637ac9a364SKalle Valo 	{-68, RATE_36M_IDX},
647ac9a364SKalle Valo 	{-80, RATE_24M_IDX},
657ac9a364SKalle Valo 	{-84, RATE_18M_IDX},
667ac9a364SKalle Valo 	{-85, RATE_12M_IDX},
677ac9a364SKalle Valo 	{-86, RATE_11M_IDX},
687ac9a364SKalle Valo 	{-88, RATE_5M_IDX},
697ac9a364SKalle Valo 	{-90, RATE_2M_IDX},
707ac9a364SKalle Valo 	{-92, RATE_1M_IDX}
717ac9a364SKalle Valo };
727ac9a364SKalle Valo 
737ac9a364SKalle Valo #define RATE_MAX_WINDOW		62
747ac9a364SKalle Valo #define RATE_FLUSH		(3*HZ)
757ac9a364SKalle Valo #define RATE_WIN_FLUSH		(HZ/2)
767ac9a364SKalle Valo #define IL39_RATE_HIGH_TH	11520
777ac9a364SKalle Valo #define IL_SUCCESS_UP_TH	8960
787ac9a364SKalle Valo #define IL_SUCCESS_DOWN_TH	10880
797ac9a364SKalle Valo #define RATE_MIN_FAILURE_TH	6
807ac9a364SKalle Valo #define RATE_MIN_SUCCESS_TH	8
817ac9a364SKalle Valo #define RATE_DECREASE_TH	1920
827ac9a364SKalle Valo #define RATE_RETRY_TH		15
837ac9a364SKalle Valo 
847ac9a364SKalle Valo static u8
il3945_get_rate_idx_by_rssi(s32 rssi,enum nl80211_band band)8557fbcce3SJohannes Berg il3945_get_rate_idx_by_rssi(s32 rssi, enum nl80211_band band)
867ac9a364SKalle Valo {
877ac9a364SKalle Valo 	u32 idx = 0;
887ac9a364SKalle Valo 	u32 table_size = 0;
897ac9a364SKalle Valo 	struct il3945_tpt_entry *tpt_table = NULL;
907ac9a364SKalle Valo 
917ac9a364SKalle Valo 	if (rssi < IL_MIN_RSSI_VAL || rssi > IL_MAX_RSSI_VAL)
927ac9a364SKalle Valo 		rssi = IL_MIN_RSSI_VAL;
937ac9a364SKalle Valo 
947ac9a364SKalle Valo 	switch (band) {
9557fbcce3SJohannes Berg 	case NL80211_BAND_2GHZ:
967ac9a364SKalle Valo 		tpt_table = il3945_tpt_table_g;
977ac9a364SKalle Valo 		table_size = ARRAY_SIZE(il3945_tpt_table_g);
987ac9a364SKalle Valo 		break;
9957fbcce3SJohannes Berg 	case NL80211_BAND_5GHZ:
1007ac9a364SKalle Valo 		tpt_table = il3945_tpt_table_a;
1017ac9a364SKalle Valo 		table_size = ARRAY_SIZE(il3945_tpt_table_a);
1027ac9a364SKalle Valo 		break;
1037ac9a364SKalle Valo 	default:
1047ac9a364SKalle Valo 		BUG();
1057ac9a364SKalle Valo 		break;
1067ac9a364SKalle Valo 	}
1077ac9a364SKalle Valo 
1087ac9a364SKalle Valo 	while (idx < table_size && rssi < tpt_table[idx].min_rssi)
1097ac9a364SKalle Valo 		idx++;
1107ac9a364SKalle Valo 
1117ac9a364SKalle Valo 	idx = min(idx, table_size - 1);
1127ac9a364SKalle Valo 
1137ac9a364SKalle Valo 	return tpt_table[idx].idx;
1147ac9a364SKalle Valo }
1157ac9a364SKalle Valo 
1167ac9a364SKalle Valo static void
il3945_clear_win(struct il3945_rate_scale_data * win)1177ac9a364SKalle Valo il3945_clear_win(struct il3945_rate_scale_data *win)
1187ac9a364SKalle Valo {
1197ac9a364SKalle Valo 	win->data = 0;
1207ac9a364SKalle Valo 	win->success_counter = 0;
1217ac9a364SKalle Valo 	win->success_ratio = -1;
1227ac9a364SKalle Valo 	win->counter = 0;
1237ac9a364SKalle Valo 	win->average_tpt = IL_INVALID_VALUE;
1247ac9a364SKalle Valo 	win->stamp = 0;
1257ac9a364SKalle Valo }
1267ac9a364SKalle Valo 
127305fd82aSLee Jones /*
1287ac9a364SKalle Valo  * il3945_rate_scale_flush_wins - flush out the rate scale wins
1297ac9a364SKalle Valo  *
1307ac9a364SKalle Valo  * Returns the number of wins that have gathered data but were
1317ac9a364SKalle Valo  * not flushed.  If there were any that were not flushed, then
1327ac9a364SKalle Valo  * reschedule the rate flushing routine.
1337ac9a364SKalle Valo  */
1347ac9a364SKalle Valo static int
il3945_rate_scale_flush_wins(struct il3945_rs_sta * rs_sta)1357ac9a364SKalle Valo il3945_rate_scale_flush_wins(struct il3945_rs_sta *rs_sta)
1367ac9a364SKalle Valo {
1377ac9a364SKalle Valo 	int unflushed = 0;
1387ac9a364SKalle Valo 	int i;
1397ac9a364SKalle Valo 	unsigned long flags;
1407ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = rs_sta->il;
1417ac9a364SKalle Valo 
1427ac9a364SKalle Valo 	/*
1437ac9a364SKalle Valo 	 * For each rate, if we have collected data on that rate
1447ac9a364SKalle Valo 	 * and it has been more than RATE_WIN_FLUSH
1457ac9a364SKalle Valo 	 * since we flushed, clear out the gathered stats
1467ac9a364SKalle Valo 	 */
1477ac9a364SKalle Valo 	for (i = 0; i < RATE_COUNT_3945; i++) {
1487ac9a364SKalle Valo 		if (!rs_sta->win[i].counter)
1497ac9a364SKalle Valo 			continue;
1507ac9a364SKalle Valo 
1517ac9a364SKalle Valo 		spin_lock_irqsave(&rs_sta->lock, flags);
1527ac9a364SKalle Valo 		if (time_after(jiffies, rs_sta->win[i].stamp + RATE_WIN_FLUSH)) {
1537ac9a364SKalle Valo 			D_RATE("flushing %d samples of rate " "idx %d\n",
1547ac9a364SKalle Valo 			       rs_sta->win[i].counter, i);
1557ac9a364SKalle Valo 			il3945_clear_win(&rs_sta->win[i]);
1567ac9a364SKalle Valo 		} else
1577ac9a364SKalle Valo 			unflushed++;
1587ac9a364SKalle Valo 		spin_unlock_irqrestore(&rs_sta->lock, flags);
1597ac9a364SKalle Valo 	}
1607ac9a364SKalle Valo 
1617ac9a364SKalle Valo 	return unflushed;
1627ac9a364SKalle Valo }
1637ac9a364SKalle Valo 
1647ac9a364SKalle Valo #define RATE_FLUSH_MAX              5000	/* msec */
1657ac9a364SKalle Valo #define RATE_FLUSH_MIN              50	/* msec */
1667ac9a364SKalle Valo #define IL_AVERAGE_PACKETS             1500
1677ac9a364SKalle Valo 
1687ac9a364SKalle Valo static void
il3945_bg_rate_scale_flush(struct timer_list * t)1692b77839bSKees Cook il3945_bg_rate_scale_flush(struct timer_list *t)
1707ac9a364SKalle Valo {
1712b77839bSKees Cook 	struct il3945_rs_sta *rs_sta = from_timer(rs_sta, t, rate_scale_flush);
1727ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = rs_sta->il;
1737ac9a364SKalle Valo 	int unflushed = 0;
1747ac9a364SKalle Valo 	unsigned long flags;
1757ac9a364SKalle Valo 	u32 packet_count, duration, pps;
1767ac9a364SKalle Valo 
1777ac9a364SKalle Valo 	D_RATE("enter\n");
1787ac9a364SKalle Valo 
1797ac9a364SKalle Valo 	unflushed = il3945_rate_scale_flush_wins(rs_sta);
1807ac9a364SKalle Valo 
1817ac9a364SKalle Valo 	spin_lock_irqsave(&rs_sta->lock, flags);
1827ac9a364SKalle Valo 
1837ac9a364SKalle Valo 	/* Number of packets Rx'd since last time this timer ran */
1847ac9a364SKalle Valo 	packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
1857ac9a364SKalle Valo 
1867ac9a364SKalle Valo 	rs_sta->last_tx_packets = rs_sta->tx_packets + 1;
1877ac9a364SKalle Valo 
1887ac9a364SKalle Valo 	if (unflushed) {
1897ac9a364SKalle Valo 		duration =
1907ac9a364SKalle Valo 		    jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
1917ac9a364SKalle Valo 
1927ac9a364SKalle Valo 		D_RATE("Tx'd %d packets in %dms\n", packet_count, duration);
1937ac9a364SKalle Valo 
1947ac9a364SKalle Valo 		/* Determine packets per second */
1957ac9a364SKalle Valo 		if (duration)
1967ac9a364SKalle Valo 			pps = (packet_count * 1000) / duration;
1977ac9a364SKalle Valo 		else
1987ac9a364SKalle Valo 			pps = 0;
1997ac9a364SKalle Valo 
2007ac9a364SKalle Valo 		if (pps) {
2017ac9a364SKalle Valo 			duration = (IL_AVERAGE_PACKETS * 1000) / pps;
2027ac9a364SKalle Valo 			if (duration < RATE_FLUSH_MIN)
2037ac9a364SKalle Valo 				duration = RATE_FLUSH_MIN;
2047ac9a364SKalle Valo 			else if (duration > RATE_FLUSH_MAX)
2057ac9a364SKalle Valo 				duration = RATE_FLUSH_MAX;
2067ac9a364SKalle Valo 		} else
2077ac9a364SKalle Valo 			duration = RATE_FLUSH_MAX;
2087ac9a364SKalle Valo 
2097ac9a364SKalle Valo 		rs_sta->flush_time = msecs_to_jiffies(duration);
2107ac9a364SKalle Valo 
2117ac9a364SKalle Valo 		D_RATE("new flush period: %d msec ave %d\n", duration,
2127ac9a364SKalle Valo 		       packet_count);
2137ac9a364SKalle Valo 
2147ac9a364SKalle Valo 		mod_timer(&rs_sta->rate_scale_flush,
2157ac9a364SKalle Valo 			  jiffies + rs_sta->flush_time);
2167ac9a364SKalle Valo 
2177ac9a364SKalle Valo 		rs_sta->last_partial_flush = jiffies;
2187ac9a364SKalle Valo 	} else {
2197ac9a364SKalle Valo 		rs_sta->flush_time = RATE_FLUSH;
2207ac9a364SKalle Valo 		rs_sta->flush_pending = 0;
2217ac9a364SKalle Valo 	}
2227ac9a364SKalle Valo 	/* If there weren't any unflushed entries, we don't schedule the timer
2237ac9a364SKalle Valo 	 * to run again */
2247ac9a364SKalle Valo 
2257ac9a364SKalle Valo 	rs_sta->last_flush = jiffies;
2267ac9a364SKalle Valo 
2277ac9a364SKalle Valo 	spin_unlock_irqrestore(&rs_sta->lock, flags);
2287ac9a364SKalle Valo 
2297ac9a364SKalle Valo 	D_RATE("leave\n");
2307ac9a364SKalle Valo }
2317ac9a364SKalle Valo 
232305fd82aSLee Jones /*
2337ac9a364SKalle Valo  * il3945_collect_tx_data - Update the success/failure sliding win
2347ac9a364SKalle Valo  *
2357ac9a364SKalle Valo  * We keep a sliding win of the last 64 packets transmitted
2367ac9a364SKalle Valo  * at this rate.  win->data contains the bitmask of successful
2377ac9a364SKalle Valo  * packets.
2387ac9a364SKalle Valo  */
2397ac9a364SKalle Valo static void
il3945_collect_tx_data(struct il3945_rs_sta * rs_sta,struct il3945_rate_scale_data * win,int success,int retries,int idx)2407ac9a364SKalle Valo il3945_collect_tx_data(struct il3945_rs_sta *rs_sta,
2417ac9a364SKalle Valo 		       struct il3945_rate_scale_data *win, int success,
2427ac9a364SKalle Valo 		       int retries, int idx)
2437ac9a364SKalle Valo {
2447ac9a364SKalle Valo 	unsigned long flags;
2457ac9a364SKalle Valo 	s32 fail_count;
2467ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = rs_sta->il;
2477ac9a364SKalle Valo 
2487ac9a364SKalle Valo 	if (!retries) {
2497ac9a364SKalle Valo 		D_RATE("leave: retries == 0 -- should be at least 1\n");
2507ac9a364SKalle Valo 		return;
2517ac9a364SKalle Valo 	}
2527ac9a364SKalle Valo 
2537ac9a364SKalle Valo 	spin_lock_irqsave(&rs_sta->lock, flags);
2547ac9a364SKalle Valo 
2557ac9a364SKalle Valo 	/*
2567ac9a364SKalle Valo 	 * Keep track of only the latest 62 tx frame attempts in this rate's
2577ac9a364SKalle Valo 	 * history win; anything older isn't really relevant any more.
2587ac9a364SKalle Valo 	 * If we have filled up the sliding win, drop the oldest attempt;
2597ac9a364SKalle Valo 	 * if the oldest attempt (highest bit in bitmap) shows "success",
2607ac9a364SKalle Valo 	 * subtract "1" from the success counter (this is the main reason
2617ac9a364SKalle Valo 	 * we keep these bitmaps!).
2627ac9a364SKalle Valo 	 * */
2637ac9a364SKalle Valo 	while (retries > 0) {
2647ac9a364SKalle Valo 		if (win->counter >= RATE_MAX_WINDOW) {
2657ac9a364SKalle Valo 
2667ac9a364SKalle Valo 			/* remove earliest */
2677ac9a364SKalle Valo 			win->counter = RATE_MAX_WINDOW - 1;
2687ac9a364SKalle Valo 
2697ac9a364SKalle Valo 			if (win->data & (1ULL << (RATE_MAX_WINDOW - 1))) {
2707ac9a364SKalle Valo 				win->data &= ~(1ULL << (RATE_MAX_WINDOW - 1));
2717ac9a364SKalle Valo 				win->success_counter--;
2727ac9a364SKalle Valo 			}
2737ac9a364SKalle Valo 		}
2747ac9a364SKalle Valo 
2757ac9a364SKalle Valo 		/* Increment frames-attempted counter */
2767ac9a364SKalle Valo 		win->counter++;
2777ac9a364SKalle Valo 
2787ac9a364SKalle Valo 		/* Shift bitmap by one frame (throw away oldest history),
2797ac9a364SKalle Valo 		 * OR in "1", and increment "success" if this
2807ac9a364SKalle Valo 		 * frame was successful. */
2817ac9a364SKalle Valo 		win->data <<= 1;
2827ac9a364SKalle Valo 		if (success > 0) {
2837ac9a364SKalle Valo 			win->success_counter++;
2847ac9a364SKalle Valo 			win->data |= 0x1;
2857ac9a364SKalle Valo 			success--;
2867ac9a364SKalle Valo 		}
2877ac9a364SKalle Valo 
2887ac9a364SKalle Valo 		retries--;
2897ac9a364SKalle Valo 	}
2907ac9a364SKalle Valo 
2917ac9a364SKalle Valo 	/* Calculate current success ratio, avoid divide-by-0! */
2927ac9a364SKalle Valo 	if (win->counter > 0)
2937ac9a364SKalle Valo 		win->success_ratio =
2947ac9a364SKalle Valo 		    128 * (100 * win->success_counter) / win->counter;
2957ac9a364SKalle Valo 	else
2967ac9a364SKalle Valo 		win->success_ratio = IL_INVALID_VALUE;
2977ac9a364SKalle Valo 
2987ac9a364SKalle Valo 	fail_count = win->counter - win->success_counter;
2997ac9a364SKalle Valo 
3007ac9a364SKalle Valo 	/* Calculate average throughput, if we have enough history. */
3017ac9a364SKalle Valo 	if (fail_count >= RATE_MIN_FAILURE_TH ||
3027ac9a364SKalle Valo 	    win->success_counter >= RATE_MIN_SUCCESS_TH)
3037ac9a364SKalle Valo 		win->average_tpt =
3047ac9a364SKalle Valo 		    ((win->success_ratio * rs_sta->expected_tpt[idx] +
3057ac9a364SKalle Valo 		      64) / 128);
3067ac9a364SKalle Valo 	else
3077ac9a364SKalle Valo 		win->average_tpt = IL_INVALID_VALUE;
3087ac9a364SKalle Valo 
3097ac9a364SKalle Valo 	/* Tag this win as having been updated */
3107ac9a364SKalle Valo 	win->stamp = jiffies;
3117ac9a364SKalle Valo 
3127ac9a364SKalle Valo 	spin_unlock_irqrestore(&rs_sta->lock, flags);
3137ac9a364SKalle Valo }
3147ac9a364SKalle Valo 
3157ac9a364SKalle Valo /*
3167ac9a364SKalle Valo  * Called after adding a new station to initialize rate scaling
3177ac9a364SKalle Valo  */
3187ac9a364SKalle Valo void
il3945_rs_rate_init(struct il_priv * il,struct ieee80211_sta * sta,u8 sta_id)3197ac9a364SKalle Valo il3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
3207ac9a364SKalle Valo {
3217ac9a364SKalle Valo 	struct ieee80211_hw *hw = il->hw;
3227ac9a364SKalle Valo 	struct ieee80211_conf *conf = &il->hw->conf;
3237ac9a364SKalle Valo 	struct il3945_sta_priv *psta;
3247ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta;
3257ac9a364SKalle Valo 	struct ieee80211_supported_band *sband;
3267ac9a364SKalle Valo 	int i;
3277ac9a364SKalle Valo 
3287ac9a364SKalle Valo 	D_INFO("enter\n");
3297ac9a364SKalle Valo 	if (sta_id == il->hw_params.bcast_id)
3307ac9a364SKalle Valo 		goto out;
3317ac9a364SKalle Valo 
3327ac9a364SKalle Valo 	psta = (struct il3945_sta_priv *)sta->drv_priv;
3337ac9a364SKalle Valo 	rs_sta = &psta->rs_sta;
3347ac9a364SKalle Valo 	sband = hw->wiphy->bands[conf->chandef.chan->band];
3357ac9a364SKalle Valo 
3367ac9a364SKalle Valo 	rs_sta->il = il;
3377ac9a364SKalle Valo 
3387ac9a364SKalle Valo 	rs_sta->start_rate = RATE_INVALID;
3397ac9a364SKalle Valo 
3407ac9a364SKalle Valo 	/* default to just 802.11b */
3417ac9a364SKalle Valo 	rs_sta->expected_tpt = il3945_expected_tpt_b;
3427ac9a364SKalle Valo 
3437ac9a364SKalle Valo 	rs_sta->last_partial_flush = jiffies;
3447ac9a364SKalle Valo 	rs_sta->last_flush = jiffies;
3457ac9a364SKalle Valo 	rs_sta->flush_time = RATE_FLUSH;
3467ac9a364SKalle Valo 	rs_sta->last_tx_packets = 0;
3477ac9a364SKalle Valo 
3487ac9a364SKalle Valo 	for (i = 0; i < RATE_COUNT_3945; i++)
3497ac9a364SKalle Valo 		il3945_clear_win(&rs_sta->win[i]);
3507ac9a364SKalle Valo 
3517ac9a364SKalle Valo 	/* TODO: what is a good starting rate for STA? About middle? Maybe not
3527ac9a364SKalle Valo 	 * the lowest or the highest rate.. Could consider using RSSI from
3537ac9a364SKalle Valo 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
3547ac9a364SKalle Valo 	 * after assoc.. */
3557ac9a364SKalle Valo 
3567ac9a364SKalle Valo 	for (i = sband->n_bitrates - 1; i >= 0; i--) {
357*046d2e7cSSriram R 		if (sta->deflink.supp_rates[sband->band] & (1 << i)) {
3587ac9a364SKalle Valo 			rs_sta->last_txrate_idx = i;
3597ac9a364SKalle Valo 			break;
3607ac9a364SKalle Valo 		}
3617ac9a364SKalle Valo 	}
3627ac9a364SKalle Valo 
363*046d2e7cSSriram R 	il->_3945.sta_supp_rates = sta->deflink.supp_rates[sband->band];
3647ac9a364SKalle Valo 	/* For 5 GHz band it start at IL_FIRST_OFDM_RATE */
36557fbcce3SJohannes Berg 	if (sband->band == NL80211_BAND_5GHZ) {
3667ac9a364SKalle Valo 		rs_sta->last_txrate_idx += IL_FIRST_OFDM_RATE;
3677ac9a364SKalle Valo 		il->_3945.sta_supp_rates <<= IL_FIRST_OFDM_RATE;
3687ac9a364SKalle Valo 	}
3697ac9a364SKalle Valo 
3707ac9a364SKalle Valo out:
3717ac9a364SKalle Valo 	il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS;
3727ac9a364SKalle Valo 
3737ac9a364SKalle Valo 	D_INFO("leave\n");
3747ac9a364SKalle Valo }
3757ac9a364SKalle Valo 
3767ac9a364SKalle Valo static void *
il3945_rs_alloc(struct ieee80211_hw * hw)3776cb5f3eaSJohannes Berg il3945_rs_alloc(struct ieee80211_hw *hw)
3787ac9a364SKalle Valo {
3797ac9a364SKalle Valo 	return hw->priv;
3807ac9a364SKalle Valo }
3817ac9a364SKalle Valo 
3827ac9a364SKalle Valo /* rate scale requires free function to be implemented */
3837ac9a364SKalle Valo static void
il3945_rs_free(void * il)3847ac9a364SKalle Valo il3945_rs_free(void *il)
3857ac9a364SKalle Valo {
3867ac9a364SKalle Valo }
3877ac9a364SKalle Valo 
3887ac9a364SKalle Valo static void *
il3945_rs_alloc_sta(void * il_priv,struct ieee80211_sta * sta,gfp_t gfp)3897ac9a364SKalle Valo il3945_rs_alloc_sta(void *il_priv, struct ieee80211_sta *sta, gfp_t gfp)
3907ac9a364SKalle Valo {
3917ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta;
3927ac9a364SKalle Valo 	struct il3945_sta_priv *psta = (void *)sta->drv_priv;
3937ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = il_priv;
3947ac9a364SKalle Valo 
3957ac9a364SKalle Valo 	D_RATE("enter\n");
3967ac9a364SKalle Valo 
3977ac9a364SKalle Valo 	rs_sta = &psta->rs_sta;
3987ac9a364SKalle Valo 
3997ac9a364SKalle Valo 	spin_lock_init(&rs_sta->lock);
4002b77839bSKees Cook 	timer_setup(&rs_sta->rate_scale_flush, il3945_bg_rate_scale_flush, 0);
4017ac9a364SKalle Valo 	D_RATE("leave\n");
4027ac9a364SKalle Valo 
4037ac9a364SKalle Valo 	return rs_sta;
4047ac9a364SKalle Valo }
4057ac9a364SKalle Valo 
4067ac9a364SKalle Valo static void
il3945_rs_free_sta(void * il_priv,struct ieee80211_sta * sta,void * il_sta)4077ac9a364SKalle Valo il3945_rs_free_sta(void *il_priv, struct ieee80211_sta *sta, void *il_sta)
4087ac9a364SKalle Valo {
4097ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta = il_sta;
4107ac9a364SKalle Valo 
4117ac9a364SKalle Valo 	/*
4127ac9a364SKalle Valo 	 * Be careful not to use any members of il3945_rs_sta (like trying
4137ac9a364SKalle Valo 	 * to use il_priv to print out debugging) since it may not be fully
4147ac9a364SKalle Valo 	 * initialized at this point.
4157ac9a364SKalle Valo 	 */
4167ac9a364SKalle Valo 	del_timer_sync(&rs_sta->rate_scale_flush);
4177ac9a364SKalle Valo }
4187ac9a364SKalle Valo 
419305fd82aSLee Jones /*
4207ac9a364SKalle Valo  * il3945_rs_tx_status - Update rate control values based on Tx results
4217ac9a364SKalle Valo  *
4227ac9a364SKalle Valo  * NOTE: Uses il_priv->retry_rate for the # of retries attempted by
4237ac9a364SKalle Valo  * the hardware for each rate.
4247ac9a364SKalle Valo  */
4257ac9a364SKalle Valo static void
il3945_rs_tx_status(void * il_rate,struct ieee80211_supported_band * sband,struct ieee80211_sta * sta,void * il_sta,struct sk_buff * skb)4267ac9a364SKalle Valo il3945_rs_tx_status(void *il_rate, struct ieee80211_supported_band *sband,
4277ac9a364SKalle Valo 		    struct ieee80211_sta *sta, void *il_sta,
4287ac9a364SKalle Valo 		    struct sk_buff *skb)
4297ac9a364SKalle Valo {
4307ac9a364SKalle Valo 	s8 retries = 0, current_count;
4317ac9a364SKalle Valo 	int scale_rate_idx, first_idx, last_idx;
4327ac9a364SKalle Valo 	unsigned long flags;
4337ac9a364SKalle Valo 	struct il_priv *il = (struct il_priv *)il_rate;
4347ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta = il_sta;
4357ac9a364SKalle Valo 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
4367ac9a364SKalle Valo 
4377ac9a364SKalle Valo 	D_RATE("enter\n");
4387ac9a364SKalle Valo 
4397ac9a364SKalle Valo 	retries = info->status.rates[0].count;
4407ac9a364SKalle Valo 	/* Sanity Check for retries */
4417ac9a364SKalle Valo 	if (retries > RATE_RETRY_TH)
4427ac9a364SKalle Valo 		retries = RATE_RETRY_TH;
4437ac9a364SKalle Valo 
4447ac9a364SKalle Valo 	first_idx = sband->bitrates[info->status.rates[0].idx].hw_value;
4457ac9a364SKalle Valo 	if (first_idx < 0 || first_idx >= RATE_COUNT_3945) {
4467ac9a364SKalle Valo 		D_RATE("leave: Rate out of bounds: %d\n", first_idx);
4477ac9a364SKalle Valo 		return;
4487ac9a364SKalle Valo 	}
4497ac9a364SKalle Valo 
4507ac9a364SKalle Valo 	if (!il_sta) {
4517ac9a364SKalle Valo 		D_RATE("leave: No STA il data to update!\n");
4527ac9a364SKalle Valo 		return;
4537ac9a364SKalle Valo 	}
4547ac9a364SKalle Valo 
4557ac9a364SKalle Valo 	/* Treat uninitialized rate scaling data same as non-existing. */
4567ac9a364SKalle Valo 	if (!rs_sta->il) {
4577ac9a364SKalle Valo 		D_RATE("leave: STA il data uninitialized!\n");
4587ac9a364SKalle Valo 		return;
4597ac9a364SKalle Valo 	}
4607ac9a364SKalle Valo 
4617ac9a364SKalle Valo 	rs_sta->tx_packets++;
4627ac9a364SKalle Valo 
4637ac9a364SKalle Valo 	scale_rate_idx = first_idx;
4647ac9a364SKalle Valo 	last_idx = first_idx;
4657ac9a364SKalle Valo 
4667ac9a364SKalle Valo 	/*
4677ac9a364SKalle Valo 	 * Update the win for each rate.  We determine which rates
4687ac9a364SKalle Valo 	 * were Tx'd based on the total number of retries vs. the number
4697ac9a364SKalle Valo 	 * of retries configured for each rate -- currently set to the
4707ac9a364SKalle Valo 	 * il value 'retry_rate' vs. rate specific
4717ac9a364SKalle Valo 	 *
4727ac9a364SKalle Valo 	 * On exit from this while loop last_idx indicates the rate
4737ac9a364SKalle Valo 	 * at which the frame was finally transmitted (or failed if no
4747ac9a364SKalle Valo 	 * ACK)
4757ac9a364SKalle Valo 	 */
4767ac9a364SKalle Valo 	while (retries > 1) {
4777ac9a364SKalle Valo 		if ((retries - 1) < il->retry_rate) {
4787ac9a364SKalle Valo 			current_count = (retries - 1);
4797ac9a364SKalle Valo 			last_idx = scale_rate_idx;
4807ac9a364SKalle Valo 		} else {
4817ac9a364SKalle Valo 			current_count = il->retry_rate;
4827ac9a364SKalle Valo 			last_idx = il3945_rs_next_rate(il, scale_rate_idx);
4837ac9a364SKalle Valo 		}
4847ac9a364SKalle Valo 
4857ac9a364SKalle Valo 		/* Update this rate accounting for as many retries
4867ac9a364SKalle Valo 		 * as was used for it (per current_count) */
4877ac9a364SKalle Valo 		il3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_idx], 0,
4887ac9a364SKalle Valo 				       current_count, scale_rate_idx);
4897ac9a364SKalle Valo 		D_RATE("Update rate %d for %d retries.\n", scale_rate_idx,
4907ac9a364SKalle Valo 		       current_count);
4917ac9a364SKalle Valo 
4927ac9a364SKalle Valo 		retries -= current_count;
4937ac9a364SKalle Valo 
4947ac9a364SKalle Valo 		scale_rate_idx = last_idx;
4957ac9a364SKalle Valo 	}
4967ac9a364SKalle Valo 
4977ac9a364SKalle Valo 	/* Update the last idx win with success/failure based on ACK */
4987ac9a364SKalle Valo 	D_RATE("Update rate %d with %s.\n", last_idx,
4997ac9a364SKalle Valo 	       (info->flags & IEEE80211_TX_STAT_ACK) ? "success" : "failure");
5007ac9a364SKalle Valo 	il3945_collect_tx_data(rs_sta, &rs_sta->win[last_idx],
5017ac9a364SKalle Valo 			       info->flags & IEEE80211_TX_STAT_ACK, 1,
5027ac9a364SKalle Valo 			       last_idx);
5037ac9a364SKalle Valo 
5047ac9a364SKalle Valo 	/* We updated the rate scale win -- if its been more than
5057ac9a364SKalle Valo 	 * flush_time since the last run, schedule the flush
5067ac9a364SKalle Valo 	 * again */
5077ac9a364SKalle Valo 	spin_lock_irqsave(&rs_sta->lock, flags);
5087ac9a364SKalle Valo 
5097ac9a364SKalle Valo 	if (!rs_sta->flush_pending &&
5107ac9a364SKalle Valo 	    time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) {
5117ac9a364SKalle Valo 
5127ac9a364SKalle Valo 		rs_sta->last_partial_flush = jiffies;
5137ac9a364SKalle Valo 		rs_sta->flush_pending = 1;
5147ac9a364SKalle Valo 		mod_timer(&rs_sta->rate_scale_flush,
5157ac9a364SKalle Valo 			  jiffies + rs_sta->flush_time);
5167ac9a364SKalle Valo 	}
5177ac9a364SKalle Valo 
5187ac9a364SKalle Valo 	spin_unlock_irqrestore(&rs_sta->lock, flags);
5197ac9a364SKalle Valo 
5207ac9a364SKalle Valo 	D_RATE("leave\n");
5217ac9a364SKalle Valo }
5227ac9a364SKalle Valo 
5237ac9a364SKalle Valo static u16
il3945_get_adjacent_rate(struct il3945_rs_sta * rs_sta,u8 idx,u16 rate_mask,enum nl80211_band band)5247ac9a364SKalle Valo il3945_get_adjacent_rate(struct il3945_rs_sta *rs_sta, u8 idx, u16 rate_mask,
52557fbcce3SJohannes Berg 			 enum nl80211_band band)
5267ac9a364SKalle Valo {
5277ac9a364SKalle Valo 	u8 high = RATE_INVALID;
5287ac9a364SKalle Valo 	u8 low = RATE_INVALID;
5297ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = rs_sta->il;
5307ac9a364SKalle Valo 
5317ac9a364SKalle Valo 	/* 802.11A walks to the next literal adjacent rate in
5327ac9a364SKalle Valo 	 * the rate table */
53357fbcce3SJohannes Berg 	if (unlikely(band == NL80211_BAND_5GHZ)) {
5347ac9a364SKalle Valo 		int i;
5357ac9a364SKalle Valo 		u32 mask;
5367ac9a364SKalle Valo 
5377ac9a364SKalle Valo 		/* Find the previous rate that is in the rate mask */
5387ac9a364SKalle Valo 		i = idx - 1;
5397ac9a364SKalle Valo 		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
5407ac9a364SKalle Valo 			if (rate_mask & mask) {
5417ac9a364SKalle Valo 				low = i;
5427ac9a364SKalle Valo 				break;
5437ac9a364SKalle Valo 			}
5447ac9a364SKalle Valo 		}
5457ac9a364SKalle Valo 
5467ac9a364SKalle Valo 		/* Find the next rate that is in the rate mask */
5477ac9a364SKalle Valo 		i = idx + 1;
5487ac9a364SKalle Valo 		for (mask = (1 << i); i < RATE_COUNT_3945; i++, mask <<= 1) {
5497ac9a364SKalle Valo 			if (rate_mask & mask) {
5507ac9a364SKalle Valo 				high = i;
5517ac9a364SKalle Valo 				break;
5527ac9a364SKalle Valo 			}
5537ac9a364SKalle Valo 		}
5547ac9a364SKalle Valo 
5557ac9a364SKalle Valo 		return (high << 8) | low;
5567ac9a364SKalle Valo 	}
5577ac9a364SKalle Valo 
5587ac9a364SKalle Valo 	low = idx;
5597ac9a364SKalle Valo 	while (low != RATE_INVALID) {
5607ac9a364SKalle Valo 		if (rs_sta->tgg)
5617ac9a364SKalle Valo 			low = il3945_rates[low].prev_rs_tgg;
5627ac9a364SKalle Valo 		else
5637ac9a364SKalle Valo 			low = il3945_rates[low].prev_rs;
5647ac9a364SKalle Valo 		if (low == RATE_INVALID)
5657ac9a364SKalle Valo 			break;
5667ac9a364SKalle Valo 		if (rate_mask & (1 << low))
5677ac9a364SKalle Valo 			break;
5687ac9a364SKalle Valo 		D_RATE("Skipping masked lower rate: %d\n", low);
5697ac9a364SKalle Valo 	}
5707ac9a364SKalle Valo 
5717ac9a364SKalle Valo 	high = idx;
5727ac9a364SKalle Valo 	while (high != RATE_INVALID) {
5737ac9a364SKalle Valo 		if (rs_sta->tgg)
5747ac9a364SKalle Valo 			high = il3945_rates[high].next_rs_tgg;
5757ac9a364SKalle Valo 		else
5767ac9a364SKalle Valo 			high = il3945_rates[high].next_rs;
5777ac9a364SKalle Valo 		if (high == RATE_INVALID)
5787ac9a364SKalle Valo 			break;
5797ac9a364SKalle Valo 		if (rate_mask & (1 << high))
5807ac9a364SKalle Valo 			break;
5817ac9a364SKalle Valo 		D_RATE("Skipping masked higher rate: %d\n", high);
5827ac9a364SKalle Valo 	}
5837ac9a364SKalle Valo 
5847ac9a364SKalle Valo 	return (high << 8) | low;
5857ac9a364SKalle Valo }
5867ac9a364SKalle Valo 
587305fd82aSLee Jones /*
5887ac9a364SKalle Valo  * il3945_rs_get_rate - find the rate for the requested packet
5897ac9a364SKalle Valo  *
5907ac9a364SKalle Valo  * Returns the ieee80211_rate structure allocated by the driver.
5917ac9a364SKalle Valo  *
5927ac9a364SKalle Valo  * The rate control algorithm has no internal mapping between hw_mode's
5937ac9a364SKalle Valo  * rate ordering and the rate ordering used by the rate control algorithm.
5947ac9a364SKalle Valo  *
5957ac9a364SKalle Valo  * The rate control algorithm uses a single table of rates that goes across
5967ac9a364SKalle Valo  * the entire A/B/G spectrum vs. being limited to just one particular
5977ac9a364SKalle Valo  * hw_mode.
5987ac9a364SKalle Valo  *
5997ac9a364SKalle Valo  * As such, we can't convert the idx obtained below into the hw_mode's
6007ac9a364SKalle Valo  * rate table and must reference the driver allocated rate table
6017ac9a364SKalle Valo  *
6027ac9a364SKalle Valo  */
6037ac9a364SKalle Valo static void
il3945_rs_get_rate(void * il_r,struct ieee80211_sta * sta,void * il_sta,struct ieee80211_tx_rate_control * txrc)6047ac9a364SKalle Valo il3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
6057ac9a364SKalle Valo 		   struct ieee80211_tx_rate_control *txrc)
6067ac9a364SKalle Valo {
6077ac9a364SKalle Valo 	struct ieee80211_supported_band *sband = txrc->sband;
6087ac9a364SKalle Valo 	struct sk_buff *skb = txrc->skb;
6097ac9a364SKalle Valo 	u8 low = RATE_INVALID;
6107ac9a364SKalle Valo 	u8 high = RATE_INVALID;
6117ac9a364SKalle Valo 	u16 high_low;
6127ac9a364SKalle Valo 	int idx;
6137ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta = il_sta;
6147ac9a364SKalle Valo 	struct il3945_rate_scale_data *win = NULL;
6157ac9a364SKalle Valo 	int current_tpt = IL_INVALID_VALUE;
6167ac9a364SKalle Valo 	int low_tpt = IL_INVALID_VALUE;
6177ac9a364SKalle Valo 	int high_tpt = IL_INVALID_VALUE;
6187ac9a364SKalle Valo 	u32 fail_count;
6197ac9a364SKalle Valo 	s8 scale_action = 0;
6207ac9a364SKalle Valo 	unsigned long flags;
6217ac9a364SKalle Valo 	u16 rate_mask;
6227ac9a364SKalle Valo 	s8 max_rate_idx = -1;
6237ac9a364SKalle Valo 	struct il_priv *il __maybe_unused = (struct il_priv *)il_r;
6247ac9a364SKalle Valo 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
6257ac9a364SKalle Valo 
6267ac9a364SKalle Valo 	D_RATE("enter\n");
6277ac9a364SKalle Valo 
6287ac9a364SKalle Valo 	/* Treat uninitialized rate scaling data same as non-existing. */
6297ac9a364SKalle Valo 	if (rs_sta && !rs_sta->il) {
6307ac9a364SKalle Valo 		D_RATE("Rate scaling information not initialized yet.\n");
6317ac9a364SKalle Valo 		il_sta = NULL;
6327ac9a364SKalle Valo 	}
6337ac9a364SKalle Valo 
634*046d2e7cSSriram R 	rate_mask = sta->deflink.supp_rates[sband->band];
6357ac9a364SKalle Valo 
6367ac9a364SKalle Valo 	/* get user max rate if set */
637a3f9d596SJohannes Berg 	max_rate_idx = fls(txrc->rate_idx_mask) - 1;
63857fbcce3SJohannes Berg 	if (sband->band == NL80211_BAND_5GHZ && max_rate_idx != -1)
6397ac9a364SKalle Valo 		max_rate_idx += IL_FIRST_OFDM_RATE;
6407ac9a364SKalle Valo 	if (max_rate_idx < 0 || max_rate_idx >= RATE_COUNT)
6417ac9a364SKalle Valo 		max_rate_idx = -1;
6427ac9a364SKalle Valo 
6437ac9a364SKalle Valo 	idx = min(rs_sta->last_txrate_idx & 0xffff, RATE_COUNT_3945 - 1);
6447ac9a364SKalle Valo 
64557fbcce3SJohannes Berg 	if (sband->band == NL80211_BAND_5GHZ)
6467ac9a364SKalle Valo 		rate_mask = rate_mask << IL_FIRST_OFDM_RATE;
6477ac9a364SKalle Valo 
6487ac9a364SKalle Valo 	spin_lock_irqsave(&rs_sta->lock, flags);
6497ac9a364SKalle Valo 
6507ac9a364SKalle Valo 	/* for recent assoc, choose best rate regarding
6517ac9a364SKalle Valo 	 * to rssi value
6527ac9a364SKalle Valo 	 */
6537ac9a364SKalle Valo 	if (rs_sta->start_rate != RATE_INVALID) {
6547ac9a364SKalle Valo 		if (rs_sta->start_rate < idx &&
6557ac9a364SKalle Valo 		    (rate_mask & (1 << rs_sta->start_rate)))
6567ac9a364SKalle Valo 			idx = rs_sta->start_rate;
6577ac9a364SKalle Valo 		rs_sta->start_rate = RATE_INVALID;
6587ac9a364SKalle Valo 	}
6597ac9a364SKalle Valo 
6607ac9a364SKalle Valo 	/* force user max rate if set by user */
6617ac9a364SKalle Valo 	if (max_rate_idx != -1 && max_rate_idx < idx) {
6627ac9a364SKalle Valo 		if (rate_mask & (1 << max_rate_idx))
6637ac9a364SKalle Valo 			idx = max_rate_idx;
6647ac9a364SKalle Valo 	}
6657ac9a364SKalle Valo 
6667ac9a364SKalle Valo 	win = &(rs_sta->win[idx]);
6677ac9a364SKalle Valo 
6687ac9a364SKalle Valo 	fail_count = win->counter - win->success_counter;
6697ac9a364SKalle Valo 
6707ac9a364SKalle Valo 	if (fail_count < RATE_MIN_FAILURE_TH &&
6717ac9a364SKalle Valo 	    win->success_counter < RATE_MIN_SUCCESS_TH) {
6727ac9a364SKalle Valo 		spin_unlock_irqrestore(&rs_sta->lock, flags);
6737ac9a364SKalle Valo 
6747ac9a364SKalle Valo 		D_RATE("Invalid average_tpt on rate %d: "
6757ac9a364SKalle Valo 		       "counter: %d, success_counter: %d, "
6767ac9a364SKalle Valo 		       "expected_tpt is %sNULL\n", idx, win->counter,
6777ac9a364SKalle Valo 		       win->success_counter,
6787ac9a364SKalle Valo 		       rs_sta->expected_tpt ? "not " : "");
6797ac9a364SKalle Valo 
6807ac9a364SKalle Valo 		/* Can't calculate this yet; not enough history */
6817ac9a364SKalle Valo 		win->average_tpt = IL_INVALID_VALUE;
6827ac9a364SKalle Valo 		goto out;
6837ac9a364SKalle Valo 
6847ac9a364SKalle Valo 	}
6857ac9a364SKalle Valo 
6867ac9a364SKalle Valo 	current_tpt = win->average_tpt;
6877ac9a364SKalle Valo 
6887ac9a364SKalle Valo 	high_low =
6897ac9a364SKalle Valo 	    il3945_get_adjacent_rate(rs_sta, idx, rate_mask, sband->band);
6907ac9a364SKalle Valo 	low = high_low & 0xff;
6917ac9a364SKalle Valo 	high = (high_low >> 8) & 0xff;
6927ac9a364SKalle Valo 
6937ac9a364SKalle Valo 	/* If user set max rate, dont allow higher than user constrain */
6947ac9a364SKalle Valo 	if (max_rate_idx != -1 && max_rate_idx < high)
6957ac9a364SKalle Valo 		high = RATE_INVALID;
6967ac9a364SKalle Valo 
6977ac9a364SKalle Valo 	/* Collect Measured throughputs of adjacent rates */
6987ac9a364SKalle Valo 	if (low != RATE_INVALID)
6997ac9a364SKalle Valo 		low_tpt = rs_sta->win[low].average_tpt;
7007ac9a364SKalle Valo 
7017ac9a364SKalle Valo 	if (high != RATE_INVALID)
7027ac9a364SKalle Valo 		high_tpt = rs_sta->win[high].average_tpt;
7037ac9a364SKalle Valo 
7047ac9a364SKalle Valo 	spin_unlock_irqrestore(&rs_sta->lock, flags);
7057ac9a364SKalle Valo 
7067ac9a364SKalle Valo 	scale_action = 0;
7077ac9a364SKalle Valo 
7087ac9a364SKalle Valo 	/* Low success ratio , need to drop the rate */
7097ac9a364SKalle Valo 	if (win->success_ratio < RATE_DECREASE_TH || !current_tpt) {
7107ac9a364SKalle Valo 		D_RATE("decrease rate because of low success_ratio\n");
7117ac9a364SKalle Valo 		scale_action = -1;
7127ac9a364SKalle Valo 		/* No throughput measured yet for adjacent rates,
7137ac9a364SKalle Valo 		 * try increase */
7147ac9a364SKalle Valo 	} else if (low_tpt == IL_INVALID_VALUE && high_tpt == IL_INVALID_VALUE) {
7157ac9a364SKalle Valo 
7167ac9a364SKalle Valo 		if (high != RATE_INVALID &&
7177ac9a364SKalle Valo 		    win->success_ratio >= RATE_INCREASE_TH)
7187ac9a364SKalle Valo 			scale_action = 1;
7197ac9a364SKalle Valo 		else if (low != RATE_INVALID)
7207ac9a364SKalle Valo 			scale_action = 0;
7217ac9a364SKalle Valo 
7227ac9a364SKalle Valo 		/* Both adjacent throughputs are measured, but neither one has
7237ac9a364SKalle Valo 		 * better throughput; we're using the best rate, don't change
7247ac9a364SKalle Valo 		 * it! */
7257ac9a364SKalle Valo 	} else if (low_tpt != IL_INVALID_VALUE && high_tpt != IL_INVALID_VALUE
7267ac9a364SKalle Valo 		   && low_tpt < current_tpt && high_tpt < current_tpt) {
7277ac9a364SKalle Valo 
7287ac9a364SKalle Valo 		D_RATE("No action -- low [%d] & high [%d] < "
7297ac9a364SKalle Valo 		       "current_tpt [%d]\n", low_tpt, high_tpt, current_tpt);
7307ac9a364SKalle Valo 		scale_action = 0;
7317ac9a364SKalle Valo 
7327ac9a364SKalle Valo 		/* At least one of the rates has better throughput */
7337ac9a364SKalle Valo 	} else {
7347ac9a364SKalle Valo 		if (high_tpt != IL_INVALID_VALUE) {
7357ac9a364SKalle Valo 
7367ac9a364SKalle Valo 			/* High rate has better throughput, Increase
7377ac9a364SKalle Valo 			 * rate */
7387ac9a364SKalle Valo 			if (high_tpt > current_tpt &&
7397ac9a364SKalle Valo 			    win->success_ratio >= RATE_INCREASE_TH)
7407ac9a364SKalle Valo 				scale_action = 1;
7417ac9a364SKalle Valo 			else {
7427ac9a364SKalle Valo 				D_RATE("decrease rate because of high tpt\n");
7437ac9a364SKalle Valo 				scale_action = 0;
7447ac9a364SKalle Valo 			}
7457ac9a364SKalle Valo 		} else if (low_tpt != IL_INVALID_VALUE) {
7467ac9a364SKalle Valo 			if (low_tpt > current_tpt) {
7477ac9a364SKalle Valo 				D_RATE("decrease rate because of low tpt\n");
7487ac9a364SKalle Valo 				scale_action = -1;
7497ac9a364SKalle Valo 			} else if (win->success_ratio >= RATE_INCREASE_TH) {
7507ac9a364SKalle Valo 				/* Lower rate has better
7517ac9a364SKalle Valo 				 * throughput,decrease rate */
7527ac9a364SKalle Valo 				scale_action = 1;
7537ac9a364SKalle Valo 			}
7547ac9a364SKalle Valo 		}
7557ac9a364SKalle Valo 	}
7567ac9a364SKalle Valo 
7577ac9a364SKalle Valo 	/* Sanity check; asked for decrease, but success rate or throughput
7587ac9a364SKalle Valo 	 * has been good at old rate.  Don't change it. */
7597ac9a364SKalle Valo 	if (scale_action == -1 && low != RATE_INVALID &&
7607ac9a364SKalle Valo 	    (win->success_ratio > RATE_HIGH_TH ||
7617ac9a364SKalle Valo 	     current_tpt > 100 * rs_sta->expected_tpt[low]))
7627ac9a364SKalle Valo 		scale_action = 0;
7637ac9a364SKalle Valo 
7647ac9a364SKalle Valo 	switch (scale_action) {
7657ac9a364SKalle Valo 	case -1:
766ac9ccb8bSYangtao Li 		/* Decrease rate */
7677ac9a364SKalle Valo 		if (low != RATE_INVALID)
7687ac9a364SKalle Valo 			idx = low;
7697ac9a364SKalle Valo 		break;
7707ac9a364SKalle Valo 	case 1:
7717ac9a364SKalle Valo 		/* Increase rate */
7727ac9a364SKalle Valo 		if (high != RATE_INVALID)
7737ac9a364SKalle Valo 			idx = high;
7747ac9a364SKalle Valo 
7757ac9a364SKalle Valo 		break;
7767ac9a364SKalle Valo 	case 0:
7777ac9a364SKalle Valo 	default:
7787ac9a364SKalle Valo 		/* No change */
7797ac9a364SKalle Valo 		break;
7807ac9a364SKalle Valo 	}
7817ac9a364SKalle Valo 
7827ac9a364SKalle Valo 	D_RATE("Selected %d (action %d) - low %d high %d\n", idx, scale_action,
7837ac9a364SKalle Valo 	       low, high);
7847ac9a364SKalle Valo 
7857ac9a364SKalle Valo out:
7867ac9a364SKalle Valo 
78757fbcce3SJohannes Berg 	if (sband->band == NL80211_BAND_5GHZ) {
7887ac9a364SKalle Valo 		if (WARN_ON_ONCE(idx < IL_FIRST_OFDM_RATE))
7897ac9a364SKalle Valo 			idx = IL_FIRST_OFDM_RATE;
7907ac9a364SKalle Valo 		rs_sta->last_txrate_idx = idx;
7917ac9a364SKalle Valo 		info->control.rates[0].idx = idx - IL_FIRST_OFDM_RATE;
7927ac9a364SKalle Valo 	} else {
7937ac9a364SKalle Valo 		rs_sta->last_txrate_idx = idx;
7947ac9a364SKalle Valo 		info->control.rates[0].idx = rs_sta->last_txrate_idx;
7957ac9a364SKalle Valo 	}
7967ac9a364SKalle Valo 	info->control.rates[0].count = 1;
7977ac9a364SKalle Valo 
7987ac9a364SKalle Valo 	D_RATE("leave: %d\n", idx);
7997ac9a364SKalle Valo }
8007ac9a364SKalle Valo 
8017ac9a364SKalle Valo #ifdef CONFIG_MAC80211_DEBUGFS
8027ac9a364SKalle Valo 
8037ac9a364SKalle Valo static ssize_t
il3945_sta_dbgfs_stats_table_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)8047ac9a364SKalle Valo il3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf,
8057ac9a364SKalle Valo 				  size_t count, loff_t *ppos)
8067ac9a364SKalle Valo {
8077ac9a364SKalle Valo 	char *buff;
8087ac9a364SKalle Valo 	int desc = 0;
8097ac9a364SKalle Valo 	int j;
8107ac9a364SKalle Valo 	ssize_t ret;
8117ac9a364SKalle Valo 	struct il3945_rs_sta *lq_sta = file->private_data;
8127ac9a364SKalle Valo 
8137ac9a364SKalle Valo 	buff = kmalloc(1024, GFP_KERNEL);
8147ac9a364SKalle Valo 	if (!buff)
8157ac9a364SKalle Valo 		return -ENOMEM;
8167ac9a364SKalle Valo 
8177ac9a364SKalle Valo 	desc +=
8187ac9a364SKalle Valo 	    sprintf(buff + desc,
8197ac9a364SKalle Valo 		    "tx packets=%d last rate idx=%d\n"
8207ac9a364SKalle Valo 		    "rate=0x%X flush time %d\n", lq_sta->tx_packets,
8217ac9a364SKalle Valo 		    lq_sta->last_txrate_idx, lq_sta->start_rate,
8227ac9a364SKalle Valo 		    jiffies_to_msecs(lq_sta->flush_time));
8237ac9a364SKalle Valo 	for (j = 0; j < RATE_COUNT_3945; j++) {
8247ac9a364SKalle Valo 		desc +=
8257ac9a364SKalle Valo 		    sprintf(buff + desc, "counter=%d success=%d %%=%d\n",
8267ac9a364SKalle Valo 			    lq_sta->win[j].counter,
8277ac9a364SKalle Valo 			    lq_sta->win[j].success_counter,
8287ac9a364SKalle Valo 			    lq_sta->win[j].success_ratio);
8297ac9a364SKalle Valo 	}
8307ac9a364SKalle Valo 	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
8317ac9a364SKalle Valo 	kfree(buff);
8327ac9a364SKalle Valo 	return ret;
8337ac9a364SKalle Valo }
8347ac9a364SKalle Valo 
8357ac9a364SKalle Valo static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
8367ac9a364SKalle Valo 	.read = il3945_sta_dbgfs_stats_table_read,
8377ac9a364SKalle Valo 	.open = simple_open,
8387ac9a364SKalle Valo 	.llseek = default_llseek,
8397ac9a364SKalle Valo };
8407ac9a364SKalle Valo 
8417ac9a364SKalle Valo static void
il3945_add_debugfs(void * il,void * il_sta,struct dentry * dir)8427ac9a364SKalle Valo il3945_add_debugfs(void *il, void *il_sta, struct dentry *dir)
8437ac9a364SKalle Valo {
8447ac9a364SKalle Valo 	struct il3945_rs_sta *lq_sta = il_sta;
8457ac9a364SKalle Valo 
8467ac9a364SKalle Valo 	debugfs_create_file("rate_stats_table", 0600, dir, lq_sta,
8477ac9a364SKalle Valo 			    &rs_sta_dbgfs_stats_table_ops);
8487ac9a364SKalle Valo }
8497ac9a364SKalle Valo #endif
8507ac9a364SKalle Valo 
8517ac9a364SKalle Valo /*
8527ac9a364SKalle Valo  * Initialization of rate scaling information is done by driver after
8537ac9a364SKalle Valo  * the station is added. Since mac80211 calls this function before a
8547ac9a364SKalle Valo  * station is added we ignore it.
8557ac9a364SKalle Valo  */
8567ac9a364SKalle Valo static void
il3945_rs_rate_init_stub(void * il_r,struct ieee80211_supported_band * sband,struct cfg80211_chan_def * chandef,struct ieee80211_sta * sta,void * il_sta)8577ac9a364SKalle Valo il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
8587ac9a364SKalle Valo 			 struct cfg80211_chan_def *chandef,
8597ac9a364SKalle Valo 			 struct ieee80211_sta *sta, void *il_sta)
8607ac9a364SKalle Valo {
8617ac9a364SKalle Valo }
8627ac9a364SKalle Valo 
8637ac9a364SKalle Valo static const struct rate_control_ops rs_ops = {
8647ac9a364SKalle Valo 	.name = RS_NAME,
8657ac9a364SKalle Valo 	.tx_status = il3945_rs_tx_status,
8667ac9a364SKalle Valo 	.get_rate = il3945_rs_get_rate,
8677ac9a364SKalle Valo 	.rate_init = il3945_rs_rate_init_stub,
8687ac9a364SKalle Valo 	.alloc = il3945_rs_alloc,
8697ac9a364SKalle Valo 	.free = il3945_rs_free,
8707ac9a364SKalle Valo 	.alloc_sta = il3945_rs_alloc_sta,
8717ac9a364SKalle Valo 	.free_sta = il3945_rs_free_sta,
8727ac9a364SKalle Valo #ifdef CONFIG_MAC80211_DEBUGFS
8737ac9a364SKalle Valo 	.add_sta_debugfs = il3945_add_debugfs,
8747ac9a364SKalle Valo #endif
8757ac9a364SKalle Valo 
8767ac9a364SKalle Valo };
8777ac9a364SKalle Valo 
8787ac9a364SKalle Valo void
il3945_rate_scale_init(struct ieee80211_hw * hw,s32 sta_id)8797ac9a364SKalle Valo il3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
8807ac9a364SKalle Valo {
8817ac9a364SKalle Valo 	struct il_priv *il = hw->priv;
8827ac9a364SKalle Valo 	s32 rssi = 0;
8837ac9a364SKalle Valo 	unsigned long flags;
8847ac9a364SKalle Valo 	struct il3945_rs_sta *rs_sta;
8857ac9a364SKalle Valo 	struct ieee80211_sta *sta;
8867ac9a364SKalle Valo 	struct il3945_sta_priv *psta;
8877ac9a364SKalle Valo 
8887ac9a364SKalle Valo 	D_RATE("enter\n");
8897ac9a364SKalle Valo 
8907ac9a364SKalle Valo 	rcu_read_lock();
8917ac9a364SKalle Valo 
8927ac9a364SKalle Valo 	sta = ieee80211_find_sta(il->vif, il->stations[sta_id].sta.sta.addr);
8937ac9a364SKalle Valo 	if (!sta) {
8947ac9a364SKalle Valo 		D_RATE("Unable to find station to initialize rate scaling.\n");
8957ac9a364SKalle Valo 		rcu_read_unlock();
8967ac9a364SKalle Valo 		return;
8977ac9a364SKalle Valo 	}
8987ac9a364SKalle Valo 
8997ac9a364SKalle Valo 	psta = (void *)sta->drv_priv;
9007ac9a364SKalle Valo 	rs_sta = &psta->rs_sta;
9017ac9a364SKalle Valo 
9027ac9a364SKalle Valo 	spin_lock_irqsave(&rs_sta->lock, flags);
9037ac9a364SKalle Valo 
9047ac9a364SKalle Valo 	rs_sta->tgg = 0;
9057ac9a364SKalle Valo 	switch (il->band) {
90657fbcce3SJohannes Berg 	case NL80211_BAND_2GHZ:
9077ac9a364SKalle Valo 		/* TODO: this always does G, not a regression */
9087ac9a364SKalle Valo 		if (il->active.flags & RXON_FLG_TGG_PROTECT_MSK) {
9097ac9a364SKalle Valo 			rs_sta->tgg = 1;
9107ac9a364SKalle Valo 			rs_sta->expected_tpt = il3945_expected_tpt_g_prot;
9117ac9a364SKalle Valo 		} else
9127ac9a364SKalle Valo 			rs_sta->expected_tpt = il3945_expected_tpt_g;
9137ac9a364SKalle Valo 		break;
91457fbcce3SJohannes Berg 	case NL80211_BAND_5GHZ:
9157ac9a364SKalle Valo 		rs_sta->expected_tpt = il3945_expected_tpt_a;
9167ac9a364SKalle Valo 		break;
9177ac9a364SKalle Valo 	default:
9187ac9a364SKalle Valo 		BUG();
9197ac9a364SKalle Valo 		break;
9207ac9a364SKalle Valo 	}
9217ac9a364SKalle Valo 
9227ac9a364SKalle Valo 	spin_unlock_irqrestore(&rs_sta->lock, flags);
9237ac9a364SKalle Valo 
9247ac9a364SKalle Valo 	rssi = il->_3945.last_rx_rssi;
9257ac9a364SKalle Valo 	if (rssi == 0)
9267ac9a364SKalle Valo 		rssi = IL_MIN_RSSI_VAL;
9277ac9a364SKalle Valo 
9287ac9a364SKalle Valo 	D_RATE("Network RSSI: %d\n", rssi);
9297ac9a364SKalle Valo 
9307ac9a364SKalle Valo 	rs_sta->start_rate = il3945_get_rate_idx_by_rssi(rssi, il->band);
9317ac9a364SKalle Valo 
9327ac9a364SKalle Valo 	D_RATE("leave: rssi %d assign rate idx: " "%d (plcp 0x%x)\n", rssi,
9337ac9a364SKalle Valo 	       rs_sta->start_rate, il3945_rates[rs_sta->start_rate].plcp);
9347ac9a364SKalle Valo 	rcu_read_unlock();
9357ac9a364SKalle Valo }
9367ac9a364SKalle Valo 
9377ac9a364SKalle Valo int
il3945_rate_control_register(void)9387ac9a364SKalle Valo il3945_rate_control_register(void)
9397ac9a364SKalle Valo {
9407ac9a364SKalle Valo 	return ieee80211_rate_control_register(&rs_ops);
9417ac9a364SKalle Valo }
9427ac9a364SKalle Valo 
9437ac9a364SKalle Valo void
il3945_rate_control_unregister(void)9447ac9a364SKalle Valo il3945_rate_control_unregister(void)
9457ac9a364SKalle Valo {
9467ac9a364SKalle Valo 	ieee80211_rate_control_unregister(&rs_ops);
9477ac9a364SKalle Valo }
948