summaryrefslogtreecommitdiffstats
path: root/iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch
diff options
context:
space:
mode:
authorJesse Keating <jkeating@redhat.com>2010-07-29 17:18:45 -0700
committerJesse Keating <jkeating@redhat.com>2010-07-29 17:18:45 -0700
commit2f82dda4a9bf41e64e864889bf06564bdf826e25 (patch)
tree118a7b483ae5de4dbf83d20001302f1404866ef0 /iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch
parent64ba2e5ffde5f2418eb26c700cb0ab62b04e5013 (diff)
downloaddom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.gz
dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.xz
dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.zip
initial srpm import
Diffstat (limited to 'iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch')
-rw-r--r--iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch446
1 files changed, 446 insertions, 0 deletions
diff --git a/iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch b/iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch
new file mode 100644
index 0000000..e3b4b5c
--- /dev/null
+++ b/iwlwifi_-Recover-TX-flow-stall-due-to-stuck-queue.patch
@@ -0,0 +1,446 @@
+This patch is not yet upstream...
+
+From a5e660b4e294556822913627544f661e59b39716 Mon Sep 17 00:00:00 2001
+From: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Date: Mon, 1 Mar 2010 17:23:50 -0800
+Subject: [PATCH 13/17] iwlwifi: Recover TX flow stall due to stuck queue
+
+Monitors the internal TX queues periodically. When a queue is stuck
+for some unknown conditions causing the throughput to drop and the
+transfer is stop, the driver will force firmware reload and bring the
+system back to normal operational state.
+
+The iwlwifi devices behave differently in this regard so this feature is
+made part of the ops infrastructure so we can have more control on how to
+monitor and recover from tx queue stall case per device.
+
+Signed-off-by: Trieu 'Andrew' Nguyen <trieux.t.nguyen@intel.com>
+Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
+Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
+
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c.orig 2010-03-22 15:33:38.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-1000.c 2010-03-22 15:48:54.000000000 -0400
+@@ -135,6 +135,7 @@ static struct iwl_lib_ops iwl1000_lib =
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl1000_set_ct_threshold,
+ },
++ .recover_from_tx_stall = iwl_bg_monitor_recover,
+ };
+
+ static struct iwl_ops iwl1000_ops = {
+@@ -163,5 +164,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl3945-base.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl3945-base.c
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl3945-base.c.orig 2010-03-22 15:44:04.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl3945-base.c 2010-03-22 15:48:54.000000000 -0400
+@@ -2453,6 +2453,13 @@ static void iwl3945_alive_start(struct i
+ /* After the ALIVE response, we can send commands to 3945 uCode */
+ set_bit(STATUS_ALIVE, &priv->status);
+
++ if (priv->cfg->ops->lib->recover_from_tx_stall) {
++ /* Enable timer to monitor the driver queues */
++ mod_timer(&priv->monitor_recover,
++ jiffies +
++ msecs_to_jiffies(priv->cfg->monitor_recover_period));
++ }
++
+ if (iwl_is_rfkill(priv))
+ return;
+
+@@ -3730,6 +3737,13 @@ static void iwl3945_setup_deferred_work(
+
+ iwl3945_hw_setup_deferred_work(priv);
+
++ if (priv->cfg->ops->lib->recover_from_tx_stall) {
++ init_timer(&priv->monitor_recover);
++ priv->monitor_recover.data = (unsigned long)priv;
++ priv->monitor_recover.function =
++ priv->cfg->ops->lib->recover_from_tx_stall;
++ }
++
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl3945_irq_tasklet, (unsigned long)priv);
+ }
+@@ -3742,6 +3756,8 @@ static void iwl3945_cancel_deferred_work
+ cancel_delayed_work(&priv->scan_check);
+ cancel_delayed_work(&priv->alive_start);
+ cancel_work_sync(&priv->beacon_update);
++ if (priv->cfg->ops->lib->recover_from_tx_stall)
++ del_timer_sync(&priv->monitor_recover);
+ }
+
+ static struct attribute *iwl3945_sysfs_entries[] = {
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c.orig 2010-03-22 14:20:28.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-3945.c 2010-03-22 15:48:54.000000000 -0400
+@@ -2897,6 +2897,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
+ .ht_greenfield_support = false,
+ .broken_powersave = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ static struct iwl_cfg iwl3945_abg_cfg = {
+@@ -2913,6 +2914,7 @@ static struct iwl_cfg iwl3945_abg_cfg =
+ .ht_greenfield_support = false,
+ .broken_powersave = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct pci_device_id iwl3945_hw_card_ids[] = {
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c.orig 2010-03-22 14:24:14.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-4965.c 2010-03-22 15:48:54.000000000 -0400
+@@ -2364,6 +2364,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
+ .ht_greenfield_support = false,
+ .broken_powersave = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ /* Module firmware */
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c.orig 2010-03-22 14:27:05.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-5000.c 2010-03-22 15:48:54.000000000 -0400
+@@ -1579,6 +1579,7 @@ struct iwl_lib_ops iwl5000_lib = {
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl5000_set_ct_threshold,
+ },
++ .recover_from_tx_stall = iwl_bg_monitor_recover,
+ };
+
+ static struct iwl_lib_ops iwl5150_lib = {
+@@ -1631,6 +1632,7 @@ static struct iwl_lib_ops iwl5150_lib =
+ .temperature = iwl5150_temperature,
+ .set_ct_kill = iwl5150_set_ct_threshold,
+ },
++ .recover_from_tx_stall = iwl_bg_monitor_recover,
+ };
+
+ struct iwl_ops iwl5000_ops = {
+@@ -1673,6 +1675,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl5100_bg_cfg = {
+@@ -1691,6 +1694,7 @@ struct iwl_cfg iwl5100_bg_cfg = {
+ .need_pll_cfg = true,
+ .ht_greenfield_support = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl5100_abg_cfg = {
+@@ -1709,6 +1713,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
+ .valid_rx_ant = ANT_AB,
+ .need_pll_cfg = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl5100_agn_cfg = {
+@@ -1728,6 +1733,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl5350_agn_cfg = {
+@@ -1747,6 +1753,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl5150_agn_cfg = {
+@@ -1766,6 +1773,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c.orig 2010-03-22 14:28:04.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-6000.c 2010-03-22 15:51:12.000000000 -0400
+@@ -137,6 +137,7 @@ static struct iwl_lib_ops iwl6000_lib =
+ .temperature = iwl5000_temperature,
+ .set_ct_kill = iwl6000_set_ct_threshold,
+ },
++ .recover_from_tx_stall = iwl_bg_monitor_recover,
+ };
+
+ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
+@@ -177,6 +178,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ /*
+@@ -202,6 +204,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl6050_2agn_cfg = {
+@@ -224,6 +227,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl6000_3agn_cfg = {
+@@ -246,6 +250,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ struct iwl_cfg iwl6050_3agn_cfg = {
+@@ -268,6 +273,7 @@ struct iwl_cfg iwl6050_3agn_cfg = {
+ .ht_greenfield_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
++ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ };
+
+ MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
+diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-agn.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-agn.c
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-agn.c.orig 2009-12-02 22:51:21.000000000 -0500
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-agn.c 2010-03-22 15:48:54.000000000 -0400
+@@ -1755,6 +1755,13 @@ static void iwl_alive_start(struct iwl_p
+ /* After the ALIVE response, we can send host commands to the uCode */
+ set_bit(STATUS_ALIVE, &priv->status);
+
++ if (priv->cfg->ops->lib->recover_from_tx_stall) {
++ /* Enable timer to monitor the driver queues */
++ mod_timer(&priv->monitor_recover,
++ jiffies +
++ msecs_to_jiffies(priv->cfg->monitor_recover_period));
++ }
++
+ if (iwl_is_rfkill(priv))
+ return;
+
+@@ -2829,6 +2836,13 @@ static void iwl_setup_deferred_work(stru
+ priv->statistics_periodic.data = (unsigned long)priv;
+ priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+
++ if (priv->cfg->ops->lib->recover_from_tx_stall) {
++ init_timer(&priv->monitor_recover);
++ priv->monitor_recover.data = (unsigned long)priv;
++ priv->monitor_recover.function =
++ priv->cfg->ops->lib->recover_from_tx_stall;
++ }
++
+ if (!priv->cfg->use_isr_legacy)
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+@@ -2847,6 +2861,8 @@ static void iwl_cancel_deferred_work(str
+ cancel_delayed_work(&priv->alive_start);
+ cancel_work_sync(&priv->beacon_update);
+ del_timer_sync(&priv->statistics_periodic);
++ if (priv->cfg->ops->lib->recover_from_tx_stall)
++ del_timer_sync(&priv->monitor_recover);
+ }
+
+ static struct attribute *iwl_sysfs_entries[] = {
+diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.c
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.c.orig 2010-03-22 15:40:48.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.c 2010-03-22 15:48:54.000000000 -0400
+@@ -3107,6 +3107,99 @@ int iwl_force_reset(struct iwl_priv *pri
+ }
+ return 0;
+ }
++EXPORT_SYMBOL(iwl_force_reset);
++
++/**
++ * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
++ *
++ * During normal condition (no queue is stuck), the timer is continually set to
++ * execute every monitor_recover_period milliseconds after the last timer
++ * expired. When the queue read_ptr is at the same place, the timer is
++ * shorten to 100mSecs. This is
++ * 1) to reduce the chance that the read_ptr may wrap around (not stuck)
++ * 2) to detect the stuck queues quicker before the station and AP can
++ * disassociate each other.
++ *
++ * This function monitors all the tx queues and recover from it if any
++ * of the queues are stuck.
++ * 1. It first check the cmd queue for stuck conditions. If it is stuck,
++ * it will recover by resetting the firmware and return.
++ * 2. Then, it checks for station association. If it associates it will check
++ * other queues. If any queue is stuck, it will recover by resetting
++ * the firmware.
++ * Note: It the number of times the queue read_ptr to be at the same place to
++ * be MAX_REPEAT+1 in order to consider to be stuck.
++ */
++/*
++ * The maximum number of times the read pointer of the tx queue at the
++ * same place without considering to be stuck.
++ */
++#define MAX_REPEAT (2)
++static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
++{
++ struct iwl_tx_queue *txq;
++ struct iwl_queue *q;
++
++ txq = &priv->txq[cnt];
++ q = &txq->q;
++ /* queue is empty, skip */
++ if (q->read_ptr != q->write_ptr) {
++ if (q->read_ptr == q->last_read_ptr) {
++ /* a queue has not been read from last time */
++ if (q->repeat_same_read_ptr > MAX_REPEAT) {
++ IWL_ERR(priv,
++ "queue %d stuck %d time. Fw reload.\n",
++ q->id, q->repeat_same_read_ptr);
++ q->repeat_same_read_ptr = 0;
++ iwl_force_reset(priv, IWL_FW_RESET);
++ } else {
++ q->repeat_same_read_ptr++;
++ IWL_DEBUG_RADIO(priv,
++ "queue %d, not read %d time\n",
++ q->id,
++ q->repeat_same_read_ptr);
++ mod_timer(&priv->monitor_recover, jiffies +
++ msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
++ }
++ return 1;
++ } else {
++ q->last_read_ptr = q->read_ptr;
++ q->repeat_same_read_ptr = 0;
++ }
++ }
++ return 0;
++}
++
++void iwl_bg_monitor_recover(unsigned long data)
++{
++ struct iwl_priv *priv = (struct iwl_priv *)data;
++ int cnt;
++
++ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
++ return;
++
++ /* monitor and check for stuck cmd queue */
++ if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
++ return;
++
++ /* monitor and check for other stuck queues */
++ if (iwl_is_associated(priv)) {
++ for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
++ /* skip as we already checked the command queue */
++ if (cnt == IWL_CMD_QUEUE_NUM)
++ continue;
++ if (iwl_check_stuck_queue(priv, cnt))
++ return;
++ }
++ }
++ /*
++ * Reschedule the timer to occur in
++ * priv->cfg->monitor_recover_period
++ */
++ mod_timer(&priv->monitor_recover,
++ jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
++}
++EXPORT_SYMBOL(iwl_bg_monitor_recover);
+
+ #ifdef CONFIG_PM
+
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h.orig 2010-03-22 15:24:28.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-core.h 2010-03-22 15:48:54.000000000 -0400
+@@ -183,6 +183,8 @@ struct iwl_lib_ops {
+
+ /* temperature */
+ struct iwl_temp_ops temp_ops;
++ /* recover from tx queue stall */
++ void (*recover_from_tx_stall)(unsigned long data);
+ };
+
+ struct iwl_ops {
+@@ -260,6 +262,8 @@ struct iwl_cfg {
+ const bool broken_powersave;
+ bool use_rts_for_ht;
+ u8 plcp_delta_threshold;
++ /* timer period for monitor the driver queues */
++ u32 monitor_recover_period;
+ };
+
+ /***************************
+@@ -543,6 +547,9 @@ static inline u16 iwl_pcie_link_ctl(stru
+ pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+ return pci_lnk_ctl;
+ }
++
++void iwl_bg_monitor_recover(unsigned long data);
++
+ #ifdef CONFIG_PM
+ int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+ int iwl_pci_resume(struct pci_dev *pdev);
+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
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h.orig 2010-03-22 15:37:04.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-dev.h 2010-03-22 15:48:54.000000000 -0400
+@@ -184,6 +184,10 @@ struct iwl_queue {
+ int n_bd; /* number of BDs in this queue */
+ int write_ptr; /* 1-st empty entry (index) host_w*/
+ int read_ptr; /* last used entry (index) host_r*/
++ /* use for monitoring and recovering the stuck queue */
++ int last_read_ptr; /* storing the last read_ptr */
++ /* number of time read_ptr and last_read_ptr are the same */
++ u8 repeat_same_read_ptr;
+ dma_addr_t dma_addr; /* physical addr for BD's */
+ int n_window; /* safe queue window */
+ u32 id;
+@@ -976,6 +980,11 @@ struct traffic_stats {
+ #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
+ #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
+
++/* timer constants use to monitor and recover stuck tx queues in mSecs */
++#define IWL_MONITORING_PERIOD (1000)
++#define IWL_ONE_HUNDRED_MSECS (100)
++#define IWL_SIXTY_SECS (60000)
++
+ enum iwl_reset {
+ IWL_RF_RESET = 0,
+ IWL_FW_RESET,
+@@ -1275,6 +1284,7 @@ struct iwl_priv {
+ u32 disable_tx_power_cal;
+ struct work_struct run_time_calib_work;
+ struct timer_list statistics_periodic;
++ struct timer_list monitor_recover;
+ bool hw_ready;
+ /*For 3945*/
+ #define IWL_DEFAULT_TX_POWER 0x0F
+diff -up linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-tx.c.orig linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-tx.c
+--- linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-tx.c.orig 2010-03-22 11:07:02.000000000 -0400
++++ linux-2.6.32.noarch/drivers/net/wireless/iwlwifi/iwl-tx.c 2010-03-22 15:48:54.000000000 -0400
+@@ -291,6 +291,8 @@ static int iwl_queue_init(struct iwl_pri
+ q->high_mark = 2;
+
+ q->write_ptr = q->read_ptr = 0;
++ q->last_read_ptr = 0;
++ q->repeat_same_read_ptr = 0;
+
+ return 0;
+ }