mwifiex: use asynchronous firmware loading
authorAmitkumar Karwar <akarwar@marvell.com>
Tue, 10 Apr 2012 03:06:57 +0000 (20:06 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 12 Apr 2012 19:10:30 +0000 (15:10 -0400)
Make use of request_firmware_nowait instead of request_firmware
to load FW asynchronously. This fixes timeouts introduced with
recent udev changes.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/sdio.c

index 2ee61626c54d58b673e18efcb10128009a0d203e..245b7329e0c9254bbbeaba04ba63feb888aeb56e 100644 (file)
@@ -292,29 +292,28 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
 }
 
 /*
- * This function initializes the hardware and firmware.
+ * This function gets firmware and initializes it.
  *
  * The main initialization steps followed are -
  *      - Download the correct firmware to card
- *      - Allocate and initialize the adapter structure
- *      - Initialize the private structures
  *      - Issue the init commands to firmware
  */
-static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 {
-       int ret, err;
+       int ret;
+       char fmt[64];
+       struct mwifiex_private *priv;
+       struct mwifiex_adapter *adapter = context;
        struct mwifiex_fw_image fw;
 
-       memset(&fw, 0, sizeof(struct mwifiex_fw_image));
-
-       err = request_firmware(&adapter->firmware, adapter->fw_name,
-                              adapter->dev);
-       if (err < 0) {
-               dev_err(adapter->dev, "request_firmware() returned"
-                               " error code %#x\n", err);
-               ret = -1;
+       if (!firmware) {
+               dev_err(adapter->dev,
+                       "Failed to get firmware %s\n", adapter->fw_name);
                goto done;
        }
+
+       memset(&fw, 0, sizeof(struct mwifiex_fw_image));
+       adapter->firmware = firmware;
        fw.fw_buf = (u8 *) adapter->firmware->data;
        fw.fw_len = adapter->firmware->size;
 
@@ -335,16 +334,54 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
        /* Wait for mwifiex_init to complete */
        wait_event_interruptible(adapter->init_wait_q,
                                 adapter->init_wait_q_woken);
-       if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
-               ret = -1;
+       if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
                goto done;
+
+       priv = adapter->priv[0];
+       if (mwifiex_register_cfg80211(priv) != 0) {
+               dev_err(adapter->dev, "cannot register with cfg80211\n");
+               goto err_init_fw;
+       }
+
+       rtnl_lock();
+       /* Create station interface by default */
+       if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+                                     NL80211_IFTYPE_STATION, NULL, NULL)) {
+               dev_err(adapter->dev, "cannot create default STA interface\n");
+               goto err_add_intf;
        }
-       ret = 0;
+       rtnl_unlock();
+
+       mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+       dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+       goto done;
 
+err_add_intf:
+       mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+       rtnl_unlock();
+err_init_fw:
+       pr_debug("info: %s: unregister device\n", __func__);
+       adapter->if_ops.unregister_dev(adapter);
 done:
        release_firmware(adapter->firmware);
-       if (ret)
-               ret = -1;
+       complete(&adapter->fw_load);
+       return;
+}
+
+/*
+ * This function initializes the hardware and gets firmware.
+ */
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+{
+       int ret;
+
+       init_completion(&adapter->fw_load);
+       ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
+                                     adapter->dev, GFP_KERNEL, adapter,
+                                     mwifiex_fw_dpc);
+       if (ret < 0)
+               dev_err(adapter->dev,
+                       "request_firmware_nowait() returned error %d\n", ret);
        return ret;
 }
 
@@ -649,8 +686,6 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                 struct mwifiex_if_ops *if_ops, u8 iface_type)
 {
        struct mwifiex_adapter *adapter;
-       char fmt[64];
-       struct mwifiex_private *priv;
 
        if (down_interruptible(sem))
                goto exit_sem_err;
@@ -691,37 +726,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                goto err_init_fw;
        }
 
-       priv = adapter->priv[0];
-
-       if (mwifiex_register_cfg80211(priv) != 0) {
-               dev_err(adapter->dev, "cannot register netdevice"
-                              " with cfg80211\n");
-                       goto err_init_fw;
-       }
-
-       rtnl_lock();
-       /* Create station interface by default */
-       if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
-                                     NL80211_IFTYPE_STATION, NULL, NULL)) {
-               rtnl_unlock();
-               dev_err(adapter->dev, "cannot create default station"
-                               " interface\n");
-               goto err_add_intf;
-       }
-
-       rtnl_unlock();
-
        up(sem);
-
-       mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
-       dev_notice(adapter->dev, "driver_version = %s\n", fmt);
-
        return 0;
 
-err_add_intf:
-       rtnl_lock();
-       mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
-       rtnl_unlock();
 err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
index 5081da36bc73ff5b5f0bba4a692fcb6fd8f06529..46c298e2e24022268e14154126bf0356312fb793 100644 (file)
@@ -655,6 +655,7 @@ struct mwifiex_adapter {
        u8 scan_wait_q_woken;
        struct cmd_ctrl_node *cmd_queued;
        spinlock_t queue_lock;          /* lock for tx queues */
+       struct completion fw_load;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
index 5867facd415d445e1bfd12ae160dd6834ba6aa3e..13fbc4eb15952fe375be1e10c55518bb2b6b3836 100644 (file)
@@ -119,6 +119,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        if (!adapter || !adapter->priv_num)
                return;
 
+       /* In case driver is removed when asynchronous FW load is in progress */
+       wait_for_completion(&adapter->fw_load);
+
        if (user_rmmod) {
 #ifdef CONFIG_PM
                if (adapter->is_suspended)
index f8012e2b7f7c735c99394f314a314073a330dd87..1aa45c4295bb082a17828e7da0c18a079a095b06 100644 (file)
@@ -123,6 +123,9 @@ mwifiex_sdio_remove(struct sdio_func *func)
        if (!adapter || !adapter->priv_num)
                return;
 
+       /* In case driver is removed when asynchronous FW load is in progress */
+       wait_for_completion(&adapter->fw_load);
+
        if (user_rmmod) {
                if (adapter->is_suspended)
                        mwifiex_sdio_resume(adapter->dev);