aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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{