aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-04-09 20:46:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-12 15:06:08 -0400
commit7c5ba4a830cbb730770129b0004e2a06e47dbac5 (patch)
tree3c86c616dbe30b31cd07d9d8720092932f84d05b
parent52bcbff762a4cfedf97c46a58ec9890464212420 (diff)
iwlwifi: move queue watchdog into transport
This removes one of the two sources of device restarts in the upper layer -- those are a bit inconvenient because normal restarts originate in the transport. By moving the watchdog down it can be treated the same. Also rewrite the watchdog logic. Timers are much more efficient when they never fire, so instead firing a timer every 500ms set up a timer for each TX queue and fire it only when the queue is really stuck. This avoids the CPU waking up when everything is working well. While at it, remove the wd_disable config item and replace it by simply setting wd_timeout to IWL_WATCHHDOG_DISABLED (0). Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c68
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c77
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h12
11 files changed, 91 insertions, 141 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 95c59e39b803..3787f845cbd6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -165,9 +165,8 @@ static const struct iwl_base_params iwl1000_base_params = {
165 .support_ct_kill_exit = true, 165 .support_ct_kill_exit = true,
166 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, 166 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
167 .chain_noise_scale = 1000, 167 .chain_noise_scale = 1000,
168 .wd_timeout = IWL_DEF_WD_TIMEOUT, 168 .wd_timeout = IWL_WATCHHDOG_DISABLED,
169 .max_event_log_size = 128, 169 .max_event_log_size = 128,
170 .wd_disable = true,
171}; 170};
172 171
173static const struct iwl_ht_params iwl1000_ht_params = { 172static const struct iwl_ht_params iwl1000_ht_params = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 34bc8dd0064b..9f379d3dad18 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -312,10 +312,9 @@ static const struct iwl_base_params iwl5000_base_params = {
312 .led_compensation = 51, 312 .led_compensation = 51,
313 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 313 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
314 .chain_noise_scale = 1000, 314 .chain_noise_scale = 1000,
315 .wd_timeout = IWL_LONG_WD_TIMEOUT, 315 .wd_timeout = IWL_WATCHHDOG_DISABLED,
316 .max_event_log_size = 512, 316 .max_event_log_size = 512,
317 .no_idle_support = true, 317 .no_idle_support = true,
318 .wd_disable = true,
319}; 318};
320 319
321static const struct iwl_ht_params iwl5000_ht_params = { 320static const struct iwl_ht_params iwl5000_ht_params = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 3d920f92a3f3..514719957919 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -741,9 +741,6 @@ int iwl_alive_start(struct iwl_priv *priv)
741 /* After the ALIVE response, we can send host commands to the uCode */ 741 /* After the ALIVE response, we can send host commands to the uCode */
742 set_bit(STATUS_ALIVE, &priv->status); 742 set_bit(STATUS_ALIVE, &priv->status);
743 743
744 /* Enable watchdog to monitor the driver tx queues */
745 iwl_setup_watchdog(priv);
746
747 if (iwl_is_rfkill(priv)) 744 if (iwl_is_rfkill(priv))
748 return -ERFKILL; 745 return -ERFKILL;
749 746
@@ -887,10 +884,6 @@ void iwl_down(struct iwl_priv *priv)
887 exit_pending = 884 exit_pending =
888 test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); 885 test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
889 886
890 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
891 * to prevent rearm timer */
892 del_timer_sync(&priv->watchdog);
893
894 iwl_clear_ucode_stations(priv, NULL); 887 iwl_clear_ucode_stations(priv, NULL);
895 iwl_dealloc_bcast_stations(priv); 888 iwl_dealloc_bcast_stations(priv);
896 iwl_clear_driver_stations(priv); 889 iwl_clear_driver_stations(priv);
@@ -1092,10 +1085,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
1092 init_timer(&priv->ucode_trace); 1085 init_timer(&priv->ucode_trace);
1093 priv->ucode_trace.data = (unsigned long)priv; 1086 priv->ucode_trace.data = (unsigned long)priv;
1094 priv->ucode_trace.function = iwl_bg_ucode_trace; 1087 priv->ucode_trace.function = iwl_bg_ucode_trace;
1095
1096 init_timer(&priv->watchdog);
1097 priv->watchdog.data = (unsigned long)priv;
1098 priv->watchdog.function = iwl_bg_watchdog;
1099} 1088}
1100 1089
1101void iwl_cancel_deferred_work(struct iwl_priv *priv) 1090void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -1410,8 +1399,6 @@ static void iwl_set_hw_params(struct iwl_priv *priv)
1410 if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL) 1399 if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
1411 hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE; 1400 hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
1412 1401
1413 hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
1414
1415 /* Device-specific setup */ 1402 /* Device-specific setup */
1416 cfg(priv)->lib->set_hw_params(priv); 1403 cfg(priv)->lib->set_hw_params(priv);
1417} 1404}
@@ -1498,6 +1485,11 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
1498 trans_cfg.no_reclaim_cmds = no_reclaim_cmds; 1485 trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
1499 trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); 1486 trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
1500 trans_cfg.rx_buf_size_8k = iwlagn_mod_params.amsdu_size_8K; 1487 trans_cfg.rx_buf_size_8k = iwlagn_mod_params.amsdu_size_8K;
1488 if (!iwlagn_mod_params.wd_disable)
1489 trans_cfg.queue_watchdog_timeout =
1490 cfg(priv)->base_params->wd_timeout;
1491 else
1492 trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
1501 1493
1502 ucode_flags = fw->ucode_capa.flags; 1494 ucode_flags = fw->ucode_capa.flags;
1503 1495
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 88ea31d9eb75..6fc1841ff536 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -837,74 +837,6 @@ int iwl_cmd_echo_test(struct iwl_priv *priv)
837 return ret; 837 return ret;
838} 838}
839 839
840static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq)
841{
842 if (iwl_trans_check_stuck_queue(trans(priv), txq)) {
843 int ret;
844 ret = iwl_force_reset(priv, IWL_FW_RESET, false);
845 return (ret == -EAGAIN) ? 0 : 1;
846 }
847 return 0;
848}
849
850/*
851 * Making watchdog tick be a quarter of timeout assure we will
852 * discover the queue hung between timeout and 1.25*timeout
853 */
854#define IWL_WD_TICK(timeout) ((timeout) / 4)
855
856/*
857 * Watchdog timer callback, we check each tx queue for stuck, if if hung
858 * we reset the firmware. If everything is fine just rearm the timer.
859 */
860void iwl_bg_watchdog(unsigned long data)
861{
862 struct iwl_priv *priv = (struct iwl_priv *)data;
863 int cnt;
864 unsigned long timeout;
865
866 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
867 return;
868
869 if (iwl_is_rfkill(priv))
870 return;
871
872 timeout = hw_params(priv).wd_timeout;
873 if (timeout == 0)
874 return;
875
876 /* monitor and check for stuck queues */
877 for (cnt = 0; cnt < cfg(priv)->base_params->num_of_queues; cnt++)
878 if (iwl_check_stuck_queue(priv, cnt))
879 return;
880
881 mod_timer(&priv->watchdog, jiffies +
882 msecs_to_jiffies(IWL_WD_TICK(timeout)));
883}
884
885void iwl_setup_watchdog(struct iwl_priv *priv)
886{
887 unsigned int timeout = hw_params(priv).wd_timeout;
888
889 if (!iwlagn_mod_params.wd_disable) {
890 /* use system default */
891 if (timeout && !cfg(priv)->base_params->wd_disable)
892 mod_timer(&priv->watchdog,
893 jiffies +
894 msecs_to_jiffies(IWL_WD_TICK(timeout)));
895 else
896 del_timer(&priv->watchdog);
897 } else {
898 /* module parameter overwrite default configuration */
899 if (timeout && iwlagn_mod_params.wd_disable == 2)
900 mod_timer(&priv->watchdog,
901 jiffies +
902 msecs_to_jiffies(IWL_WD_TICK(timeout)));
903 else
904 del_timer(&priv->watchdog);
905 }
906}
907
908/** 840/**
909 * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time 841 * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
910 * @priv -- pointer to iwl_priv data structure 842 * @priv -- pointer to iwl_priv data structure
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 7aa3060fc6b5..f388dc4474da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -151,7 +151,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
151******************************************************/ 151******************************************************/
152void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); 152void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
153 153
154void iwl_setup_watchdog(struct iwl_priv *priv);
155/***************************************************** 154/*****************************************************
156 * TX power 155 * TX power
157 ****************************************************/ 156 ****************************************************/
@@ -193,7 +192,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
193 * S e n d i n g H o s t C o m m a n d s * 192 * S e n d i n g H o s t C o m m a n d s *
194 *****************************************************/ 193 *****************************************************/
195 194
196void iwl_bg_watchdog(unsigned long data);
197u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); 195u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
198__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, 196__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
199 u32 addon, u32 beacon_interval); 197 u32 addon, u32 beacon_interval);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 99be58940e27..780bcf3f6ff1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -585,6 +585,7 @@ struct iwl_event_log {
585#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) 585#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
586 586
587/* TX queue watchdog timeouts in mSecs */ 587/* TX queue watchdog timeouts in mSecs */
588#define IWL_WATCHHDOG_DISABLED (0)
588#define IWL_DEF_WD_TIMEOUT (2000) 589#define IWL_DEF_WD_TIMEOUT (2000)
589#define IWL_LONG_WD_TIMEOUT (10000) 590#define IWL_LONG_WD_TIMEOUT (10000)
590#define IWL_MAX_WD_TIMEOUT (120000) 591#define IWL_MAX_WD_TIMEOUT (120000)
@@ -973,7 +974,6 @@ struct iwl_priv {
973 struct work_struct run_time_calib_work; 974 struct work_struct run_time_calib_work;
974 struct timer_list statistics_periodic; 975 struct timer_list statistics_periodic;
975 struct timer_list ucode_trace; 976 struct timer_list ucode_trace;
976 struct timer_list watchdog;
977 977
978 struct iwl_event_log event_log; 978 struct iwl_event_log event_log;
979 979
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index c2e5ce995fb4..c6049cfb653d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -169,7 +169,6 @@ struct iwl_mod_params {
169 * @ct_kill_threshold: temperature threshold - in hw dependent unit 169 * @ct_kill_threshold: temperature threshold - in hw dependent unit
170 * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit 170 * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
171 * relevant for 1000, 6000 and up 171 * relevant for 1000, 6000 and up
172 * @wd_timeout: TX queues watchdog timeout
173 * @struct iwl_sensitivity_ranges: range of sensitivity values 172 * @struct iwl_sensitivity_ranges: range of sensitivity values
174 * @use_rts_for_aggregation: use rts/cts protection for HT traffic 173 * @use_rts_for_aggregation: use rts/cts protection for HT traffic
175 */ 174 */
@@ -183,7 +182,6 @@ struct iwl_hw_params {
183 u16 sku; 182 u16 sku;
184 u32 ct_kill_threshold; 183 u32 ct_kill_threshold;
185 u32 ct_kill_exit_threshold; 184 u32 ct_kill_exit_threshold;
186 unsigned int wd_timeout;
187 185
188 const struct iwl_sensitivity_ranges *sens; 186 const struct iwl_sensitivity_ranges *sens;
189}; 187};
@@ -221,7 +219,6 @@ enum iwl_led_mode {
221 * @shadow_reg_enable: HW shadhow register bit 219 * @shadow_reg_enable: HW shadhow register bit
222 * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up 220 * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
223 * @no_idle_support: do not support idle mode 221 * @no_idle_support: do not support idle mode
224 * wd_disable: disable watchdog timer
225 */ 222 */
226struct iwl_base_params { 223struct iwl_base_params {
227 int eeprom_size; 224 int eeprom_size;
@@ -241,7 +238,6 @@ struct iwl_base_params {
241 const bool shadow_reg_enable; 238 const bool shadow_reg_enable;
242 const bool hd_v2; 239 const bool hd_v2;
243 const bool no_idle_support; 240 const bool no_idle_support;
244 const bool wd_disable;
245}; 241};
246 242
247/* 243/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index a1fc439aafd0..731d2750439c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -34,6 +34,7 @@
34#include <linux/skbuff.h> 34#include <linux/skbuff.h>
35#include <linux/wait.h> 35#include <linux/wait.h>
36#include <linux/pci.h> 36#include <linux/pci.h>
37#include <linux/timer.h>
37 38
38#include "iwl-fh.h" 39#include "iwl-fh.h"
39#include "iwl-csr.h" 40#include "iwl-csr.h"
@@ -204,7 +205,8 @@ struct iwl_tx_queue {
204 struct iwl_cmd_meta *meta; 205 struct iwl_cmd_meta *meta;
205 struct sk_buff **skbs; 206 struct sk_buff **skbs;
206 spinlock_t lock; 207 spinlock_t lock;
207 unsigned long time_stamp; 208 struct timer_list stuck_timer;
209 struct iwl_trans_pcie *trans_pcie;
208 u8 need_update; 210 u8 need_update;
209 u8 active; 211 u8 active;
210}; 212};
@@ -227,6 +229,7 @@ struct iwl_tx_queue {
227 * @cmd_queue - command queue number 229 * @cmd_queue - command queue number
228 * @rx_buf_size_8k: 8 kB RX buffer size 230 * @rx_buf_size_8k: 8 kB RX buffer size
229 * @rx_page_order: page order for receive buffer size 231 * @rx_page_order: page order for receive buffer size
232 * @wd_timeout: queue watchdog timeout (jiffies)
230 */ 233 */
231struct iwl_trans_pcie { 234struct iwl_trans_pcie {
232 struct iwl_rx_queue rxq; 235 struct iwl_rx_queue rxq;
@@ -269,11 +272,22 @@ struct iwl_trans_pcie {
269 272
270 bool rx_buf_size_8k; 273 bool rx_buf_size_8k;
271 u32 rx_page_order; 274 u32 rx_page_order;
275
276
277 /* queue watchdog */
278 unsigned long wd_timeout;
272}; 279};
273 280
274#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ 281#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
275 ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) 282 ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
276 283
284static inline struct iwl_trans *
285iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
286{
287 return container_of((void *)trans_pcie, struct iwl_trans,
288 trans_specific);
289}
290
277/***************************************************** 291/*****************************************************
278* RX 292* RX
279******************************************************/ 293******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index d35d0b81fd28..c34eac062762 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -668,6 +668,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
668 trace_bufs[2], trace_lens[2]); 668 trace_bufs[2], trace_lens[2]);
669#endif 669#endif
670 670
671 /* start timer if queue currently empty */
672 if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
673 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
674
671 /* Increment and update queue's write index */ 675 /* Increment and update queue's write index */
672 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 676 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
673 iwl_txq_update_write_ptr(trans, txq); 677 iwl_txq_update_write_ptr(trans, txq);
@@ -677,6 +681,22 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
677 return idx; 681 return idx;
678} 682}
679 683
684static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
685 struct iwl_tx_queue *txq)
686{
687 if (!trans_pcie->wd_timeout)
688 return;
689
690 /*
691 * if empty delete timer, otherwise move timer forward
692 * since we're making progress on this queue
693 */
694 if (txq->q.read_ptr == txq->q.write_ptr)
695 del_timer(&txq->stuck_timer);
696 else
697 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
698}
699
680/** 700/**
681 * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd 701 * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
682 * 702 *
@@ -711,6 +731,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
711 } 731 }
712 732
713 } 733 }
734
735 iwl_queue_progress(trans_pcie, txq);
714} 736}
715 737
716/** 738/**
@@ -754,8 +776,6 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
754 cmd = txq->cmd[cmd_index]; 776 cmd = txq->cmd[cmd_index];
755 meta = &txq->meta[cmd_index]; 777 meta = &txq->meta[cmd_index];
756 778
757 txq->time_stamp = jiffies;
758
759 iwlagn_unmap_tfd(trans, meta, &txq->tfds[index], 779 iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
760 DMA_BIDIRECTIONAL); 780 DMA_BIDIRECTIONAL);
761 781
@@ -949,5 +969,8 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
949 iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); 969 iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE);
950 freed++; 970 freed++;
951 } 971 }
972
973 iwl_queue_progress(trans_pcie, txq);
974
952 return freed; 975 return freed;
953} 976}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 1d100491be4c..f3695fea45ef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -299,6 +299,33 @@ static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
299 memset(ptr, 0, sizeof(*ptr)); 299 memset(ptr, 0, sizeof(*ptr));
300} 300}
301 301
302static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
303{
304 struct iwl_tx_queue *txq = (void *)data;
305 struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
306 struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
307
308 spin_lock(&txq->lock);
309 /* check if triggered erroneously */
310 if (txq->q.read_ptr == txq->q.write_ptr) {
311 spin_unlock(&txq->lock);
312 return;
313 }
314 spin_unlock(&txq->lock);
315
316
317 IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
318 jiffies_to_msecs(trans_pcie->wd_timeout));
319 IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
320 txq->q.read_ptr, txq->q.write_ptr);
321 IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
322 iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq->q.id))
323 & (TFD_QUEUE_SIZE_MAX - 1),
324 iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq->q.id)));
325
326 iwl_op_mode_nic_error(trans->op_mode);
327}
328
302static int iwl_trans_txq_alloc(struct iwl_trans *trans, 329static int iwl_trans_txq_alloc(struct iwl_trans *trans,
303 struct iwl_tx_queue *txq, int slots_num, 330 struct iwl_tx_queue *txq, int slots_num,
304 u32 txq_id) 331 u32 txq_id)
@@ -310,6 +337,10 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
310 if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds)) 337 if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds))
311 return -EINVAL; 338 return -EINVAL;
312 339
340 setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
341 (unsigned long)txq);
342 txq->trans_pcie = trans_pcie;
343
313 txq->q.n_window = slots_num; 344 txq->q.n_window = slots_num;
314 345
315 txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL); 346 txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL);
@@ -472,6 +503,8 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
472 txq->cmd = NULL; 503 txq->cmd = NULL;
473 txq->meta = NULL; 504 txq->meta = NULL;
474 505
506 del_timer_sync(&txq->stuck_timer);
507
475 /* 0-fill queue descriptor structure */ 508 /* 0-fill queue descriptor structure */
476 memset(txq, 0, sizeof(*txq)); 509 memset(txq, 0, sizeof(*txq));
477} 510}
@@ -1347,6 +1380,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1347 &dev_cmd->hdr, firstlen, 1380 &dev_cmd->hdr, firstlen,
1348 skb->data + hdr_len, secondlen); 1381 skb->data + hdr_len, secondlen);
1349 1382
1383 /* start timer if queue currently empty */
1384 if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
1385 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
1386
1350 /* Tell device the write index *just past* this latest filled TFD */ 1387 /* Tell device the write index *just past* this latest filled TFD */
1351 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 1388 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
1352 iwl_txq_update_write_ptr(trans, txq); 1389 iwl_txq_update_write_ptr(trans, txq);
@@ -1442,8 +1479,6 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
1442 1479
1443 spin_lock(&txq->lock); 1480 spin_lock(&txq->lock);
1444 1481
1445 txq->time_stamp = jiffies;
1446
1447 if (txq->q.read_ptr != tfd_num) { 1482 if (txq->q.read_ptr != tfd_num) {
1448 IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n", 1483 IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
1449 txq_id, txq->q.read_ptr, tfd_num, ssn); 1484 txq_id, txq->q.read_ptr, tfd_num, ssn);
@@ -1500,6 +1535,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
1500 trans_pcie->rx_page_order = get_order(8 * 1024); 1535 trans_pcie->rx_page_order = get_order(8 * 1024);
1501 else 1536 else
1502 trans_pcie->rx_page_order = get_order(4 * 1024); 1537 trans_pcie->rx_page_order = get_order(4 * 1024);
1538
1539 trans_pcie->wd_timeout =
1540 msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
1503} 1541}
1504 1542
1505static void iwl_trans_pcie_free(struct iwl_trans *trans) 1543static void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1589,40 +1627,6 @@ static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
1589 return ret; 1627 return ret;
1590} 1628}
1591 1629
1592/*
1593 * On every watchdog tick we check (latest) time stamp. If it does not
1594 * change during timeout period and queue is not empty we reset firmware.
1595 */
1596static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt)
1597{
1598 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1599 struct iwl_tx_queue *txq = &trans_pcie->txq[cnt];
1600 struct iwl_queue *q = &txq->q;
1601 unsigned long timeout;
1602
1603 if (q->read_ptr == q->write_ptr) {
1604 txq->time_stamp = jiffies;
1605 return 0;
1606 }
1607
1608 timeout = txq->time_stamp +
1609 msecs_to_jiffies(hw_params(trans).wd_timeout);
1610
1611 if (time_after(jiffies, timeout)) {
1612 IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
1613 hw_params(trans).wd_timeout);
1614 IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
1615 q->read_ptr, q->write_ptr);
1616 IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
1617 iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt))
1618 & (TFD_QUEUE_SIZE_MAX - 1),
1619 iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
1620 return 1;
1621 }
1622
1623 return 0;
1624}
1625
1626static const char *get_fh_string(int cmd) 1630static const char *get_fh_string(int cmd)
1627{ 1631{
1628 switch (cmd) { 1632 switch (cmd) {
@@ -2039,7 +2043,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
2039 .dbgfs_register = iwl_trans_pcie_dbgfs_register, 2043 .dbgfs_register = iwl_trans_pcie_dbgfs_register,
2040 2044
2041 .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty, 2045 .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
2042 .check_stuck_queue = iwl_trans_pcie_check_stuck_queue,
2043 2046
2044#ifdef CONFIG_PM_SLEEP 2047#ifdef CONFIG_PM_SLEEP
2045 .suspend = iwl_trans_pcie_suspend, 2048 .suspend = iwl_trans_pcie_suspend,
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 46be59f5ef39..a6598a29ef59 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -307,6 +307,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
307 * @n_no_reclaim_cmds: # of commands in list 307 * @n_no_reclaim_cmds: # of commands in list
308 * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs, 308 * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
309 * if unset 4k will be the RX buffer size 309 * if unset 4k will be the RX buffer size
310 * @queue_watchdog_timeout: time (in ms) after which queues
311 * are considered stuck and will trigger device restart
310 */ 312 */
311struct iwl_trans_config { 313struct iwl_trans_config {
312 struct iwl_op_mode *op_mode; 314 struct iwl_op_mode *op_mode;
@@ -318,6 +320,7 @@ struct iwl_trans_config {
318 int n_no_reclaim_cmds; 320 int n_no_reclaim_cmds;
319 321
320 bool rx_buf_size_8k; 322 bool rx_buf_size_8k;
323 unsigned int queue_watchdog_timeout;
321}; 324};
322 325
323/** 326/**
@@ -355,7 +358,6 @@ struct iwl_trans_config {
355 * irq, tasklet etc... From this point on, the device may not issue 358 * irq, tasklet etc... From this point on, the device may not issue
356 * any interrupt (incl. RFKILL). 359 * any interrupt (incl. RFKILL).
357 * May sleep 360 * May sleep
358 * @check_stuck_queue: check if a specific queue is stuck
359 * @wait_tx_queue_empty: wait until all tx queues are empty 361 * @wait_tx_queue_empty: wait until all tx queues are empty
360 * May sleep 362 * May sleep
361 * @dbgfs_register: add the dbgfs files under this directory. Files will be 363 * @dbgfs_register: add the dbgfs files under this directory. Files will be
@@ -394,7 +396,6 @@ struct iwl_trans_ops {
394 void (*free)(struct iwl_trans *trans); 396 void (*free)(struct iwl_trans *trans);
395 397
396 int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); 398 int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
397 int (*check_stuck_queue)(struct iwl_trans *trans, int q);
398 int (*wait_tx_queue_empty)(struct iwl_trans *trans); 399 int (*wait_tx_queue_empty)(struct iwl_trans *trans);
399#ifdef CONFIG_PM_SLEEP 400#ifdef CONFIG_PM_SLEEP
400 int (*suspend)(struct iwl_trans *trans); 401 int (*suspend)(struct iwl_trans *trans);
@@ -577,13 +578,6 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
577 return trans->ops->wait_tx_queue_empty(trans); 578 return trans->ops->wait_tx_queue_empty(trans);
578} 579}
579 580
580static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q)
581{
582 WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
583 "%s bad state = %d", __func__, trans->state);
584
585 return trans->ops->check_stuck_queue(trans, q);
586}
587static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, 581static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
588 struct dentry *dir) 582 struct dentry *dir)
589{ 583{