📄 iwl-4965-rs.c
字号:
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 + -