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