diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-1000.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 111 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debugfs.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 21 |
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 | } |
1895 | EXPORT_SYMBOL(iwl_mac_change_interface); | 1895 | EXPORT_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) | ||
1923 | static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) | 1901 | static 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 | ||
1960 | void 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 | */ | ||
1936 | void 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 | } |
1991 | EXPORT_SYMBOL(iwl_bg_monitor_recover); | 1967 | EXPORT_SYMBOL(iwl_bg_watchdog); |
1968 | |||
1969 | void 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 | } | ||
1979 | EXPORT_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, | |||
546 | void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, | 543 | void 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); |
548 | void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); | 545 | void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); |
546 | void 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 | ||
628 | void iwl_bg_monitor_recover(unsigned long data); | 626 | void iwl_bg_watchdog(unsigned long data); |
629 | u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); | 627 | u32 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 | ||
1537 | static ssize_t iwl_dbgfs_monitor_period_write(struct file *file, | 1537 | static 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); | |||
1686 | DEBUGFS_READ_FILE_OPS(rxon_filter_flags); | 1680 | DEBUGFS_READ_FILE_OPS(rxon_filter_flags); |
1687 | DEBUGFS_WRITE_FILE_OPS(txfifo_flush); | 1681 | DEBUGFS_WRITE_FILE_OPS(txfifo_flush); |
1688 | DEBUGFS_READ_FILE_OPS(ucode_bt_stats); | 1682 | DEBUGFS_READ_FILE_OPS(ucode_bt_stats); |
1689 | DEBUGFS_WRITE_FILE_OPS(monitor_period); | 1683 | DEBUGFS_WRITE_FILE_OPS(wd_timeout); |
1690 | DEBUGFS_READ_FILE_OPS(bt_traffic); | 1684 | DEBUGFS_READ_FILE_OPS(bt_traffic); |
1691 | DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); | 1685 | DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); |
1692 | DEBUGFS_READ_FILE_OPS(reply_tx_error); | 1686 | DEBUGFS_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); |