* the firmware image is swapped.
         */
        struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
+
+       /* async firmware loading state */
+       unsigned fw_state;
+       char *fw_pref;
+       char *fw_alt;
+       struct completion firmware_loading_complete;
 };
 
 /* Per interface specific private data */
        mwl8k_release_fw(&priv->fw_helper);
 }
 
+/* states for asynchronous f/w loading */
+static void mwl8k_fw_state_machine(const struct firmware *fw, void *context);
+enum {
+       FW_STATE_INIT = 0,
+       FW_STATE_LOADING_PREF,
+       FW_STATE_LOADING_ALT,
+       FW_STATE_ERROR,
+};
+
 /* Request fw image */
 static int mwl8k_request_fw(struct mwl8k_priv *priv,
-                           const char *fname, struct firmware **fw)
+                           const char *fname, struct firmware **fw,
+                           bool nowait)
 {
        /* release current image */
        if (*fw != NULL)
                mwl8k_release_fw(fw);
 
-       return request_firmware((const struct firmware **)fw,
-                               fname, &priv->pdev->dev);
+       if (nowait)
+               return request_firmware_nowait(THIS_MODULE, 1, fname,
+                                              &priv->pdev->dev, GFP_KERNEL,
+                                              priv, mwl8k_fw_state_machine);
+       else
+               return request_firmware((const struct firmware **)fw,
+                                       fname, &priv->pdev->dev);
 }
 
