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

📄 iwl-4965-rs.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			search_tbl->is_fat = 0;			search_tbl->antenna_type = ANT_BOTH;			rc = rs_switch_to_mimo(priv, lq_data, search_tbl,					       index);			if (!rc)				lq_data->search_better_tbl = 1;			if (!rc)				goto out;			break;		case IWL_SISO_SWITCH_GI:			IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");			memcpy(search_tbl, tbl, sz);			search_tbl->action = 0;			if (search_tbl->is_SGI)				search_tbl->is_SGI = 0;			else if (!is_green)				search_tbl->is_SGI = 1;			else				break;			lq_data->search_better_tbl = 1;			if ((tbl->lq_type == LQ_SISO) &&			    (tbl->is_SGI)) {				s32 tpt = lq_data->last_tpt / 100;				if (((!tbl->is_fat) &&				     (tpt >= expected_tpt_siso20MHz[index])) ||				    ((tbl->is_fat) &&				     (tpt >= expected_tpt_siso40MHz[index])))					lq_data->search_better_tbl = 0;			}			rs_get_expected_tpt_table(lq_data, search_tbl);			rs_mcs_from_tbl(&search_tbl->current_rate,					     search_tbl, index, is_green);			goto out;		}		tbl->action++;		if (tbl->action > IWL_SISO_SWITCH_GI)			tbl->action = IWL_SISO_SWITCH_ANTENNA;		if (tbl->action == start_action)			break;	}	return 0; out:	tbl->action++;	if (tbl->action > IWL_SISO_SWITCH_GI)		tbl->action = IWL_SISO_SWITCH_ANTENNA;	return 0;}static int rs_move_mimo_to_other(struct iwl_priv *priv,				 struct iwl_rate_scale_priv *lq_data,				 int index){	int rc = -1;	s8 is_green = lq_data->is_green;	struct iwl_scale_tbl_info *tbl =	    &(lq_data->lq_info[lq_data->active_tbl]);	struct iwl_scale_tbl_info *search_tbl =	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);	u32 sz = (sizeof(struct iwl_scale_tbl_info) -		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));	u8 start_action = tbl->action;	for (;;) {		lq_data->action_counter++;		switch (tbl->action) {		case IWL_MIMO_SWITCH_ANTENNA_A:		case IWL_MIMO_SWITCH_ANTENNA_B:			IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");			memcpy(search_tbl, tbl, sz);			search_tbl->lq_type = LQ_SISO;			search_tbl->is_SGI = 0;			search_tbl->is_fat = 0;			if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)				search_tbl->antenna_type = ANT_MAIN;			else				search_tbl->antenna_type = ANT_AUX;			rc = rs_switch_to_siso(priv, lq_data, search_tbl,					       index);			if (!rc) {				lq_data->search_better_tbl = 1;				goto out;			}			break;		case IWL_MIMO_SWITCH_GI:			IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");			memcpy(search_tbl, tbl, sz);			search_tbl->lq_type = LQ_MIMO;			search_tbl->antenna_type = ANT_BOTH;			search_tbl->action = 0;			if (search_tbl->is_SGI)				search_tbl->is_SGI = 0;			else				search_tbl->is_SGI = 1;			lq_data->search_better_tbl = 1;			if ((tbl->lq_type == LQ_MIMO) &&			    (tbl->is_SGI)) {				s32 tpt = lq_data->last_tpt / 100;				if (((!tbl->is_fat) &&				     (tpt >= expected_tpt_mimo20MHz[index])) ||				    ((tbl->is_fat) &&				     (tpt >= expected_tpt_mimo40MHz[index])))					lq_data->search_better_tbl = 0;			}			rs_get_expected_tpt_table(lq_data, search_tbl);			rs_mcs_from_tbl(&search_tbl->current_rate,					     search_tbl, index, is_green);			goto out;		}		tbl->action++;		if (tbl->action > IWL_MIMO_SWITCH_GI)			tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;		if (tbl->action == start_action)			break;	}	return 0; out:	tbl->action++;	if (tbl->action > IWL_MIMO_SWITCH_GI)		tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;	return 0;}static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data){	struct iwl_scale_tbl_info *tbl;	int i;	int active_tbl;	int flush_interval_passed = 0;	active_tbl = lq_data->active_tbl;	tbl = &(lq_data->lq_info[active_tbl]);	if (lq_data->stay_in_tbl) {		if (lq_data->flush_timer)			flush_interval_passed =			    time_after(jiffies,				       (unsigned long)(lq_data->flush_timer +					IWL_RATE_SCALE_FLUSH_INTVL));		flush_interval_passed = 0;		if ((lq_data->total_failed > lq_data->max_failure_limit) ||		    (lq_data->total_success > lq_data->max_success_limit) ||		    ((!lq_data->search_better_tbl) && (lq_data->flush_timer)		     && (flush_interval_passed))) {			IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",				     lq_data->total_failed,				     lq_data->total_success,				     flush_interval_passed);			lq_data->stay_in_tbl = 0;			lq_data->total_failed = 0;			lq_data->total_success = 0;			lq_data->flush_timer = 0;		} else if (lq_data->table_count > 0) {			lq_data->table_count++;			if (lq_data->table_count >=			    lq_data->table_count_limit) {				lq_data->table_count = 0;				IWL_DEBUG_HT("LQ: stay in table clear win\n");				for (i = 0; i < IWL_RATE_COUNT; i++)					rs_rate_scale_clear_window(						&(tbl->win[i]));			}		}		if (!lq_data->stay_in_tbl) {			for (i = 0; i < IWL_RATE_COUNT; i++)				rs_rate_scale_clear_window(&(tbl->win[i]));		}	}}static void rs_rate_scale_perform(struct iwl_priv *priv,				  struct net_device *dev,				  struct ieee80211_hdr *hdr,				  struct sta_info *sta){	int low = IWL_RATE_INVALID;	int high = IWL_RATE_INVALID;	int index;	int i;	struct iwl_rate_scale_data *window = NULL;	int current_tpt = IWL_INVALID_VALUE;	int low_tpt = IWL_INVALID_VALUE;	int high_tpt = IWL_INVALID_VALUE;	u32 fail_count;	s8 scale_action = 0;	u16 fc, rate_mask;	u8 update_lq = 0;	struct iwl_rate_scale_priv *lq_data;	struct iwl_scale_tbl_info *tbl, *tbl1;	u16 rate_scale_index_msk = 0;	struct iwl_rate mcs_rate;	u8 is_green = 0;	u8 active_tbl = 0;	u8 done_search = 0;	u16 high_low;	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");	fc = le16_to_cpu(hdr->frame_control);	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {		/* Send management frames and broadcast/multicast data using		 * lowest rate. */		/* TODO: this could probably be improved.. */		return;	}	if (!sta || !sta->rate_ctrl_priv)		return;	if (!priv->lq_mngr.lq_ready) {		IWL_DEBUG_RATE("still rate scaling not ready\n");		return;	}	lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;	if (!lq_data->search_better_tbl)		active_tbl = lq_data->active_tbl;	else		active_tbl = 1 - lq_data->active_tbl;	tbl = &(lq_data->lq_info[active_tbl]);	is_green = lq_data->is_green;	index = sta->last_txrate;	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,		       tbl->lq_type);	rs_get_supported_rates(lq_data, hdr, tbl->lq_type,				&rate_mask);	IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);	/* mask with station rate restriction */	if (is_legacy(tbl->lq_type)) {		if (lq_data->phymode == (u8) MODE_IEEE80211A)			rate_scale_index_msk = (u16) (rate_mask &				(lq_data->supp_rates << IWL_FIRST_OFDM_RATE));		else			rate_scale_index_msk = (u16) (rate_mask &						      lq_data->supp_rates);	} else		rate_scale_index_msk = rate_mask;	if (!rate_scale_index_msk)		rate_scale_index_msk = rate_mask;	if (index < 0 || !((1 << index) & rate_scale_index_msk)) {		index = IWL_INVALID_VALUE;		update_lq = 1;		/* get the lowest availabe rate */		for (i = 0; i <= IWL_RATE_COUNT; i++) {			if ((1 << i) & rate_scale_index_msk)				index = i;		}		if (index == IWL_INVALID_VALUE) {			IWL_WARNING("Can not find a suitable rate\n");			return;		}	}	if (!tbl->expected_tpt)		rs_get_expected_tpt_table(lq_data, tbl);	window = &(tbl->win[index]);	fail_count = window->counter - window->success_counter;	if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))	    || (tbl->expected_tpt == NULL)) {		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "			       "for index %d\n",			       window->success_counter, window->counter, index);		window->average_tpt = IWL_INVALID_VALUE;		rs_stay_in_table(lq_data);		if (update_lq) {			rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);			rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);		}		goto out;	} else		window->average_tpt = ((window->success_ratio *					tbl->expected_tpt[index] + 64) / 128);	if (lq_data->search_better_tbl) {		int success_limit = IWL_RATE_SCALE_SWITCH;		if ((window->success_ratio > success_limit) ||		    (window->average_tpt > lq_data->last_tpt)) {			if (!is_legacy(tbl->lq_type)) {				IWL_DEBUG_HT("LQ: we are switching to HT"					     " rate suc %d current tpt %d"					     " old tpt %d\n",					     window->success_ratio,					     window->average_tpt,					     lq_data->last_tpt);				lq_data->enable_counter = 1;			}			lq_data->active_tbl = active_tbl;			current_tpt = window->average_tpt;		} else {			tbl->lq_type = LQ_NONE;			active_tbl = lq_data->active_tbl;			tbl = &(lq_data->lq_info[active_tbl]);			index = iwl_rate_index_from_plcp(				tbl->current_rate.rate_n_flags);			update_lq = 1;			current_tpt = lq_data->last_tpt;			IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");		}		lq_data->search_better_tbl = 0;		done_search = 1;		goto lq_update;	}	high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,					tbl->lq_type);	low = high_low & 0xff;	high = (high_low >> 8) & 0xff;	current_tpt = window->average_tpt;	if (low != IWL_RATE_INVALID)		low_tpt = tbl->win[low].average_tpt;	if (high != IWL_RATE_INVALID)		high_tpt = tbl->win[high].average_tpt;	scale_action = 1;	if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||	    (current_tpt == 0)) {		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");		scale_action = -1;	} else if ((low_tpt == IWL_INVALID_VALUE) &&		   (high_tpt == IWL_INVALID_VALUE))		scale_action = 1;	else if ((low_tpt != IWL_INVALID_VALUE) &&		 (high_tpt != IWL_INVALID_VALUE) &&		 (low_tpt < current_tpt) &&		 (high_tpt < current_tpt))		scale_action = 0;	else {		if (high_tpt != IWL_INVALID_VALUE) {			if (high_tpt > current_tpt)				scale_action = 1;			else {				IWL_DEBUG_RATE				    ("decrease rate because of high tpt\n");				scale_action = -1;			}		} else if (low_tpt != IWL_INVALID_VALUE) {			if (low_tpt > current_tpt) {				IWL_DEBUG_RATE				    ("decrease rate because of low tpt\n");				scale_action = -1;			} else				scale_action = 1;		}	}	if (scale_action == -1) {		if ((low != IWL_RATE_INVALID) &&		    ((window->success_ratio > IWL_RATE_HIGH_TH) ||		     (current_tpt > (100 * tbl->expected_tpt[low]))))			scale_action = 0;	} else if ((scale_action == 1) &&		   (window->success_ratio < IWL_RATE_INCREASE_TH))		scale_action = 0;	switch (scale_action) {	case -1:		if (low != IWL_RATE_INVALID) {			update_lq = 1;			index = low;		}		break;	case 1:		if (high != IWL_RATE_INVALID) {			update_lq = 1;			index = high;		}		break;	case 0:	default:		break;	}	IWL_DEBUG_HT("choose rate scale index %d action %d low %d "		    "high %d type %d\n",		     index, scale_action, low, high, tbl->lq_type); lq_update:	if (update_lq) {		rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);		rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);		rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);	}	rs_stay_in_table(lq_data);	if (!update_lq && !done_search && !lq_data->stay_in_tbl) {		lq_data->last_tpt = current_tpt;		if (is_legacy(tbl->lq_type))			rs_move_legacy_other(priv, lq_data, index);		else if (is_siso(tbl->lq_type))			rs_move_siso_to_other(priv, lq_data, index);		else			rs_move_mimo_to_other(priv, lq_data, index);		if (lq_data->search_better_tbl) {			tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);			for (i = 0; i < IWL_RATE_COUNT; i++)				rs_rate_scale_clear_window(&(tbl->win[i]));			index = iwl_rate_index_from_plcp(					tbl->current_rate.rate_n_flags);			IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",				     tbl->current_rate.rate_n_flags, index);			rs_fill_link_cmd(lq_data, &tbl->current_rate,					 &lq_data->lq);			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);		}		tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);		if (is_legacy(tbl1->lq_type) &&#ifdef CONFIG_IWLWIFI_HT		    !priv->current_assoc_ht.is_ht &&#endif		    (lq_data->action_counter >= 1)) {			lq_data->action_counter = 0;			IWL_DEBUG_HT("LQ: STAY in legacy table\n");			rs_set_stay_in_table(1, lq_data);		}		if (lq_data->enable_counter &&		    (lq_data->action_counter >= IWL_ACTION_LIMIT)) {#ifdef CONFIG_IWLWIFI_HT_AGG			if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&			    (priv->lq_mngr.agg_ctrl.auto_agg)) {				priv->lq_mngr.agg_ctrl.tid_retry =				    TID_ALL_SPECIFIED;				schedule_work(&priv->agg_work);			}#endif /*CONFIG_IWLWIFI_HT_AGG */			lq_data->action_counter = 0;			rs_set_stay_in_table(0, lq_data);		}	} else {		if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))			lq_data->flush_timer = jiffies;	}out:	rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);	i = index;	sta->last_txrate = i;	/* sta->txrate is an index to A mode rates which start	 * at IWL_FIRST_OFDM_RATE	 */	if (lq_data->phymode == (u8) MODE_IEEE80211A)		sta->txrate = i - IWL_FIRST_OFDM_RATE;	else		sta->txrate = i;	return;}static void rs_initialize_lq(struct iwl_priv *priv,			     struct sta_info *sta){	int i;	struct iwl_rate_scale_priv *lq;	struct iwl_scale_tbl_info *tbl;	u8 active_tbl = 0;	int rate_idx;	u8 use_green = rs_use_green(priv);	struct iwl_rate mcs_rate;	if (!sta || !sta->rate_ctrl_priv)		goto out;	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;	i = sta->last_txrate;	if ((lq->lq.sta_id == 0xff) &&	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))		goto out;	if (!lq->search_better_tbl)		active_tbl = lq->active_tbl;	else		active_tbl = 1 - lq->active_tbl;	tbl = &(lq->lq_info[active_tbl]);	if ((i < 0) || (i >= IWL_RATE_COUNT))		i = 0;	mcs_rate.rate_n_flags = iwl_rates[i].plcp ;	mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;	mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)		mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;	tbl->antenna_type = ANT_AUX;	rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);	if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))	    rs_toggle_antenna(&mcs_rate, tbl);	rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);	tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;	rs_get_expected_tpt_table(lq, tbl);	rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);	rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); out:	return;}static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local						 *local){	struct ieee80211_hw_mode *mode = local->oper_hw_mode;	int i;	for (i = 0; i < mode->num_rates; i++) {		struct ieee80211_rate *rate = &mode->rates[i];		if (rate->flags & IEEE80211_RATE_SUPPORTED)			return rate;	}	return &mode->rates[0];}static struct ieee80211_rate *rs_get_rate(void *priv_rate,					       struct net_device *dev,					       struct sk_buff *skb,					       struct rate_control_extra					       *extra){	int i;	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;	struct sta_info *sta;	u16 fc;	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;	struct iwl_rate_scale_priv *lq;

⌨️ 快捷键说明

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