aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2010-12-03 09:41:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-06 16:01:29 -0500
commit22de94de7de78b8de2fb1f2df5aa85b5556cfcfd (patch)
treef965d5f907ffc039ca146c22a5c2e87744cbc604 /drivers/net
parentabc471dc31be15f9fee5ec77f25d31b927d334b9 (diff)
iwlwifi: jiffies based tx queues watchdog
This patch replace monitor/recover timer by watchdog based on time stamp. New code allow to discover hangs more precisely. Timeout values are currently doubled monitoring period values of previous timer. This have to be tuned based of firmware timing capabilities. Tested on 3945, 4965, 5300, 6300. Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c111
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c21
13 files changed, 91 insertions, 138 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index fb3e3713bae4..3c983e426f25 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -228,7 +228,6 @@ static struct iwl_lib_ops iwl1000_lib = {
228 .bt_stats_read = iwl_ucode_bt_stats_read, 228 .bt_stats_read = iwl_ucode_bt_stats_read,
229 .reply_tx_error = iwl_reply_tx_error_read, 229 .reply_tx_error = iwl_reply_tx_error_read,
230 }, 230 },
231 .recover_from_tx_stall = iwl_bg_monitor_recover,
232 .check_plcp_health = iwl_good_plcp_health, 231 .check_plcp_health = iwl_good_plcp_health,
233 .check_ack_health = iwl_good_ack_health, 232 .check_ack_health = iwl_good_ack_health,
234 .txfifo_flush = iwlagn_txfifo_flush, 233 .txfifo_flush = iwlagn_txfifo_flush,
@@ -262,7 +261,7 @@ static struct iwl_base_params iwl1000_base_params = {
262 .support_ct_kill_exit = true, 261 .support_ct_kill_exit = true,
263 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, 262 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
264 .chain_noise_scale = 1000, 263 .chain_noise_scale = 1000,
265 .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, 264 .wd_timeout = IWL_DEF_WD_TIMEOUT,
266 .max_event_log_size = 128, 265 .max_event_log_size = 128,
267 .ucode_tracing = true, 266 .ucode_tracing = true,
268 .sensitivity_calib_by_driver = true, 267 .sensitivity_calib_by_driver = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index cac9647da71c..a9b852be4509 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -325,6 +325,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
325 return; 325 return;
326 } 326 }
327 327
328 txq->time_stamp = jiffies;
328 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); 329 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
329 ieee80211_tx_info_clear_status(info); 330 ieee80211_tx_info_clear_status(info);
330 331
@@ -2733,7 +2734,6 @@ static struct iwl_lib_ops iwl3945_lib = {
2733 .isr_ops = { 2734 .isr_ops = {
2734 .isr = iwl_isr_legacy, 2735 .isr = iwl_isr_legacy,
2735 }, 2736 },
2736 .recover_from_tx_stall = iwl_bg_monitor_recover,
2737 .check_plcp_health = iwl3945_good_plcp_health, 2737 .check_plcp_health = iwl3945_good_plcp_health,
2738 2738
2739 .debugfs_ops = { 2739 .debugfs_ops = {
@@ -2776,7 +2776,7 @@ static struct iwl_base_params iwl3945_base_params = {
2776 .led_compensation = 64, 2776 .led_compensation = 64,
2777 .broken_powersave = true, 2777 .broken_powersave = true,
2778 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 2778 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
2779 .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, 2779 .wd_timeout = IWL_DEF_WD_TIMEOUT,
2780 .max_event_log_size = 512, 2780 .max_event_log_size = 512,
2781 .tx_power_by_driver = true, 2781 .tx_power_by_driver = true,
2782}; 2782};
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 6788ceb37686..3f1e5f1bf847 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2198,6 +2198,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
2198 return; 2198 return;
2199 } 2199 }
2200 2200
2201 txq->time_stamp = jiffies;
2201 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); 2202 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
2202 memset(&info->status, 0, sizeof(info->status)); 2203 memset(&info->status, 0, sizeof(info->status));
2203 2204
@@ -2554,7 +2555,6 @@ static struct iwl_lib_ops iwl4965_lib = {
2554 .bt_stats_read = iwl_ucode_bt_stats_read, 2555 .bt_stats_read = iwl_ucode_bt_stats_read,
2555 .reply_tx_error = iwl_reply_tx_error_read, 2556 .reply_tx_error = iwl_reply_tx_error_read,
2556 }, 2557 },
2557 .recover_from_tx_stall = iwl_bg_monitor_recover,
2558 .check_plcp_health = iwl_good_plcp_health, 2558 .check_plcp_health = iwl_good_plcp_health,
2559}; 2559};
2560 2560
@@ -2609,7 +2609,7 @@ static struct iwl_base_params iwl4965_base_params = {
2609 .led_compensation = 61, 2609 .led_compensation = 61,
2610 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, 2610 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
2611 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 2611 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2612 .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, 2612 .wd_timeout = IWL_DEF_WD_TIMEOUT,
2613 .temperature_kelvin = true, 2613 .temperature_kelvin = true,
2614 .max_event_log_size = 512, 2614 .max_event_log_size = 512,
2615 .tx_power_by_driver = true, 2615 .tx_power_by_driver = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index cf74edb82a70..8435e5a4e69d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -402,7 +402,6 @@ static struct iwl_lib_ops iwl5000_lib = {
402 .bt_stats_read = iwl_ucode_bt_stats_read, 402 .bt_stats_read = iwl_ucode_bt_stats_read,
403 .reply_tx_error = iwl_reply_tx_error_read, 403 .reply_tx_error = iwl_reply_tx_error_read,
404 }, 404 },
405 .recover_from_tx_stall = iwl_bg_monitor_recover,
406 .check_plcp_health = iwl_good_plcp_health, 405 .check_plcp_health = iwl_good_plcp_health,
407 .check_ack_health = iwl_good_ack_health, 406 .check_ack_health = iwl_good_ack_health,
408 .txfifo_flush = iwlagn_txfifo_flush, 407 .txfifo_flush = iwlagn_txfifo_flush,
@@ -472,7 +471,6 @@ static struct iwl_lib_ops iwl5150_lib = {
472 .bt_stats_read = iwl_ucode_bt_stats_read, 471 .bt_stats_read = iwl_ucode_bt_stats_read,
473 .reply_tx_error = iwl_reply_tx_error_read, 472 .reply_tx_error = iwl_reply_tx_error_read,
474 }, 473 },
475 .recover_from_tx_stall = iwl_bg_monitor_recover,
476 .check_plcp_health = iwl_good_plcp_health, 474 .check_plcp_health = iwl_good_plcp_health,
477 .check_ack_health = iwl_good_ack_health, 475 .check_ack_health = iwl_good_ack_health,
478 .txfifo_flush = iwlagn_txfifo_flush, 476 .txfifo_flush = iwlagn_txfifo_flush,
@@ -511,7 +509,7 @@ static struct iwl_base_params iwl5000_base_params = {
511 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 509 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
512 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 510 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
513 .chain_noise_scale = 1000, 511 .chain_noise_scale = 1000,
514 .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, 512 .wd_timeout = IWL_LONG_WD_TIMEOUT,
515 .max_event_log_size = 512, 513 .max_event_log_size = 512,
516 .ucode_tracing = true, 514 .ucode_tracing = true,
517 .sensitivity_calib_by_driver = true, 515 .sensitivity_calib_by_driver = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 8018f38d5165..808942cc2991 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -339,7 +339,6 @@ static struct iwl_lib_ops iwl6000_lib = {
339 .bt_stats_read = iwl_ucode_bt_stats_read, 339 .bt_stats_read = iwl_ucode_bt_stats_read,
340 .reply_tx_error = iwl_reply_tx_error_read, 340 .reply_tx_error = iwl_reply_tx_error_read,
341 }, 341 },
342 .recover_from_tx_stall = iwl_bg_monitor_recover,
343 .check_plcp_health = iwl_good_plcp_health, 342 .check_plcp_health = iwl_good_plcp_health,
344 .check_ack_health = iwl_good_ack_health, 343 .check_ack_health = iwl_good_ack_health,
345 .txfifo_flush = iwlagn_txfifo_flush, 344 .txfifo_flush = iwlagn_txfifo_flush,
@@ -412,7 +411,6 @@ static struct iwl_lib_ops iwl6000g2b_lib = {
412 .bt_stats_read = iwl_ucode_bt_stats_read, 411 .bt_stats_read = iwl_ucode_bt_stats_read,
413 .reply_tx_error = iwl_reply_tx_error_read, 412 .reply_tx_error = iwl_reply_tx_error_read,
414 }, 413 },
415 .recover_from_tx_stall = iwl_bg_monitor_recover,
416 .check_plcp_health = iwl_good_plcp_health, 414 .check_plcp_health = iwl_good_plcp_health,
417 .check_ack_health = iwl_good_ack_health, 415 .check_ack_health = iwl_good_ack_health,
418 .txfifo_flush = iwlagn_txfifo_flush, 416 .txfifo_flush = iwlagn_txfifo_flush,
@@ -482,7 +480,7 @@ static struct iwl_base_params iwl6000_base_params = {
482 .support_ct_kill_exit = true, 480 .support_ct_kill_exit = true,
483 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 481 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
484 .chain_noise_scale = 1000, 482 .chain_noise_scale = 1000,
485 .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, 483 .wd_timeout = IWL_DEF_WD_TIMEOUT,
486 .max_event_log_size = 512, 484 .max_event_log_size = 512,
487 .ucode_tracing = true, 485 .ucode_tracing = true,
488 .sensitivity_calib_by_driver = true, 486 .sensitivity_calib_by_driver = true,
@@ -506,7 +504,7 @@ static struct iwl_base_params iwl6050_base_params = {
506 .support_ct_kill_exit = true, 504 .support_ct_kill_exit = true,
507 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 505 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
508 .chain_noise_scale = 1500, 506 .chain_noise_scale = 1500,
509 .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, 507 .wd_timeout = IWL_DEF_WD_TIMEOUT,
510 .max_event_log_size = 1024, 508 .max_event_log_size = 1024,
511 .ucode_tracing = true, 509 .ucode_tracing = true,
512 .sensitivity_calib_by_driver = true, 510 .sensitivity_calib_by_driver = true,
@@ -529,7 +527,7 @@ static struct iwl_base_params iwl6000_coex_base_params = {
529 .support_ct_kill_exit = true, 527 .support_ct_kill_exit = true,
530 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 528 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
531 .chain_noise_scale = 1000, 529 .chain_noise_scale = 1000,
532 .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, 530 .wd_timeout = IWL_LONG_WD_TIMEOUT,
533 .max_event_log_size = 512, 531 .max_event_log_size = 512,
534 .ucode_tracing = true, 532 .ucode_tracing = true,
535 .sensitivity_calib_by_driver = true, 533 .sensitivity_calib_by_driver = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 407f0bb8422a..d941910e7ef4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -405,6 +405,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
405 return; 405 return;
406 } 406 }
407 407
408 txq->time_stamp = jiffies;
408 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); 409 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
409 memset(&info->status, 0, sizeof(info->status)); 410 memset(&info->status, 0, sizeof(info->status));
410 411
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 32ab4a0215a0..d4075476670a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2654,13 +2654,8 @@ static void iwl_alive_start(struct iwl_priv *priv)
2654 /* After the ALIVE response, we can send host commands to the uCode */ 2654 /* After the ALIVE response, we can send host commands to the uCode */
2655 set_bit(STATUS_ALIVE, &priv->status); 2655 set_bit(STATUS_ALIVE, &priv->status);
2656 2656
2657 if (priv->cfg->ops->lib->recover_from_tx_stall) { 2657 /* Enable watchdog to monitor the driver tx queues */
2658 /* Enable timer to monitor the driver queues */ 2658 iwl_setup_watchdog(priv);
2659 mod_timer(&priv->monitor_recover,
2660 jiffies +
2661 msecs_to_jiffies(
2662 priv->cfg->base_params->monitor_recover_period));
2663 }
2664 2659
2665 if (iwl_is_rfkill(priv)) 2660 if (iwl_is_rfkill(priv))
2666 return; 2661 return;
@@ -2755,8 +2750,7 @@ static void __iwl_down(struct iwl_priv *priv)
2755 2750
2756 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set 2751 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
2757 * to prevent rearm timer */ 2752 * to prevent rearm timer */
2758 if (priv->cfg->ops->lib->recover_from_tx_stall) 2753 del_timer_sync(&priv->watchdog);
2759 del_timer_sync(&priv->monitor_recover);
2760 2754
2761 iwl_clear_ucode_stations(priv, NULL); 2755 iwl_clear_ucode_stations(priv, NULL);
2762 iwl_dealloc_bcast_stations(priv); 2756 iwl_dealloc_bcast_stations(priv);
@@ -3742,12 +3736,9 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3742 priv->ucode_trace.data = (unsigned long)priv; 3736 priv->ucode_trace.data = (unsigned long)priv;
3743 priv->ucode_trace.function = iwl_bg_ucode_trace; 3737 priv->ucode_trace.function = iwl_bg_ucode_trace;
3744 3738
3745 if (priv->cfg->ops->lib->recover_from_tx_stall) { 3739 init_timer(&priv->watchdog);
3746 init_timer(&priv->monitor_recover); 3740 priv->watchdog.data = (unsigned long)priv;
3747 priv->monitor_recover.data = (unsigned long)priv; 3741 priv->watchdog.function = iwl_bg_watchdog;
3748 priv->monitor_recover.function =
3749 priv->cfg->ops->lib->recover_from_tx_stall;
3750 }
3751 3742
3752 if (!priv->cfg->base_params->use_isr_legacy) 3743 if (!priv->cfg->base_params->use_isr_legacy)
3753 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 3744 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c41f5a878210..d62b92518417 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1894,77 +1894,58 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1894} 1894}
1895EXPORT_SYMBOL(iwl_mac_change_interface); 1895EXPORT_SYMBOL(iwl_mac_change_interface);
1896 1896
1897/**
1898 * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
1899 *
1900 * During normal condition (no queue is stuck), the timer is continually set to
1901 * execute every monitor_recover_period milliseconds after the last timer
1902 * expired. When the queue read_ptr is at the same place, the timer is
1903 * shorten to 100mSecs. This is
1904 * 1) to reduce the chance that the read_ptr may wrap around (not stuck)
1905 * 2) to detect the stuck queues quicker before the station and AP can
1906 * disassociate each other.
1907 *
1908 * This function monitors all the tx queues and recover from it if any
1909 * of the queues are stuck.
1910 * 1. It first check the cmd queue for stuck conditions. If it is stuck,
1911 * it will recover by resetting the firmware and return.
1912 * 2. Then, it checks for station association. If it associates it will check
1913 * other queues. If any queue is stuck, it will recover by resetting
1914 * the firmware.
1915 * Note: It the number of times the queue read_ptr to be at the same place to
1916 * be MAX_REPEAT+1 in order to consider to be stuck.
1917 */
1918/* 1897/*
1919 * The maximum number of times the read pointer of the tx queue at the 1898 * On every watchdog tick we check (latest) time stamp. If it does not
1920 * same place without considering to be stuck. 1899 * change during timeout period and queue is not empty we reset firmware.
1921 */ 1900 */
1922#define MAX_REPEAT (2)
1923static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) 1901static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
1924{ 1902{
1925 struct iwl_tx_queue *txq; 1903 struct iwl_tx_queue *txq = &priv->txq[cnt];
1926 struct iwl_queue *q; 1904 struct iwl_queue *q = &txq->q;
1905 unsigned long timeout;
1906 int ret;
1927 1907
1928 txq = &priv->txq[cnt]; 1908 if (q->read_ptr == q->write_ptr) {
1929 q = &txq->q; 1909 txq->time_stamp = jiffies;
1930 /* queue is empty, skip */
1931 if (q->read_ptr == q->write_ptr)
1932 return 0; 1910 return 0;
1911 }
1933 1912
1934 if (q->read_ptr == q->last_read_ptr) { 1913 timeout = txq->time_stamp +
1935 /* a queue has not been read from last time */ 1914 msecs_to_jiffies(priv->cfg->base_params->wd_timeout);
1936 if (q->repeat_same_read_ptr > MAX_REPEAT) { 1915
1937 IWL_ERR(priv, 1916 if (time_after(jiffies, timeout)) {
1938 "queue %d stuck %d time. Fw reload.\n", 1917 IWL_ERR(priv, "Queue %d stuck for %u ms.\n",
1939 q->id, q->repeat_same_read_ptr); 1918 q->id, priv->cfg->base_params->wd_timeout);
1940 q->repeat_same_read_ptr = 0; 1919 ret = iwl_force_reset(priv, IWL_FW_RESET, false);
1941 iwl_force_reset(priv, IWL_FW_RESET, false); 1920 return (ret == -EAGAIN) ? 0 : 1;
1942 } else {
1943 q->repeat_same_read_ptr++;
1944 IWL_DEBUG_RADIO(priv,
1945 "queue %d, not read %d time\n",
1946 q->id,
1947 q->repeat_same_read_ptr);
1948 mod_timer(&priv->monitor_recover,
1949 jiffies + msecs_to_jiffies(
1950 IWL_ONE_HUNDRED_MSECS));
1951 return 1;
1952 }
1953 } else {
1954 q->last_read_ptr = q->read_ptr;
1955 q->repeat_same_read_ptr = 0;
1956 } 1921 }
1922
1957 return 0; 1923 return 0;
1958} 1924}
1959 1925
1960void iwl_bg_monitor_recover(unsigned long data) 1926/*
1927 * Making watchdog tick be a quarter of timeout assure we will
1928 * discover the queue hung between timeout and 1.25*timeout
1929 */
1930#define IWL_WD_TICK(timeout) ((timeout) / 4)
1931
1932/*
1933 * Watchdog timer callback, we check each tx queue for stuck, if if hung
1934 * we reset the firmware. If everything is fine just rearm the timer.
1935 */
1936void iwl_bg_watchdog(unsigned long data)
1961{ 1937{
1962 struct iwl_priv *priv = (struct iwl_priv *)data; 1938 struct iwl_priv *priv = (struct iwl_priv *)data;
1963 int cnt; 1939 int cnt;
1940 unsigned long timeout;
1964 1941
1965 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 1942 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
1966 return; 1943 return;
1967 1944
1945 timeout = priv->cfg->base_params->wd_timeout;
1946 if (timeout == 0)
1947 return;
1948
1968 /* monitor and check for stuck cmd queue */ 1949 /* monitor and check for stuck cmd queue */
1969 if (iwl_check_stuck_queue(priv, priv->cmd_queue)) 1950 if (iwl_check_stuck_queue(priv, priv->cmd_queue))
1970 return; 1951 return;
@@ -1979,17 +1960,23 @@ void iwl_bg_monitor_recover(unsigned long data)
1979 return; 1960 return;
1980 } 1961 }
1981 } 1962 }
1982 if (priv->cfg->base_params->monitor_recover_period) { 1963
1983 /* 1964 mod_timer(&priv->watchdog, jiffies +
1984 * Reschedule the timer to occur in 1965 msecs_to_jiffies(IWL_WD_TICK(timeout)));
1985 * priv->cfg->base_params->monitor_recover_period
1986 */
1987 mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
1988 priv->cfg->base_params->monitor_recover_period));
1989 }
1990} 1966}
1991EXPORT_SYMBOL(iwl_bg_monitor_recover); 1967EXPORT_SYMBOL(iwl_bg_watchdog);
1968
1969void iwl_setup_watchdog(struct iwl_priv *priv)
1970{
1971 unsigned int timeout = priv->cfg->base_params->wd_timeout;
1992 1972
1973 if (timeout)
1974 mod_timer(&priv->watchdog,
1975 jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
1976 else
1977 del_timer(&priv->watchdog);
1978}
1979EXPORT_SYMBOL(iwl_setup_watchdog);
1993 1980
1994/* 1981/*
1995 * extended beacon time format 1982 * extended beacon time format
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 808be731ecb7..568920ac982d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -210,8 +210,6 @@ struct iwl_lib_ops {
210 210
211 /* temperature */ 211 /* temperature */
212 struct iwl_temp_ops temp_ops; 212 struct iwl_temp_ops temp_ops;
213 /* recover from tx queue stall */
214 void (*recover_from_tx_stall)(unsigned long data);
215 /* check for plcp health */ 213 /* check for plcp health */
216 bool (*check_plcp_health)(struct iwl_priv *priv, 214 bool (*check_plcp_health)(struct iwl_priv *priv,
217 struct iwl_rx_packet *pkt); 215 struct iwl_rx_packet *pkt);
@@ -280,7 +278,7 @@ struct iwl_mod_params {
280 * @plcp_delta_threshold: plcp error rate threshold used to trigger 278 * @plcp_delta_threshold: plcp error rate threshold used to trigger
281 * radio tuning when there is a high receiving plcp error rate 279 * radio tuning when there is a high receiving plcp error rate
282 * @chain_noise_scale: default chain noise scale used for gain computation 280 * @chain_noise_scale: default chain noise scale used for gain computation
283 * @monitor_recover_period: default timer used to check stuck queues 281 * @wd_timeout: TX queues watchdog timeout
284 * @temperature_kelvin: temperature report by uCode in kelvin 282 * @temperature_kelvin: temperature report by uCode in kelvin
285 * @max_event_log_size: size of event log buffer size for ucode event logging 283 * @max_event_log_size: size of event log buffer size for ucode event logging
286 * @tx_power_by_driver: tx power calibration performed by driver 284 * @tx_power_by_driver: tx power calibration performed by driver
@@ -315,8 +313,7 @@ struct iwl_base_params {
315 const bool support_wimax_coexist; 313 const bool support_wimax_coexist;
316 u8 plcp_delta_threshold; 314 u8 plcp_delta_threshold;
317 s32 chain_noise_scale; 315 s32 chain_noise_scale;
318 /* timer period for monitor the driver queues */ 316 unsigned int wd_timeout;
319 u32 monitor_recover_period;
320 bool temperature_kelvin; 317 bool temperature_kelvin;
321 u32 max_event_log_size; 318 u32 max_event_log_size;
322 const bool tx_power_by_driver; 319 const bool tx_power_by_driver;
@@ -546,6 +543,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
546void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, 543void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
547 int slots_num, u32 txq_id); 544 int slots_num, u32 txq_id);
548void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); 545void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
546void iwl_setup_watchdog(struct iwl_priv *priv);
549/***************************************************** 547/*****************************************************
550 * TX power 548 * TX power
551 ****************************************************/ 549 ****************************************************/
@@ -625,7 +623,7 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
625 return pci_lnk_ctl; 623 return pci_lnk_ctl;
626} 624}
627 625
628void iwl_bg_monitor_recover(unsigned long data); 626void iwl_bg_watchdog(unsigned long data);
629u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); 627u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
630__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, 628__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
631 u32 addon, u32 beacon_interval); 629 u32 addon, u32 beacon_interval);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 3cc58420d445..d36836376e6b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -1534,32 +1534,26 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
1534 user_buf, count, ppos); 1534 user_buf, count, ppos);
1535} 1535}
1536 1536
1537static ssize_t iwl_dbgfs_monitor_period_write(struct file *file, 1537static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
1538 const char __user *user_buf, 1538 const char __user *user_buf,
1539 size_t count, loff_t *ppos) { 1539 size_t count, loff_t *ppos) {
1540 1540
1541 struct iwl_priv *priv = file->private_data; 1541 struct iwl_priv *priv = file->private_data;
1542 char buf[8]; 1542 char buf[8];
1543 int buf_size; 1543 int buf_size;
1544 int period; 1544 int timeout;
1545 1545
1546 memset(buf, 0, sizeof(buf)); 1546 memset(buf, 0, sizeof(buf));
1547 buf_size = min(count, sizeof(buf) - 1); 1547 buf_size = min(count, sizeof(buf) - 1);
1548 if (copy_from_user(buf, user_buf, buf_size)) 1548 if (copy_from_user(buf, user_buf, buf_size))
1549 return -EFAULT; 1549 return -EFAULT;
1550 if (sscanf(buf, "%d", &period) != 1) 1550 if (sscanf(buf, "%d", &timeout) != 1)
1551 return -EINVAL; 1551 return -EINVAL;
1552 if (period < 0 || period > IWL_MAX_MONITORING_PERIOD) 1552 if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
1553 priv->cfg->base_params->monitor_recover_period = 1553 timeout = IWL_DEF_WD_TIMEOUT;
1554 IWL_DEF_MONITORING_PERIOD;
1555 else
1556 priv->cfg->base_params->monitor_recover_period = period;
1557 1554
1558 if (priv->cfg->base_params->monitor_recover_period) 1555 priv->cfg->base_params->wd_timeout = timeout;
1559 mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies( 1556 iwl_setup_watchdog(priv);
1560 priv->cfg->base_params->monitor_recover_period));
1561 else
1562 del_timer_sync(&priv->monitor_recover);
1563 return count; 1557 return count;
1564} 1558}
1565 1559
@@ -1686,7 +1680,7 @@ DEBUGFS_READ_FILE_OPS(rxon_flags);
1686DEBUGFS_READ_FILE_OPS(rxon_filter_flags); 1680DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
1687DEBUGFS_WRITE_FILE_OPS(txfifo_flush); 1681DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
1688DEBUGFS_READ_FILE_OPS(ucode_bt_stats); 1682DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
1689DEBUGFS_WRITE_FILE_OPS(monitor_period); 1683DEBUGFS_WRITE_FILE_OPS(wd_timeout);
1690DEBUGFS_READ_FILE_OPS(bt_traffic); 1684DEBUGFS_READ_FILE_OPS(bt_traffic);
1691DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); 1685DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
1692DEBUGFS_READ_FILE_OPS(reply_tx_error); 1686DEBUGFS_READ_FILE_OPS(reply_tx_error);
@@ -1763,7 +1757,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
1763 DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); 1757 DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
1764 DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); 1758 DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
1765 DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); 1759 DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
1766 DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR); 1760 DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
1767 if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) 1761 if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
1768 DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); 1762 DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
1769 if (priv->cfg->base_params->sensitivity_calib_by_driver) 1763 if (priv->cfg->base_params->sensitivity_calib_by_driver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index ea81ced13756..836f1816b110 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -129,9 +129,6 @@ struct iwl_queue {
129 int write_ptr; /* 1-st empty entry (index) host_w*/ 129 int write_ptr; /* 1-st empty entry (index) host_w*/
130 int read_ptr; /* last used entry (index) host_r*/ 130 int read_ptr; /* last used entry (index) host_r*/
131 /* use for monitoring and recovering the stuck queue */ 131 /* use for monitoring and recovering the stuck queue */
132 int last_read_ptr; /* storing the last read_ptr */
133 /* number of time read_ptr and last_read_ptr are the same */
134 u8 repeat_same_read_ptr;
135 dma_addr_t dma_addr; /* physical addr for BD's */ 132 dma_addr_t dma_addr; /* physical addr for BD's */
136 int n_window; /* safe queue window */ 133 int n_window; /* safe queue window */
137 u32 id; 134 u32 id;
@@ -155,6 +152,7 @@ struct iwl_tx_info {
155 * @meta: array of meta data for each command/tx buffer 152 * @meta: array of meta data for each command/tx buffer
156 * @dma_addr_cmd: physical address of cmd/tx buffer array 153 * @dma_addr_cmd: physical address of cmd/tx buffer array
157 * @txb: array of per-TFD driver data 154 * @txb: array of per-TFD driver data
155 * @time_stamp: time (in jiffies) of last read_ptr change
158 * @need_update: indicates need to update read/write index 156 * @need_update: indicates need to update read/write index
159 * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled 157 * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
160 * 158 *
@@ -170,6 +168,7 @@ struct iwl_tx_queue {
170 struct iwl_device_cmd **cmd; 168 struct iwl_device_cmd **cmd;
171 struct iwl_cmd_meta *meta; 169 struct iwl_cmd_meta *meta;
172 struct iwl_tx_info *txb; 170 struct iwl_tx_info *txb;
171 unsigned long time_stamp;
173 u8 need_update; 172 u8 need_update;
174 u8 sched_retry; 173 u8 sched_retry;
175 u8 active; 174 u8 active;
@@ -1104,11 +1103,10 @@ struct iwl_event_log {
1104#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) 1103#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
1105#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) 1104#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
1106 1105
1107/* timer constants use to monitor and recover stuck tx queues in mSecs */ 1106/* TX queue watchdog timeouts in mSecs */
1108#define IWL_DEF_MONITORING_PERIOD (1000) 1107#define IWL_DEF_WD_TIMEOUT (2000)
1109#define IWL_LONG_MONITORING_PERIOD (5000) 1108#define IWL_LONG_WD_TIMEOUT (10000)
1110#define IWL_ONE_HUNDRED_MSECS (100) 1109#define IWL_MAX_WD_TIMEOUT (120000)
1111#define IWL_MAX_MONITORING_PERIOD (60000)
1112 1110
1113/* BT Antenna Coupling Threshold (dB) */ 1111/* BT Antenna Coupling Threshold (dB) */
1114#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35) 1112#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
@@ -1544,7 +1542,7 @@ struct iwl_priv {
1544 struct work_struct run_time_calib_work; 1542 struct work_struct run_time_calib_work;
1545 struct timer_list statistics_periodic; 1543 struct timer_list statistics_periodic;
1546 struct timer_list ucode_trace; 1544 struct timer_list ucode_trace;
1547 struct timer_list monitor_recover; 1545 struct timer_list watchdog;
1548 bool hw_ready; 1546 bool hw_ready;
1549 1547
1550 struct iwl_event_log event_log; 1548 struct iwl_event_log event_log;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 90659bcf5804..073b6ce6141c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -263,8 +263,6 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
263 q->high_mark = 2; 263 q->high_mark = 2;
264 264
265 q->write_ptr = q->read_ptr = 0; 265 q->write_ptr = q->read_ptr = 0;
266 q->last_read_ptr = 0;
267 q->repeat_same_read_ptr = 0;
268 266
269 return 0; 267 return 0;
270} 268}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index cc282aa2f43c..371abbf60eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2509,13 +2509,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
2509 /* After the ALIVE response, we can send commands to 3945 uCode */ 2509 /* After the ALIVE response, we can send commands to 3945 uCode */
2510 set_bit(STATUS_ALIVE, &priv->status); 2510 set_bit(STATUS_ALIVE, &priv->status);
2511 2511
2512 if (priv->cfg->ops->lib->recover_from_tx_stall) { 2512 /* Enable watchdog to monitor the driver tx queues */
2513 /* Enable timer to monitor the driver queues */ 2513 iwl_setup_watchdog(priv);
2514 mod_timer(&priv->monitor_recover,
2515 jiffies +
2516 msecs_to_jiffies(
2517 priv->cfg->base_params->monitor_recover_period));
2518 }
2519 2514
2520 if (iwl_is_rfkill(priv)) 2515 if (iwl_is_rfkill(priv))
2521 return; 2516 return;
@@ -2572,8 +2567,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
2572 2567
2573 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set 2568 /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
2574 * to prevent rearm timer */ 2569 * to prevent rearm timer */
2575 if (priv->cfg->ops->lib->recover_from_tx_stall) 2570 del_timer_sync(&priv->watchdog);
2576 del_timer_sync(&priv->monitor_recover);
2577 2571
2578 /* Station information will now be cleared in device */ 2572 /* Station information will now be cleared in device */
2579 iwl_clear_ucode_stations(priv, NULL); 2573 iwl_clear_ucode_stations(priv, NULL);
@@ -3775,12 +3769,9 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
3775 3769
3776 iwl3945_hw_setup_deferred_work(priv); 3770 iwl3945_hw_setup_deferred_work(priv);
3777 3771
3778 if (priv->cfg->ops->lib->recover_from_tx_stall) { 3772 init_timer(&priv->watchdog);
3779 init_timer(&priv->monitor_recover); 3773 priv->watchdog.data = (unsigned long)priv;
3780 priv->monitor_recover.data = (unsigned long)priv; 3774 priv->watchdog.function = iwl_bg_watchdog;
3781 priv->monitor_recover.function =
3782 priv->cfg->ops->lib->recover_from_tx_stall;
3783 }
3784 3775
3785 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 3776 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
3786 iwl3945_irq_tasklet, (unsigned long)priv); 3777 iwl3945_irq_tasklet, (unsigned long)priv);