aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTrieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>2010-01-22 17:22:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-25 16:36:21 -0500
commit3e4fb5faefb57824f2e42305b3d5907845af978c (patch)
treea9cb64dff2fea16e290ab29eb4260c973d52e88f /drivers
parentd4d59e88cb746165c6fe33eacb6f582d525c6ef1 (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c44
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c54
10 files changed, 132 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index d5c6edbbc95a..85162e2c35d9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -175,6 +175,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
175 .use_rts_for_ht = true, /* use rts/cts protection */ 175 .use_rts_for_ht = true, /* use rts/cts protection */
176 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 176 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
177 .support_ct_kill_exit = true, 177 .support_ct_kill_exit = true,
178 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
178}; 179};
179 180
180struct iwl_cfg iwl1000_bg_cfg = { 181struct iwl_cfg iwl1000_bg_cfg = {
@@ -201,6 +202,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
201 .led_compensation = 51, 202 .led_compensation = 51,
202 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 203 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
203 .support_ct_kill_exit = true, 204 .support_ct_kill_exit = true,
205 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
204}; 206};
205 207
206MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); 208MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 6472910b72d4..764479f74c8b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2830,6 +2830,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
2830 .ht_greenfield_support = false, 2830 .ht_greenfield_support = false,
2831 .led_compensation = 64, 2831 .led_compensation = 64,
2832 .broken_powersave = true, 2832 .broken_powersave = true,
2833 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2833}; 2834};
2834 2835
2835static struct iwl_cfg iwl3945_abg_cfg = { 2836static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2847,6 +2848,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
2847 .ht_greenfield_support = false, 2848 .ht_greenfield_support = false,
2848 .led_compensation = 64, 2849 .led_compensation = 64,
2849 .broken_powersave = true, 2850 .broken_powersave = true,
2851 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2850}; 2852};
2851 2853
2852struct pci_device_id iwl3945_hw_card_ids[] = { 2854struct pci_device_id iwl3945_hw_card_ids[] = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8159a0fcf5a8..c36fef99b4b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2239,6 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
2239 .broken_powersave = true, 2239 .broken_powersave = true,
2240 .led_compensation = 61, 2240 .led_compensation = 61,
2241 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, 2241 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
2242 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2242}; 2243};
2243 2244
2244/* Module firmware */ 2245/* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index aab6cf23c2bd..cbbc0e4f2c76 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1603,6 +1603,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
1603 .led_compensation = 51, 1603 .led_compensation = 51,
1604 .use_rts_for_ht = true, /* use rts/cts protection */ 1604 .use_rts_for_ht = true, /* use rts/cts protection */
1605 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1605 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1606 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1606}; 1607};
1607 1608
1608struct iwl_cfg iwl5100_bgn_cfg = { 1609struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1627,6 +1628,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
1627 .led_compensation = 51, 1628 .led_compensation = 51,
1628 .use_rts_for_ht = true, /* use rts/cts protection */ 1629 .use_rts_for_ht = true, /* use rts/cts protection */
1629 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1630 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1631 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1630}; 1632};
1631 1633
1632struct iwl_cfg iwl5100_abg_cfg = { 1634struct iwl_cfg iwl5100_abg_cfg = {
@@ -1649,6 +1651,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
1649 .use_bsm = false, 1651 .use_bsm = false,
1650 .led_compensation = 51, 1652 .led_compensation = 51,
1651 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1653 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1654 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1652}; 1655};
1653 1656
1654struct iwl_cfg iwl5100_agn_cfg = { 1657struct iwl_cfg iwl5100_agn_cfg = {
@@ -1673,6 +1676,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
1673 .led_compensation = 51, 1676 .led_compensation = 51,
1674 .use_rts_for_ht = true, /* use rts/cts protection */ 1677 .use_rts_for_ht = true, /* use rts/cts protection */
1675 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1678 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1679 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1676}; 1680};
1677 1681
1678struct iwl_cfg iwl5350_agn_cfg = { 1682struct iwl_cfg iwl5350_agn_cfg = {
@@ -1697,6 +1701,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
1697 .led_compensation = 51, 1701 .led_compensation = 51,
1698 .use_rts_for_ht = true, /* use rts/cts protection */ 1702 .use_rts_for_ht = true, /* use rts/cts protection */
1699 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1703 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1704 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1700}; 1705};
1701 1706
1702struct iwl_cfg iwl5150_agn_cfg = { 1707struct iwl_cfg iwl5150_agn_cfg = {
@@ -1721,6 +1726,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
1721 .led_compensation = 51, 1726 .led_compensation = 51,
1722 .use_rts_for_ht = true, /* use rts/cts protection */ 1727 .use_rts_for_ht = true, /* use rts/cts protection */
1723 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1728 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1729 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1724}; 1730};
1725 1731
1726struct iwl_cfg iwl5150_abg_cfg = { 1732struct iwl_cfg iwl5150_abg_cfg = {
@@ -1743,6 +1749,7 @@ struct iwl_cfg iwl5150_abg_cfg = {
1743 .use_bsm = false, 1749 .use_bsm = false,
1744 .led_compensation = 51, 1750 .led_compensation = 51,
1745 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1751 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1752 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1746}; 1753};
1747 1754
1748MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); 1755MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 4dab7f12e725..b191c634ad92 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -308,6 +308,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
308 .supports_idle = true, 308 .supports_idle = true,
309 .adv_thermal_throttle = true, 309 .adv_thermal_throttle = true,
310 .support_ct_kill_exit = true, 310 .support_ct_kill_exit = true,
311 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
311}; 312};
312 313
313struct iwl_cfg iwl6000i_2abg_cfg = { 314struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -337,6 +338,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
337 .supports_idle = true, 338 .supports_idle = true,
338 .adv_thermal_throttle = true, 339 .adv_thermal_throttle = true,
339 .support_ct_kill_exit = true, 340 .support_ct_kill_exit = true,
341 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
340}; 342};
341 343
342struct iwl_cfg iwl6000i_2bg_cfg = { 344struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -366,6 +368,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
366 .supports_idle = true, 368 .supports_idle = true,
367 .adv_thermal_throttle = true, 369 .adv_thermal_throttle = true,
368 .support_ct_kill_exit = true, 370 .support_ct_kill_exit = true,
371 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
369}; 372};
370 373
371struct iwl_cfg iwl6050_2agn_cfg = { 374struct iwl_cfg iwl6050_2agn_cfg = {
@@ -396,6 +399,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
396 .supports_idle = true, 399 .supports_idle = true,
397 .adv_thermal_throttle = true, 400 .adv_thermal_throttle = true,
398 .support_ct_kill_exit = true, 401 .support_ct_kill_exit = true,
402 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
399}; 403};
400 404
401struct iwl_cfg iwl6050_2abg_cfg = { 405struct iwl_cfg iwl6050_2abg_cfg = {
@@ -425,6 +429,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
425 .supports_idle = true, 429 .supports_idle = true,
426 .adv_thermal_throttle = true, 430 .adv_thermal_throttle = true,
427 .support_ct_kill_exit = true, 431 .support_ct_kill_exit = true,
432 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
428}; 433};
429 434
430struct iwl_cfg iwl6000_3agn_cfg = { 435struct iwl_cfg iwl6000_3agn_cfg = {
@@ -455,6 +460,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
455 .supports_idle = true, 460 .supports_idle = true,
456 .adv_thermal_throttle = true, 461 .adv_thermal_throttle = true,
457 .support_ct_kill_exit = true, 462 .support_ct_kill_exit = true,
463 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
458}; 464};
459 465
460MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); 466MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 6de83d1e1eb8..661918347d48 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -232,6 +232,8 @@ struct iwl_mod_params {
232 * @adv_thermal_throttle: support advance thermal throttle 232 * @adv_thermal_throttle: support advance thermal throttle
233 * @support_ct_kill_exit: support ct kill exit condition 233 * @support_ct_kill_exit: support ct kill exit condition
234 * @support_wimax_coexist: support wimax/wifi co-exist 234 * @support_wimax_coexist: support wimax/wifi co-exist
235 * @plcp_delta_threshold: plcp error rate threshold used to trigger
236 * radio tuning when there is a high receiving plcp error rate
235 * 237 *
236 * We enable the driver to be backward compatible wrt API version. The 238 * We enable the driver to be backward compatible wrt API version. The
237 * driver specifies which APIs it supports (with @ucode_api_max being the 239 * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -288,6 +290,7 @@ struct iwl_cfg {
288 bool adv_thermal_throttle; 290 bool adv_thermal_throttle;
289 bool support_ct_kill_exit; 291 bool support_ct_kill_exit;
290 const bool support_wimax_coexist; 292 const bool support_wimax_coexist;
293 u8 plcp_delta_threshold;
291}; 294};
292 295
293/*************************** 296/***************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index d81b4f39bb1d..aff1dc0756fc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -114,6 +114,7 @@ struct iwl_debugfs {
114 struct dentry *file_fh_reg; 114 struct dentry *file_fh_reg;
115 struct dentry *file_missed_beacon; 115 struct dentry *file_missed_beacon;
116 struct dentry *file_internal_scan; 116 struct dentry *file_internal_scan;
117 struct dentry *file_plcp_delta;
117 } dbgfs_debug_files; 118 } dbgfs_debug_files;
118 u32 sram_offset; 119 u32 sram_offset;
119 u32 sram_len; 120 u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 4944fdb31ba8..3f9c03998491 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2195,6 +2195,47 @@ static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
2195 return count; 2195 return count;
2196} 2196}
2197 2197
2198static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
2199 char __user *user_buf,
2200 size_t count, loff_t *ppos) {
2201
2202 struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
2203 int pos = 0;
2204 char buf[12];
2205 const size_t bufsz = sizeof(buf);
2206 ssize_t ret;
2207
2208 pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
2209 priv->cfg->plcp_delta_threshold);
2210
2211 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
2212 return ret;
2213}
2214
2215static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
2216 const char __user *user_buf,
2217 size_t count, loff_t *ppos) {
2218
2219 struct iwl_priv *priv = file->private_data;
2220 char buf[8];
2221 int buf_size;
2222 int plcp;
2223
2224 memset(buf, 0, sizeof(buf));
2225 buf_size = min(count, sizeof(buf) - 1);
2226 if (copy_from_user(buf, user_buf, buf_size))
2227 return -EFAULT;
2228 if (sscanf(buf, "%d", &plcp) != 1)
2229 return -EINVAL;
2230 if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
2231 (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
2232 priv->cfg->plcp_delta_threshold =
2233 IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
2234 else
2235 priv->cfg->plcp_delta_threshold = plcp;
2236 return count;
2237}
2238
2198DEBUGFS_READ_FILE_OPS(rx_statistics); 2239DEBUGFS_READ_FILE_OPS(rx_statistics);
2199DEBUGFS_READ_FILE_OPS(tx_statistics); 2240DEBUGFS_READ_FILE_OPS(tx_statistics);
2200DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); 2241DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -2214,6 +2255,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
2214DEBUGFS_READ_FILE_OPS(fh_reg); 2255DEBUGFS_READ_FILE_OPS(fh_reg);
2215DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); 2256DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
2216DEBUGFS_WRITE_FILE_OPS(internal_scan); 2257DEBUGFS_WRITE_FILE_OPS(internal_scan);
2258DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
2217 2259
2218/* 2260/*
2219 * Create the debugfs files and directories 2261 * Create the debugfs files and directories
@@ -2268,6 +2310,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
2268 DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); 2310 DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR);
2269 DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); 2311 DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR);
2270 DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR); 2312 DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR);
2313 DEBUGFS_ADD_FILE(plcp_delta, debug, S_IWUSR | S_IRUSR);
2271 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { 2314 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
2272 DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); 2315 DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
2273 DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); 2316 DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
@@ -2330,6 +2373,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
2330 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); 2373 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg);
2331 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); 2374 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon);
2332 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan); 2375 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan);
2376 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_plcp_delta);
2333 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { 2377 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
2334 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. 2378 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
2335 file_ucode_rx_stats); 2379 file_ucode_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 86d38ae2ec7e..a1f3ecb69ed0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1026,6 +1026,15 @@ struct iwl_event_log {
1026#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) 1026#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
1027#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) 1027#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
1028 1028
1029/*
1030 * This is the threshold value of plcp error rate per 100mSecs. It is
1031 * used to set and check for the validity of plcp_delta.
1032 */
1033#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
1034#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
1035#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100)
1036#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
1037
1029struct iwl_priv { 1038struct iwl_priv {
1030 1039
1031 /* ieee device used by generic ieee processing code */ 1040 /* ieee device used by generic ieee processing code */
@@ -1055,6 +1064,9 @@ struct iwl_priv {
1055 u32 ucode_beacon_time; 1064 u32 ucode_beacon_time;
1056 int missed_beacon_threshold; 1065 int missed_beacon_threshold;
1057 1066
1067 /* storing the jiffies when the plcp error rate is received */
1068 unsigned long plcp_jiffies;
1069
1058 /* we allocate array of iwl4965_channel_info for NIC's valid channels. 1070 /* we allocate array of iwl4965_channel_info for NIC's valid channels.
1059 * Access via channel # using indirect index array */ 1071 * Access via channel # using indirect index array */
1060 struct iwl_channel_info *channel_info; /* channel info array */ 1072 struct iwl_channel_info *channel_info; /* channel info array */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index dc06c7bb0f5c..ea309f42a78a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -602,11 +602,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
602 602
603#define REG_RECALIB_PERIOD (60) 603#define REG_RECALIB_PERIOD (60)
604 604
605#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
605void iwl_rx_statistics(struct iwl_priv *priv, 606void iwl_rx_statistics(struct iwl_priv *priv,
606 struct iwl_rx_mem_buffer *rxb) 607 struct iwl_rx_mem_buffer *rxb)
607{ 608{
608 int change; 609 int change;
609 struct iwl_rx_packet *pkt = rxb_addr(rxb); 610 struct iwl_rx_packet *pkt = rxb_addr(rxb);
611 int combined_plcp_delta;
612 unsigned int plcp_msec;
613 unsigned long plcp_received_jiffies;
610 614
611 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", 615 IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
612 (int)sizeof(priv->statistics), 616 (int)sizeof(priv->statistics),
@@ -621,6 +625,56 @@ void iwl_rx_statistics(struct iwl_priv *priv,
621#ifdef CONFIG_IWLWIFI_DEBUG 625#ifdef CONFIG_IWLWIFI_DEBUG
622 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); 626 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
623#endif 627#endif
628 /*
629 * check for plcp_err and trigger radio reset if it exceeds
630 * the plcp error threshold plcp_delta.
631 */
632 plcp_received_jiffies = jiffies;
633 plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
634 (long) priv->plcp_jiffies);
635 priv->plcp_jiffies = plcp_received_jiffies;
636 /*
637 * check to make sure plcp_msec is not 0 to prevent division
638 * by zero.
639 */
640 if (plcp_msec) {
641 combined_plcp_delta =
642 (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
643 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
644 (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
645 le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
646
647 if ((combined_plcp_delta > 0) &&
648 ((combined_plcp_delta * 100) / plcp_msec) >
649 priv->cfg->plcp_delta_threshold) {
650 /*
651 * if plcp_err exceed the threshold, the following
652 * data is printed in csv format:
653 * Text: plcp_err exceeded %d,
654 * Received ofdm.plcp_err,
655 * Current ofdm.plcp_err,
656 * Received ofdm_ht.plcp_err,
657 * Current ofdm_ht.plcp_err,
658 * combined_plcp_delta,
659 * plcp_msec
660 */
661 IWL_DEBUG_RADIO(priv, PLCP_MSG,
662 priv->cfg->plcp_delta_threshold,
663 le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
664 le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
665 le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
666 le32_to_cpu(
667 priv->statistics.rx.ofdm_ht.plcp_err),
668 combined_plcp_delta, plcp_msec);
669
670 /*
671 * Reset the RF radio due to the high plcp
672 * error rate
673 */
674 iwl_force_rf_reset(priv);
675 }
676 }
677
624 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); 678 memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
625 679
626 set_bit(STATUS_STATISTICS, &priv->status); 680 set_bit(STATUS_STATISTICS, &priv->status);