iwlwifi: Tune radio to prevent unexpected behavior

We have seen the throughput dropped due to external noisy environment
and the radio is out of tune.  There are lot of plcp errors indicating
this condition. Eventually the station can get de-authenticated by the
Access Point.  By resetting and tuning the radio, the plcp errors are
reduced or eliminated and the throughput starts to rise.

To prevent unexpected behavior such as drop in throughput or deauthentication,
- The change provides the driver feature to monitor and tune the radio base on
the statistics notification from the uCode.
- It also allows the setting of the plcp error rate threshold via
the plcp_delta under debugfs interface.

Signed-off-by: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Trieu 'Andrew' Nguyen 2010-01-22 14:22:46 -08:00 committed by John W. Linville
parent d4d59e88cb
commit 3e4fb5faef
10 changed files with 132 additions and 0 deletions

View file

@ -2195,6 +2195,47 @@ static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
return count;
}
static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
int pos = 0;
char buf[12];
const size_t bufsz = sizeof(buf);
ssize_t ret;
pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
priv->cfg->plcp_delta_threshold);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
int plcp;
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, "%d", &plcp) != 1)
return -EINVAL;
if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
priv->cfg->plcp_delta_threshold =
IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
else
priv->cfg->plcp_delta_threshold = plcp;
return count;
}
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@ -2214,6 +2255,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
DEBUGFS_WRITE_FILE_OPS(internal_scan);
DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
/*
* Create the debugfs files and directories
@ -2268,6 +2310,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR);
DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR);
DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR);
DEBUGFS_ADD_FILE(plcp_delta, debug, S_IWUSR | S_IRUSR);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
@ -2330,6 +2373,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_plcp_delta);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats);