Commit b0302aba authored by Larry Finger's avatar Larry Finger Committed by John W. Linville

rtlwifi: Convert to asynchronous firmware load

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: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent feced201
...@@ -410,6 +410,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw) ...@@ -410,6 +410,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)
wiphy_rfkill_start_polling(hw->wiphy); wiphy_rfkill_start_polling(hw->wiphy);
} }
EXPORT_SYMBOL(rtl_init_rfkill);
void rtl_deinit_rfkill(struct ieee80211_hw *hw) void rtl_deinit_rfkill(struct ieee80211_hw *hw)
{ {
......
...@@ -31,8 +31,50 @@ ...@@ -31,8 +31,50 @@
#include "core.h" #include "core.h"
#include "cam.h" #include "cam.h"
#include "base.h" #include "base.h"
#include "pci.h"
#include "ps.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. */ /*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw) static int rtl_op_start(struct ieee80211_hw *hw)
{ {
...@@ -254,10 +296,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -254,10 +296,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
* because that will cause nullfunc send by mac80211 * because that will cause nullfunc send by mac80211
* fail, and cause pkt loss, we have tested that 5mA * fail, and cause pkt loss, we have tested that 5mA
* is worked very well */ * is worked very well */
if (!rtlpriv->psc.multi_buffered) if (!rtlpriv->psc.multi_buffered) {
queue_delayed_work(rtlpriv->works.rtl_wq, queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.ps_work, &rtlpriv->works.ps_work,
MSECS(5)); MSECS(5));
pr_info("In section\n");
}
} else { } else {
rtl_swlps_rf_awake(hw); rtl_swlps_rf_awake(hw);
rtlpriv->psc.sw_ps_enabled = false; rtlpriv->psc.sw_ps_enabled = false;
......
...@@ -40,4 +40,6 @@ ...@@ -40,4 +40,6 @@
#define RTL_SUPPORTED_CTRL_FILTER 0xFF #define RTL_SUPPORTED_CTRL_FILTER 0xFF
extern const struct ieee80211_ops rtl_ops; extern const struct ieee80211_ops rtl_ops;
void rtl_fw_cb(const struct firmware *firmware, void *context);
#endif #endif
...@@ -1565,6 +1565,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw) ...@@ -1565,6 +1565,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
rtlpci->driver_is_goingto_unload = true; rtlpci->driver_is_goingto_unload = true;
rtlpriv->cfg->ops->hw_disable(hw); 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); rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
...@@ -1779,6 +1782,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -1779,6 +1782,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
rtlpriv = hw->priv; rtlpriv = hw->priv;
pcipriv = (void *)rtlpriv->priv; pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev; pcipriv->dev.pdev = pdev;
init_completion(&rtlpriv->firmware_loading_complete);
/* init cfg & intf_ops */ /* init cfg & intf_ops */
rtlpriv->rtlhal.interface = INTF_PCI; rtlpriv->rtlhal.interface = INTF_PCI;
...@@ -1799,7 +1803,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -1799,7 +1803,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
err = pci_request_regions(pdev, KBUILD_MODNAME); err = pci_request_regions(pdev, KBUILD_MODNAME);
if (err) { if (err) {
RT_ASSERT(false, "Can't obtain PCI resources\n"); RT_ASSERT(false, "Can't obtain PCI resources\n");
return err; goto fail2;
} }
pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
...@@ -1862,15 +1866,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -1862,15 +1866,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
goto fail3; 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); err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
...@@ -1878,9 +1873,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -1878,9 +1873,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
goto fail3; goto fail3;
} }
/*init rfkill */
rtl_init_rfkill(hw);
rtlpci = rtl_pcidev(pcipriv); rtlpci = rtl_pcidev(pcipriv);
err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
IRQF_SHARED, KBUILD_MODNAME, hw); IRQF_SHARED, KBUILD_MODNAME, hw);
...@@ -1889,24 +1881,22 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -1889,24 +1881,22 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
"%s: failed to register IRQ handler\n", "%s: failed to register IRQ handler\n",
wiphy_name(hw->wiphy)); wiphy_name(hw->wiphy));
goto fail3; goto fail3;
} else {
rtlpci->irq_alloc = 1;
} }
rtlpci->irq_alloc = 1;
set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
return 0; return 0;
fail3: fail3:
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
rtl_deinit_core(hw); rtl_deinit_core(hw);
_rtl_pci_io_handler_release(hw); _rtl_pci_io_handler_release(hw);
ieee80211_free_hw(hw);
if (rtlpriv->io.pci_mem_start != 0) if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
fail2: fail2:
pci_release_regions(pdev); pci_release_regions(pdev);
complete(&rtlpriv->firmware_loading_complete);
fail1: fail1:
...@@ -1925,6 +1915,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev) ...@@ -1925,6 +1915,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
struct rtl_mac *rtlmac = rtl_mac(rtlpriv); 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); clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group); sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
......
...@@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, ...@@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
void rtl_pci_disconnect(struct pci_dev *pdev); void rtl_pci_disconnect(struct pci_dev *pdev);
int rtl_pci_suspend(struct device *dev); int rtl_pci_suspend(struct device *dev);
int rtl_pci_resume(struct device *dev); int rtl_pci_resume(struct device *dev);
static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
{ {
return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
......
...@@ -47,7 +47,8 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) ...@@ -47,7 +47,8 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
"Driver is already down!\n"); "Driver is already down!\n");
/*<2> Enable Adapter */ /*<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); RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*<3> Enable Interrupt */ /*<3> Enable Interrupt */
......
...@@ -257,10 +257,9 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) ...@@ -257,10 +257,9 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
u32 fwsize; u32 fwsize;
enum version_8192c version = rtlhal->version; enum version_8192c version = rtlhal->version;
if (!rtlhal->pfirmware) if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1; return 1;
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *) rtlhal->pfirmware; pfwdata = (u8 *) rtlhal->pfirmware;
fwsize = rtlhal->fwsize; fwsize = rtlhal->fwsize;
...@@ -512,15 +511,8 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, ...@@ -512,15 +511,8 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
{ {
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u32 tmp_cmdbuf[2]; 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); memset(tmp_cmdbuf, 0, 8);
memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
......
...@@ -917,10 +917,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) ...@@ -917,10 +917,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n"); "Failed to download FW. Init HW without FW now..\n");
err = 1; err = 1;
rtlhal->fw_ready = false;
return err; return err;
} else {
rtlhal->fw_ready = true;
} }
rtlhal->last_hmeboxnum = 0; rtlhal->last_hmeboxnum = 0;
...@@ -1193,7 +1190,6 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) ...@@ -1193,7 +1190,6 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 u1b_tmp; u8 u1b_tmp;
u32 u4b_tmp; u32 u4b_tmp;
...@@ -1204,7 +1200,7 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) ...@@ -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_APSD_CTRL, 0x40);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0); 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); rtl92c_firmware_selfreset(hw);
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51); rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51);
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
......
...@@ -91,9 +91,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) ...@@ -91,9 +91,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
int err; int err;
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
char *fw_name = NULL;
rtl8192ce_bt_reg_init(hw); rtl8192ce_bt_reg_init(hw);
...@@ -165,26 +163,20 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) ...@@ -165,26 +163,20 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
/* request fw */ /* request fw */
if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
!IS_92C_SERIAL(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)) else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
fw_name = "rtlwifi/rtl8192cfwU_B.bin"; rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
else
fw_name = rtlpriv->cfg->fw_name; rtlpriv->max_fw_size = 0x4000;
err = request_firmware(&firmware, fw_name, rtlpriv->io.dev); 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) { if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n"); "Failed to request firmware!\n");
return 1; 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; return 0;
} }
......
...@@ -997,10 +997,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) ...@@ -997,10 +997,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n"); "Failed to download FW. Init HW without FW now..\n");
err = 1; err = 1;
rtlhal->fw_ready = false;
return err; return err;
} else {
rtlhal->fw_ready = true;
} }
rtlhal->last_hmeboxnum = 0; /* h2c */ rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw); _rtl92cu_phy_param_tab_init(hw);
...@@ -1094,7 +1091,6 @@ static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM) ...@@ -1094,7 +1091,6 @@ static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM)
if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(1)) { if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(1)) {
/* reset MCU ready status */ /* reset MCU ready status */
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
if (rtlhal->fw_ready) {
/* 8051 reset by self */ /* 8051 reset by self */
rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20); rtl_write_byte(rtlpriv, REG_HMETFR+3, 0x20);
while ((retry_cnts++ < 100) && while ((retry_cnts++ < 100) &&
...@@ -1112,7 +1108,6 @@ static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM) ...@@ -1112,7 +1108,6 @@ static void _ResetDigitalProcedure1(struct ieee80211_hw *hw, bool bWithoutHWSM)
udelay(100); udelay(100);
} }
} }
}
/* Reset MAC and Enable 8051 */ /* Reset MAC and Enable 8051 */
rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x54); rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x54);
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
......
...@@ -53,7 +53,6 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); ...@@ -53,7 +53,6 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
const struct firmware *firmware;
int err; int err;
rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_initialgain_enable = true;
...@@ -61,29 +60,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) ...@@ -61,29 +60,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.disable_framebursting = false;
rtlpriv->dm.thermalvalue = 0; rtlpriv->dm.thermalvalue = 0;
rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; 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) { if (!rtlpriv->rtlhal.pfirmware) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Can't alloc buffer for fw\n"); "Can't alloc buffer for fw\n");
return 1; return 1;
} }
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name, pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name);
rtlpriv->io.dev); rtlpriv->max_fw_size = 0x4000;
if (err) { err = request_firmware_nowait(THIS_MODULE, 1,
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, rtlpriv->cfg->fw_name, rtlpriv->io.dev,
"Failed to request firmware!\n"); GFP_KERNEL, hw, rtl_fw_cb);
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; return 0;
} }
......
...@@ -253,7 +253,7 @@ int rtl92d_download_fw(struct ieee80211_hw *hw) ...@@ -253,7 +253,7 @@ int rtl92d_download_fw(struct ieee80211_hw *hw)
bool fw_downloaded = false, fwdl_in_process = false; bool fw_downloaded = false, fwdl_in_process = false;
unsigned long flags; unsigned long flags;
if (!rtlhal->pfirmware) if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1; return 1;
fwsize = rtlhal->fwsize; fwsize = rtlhal->fwsize;
pfwheader = (u8 *) rtlhal->pfirmware; pfwheader = (u8 *) rtlhal->pfirmware;
...@@ -532,14 +532,8 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, ...@@ -532,14 +532,8 @@ static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
u8 element_id, u32 cmd_len, u8 *cmdbuffer) u8 element_id, u32 cmd_len, u8 *cmdbuffer)
{ {
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u32 tmp_cmdbuf[2]; 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); memset(tmp_cmdbuf, 0, 8);
memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
_rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
......
...@@ -931,10 +931,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw) ...@@ -931,10 +931,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW..\n"); "Failed to download FW. Init HW without FW..\n");
rtlhal->fw_ready = false;
return 1; return 1;
} else {
rtlhal->fw_ready = true;
} }
rtlhal->last_hmeboxnum = 0; rtlhal->last_hmeboxnum = 0;
rtlpriv->psc.fw_current_inpsmode = false; rtlpriv->psc.fw_current_inpsmode = false;
......
...@@ -91,7 +91,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) ...@@ -91,7 +91,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
u8 tid; u8 tid;
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
static int header_print; static int header_print;
rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_initialgain_enable = true;
...@@ -167,6 +166,15 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) ...@@ -167,6 +166,15 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
else if (rtlpriv->psc.reg_fwctrl_lps == 3) else if (rtlpriv->psc.reg_fwctrl_lps == 3)
rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; 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 */ /* for firmware buf */
rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
if (!rtlpriv->rtlhal.pfirmware) { if (!rtlpriv->rtlhal.pfirmware) {
...@@ -175,33 +183,21 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) ...@@ -175,33 +183,21 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
return 1; return 1;
} }
if (!header_print) { rtlpriv->max_fw_size = 0x8000;
pr_info("Driver for Realtek RTL8192DE WLAN interface\n"); pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
header_print++; header_print++;
}
/* request fw */ /* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name, err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev); rtlpriv->io.dev, GFP_KERNEL, hw,
rtl_fw_cb);
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n"); "Failed to request firmware!\n");
return 1; 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; return 0;
} }
......
...@@ -364,7 +364,7 @@ int rtl92s_download_fw(struct ieee80211_hw *hw) ...@@ -364,7 +364,7 @@ int rtl92s_download_fw(struct ieee80211_hw *hw)
u8 fwstatus = FW_STATUS_INIT; u8 fwstatus = FW_STATUS_INIT;
bool rtstatus = true; bool rtstatus = true;
if (!rtlhal->pfirmware) if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
return 1; return 1;
firmware = (struct rt_firmware *)rtlhal->pfirmware; firmware = (struct rt_firmware *)rtlhal->pfirmware;
......
...@@ -949,10 +949,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) ...@@ -949,10 +949,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtstatus = rtl92s_download_fw(hw); rtstatus = rtl92s_download_fw(hw);
if (!rtstatus) { if (!rtstatus) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now... Please copy FW into /lib/firmware/rtlwifi\n"); "Failed to download FW. Init HW without FW now... "
rtlhal->fw_ready = false; "Please copy FW into /lib/firmware/rtlwifi\n");
} else { return 1;
rtlhal->fw_ready = true;
} }
/* After FW download, we have to reset MAC register */ /* After FW download, we have to reset MAC register */
...@@ -1215,9 +1214,14 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw) ...@@ -1215,9 +1214,14 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
void rtl92se_disable_interrupt(struct ieee80211_hw *hw) void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv;
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); 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, 0);
rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
......
...@@ -76,10 +76,13 @@ void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) ...@@ -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) 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); struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
u8 ledcfg; 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", RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n",
LEDCFG, pled->ledpin); LEDCFG, pled->ledpin);
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "../wifi.h" #include "../wifi.h"
#include "../core.h" #include "../core.h"
#include "../pci.h" #include "../pci.h"
#include "../base.h"
#include "../pci.h"
#include "reg.h" #include "reg.h"
#include "def.h" #include "def.h"
#include "phy.h" #include "phy.h"
...@@ -86,12 +88,53 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) ...@@ -86,12 +88,53 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
rtlpci->const_support_pciaspm = 2; 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) static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
struct rt_firmware *pfirmware = NULL;
int err = 0; int err = 0;
u16 earlyrxthreshold = 7; u16 earlyrxthreshold = 7;
...@@ -189,27 +232,19 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) ...@@ -189,27 +232,19 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
return 1; return 1;
} }
rtlpriv->max_fw_size = sizeof(struct rt_firmware);
pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n" pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
"Loading firmware %s\n", rtlpriv->cfg->fw_name); "Loading firmware %s\n", rtlpriv->cfg->fw_name);
/* request fw */ /* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name, err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev); rtlpriv->io.dev, GFP_KERNEL, hw,
rtl92se_fw_cb);
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Failed to request firmware!\n"); "Failed to request firmware!\n");
return 1; 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; return err;
} }
......
...@@ -664,6 +664,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw) ...@@ -664,6 +664,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
err = rtlpriv->cfg->ops->hw_init(hw); err = rtlpriv->cfg->ops->hw_init(hw);
if (!err) {
rtl_init_rx_config(hw); rtl_init_rx_config(hw);
/* Enable software */ /* Enable software */
...@@ -673,6 +674,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw) ...@@ -673,6 +674,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
/* Start bulk IN */ /* Start bulk IN */
_rtl_usb_receive(hw); _rtl_usb_receive(hw);
}
return err; return err;
} }
...@@ -949,6 +951,7 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, ...@@ -949,6 +951,7 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
} }
rtlpriv = hw->priv; rtlpriv = hw->priv;
init_completion(&rtlpriv->firmware_loading_complete);
SET_IEEE80211_DEV(hw, &intf->dev); SET_IEEE80211_DEV(hw, &intf->dev);
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
usb_get_dev(udev); usb_get_dev(udev);
...@@ -982,24 +985,12 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, ...@@ -982,24 +985,12 @@ int __devinit rtl_usb_probe(struct usb_interface *intf,
goto error_out; 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; return 0;
error_out: error_out:
rtl_deinit_core(hw); rtl_deinit_core(hw);
_rtl_usb_io_handler_release(hw); _rtl_usb_io_handler_release(hw);
ieee80211_free_hw(hw);
usb_put_dev(udev); usb_put_dev(udev);
complete(&rtlpriv->firmware_loading_complete);
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL(rtl_usb_probe); EXPORT_SYMBOL(rtl_usb_probe);
...@@ -1013,6 +1004,9 @@ void rtl_usb_disconnect(struct usb_interface *intf) ...@@ -1013,6 +1004,9 @@ void rtl_usb_disconnect(struct usb_interface *intf)
if (unlikely(!rtlpriv)) if (unlikely(!rtlpriv))
return; return;
/* just in case driver is removed before firmware callback */
wait_for_completion(&rtlpriv->firmware_loading_complete);
/*ieee80211_unregister_hw will call ops_stop */ /*ieee80211_unregister_hw will call ops_stop */
if (rtlmac->mac80211_registered == 1) { if (rtlmac->mac80211_registered == 1) {
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include <linux/completion.h>
#include "debug.h" #include "debug.h"
#define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_INIT 0
...@@ -1047,7 +1048,6 @@ struct rtl_hal { ...@@ -1047,7 +1048,6 @@ struct rtl_hal {
u16 fw_subversion; u16 fw_subversion;
bool h2c_setinprogress; bool h2c_setinprogress;
u8 last_hmeboxnum; u8 last_hmeboxnum;
bool fw_ready;
/*Reserve page start offset except beacon in TxQ. */ /*Reserve page start offset except beacon in TxQ. */
u8 fw_rsvdpage_startoffset; u8 fw_rsvdpage_startoffset;
u8 h2c_txcmd_seq; u8 h2c_txcmd_seq;
...@@ -1593,6 +1593,7 @@ struct rtl_debug { ...@@ -1593,6 +1593,7 @@ struct rtl_debug {
}; };
struct rtl_priv { struct rtl_priv {
struct completion firmware_loading_complete;
struct rtl_locks locks; struct rtl_locks locks;
struct rtl_works works; struct rtl_works works;
struct rtl_mac mac80211; struct rtl_mac mac80211;
...@@ -1614,6 +1615,7 @@ struct rtl_priv { ...@@ -1614,6 +1615,7 @@ struct rtl_priv {
struct rtl_rate_priv *rate_priv; struct rtl_rate_priv *rate_priv;
struct rtl_debug dbg; struct rtl_debug dbg;
int max_fw_size;
/* /*
*hal_cfg : for diff cards *hal_cfg : for diff cards
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment