Jesse Keating 2f82dda
Back-port of the following upstream commit...
Jesse Keating 2f82dda
Jesse Keating 2f82dda
commit 3e4fb5faefb57824f2e42305b3d5907845af978c
Jesse Keating 2f82dda
Author: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>
Jesse Keating 2f82dda
Date:   Fri Jan 22 14:22:46 2010 -0800
Jesse Keating 2f82dda
Jesse Keating 2f82dda
    iwlwifi: Tune radio to prevent unexpected behavior
Jesse Keating 2f82dda
    
Jesse Keating 2f82dda
    We have seen the throughput dropped due to external noisy environment
Jesse Keating 2f82dda
    and the radio is out of tune.  There are lot of plcp errors indicating
Jesse Keating 2f82dda
    this condition. Eventually the station can get de-authenticated by the
Jesse Keating 2f82dda
    Access Point.  By resetting and tuning the radio, the plcp errors are
Jesse Keating 2f82dda
    reduced or eliminated and the throughput starts to rise.
Jesse Keating 2f82dda
    
Jesse Keating 2f82dda
    To prevent unexpected behavior such as drop in throughput or deauthentication,
Jesse Keating 2f82dda
    - The change provides the driver feature to monitor and tune the radio base on
Jesse Keating 2f82dda
    the statistics notification from the uCode.
Jesse Keating 2f82dda
    - It also allows the setting of the plcp error rate threshold via
Jesse Keating 2f82dda
    the plcp_delta under debugfs interface.
Jesse Keating 2f82dda
    
Jesse Keating 2f82dda
    Signed-off-by: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>
Jesse Keating 2f82dda
    Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Jesse Keating 2f82dda
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
Jesse Keating 2f82dda
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c.orig	2009-12-02 22:51:21.000000000 -0500
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c	2010-03-22 14:23:01.000000000 -0400
Jesse Keating 2f82dda
@@ -162,5 +162,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = false,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c.orig	2010-03-22 10:23:59.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c	2010-03-22 14:20:28.000000000 -0400
Jesse Keating 2f82dda
@@ -2896,6 +2896,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
Jesse Keating 2f82dda
 	.use_isr_legacy = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = false,
Jesse Keating 2f82dda
 	.broken_powersave = true,
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 static struct iwl_cfg iwl3945_abg_cfg = {
Jesse Keating 2f82dda
@@ -2911,6 +2912,7 @@ static struct iwl_cfg iwl3945_abg_cfg = 
Jesse Keating 2f82dda
 	.use_isr_legacy = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = false,
Jesse Keating 2f82dda
 	.broken_powersave = true,
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct pci_device_id iwl3945_hw_card_ids[] = {
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c.orig	2010-03-22 11:22:14.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c	2010-03-22 14:24:14.000000000 -0400
Jesse Keating 2f82dda
@@ -2363,6 +2363,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
Jesse Keating 2f82dda
 	.use_isr_legacy = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = false,
Jesse Keating 2f82dda
 	.broken_powersave = true,
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /* Module firmware */
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c.orig	2010-03-22 11:22:14.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c	2010-03-22 14:27:05.000000000 -0400
Jesse Keating 2f82dda
@@ -1672,6 +1672,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl5100_bg_cfg = {
Jesse Keating 2f82dda
@@ -1689,6 +1690,7 @@ struct iwl_cfg iwl5100_bg_cfg = {
Jesse Keating 2f82dda
 	.valid_rx_ant = ANT_AB,
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl5100_abg_cfg = {
Jesse Keating 2f82dda
@@ -1706,6 +1708,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
Jesse Keating 2f82dda
 	.valid_tx_ant = ANT_B,
Jesse Keating 2f82dda
 	.valid_rx_ant = ANT_AB,
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl5100_agn_cfg = {
Jesse Keating 2f82dda
@@ -1724,6 +1727,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl5350_agn_cfg = {
Jesse Keating 2f82dda
@@ -1742,6 +1746,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl5150_agn_cfg = {
Jesse Keating 2f82dda
@@ -1760,6 +1765,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
Jesse Keating 2f82dda
 	.need_pll_cfg = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c.orig	2009-12-02 22:51:21.000000000 -0500
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c	2010-03-22 14:28:04.000000000 -0400
Jesse Keating 2f82dda
@@ -176,6 +176,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /*
Jesse Keating 2f82dda
@@ -200,6 +201,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl6050_2agn_cfg = {
Jesse Keating 2f82dda
@@ -221,6 +223,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl6000_3agn_cfg = {
Jesse Keating 2f82dda
@@ -242,6 +245,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 struct iwl_cfg iwl6050_3agn_cfg = {
Jesse Keating 2f82dda
@@ -263,6 +267,7 @@ struct iwl_cfg iwl6050_3agn_cfg = {
Jesse Keating 2f82dda
 	.shadow_ram_support = true,
Jesse Keating 2f82dda
 	.ht_greenfield_support = true,
Jesse Keating 2f82dda
 	.use_rts_for_ht = true, /* use rts/cts protection */
Jesse Keating 2f82dda
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h.orig	2010-03-22 11:26:18.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h	2010-03-22 14:29:11.000000000 -0400
Jesse Keating 2f82dda
@@ -214,6 +214,8 @@ struct iwl_mod_params {
Jesse Keating 2f82dda
  * @max_ll_items: max number of OTP blocks
Jesse Keating 2f82dda
  * @shadow_ram_support: shadow support for OTP memory
Jesse Keating 2f82dda
  * @use_rts_for_ht: use rts/cts protection for HT traffic
Jesse Keating 2f82dda
+ * @plcp_delta_threshold: plcp error rate threshold used to trigger
Jesse Keating 2f82dda
+ *	radio tuning when there is a high receiving plcp error rate
Jesse Keating 2f82dda
  *
Jesse Keating 2f82dda
  * We enable the driver to be backward compatible wrt API version. The
Jesse Keating 2f82dda
  * driver specifies which APIs it supports (with @ucode_api_max being the
Jesse Keating 2f82dda
@@ -257,6 +259,7 @@ struct iwl_cfg {
Jesse Keating 2f82dda
 	const bool ht_greenfield_support;
Jesse Keating 2f82dda
 	const bool broken_powersave;
Jesse Keating 2f82dda
 	bool use_rts_for_ht;
Jesse Keating 2f82dda
+	u8 plcp_delta_threshold;
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /***************************
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debugfs.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debugfs.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debugfs.c.orig	2010-03-22 11:33:02.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debugfs.c	2010-03-22 14:31:01.000000000 -0400
Jesse Keating 2f82dda
@@ -853,6 +853,47 @@ static ssize_t iwl_dbgfs_current_sleep_c
Jesse Keating 2f82dda
 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
Jesse Keating 2f82dda
+					char __user *user_buf,
Jesse Keating 2f82dda
+					size_t count, loff_t *ppos) {
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
Jesse Keating 2f82dda
+	int pos = 0;
Jesse Keating 2f82dda
+	char buf[12];
Jesse Keating 2f82dda
+	const size_t bufsz = sizeof(buf);
Jesse Keating 2f82dda
+	ssize_t ret;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
Jesse Keating 2f82dda
+			priv->cfg->plcp_delta_threshold);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
Jesse Keating 2f82dda
+	return ret;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
Jesse Keating 2f82dda
+					const char __user *user_buf,
Jesse Keating 2f82dda
+					size_t count, loff_t *ppos) {
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	struct iwl_priv *priv = file->private_data;
Jesse Keating 2f82dda
+	char buf[8];
Jesse Keating 2f82dda
+	int buf_size;
Jesse Keating 2f82dda
+	int plcp;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	memset(buf, 0, sizeof(buf));
Jesse Keating 2f82dda
+	buf_size = min(count, sizeof(buf) -  1);
Jesse Keating 2f82dda
+	if (copy_from_user(buf, user_buf, buf_size))
Jesse Keating 2f82dda
+		return -EFAULT;
Jesse Keating 2f82dda
+	if (sscanf(buf, "%d", &plcp) != 1)
Jesse Keating 2f82dda
+		return -EINVAL;
Jesse Keating 2f82dda
+	if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
Jesse Keating 2f82dda
+		(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
Jesse Keating 2f82dda
+		priv->cfg->plcp_delta_threshold =
Jesse Keating 2f82dda
+			IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
Jesse Keating 2f82dda
+	else
Jesse Keating 2f82dda
+		priv->cfg->plcp_delta_threshold = plcp;
Jesse Keating 2f82dda
+	return count;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
Jesse Keating 2f82dda
 DEBUGFS_WRITE_FILE_OPS(log_event);
Jesse Keating 2f82dda
 DEBUGFS_READ_FILE_OPS(nvm);
Jesse Keating 2f82dda
@@ -1647,6 +1688,7 @@ DEBUGFS_READ_FILE_OPS(sensitivity);
Jesse Keating 2f82dda
 DEBUGFS_READ_FILE_OPS(chain_noise);
Jesse Keating 2f82dda
 DEBUGFS_READ_FILE_OPS(tx_power);
Jesse Keating 2f82dda
 DEBUGFS_WRITE_FILE_OPS(internal_scan);
Jesse Keating 2f82dda
+DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /*
Jesse Keating 2f82dda
  * Create the debugfs files and directories
Jesse Keating 2f82dda
@@ -1697,6 +1739,7 @@ int iwl_dbgfs_register(struct iwl_priv *
Jesse Keating 2f82dda
 	DEBUGFS_ADD_FILE(tx_queue, debug);
Jesse Keating 2f82dda
 	DEBUGFS_ADD_FILE(tx_power, debug);
Jesse Keating 2f82dda
 	DEBUGFS_ADD_FILE(internal_scan, debug);
Jesse Keating 2f82dda
+	DEBUGFS_ADD_FILE(plcp_delta, debug);
Jesse Keating 2f82dda
 	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
Jesse Keating 2f82dda
 		DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
Jesse Keating 2f82dda
 		DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
Jesse Keating 2f82dda
@@ -1752,6 +1795,7 @@ void iwl_dbgfs_unregister(struct iwl_pri
Jesse Keating 2f82dda
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
Jesse Keating 2f82dda
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
Jesse Keating 2f82dda
 	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan);
Jesse Keating 2f82dda
+	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_plcp_delta);
Jesse Keating 2f82dda
 	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
Jesse Keating 2f82dda
 		DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
Jesse Keating 2f82dda
 			file_ucode_rx_stats);
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debug.h.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debug.h
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debug.h.orig	2010-03-22 11:27:31.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-debug.h	2010-03-22 14:20:28.000000000 -0400
Jesse Keating 2f82dda
@@ -109,6 +109,7 @@ struct iwl_debugfs {
Jesse Keating 2f82dda
 		struct dentry *file_chain_noise;
Jesse Keating 2f82dda
 		struct dentry *file_tx_power;
Jesse Keating 2f82dda
 		struct dentry *file_internal_scan;
Jesse Keating 2f82dda
+		struct dentry *file_plcp_delta;
Jesse Keating 2f82dda
 	} dbgfs_debug_files;
Jesse Keating 2f82dda
 	u32 sram_offset;
Jesse Keating 2f82dda
 	u32 sram_len;
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h.orig	2010-03-22 14:12:32.000000000 -0400
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h	2010-03-22 14:20:28.000000000 -0400
Jesse Keating 2f82dda
@@ -963,6 +963,15 @@ struct traffic_stats {
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 #define IWL_MAX_NUM_QUEUES	20 /* FIXME: do dynamic allocation */
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+/*
Jesse Keating 2f82dda
+ * This is the threshold value of plcp error rate per 100mSecs.  It is
Jesse Keating 2f82dda
+ * used to set and check for the validity of plcp_delta.
Jesse Keating 2f82dda
+ */
Jesse Keating 2f82dda
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN	(0)
Jesse Keating 2f82dda
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF	(50)
Jesse Keating 2f82dda
+#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF	(100)
Jesse Keating 2f82dda
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX	(255)
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 struct iwl_priv {
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	/* ieee device used by generic ieee processing code */
Jesse Keating 2f82dda
@@ -991,6 +1000,9 @@ struct iwl_priv {
Jesse Keating 2f82dda
 	/* ucode beacon time */
Jesse Keating 2f82dda
 	u32 ucode_beacon_time;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+	/* storing the jiffies when the plcp error rate is received */
Jesse Keating 2f82dda
+	unsigned long plcp_jiffies;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
Jesse Keating 2f82dda
 	 *    Access via channel # using indirect index array */
Jesse Keating 2f82dda
 	struct iwl_channel_info *channel_info;	/* channel info array */
Jesse Keating 2f82dda
diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-rx.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-rx.c
Jesse Keating 2f82dda
--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-rx.c.orig	2009-12-02 22:51:21.000000000 -0500
Jesse Keating 2f82dda
+++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-rx.c	2010-03-22 15:18:59.000000000 -0400
Jesse Keating 2f82dda
@@ -550,11 +550,15 @@ static void iwl_rx_calc_noise(struct iwl
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 #define REG_RECALIB_PERIOD (60)
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
Jesse Keating 2f82dda
 void iwl_rx_statistics(struct iwl_priv *priv,
Jesse Keating 2f82dda
 			      struct iwl_rx_mem_buffer *rxb)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	int change;
Jesse Keating 2f82dda
 	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
Jesse Keating 2f82dda
+	int combined_plcp_delta;
Jesse Keating 2f82dda
+	unsigned int plcp_msec;
Jesse Keating 2f82dda
+	unsigned long plcp_received_jiffies;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
Jesse Keating 2f82dda
 		     (int)sizeof(priv->statistics),
Jesse Keating 2f82dda
@@ -566,6 +570,56 @@ void iwl_rx_statistics(struct iwl_priv *
Jesse Keating 2f82dda
 		    STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
Jesse Keating 2f82dda
 		   (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+	/*
Jesse Keating 2f82dda
+	 * check for plcp_err and trigger radio reset if it exceeds
Jesse Keating 2f82dda
+	 * the plcp error threshold plcp_delta.
Jesse Keating 2f82dda
+	 */
Jesse Keating 2f82dda
+	plcp_received_jiffies = jiffies;
Jesse Keating 2f82dda
+	plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
Jesse Keating 2f82dda
+					(long) priv->plcp_jiffies);
Jesse Keating 2f82dda
+	priv->plcp_jiffies = plcp_received_jiffies;
Jesse Keating 2f82dda
+	/*
Jesse Keating 2f82dda
+	 * check to make sure plcp_msec is not 0 to prevent division
Jesse Keating 2f82dda
+	 * by zero.
Jesse Keating 2f82dda
+	 */
Jesse Keating 2f82dda
+	if (plcp_msec) {
Jesse Keating 2f82dda
+		combined_plcp_delta =
Jesse Keating 2f82dda
+			(le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
Jesse Keating 2f82dda
+			le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
Jesse Keating 2f82dda
+			(le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
Jesse Keating 2f82dda
+			le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+		if ((combined_plcp_delta > 0) &&
Jesse Keating 2f82dda
+			((combined_plcp_delta * 100) / plcp_msec) >
Jesse Keating 2f82dda
+			priv->cfg->plcp_delta_threshold) {
Jesse Keating 2f82dda
+			/*
Jesse Keating 2f82dda
+			 * if plcp_err exceed the threshold, the following
Jesse Keating 2f82dda
+			 * data is printed in csv format:
Jesse Keating 2f82dda
+			 *    Text: plcp_err exceeded %d,
Jesse Keating 2f82dda
+			 *    Received ofdm.plcp_err,
Jesse Keating 2f82dda
+			 *    Current ofdm.plcp_err,
Jesse Keating 2f82dda
+			 *    Received ofdm_ht.plcp_err,
Jesse Keating 2f82dda
+			 *    Current ofdm_ht.plcp_err,
Jesse Keating 2f82dda
+			 *    combined_plcp_delta,
Jesse Keating 2f82dda
+			 *    plcp_msec
Jesse Keating 2f82dda
+			 */
Jesse Keating 2f82dda
+			IWL_DEBUG_RADIO(priv, PLCP_MSG,
Jesse Keating 2f82dda
+				priv->cfg->plcp_delta_threshold,
Jesse Keating 2f82dda
+				le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
Jesse Keating 2f82dda
+				le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
Jesse Keating 2f82dda
+				le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
Jesse Keating 2f82dda
+				le32_to_cpu(
Jesse Keating 2f82dda
+					priv->statistics.rx.ofdm_ht.plcp_err),
Jesse Keating 2f82dda
+				combined_plcp_delta, plcp_msec);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+			/*
Jesse Keating 2f82dda
+			 * Reset the RF radio due to the high plcp
Jesse Keating 2f82dda
+			 * error rate
Jesse Keating 2f82dda
+			 */
Jesse Keating 2f82dda
+			iwl_force_rf_reset(priv);
Jesse Keating 2f82dda
+		}
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 	memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	set_bit(STATUS_STATISTICS, &priv->status);