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