iwmc3200wifi: Handle UMAC stalls and UMAC assert properly
authorSamuel Ortiz <sameo@linux.intel.com>
Tue, 1 Sep 2009 13:14:05 +0000 (15:14 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 1 Sep 2009 16:48:28 +0000 (12:48 -0400)
When UMAC stalls or asserts, we want to reset the device. But when we're
associated, the current reset worker will end up calling
cfg80211_connect_result() with the cfg80211 sme layer knowing that we're
reassociating. That ends up with some ugly warnings.
With this patch we're telling the upper layer that we've roamed if
reassociation succeeds, and that we're disconnected if it fails.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/main.c
drivers/net/wireless/iwmc3200wifi/rx.c

index 74964ee93bb7519915baa68bf9d5f35d774d4fda..f5c2d6f3fd43d8efcf103582b02135ab7c005845 100644 (file)
@@ -178,6 +178,7 @@ struct iwm_key {
 #define IWM_STATUS_SCAN_ABORTING       2
 #define IWM_STATUS_SME_CONNECTING      3
 #define IWM_STATUS_ASSOCIATED          4
+#define IWM_STATUS_RESETTING           5
 
 struct iwm_tx_queue {
        int id;
@@ -317,6 +318,7 @@ int iwm_mode_to_nl80211_iftype(int mode);
 int iwm_priv_init(struct iwm_priv *iwm);
 void iwm_priv_deinit(struct iwm_priv *iwm);
 void iwm_reset(struct iwm_priv *iwm);
+void iwm_resetting(struct iwm_priv *iwm);
 void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
                              struct iwm_umac_notif_alive *alive);
 int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb);
index fc7fce44a9d795c129d90838ca441bce6682129d..6a5b76acb64547b0cca0854ee80421958160d73f 100644 (file)
@@ -187,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work)
                memcpy(iwm->umac_profile, profile, sizeof(*profile));
                iwm_send_mlme_profile(iwm);
                kfree(profile);
-       }
+       } else
+               clear_bit(IWM_STATUS_RESETTING, &iwm->status);
 
  out:
        mutex_unlock(&iwm->mutex);
@@ -200,7 +201,7 @@ static void iwm_watchdog(unsigned long data)
        IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
 
        if (modparam_reset)
-               schedule_work(&iwm->reset_worker);
+               iwm_resetting(iwm);
 }
 
 int iwm_priv_init(struct iwm_priv *iwm)
@@ -284,7 +285,11 @@ void iwm_reset(struct iwm_priv *iwm)
        if (test_bit(IWM_STATUS_READY, &iwm->status))
                iwm_target_reset(iwm);
 
-       iwm->status = 0;
+       if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) {
+               iwm->status = 0;
+               set_bit(IWM_STATUS_RESETTING, &iwm->status);
+       } else
+               iwm->status = 0;
        iwm->scan_id = 1;
 
        list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
@@ -300,6 +305,13 @@ void iwm_reset(struct iwm_priv *iwm)
        iwm_link_off(iwm);
 }
 
+void iwm_resetting(struct iwm_priv *iwm)
+{
+       set_bit(IWM_STATUS_RESETTING, &iwm->status);
+
+       schedule_work(&iwm->reset_worker);
+}
+
 /*
  * Notification code:
  *
index 2daa58633e6fd1609bbbe36d84da1a4485fdefa7..14950b147f9138a4054cc4a6d638eeb2f704837d 100644 (file)
@@ -118,6 +118,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
        IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status));
        IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status));
 
+       iwm_resetting(iwm);
+
        return 0;
 }
 
@@ -528,11 +530,19 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                if (iwm->conf.mode == UMAC_MODE_IBSS)
                        goto ibss;
 
-               cfg80211_connect_result(iwm_to_ndev(iwm),
+               if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+                       cfg80211_connect_result(iwm_to_ndev(iwm),
+                                               complete->bssid,
+                                               iwm->req_ie, iwm->req_ie_len,
+                                               iwm->resp_ie, iwm->resp_ie_len,
+                                               WLAN_STATUS_SUCCESS,
+                                               GFP_KERNEL);
+               else
+                       cfg80211_roamed(iwm_to_ndev(iwm),
                                        complete->bssid,
                                        iwm->req_ie, iwm->req_ie_len,
                                        iwm->resp_ie, iwm->resp_ie_len,
-                                       WLAN_STATUS_SUCCESS, GFP_KERNEL);
+                                       GFP_KERNEL);
                break;
        case UMAC_ASSOC_COMPLETE_FAILURE:
                clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -551,19 +561,26 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                if (iwm->conf.mode == UMAC_MODE_IBSS)
                        goto ibss;
 
-               cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
-                                       NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                       GFP_KERNEL);
+               if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
+                       cfg80211_connect_result(iwm_to_ndev(iwm),
+                                               complete->bssid,
+                                               NULL, 0, NULL, 0,
+                                               WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                               GFP_KERNEL);
+               else
+                       cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
+                                             GFP_KERNEL);
                break;
        default:
                break;
        }
 
+       clear_bit(IWM_STATUS_RESETTING, &iwm->status);
        return 0;
 
  ibss:
        cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
+       clear_bit(IWM_STATUS_RESETTING, &iwm->status);
        return 0;
 }