diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-02-03 14:47:19 -0500 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-02-11 13:24:12 -0500 |
commit | a93e7973d0983d22fcbe5f691244736211639fe7 (patch) | |
tree | 161f64fa2297146b8263ea120638404f97fc288c /drivers | |
parent | dff010ac8e57e43669518a14c0e945dfeb80c2a7 (diff) |
iwlwifi: multiple force reset mode
Provide the function to perform different type of uCode reset/reload operation.
When uCode detect error and can not fix itself, this iwl_force_reset()
function allow driver to perform the necessary reset/reload functions and help
to bring uCode back to normal operation state.
Currently only 2 type of force reset are available:
- reset radio
- reload firmware
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 10 |
5 files changed, 52 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d390eef2efe5..500ced452098 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) | |||
3334 | } | 3334 | } |
3335 | EXPORT_SYMBOL(iwl_dump_fh); | 3335 | EXPORT_SYMBOL(iwl_dump_fh); |
3336 | 3336 | ||
3337 | void iwl_force_rf_reset(struct iwl_priv *priv) | 3337 | static void iwl_force_rf_reset(struct iwl_priv *priv) |
3338 | { | 3338 | { |
3339 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 3339 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
3340 | return; | 3340 | return; |
@@ -3356,7 +3356,47 @@ void iwl_force_rf_reset(struct iwl_priv *priv) | |||
3356 | iwl_internal_short_hw_scan(priv); | 3356 | iwl_internal_short_hw_scan(priv); |
3357 | return; | 3357 | return; |
3358 | } | 3358 | } |
3359 | EXPORT_SYMBOL(iwl_force_rf_reset); | 3359 | |
3360 | #define IWL_DELAY_NEXT_FORCE_RESET (HZ*3) | ||
3361 | |||
3362 | int iwl_force_reset(struct iwl_priv *priv, int mode) | ||
3363 | { | ||
3364 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
3365 | return -EINVAL; | ||
3366 | |||
3367 | if (priv->last_force_reset_jiffies && | ||
3368 | time_after(priv->last_force_reset_jiffies + | ||
3369 | IWL_DELAY_NEXT_FORCE_RESET, jiffies)) { | ||
3370 | IWL_DEBUG_INFO(priv, "force reset rejected\n"); | ||
3371 | return -EAGAIN; | ||
3372 | } | ||
3373 | |||
3374 | IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode); | ||
3375 | |||
3376 | switch (mode) { | ||
3377 | case IWL_RF_RESET: | ||
3378 | iwl_force_rf_reset(priv); | ||
3379 | break; | ||
3380 | case IWL_FW_RESET: | ||
3381 | IWL_ERR(priv, "On demand firmware reload\n"); | ||
3382 | /* Set the FW error flag -- cleared on iwl_down */ | ||
3383 | set_bit(STATUS_FW_ERROR, &priv->status); | ||
3384 | wake_up_interruptible(&priv->wait_command_queue); | ||
3385 | /* | ||
3386 | * Keep the restart process from trying to send host | ||
3387 | * commands by clearing the INIT status bit | ||
3388 | */ | ||
3389 | clear_bit(STATUS_READY, &priv->status); | ||
3390 | queue_work(priv->workqueue, &priv->restart); | ||
3391 | break; | ||
3392 | default: | ||
3393 | IWL_DEBUG_INFO(priv, "invalid reset request.\n"); | ||
3394 | return -EINVAL; | ||
3395 | } | ||
3396 | priv->last_force_reset_jiffies = jiffies; | ||
3397 | |||
3398 | return 0; | ||
3399 | } | ||
3360 | 3400 | ||
3361 | #ifdef CONFIG_PM | 3401 | #ifdef CONFIG_PM |
3362 | 3402 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8f0c564e68b0..df558796fbe6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -501,7 +501,7 @@ int iwl_scan_cancel(struct iwl_priv *priv); | |||
501 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); | 501 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); |
502 | int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); | 502 | int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); |
503 | int iwl_internal_short_hw_scan(struct iwl_priv *priv); | 503 | int iwl_internal_short_hw_scan(struct iwl_priv *priv); |
504 | void iwl_force_rf_reset(struct iwl_priv *priv); | 504 | int iwl_force_reset(struct iwl_priv *priv, int mode); |
505 | u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, | 505 | u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, |
506 | const u8 *ie, int ie_len, int left); | 506 | const u8 *ie, int ie_len, int left); |
507 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); | 507 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 55dc5a866542..9f1d302e3a34 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1035,6 +1035,11 @@ struct iwl_event_log { | |||
1035 | #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) | 1035 | #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) |
1036 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) | 1036 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) |
1037 | 1037 | ||
1038 | enum iwl_reset { | ||
1039 | IWL_RF_RESET = 0, | ||
1040 | IWL_FW_RESET, | ||
1041 | }; | ||
1042 | |||
1038 | struct iwl_priv { | 1043 | struct iwl_priv { |
1039 | 1044 | ||
1040 | /* ieee device used by generic ieee processing code */ | 1045 | /* ieee device used by generic ieee processing code */ |
@@ -1066,6 +1071,9 @@ struct iwl_priv { | |||
1066 | /* storing the jiffies when the plcp error rate is received */ | 1071 | /* storing the jiffies when the plcp error rate is received */ |
1067 | unsigned long plcp_jiffies; | 1072 | unsigned long plcp_jiffies; |
1068 | 1073 | ||
1074 | /* force reset */ | ||
1075 | unsigned long last_force_reset_jiffies; | ||
1076 | |||
1069 | /* we allocate array of iwl4965_channel_info for NIC's valid channels. | 1077 | /* we allocate array of iwl4965_channel_info for NIC's valid channels. |
1070 | * Access via channel # using indirect index array */ | 1078 | * Access via channel # using indirect index array */ |
1071 | struct iwl_channel_info *channel_info; /* channel info array */ | 1079 | struct iwl_channel_info *channel_info; /* channel info array */ |
@@ -1087,7 +1095,6 @@ struct iwl_priv { | |||
1087 | unsigned long scan_start; | 1095 | unsigned long scan_start; |
1088 | unsigned long scan_pass_start; | 1096 | unsigned long scan_pass_start; |
1089 | unsigned long scan_start_tsf; | 1097 | unsigned long scan_start_tsf; |
1090 | unsigned long last_internal_scan_jiffies; | ||
1091 | void *scan; | 1098 | void *scan; |
1092 | int scan_bands; | 1099 | int scan_bands; |
1093 | struct cfg80211_scan_request *scan_request; | 1100 | struct cfg80211_scan_request *scan_request; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5df66382d922..909d9c9b9ad8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -689,7 +689,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
689 | * Reset the RF radio due to the high plcp | 689 | * Reset the RF radio due to the high plcp |
690 | * error rate | 690 | * error rate |
691 | */ | 691 | */ |
692 | iwl_force_rf_reset(priv); | 692 | iwl_force_reset(priv, IWL_RF_RESET); |
693 | } | 693 | } |
694 | } | 694 | } |
695 | 695 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index f786a407638f..501477464e07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, | |||
250 | 250 | ||
251 | if (!priv->is_internal_short_scan) | 251 | if (!priv->is_internal_short_scan) |
252 | priv->next_scan_jiffies = 0; | 252 | priv->next_scan_jiffies = 0; |
253 | else | ||
254 | priv->last_internal_scan_jiffies = jiffies; | ||
255 | 253 | ||
256 | IWL_DEBUG_INFO(priv, "Setting scan to off\n"); | 254 | IWL_DEBUG_INFO(priv, "Setting scan to off\n"); |
257 | 255 | ||
@@ -551,8 +549,6 @@ EXPORT_SYMBOL(iwl_mac_hw_scan); | |||
551 | * internal short scan, this function should only been called while associated. | 549 | * internal short scan, this function should only been called while associated. |
552 | * It will reset and tune the radio to prevent possible RF related problem | 550 | * It will reset and tune the radio to prevent possible RF related problem |
553 | */ | 551 | */ |
554 | #define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1) | ||
555 | |||
556 | int iwl_internal_short_hw_scan(struct iwl_priv *priv) | 552 | int iwl_internal_short_hw_scan(struct iwl_priv *priv) |
557 | { | 553 | { |
558 | int ret = 0; | 554 | int ret = 0; |
@@ -572,12 +568,6 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv) | |||
572 | ret = -EAGAIN; | 568 | ret = -EAGAIN; |
573 | goto out; | 569 | goto out; |
574 | } | 570 | } |
575 | if (priv->last_internal_scan_jiffies && | ||
576 | time_after(priv->last_internal_scan_jiffies + | ||
577 | IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) { | ||
578 | IWL_DEBUG_SCAN(priv, "internal scan rejected\n"); | ||
579 | goto out; | ||
580 | } | ||
581 | 571 | ||
582 | priv->scan_bands = 0; | 572 | priv->scan_bands = 0; |
583 | if (priv->band == IEEE80211_BAND_5GHZ) | 573 | if (priv->band == IEEE80211_BAND_5GHZ) |