-static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image)
+static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image,
+                                 bool nowait)
 {
        struct mwl8k_device_info *di = priv->device_info;
        int rc;
 
        if (di->helper_image != NULL) {
-               rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
-               if (rc) {
-                       printk(KERN_ERR "%s: Error requesting helper "
-                              "firmware file %s\n", pci_name(priv->pdev),
-                              di->helper_image);
+               if (nowait)
+                       rc = mwl8k_request_fw(priv, di->helper_image,
+                                             &priv->fw_helper, true);
+               else
+                       rc = mwl8k_request_fw(priv, di->helper_image,
+                                             &priv->fw_helper, false);
+               if (rc)
+                       printk(KERN_ERR "%s: Error requesting helper fw %s\n",
+                              pci_name(priv->pdev), di->helper_image);
+
+               if (rc || nowait)
                        return rc;
-               }
        }
 
-       rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode);
+       if (nowait) {
+               /*
+                * if we get here, no helper image is needed.  Skip the
+                * FW_STATE_INIT state.
+                */
+               priv->fw_state = FW_STATE_LOADING_PREF;
+               rc = mwl8k_request_fw(priv, fw_image,
+                                     &priv->fw_ucode,
+                                     true);
+       } else
+               rc = mwl8k_request_fw(priv, fw_image,
+                                     &priv->fw_ucode, false);
        if (rc) {
                printk(KERN_ERR "%s: Error requesting firmware file %s\n",
                       pci_name(priv->pdev), fw_image);
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
 
-static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image)
+static int mwl8k_request_alt_fw(struct mwl8k_priv *priv)
+{
+       int rc;
+       printk(KERN_ERR "%s: Error requesting preferred fw %s.\n"
+              "Trying alternative firmware %s\n", pci_name(priv->pdev),
+              priv->fw_pref, priv->fw_alt);
+       rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true);
+       if (rc) {
+               printk(KERN_ERR "%s: Error requesting alt fw %s\n",
+                      pci_name(priv->pdev), priv->fw_alt);
+               return rc;
+       }
+       return 0;
+}
+
+static int mwl8k_firmware_load_success(struct mwl8k_priv *priv);
+static void mwl8k_fw_state_machine(const struct firmware *fw, void *context)
+{
+       struct mwl8k_priv *priv = context;
+       struct mwl8k_device_info *di = priv->device_info;
+       int rc;
+
+       switch (priv->fw_state) {
+       case FW_STATE_INIT:
+               if (!fw) {
+                       printk(KERN_ERR "%s: Error requesting helper fw %s\n",
+                              pci_name(priv->pdev), di->helper_image);
+                       goto fail;
+               }
+               priv->fw_helper = fw;
+               rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode,
+                                     true);
+               if (rc && priv->fw_alt) {
+                       rc = mwl8k_request_alt_fw(priv);
+                       if (rc)
+                               goto fail;
+                       priv->fw_state = FW_STATE_LOADING_ALT;
+               } else if (rc)
+                       goto fail;
+               else
+                       priv->fw_state = FW_STATE_LOADING_PREF;
+               break;
+
+       case FW_STATE_LOADING_PREF:
+               if (!fw) {
+                       if (priv->fw_alt) {
+                               rc = mwl8k_request_alt_fw(priv);
+                               if (rc)
+                                       goto fail;
+                               priv->fw_state = FW_STATE_LOADING_ALT;
+                       } else
+                               goto fail;
+               } else {
+                       priv->fw_ucode = fw;
+                       rc = mwl8k_firmware_load_success(priv);
+                       if (rc)
+                               goto fail;
+                       else
+                               complete(&priv->firmware_loading_complete);
+               }
+               break;
+
+       case FW_STATE_LOADING_ALT:
+               if (!fw) {
+                       printk(KERN_ERR "%s: Error requesting alt fw %s\n",
+                              pci_name(priv->pdev), di->helper_image);
+                       goto fail;
+               }
+               priv->fw_ucode = fw;
+               rc = mwl8k_firmware_load_success(priv);
+               if (rc)
+                       goto fail;
+               else
+                       complete(&priv->firmware_loading_complete);
+               break;
+
+       default:
+               printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n",
+                      MWL8K_NAME, priv->fw_state);
+               BUG_ON(1);
+       }
+
+       return;
+
+fail:
+       priv->fw_state = FW_STATE_ERROR;
+       complete(&priv->firmware_loading_complete);
+       device_release_driver(&priv->pdev->dev);
+       mwl8k_release_firmware(priv);
+}
+
+static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
+                              bool nowait)
 {
        struct mwl8k_priv *priv = hw->priv;
        int rc;
        mwl8k_hw_reset(priv);
 
        /* Ask userland hotplug daemon for the device firmware */
-       rc = mwl8k_request_firmware(priv, fw_image);
+       rc = mwl8k_request_firmware(priv, fw_image, nowait);
        if (rc) {
                wiphy_err(hw->wiphy, "Firmware files not found\n");
                return rc;
        }
 
+       if (nowait)
+               return rc;
+
        /* Load firmware into hardware */
        rc = mwl8k_load_firmware(hw);
        if (rc)
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
                mwl8k_txq_deinit(hw, i);
 
-       rc = mwl8k_init_firmware(hw, fw_image);
+       rc = mwl8k_init_firmware(hw, fw_image, false);
        if (rc)
                goto fail;
 
        struct ieee80211_hw *hw = priv->hw;
        int i, rc;
 
+       rc = mwl8k_load_firmware(hw);
+       mwl8k_release_firmware(priv);
+       if (rc) {
+               wiphy_err(hw->wiphy, "Cannot start firmware\n");
+               return rc;
+       }
+
        /*
         * Extra headroom is the size of the required DMA header
         * minus the size of the smallest 802.11 frame (CTS frame).
        }
 
        /*
-        * Choose the initial fw image depending on user input and availability
-        * of images.
+        * Choose the initial fw image depending on user input.  If a second
+        * image is available, make it the alternative image that will be
+        * loaded if the first one fails.
         */
+       init_completion(&priv->firmware_loading_complete);
        di = priv->device_info;
-       if (ap_mode_default && di->fw_image_ap)
-               rc = mwl8k_init_firmware(hw, di->fw_image_ap);
-       else if (!ap_mode_default && di->fw_image_sta)
-               rc = mwl8k_init_firmware(hw, di->fw_image_sta);
-       else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
+       if (ap_mode_default && di->fw_image_ap) {
+               priv->fw_pref = di->fw_image_ap;
+               priv->fw_alt = di->fw_image_sta;
+       } else if (!ap_mode_default && di->fw_image_sta) {
+               priv->fw_pref = di->fw_image_sta;
+               priv->fw_alt = di->fw_image_ap;
+       } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
                printk(KERN_WARNING "AP fw is unavailable.  Using STA fw.");
-               rc = mwl8k_init_firmware(hw, di->fw_image_sta);
+               priv->fw_pref = di->fw_image_sta;
        } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) {
                printk(KERN_WARNING "STA fw is unavailable.  Using AP fw.");
-               rc = mwl8k_init_firmware(hw, di->fw_image_ap);
-       } else
-               rc = mwl8k_init_firmware(hw, di->fw_image_sta);
+               priv->fw_pref = di->fw_image_ap;
+       }
+       rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
        if (rc)
                goto err_stop_firmware;
-
-       rc = mwl8k_firmware_load_success(priv);
-       if (!rc)
-               return rc;
+       return rc;
 
 err_stop_firmware:
        mwl8k_hw_reset(priv);
                return;
        priv = hw->priv;
 
+       wait_for_completion(&priv->firmware_loading_complete);
+
+       if (priv->fw_state == FW_STATE_ERROR) {
+               mwl8k_hw_reset(priv);
+               goto unmap;
+       }
+
        ieee80211_stop_queues(hw);
 
        ieee80211_unregister_hw(hw);
 
        pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);
 
+unmap:
        pci_iounmap(pdev, priv->regs);
        pci_iounmap(pdev, priv->sram);
        pci_set_drvdata(pdev, NULL);