]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 26 Mar 2012 22:11:53 +0000 (15:11 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 26 Mar 2012 22:11:53 +0000 (15:11 -0700)
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

queue-3.3/pm-domains-introduce-always-on-device-flag.patch [new file with mode: 0644]
queue-3.3/pm-shmobile-make-cmt-driver-use-pm_genpd_dev_always_on.patch [new file with mode: 0644]
queue-3.3/pm-shmobile-make-mtu2-driver-use-pm_genpd_dev_always_on.patch [new file with mode: 0644]
queue-3.3/pm-shmobile-make-tmu-driver-use-pm_genpd_dev_always_on.patch [new file with mode: 0644]
queue-3.3/rtlwifi-convert-to-asynchronous-firmware-load.patch [new file with mode: 0644]
queue-3.3/series
queue-3.3/staging-r8712u-add-missing-initialization-and-remove-configuration-parameter-config_r8712_ap.patch [new file with mode: 0644]

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 (file)
index 0000000..b14dba6
--- /dev/null
@@ -0,0 +1,154 @@
+From rjw@sisk.pl  Mon Mar 26 15:02:14 2012
+From: "Rafael J. Wysocki" <rjw@sisk.pl>
+Date: Mon, 26 Mar 2012 23:25:24 +0200
+Subject: PM / Domains: Introduce "always on" device flag
+To: Greg KH <gregkh@linuxfoundation.org>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Tested-by: Simon Horman <horms@verge.net.au>
+Acked-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..378e4ec
--- /dev/null
@@ -0,0 +1,46 @@
+From rjw@sisk.pl  Mon Mar 26 15:03:04 2012
+From: "Rafael J. Wysocki" <rjw@sisk.pl>
+Date: Mon, 26 Mar 2012 23:26:53 +0200
+Subject: PM / shmobile: Make CMT driver use pm_genpd_dev_always_on()
+To: Greg KH <gregkh@linuxfoundation.org>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Tested-by: Simon Horman <horms@verge.net.au>
+Acked-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/sh_timer.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
++#include <linux/pm_domain.h>
+ 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 (file)
index 0000000..a2f6775
--- /dev/null
@@ -0,0 +1,46 @@
+From rjw@sisk.pl  Mon Mar 26 15:03:17 2012
+From: "Rafael J. Wysocki" <rjw@sisk.pl>
+Date: Mon, 26 Mar 2012 23:27:33 +0200
+Subject: PM / shmobile: Make MTU2 driver use pm_genpd_dev_always_on()
+To: Greg KH <gregkh@linuxfoundation.org>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Tested-by: Simon Horman <horms@verge.net.au>
+Acked-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/sh_timer.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
++#include <linux/pm_domain.h>
+ 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 (file)
index 0000000..900ee66
--- /dev/null
@@ -0,0 +1,60 @@
+From rjw@sisk.pl  Mon Mar 26 15:02:35 2012
+From: "Rafael J. Wysocki" <rjw@sisk.pl>
+Date: Mon, 26 Mar 2012 23:26:10 +0200
+Subject: PM / shmobile: Make TMU driver use pm_genpd_dev_always_on()
+To: Greg KH <gregkh@linuxfoundation.org>
+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 <rjw@sisk.pl>
+
+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 <rjw@sisk.pl>
+Tested-by: Simon Horman <horms@verge.net.au>
+Acked-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/sh_timer.h>
+ #include <linux/slab.h>
+ #include <linux/module.h>
++#include <linux/pm_domain.h>
+ 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 (file)
index 0000000..b988a61
--- /dev/null
@@ -0,0 +1,852 @@
+From b0302aba812bcc39291cdab9ad7e37008f352a91 Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+Date: Mon, 30 Jan 2012 09:54:49 -0600
+Subject: rtlwifi: Convert to asynchronous firmware load
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+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 <Larry.Finger@lwfinger.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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 <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)
+ {
+--- 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 <net/mac80211.h>
+-
+ #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 <linux/export.h>
+-#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 <linux/usb.h>
+ #include <linux/export.h>
+-#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 <linux/vmalloc.h>
+ #include <linux/usb.h>
+ #include <net/mac80211.h>
++#include <linux/completion.h>
+ #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
index 9fa7f283469a2b0d5fd1a531ca2df505d74762c0..02f7286bdcad3f60ff4e216bb16085c35e940b0b 100644 (file)
@@ -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 (file)
index 0000000..10afc87
--- /dev/null
@@ -0,0 +1,101 @@
+From 073863432f7eaa23c7c09733414d4be2eabf5eef Mon Sep 17 00:00:00 2001
+From: Larry Finger <Larry.Finger@lwfinger.net>
+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 <Larry.Finger@lwfinger.net>
+
+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 <Larry.Finger@lwfinger.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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)