aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c93
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c16
11 files changed, 167 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index e31e8a3459b..5a9cb70160f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -212,6 +212,7 @@ static struct iwl_lib_ops iwl1000_lib = {
212 .set_ct_kill = iwl1000_set_ct_threshold, 212 .set_ct_kill = iwl1000_set_ct_threshold,
213 }, 213 },
214 .add_bcast_station = iwl_add_bcast_station, 214 .add_bcast_station = iwl_add_bcast_station,
215 .recover_from_tx_stall = iwl_bg_monitor_recover,
215}; 216};
216 217
217static const struct iwl_ops iwl1000_ops = { 218static const struct iwl_ops iwl1000_ops = {
@@ -249,6 +250,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
249 .support_ct_kill_exit = true, 250 .support_ct_kill_exit = true,
250 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, 251 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
251 .chain_noise_scale = 1000, 252 .chain_noise_scale = 1000,
253 .monitor_recover_period = IWL_MONITORING_PERIOD,
252}; 254};
253 255
254struct iwl_cfg iwl1000_bg_cfg = { 256struct iwl_cfg iwl1000_bg_cfg = {
@@ -277,6 +279,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
277 .support_ct_kill_exit = true, 279 .support_ct_kill_exit = true,
278 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, 280 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
279 .chain_noise_scale = 1000, 281 .chain_noise_scale = 1000,
282 .monitor_recover_period = IWL_MONITORING_PERIOD,
280}; 283};
281 284
282MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); 285MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 11785e2c767..21ae61dd3d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2820,6 +2820,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
2820 .led_compensation = 64, 2820 .led_compensation = 64,
2821 .broken_powersave = true, 2821 .broken_powersave = true,
2822 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 2822 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2823 .monitor_recover_period = IWL_MONITORING_PERIOD,
2823}; 2824};
2824 2825
2825static struct iwl_cfg iwl3945_abg_cfg = { 2826static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2838,6 +2839,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
2838 .led_compensation = 64, 2839 .led_compensation = 64,
2839 .broken_powersave = true, 2840 .broken_powersave = true,
2840 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 2841 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2842 .monitor_recover_period = IWL_MONITORING_PERIOD,
2841}; 2843};
2842 2844
2843DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { 2845DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 7f9e448fe5e..acca89a635a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2255,6 +2255,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
2255 .led_compensation = 61, 2255 .led_compensation = 61,
2256 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, 2256 .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
2257 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 2257 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
2258 .monitor_recover_period = IWL_MONITORING_PERIOD,
2258}; 2259};
2259 2260
2260/* Module firmware */ 2261/* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 8ab28a76015..a01b3c59a5a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1499,6 +1499,7 @@ struct iwl_lib_ops iwl5000_lib = {
1499 .set_ct_kill = iwl5000_set_ct_threshold, 1499 .set_ct_kill = iwl5000_set_ct_threshold,
1500 }, 1500 },
1501 .add_bcast_station = iwl_add_bcast_station, 1501 .add_bcast_station = iwl_add_bcast_station,
1502 .recover_from_tx_stall = iwl_bg_monitor_recover,
1502}; 1503};
1503 1504
1504static struct iwl_lib_ops iwl5150_lib = { 1505static struct iwl_lib_ops iwl5150_lib = {
@@ -1553,6 +1554,7 @@ static struct iwl_lib_ops iwl5150_lib = {
1553 .set_ct_kill = iwl5150_set_ct_threshold, 1554 .set_ct_kill = iwl5150_set_ct_threshold,
1554 }, 1555 },
1555 .add_bcast_station = iwl_add_bcast_station, 1556 .add_bcast_station = iwl_add_bcast_station,
1557 .recover_from_tx_stall = iwl_bg_monitor_recover,
1556}; 1558};
1557 1559
1558static const struct iwl_ops iwl5000_ops = { 1560static const struct iwl_ops iwl5000_ops = {
@@ -1602,6 +1604,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
1602 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1604 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1603 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1605 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1604 .chain_noise_scale = 1000, 1606 .chain_noise_scale = 1000,
1607 .monitor_recover_period = IWL_MONITORING_PERIOD,
1605}; 1608};
1606 1609
1607struct iwl_cfg iwl5100_bgn_cfg = { 1610struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1628,6 +1631,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
1628 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1631 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1629 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1632 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1630 .chain_noise_scale = 1000, 1633 .chain_noise_scale = 1000,
1634 .monitor_recover_period = IWL_MONITORING_PERIOD,
1631}; 1635};
1632 1636
1633struct iwl_cfg iwl5100_abg_cfg = { 1637struct iwl_cfg iwl5100_abg_cfg = {
@@ -1652,6 +1656,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
1652 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1656 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1653 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1657 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1654 .chain_noise_scale = 1000, 1658 .chain_noise_scale = 1000,
1659 .monitor_recover_period = IWL_MONITORING_PERIOD,
1655}; 1660};
1656 1661
1657struct iwl_cfg iwl5100_agn_cfg = { 1662struct iwl_cfg iwl5100_agn_cfg = {
@@ -1678,6 +1683,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
1678 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1683 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1679 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1684 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1680 .chain_noise_scale = 1000, 1685 .chain_noise_scale = 1000,
1686 .monitor_recover_period = IWL_MONITORING_PERIOD,
1681}; 1687};
1682 1688
1683struct iwl_cfg iwl5350_agn_cfg = { 1689struct iwl_cfg iwl5350_agn_cfg = {
@@ -1704,6 +1710,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
1704 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1710 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1705 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1711 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1706 .chain_noise_scale = 1000, 1712 .chain_noise_scale = 1000,
1713 .monitor_recover_period = IWL_MONITORING_PERIOD,
1707}; 1714};
1708 1715
1709struct iwl_cfg iwl5150_agn_cfg = { 1716struct iwl_cfg iwl5150_agn_cfg = {
@@ -1730,6 +1737,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
1730 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1737 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1731 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1738 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1732 .chain_noise_scale = 1000, 1739 .chain_noise_scale = 1000,
1740 .monitor_recover_period = IWL_MONITORING_PERIOD,
1733}; 1741};
1734 1742
1735struct iwl_cfg iwl5150_abg_cfg = { 1743struct iwl_cfg iwl5150_abg_cfg = {
@@ -1754,6 +1762,7 @@ struct iwl_cfg iwl5150_abg_cfg = {
1754 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, 1762 .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
1755 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, 1763 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
1756 .chain_noise_scale = 1000, 1764 .chain_noise_scale = 1000,
1765 .monitor_recover_period = IWL_MONITORING_PERIOD,
1757}; 1766};
1758 1767
1759MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); 1768MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index fb7012289c3..4fbc38cfd91 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -278,6 +278,7 @@ static struct iwl_lib_ops iwl6000_lib = {
278 .set_ct_kill = iwl6000_set_ct_threshold, 278 .set_ct_kill = iwl6000_set_ct_threshold,
279 }, 279 },
280 .add_bcast_station = iwl_add_bcast_station, 280 .add_bcast_station = iwl_add_bcast_station,
281 .recover_from_tx_stall = iwl_bg_monitor_recover,
281}; 282};
282 283
283static const struct iwl_ops iwl6000_ops = { 284static const struct iwl_ops iwl6000_ops = {
@@ -343,6 +344,7 @@ static struct iwl_lib_ops iwl6050_lib = {
343 .set_calib_version = iwl6050_set_calib_version, 344 .set_calib_version = iwl6050_set_calib_version,
344 }, 345 },
345 .add_bcast_station = iwl_add_bcast_station, 346 .add_bcast_station = iwl_add_bcast_station,
347 .recover_from_tx_stall = iwl_bg_monitor_recover,
346}; 348};
347 349
348static const struct iwl_ops iwl6050_ops = { 350static const struct iwl_ops iwl6050_ops = {
@@ -386,6 +388,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
386 .support_ct_kill_exit = true, 388 .support_ct_kill_exit = true,
387 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 389 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
388 .chain_noise_scale = 1000, 390 .chain_noise_scale = 1000,
391 .monitor_recover_period = IWL_MONITORING_PERIOD,
389}; 392};
390 393
391struct iwl_cfg iwl6000i_2abg_cfg = { 394struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -417,6 +420,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
417 .support_ct_kill_exit = true, 420 .support_ct_kill_exit = true,
418 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 421 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
419 .chain_noise_scale = 1000, 422 .chain_noise_scale = 1000,
423 .monitor_recover_period = IWL_MONITORING_PERIOD,
420}; 424};
421 425
422struct iwl_cfg iwl6000i_2bg_cfg = { 426struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -448,6 +452,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
448 .support_ct_kill_exit = true, 452 .support_ct_kill_exit = true,
449 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 453 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
450 .chain_noise_scale = 1000, 454 .chain_noise_scale = 1000,
455 .monitor_recover_period = IWL_MONITORING_PERIOD,
451}; 456};
452 457
453struct iwl_cfg iwl6050_2agn_cfg = { 458struct iwl_cfg iwl6050_2agn_cfg = {
@@ -480,6 +485,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
480 .support_ct_kill_exit = true, 485 .support_ct_kill_exit = true,
481 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 486 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
482 .chain_noise_scale = 1500, 487 .chain_noise_scale = 1500,
488 .monitor_recover_period = IWL_MONITORING_PERIOD,
483}; 489};
484 490
485struct iwl_cfg iwl6050_2abg_cfg = { 491struct iwl_cfg iwl6050_2abg_cfg = {
@@ -511,6 +517,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
511 .support_ct_kill_exit = true, 517 .support_ct_kill_exit = true,
512 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 518 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
513 .chain_noise_scale = 1500, 519 .chain_noise_scale = 1500,
520 .monitor_recover_period = IWL_MONITORING_PERIOD,
514}; 521};
515 522
516struct iwl_cfg iwl6000_3agn_cfg = { 523struct iwl_cfg iwl6000_3agn_cfg = {
@@ -543,6 +550,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
543 .support_ct_kill_exit = true, 550 .support_ct_kill_exit = true,
544 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, 551 .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
545 .chain_noise_scale = 1000, 552 .chain_noise_scale = 1000,
553 .monitor_recover_period = IWL_MONITORING_PERIOD,
546}; 554};
547 555
548MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); 556MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 93931b61304..82b1a3fb54e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2074,6 +2074,13 @@ static void iwl_alive_start(struct iwl_priv *priv)
2074 /* After the ALIVE response, we can send host commands to the uCode */ 2074 /* After the ALIVE response, we can send host commands to the uCode */
2075 set_bit(STATUS_ALIVE, &priv->status); 2075 set_bit(STATUS_ALIVE, &priv->status);
2076 2076
2077 if (priv->cfg->ops->lib->recover_from_tx_stall) {
2078 /* Enable timer to monitor the driver queues */
2079 mod_timer(&priv->monitor_recover,
2080 jiffies +
2081 msecs_to_jiffies(priv->cfg->monitor_recover_period));
2082 }
2083
2077 if (iwl_is_rfkill(priv)) 2084 if (iwl_is_rfkill(priv))
2078 return; 2085 return;
2079 2086
@@ -3224,6 +3231,13 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3224 priv->ucode_trace.data = (unsigned long)priv; 3231 priv->ucode_trace.data = (unsigned long)priv;
3225 priv->ucode_trace.function = iwl_bg_ucode_trace; 3232 priv->ucode_trace.function = iwl_bg_ucode_trace;
3226 3233
3234 if (priv->cfg->ops->lib->recover_from_tx_stall) {
3235 init_timer(&priv->monitor_recover);
3236 priv->monitor_recover.data = (unsigned long)priv;
3237 priv->monitor_recover.function =
3238 priv->cfg->ops->lib->recover_from_tx_stall;
3239 }
3240
3227 if (!priv->cfg->use_isr_legacy) 3241 if (!priv->cfg->use_isr_legacy)
3228 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 3242 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
3229 iwl_irq_tasklet, (unsigned long)priv); 3243 iwl_irq_tasklet, (unsigned long)priv);
@@ -3243,6 +3257,8 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
3243 cancel_work_sync(&priv->beacon_update); 3257 cancel_work_sync(&priv->beacon_update);
3244 del_timer_sync(&priv->statistics_periodic); 3258 del_timer_sync(&priv->statistics_periodic);
3245 del_timer_sync(&priv->ucode_trace); 3259 del_timer_sync(&priv->ucode_trace);
3260 if (priv->cfg->ops->lib->recover_from_tx_stall)
3261 del_timer_sync(&priv->monitor_recover);
3246} 3262}
3247 3263
3248static void iwl_init_hw_rates(struct iwl_priv *priv, 3264static void iwl_init_hw_rates(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index d4c2a3e17c5..5180fb24cd3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -3051,6 +3051,99 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
3051 } 3051 }
3052 return 0; 3052 return 0;
3053} 3053}
3054EXPORT_SYMBOL(iwl_force_reset);
3055
3056/**
3057 * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
3058 *
3059 * During normal condition (no queue is stuck), the timer is continually set to
3060 * execute every monitor_recover_period milliseconds after the last timer
3061 * expired. When the queue read_ptr is at the same place, the timer is
3062 * shorten to 100mSecs. This is
3063 * 1) to reduce the chance that the read_ptr may wrap around (not stuck)
3064 * 2) to detect the stuck queues quicker before the station and AP can
3065 * disassociate each other.
3066 *
3067 * This function monitors all the tx queues and recover from it if any
3068 * of the queues are stuck.
3069 * 1. It first check the cmd queue for stuck conditions. If it is stuck,
3070 * it will recover by resetting the firmware and return.
3071 * 2. Then, it checks for station association. If it associates it will check
3072 * other queues. If any queue is stuck, it will recover by resetting
3073 * the firmware.
3074 * Note: It the number of times the queue read_ptr to be at the same place to
3075 * be MAX_REPEAT+1 in order to consider to be stuck.
3076 */
3077/*
3078 * The maximum number of times the read pointer of the tx queue at the
3079 * same place without considering to be stuck.
3080 */
3081#define MAX_REPEAT (2)
3082static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
3083{
3084 struct iwl_tx_queue *txq;
3085 struct iwl_queue *q;
3086
3087 txq = &priv->txq[cnt];
3088 q = &txq->q;
3089 /* queue is empty, skip */
3090 if (q->read_ptr != q->write_ptr) {
3091 if (q->read_ptr == q->last_read_ptr) {
3092 /* a queue has not been read from last time */
3093 if (q->repeat_same_read_ptr > MAX_REPEAT) {
3094 IWL_ERR(priv,
3095 "queue %d stuck %d time. Fw reload.\n",
3096 q->id, q->repeat_same_read_ptr);
3097 q->repeat_same_read_ptr = 0;
3098 iwl_force_reset(priv, IWL_FW_RESET);
3099 } else {
3100 q->repeat_same_read_ptr++;
3101 IWL_DEBUG_RADIO(priv,
3102 "queue %d, not read %d time\n",
3103 q->id,
3104 q->repeat_same_read_ptr);
3105 mod_timer(&priv->monitor_recover, jiffies +
3106 msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
3107 }
3108 return 1;
3109 } else {
3110 q->last_read_ptr = q->read_ptr;
3111 q->repeat_same_read_ptr = 0;
3112 }
3113 }
3114 return 0;
3115}
3116
3117void iwl_bg_monitor_recover(unsigned long data)
3118{
3119 struct iwl_priv *priv = (struct iwl_priv *)data;
3120 int cnt;
3121
3122 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
3123 return;
3124
3125 /* monitor and check for stuck cmd queue */
3126 if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
3127 return;
3128
3129 /* monitor and check for other stuck queues */
3130 if (iwl_is_associated(priv)) {
3131 for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
3132 /* skip as we already checked the command queue */
3133 if (cnt == IWL_CMD_QUEUE_NUM)
3134 continue;
3135 if (iwl_check_stuck_queue(priv, cnt))
3136 return;
3137 }
3138 }
3139 /*
3140 * Reschedule the timer to occur in
3141 * priv->cfg->monitor_recover_period
3142 */
3143 mod_timer(&priv->monitor_recover,
3144 jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
3145}
3146EXPORT_SYMBOL(iwl_bg_monitor_recover);
3054 3147
3055#ifdef CONFIG_PM 3148#ifdef CONFIG_PM
3056 3149
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 2482a25d543..c4cd1deb3b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -191,6 +191,8 @@ struct iwl_lib_ops {
191 struct iwl_temp_ops temp_ops; 191 struct iwl_temp_ops temp_ops;
192 /* station management */ 192 /* station management */
193 void (*add_bcast_station)(struct iwl_priv *priv); 193 void (*add_bcast_station)(struct iwl_priv *priv);
194 /* recover from tx queue stall */
195 void (*recover_from_tx_stall)(unsigned long data);
194}; 196};
195 197
196struct iwl_led_ops { 198struct iwl_led_ops {
@@ -295,6 +297,8 @@ struct iwl_cfg {
295 const bool support_wimax_coexist; 297 const bool support_wimax_coexist;
296 u8 plcp_delta_threshold; 298 u8 plcp_delta_threshold;
297 s32 chain_noise_scale; 299 s32 chain_noise_scale;
300 /* timer period for monitor the driver queues */
301 u32 monitor_recover_period;
298}; 302};
299 303
300/*************************** 304/***************************
@@ -568,6 +572,9 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
568 pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); 572 pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
569 return pci_lnk_ctl; 573 return pci_lnk_ctl;
570} 574}
575
576void iwl_bg_monitor_recover(unsigned long data);
577
571#ifdef CONFIG_PM 578#ifdef CONFIG_PM
572int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); 579int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
573int iwl_pci_resume(struct pci_dev *pdev); 580int iwl_pci_resume(struct pci_dev *pdev);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 9c676ea420b..bb4cba508ac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -183,6 +183,10 @@ struct iwl_queue {
183 int n_bd; /* number of BDs in this queue */ 183 int n_bd; /* number of BDs in this queue */
184 int write_ptr; /* 1-st empty entry (index) host_w*/ 184 int write_ptr; /* 1-st empty entry (index) host_w*/
185 int read_ptr; /* last used entry (index) host_r*/ 185 int read_ptr; /* last used entry (index) host_r*/
186 /* use for monitoring and recovering the stuck queue */
187 int last_read_ptr; /* storing the last read_ptr */
188 /* number of time read_ptr and last_read_ptr are the same */
189 u8 repeat_same_read_ptr;
186 dma_addr_t dma_addr; /* physical addr for BD's */ 190 dma_addr_t dma_addr; /* physical addr for BD's */
187 int n_window; /* safe queue window */ 191 int n_window; /* safe queue window */
188 u32 id; 192 u32 id;
@@ -1044,6 +1048,11 @@ struct iwl_event_log {
1044#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) 1048#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
1045#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) 1049#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
1046 1050
1051/* timer constants use to monitor and recover stuck tx queues in mSecs */
1052#define IWL_MONITORING_PERIOD (1000)
1053#define IWL_ONE_HUNDRED_MSECS (100)
1054#define IWL_SIXTY_SECS (60000)
1055
1047enum iwl_reset { 1056enum iwl_reset {
1048 IWL_RF_RESET = 0, 1057 IWL_RF_RESET = 0,
1049 IWL_FW_RESET, 1058 IWL_FW_RESET,
@@ -1354,6 +1363,7 @@ struct iwl_priv {
1354 struct work_struct run_time_calib_work; 1363 struct work_struct run_time_calib_work;
1355 struct timer_list statistics_periodic; 1364 struct timer_list statistics_periodic;
1356 struct timer_list ucode_trace; 1365 struct timer_list ucode_trace;
1366 struct timer_list monitor_recover;
1357 bool hw_ready; 1367 bool hw_ready;
1358 1368
1359 struct iwl_event_log event_log; 1369 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 045e4a67344..34c983833a8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -322,6 +322,8 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
322 q->high_mark = 2; 322 q->high_mark = 2;
323 323
324 q->write_ptr = q->read_ptr = 0; 324 q->write_ptr = q->read_ptr = 0;
325 q->last_read_ptr = 0;
326 q->repeat_same_read_ptr = 0;
325 327
326 return 0; 328 return 0;
327} 329}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 6687b945655..4995134d7e4 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2501,6 +2501,13 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
2501 /* After the ALIVE response, we can send commands to 3945 uCode */ 2501 /* After the ALIVE response, we can send commands to 3945 uCode */
2502 set_bit(STATUS_ALIVE, &priv->status); 2502 set_bit(STATUS_ALIVE, &priv->status);
2503 2503
2504 if (priv->cfg->ops->lib->recover_from_tx_stall) {
2505 /* Enable timer to monitor the driver queues */
2506 mod_timer(&priv->monitor_recover,
2507 jiffies +
2508 msecs_to_jiffies(priv->cfg->monitor_recover_period));
2509 }
2510
2504 if (iwl_is_rfkill(priv)) 2511 if (iwl_is_rfkill(priv))
2505 return; 2512 return;
2506 2513
@@ -3796,6 +3803,13 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
3796 3803
3797 iwl3945_hw_setup_deferred_work(priv); 3804 iwl3945_hw_setup_deferred_work(priv);
3798 3805
3806 if (priv->cfg->ops->lib->recover_from_tx_stall) {
3807 init_timer(&priv->monitor_recover);
3808 priv->monitor_recover.data = (unsigned long)priv;
3809 priv->monitor_recover.function =
3810 priv->cfg->ops->lib->recover_from_tx_stall;
3811 }
3812
3799 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 3813 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
3800 iwl3945_irq_tasklet, (unsigned long)priv); 3814 iwl3945_irq_tasklet, (unsigned long)priv);
3801} 3815}
@@ -3808,6 +3822,8 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
3808 cancel_delayed_work(&priv->scan_check); 3822 cancel_delayed_work(&priv->scan_check);
3809 cancel_delayed_work(&priv->alive_start); 3823 cancel_delayed_work(&priv->alive_start);
3810 cancel_work_sync(&priv->beacon_update); 3824 cancel_work_sync(&priv->beacon_update);
3825 if (priv->cfg->ops->lib->recover_from_tx_stall)
3826 del_timer_sync(&priv->monitor_recover);
3811} 3827}
3812 3828
3813static struct attribute *iwl3945_sysfs_entries[] = { 3829static struct attribute *iwl3945_sysfs_entries[] = {