⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iwl-3945-rs.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** * * 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 + -