rtlwifi: Convert to asynchronous firmware load
authorLarry Finger <Larry.Finger@lwfinger.net>
Mon, 30 Jan 2012 15:54:49 +0000 (09:54 -0600)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 30 Jan 2012 20:48:50 +0000 (15:48 -0500)
This patch addresses a kernel bugzilla report and two recent mail threads.

The kernel bugzilla report is https://bugzilla.kernel.org/show_bug.cgi?id=42632,
which reports a udev timeout on boot.

The first mail thread, which was on LKML (http://lkml.indiana.edu/hypermail/
linux/kernel/1112.3/00965.html) was for a WARNING that occurs after a
suspend/resume cycle for rtl8192cu.

The scond mail thread (http://marc.info/?l=linux-wireless&m=132655490826766&w=2)
concerned changes in udev that break drivers that delay while firmware is loaded
on modprobe.

This patch converts all rtlwifi-based drivers to use the asynchronous firmware
loading mechanism. Drivers rtl8192ce, rtl8192cu and rtl8192de share a common
callback routine. Driver rtl8192se needs different handling of the firmware,
thus it has its own code.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
20 files changed:
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/core.h
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/pci.h
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/rtlwifi/rtl8192de/fw.c
drivers/net/wireless/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/rtlwifi/rtl8192de/sw.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/led.c
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h

index 7a95a544a9b1cb761654bc0a3d148474b87f0598..df5655cc55c0a315f768073e994695d79043ffa6 100644 (file)
@@ -410,6 +410,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)
 
        wiphy_rfkill_start_polling(hw->wiphy);
 }
+EXPORT_SYMBOL(rtl_init_rfkill);
 
 void rtl_deinit_rfkill(struct ieee80211_hw *hw)
 {
index 0ee01ab2e4f6f1d81745af6e717510c3e8a7c5cd..f231b9180436ba75043aa9320489908cb17eb75e 100644 (file)
 #include "core.h"
 #include "cam.h"
 #include "base.h"
+#include "pci.h"
 #include "ps.h"
 
+#include <linux/export.h>
+
+void rtl_fw_cb(const struct firmware *firmware, void *context)
+{
+       struct ieee80211_hw *hw = context;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int err;
+
+       RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+                        "Firmware callback routine entered!\n");
+       complete(&rtlpriv->firmware_loading_complete);
+       if (!firmware) {
+               pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
+               rtlpriv->max_fw_size = 0;
+               return;
+       }
+       if (firmware->size > rtlpriv->max_fw_size) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Firmware is too big!\n");
+               release_firmware(firmware);
+               return;
+       }
+       memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
+       rtlpriv->rtlhal.fwsize = firmware->size;
+       release_firmware(firmware);
+
+       err = ieee80211_register_hw(hw);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Can't register mac80211 hw\n");
+               return;
+       } else {
+               rtlpriv->mac80211.mac80211_registered = 1;
+       }
+       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+
+       /*init rfkill */
+       rtl_init_rfkill(hw);
+}
+EXPORT_SYMBOL(rtl_fw_cb);
+
 /*mutex for start & stop is must here. */
 static int rtl_op_start(struct ieee80211_hw *hw)
 {
@@ -254,10 +296,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
                         * because that will cause nullfunc send by mac80211
                         * fail, and cause pkt loss, we have tested that 5mA
                         * is worked very well */
-                       if (!rtlpriv->psc.multi_buffered)
+                       if (!rtlpriv->psc.multi_buffered) {
                                queue_delayed_work(rtlpriv->works.rtl_wq,
                                                &rtlpriv->works.ps_work,
                                                MSECS(5));
+                               pr_info("In section\n");
+                       }
                } else {
                        rtl_swlps_rf_awake(hw);
                        rtlpriv->psc.sw_ps_enabled = false;
index 57569e0e3d475a7766f5f1eb87c3a4a9f871a040..2fe46a1b4f1f12c3e77ba985d59c4aaff1d88357 100644 (file)
@@ -40,4 +40,6 @@
 #define RTL_SUPPORTED_CTRL_FILTER      0xFF
 
 extern const struct ieee80211_ops rtl_ops;
+void rtl_fw_cb(const struct firmware *firmware, void *context);
+
 #endif
index e4d1dcfe82995a40136ac1b44fa6b490b7a4d92d..5cb2199435d2382a28d2fd9028710a101bdb083f 100644 (file)
@@ -1565,6 +1565,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
 
        rtlpci->driver_is_goingto_unload = true;
        rtlpriv->cfg->ops->hw_disable(hw);
+       /* some things are not needed if firmware not available */
+       if (!rtlpriv->max_fw_size)
+               return;
        rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
 
        spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
@@ -1779,6 +1782,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        rtlpriv = hw->priv;
        pcipriv = (void *)rtlpriv->priv;
        pcipriv->dev.pdev = pdev;
+       init_completion(&rtlpriv->firmware_loading_complete);
 
        /* init cfg & intf_ops */
        rtlpriv->rtlhal.interface = INTF_PCI;
@@ -1799,7 +1803,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        err = pci_request_regions(pdev, KBUILD_MODNAME);
        if (err) {
                RT_ASSERT(false, "Can't obtain PCI resources\n");
-               return err;
+               goto fail2;
        }
 
        pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
@@ -1862,15 +1866,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                goto fail3;
        }
 
-       err = ieee80211_register_hw(hw);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Can't register mac80211 hw\n");
-               goto fail3;
-       } else {
-               rtlpriv->mac80211.mac80211_registered = 1;
-       }
-
        err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -1878,9 +1873,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                goto fail3;
        }
 
-       /*init rfkill */
-       rtl_init_rfkill(hw);
-
        rtlpci = rtl_pcidev(pcipriv);
        err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
                          IRQF_SHARED, KBUILD_MODNAME, hw);
@@ -1889,24 +1881,22 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                         "%s: failed to register IRQ handler\n",
                         wiphy_name(hw->wiphy));
                goto fail3;
-       } else {
-               rtlpci->irq_alloc = 1;
        }
+       rtlpci->irq_alloc = 1;
 
-       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
        return 0;
 
 fail3:
        pci_set_drvdata(pdev, NULL);
        rtl_deinit_core(hw);
        _rtl_pci_io_handler_release(hw);
-       ieee80211_free_hw(hw);
 
        if (rtlpriv->io.pci_mem_start != 0)
                pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
 
 fail2:
        pci_release_regions(pdev);
+       complete(&rtlpriv->firmware_loading_complete);
 
 fail1:
 
@@ -1925,6 +1915,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
        struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
        struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
 
+       /* just in case driver is removed before firmware callback */
+       wait_for_completion(&rtlpriv->firmware_loading_complete);
        clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
 
        sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
index 99d81ede17b8b5fff36daa3507c46815a4d6e348..241448fc9ed5d190a5a54097571d4f3fc6504870 100644 (file)
@@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
 void rtl_pci_disconnect(struct pci_dev *pdev);
 int rtl_pci_suspend(struct device *dev);
 int rtl_pci_resume(struct device *dev);
-
 static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
 {
        return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
index b151266ef9f6811d5d2adf356991b686ff8b9ec5..15f86eaa1cd621437f1b1f6dcaff3b317c88d943 100644 (file)
@@ -47,7 +47,8 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
                         "Driver is already down!\n");
 
        /*<2> Enable Adapter */
-       rtlpriv->cfg->ops->hw_init(hw);
+       if (rtlpriv->cfg->ops->hw_init(hw))
+               return 1;
        RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
 
        /*<3> Enable Interrupt */
index 82bbc8384aca5205013e550e85a843e1e13d1343..c20b3c30f62ed7bfdeef57cebef888228ec07d9f 100644 (file)
@@ -257,10 +257,9 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
        u32 fwsize;
        enum version_8192c version = rtlhal->version;
 
-       if (!rtlhal->pfirmware)
+       if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
                return 1;
 
-       pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
        pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
        pfwdata = (u8 *) rtlhal->pfirmware;
        fwsize = rtlhal->fwsize;
