diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-1000.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 93 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 16 |
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 | ||
217 | static const struct iwl_ops iwl1000_ops = { | 218 | static 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 | ||
254 | struct iwl_cfg iwl1000_bg_cfg = { | 256 | struct 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 | ||
282 | MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); | 285 | MODULE_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 | ||
2825 | static struct iwl_cfg iwl3945_abg_cfg = { | 2826 | static 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 | ||
2843 | DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { | 2845 | DEFINE_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 | ||
1504 | static struct iwl_lib_ops iwl5150_lib = { | 1505 | static 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 | ||
1558 | static const struct iwl_ops iwl5000_ops = { | 1560 | static 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 | ||
1607 | struct iwl_cfg iwl5100_bgn_cfg = { | 1610 | struct 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 | ||
1633 | struct iwl_cfg iwl5100_abg_cfg = { | 1637 | struct 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 | ||
1657 | struct iwl_cfg iwl5100_agn_cfg = { | 1662 | struct 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 | ||
1683 | struct iwl_cfg iwl5350_agn_cfg = { | 1689 | struct 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 | ||
1709 | struct iwl_cfg iwl5150_agn_cfg = { | 1716 | struct 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 | ||
1735 | struct iwl_cfg iwl5150_abg_cfg = { | 1743 | struct 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 | ||
1759 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); | 1768 | MODULE_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 | ||
283 | static const struct iwl_ops iwl6000_ops = { | 284 | static 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 | ||
348 | static const struct iwl_ops iwl6050_ops = { | 350 | static 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 | ||
391 | struct iwl_cfg iwl6000i_2abg_cfg = { | 394 | struct 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 | ||
422 | struct iwl_cfg iwl6000i_2bg_cfg = { | 426 | struct 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 | ||
453 | struct iwl_cfg iwl6050_2agn_cfg = { | 458 | struct 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 | ||
485 | struct iwl_cfg iwl6050_2abg_cfg = { | 491 | struct 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 | ||
516 | struct iwl_cfg iwl6000_3agn_cfg = { | 523 | struct 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 | ||
548 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); | 556 | MODULE_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 | ||
3248 | static void iwl_init_hw_rates(struct iwl_priv *priv, | 3264 | static 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 | } |
3054 | EXPORT_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) | ||
3082 | static 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 | |||
3117 | void 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 | } | ||
3146 | EXPORT_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 | ||
196 | struct iwl_led_ops { | 198 | struct 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 | |||
576 | void iwl_bg_monitor_recover(unsigned long data); | ||
577 | |||
571 | #ifdef CONFIG_PM | 578 | #ifdef CONFIG_PM |
572 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); | 579 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); |
573 | int iwl_pci_resume(struct pci_dev *pdev); | 580 | int 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 | |||
1047 | enum iwl_reset { | 1056 | enum 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 | ||
3813 | static struct attribute *iwl3945_sysfs_entries[] = { | 3829 | static struct attribute *iwl3945_sysfs_entries[] = { |