From 3bb353cb4a3ddcb790585ecd2064c770fff26730 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 26 Mar 2012 15:11:53 -0700 Subject: [PATCH] 3.3-stable patches added patches: pm-domains-introduce-always-on-device-flag.patch pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch rtlwifi-convert-to-asynchronous-firmware-load.patch staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch --- ...ains-introduce-always-on-device-flag.patch | 154 ++++ ...mt-driver-use-pm_genpd_dev_always_on.patch | 46 + ...u2-driver-use-pm_genpd_dev_always_on.patch | 46 + ...mu-driver-use-pm_genpd_dev_always_on.patch | 60 ++ ...onvert-to-asynchronous-firmware-load.patch | 852 ++++++++++++++++++ queue-3.3/series | 6 + ...figuration-parameter-config_r8712_ap.patch | 101 +++ 7 files changed, 1265 insertions(+) create mode 100644 queue-3.3/pm-domains-introduce-always-on-device-flag.patch create mode 100644 queue-3.3/pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch create mode 100644 queue-3.3/pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch create mode 100644 queue-3.3/pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch create mode 100644 queue-3.3/rtlwifi-convert-to-asynchronous-firmware-load.patch create mode 100644 queue-3.3/staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch diff --git a/queue-3.3/pm-domains-introduce-always-on-device-flag.patch b/queue-3.3/pm-domains-introduce-always-on-device-flag.patch new file mode 100644 index 00000000000..b14dba6dbb6 --- /dev/null +++ b/queue-3.3/pm-domains-introduce-always-on-device-flag.patch @@ -0,0 +1,154 @@ +From rjw@sisk.pl Mon Mar 26 15:02:14 2012 +From: "Rafael J. Wysocki" +Date: Mon, 26 Mar 2012 23:25:24 +0200 +Subject: PM / Domains: Introduce "always on" device flag +To: Greg KH +Cc: horms@verge.net.au, lethal@linux-sh.org, stable@vger.kernel.org, stable-commits@vger.kernel.org +Message-ID: <201203262325.24722.rjw@sisk.pl> + + +From: Rafael J. Wysocki + +This is a backport of mainline commit +1e78a0c7fc92aee076965d516cf54475c39e9894. + +The TMU device on the Mackerel board belongs to the A4R power domain +and loses power when the domain is turned off. Unfortunately, the +TMU driver is not prepared to cope with such situations and crashes +the system when that happens. To work around this problem introduce +a new helper function, pm_genpd_dev_always_on(), allowing a device +driver to mark its device as "always on" in case it belongs to a PM +domain, which will make the generic PM domains core code avoid +powering off the domain containing the device, both at run time and +during system suspend. + +Signed-off-by: Rafael J. Wysocki +Tested-by: Simon Horman +Acked-by: Paul Mundt +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/power/domain.c | 36 ++++++++++++++++++++++++++++++------ + include/linux/pm_domain.h | 3 +++ + 2 files changed, 33 insertions(+), 6 deletions(-) + +--- a/drivers/base/power/domain.c ++++ b/drivers/base/power/domain.c +@@ -366,7 +366,7 @@ static int pm_genpd_poweroff(struct gene + not_suspended = 0; + list_for_each_entry(pdd, &genpd->dev_list, list_node) + if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) +- || pdd->dev->power.irq_safe)) ++ || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on)) + not_suspended++; + + if (not_suspended > genpd->in_progress) +@@ -503,6 +503,9 @@ static int pm_genpd_runtime_suspend(stru + + might_sleep_if(!genpd->dev_irq_safe); + ++ if (dev_gpd_data(dev)->always_on) ++ return -EBUSY; ++ + stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; + if (stop_ok && !stop_ok(dev)) + return -EBUSY; +@@ -847,7 +850,8 @@ static int pm_genpd_suspend_noirq(struct + if (ret) + return ret; + +- if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) ++ if (dev_gpd_data(dev)->always_on ++ || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) + return 0; + + genpd_stop_dev(genpd, dev); +@@ -882,7 +886,7 @@ static int pm_genpd_resume_noirq(struct + if (IS_ERR(genpd)) + return -EINVAL; + +- if (genpd->suspend_power_off ++ if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) + return 0; + +@@ -960,7 +964,7 @@ static int pm_genpd_freeze_noirq(struct + if (IS_ERR(genpd)) + return -EINVAL; + +- if (genpd->suspend_power_off) ++ if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on) + return 0; + + ret = genpd_freeze_late(genpd, dev); +@@ -991,7 +995,7 @@ static int pm_genpd_thaw_noirq(struct de + if (IS_ERR(genpd)) + return -EINVAL; + +- if (genpd->suspend_power_off) ++ if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on) + return 0; + + genpd_start_dev(genpd, dev); +@@ -1064,7 +1068,7 @@ static int pm_genpd_restore_noirq(struct + } + } + +- if (genpd->suspend_power_off) ++ if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on) + return 0; + + pm_genpd_poweron(genpd); +@@ -1230,6 +1234,26 @@ int pm_genpd_remove_device(struct generi + } + + /** ++ * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device. ++ * @dev: Device to set/unset the flag for. ++ * @val: The new value of the device's "always on" flag. ++ */ ++void pm_genpd_dev_always_on(struct device *dev, bool val) ++{ ++ struct pm_subsys_data *psd; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->power.lock, flags); ++ ++ psd = dev_to_psd(dev); ++ if (psd && psd->domain_data) ++ to_gpd_data(psd->domain_data)->always_on = val; ++ ++ spin_unlock_irqrestore(&dev->power.lock, flags); ++} ++EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); ++ ++/** + * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. + * @genpd: Master PM domain to add the subdomain to. + * @subdomain: Subdomain to be added. +--- a/include/linux/pm_domain.h ++++ b/include/linux/pm_domain.h +@@ -97,6 +97,7 @@ struct generic_pm_domain_data { + struct gpd_dev_ops ops; + struct gpd_timing_data td; + bool need_restore; ++ bool always_on; + }; + + static inline struct generic_pm_domain_data *to_gpd_data(struct pm_domain_data *pdd) +@@ -125,6 +126,7 @@ static inline int pm_genpd_add_device(st + + extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, + struct device *dev); ++extern void pm_genpd_dev_always_on(struct device *dev, bool val); + extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, + struct generic_pm_domain *new_subdomain); + extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, +@@ -163,6 +165,7 @@ static inline int pm_genpd_remove_device + { + return -ENOSYS; + } ++static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {} + static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, + struct generic_pm_domain *new_sd) + { diff --git a/queue-3.3/pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch b/queue-3.3/pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch new file mode 100644 index 00000000000..378e4eca6f4 --- /dev/null +++ b/queue-3.3/pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch @@ -0,0 +1,46 @@ +From rjw@sisk.pl Mon Mar 26 15:03:04 2012 +From: "Rafael J. Wysocki" +Date: Mon, 26 Mar 2012 23:26:53 +0200 +Subject: PM / shmobile: Make CMT driver use pm_genpd_dev_always_on() +To: Greg KH +Cc: horms@verge.net.au, lethal@linux-sh.org, stable@vger.kernel.org, stable-commits@vger.kernel.org +Message-ID: <201203262326.53650.rjw@sisk.pl> + + +From: Rafael J. Wysocki + +Commit 615a445f7f8a077c145e737864ae59a4d8717882 upstream. + +Make the CMT clocksource driver mark its device as "always on" +using pm_genpd_dev_always_on() to protect it from surprise power +removals. + +Signed-off-by: Rafael J. Wysocki +Tested-by: Simon Horman +Acked-by: Paul Mundt +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/clocksource/sh_cmt.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/clocksource/sh_cmt.c ++++ b/drivers/clocksource/sh_cmt.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + struct sh_cmt_priv { + void __iomem *mapbase; +@@ -689,6 +690,9 @@ static int __devinit sh_cmt_probe(struct + struct sh_cmt_priv *p = platform_get_drvdata(pdev); + int ret; + ++ if (!is_early_platform_device(pdev)) ++ pm_genpd_dev_always_on(&pdev->dev, true); ++ + if (p) { + dev_info(&pdev->dev, "kept as earlytimer\n"); + return 0; diff --git a/queue-3.3/pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch b/queue-3.3/pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch new file mode 100644 index 00000000000..a2f6775c66a --- /dev/null +++ b/queue-3.3/pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch @@ -0,0 +1,46 @@ +From rjw@sisk.pl Mon Mar 26 15:03:17 2012 +From: "Rafael J. Wysocki" +Date: Mon, 26 Mar 2012 23:27:33 +0200 +Subject: PM / shmobile: Make MTU2 driver use pm_genpd_dev_always_on() +To: Greg KH +Cc: horms@verge.net.au, lethal@linux-sh.org, stable@vger.kernel.org, stable-commits@vger.kernel.org +Message-ID: <201203262327.34136.rjw@sisk.pl> + + +From: Rafael J. Wysocki + +Commit 57d13370cfaf6017c68981e66ff5b3bf20a2705c upstream. + +Make the MTU2 clocksource driver mark its device as "always on" +using pm_genpd_dev_always_on() to protect it from surprise power +removals. + +Signed-off-by: Rafael J. Wysocki +Tested-by: Simon Horman +Acked-by: Paul Mundt +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/clocksource/sh_mtu2.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/clocksource/sh_mtu2.c ++++ b/drivers/clocksource/sh_mtu2.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + struct sh_mtu2_priv { + void __iomem *mapbase; +@@ -306,6 +307,9 @@ static int __devinit sh_mtu2_probe(struc + struct sh_mtu2_priv *p = platform_get_drvdata(pdev); + int ret; + ++ if (!is_early_platform_device(pdev)) ++ pm_genpd_dev_always_on(&pdev->dev, true); ++ + if (p) { + dev_info(&pdev->dev, "kept as earlytimer\n"); + return 0; diff --git a/queue-3.3/pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch b/queue-3.3/pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch new file mode 100644 index 00000000000..900ee66ad68 --- /dev/null +++ b/queue-3.3/pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch @@ -0,0 +1,60 @@ +From rjw@sisk.pl Mon Mar 26 15:02:35 2012 +From: "Rafael J. Wysocki" +Date: Mon, 26 Mar 2012 23:26:10 +0200 +Subject: PM / shmobile: Make TMU driver use pm_genpd_dev_always_on() +To: Greg KH +Cc: horms@verge.net.au, lethal@linux-sh.org, stable@vger.kernel.org, stable-commits@vger.kernel.org +Message-ID: <201203262326.10558.rjw@sisk.pl> + + +From: Rafael J. Wysocki + +Commit 2ee619f9487c2acc1efdf2c78e68e2bd51b635fa upstream. + +Make the TMU clocksource driver mark its device as "always on" +using pm_genpd_dev_always_on() to protect it from surprise power +removals and make sh7372_add_standard_devices() add TMU devices on +sh7372 to the A4R power domain so that their "always on" flags +are taken into account as appropriate. + +Signed-off-by: Rafael J. Wysocki +Tested-by: Simon Horman +Acked-by: Paul Mundt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/mach-shmobile/setup-sh7372.c | 2 ++ + drivers/clocksource/sh_tmu.c | 4 ++++ + 2 files changed, 6 insertions(+) + +--- a/arch/arm/mach-shmobile/setup-sh7372.c ++++ b/arch/arm/mach-shmobile/setup-sh7372.c +@@ -1043,6 +1043,8 @@ void __init sh7372_add_standard_devices( + sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); + sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); + sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); ++ sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device); ++ sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device); + } + + void __init sh7372_add_early_devices(void) +--- a/drivers/clocksource/sh_tmu.c ++++ b/drivers/clocksource/sh_tmu.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + struct sh_tmu_priv { + void __iomem *mapbase; +@@ -410,6 +411,9 @@ static int __devinit sh_tmu_probe(struct + struct sh_tmu_priv *p = platform_get_drvdata(pdev); + int ret; + ++ if (!is_early_platform_device(pdev)) ++ pm_genpd_dev_always_on(&pdev->dev, true); ++ + if (p) { + dev_info(&pdev->dev, "kept as earlytimer\n"); + return 0; diff --git a/queue-3.3/rtlwifi-convert-to-asynchronous-firmware-load.patch b/queue-3.3/rtlwifi-convert-to-asynchronous-firmware-load.patch new file mode 100644 index 00000000000..b988a615f18 --- /dev/null +++ b/queue-3.3/rtlwifi-convert-to-asynchronous-firmware-load.patch @@ -0,0 +1,852 @@ +From b0302aba812bcc39291cdab9ad7e37008f352a91 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Mon, 30 Jan 2012 09:54:49 -0600 +Subject: rtlwifi: Convert to asynchronous firmware load + +From: Larry Finger + +commit b0302aba812bcc39291cdab9ad7e37008f352a91 upstream. + +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 +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/net/wireless/rtlwifi/base.c | 1 + drivers/net/wireless/rtlwifi/core.c | 42 ++++++++++++++ + drivers/net/wireless/rtlwifi/core.h | 4 - + drivers/net/wireless/rtlwifi/pci.c | 28 +++------ + drivers/net/wireless/rtlwifi/pci.h | 1 + drivers/net/wireless/rtlwifi/ps.c | 3 - + drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 10 --- + drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 6 -- + drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 24 ++------ + drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 33 ++++------- + drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 29 +++------ + drivers/net/wireless/rtlwifi/rtl8192de/fw.c | 8 -- + drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 3 - + drivers/net/wireless/rtlwifi/rtl8192de/sw.c | 38 +++++------- + drivers/net/wireless/rtlwifi/rtl8192se/fw.c | 2 + drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 16 +++-- + drivers/net/wireless/rtlwifi/rtl8192se/led.c | 5 + + drivers/net/wireless/rtlwifi/rtl8192se/sw.c | 65 ++++++++++++++++------ + drivers/net/wireless/rtlwifi/usb.c | 36 +++++------- + drivers/net/wireless/rtlwifi/wifi.h | 4 + + 20 files changed, 192 insertions(+), 166 deletions(-) + +--- a/drivers/net/wireless/rtlwifi/base.c ++++ b/drivers/net/wireless/rtlwifi/base.c +@@ -413,6 +413,7 @@ void rtl_init_rfkill(struct ieee80211_hw + + wiphy_rfkill_start_polling(hw->wiphy); + } ++EXPORT_SYMBOL(rtl_init_rfkill); + + void rtl_deinit_rfkill(struct ieee80211_hw *hw) + { +--- a/drivers/net/wireless/rtlwifi/core.c ++++ b/drivers/net/wireless/rtlwifi/core.c +@@ -31,8 +31,50 @@ + #include "core.h" + #include "cam.h" + #include "base.h" ++#include "pci.h" + #include "ps.h" + ++#include ++ ++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) + { +--- a/drivers/net/wireless/rtlwifi/core.h ++++ b/drivers/net/wireless/rtlwifi/core.h +@@ -30,8 +30,6 @@ + #ifndef __RTL_CORE_H__ + #define __RTL_CORE_H__ + +-#include +- + #define RTL_SUPPORTED_FILTERS \ + (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | FIF_CONTROL | \ +@@ -42,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 +--- a/drivers/net/wireless/rtlwifi/pci.c ++++ b/drivers/net/wireless/rtlwifi/pci.c +@@ -28,8 +28,8 @@ + *****************************************************************************/ + + #include +-#include "core.h" + #include "wifi.h" ++#include "core.h" + #include "pci.h" + #include "base.h" + #include "ps.h" +@@ -1579,6 +1579,9 @@ static void rtl_pci_stop(struct ieee8021 + + 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); +@@ -1797,6 +1800,7 @@ int __devinit rtl_pci_probe(struct pci_d + 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; +@@ -1817,7 +1821,7 @@ int __devinit rtl_pci_probe(struct pci_d + 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); +@@ -1883,15 +1887,6 @@ int __devinit rtl_pci_probe(struct pci_d + 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, +@@ -1899,9 +1894,6 @@ int __devinit rtl_pci_probe(struct pci_d + 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); +@@ -1910,24 +1902,22 @@ int __devinit rtl_pci_probe(struct pci_d + ("%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: + +@@ -1946,6 +1936,8 @@ void rtl_pci_disconnect(struct pci_dev * + 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); +--- a/drivers/net/wireless/rtlwifi/pci.h ++++ b/drivers/net/wireless/rtlwifi/pci.h +@@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_d + 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); +--- a/drivers/net/wireless/rtlwifi/ps.c ++++ b/drivers/net/wireless/rtlwifi/ps.c +@@ -47,7 +47,8 @@ bool rtl_ps_enable_nic(struct ieee80211_ + ("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 */ +--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +@@ -262,10 +262,9 @@ int rtl92c_download_fw(struct ieee80211_ + 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; +@@ -518,15 +517,8 @@ static void _rtl92c_fill_h2c_command(str + 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); +--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +@@ -921,10 +921,7 @@ int rtl92ce_hw_init(struct ieee80211_hw + ("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; +@@ -1199,7 +1196,6 @@ static void _rtl92ce_poweroff_adapter(st + { + 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; + +@@ -1210,7 +1206,7 @@ static void _rtl92ce_poweroff_adapter(st + 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); +--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +@@ -92,9 +92,7 @@ int rtl92c_init_sw_vars(struct ieee80211 + 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); + +@@ -166,26 +164,20 @@ int rtl92c_init_sw_vars(struct ieee80211 + /* 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; + } +--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +@@ -1171,10 +1171,7 @@ int rtl92cu_hw_init(struct ieee80211_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); +@@ -1270,24 +1267,22 @@ static void _ResetDigitalProcedure1(str + 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 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); +- } ++ /* if 8051 reset fail, reset MAC. */ ++ rtl_write_byte(rtlpriv, ++ REG_SYS_FUNC_EN + 1, ++ 0x50); ++ udelay(100); + } + } + /* Reset MAC and Enable 8051 */ +--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +@@ -54,7 +54,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; +@@ -62,29 +61,21 @@ static int rtl92cu_init_sw_vars(struct i + 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; + } +--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c +@@ -257,7 +257,7 @@ int rtl92d_download_fw(struct ieee80211_ + 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; +@@ -539,14 +539,8 @@ static void _rtl92d_fill_h2c_command(str + 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); +--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +@@ -932,10 +932,7 @@ int rtl92de_hw_init(struct ieee80211_hw + 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; +--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +@@ -94,7 +94,6 @@ static int rtl92d_init_sw_vars(struct ie + 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; +@@ -170,6 +169,15 @@ static int rtl92d_init_sw_vars(struct ie + 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) { +@@ -178,33 +186,21 @@ static int rtl92d_init_sw_vars(struct ie + 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; + } + +--- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +@@ -364,7 +364,7 @@ int rtl92s_download_fw(struct ieee80211_ + 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; +--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +@@ -952,11 +952,10 @@ int rtl92se_hw_init(struct ieee80211_hw + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Failed to download FW. " +- "Init HW without FW now.., Please copy FW into" ++ "Init HW without FW now.., " ++ "Please copy FW into" + "/lib/firmware/rtlwifi\n")); +- rtlhal->fw_ready = false; +- } else { +- rtlhal->fw_ready = true; ++ return 1; + } + + /* After FW download, we have to reset MAC register */ +@@ -1219,9 +1218,14 @@ void rtl92se_enable_interrupt(struct iee + + 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); + +--- a/drivers/net/wireless/rtlwifi/rtl8192se/led.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c +@@ -76,10 +76,13 @@ void rtl92se_sw_led_on(struct ieee80211_ + + 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)); + +--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c ++++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +@@ -35,6 +35,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" +@@ -89,12 +91,53 @@ static void rtl92s_init_aspm_vars(struct + 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; + +@@ -192,27 +235,19 @@ static int rtl92s_init_sw_vars(struct ie + 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; + } +--- a/drivers/net/wireless/rtlwifi/usb.c ++++ b/drivers/net/wireless/rtlwifi/usb.c +@@ -29,8 +29,8 @@ + + #include + #include +-#include "core.h" + #include "wifi.h" ++#include "core.h" + #include "usb.h" + #include "base.h" + #include "ps.h" +@@ -667,15 +667,17 @@ static int rtl_usb_start(struct ieee8021 + 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; + } +@@ -952,6 +954,7 @@ int __devinit rtl_usb_probe(struct usb_i + 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); +@@ -986,24 +989,12 @@ int __devinit rtl_usb_probe(struct usb_i + 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); +@@ -1017,6 +1008,9 @@ void rtl_usb_disconnect(struct usb_inter + + 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); +--- a/drivers/net/wireless/rtlwifi/wifi.h ++++ b/drivers/net/wireless/rtlwifi/wifi.h +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include "debug.h" + + #define RF_CHANGE_BY_INIT 0 +@@ -1045,7 +1046,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; +@@ -1591,6 +1591,7 @@ struct rtl_debug { + }; + + struct rtl_priv { ++ struct completion firmware_loading_complete; + struct rtl_locks locks; + struct rtl_works works; + struct rtl_mac mac80211; +@@ -1612,6 +1613,7 @@ struct rtl_priv { + struct rtl_rate_priv *rate_priv; + + struct rtl_debug dbg; ++ int max_fw_size; + + /* + *hal_cfg : for diff cards diff --git a/queue-3.3/series b/queue-3.3/series index 9fa7f283469..02f7286bdca 100644 --- a/queue-3.3/series +++ b/queue-3.3/series @@ -125,3 +125,9 @@ pvrusb2-fix-7mhz-8mhz-dvb-t-tuner-support-for-hvr1900-rev-d1f5.patch mxl111sf-fix-error-on-stream-stop-in-mxl111sf_ep6_streaming_ctrl.patch pm-domains-fix-hibernation-restore-of-devices-v2.patch pm-domains-check-domain-status-during-hibernation-restore-of-devices.patch +pm-domains-introduce-always-on-device-flag.patch +pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch +pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch +pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch +rtlwifi-convert-to-asynchronous-firmware-load.patch +staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch diff --git a/queue-3.3/staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch b/queue-3.3/staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch new file mode 100644 index 00000000000..10afc87d6fc --- /dev/null +++ b/queue-3.3/staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch @@ -0,0 +1,101 @@ +From 073863432f7eaa23c7c09733414d4be2eabf5eef Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Thu, 9 Feb 2012 16:37:17 -0600 +Subject: staging: r8712u: Add missing initialization and remove configuration parameter CONFIG_R8712_AP + +From: Larry Finger + +commit 073863432f7eaa23c7c09733414d4be2eabf5eef upstream. + +When this driver was upgraded to the vendor 20100831 version in +commit 93c55dda092c7 et al,, one listhead initialization was missed. +This broke complete operation of the driver whenever AP mode was +enabled. This fixes https://bugs.archlinux.org/task/27996. + +The configuration parameter R8712_AP is misleading as the driver cannot +function as an AP without a heavily hacked version of hostapd. Thus, it +makes sense to remove the parameter; however the code and data configured +for the option is left in. + +Signed-off-by: Larry Finger +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/staging/rtl8712/Kconfig | 7 ------- + drivers/staging/rtl8712/rtl871x_sta_mgt.c | 4 ---- + drivers/staging/rtl8712/sta_info.h | 4 ---- + 3 files changed, 15 deletions(-) + +--- a/drivers/staging/rtl8712/Kconfig ++++ b/drivers/staging/rtl8712/Kconfig +@@ -9,13 +9,6 @@ config R8712U + This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130. + If built as a module, it will be called r8712u. + +-config R8712_AP +- bool "Realtek RTL8712U AP code" +- depends on R8712U +- default N +- ---help--- +- This option allows the Realtek RTL8712 USB device to be an Access Point. +- + config R8712_TX_AGGR + bool "Realtek RTL8712U Transmit Aggregation code" + depends on R8712U && BROKEN +--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c ++++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c +@@ -42,10 +42,8 @@ static void _init_stainfo(struct sta_inf + _init_listhead(&psta->hash_list); + _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); + _r8712_init_sta_recv_priv(&psta->sta_recvpriv); +-#ifdef CONFIG_R8712_AP + _init_listhead(&psta->asoc_list); + _init_listhead(&psta->auth_list); +-#endif + } + + u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) +@@ -72,10 +70,8 @@ u32 _r8712_init_sta_priv(struct sta_priv + get_list_head(&pstapriv->free_sta_queue)); + psta++; + } +-#ifdef CONFIG_R8712_AP + _init_listhead(&pstapriv->asoc_list); + _init_listhead(&pstapriv->auth_list); +-#endif + return _SUCCESS; + } + +--- a/drivers/staging/rtl8712/sta_info.h ++++ b/drivers/staging/rtl8712/sta_info.h +@@ -90,7 +90,6 @@ struct sta_info { + * curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO + * sta_info: (AP & STA) CAP/INFO + */ +-#ifdef CONFIG_R8712_AP + struct list_head asoc_list; + struct list_head auth_list; + unsigned int expire_to; +@@ -98,7 +97,6 @@ struct sta_info { + unsigned int authalg; + unsigned char chg_txt[128]; + unsigned int tx_ra_bitmap; +-#endif + }; + + struct sta_priv { +@@ -111,13 +109,11 @@ struct sta_priv { + struct __queue sleep_q; + struct __queue wakeup_q; + struct _adapter *padapter; +-#ifdef CONFIG_R8712_AP + struct list_head asoc_list; + struct list_head auth_list; + unsigned int auth_to; /* sec, time to expire in authenticating. */ + unsigned int assoc_to; /* sec, time to expire before associating. */ + unsigned int expire_to; /* sec , time to expire after associated. */ +-#endif + }; + + static inline u32 wifi_mac_hash(u8 *mac) -- 2.47.3