Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/apm
[cascardo/linux.git] / drivers / net / wireless / brcm80211 / brcmsmac / mac80211_if.c
index 0d8a9cd..d106576 100644 (file)
 #define __UNDEF_NO_VERSION__
 
 #include <linux/etherdevice.h>
-#include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/bcma/bcma.h>
 #include <net/mac80211.h>
 #include <defs.h>
 #include "nicpci.h"
 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
        FIF_ALLMULTI | \
        FIF_FCSFAIL | \
-       FIF_PLCPFAIL | \
        FIF_CONTROL | \
        FIF_OTHER_BSS | \
-       FIF_BCN_PRBRESP_PROMISC)
+       FIF_BCN_PRBRESP_PROMISC | \
+       FIF_PSPOLL)
 
 #define CHAN2GHZ(channel, freqency, chflags)  { \
        .band = IEEE80211_BAND_2GHZ, \
@@ -87,16 +87,14 @@ MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
-/* recognized PCI IDs */
-static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */
-       {0}
-};
 
-MODULE_DEVICE_TABLE(pci, brcms_pci_id_table);
+/* recognized BCMA Core IDs */
+static struct bcma_device_id brcms_coreid_table[] = {
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
+       BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
 
 #ifdef BCMDBG
 static int msglevel = 0xdeadbeef;
@@ -216,8 +214,7 @@ static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
        .ht_cap = {
                   /* from include/linux/ieee80211.h */
                   .cap = IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+                         IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -238,8 +235,7 @@ static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
                        BRCMS_LEGACY_5G_RATE_OFFSET,
        .ht_cap = {
                   .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
-                         IEEE80211_HT_CAP_SGI_40 |
-                         IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+                         IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -287,6 +283,7 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
 {
        struct brcms_info *wl = hw->priv;
        bool blocked;
+       int err;
 
        ieee80211_wake_queues(hw);
        spin_lock_bh(&wl->lock);
@@ -295,57 +292,69 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (!blocked)
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
 
-       return 0;
+       spin_lock_bh(&wl->lock);
+       /* avoid acknowledging frames before a non-monitor device is added */
+       wl->mute_tx = true;
+
+       if (!wl->pub->up)
+               err = brcms_up(wl);
+       else
+               err = -ENODEV;
+       spin_unlock_bh(&wl->lock);
+
+       if (err != 0)
+               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
+                         err);
+       return err;
 }
 
 static void brcms_ops_stop(struct ieee80211_hw *hw)
 {
+       struct brcms_info *wl = hw->priv;
+       int status;
+
        ieee80211_stop_queues(hw);
+
+       if (wl->wlc == NULL)
+               return;
+
+       spin_lock_bh(&wl->lock);
+       status = brcms_c_chipmatch(wl->wlc->hw->vendorid,
+                                  wl->wlc->hw->deviceid);
+       spin_unlock_bh(&wl->lock);
+       if (!status) {
+               wiphy_err(wl->wiphy,
+                         "wl: brcms_ops_stop: chipmatch failed\n");
+               return;
+       }
+
+       /* put driver in down state */
+       spin_lock_bh(&wl->lock);
+       brcms_down(wl);
+       spin_unlock_bh(&wl->lock);
 }
 
 static int
 brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-       int err;
+       struct brcms_info *wl = hw->priv;
 
        /* Just STA for now */
-       if (vif->type != NL80211_IFTYPE_AP &&
-           vif->type != NL80211_IFTYPE_MESH_POINT &&
-           vif->type != NL80211_IFTYPE_STATION &&
-           vif->type != NL80211_IFTYPE_WDS &&
-           vif->type != NL80211_IFTYPE_ADHOC) {
+       if (vif->type != NL80211_IFTYPE_STATION) {
                wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
                          " STA for now\n", __func__, vif->type);
                return -EOPNOTSUPP;
        }
 
-       wl = hw->priv;
-       spin_lock_bh(&wl->lock);
-       if (!wl->pub->up)
-               err = brcms_up(wl);
-       else
-               err = -ENODEV;
-       spin_unlock_bh(&wl->lock);
+       wl->mute_tx = false;
+       brcms_c_mute(wl->wlc, false);
 
-       if (err != 0)
-               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
-                         err);
-
-       return err;
+       return 0;
 }
 
 static void
 brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-
-       wl = hw->priv;
-
-       /* put driver in down state */
-       spin_lock_bh(&wl->lock);
-       brcms_down(wl);
-       spin_unlock_bh(&wl->lock);
 }
 
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -362,7 +371,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
                                                   conf->listen_interval);
        }
        if (changed & IEEE80211_CONF_CHANGE_MONITOR)
-               wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
+               wiphy_dbg(wiphy, "%s: change monitor mode: %s\n",
                          __func__, conf->flags & IEEE80211_CONF_MONITOR ?
                          "true" : "false");
        if (changed & IEEE80211_CONF_CHANGE_PS)
@@ -539,29 +548,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
 
        changed_flags &= MAC_FILTERS;
        *total_flags &= MAC_FILTERS;
+
        if (changed_flags & FIF_PROMISC_IN_BSS)
-               wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n");
+               wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n");
        if (changed_flags & FIF_ALLMULTI)
-               wiphy_err(wiphy, "FIF_ALLMULTI\n");
+               wiphy_dbg(wiphy, "FIF_ALLMULTI\n");
        if (changed_flags & FIF_FCSFAIL)
-               wiphy_err(wiphy, "FIF_FCSFAIL\n");
-       if (changed_flags & FIF_PLCPFAIL)
-               wiphy_err(wiphy, "FIF_PLCPFAIL\n");
+               wiphy_dbg(wiphy, "FIF_FCSFAIL\n");
        if (changed_flags & FIF_CONTROL)
-               wiphy_err(wiphy, "FIF_CONTROL\n");
+               wiphy_dbg(wiphy, "FIF_CONTROL\n");
        if (changed_flags & FIF_OTHER_BSS)
-               wiphy_err(wiphy, "FIF_OTHER_BSS\n");
-       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-               spin_lock_bh(&wl->lock);
-               if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
-                       wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
-                       brcms_c_mac_bcn_promisc_change(wl->wlc, 1);
-               } else {
-                       brcms_c_mac_bcn_promisc_change(wl->wlc, 0);
-                       wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
-               }
-               spin_unlock_bh(&wl->lock);
-       }
+               wiphy_dbg(wiphy, "FIF_OTHER_BSS\n");
+       if (changed_flags & FIF_PSPOLL)
+               wiphy_dbg(wiphy, "FIF_PSPOLL\n");
+       if (changed_flags & FIF_BCN_PRBRESP_PROMISC)
+               wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n");
+
+       spin_lock_bh(&wl->lock);
+       brcms_c_mac_promisc(wl->wlc, *total_flags);
+       spin_unlock_bh(&wl->lock);
        return;
 }
 
@@ -609,13 +614,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        wl->pub->global_ampdu->scb = scb;
        wl->pub->global_ampdu->max_pdu = 16;
 
-       sta->ht_cap.ht_supported = true;
-       sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
-       sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
-           IEEE80211_HT_CAP_SGI_20 |
-           IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
-
        /*
         * minstrel_ht initiates addBA on our behalf by calling
         * ieee80211_start_tx_ba_session()
@@ -724,7 +722,7 @@ static const struct ieee80211_ops brcms_ops = {
 };
 
 /*
- * is called in brcms_pci_probe() context, therefore no locking required.
+ * is called in brcms_bcma_probe() context, therefore no locking required.
  */
 static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
 {
@@ -864,56 +862,26 @@ static void brcms_free(struct brcms_info *wl)
 #endif
                kfree(t);
        }
-
-       /*
-        * unregister_netdev() calls get_stats() which may read chip
-        * registers so we cannot unmap the chip registers until
-        * after calling unregister_netdev() .
-        */
-       if (wl->regsva)
-               iounmap(wl->regsva);
-
-       wl->regsva = NULL;
 }
 
 /*
-* called from both kernel as from this kernel module.
+* called from both kernel as from this kernel module (error flow on attach)
 * precondition: perimeter lock is not acquired.
 */
-static void brcms_remove(struct pci_dev *pdev)
+static void brcms_remove(struct bcma_device *pdev)
 {
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
-       int status;
-
-       hw = pci_get_drvdata(pdev);
-       wl = hw->priv;
-       if (!wl) {
-               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
-               return;
-       }
+       struct ieee80211_hw *hw = bcma_get_drvdata(pdev);
+       struct brcms_info *wl = hw->priv;
 
-       spin_lock_bh(&wl->lock);
-       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
-       spin_unlock_bh(&wl->lock);
-       if (!status) {
-               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
-                                    "failed\n");
-               return;
-       }
        if (wl->wlc) {
                wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
                ieee80211_unregister_hw(hw);
-               spin_lock_bh(&wl->lock);
-               brcms_down(wl);
-               spin_unlock_bh(&wl->lock);
        }
-       pci_disable_device(pdev);
 
        brcms_free(wl);
 
-       pci_set_drvdata(pdev, NULL);
+       bcma_set_drvdata(pdev, NULL);
        ieee80211_free_hw(hw);
 }
 
@@ -1021,11 +989,9 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
  * it as static.
  *
  *
- * is called in brcms_pci_probe() context, therefore no locking required.
+ * is called in brcms_bcma_probe() context, therefore no locking required.
  */
-static struct brcms_info *brcms_attach(u16 vendor, u16 device,
-                                      resource_size_t regs,
-                                      struct pci_dev *btparam, uint irq)
+static struct brcms_info *brcms_attach(struct bcma_device *pdev)
 {
        struct brcms_info *wl = NULL;
        int unit, err;
@@ -1039,7 +1005,7 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
                return NULL;
 
        /* allocate private info */
-       hw = pci_get_drvdata(btparam);  /* btparam == pdev */
+       hw = bcma_get_drvdata(pdev);
        if (hw != NULL)
                wl = hw->priv;
        if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL))
@@ -1051,26 +1017,20 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
        /* setup the bottom half handler */
        tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
 
-       wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ);
-       if (wl->regsva == NULL) {
-               wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit);
-               goto fail;
-       }
        spin_lock_init(&wl->lock);
        spin_lock_init(&wl->isr_lock);
 
        /* prepare ucode */
-       if (brcms_request_fw(wl, btparam) < 0) {
+       if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) {
                wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
                          "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
                brcms_release_fw(wl);
-               brcms_remove(btparam);
+               brcms_remove(pdev);
                return NULL;
        }
 
        /* common load-time initialization */
-       wl->wlc = brcms_c_attach(wl, vendor, device, unit, false,
-                                wl->regsva, btparam, &err);
+       wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err);
        brcms_release_fw(wl);
        if (!wl->wlc) {
                wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
@@ -1081,15 +1041,13 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
 
        wl->pub->ieee_hw = hw;
 
-       /* disable mpc */
-       brcms_c_set_radio_mpc(wl->wlc, false);
-
        /* register our interrupt handler */
-       if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
+       if (request_irq(pdev->bus->host_pci->irq, brcms_isr,
+                       IRQF_SHARED, KBUILD_MODNAME, wl)) {
                wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
                goto fail;
        }
-       wl->irq = irq;
+       wl->irq = pdev->bus->host_pci->irq;
 
        /* register module */
        brcms_c_module_register(wl->pub, "linux", wl, NULL);
@@ -1136,38 +1094,19 @@ fail:
  *
  * Perimeter lock is initialized in the course of this function.
  */
-static int __devinit
-brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit brcms_bcma_probe(struct bcma_device *pdev)
 {
-       int rc;
        struct brcms_info *wl;
        struct ieee80211_hw *hw;
-       u32 val;
 
-       dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n",
-              pdev->bus->number, PCI_SLOT(pdev->devfn),
-              PCI_FUNC(pdev->devfn), pdev->irq);
+       dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
+                pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
+                pdev->bus->host_pci->irq);
 
-       if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) ||
-           ((pdev->device != 0x0576) &&
-            ((pdev->device & 0xff00) != 0x4300) &&
-            ((pdev->device & 0xff00) != 0x4700) &&
-            ((pdev->device < 43000) || (pdev->device > 43999))))
+       if ((pdev->id.manuf != BCMA_MANUF_BCM) ||
+           (pdev->id.id != BCMA_CORE_80211))
                return -ENODEV;
 
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               pr_err("%s: Cannot enable device %d-%d_%d\n",
-                      __func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
-                      PCI_FUNC(pdev->devfn));
-               return -ENODEV;
-       }
-       pci_set_master(pdev);
-
-       pci_read_config_dword(pdev, 0x40, &val);
-       if ((val & 0x0000ff00) != 0)
-               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
        hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);
        if (!hw) {
                pr_err("%s: ieee80211_alloc_hw failed\n", __func__);
@@ -1176,14 +1115,11 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
-       pci_set_drvdata(pdev, hw);
+       bcma_set_drvdata(pdev, hw);
 
        memset(hw->priv, 0, sizeof(*wl));
 
-       wl = brcms_attach(pdev->vendor, pdev->device,
-                         pci_resource_start(pdev, 0), pdev,
-                         pdev->irq);
-
+       wl = brcms_attach(pdev);
        if (!wl) {
                pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME,
                       __func__);
@@ -1192,16 +1128,23 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 }
 
-static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
+static int brcms_pci_suspend(struct pci_dev *pdev)
+{
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       return pci_set_power_state(pdev, PCI_D3hot);
+}
+
+static int brcms_suspend(struct bcma_device *pdev, pm_message_t state)
 {
        struct brcms_info *wl;
        struct ieee80211_hw *hw;
 
-       hw = pci_get_drvdata(pdev);
+       hw = bcma_get_drvdata(pdev);
        wl = hw->priv;
        if (!wl) {
                wiphy_err(wl->wiphy,
-                         "brcms_suspend: pci_get_drvdata failed\n");
+                         "brcms_suspend: bcma_get_drvdata failed\n");
                return -ENODEV;
        }
 
@@ -1210,25 +1153,14 @@ static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
        wl->pub->hw_up = false;
        spin_unlock_bh(&wl->lock);
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       return pci_set_power_state(pdev, PCI_D3hot);
+       /* temporarily do suspend ourselves */
+       return brcms_pci_suspend(pdev->bus->host_pci);
 }
 
-static int brcms_resume(struct pci_dev *pdev)
+static int brcms_pci_resume(struct pci_dev *pdev)
 {
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
        int err = 0;
-       u32 val;
-
-       hw = pci_get_drvdata(pdev);
-       wl = hw->priv;
-       if (!wl) {
-               wiphy_err(wl->wiphy,
-                         "wl: brcms_resume: pci_get_drvdata failed\n");
-               return -ENODEV;
-       }
+       uint val;
 
        err = pci_set_power_state(pdev, PCI_D0);
        if (err)
@@ -1246,24 +1178,28 @@ static int brcms_resume(struct pci_dev *pdev)
        if ((val & 0x0000ff00) != 0)
                pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
+       return 0;
+}
+
+static int brcms_resume(struct bcma_device *pdev)
+{
        /*
-       *  done. driver will be put in up state
-       *  in brcms_ops_add_interface() call.
+       *  just do pci resume for now until bcma supports it.
        */
-       return err;
+       return brcms_pci_resume(pdev->bus->host_pci);
 }
 
-static struct pci_driver brcms_pci_driver = {
+static struct bcma_driver brcms_bcma_driver = {
        .name     = KBUILD_MODNAME,
-       .probe    = brcms_pci_probe,
+       .probe    = brcms_bcma_probe,
        .suspend  = brcms_suspend,
        .resume   = brcms_resume,
        .remove   = __devexit_p(brcms_remove),
-       .id_table = brcms_pci_id_table,
+       .id_table = brcms_coreid_table,
 };
 
 /**
- * This is the main entry point for the WL driver.
+ * This is the main entry point for the brcmsmac driver.
  *
  * This function determines if a device pointed to by pdev is a WL device,
  * and if so, performs a brcms_attach() on it.
@@ -1278,26 +1214,24 @@ static int __init brcms_module_init(void)
                brcm_msg_level = msglevel;
 #endif                         /* BCMDBG */
 
-       error = pci_register_driver(&brcms_pci_driver);
+       error = bcma_driver_register(&brcms_bcma_driver);
+       printk(KERN_ERR "%s: register returned %d\n", __func__, error);
        if (!error)
                return 0;
 
-
-
        return error;
 }
 
 /**
- * This function unloads the WL driver from the system.
+ * This function unloads the brcmsmac driver from the system.
  *
- * This function unconditionally unloads the WL driver module from the
+ * This function unconditionally unloads the brcmsmac driver module from the
  * system.
  *
  */
 static void __exit brcms_module_exit(void)
 {
-       pci_unregister_driver(&brcms_pci_driver);
-
+       bcma_driver_unregister(&brcms_bcma_driver);
 }
 
 module_init(brcms_module_init);
@@ -1319,8 +1253,7 @@ void brcms_init(struct brcms_info *wl)
 {
        BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_reset(wl);
-
-       brcms_c_init(wl->wlc);
+       brcms_c_init(wl->wlc, wl->mute_tx);
 }
 
 /*
@@ -1332,11 +1265,19 @@ uint brcms_reset(struct brcms_info *wl)
        brcms_c_reset(wl->wlc);
 
        /* dpc will not be rescheduled */
-       wl->resched = 0;
+       wl->resched = false;
 
        return 0;
 }
 
+void brcms_fatal_error(struct brcms_info *wl)
+{
+       wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+                 wl->wlc->pub->unit);
+       brcms_reset(wl);
+       ieee80211_restart_hw(wl->pub->ieee_hw);
+}
+
 /*
  * These are interrupt on/off entry points. Disable interrupts
  * during interrupt state transition.
@@ -1561,11 +1502,10 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
                        if (le32_to_cpu(hdr->idx) == idx) {
                                pdata = wl->fw.fw_bin[i]->data +
                                        le32_to_cpu(hdr->offset);
-                               *pbuf = kmalloc(len, GFP_ATOMIC);
+                               *pbuf = kmemdup(pdata, len, GFP_ATOMIC);
                                if (*pbuf == NULL)
                                        goto fail;
 
-                               memcpy(*pbuf, pdata, len);
                                return 0;
                        }
                }
@@ -1578,7 +1518,7 @@ fail:
 }
 
 /*
- * Precondition: Since this function is called in brcms_pci_probe() context,
+ * Precondition: Since this function is called in brcms_bcma_probe() context,
  * no locking is required.
  */
 int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
@@ -1618,7 +1558,7 @@ void brcms_ucode_free_buf(void *p)
 /*
  * checks validity of all firmware images loaded from user space
  *
- * Precondition: Since this function is called in brcms_pci_probe() context,
+ * Precondition: Since this function is called in brcms_bcma_probe() context,
  * no locking is required.
  */
 int brcms_check_firmwares(struct brcms_info *wl)