@@ -512,15 +511,8 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
                         u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
 {
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        u32 tmp_cmdbuf[2];
 
-       if (rtlhal->fw_ready == false) {
-               RT_ASSERT(false,
-                         "return H2C cmd because of Fw download fail!!!\n");
-               return;
-       }
-
        memset(tmp_cmdbuf, 0, 8);
        memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
        _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
index c5aced459cd025bad5dc5145040d1c9ad13c3c9d..48c7b5d3fc5b17e68b7fa7f5de2dd56faa60b36e 100644 (file)
@@ -917,10 +917,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now..\n");
                err = 1;
-               rtlhal->fw_ready = false;
                return err;
-       } else {
-               rtlhal->fw_ready = true;
        }
 
        rtlhal->last_hmeboxnum = 0;
@@ -1193,7 +1190,6 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        u8 u1b_tmp;
        u32 u4b_tmp;
 
@@ -1204,7 +1200,7 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
        rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0);
-       if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+       if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7))
                rtl92c_firmware_selfreset(hw);
        rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51);
        rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
index 460dc925b4e4fe60f7009245904e2e34a88d4c67..2c3b73366cd2e2928423c1f600d7106966bd34c4 100644 (file)
@@ -91,9 +91,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
        int err;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       const struct firmware *firmware;
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       char *fw_name = NULL;
 
        rtl8192ce_bt_reg_init(hw);
 
@@ -165,26 +163,20 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
        /* request fw */
        if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
            !IS_92C_SERIAL(rtlhal->version))
-               fw_name = "rtlwifi/rtl8192cfwU.bin";
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
        else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
-               fw_name = "rtlwifi/rtl8192cfwU_B.bin";
-       else
-               fw_name = rtlpriv->cfg->fw_name;
-       err = request_firmware(&firmware, fw_name, rtlpriv->io.dev);
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+
+       rtlpriv->max_fw_size = 0x4000;
+       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+                                     rtlpriv->io.dev, GFP_KERNEL, hw,
+                                     rtl_fw_cb);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Failed to request firmware!\n");
                return 1;
        }
-       if (firmware->size > 0x4000) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Firmware is too big!\n");
-               release_firmware(firmware);
-               return 1;
-       }
-       memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
-       rtlpriv->rtlhal.fwsize = firmware->size;
-       release_firmware(firmware);
 
        return 0;
 }
index 7f171682d3d64f8feb6689d3db6958a03f9cff0b..0c74d4f2eeb43c86ed59f9309b3170bd3aaed7a1 100644 (file)
@@ -997,10 +997,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW now..\n");
                err = 1;
-               rtlhal->fw_ready = false;
                return err;
-       } else {
-               rtlhal->fw_ready = true;
        }
        rtlhal->last_hmeboxnum = 0; /* h2c */
        _rtl92cu_phy_param_tab_init(hw);
@@ -1094,23 +1091,21 @@ static void  _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM)
                if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(1)) {
                        /* reset MCU ready status */
                        rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
-                       if (rtlhal->fw_ready) {
-                               /* 8051 reset by self */
-                               rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20);
-                               while ((retry_cnts++ < 100) &&
-                                      (FEN_CPUEN & rtl_read_word(rtlpriv,
-                                      REG_SYS_FUNC_EN))) {
-                                       udelay(50);
-                               }
-                               if (retry_cnts >= 100) {
-                                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                                "#####=> 8051 reset failed!.........................\n");
-                                       /* if 8051 reset fail, reset MAC. */
-                                       rtl_write_byte(rtlpriv,
-                                                      REG_SYS_FUNC_EN + 1,
-                                                      0x50);
-                                       udelay(100);
-                               }
+                       /* 8051 reset by self */
+                       rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20);
+                       while ((retry_cnts++ < 100) &&
+                              (FEN_CPUEN & rtl_read_word(rtlpriv,
+                              REG_SYS_FUNC_EN))) {
+                               udelay(50);
+                       }
+                       if (retry_cnts >= 100) {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                        "#####=> 8051 reset failed!.........................\n");
+                               /* if 8051 reset fail, reset MAC. */
+                               rtl_write_byte(rtlpriv,
+                                              REG_SYS_FUNC_EN + 1,
+                                              0x50);
+                               udelay(100);
                        }
                }
                /* Reset MAC and Enable 8051 */
index c04c3be5bd4e15a83ed139f06431695794704abc..82c85286ab2e25852eb7e45f878fc7b783e07f97 100644 (file)
@@ -53,7 +53,6 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
 static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       const struct firmware *firmware;
        int err;
 
        rtlpriv->dm.dm_initialgain_enable = true;
@@ -61,29 +60,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
        rtlpriv->dm.disable_framebursting = false;
        rtlpriv->dm.thermalvalue = 0;
        rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
-       rtlpriv->rtlhal.pfirmware = vmalloc(0x4000);
+
+       /* for firmware buf */
+       rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
        if (!rtlpriv->rtlhal.pfirmware) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Can't alloc buffer for fw\n");
                return 1;
        }
-       /* request fw */
-       err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
-                       rtlpriv->io.dev);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Failed to request firmware!\n");
-               return 1;
-       }
-       if (firmware->size > 0x4000) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Firmware is too big!\n");
-               release_firmware(firmware);
-               return 1;
-       }
-       memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
-       rtlpriv->rtlhal.fwsize = firmware->size;
-       release_firmware(firmware);
+
+       pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name);
+       rtlpriv->max_fw_size = 0x4000;
+       err = request_firmware_nowait(THIS_MODULE, 1,
+                                     rtlpriv->cfg->fw_name, rtlpriv->io.dev,
+                                     GFP_KERNEL, hw, rtl_fw_cb);
+
 
        return 0;
 }
index b59de75a36435fab9d09e5cff6fd6ee8d5342f3e..f548a8d0068d22d672bf505a9e9f071f1171560e 100644 (file)
@@ -253,7 +253,7 @@ int rtl92d_download_fw(struct ieee80211_hw *hw)
        bool fw_downloaded = false, fwdl_in_process = false;
        unsigned long flags;
 
-       if (!rtlhal->pfirmware)
+       if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
                return 1;
        fwsize = rtlhal->fwsize;
        pfwheader = (u8 *) rtlhal->pfirmware;
@@ -532,14 +532,8 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
                         u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 {
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        u32 tmp_cmdbuf[2];
 
-       if (rtlhal->fw_ready == false) {
-               RT_ASSERT(false,
-                         "return H2C cmd because of Fw download fail!!!\n");
-               return;
-       }
        memset(tmp_cmdbuf, 0, 8);
        memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
        _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
index 695bccb437507b2eea245664cdf03e22bbf2dcfb..7d877125db29e12da4b12cad901f2f8bc641c331 100644 (file)
@@ -931,10 +931,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         "Failed to download FW. Init HW without FW..\n");
-               rtlhal->fw_ready = false;
                return 1;
-       } else {
-               rtlhal->fw_ready = true;
        }
        rtlhal->last_hmeboxnum = 0;
        rtlpriv->psc.fw_current_inpsmode = false;
index bf625f9e632ee94556269207807e0bf83967d42c..4898c502974db606bf725ed0664318f0655ab7f8 100644 (file)
@@ -91,7 +91,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
        u8 tid;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       const struct firmware *firmware;
        static int header_print;
 
        rtlpriv->dm.dm_initialgain_enable = true;
@@ -167,6 +166,15 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
        else if (rtlpriv->psc.reg_fwctrl_lps == 3)
                rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
 
+       /* for early mode */
+       rtlpriv->rtlhal.earlymode_enable = true;
+       for (tid = 0; tid < 8; tid++)
+               skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
+
+       /* Only load firmware for first MAC */
+       if (header_print)
+               return 0;
+
        /* for firmware buf */
        rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
        if (!rtlpriv->rtlhal.pfirmware) {
@@ -175,33 +183,21 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
                return 1;
        }
 
-       if (!header_print) {
-               pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
-               pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
-               header_print++;
-       }
+       rtlpriv->max_fw_size = 0x8000;
+       pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
+       pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
+       header_print++;
+
        /* request fw */
-       err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
-                              rtlpriv->io.dev);
+       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+                                     rtlpriv->io.dev, GFP_KERNEL, hw,
+                                     rtl_fw_cb);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Failed to request firmware!\n");
                return 1;
        }
-       if (firmware->size > 0x8000) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Firmware is too big!\n");
-               release_firmware(firmware);
-               return 1;
-       }
-       memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
-       rtlpriv->rtlhal.fwsize = firmware->size;
-       release_firmware(firmware);
 
-       /* for early mode */
-       rtlpriv->rtlhal.earlymode_enable = true;
-       for (tid = 0; tid < 8; tid++)
-               skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
        return 0;
 }
 
index 595ecd22ffa0bf548d670a1c8892e55a9b0cc147..0d8bf565700881e22e1b5a0c3c652ad9c1366834 100644 (file)
@@ -364,7 +364,7 @@ int rtl92s_download_fw(struct ieee80211_hw *hw)
        u8 fwstatus = FW_STATUS_INIT;
        bool rtstatus = true;
 
-       if (!rtlhal->pfirmware)
+       if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
                return 1;
 
        firmware = (struct rt_firmware *)rtlhal->pfirmware;
index cbaf1f345c6ee09dab67a2712112f40dae83a15c..22098c2f38f13682056cfa541d86a932ebb6bbf4 100644 (file)
@@ -949,10 +949,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
        rtstatus = rtl92s_download_fw(hw);
        if (!rtstatus) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-                        "Failed to download FW. Init HW without FW now... Please copy FW into /lib/firmware/rtlwifi\n");
-               rtlhal->fw_ready = false;
-       } else {
-               rtlhal->fw_ready = true;
+                        "Failed to download FW. Init HW without FW now... "
+                        "Please copy FW into /lib/firmware/rtlwifi\n");
+               return 1;
        }
 
        /* After FW download, we have to reset MAC register */
@@ -1215,9 +1214,14 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
 
 void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
 {
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv;
+       struct rtl_pci *rtlpci;
 
+       rtlpriv = rtl_priv(hw);
+       /* if firmware not available, no interrupts */
+       if (!rtlpriv || !rtlpriv->max_fw_size)
+               return;
+       rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        rtl_write_dword(rtlpriv, INTA_MASK, 0);
        rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
 
index ef4211bca58733e823f652531a98a469e8b4b298..44949b5cbb872e9ccbdc3416486b1d45d214c094 100644 (file)
@@ -76,10 +76,13 @@ void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
 
 void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
 {
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_priv *rtlpriv;
        struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
        u8 ledcfg;
 
+       rtlpriv = rtl_priv(hw);
+       if (!rtlpriv || rtlpriv->max_fw_size)
+               return;
        RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n",
                 LEDCFG, pled->ledpin);
 
index 0c47310b39b92a8d23fc067440ea7162f782a3e0..ca38dd9f3564a2a85ca4c4a126ba005cbaa8b60f 100644 (file)
@@ -30,6 +30,8 @@
 #include "../wifi.h"
 #include "../core.h"
 #include "../pci.h"
+#include "../base.h"
+#include "../pci.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -86,12 +88,53 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
        rtlpci->const_support_pciaspm = 2;
 }
 
+static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
+{
+       struct ieee80211_hw *hw = context;
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       struct rt_firmware *pfirmware = NULL;
+       int err;
+
+       RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+                        "Firmware callback routine entered!\n");
+       complete(&rtlpriv->firmware_loading_complete);
+       if (!firmware) {
+               pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
+               rtlpriv->max_fw_size = 0;
+               return;
+       }
+       if (firmware->size > rtlpriv->max_fw_size) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Firmware is too big!\n");
+               release_firmware(firmware);
+               return;
+       }
+       pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
+       memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
+       pfirmware->sz_fw_tmpbufferlen = firmware->size;
+       release_firmware(firmware);
+
+       err = ieee80211_register_hw(hw);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Can't register mac80211 hw\n");
+               return;
+       } else {
+               rtlpriv->mac80211.mac80211_registered = 1;
+       }
+       rtlpci->irq_alloc = 1;
+       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+
+       /*init rfkill */
+       rtl_init_rfkill(hw);
+}
+
 static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       const struct firmware *firmware;
-       struct rt_firmware *pfirmware = NULL;
        int err = 0;
        u16 earlyrxthreshold = 7;
 
@@ -189,27 +232,19 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
                return 1;
        }
 
+       rtlpriv->max_fw_size = sizeof(struct rt_firmware);
+
        pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
                "Loading firmware %s\n", rtlpriv->cfg->fw_name);
        /* request fw */
