📄 iwl-4965-rs.c
字号:
tbl->is_fat = 0; tbl->is_SGI = 0; } rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); /* mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { if (lq_data->phymode == (u8) MODE_IEEE80211A) rate_mask = (u16)(rate_mask & (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); else rate_mask = (u16)(rate_mask & lq_data->supp_rates); } /* if we did switched from HT to legacy check current rate */ if ((switch_to_legacy) && (rate_mask & (1 << scale_index))) { rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); return 0; } high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); low = high_low & 0xff; if (low != IWL_RATE_INVALID) rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); else rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); return 0;}static void rs_tx_status(void *priv_rate, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *tx_resp){ int status; u8 retries; int rs_index, index = 0; struct iwl_rate_scale_priv *lq; struct iwl_link_quality_cmd *table; 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_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; struct iwl_rate tx_mcs; struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; u16 fc = le16_to_cpu(hdr->frame_control); s32 tpt = 0; IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return; retries = tx_resp->retry_count; if (retries > 15) retries = 15; sta = sta_info_get(local, hdr->addr1); if (!sta || !sta->rate_ctrl_priv) { if (sta) sta_info_put(sta); return; } lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; if (!priv->lq_mngr.lq_ready) return; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) return; table = &lq->lq; active_index = lq->active_tbl; lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); if (!lq->antenna) lq->antenna = lq->valid_antenna; lq->antenna = lq->valid_antenna; curr_tbl = &(lq->lq_info[active_index]); search_tbl = &(lq->lq_info[(1 - active_index)]); window = (struct iwl_rate_scale_data *) &(curr_tbl->win[0]); search_win = (struct iwl_rate_scale_data *) &(search_tbl->win[0]); tx_mcs.rate_n_flags = tx_resp->control.tx_rate; rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, &tbl_type, &rs_index); if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", rs_index, tx_mcs.rate_n_flags); sta_info_put(sta); return; } if (retries && (tx_mcs.rate_n_flags != le32_to_cpu(table->rs_table[0].rate_n_flags))) { IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", tx_mcs.rate_n_flags, le32_to_cpu(table->rs_table[0].rate_n_flags)); sta_info_put(sta); return; } while (retries) { tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, &tbl_type, &rs_index); if ((tbl_type.lq_type == search_tbl->lq_type) && (tbl_type.antenna_type == search_tbl->antenna_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; rs_collect_tx_data(search_win, rs_index, tpt, 0); } else if ((tbl_type.lq_type == curr_tbl->lq_type) && (tbl_type.antenna_type == curr_tbl->antenna_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; rs_collect_tx_data(window, rs_index, tpt, 0); } if (lq->stay_in_tbl) lq->total_failed++; --retries; index++; } if (!tx_resp->retry_count) tx_mcs.rate_n_flags = tx_resp->control.tx_rate; else tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, &tbl_type, &rs_index); if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) status = 1; else status = 0; if ((tbl_type.lq_type == search_tbl->lq_type) && (tbl_type.antenna_type == search_tbl->antenna_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { if (search_tbl->expected_tpt) tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; rs_collect_tx_data(search_win, rs_index, tpt, status); } else if ((tbl_type.lq_type == curr_tbl->lq_type) && (tbl_type.antenna_type == curr_tbl->antenna_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { if (curr_tbl->expected_tpt) tpt = curr_tbl->expected_tpt[rs_index]; else tpt = 0; rs_collect_tx_data(window, rs_index, tpt, status); } if (lq->stay_in_tbl) { if (status) lq->total_success++; else lq->total_failed++; } rs_rate_scale_perform(priv, dev, hdr, sta); sta_info_put(sta); return;}static u8 rs_is_ant_connected(u8 valid_antenna, enum iwl_antenna_type antenna_type){ if (antenna_type == ANT_AUX) return ((valid_antenna & 0x2) ? 1:0); else if (antenna_type == ANT_MAIN) return ((valid_antenna & 0x1) ? 1:0); else if (antenna_type == ANT_BOTH) { if ((valid_antenna & 0x3) == 0x3) return 1; else return 0; } return 1;}static u8 rs_is_other_ant_connected(u8 valid_antenna, enum iwl_antenna_type antenna_type){ if (antenna_type == ANT_AUX) return (rs_is_ant_connected(valid_antenna, ANT_MAIN)); else return (rs_is_ant_connected(valid_antenna, ANT_AUX)); return 0;}static void rs_set_stay_in_table(u8 is_legacy, struct iwl_rate_scale_priv *lq_data){ IWL_DEBUG_HT("we are staying in the same table\n"); lq_data->stay_in_tbl = 1; if (is_legacy) { lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT; } else { lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; } lq_data->table_count = 0; lq_data->total_failed = 0; lq_data->total_success = 0;}static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl){ if (is_legacy(tbl->lq_type)) { if (!is_a_band(tbl->lq_type)) tbl->expected_tpt = expected_tpt_G; else tbl->expected_tpt = expected_tpt_A; } else if (is_siso(tbl->lq_type)) { if (tbl->is_fat && !lq_data->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso40MHzSGI; else tbl->expected_tpt = expected_tpt_siso40MHz; else if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso20MHzSGI; else tbl->expected_tpt = expected_tpt_siso20MHz; } else if (is_mimo(tbl->lq_type)) { if (tbl->is_fat && !lq_data->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo40MHzSGI; else tbl->expected_tpt = expected_tpt_mimo40MHz; else if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo20MHzSGI; else tbl->expected_tpt = expected_tpt_mimo20MHz; } else tbl->expected_tpt = expected_tpt_G;}#ifdef CONFIG_IWLWIFI_HTstatic s32 rs_get_best_rate(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl, u16 rate_mask, s8 index, s8 rate){ struct iwl_scale_tbl_info *active_tbl = &(lq_data->lq_info[lq_data->active_tbl]); s32 new_rate, high, low, start_hi; s32 active_sr = active_tbl->win[index].success_ratio; s32 *tpt_tbl = tbl->expected_tpt; s32 active_tpt = active_tbl->expected_tpt[index]; u16 high_low; new_rate = high = low = start_hi = IWL_RATE_INVALID; for (; ;) { high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && ((active_sr > IWL_RATE_DECREASE_TH) && (active_sr <= IWL_RATE_HIGH_TH) && (tpt_tbl[rate] <= active_tpt))) || ((active_sr >= IWL_RATE_SCALE_SWITCH) && (tpt_tbl[rate] > active_tpt))) { if (start_hi != IWL_RATE_INVALID) { new_rate = start_hi; break; } new_rate = rate; if (low != IWL_RATE_INVALID) rate = low; else break; } else { if (new_rate != IWL_RATE_INVALID) break; else if (high != IWL_RATE_INVALID) { start_hi = high; rate = high; } else { new_rate = rate; break; } } } return new_rate;}#endif /* CONFIG_IWLWIFI_HT */static inline u8 rs_is_both_ant_supp(u8 valid_antenna){ return (rs_is_ant_connected(valid_antenna, ANT_BOTH));}static int rs_switch_to_mimo(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl, int index){ int rc = -1;#ifdef CONFIG_IWLWIFI_HT u16 rate_mask; s32 rate; s8 is_green = lq_data->is_green; if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) return -1; IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); tbl->lq_type = LQ_MIMO; rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) return -1; if (!rs_is_both_ant_supp(lq_data->antenna)) return -1; rc = 0; tbl->is_dup = lq_data->is_dup; tbl->action = 0; if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) tbl->is_fat = 1; else tbl->is_fat = 0; if (tbl->is_fat) { if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; rs_get_expected_tpt_table(lq_data, tbl); rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) return -1; rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate.rate_n_flags, is_green);#endif /*CONFIG_IWLWIFI_HT */ return rc;}static int rs_switch_to_siso(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl, int index){ int rc = -1;#ifdef CONFIG_IWLWIFI_HT u16 rate_mask; u8 is_green = lq_data->is_green; s32 rate; IWL_DEBUG_HT("LQ: try to switch to SISO\n"); if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) return -1; rc = 0; tbl->is_dup = lq_data->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) tbl->is_fat = 1; else tbl->is_fat = 0; if (tbl->is_fat) { if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; if (is_green) tbl->is_SGI = 0; rs_get_expected_tpt_table(lq_data, tbl); rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { IWL_DEBUG_HT("can not switch with index %d rate mask %x\n", rate, rate_mask); return -1; } rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate.rate_n_flags, is_green);#endif /*CONFIG_IWLWIFI_HT */ return rc;}static int rs_move_legacy_other(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, int index){ int rc = 0; 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)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; for (; ;) { switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA: IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); search_tbl->lq_type = LQ_NONE; lq_data->action_counter++; if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; if (!rs_is_other_ant_connected(lq_data->antenna, tbl->antenna_type)) break; memcpy(search_tbl, tbl, sz); rs_toggle_antenna(&(search_tbl->current_rate), search_tbl); rs_get_expected_tpt_table(lq_data, search_tbl); lq_data->search_better_tbl = 1; goto out; case IWL_LEGACY_SWITCH_SISO: IWL_DEBUG_HT("LQ: Legacy 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; rc = rs_switch_to_siso(priv, lq_data, search_tbl, index); if (!rc) { lq_data->search_better_tbl = 1; lq_data->action_counter = 0; } if (!rc) goto out; break; case IWL_LEGACY_SWITCH_MIMO: IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_MIMO; search_tbl->is_SGI = 0; 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; lq_data->action_counter = 0; } if (!rc) goto out; break; } tbl->action++; if (tbl->action > IWL_LEGACY_SWITCH_MIMO) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; if (tbl->action == start_action) break; } return 0; out: tbl->action++; if (tbl->action > IWL_LEGACY_SWITCH_MIMO) tbl->action = IWL_LEGACY_SWITCH_ANTENNA; return 0;}static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_rate_scale_priv *lq_data, int index){ int rc = -1; u8 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)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); 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_SISO_SWITCH_ANTENNA: IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); search_tbl->lq_type = LQ_NONE; if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; if (!rs_is_other_ant_connected(lq_data->antenna, tbl->antenna_type)) break; memcpy(search_tbl, tbl, sz); search_tbl->action = IWL_SISO_SWITCH_MIMO; rs_toggle_antenna(&(search_tbl->current_rate), search_tbl); lq_data->search_better_tbl = 1; goto out; case IWL_SISO_SWITCH_MIMO: IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n"); memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_MIMO; search_tbl->is_SGI = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -