📄 iwl-3945-rs.c
字号:
/****************************************************************************** * * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * James P. Ketrenos <ipw2100-admin@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/#include <linux/kernel.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/wireless.h>#include <net/mac80211.h>#include <net/ieee80211.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <linux/workqueue.h>#define IWL 3945#include "../net/mac80211/ieee80211_rate.h"#include "iwlwifi.h"#define RS_NAME "iwl-3945-rs"struct iwl_rate_scale_data { u64 data; s32 success_counter; s32 success_ratio; s32 counter; s32 average_tpt; unsigned long stamp;};struct iwl_rate_scale_priv { spinlock_t lock; s32 *expected_tpt; unsigned long last_partial_flush; unsigned long last_flush; u32 flush_time; u32 last_tx_packets; u32 tx_packets; u8 tgg; u8 flush_pending; u8 start_rate; u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl_rate_scale_data win[IWL_RATE_COUNT];};static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202};static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125};static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186};static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0};struct iwl_tpt_entry { s8 min_rssi; u8 index;};static struct iwl_tpt_entry iwl_tpt_table_a[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, {-72, IWL_RATE_36M_INDEX}, {-80, IWL_RATE_24M_INDEX}, {-84, IWL_RATE_18M_INDEX}, {-85, IWL_RATE_12M_INDEX}, {-87, IWL_RATE_9M_INDEX}, {-89, IWL_RATE_6M_INDEX}};static struct iwl_tpt_entry iwl_tpt_table_b[] = { {-86, IWL_RATE_11M_INDEX}, {-88, IWL_RATE_5M_INDEX}, {-90, IWL_RATE_2M_INDEX}, {-92, IWL_RATE_1M_INDEX}};static struct iwl_tpt_entry iwl_tpt_table_g[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, {-68, IWL_RATE_36M_INDEX}, {-80, IWL_RATE_24M_INDEX}, {-84, IWL_RATE_18M_INDEX}, {-85, IWL_RATE_12M_INDEX}, {-86, IWL_RATE_11M_INDEX}, {-88, IWL_RATE_5M_INDEX}, {-90, IWL_RATE_2M_INDEX}, {-92, IWL_RATE_1M_INDEX}};#define IWL_RATE_MAX_WINDOW 62#define IWL_RATE_FLUSH (3*HZ/10)#define IWL_RATE_WIN_FLUSH (HZ/2)#define IWL_RATE_HIGH_TH 11520#define IWL_RATE_MIN_FAILURE_TH 8#define IWL_RATE_MIN_SUCCESS_TH 8#define IWL_RATE_DECREASE_TH 1920static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode){ u32 index = 0; u32 table_size = 0; struct iwl_tpt_entry *tpt_table = NULL; if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) rssi = IWL_MIN_RSSI_VAL; switch (mode) { case MODE_IEEE80211G: tpt_table = iwl_tpt_table_g; table_size = ARRAY_SIZE(iwl_tpt_table_g); break; case MODE_IEEE80211A: tpt_table = iwl_tpt_table_a; table_size = ARRAY_SIZE(iwl_tpt_table_a); break; default: case MODE_IEEE80211B: tpt_table = iwl_tpt_table_b; table_size = ARRAY_SIZE(iwl_tpt_table_b); break; } while ((index < table_size) && (rssi < tpt_table[index].min_rssi)) index++; index = min(index, (table_size - 1)); return tpt_table[index].index;}static void iwl_clear_window(struct iwl_rate_scale_data *window){ window->data = 0; window->success_counter = 0; window->success_ratio = IWL_INVALID_VALUE; window->counter = 0; window->average_tpt = IWL_INVALID_VALUE; window->stamp = 0;}/** * iwl_rate_scale_flush_windows - flush out the rate scale windows * * Returns the number of windows that have gathered data but were * not flushed. If there were any that were not flushed, then * reschedule the rate flushing routine. */static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv){ int unflushed = 0; int i; unsigned long flags; /* * For each rate, if we have collected data on that rate * and it has been more than IWL_RATE_WIN_FLUSH * since we flushed, clear out the gathered statistics */ for (i = 0; i < IWL_RATE_COUNT; i++) { if (!rs_priv->win[i].counter) continue; spin_lock_irqsave(&rs_priv->lock, flags); if (time_after(jiffies, rs_priv->win[i].stamp + IWL_RATE_WIN_FLUSH)) { IWL_DEBUG_RATE("flushing %d samples of rate " "index %d\n", rs_priv->win[i].counter, i); iwl_clear_window(&rs_priv->win[i]); } else unflushed++; spin_unlock_irqrestore(&rs_priv->lock, flags); } return unflushed;}#define IWL_RATE_FLUSH_MAX 5000 /* msec */#define IWL_RATE_FLUSH_MIN 50 /* msec */static void iwl_bg_rate_scale_flush(unsigned long data){ struct iwl_rate_scale_priv *rs_priv = (void *)data; int unflushed = 0; unsigned long flags; u32 packet_count, duration, pps; IWL_DEBUG_RATE("enter\n"); unflushed = iwl_rate_scale_flush_windows(rs_priv); spin_lock_irqsave(&rs_priv->lock, flags); rs_priv->flush_pending = 0; /* Number of packets Rx'd since last time this timer ran */ packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1; rs_priv->last_tx_packets = rs_priv->tx_packets + 1; if (unflushed) { duration = jiffies_to_msecs(jiffies - rs_priv->last_partial_flush);/* duration = jiffies_to_msecs(rs_priv->flush_time); */ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", packet_count, duration); /* Determine packets per second */ if (duration) pps = (packet_count * 1000) / duration; else pps = 0; if (pps) { duration = IWL_RATE_FLUSH_MAX / pps; if (duration < IWL_RATE_FLUSH_MIN) duration = IWL_RATE_FLUSH_MIN; } else duration = IWL_RATE_FLUSH_MAX; rs_priv->flush_time = msecs_to_jiffies(duration); IWL_DEBUG_RATE("new flush period: %d msec ave %d\n", duration, packet_count); mod_timer(&rs_priv->rate_scale_flush, jiffies + rs_priv->flush_time); rs_priv->last_partial_flush = jiffies; } /* If there weren't any unflushed entries, we don't schedule the timer * to run again */ rs_priv->last_flush = jiffies; spin_unlock_irqrestore(&rs_priv->lock, flags); IWL_DEBUG_RATE("leave\n");}/** * iwl_collect_tx_data - Update the success/failure sliding window * * We keep a sliding window of the last 64 packets transmitted * at this rate. window->data contains the bitmask of successful * packets. */static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, struct iwl_rate_scale_data *window, int success, int retries){ unsigned long flags; if (!retries) { IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); return; } while (retries--) { spin_lock_irqsave(&rs_priv->lock, flags); /* If we have filled up the window then subtract one from the * success counter if the high-bit is counting toward * success */ if (window->counter == IWL_RATE_MAX_WINDOW) { if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1))) window->success_counter--; } else window->counter++; /* Slide the window to the left one bit */ window->data = (window->data << 1); /* If this packet was a success then set the low bit high */ if (success) { window->success_counter++; window->data |= 1; } /* window->counter can't be 0 -- it is either >0 or * IWL_RATE_MAX_WINDOW */ window->success_ratio = 12800 * window->success_counter / window->counter; /* Tag this window as having been updated */ window->stamp = jiffies; spin_unlock_irqrestore(&rs_priv->lock, flags); }}static void rs_rate_init(void *priv_rate, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta){ int i; IWL_DEBUG_RATE("enter\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { if (sta->supp_rates & (1 << i)) { sta->txrate = i; break; } } sta->last_txrate = sta->txrate; /* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */ if (local->hw.conf.phymode == MODE_IEEE80211A) sta->last_txrate += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n");}static void *rs_alloc(struct ieee80211_local *local){ return local->hw.priv;}/* rate scale requires free function to be implmented */static void rs_free(void *priv){ return;}static void rs_clear(void *priv){ return;}static void *rs_alloc_sta(void *priv, gfp_t gfp){ struct iwl_rate_scale_priv *rs_priv; int i; IWL_DEBUG_RATE("enter\n"); rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); if (!rs_priv) { IWL_DEBUG_RATE("leave: ENOMEM\n"); return NULL; } spin_lock_init(&rs_priv->lock); rs_priv->start_rate = IWL_RATE_INVALID; /* default to just 802.11b */ rs_priv->expected_tpt = iwl_expected_tpt_b; rs_priv->last_partial_flush = jiffies; rs_priv->last_flush = jiffies; rs_priv->flush_time = IWL_RATE_FLUSH; rs_priv->last_tx_packets = 0; rs_priv->ibss_sta_added = 0; init_timer(&rs_priv->rate_scale_flush); rs_priv->rate_scale_flush.data = (unsigned long)rs_priv; rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush; for (i = 0; i < IWL_RATE_COUNT; i++) iwl_clear_window(&rs_priv->win[i]); IWL_DEBUG_RATE("leave\n"); return rs_priv;}static void rs_free_sta(void *priv, void *priv_sta){ struct iwl_rate_scale_priv *rs_priv = priv_sta; IWL_DEBUG_RATE("enter\n"); del_timer_sync(&rs_priv->rate_scale_flush); kfree(rs_priv); IWL_DEBUG_RATE("leave\n");}/* * get ieee prev rate from rate scale table. * for A and B mode we need to overright prev * value */static int rs_adjust_next_rate(struct iwl_priv *priv, int rate){ int next_rate = iwl_get_prev_ieee_rate(rate); switch (priv->phymode) { case MODE_IEEE80211A: if (rate == IWL_RATE_12M_INDEX) next_rate = IWL_RATE_9M_INDEX; else if (rate == IWL_RATE_6M_INDEX) next_rate = IWL_RATE_6M_INDEX; break; case MODE_IEEE80211B: if (rate == IWL_RATE_11M_INDEX_TABLE) next_rate = IWL_RATE_5M_INDEX_TABLE; break; default: break; } return next_rate;}/** * rs_tx_status - Update rate control values based on Tx results * * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by * the hardware for each rate. */static void rs_tx_status(void *priv_rate, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *tx_resp){ u8 retries, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct sta_info *sta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl_rate_scale_priv *rs_priv; IWL_DEBUG_RATE("enter\n"); retries = tx_resp->retry_count; first_index = tx_resp->control.tx_rate; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n", tx_resp->control.tx_rate, first_index); return; } sta = sta_info_get(local, hdr->addr1); if (!sta || !sta->rate_ctrl_priv) { if (sta) sta_info_put(sta); IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); return; } rs_priv = (void *)sta->rate_ctrl_priv; rs_priv->tx_packets++; scale_rate_index = first_index; last_index = first_index; /* * Update the window for each rate. We determine which rates * were Tx'd based on the total number of retries vs. the number * of retries configured for each rate -- currently set to the * priv value 'retry_rate' vs. rate specific * * On exit from this while loop last_index indicates the rate * at which the frame was finally transmitted (or failed if no * ACK) */ while (retries > 0) { if (retries < priv->retry_rate) { current_count = retries; last_index = scale_rate_index;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -