#include <linux/workqueue.h>
-#include <net/mac80211.h>
-#include <linux/wireless.h>
+#define IWL 4965
#include "../net/mac80211/ieee80211_rate.h"
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 int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
struct iwl_rate *tx_mcs,
- struct iwl_link_quality_cmd *tbl,
- struct sta_info *sta);
+ struct iwl_link_quality_cmd *tbl);
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{}
+#endif
static s32 expected_tpt_A[IWL_RATE_COUNT] = {
0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
};
u8 high = IWL_RATE_INVALID;
u8 low = IWL_RATE_INVALID;
- /* 802.11A or ht walks to the next literal adjascent rate in
+ /* 802.11A or ht walks to the next literal adjacent rate in
* the rate table */
if (is_a_band(rate_type) || !is_legacy(rate_type)) {
int i;
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,
- struct sta_info *sta)
+ u8 ht_possible, struct iwl_rate *mcs_rate)
{
- u8 is_green = lq_data->is_green;
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)
if (is_legacy(tbl->lq_type)) {
if (lq_data->phymode == (u8) MODE_IEEE80211A)
rate_mask = (u16)(rate_mask &
- (sta->supp_rates << IWL_FIRST_OFDM_RATE));
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
else
- rate_mask = (u16)(rate_mask & sta->supp_rates);
+ rate_mask = (u16)(rate_mask & lq_data->supp_rates);
}
/* if we did switched from HT to legacy check current rate */
u16 fc = le16_to_cpu(hdr->frame_control);
s32 tpt = 0;
- IWL_DEBUG_RATE("get frame ack response, update rate scale window\n");
+ 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;
if (is_legacy(tbl->lq_type)) {
if (lq_data->phymode == (u8) MODE_IEEE80211A)
rate_scale_index_msk = (u16) (rate_mask &
- (sta->supp_rates << IWL_FIRST_OFDM_RATE));
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
else
rate_scale_index_msk = (u16) (rate_mask &
- sta->supp_rates);
+ lq_data->supp_rates);
} else
rate_scale_index_msk = rate_mask;
index = IWL_INVALID_VALUE;
update_lq = 1;
- /* get the lowest availabe rate */
+ /* get the lowest available rate */
for (i = 0; i <= IWL_RATE_COUNT; i++) {
if ((1 << i) & rate_scale_index_msk)
index = i;
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, sta);
+ rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
}
goto out;
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, sta);
+ 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);
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), sta);
+ &lq_data->lq);
rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
}
tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
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_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), sta);
+ 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)
+static void rs_get_rate(void *priv_rate, struct net_device *dev,
+ struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+ struct rate_selection *sel)
{
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;
- IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
-
- memset(extra, 0, sizeof(*extra));
-
- 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 rs_get_lowest_rate(local);
- }
+ IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
+ sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
if (sta)
sta_info_put(sta);
- return rs_get_lowest_rate(local);
+ return;
}
lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
}
done:
+ if ((i < 0) || (i > IWL_RATE_COUNT)) {
+ sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
+ return;
+ }
sta_info_put(sta);
- if ((i < 0) || (i > IWL_RATE_COUNT))
- return rs_get_lowest_rate(local);
- return &priv->ieee_rates[i];
+ sel->rate = &priv->ieee_rates[i];
}
static void *rs_alloc_sta(void *priv, gfp_t gfp)
if (crl == NULL)
return NULL;
-
- memset(crl, 0, sizeof(struct iwl_rate_scale_priv));
crl->lq.sta_id = 0xff;
+
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
struct iwl_rate_scale_priv *crl = priv_sta;
- memset(crl, 0, sizeof(struct iwl_rate_scale_priv));
-
- crl->lq.sta_id = 0xff;
crl->flush_timer = 0;
+ crl->supp_rates = sta->supp_rates;
sta->txrate = 3;
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
crl->active_mimo_rate);
#endif /*CONFIG_IWLWIFI_HT*/
+#ifdef CONFIG_MAC80211_DEBUGFS
+ crl->drv = priv;
+#endif
if (priv->assoc_station_added)
priv->lq_mngr.lq_ready = 1;
rs_initialize_lq(priv, sta);
}
-static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
struct iwl_rate *tx_mcs,
- struct iwl_link_quality_cmd *lq_cmd,
- struct sta_info *sta)
+ struct iwl_link_quality_cmd *lq_cmd)
{
int index = 0;
- int rc = 0;
int rate_idx;
+ int repeat_rate = 0;
u8 ant_toggle_count = 0;
u8 use_ht_possible = 1;
- u8 repeat_cur_rate = 0;
struct iwl_rate new_rate;
struct iwl_scale_tbl_info tbl_type = { 0 };
+ rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+
rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
&tbl_type, &rate_idx);
if (is_legacy(tbl_type.lq_type)) {
ant_toggle_count = 1;
- repeat_cur_rate = IWL_NUMBER_TRY;
+ repeat_rate = IWL_NUMBER_TRY;
} else
- repeat_cur_rate = IWL_HT_NUMBER_TRY;
+ repeat_rate = IWL_HT_NUMBER_TRY;
lq_cmd->general_params.mimo_delimiter =
is_mimo(tbl_type.lq_type) ? 1 : 0;
lq_cmd->general_params.single_stream_ant_msk = 2;
index++;
- repeat_cur_rate--;
+ repeat_rate--;
while (index < LINK_QUAL_MAX_RETRY_NUM) {
- while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
if (is_legacy(tbl_type.lq_type)) {
if (ant_toggle_count <
NUM_TRY_BEFORE_ANTENNA_TOGGLE)
ant_toggle_count = 1;
}
}
+
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
lq_cmd->rs_table[index].rate_n_flags =
cpu_to_le32(new_rate.rate_n_flags);
- repeat_cur_rate--;
+ repeat_rate--;
index++;
}
lq_cmd->general_params.mimo_delimiter = index;
rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
- use_ht_possible, &new_rate, sta);
+ use_ht_possible, &new_rate);
if (is_legacy(tbl_type.lq_type)) {
if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
rs_toggle_antenna(&new_rate, &tbl_type);
ant_toggle_count = 1;
}
- repeat_cur_rate = IWL_NUMBER_TRY;
+ repeat_rate = IWL_NUMBER_TRY;
} else
- repeat_cur_rate = IWL_HT_NUMBER_TRY;
+ repeat_rate = IWL_HT_NUMBER_TRY;
use_ht_possible = 0;
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
lq_cmd->rs_table[index].rate_n_flags =
cpu_to_le32(new_rate.rate_n_flags);
- /* lq_cmd->rs_table[index].rate_n_flags = 0x800d; */
index++;
- repeat_cur_rate--;
+ repeat_rate--;
}
- /* lq_cmd->rs_table[0].rate_n_flags = 0x800d; */
-
lq_cmd->general_params.dual_stream_ant_msk = 3;
lq_cmd->agg_params.agg_dis_start_th = 3;
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
- return rc;
}
static void *rs_alloc(struct ieee80211_local *local)
}
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{
+ u32 base_rate;
+
+ if (rs_priv->phymode == (u8) MODE_IEEE80211A)
+ base_rate = 0x800D;
+ else
+ base_rate = 0x820A;
+
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ if (index < 12)
+ mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+ else
+ mcs->rate_n_flags = base_rate;
+ IWL_DEBUG_RATE("Fixed rate ON\n");
+ return;
+ }
+
+ IWL_DEBUG_RATE("Fixed rate OFF\n");
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ char buf[64];
+ int buf_size;
+ u32 parsed_rate;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x", &parsed_rate) == 1)
+ rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+ else
+ rs_priv->dbg_fixed.rate_n_flags = 0;
+
+ rs_priv->active_rate = 0x0FFF;
+ rs_priv->active_siso_rate = 0x1FD0;
+ rs_priv->active_mimo_rate = 0x1FD0;
+
+ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
+ rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
+ rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+ }
+
+ return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i = 0;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+
+ desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+ desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+ rs_priv->total_failed, rs_priv->total_success,
+ rs_priv->active_rate);
+ desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+ rs_priv->dbg_fixed.rate_n_flags);
+ desc += sprintf(buff+desc, "general:"
+ "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+ rs_priv->lq.general_params.flags,
+ rs_priv->lq.general_params.mimo_delimiter,
+ rs_priv->lq.general_params.single_stream_ant_msk,
+ rs_priv->lq.general_params.dual_stream_ant_msk);
+
+ desc += sprintf(buff+desc, "agg:"
+ "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+ le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
+ rs_priv->lq.agg_params.agg_dis_start_th,
+ rs_priv->lq.agg_params.agg_frame_cnt_limit);
+
+ desc += sprintf(buff+desc,
+ "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+ rs_priv->lq.general_params.start_rate_index[0],
+ rs_priv->lq.general_params.start_rate_index[1],
+ rs_priv->lq.general_params.start_rate_index[2],
+ rs_priv->lq.general_params.start_rate_index[3]);
+
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
+ i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+ .write = rs_sta_dbgfs_scale_table_write,
+ .read = rs_sta_dbgfs_scale_table_read,
+ .open = open_file_generic,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i, j;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ for (i = 0; i < LQ_SIZE; i++) {
+ desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+ "rate=0x%X\n",
+ rs_priv->active_tbl == i?"*":"x",
+ rs_priv->lq_info[i].lq_type,
+ rs_priv->lq_info[i].is_SGI,
+ rs_priv->lq_info[i].is_fat,
+ rs_priv->lq_info[i].is_dup,
+ rs_priv->lq_info[i].current_rate.rate_n_flags);
+ for (j = 0; j < IWL_RATE_COUNT; j++) {
+ desc += sprintf(buff+desc,
+ "counter=%d success=%d %%=%d\n",
+ rs_priv->lq_info[i].win[j].counter,
+ rs_priv->lq_info[i].win[j].success_counter,
+ rs_priv->lq_info[i].win[j].success_ratio);
+ }
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+ .read = rs_sta_dbgfs_stats_table_read,
+ .open = open_file_generic,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ rs_priv->rs_sta_dbgfs_scale_table_file =
+ debugfs_create_file("rate_scale_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_scale_table_ops);
+ rs_priv->rs_sta_dbgfs_stats_table_file =
+ debugfs_create_file("rate_stats_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_stats_table_ops);
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
+ debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
static struct rate_control_ops rs_ops = {
.module = NULL,
.name = RS_NAME,
.free = rs_free,
.alloc_sta = rs_alloc_sta,
.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = rs_add_debugfs,
+ .remove_sta_debugfs = rs_remove_debugfs,
+#endif
};
int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
max_time, good * 100 / samples, good, samples);
else
count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
- count += sprintf(&buf[count], "\nrate scale type %d anntena %d "
+ count += sprintf(&buf[count], "\nrate scale type %d antenna %d "
"active_search %d rate index %d\n", lq_type, antenna,
rs_priv->search_better_tbl, sta->last_txrate);