-       err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
-                       rtlpriv->io.dev);
+       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+                                     rtlpriv->io.dev, GFP_KERNEL, hw,
+                                     rtl92se_fw_cb);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Failed to request firmware!\n");
                return 1;
        }
-       if (firmware->size > sizeof(struct rt_firmware)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        "Firmware is too big!\n");
-               release_firmware(firmware);
-               return 1;
-       }
-
-       pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
-       memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
-       pfirmware->sz_fw_tmpbufferlen = firmware->size;
-       release_firmware(firmware);
 
        return err;
 }
index e7a7ea96f42bb1fd788b7d4eac55115e97710374..ffcf89fe45e4045f457b02d95c2ffc22c54151d5 100644 (file)
@@ -664,15 +664,17 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
        struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
 
        err = rtlpriv->cfg->ops->hw_init(hw);
-       rtl_init_rx_config(hw);
+       if (!err) {
+               rtl_init_rx_config(hw);
 
-       /* Enable software */
-       SET_USB_START(rtlusb);
-       /* should after adapter start and interrupt enable. */
-       set_hal_start(rtlhal);
+               /* Enable software */
+               SET_USB_START(rtlusb);
+               /* should after adapter start and interrupt enable. */
+               set_hal_start(rtlhal);
 
-       /* Start bulk IN */
-       _rtl_usb_receive(hw);
+               /* Start bulk IN */
+               _rtl_usb_receive(hw);
+       }
 
        return err;
 }
@@ -949,6 +951,7 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
        rtlpriv = hw->priv;
+       init_completion(&rtlpriv->firmware_loading_complete);
        SET_IEEE80211_DEV(hw, &intf->dev);
        udev = interface_to_usbdev(intf);
        usb_get_dev(udev);
@@ -982,24 +985,12 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
                goto error_out;
        }
 
-       /*init rfkill */
-       /* rtl_init_rfkill(hw); */
-
-       err = ieee80211_register_hw(hw);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
-                        "Can't register mac80211 hw\n");
-               goto error_out;
-       } else {
-               rtlpriv->mac80211.mac80211_registered = 1;
-       }
-       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
        return 0;
 error_out:
        rtl_deinit_core(hw);
        _rtl_usb_io_handler_release(hw);
-       ieee80211_free_hw(hw);
        usb_put_dev(udev);
+       complete(&rtlpriv->firmware_loading_complete);
        return -ENODEV;
 }
 EXPORT_SYMBOL(rtl_usb_probe);
@@ -1013,6 +1004,9 @@ void rtl_usb_disconnect(struct usb_interface *intf)
 
        if (unlikely(!rtlpriv))
                return;
+
+       /* just in case driver is removed before firmware callback */
+       wait_for_completion(&rtlpriv->firmware_loading_complete);
        /*ieee80211_unregister_hw will call ops_stop */
        if (rtlmac->mac80211_registered == 1) {
                ieee80211_unregister_hw(hw);
index 1e5fffb2db0b6b1804f9f67942003a4fa08beb40..b591614c3b9bb79c7b6e00ec6fe48cb8b06c480b 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/vmalloc.h>
 #include <linux/usb.h>
 #include <net/mac80211.h>
+#include <linux/completion.h>
 #include "debug.h"
 
 #define RF_CHANGE_BY_INIT                      0
@@ -1047,7 +1048,6 @@ struct rtl_hal {
        u16 fw_subversion;
        bool h2c_setinprogress;
        u8 last_hmeboxnum;
-       bool fw_ready;
        /*Reserve page start offset except beacon in TxQ. */
        u8 fw_rsvdpage_startoffset;
        u8 h2c_txcmd_seq;
@@ -1593,6 +1593,7 @@ struct rtl_debug {
 };
 
 struct rtl_priv {
+       struct completion firmware_loading_complete;
        struct rtl_locks locks;
        struct rtl_works works;
        struct rtl_mac mac80211;
@@ -1614,6 +1615,7 @@ struct rtl_priv {
        struct rtl_rate_priv *rate_priv;
 
        struct rtl_debug dbg;
+       int max_fw_size;
 
        /*
         *hal_cfg : for diff cards