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

📄 iwl-4965-rs.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************** * * 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 4965#include "../net/mac80211/ieee80211_rate.h"#include "iwlwifi.h"#include "iwl-helpers.h"#define RS_NAME "iwl-4965-rs"#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1#define IWL_NUMBER_TRY      1#define IWL_HT_NUMBER_TRY   3#define IWL_RATE_MAX_WINDOW		62#define IWL_RATE_HIGH_TH		10880#define IWL_RATE_MIN_FAILURE_TH		6#define IWL_RATE_MIN_SUCCESS_TH		8#define IWL_RATE_DECREASE_TH		1920#define IWL_RATE_INCREASE_TH            8960#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)        /*2 seconds */static u8 rs_ht_to_legacy[] = {	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,	IWL_RATE_6M_INDEX,	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX};struct iwl_rate {	u32 rate_n_flags;} __attribute__ ((packed));struct iwl_rate_scale_data {	u64 data;	s32 success_counter;	s32 success_ratio;	s32 counter;	s32 average_tpt;	unsigned long stamp;};struct iwl_scale_tbl_info {	enum iwl_table_type lq_type;	enum iwl_antenna_type antenna_type;	u8 is_SGI;	u8 is_fat;	u8 is_dup;	u8 action;	s32 *expected_tpt;	struct iwl_rate current_rate;	struct iwl_rate_scale_data win[IWL_RATE_COUNT];};struct iwl_rate_scale_priv {	u8 active_tbl;	u8 enable_counter;	u8 stay_in_tbl;	u8 search_better_tbl;	s32 last_tpt;	u32 table_count_limit;	u32 max_failure_limit;	u32 max_success_limit;	u32 table_count;	u32 total_failed;	u32 total_success;	u32 flush_timer;	u8 action_counter;	u8 antenna;	u8 valid_antenna;	u8 is_green;	u8 is_dup;	u8 phymode;	u8 ibss_sta_added;	u32 supp_rates;	u16 active_rate;	u16 active_siso_rate;	u16 active_mimo_rate;	u16 active_rate_basic;	struct iwl_link_quality_cmd lq;	struct iwl_scale_tbl_info lq_info[LQ_SIZE];#ifdef CONFIG_MAC80211_DEBUGFS	struct dentry *rs_sta_dbgfs_scale_table_file;	struct dentry *rs_sta_dbgfs_stats_table_file;	struct iwl_rate dbg_fixed;	struct iwl_priv *drv;#endif};static void rs_rate_scale_perform(struct iwl_priv *priv,				   struct net_device *dev,				   struct ieee80211_hdr *hdr,				   struct sta_info *sta);static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,			     struct iwl_rate *tx_mcs,			     struct iwl_link_quality_cmd *tbl);#ifdef CONFIG_MAC80211_DEBUGFSstatic void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,				struct iwl_rate *mcs, int index);#elsestatic void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,				struct iwl_rate *mcs, int index){}#endifstatic s32 expected_tpt_A[IWL_RATE_COUNT] = {	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186};static s32 expected_tpt_G[IWL_RATE_COUNT] = {	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186};static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {	0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202};static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {	0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211};static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {	0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251};static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {	0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257};static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {	0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257};static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {	0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264};static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {	0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289};static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293};static int iwl_lq_sync_callback(struct iwl_priv *priv,				struct iwl_cmd *cmd, struct sk_buff *skb){	/*We didn't cache the SKB; let the caller free it */	return 1;}static inline u8 iwl_rate_get_rate(u32 rate_n_flags){	return (u8)(rate_n_flags & 0xFF);}static int rs_send_lq_cmd(struct iwl_priv *priv,			  struct iwl_link_quality_cmd *lq, u8 flags){#ifdef CONFIG_IWLWIFI_DEBUG	int i;#endif	int rc = -1;	struct iwl_host_cmd cmd = {		.id = REPLY_TX_LINK_QUALITY_CMD,		.len = sizeof(struct iwl_link_quality_cmd),		.meta.flags = flags,		.data = lq,	};	if ((lq->sta_id == 0xFF) &&	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))		return rc;	if (lq->sta_id == 0xFF)		lq->sta_id = IWL_AP_ID;	IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",		       lq->general_params.single_stream_ant_msk,		       lq->general_params.dual_stream_ant_msk);#ifdef CONFIG_IWLWIFI_DEBUG	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)		IWL_DEBUG_RATE("lq index %d 0x%X\n",				i, lq->rs_table[i].rate_n_flags);#endif	if (flags & CMD_ASYNC)		cmd.meta.u.callback = iwl_lq_sync_callback;	if (iwl_is_associated(priv) && priv->assoc_station_added &&	    priv->lq_mngr.lq_ready)		rc = iwl_send_cmd(priv, &cmd);	return rc;}static int rs_rate_scale_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;	return 0;}static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,			      int scale_index, s32 tpt, u32 status){	int rc = 0;	struct iwl_rate_scale_data *window = NULL;	u64 mask;	u8 win_size = IWL_RATE_MAX_WINDOW;	s32 fail_count;	if (scale_index < 0)		return -1;	if (scale_index >= IWL_RATE_COUNT)		return -1;	window = &(windows[scale_index]);	if (window->counter >= win_size) {		window->counter = win_size - 1;		mask = 1;		mask = (mask << (win_size - 1));		if ((window->data & mask)) {			window->data &= ~mask;			window->success_counter = window->success_counter - 1;		}	}	window->counter = window->counter + 1;	mask = window->data;	window->data = (mask << 1);	if (status != 0) {		window->success_counter = window->success_counter + 1;		window->data |= 0x1;	}	if (window->counter > 0)		window->success_ratio = 128 * (100 * window->success_counter)					/ window->counter;	else		window->success_ratio = IWL_INVALID_VALUE;	fail_count = window->counter - window->success_counter;	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))		window->average_tpt = (window->success_ratio * tpt + 64) / 128;	else		window->average_tpt = IWL_INVALID_VALUE;	window->stamp = jiffies;	return rc;}int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,			   struct iwl_scale_tbl_info *tbl,			   int index, u8 use_green){	int rc = 0;	if (is_legacy(tbl->lq_type)) {		mcs_rate->rate_n_flags = iwl_rates[index].plcp;		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)			mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;	} else if (is_siso(tbl->lq_type)) {		if (index > IWL_LAST_OFDM_RATE)			index = IWL_LAST_OFDM_RATE;		 mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |					  RATE_MCS_HT_MSK;	} else {		if (index > IWL_LAST_OFDM_RATE)			index = IWL_LAST_OFDM_RATE;		mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |					 RATE_MCS_HT_MSK;	}	switch (tbl->antenna_type) {	case ANT_BOTH:		mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;		break;	case ANT_MAIN:		mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;		break;	case ANT_AUX:		mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;		break;	case ANT_NONE:		break;	}	if (is_legacy(tbl->lq_type))		return rc;	if (tbl->is_fat) {		if (tbl->is_dup)			mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;		else			mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;	}	if (tbl->is_SGI)		mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;	if (use_green) {		mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;		if (is_siso(tbl->lq_type))			mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;	}	return rc;}static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,				    int phymode, struct iwl_scale_tbl_info *tbl,				    int *rate_idx){	int index;	u32 ant_msk;	index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);	if (index  == IWL_RATE_INVALID) {		*rate_idx = -1;		return -1;	}	tbl->is_SGI = 0;	tbl->is_fat = 0;	tbl->is_dup = 0;	tbl->antenna_type = ANT_BOTH;	if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);		if (ant_msk == RATE_MCS_ANT_AB_MSK)			tbl->lq_type = LQ_NONE;		else {			if (phymode == MODE_IEEE80211A)				tbl->lq_type = LQ_A;			else				tbl->lq_type = LQ_G;			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)				tbl->antenna_type = ANT_MAIN;			else				tbl->antenna_type = ANT_AUX;		}		*rate_idx = index;	} else if (iwl_rate_get_rate(mcs_rate->rate_n_flags)					<= IWL_RATE_SISO_60M_PLCP) {		tbl->lq_type = LQ_SISO;		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);		if (ant_msk == RATE_MCS_ANT_AB_MSK)			tbl->lq_type = LQ_NONE;		else {			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)				tbl->antenna_type = ANT_MAIN;			else				tbl->antenna_type = ANT_AUX;		}		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)			tbl->is_SGI = 1;		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))			tbl->is_fat = 1;		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)			tbl->is_dup = 1;		*rate_idx = index;	} else {		tbl->lq_type = LQ_MIMO;		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)			tbl->is_SGI = 1;		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))			tbl->is_fat = 1;		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)			tbl->is_dup = 1;		*rate_idx = index;	}	return 0;}static inline void rs_toggle_antenna(struct iwl_rate *new_rate,				     struct iwl_scale_tbl_info *tbl){	if (tbl->antenna_type == ANT_AUX) {		tbl->antenna_type = ANT_MAIN;		new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;		new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;	} else {		tbl->antenna_type = ANT_AUX;		new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;		new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;	}}static inline s8 rs_use_green(struct iwl_priv *priv){	s8 rc = 0;#ifdef CONFIG_IWLWIFI_HT	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)		return 0;	if ((priv->current_assoc_ht.is_green_field) &&	    !(priv->current_assoc_ht.operating_mode & 0x4))		rc = 1;#endif	/*CONFIG_IWLWIFI_HT */	return rc;}/** * rs_get_supported_rates - get the available rates * * if management frame or broadcast frame only return * basic available rates. * */static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,				   struct ieee80211_hdr *hdr,				   enum iwl_table_type rate_type,				   u16 *data_rate){	if (is_legacy(rate_type))		*data_rate = lq_data->active_rate;	else {		if (is_siso(rate_type))			*data_rate = lq_data->active_siso_rate;		else			*data_rate = lq_data->active_mimo_rate;	}	if (hdr && is_multicast_ether_addr(hdr->addr1) &&	    lq_data->active_rate_basic)		*data_rate = lq_data->active_rate_basic;}static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type){	u8 high = IWL_RATE_INVALID;	u8 low = IWL_RATE_INVALID;	/* 802.11A or ht walks to the next literal adjascent rate in	 * the rate table */	if (is_a_band(rate_type) || !is_legacy(rate_type)) {		int i;		u32 mask;		/* Find the previous rate that is in the rate mask */		i = index - 1;		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {			if (rate_mask & mask) {				low = i;				break;			}		}		/* Find the next rate that is in the rate mask */		i = index + 1;		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {			if (rate_mask & mask) {				high = i;				break;			}		}		return (high << 8) | low;	}	low = index;	while (low != IWL_RATE_INVALID) {		low = iwl_rates[low].prev_rs;		if (low == IWL_RATE_INVALID)			break;		if (rate_mask & (1 << low))			break;		IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);	}	high = index;	while (high != IWL_RATE_INVALID) {		high = iwl_rates[high].next_rs;		if (high == IWL_RATE_INVALID)			break;		if (rate_mask & (1 << high))			break;		IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);	}	return (high << 8) | low;}static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,			     struct iwl_scale_tbl_info *tbl, u8 scale_index,			     u8 ht_possible, struct iwl_rate *mcs_rate){	s32 low;	u16 rate_mask;	u16 high_low;	u8 switch_to_legacy = 0;	u8 is_green = lq_data->is_green;	/* check if we need to switch from HT to legacy rates.	 * assumption is that mandatory rates (1Mbps or 6Mbps)	 * are always supported (spec demand) */	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {		switch_to_legacy = 1;		scale_index = rs_ht_to_legacy[scale_index];		if (lq_data->phymode == MODE_IEEE80211A)			tbl->lq_type = LQ_A;		else			tbl->lq_type = LQ_G;		if ((tbl->antenna_type == ANT_BOTH) ||		    (tbl->antenna_type == ANT_NONE))			tbl->antenna_type = ANT_MAIN;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -