Upgrade b43 and mac80211.
[openwrt/staging/lynxis/omap.git] / package / b43 / src / main.c
index 9f8175c25a8a2785887e930a23613eed10282c30..afb109447a45d4e7341d413a1a381277b781d0c4 100644 (file)
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -46,7 +46,6 @@
 #include "debugfs.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
@@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-extern char *nvram_get(char *name);
-
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static int modparam_pio;
-module_param_named(pio, modparam_pio, int, 0444);
-MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
-#elif defined(CONFIG_B43_DMA)
-# define modparam_pio  0
-#elif defined(CONFIG_B43_PIO)
-# define modparam_pio  1
-#endif
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
 MODULE_PARM_DESC(bad_frames_preempt,
                 "enable(1) / disable(0) Bad Frames Preemption");
 
-static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
-module_param_named(short_retry, modparam_short_retry, int, 0444);
-MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
-
-static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
-module_param_named(long_retry, modparam_long_retry, int, 0444);
-MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
@@ -101,52 +81,41 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
        SSB_DEVTABLE_END
 };
 
 MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
 
-static const struct pci_device_id b43_pci_bridge_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
-
-static struct pci_driver b43_pci_bridge_driver = {
-       .name = "b43-pci-bridge",
-       .id_table = b43_pci_bridge_tbl,
-};
 /* Channel and ratetables are shared for all devices.
  * They can't be const, because ieee80211 puts some precalculated
  * data in there. This data is the same for all devices, so we don't
  * get concurrency issues */
 #define RATETAB_ENT(_rateid, _flags) \
-       {                                                       \
-               .rate   = B43_RATE_TO_BASE100KBPS(_rateid),     \
-               .val    = (_rateid),                            \
-               .val2   = (_rateid),                            \
-               .flags  = (_flags),                             \
+       {                                                               \
+               .bitrate        = B43_RATE_TO_BASE100KBPS(_rateid),     \
+               .hw_value       = (_rateid),                            \
+               .flags          = (_flags),                             \
        }
+
+/*
+ * NOTE: When changing this, sync with xmit.c's
+ *      b43_plcp_get_bitrate_idx_* functions!
+ */
 static struct ieee80211_rate __b43_ratetable[] = {
-       RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
-       RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
-       RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
-       RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+       RATETAB_ENT(B43_CCK_RATE_1MB, 0),
+       RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
+       RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
 };
 
 #define b43_a_ratetable                (__b43_ratetable + 4)
@@ -158,16 +127,10 @@ static struct ieee80211_rate __b43_ratetable[] = {
 
 #define CHANTAB_ENT(_chanid, _freq) \
        {                                                       \
-               .chan   = (_chanid),                            \
-               .freq   = (_freq),                              \
-               .val    = (_chanid),                            \
-               .flag   = IEEE80211_CHAN_W_SCAN |               \
-                         IEEE80211_CHAN_W_ACTIVE_SCAN |        \
-                         IEEE80211_CHAN_W_IBSS,                \
-               .power_level    = 0xFF,                         \
-               .antenna_max    = 0xFF,                         \
+               .center_freq    = (_freq),                      \
+               .hw_value       = (_chanid),                    \
        }
-static struct ieee80211_channel b43_bg_chantable[] = {
+static struct ieee80211_channel b43_2ghz_chantable[] = {
        CHANTAB_ENT(1, 2412),
        CHANTAB_ENT(2, 2417),
        CHANTAB_ENT(3, 2422),
@@ -184,8 +147,8 @@ static struct ieee80211_channel b43_bg_chantable[] = {
        CHANTAB_ENT(14, 2484),
 };
 
-#define b43_bg_chantable_size  ARRAY_SIZE(b43_bg_chantable)
-static struct ieee80211_channel b43_a_chantable[] = {
+#ifdef NOTYET
+static struct ieee80211_channel b43_5ghz_chantable[] = {
        CHANTAB_ENT(36, 5180),
        CHANTAB_ENT(40, 5200),
        CHANTAB_ENT(44, 5220),
@@ -201,7 +164,20 @@ static struct ieee80211_channel b43_a_chantable[] = {
        CHANTAB_ENT(165, 5825),
 };
 
-#define b43_a_chantable_size   ARRAY_SIZE(b43_a_chantable)
+static struct ieee80211_supported_band b43_band_5GHz = {
+       .channels = b43_5ghz_chantable,
+       .n_channels = ARRAY_SIZE(b43_5ghz_chantable),
+       .bitrates = b43_a_ratetable,
+       .n_bitrates = b43_a_ratetable_size,
+};
+#endif
+
+static struct ieee80211_supported_band b43_band_2GHz = {
+       .channels = b43_2ghz_chantable,
+       .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
+       .bitrates = b43_g_ratetable,
+       .n_bitrates = b43_g_ratetable_size,
+};
 
 static void b43_wireless_core_exit(struct b43_wldev *dev);
 static int b43_wireless_core_init(struct b43_wldev *dev);
@@ -286,13 +262,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
        b43_write32(dev, B43_MMIO_RAM_DATA, val);
 }
 
-static inline
-    void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+static inline void b43_shm_control_word(struct b43_wldev *dev,
+                                       u16 routing, u16 offset)
 {
        u32 control;
 
        /* "offset" is the WORD offset. */
-
        control = routing;
        control <<= 16;
        control |= offset;
@@ -301,8 +276,11 @@ static inline
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
        u32 ret;
 
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -313,20 +291,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
                        b43_shm_control_word(dev, routing, (offset >> 2) + 1);
                        ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
 
-                       return ret;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 
        return ret;
 }
 
 u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
        u16 ret;
 
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
@@ -334,55 +317,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
                        b43_shm_control_word(dev, routing, offset >> 2);
                        ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
 
-                       return ret;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
        ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 
        return ret;
 }
 
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
                        /* Unaligned access */
                        b43_shm_control_word(dev, routing, offset >> 2);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
                                    (value >> 16) & 0xffff);
-                       mmiowb();
                        b43_shm_control_word(dev, routing, (offset >> 2) + 1);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-                       return;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
-       mmiowb();
        b43_write32(dev, B43_MMIO_SHM_DATA, value);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
+       struct b43_wl *wl = dev->wl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->shm_lock, flags);
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
                if (offset & 0x0003) {
                        /* Unaligned access */
                        b43_shm_control_word(dev, routing, offset >> 2);
-                       mmiowb();
                        b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-                       return;
+                       goto out;
                }
                offset >>= 2;
        }
        b43_shm_control_word(dev, routing, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_SHM_DATA, value);
+out:
+       spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 /* Read HostFlags */
@@ -1029,9 +1020,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
 static void b43_generate_noise_sample(struct b43_wldev *dev)
 {
        b43_jssi_write(dev, 0x7F7F7F7F);
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-                   b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-                   | (1 << 4));
+       b43_write32(dev, B43_MMIO_MACCMD,
+                   b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
        B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
 }
 
@@ -1117,18 +1107,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev)
                if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
                        b43_power_saving_ctl_bits(dev, 0);
        }
-       dev->reg124_set_0x4 = 0;
        if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
-               dev->reg124_set_0x4 = 1;
+               dev->dfq_valid = 1;
 }
 
 static void handle_irq_atim_end(struct b43_wldev *dev)
 {
-       if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
-               return;
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-                   b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-                   | 0x4);
+       if (dev->dfq_valid) {
+               b43_write32(dev, B43_MMIO_MACCMD,
+                           b43_read32(dev, B43_MMIO_MACCMD)
+                           | B43_MACCMD_DFQ_VALID);
+               dev->dfq_valid = 0;
+       }
 }
 
 static void handle_irq_pmq(struct b43_wldev *dev)
@@ -1183,29 +1173,74 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
                                      u16 ram_offset,
                                      u16 shm_size_offset, u8 rate)
 {
-       int len;
-       const u8 *data;
+       unsigned int i, len, variable_len;
+       const struct ieee80211_mgmt *bcn;
+       const u8 *ie;
+       bool tim_found = 0;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       len = min((size_t) dev->cached_beacon->len,
+       bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+       len = min((size_t) dev->wl->current_beacon->len,
                  0x200 - sizeof(struct b43_plcp_hdr6));
-       data = (const u8 *)(dev->cached_beacon->data);
-       b43_write_template_common(dev, data,
+
+       b43_write_template_common(dev, (const u8 *)bcn,
                                  len, ram_offset, shm_size_offset, rate);
+
+       /* Find the position of the TIM and the DTIM_period value
+        * and write them to SHM. */
+       ie = bcn->u.beacon.variable;
+       variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+       for (i = 0; i < variable_len - 2; ) {
+               uint8_t ie_id, ie_len;
+
+               ie_id = ie[i];
+               ie_len = ie[i + 1];
+               if (ie_id == 5) {
+                       u16 tim_position;
+                       u16 dtim_period;
+                       /* This is the TIM Information Element */
+
+                       /* Check whether the ie_len is in the beacon data range. */
+                       if (variable_len < ie_len + 2 + i)
+                               break;
+                       /* A valid TIM is at least 4 bytes long. */
+                       if (ie_len < 4)
+                               break;
+                       tim_found = 1;
+
+                       tim_position = sizeof(struct b43_plcp_hdr6);
+                       tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
+                       tim_position += i;
+
+                       dtim_period = ie[i + 3];
+
+                       b43_shm_write16(dev, B43_SHM_SHARED,
+                                       B43_SHM_SH_TIMBPOS, tim_position);
+                       b43_shm_write16(dev, B43_SHM_SHARED,
+                                       B43_SHM_SH_DTIMPER, dtim_period);
+                       break;
+               }
+               i += ie_len + 2;
+       }
+       if (!tim_found) {
+               b43warn(dev->wl, "Did not find a valid TIM IE in "
+                       "the beacon template packet. AP or IBSS operation "
+                       "may be broken.\n");
+       }
 }
 
 static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
-                                     u16 shm_offset, u16 size, u8 rate)
+                                     u16 shm_offset, u16 size,
+                                     struct ieee80211_rate *rate)
 {
        struct b43_plcp_hdr4 plcp;
        u32 tmp;
        __le16 dur;
 
        plcp.data = 0;
-       b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+       b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value);
        dur = ieee80211_generic_frame_duration(dev->wl->hw,
-                                              dev->wl->if_id, size,
-                                              B43_RATE_TO_BASE100KBPS(rate));
+                                              dev->wl->vif, size,
+                                              rate);
        /* Write PLCP in two parts and timing for packet transfer */
        tmp = le32_to_cpu(plcp.data);
        b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
@@ -1219,40 +1254,44 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
  * 2) Patching duration field
  * 3) Stripping TIM
  */
-static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
-                                  u16 * dest_size, u8 rate)
+static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
+                                         u16 *dest_size,
+                                         struct ieee80211_rate *rate)
 {
        const u8 *src_data;
        u8 *dest_data;
        u16 src_size, elem_size, src_pos, dest_pos;
        __le16 dur;
        struct ieee80211_hdr *hdr;
+       size_t ie_start;
+
+       src_size = dev->wl->current_beacon->len;
+       src_data = (const u8 *)dev->wl->current_beacon->data;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       src_size = dev->cached_beacon->len;
-       src_data = (const u8 *)dev->cached_beacon->data;
+       /* Get the start offset of the variable IEs in the packet. */
+       ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+       B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
 
-       if (unlikely(src_size < 0x24)) {
-               b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+       if (B43_WARN_ON(src_size < ie_start))
                return NULL;
-       }
 
        dest_data = kmalloc(src_size, GFP_ATOMIC);
        if (unlikely(!dest_data))
                return NULL;
 
-       /* 0x24 is offset of first variable-len Information-Element
-        * in beacon frame.
-        */
-       memcpy(dest_data, src_data, 0x24);
-       src_pos = dest_pos = 0x24;
-       for (; src_pos < src_size - 2; src_pos += elem_size) {
+       /* Copy the static data and all Information Elements, except the TIM. */
+       memcpy(dest_data, src_data, ie_start);
+       src_pos = ie_start;
+       dest_pos = ie_start;
+       for ( ; src_pos < src_size - 2; src_pos += elem_size) {
                elem_size = src_data[src_pos + 1] + 2;
-               if (src_data[src_pos] != 0x05) {        /* TIM */
-                       memcpy(dest_data + dest_pos, src_data + src_pos,
-                              elem_size);
-                       dest_pos += elem_size;
+               if (src_data[src_pos] == 5) {
+                       /* This is the TIM. */
+                       continue;
                }
+               memcpy(dest_data + dest_pos, src_data + src_pos,
+                      elem_size);
+               dest_pos += elem_size;
        }
        *dest_size = dest_pos;
        hdr = (struct ieee80211_hdr *)dest_data;
@@ -1261,8 +1300,8 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
        hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                         IEEE80211_STYPE_PROBE_RESP);
        dur = ieee80211_generic_frame_duration(dev->wl->hw,
-                                              dev->wl->if_id, *dest_size,
-                                              B43_RATE_TO_BASE100KBPS(rate));
+                                              dev->wl->vif, *dest_size,
+                                              rate);
        hdr->duration_id = dur;
 
        return dest_data;
@@ -1270,13 +1309,13 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
 
 static void b43_write_probe_resp_template(struct b43_wldev *dev,
                                          u16 ram_offset,
-                                         u16 shm_size_offset, u8 rate)
+                                         u16 shm_size_offset,
+                                         struct ieee80211_rate *rate)
 {
-       u8 *probe_resp_data;
+       const u8 *probe_resp_data;
        u16 size;
 
-       B43_WARN_ON(!dev->cached_beacon);
-       size = dev->cached_beacon->len;
+       size = dev->wl->current_beacon->len;
        probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
        if (unlikely(!probe_resp_data))
                return;
@@ -1284,50 +1323,33 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
        /* Looks like PLCP headers plus packet timings are stored for
         * all possible basic rates
         */
-       b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
-       b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
-       b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
-       b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+       b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
+       b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
+       b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
+       b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
 
        size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
        b43_write_template_common(dev, probe_resp_data,
-                                 size, ram_offset, shm_size_offset, rate);
+                                 size, ram_offset, shm_size_offset,
+                                 rate->hw_value);
        kfree(probe_resp_data);
 }
 
-static int b43_refresh_cached_beacon(struct b43_wldev *dev,
-                                    struct sk_buff *beacon)
-{
-       if (dev->cached_beacon)
-               kfree_skb(dev->cached_beacon);
-       dev->cached_beacon = beacon;
-
-       return 0;
-}
-
-static void b43_update_templates(struct b43_wldev *dev)
-{
-       u32 status;
-
-       B43_WARN_ON(!dev->cached_beacon);
-
-       b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-       b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-       b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
-
-       status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
-       status |= 0x03;
-       b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
-}
-
-static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+/* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
 {
-       int err;
+       /* This is the top half of the ansynchronous beacon update.
+        * The bottom half is the beacon IRQ.
+        * Beacon update must be asynchronous to avoid sending an
+        * invalid beacon. This can happen for example, if the firmware
+        * transmits a beacon while we are updating it. */
 
-       err = b43_refresh_cached_beacon(dev, beacon);
-       if (unlikely(err))
-               return;
-       b43_update_templates(dev);
+       if (wl->current_beacon)
+               dev_kfree_skb_any(wl->current_beacon);
+       wl->current_beacon = beacon;
+       wl->beacon0_uploaded = 0;
+       wl->beacon1_uploaded = 0;
 }
 
 static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
@@ -1363,33 +1385,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 
 static void handle_irq_beacon(struct b43_wldev *dev)
 {
-       u32 status;
+       struct b43_wl *wl = dev->wl;
+       u32 cmd;
 
-       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+       if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
                return;
 
-       dev->irq_savedstate &= ~B43_IRQ_BEACON;
-       status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+       /* This is the bottom half of the asynchronous beacon update. */
 
-       if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
-               /* ACK beacon IRQ. */
-               b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
-               dev->irq_savedstate |= B43_IRQ_BEACON;
-               if (dev->cached_beacon)
-                       kfree_skb(dev->cached_beacon);
-               dev->cached_beacon = NULL;
-               return;
-       }
-       if (!(status & 0x1)) {
-               b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-               status |= 0x1;
-               b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+       cmd = b43_read32(dev, B43_MMIO_MACCMD);
+       if (!(cmd & B43_MACCMD_BEACON0_VALID)) {
+               if (!wl->beacon0_uploaded) {
+                       b43_write_beacon_template(dev, 0x68, 0x18,
+                                                 B43_CCK_RATE_1MB);
+                       b43_write_probe_resp_template(dev, 0x268, 0x4A,
+                                                     &__b43_ratetable[3]);
+                       wl->beacon0_uploaded = 1;
+               }
+               cmd |= B43_MACCMD_BEACON0_VALID;
        }
-       if (!(status & 0x2)) {
-               b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-               status |= 0x2;
-               b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+       if (!(cmd & B43_MACCMD_BEACON1_VALID)) {
+               if (!wl->beacon1_uploaded) {
+                       b43_write_beacon_template(dev, 0x468, 0x1A,
+                                                 B43_CCK_RATE_1MB);
+                       wl->beacon1_uploaded = 1;
+               }
+               cmd |= B43_MACCMD_BEACON1_VALID;
        }
+       b43_write32(dev, B43_MMIO_MACCMD, cmd);
 }
 
 static void handle_irq_ucode_debug(struct b43_wldev *dev)
@@ -1419,8 +1442,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
        if (unlikely(reason & B43_IRQ_MAC_TXERR))
                b43err(dev->wl, "MAC transmission error\n");
 
-       if (unlikely(reason & B43_IRQ_PHY_TXERR))
+       if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
                b43err(dev->wl, "PHY transmission error\n");
+               rmb();
+               if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
+                       atomic_set(&dev->phy.txerr_cnt,
+                                  B43_PHY_TX_BADNESS_LIMIT);
+                       b43err(dev->wl, "Too many PHY TX errors, "
+                                       "restarting the controller\n");
+                       b43_controller_restart(dev, "PHY TX errors");
+               }
+       }
 
        if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
                                          B43_DMAIRQ_NONFATALMASK))) {
@@ -1462,20 +1494,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
                handle_irq_noise(dev);
 
        /* Check the DMA reason registers for received data. */
-       if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
-               if (b43_using_pio(dev))
-                       b43_pio_rx(dev->pio.queue0);
-               else
-                       b43_dma_rx(dev->dma.rx_ring0);
-       }
+       if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
+               b43_dma_rx(dev->dma.rx_ring0);
+       if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
+               b43_dma_rx(dev->dma.rx_ring3);
        B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
        B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
-       if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
-               if (b43_using_pio(dev))
-                       b43_pio_rx(dev->pio.queue3);
-               else
-                       b43_dma_rx(dev->dma.rx_ring3);
-       }
        B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
        B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
 
@@ -1487,29 +1511,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
        spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 }
 
-static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
-{
-       u16 rxctl;
-
-       rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
-       if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
-               dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
-       else
-               dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
-}
-
 static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
 {
-       if (b43_using_pio(dev) &&
-           (dev->dev->id.revision < 3) &&
-           (!(reason & B43_IRQ_PIO_WORKAROUND))) {
-               /* Apply a PIO specific workaround to the dma_reasons */
-               pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
-               pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
-               pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
-               pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
-       }
-
        b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
 
        b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
@@ -1568,54 +1571,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
        return ret;
 }
 
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+       release_firmware(fw->data);
+       fw->data = NULL;
+       fw->filename = NULL;
+}
+
 static void b43_release_firmware(struct b43_wldev *dev)
 {
-       release_firmware(dev->fw.ucode);
-       dev->fw.ucode = NULL;
-       release_firmware(dev->fw.pcm);
-       dev->fw.pcm = NULL;
-       release_firmware(dev->fw.initvals);
-       dev->fw.initvals = NULL;
-       release_firmware(dev->fw.initvals_band);
-       dev->fw.initvals_band = NULL;
+       do_release_fw(&dev->fw.ucode);
+       do_release_fw(&dev->fw.pcm);
+       do_release_fw(&dev->fw.initvals);
+       do_release_fw(&dev->fw.initvals_band);
 }
 
-static void b43_print_fw_helptext(struct b43_wl *wl)
+static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
 {
-       b43err(wl, "You must go to "
-              "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
-              "and download the correct firmware (version 4).\n");
+       const char *text;
+
+       text = "You must go to "
+              "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
+              "and download the latest firmware (version 4).\n";
+       if (error)
+               b43err(wl, text);
+       else
+               b43warn(wl, text);
 }
 
 static int do_request_fw(struct b43_wldev *dev,
                         const char *name,
-                        const struct firmware **fw)
+                        struct b43_firmware_file *fw)
 {
        char path[sizeof(modparam_fwpostfix) + 32];
+       const struct firmware *blob;
        struct b43_fw_header *hdr;
        u32 size;
        int err;
 
-       if (!name)
+       if (!name) {
+               /* Don't fetch anything. Free possibly cached firmware. */
+               do_release_fw(fw);
                return 0;
+       }
+       if (fw->filename) {
+               if (strcmp(fw->filename, name) == 0)
+                       return 0; /* Already have this fw. */
+               /* Free the cached firmware first. */
+               do_release_fw(fw);
+       }
 
        snprintf(path, ARRAY_SIZE(path),
                 "b43%s/%s.fw",
                 modparam_fwpostfix, name);
-       err = request_firmware(fw, path, dev->dev->dev);
+       err = request_firmware(&blob, path, dev->dev->dev);
        if (err) {
                b43err(dev->wl, "Firmware file \"%s\" not found "
                       "or load failed.\n", path);
                return err;
        }
-       if ((*fw)->size < sizeof(struct b43_fw_header))
+       if (blob->size < sizeof(struct b43_fw_header))
                goto err_format;
-       hdr = (struct b43_fw_header *)((*fw)->data);
+       hdr = (struct b43_fw_header *)(blob->data);
        switch (hdr->type) {
        case B43_FW_TYPE_UCODE:
        case B43_FW_TYPE_PCM:
                size = be32_to_cpu(hdr->size);
-               if (size != (*fw)->size - sizeof(struct b43_fw_header))
+               if (size != blob->size - sizeof(struct b43_fw_header))
                        goto err_format;
                /* fallthrough */
        case B43_FW_TYPE_IV:
@@ -1626,10 +1648,15 @@ static int do_request_fw(struct b43_wldev *dev,
                goto err_format;
        }
 
-       return err;
+       fw->data = blob;
+       fw->filename = name;
+
+       return 0;
 
 err_format:
        b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+       release_firmware(blob);
+
        return -EPROTO;
 }
 
@@ -1641,90 +1668,101 @@ static int b43_request_firmware(struct b43_wldev *dev)
        u32 tmshigh;
        int err;
 
+       /* Get microcode */
        tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-       if (!fw->ucode) {
+       if ((rev >= 5) && (rev <= 10))
+               filename = "ucode5";
+       else if ((rev >= 11) && (rev <= 12))
+               filename = "ucode11";
+       else if (rev >= 13)
+               filename = "ucode13";
+       else
+               goto err_no_ucode;
+       err = do_request_fw(dev, filename, &fw->ucode);
+       if (err)
+               goto err_load;
+
+       /* Get PCM code */
+       if ((rev >= 5) && (rev <= 10))
+               filename = "pcm5";
+       else if (rev >= 11)
+               filename = NULL;
+       else
+               goto err_no_pcm;
+       err = do_request_fw(dev, filename, &fw->pcm);
+       if (err)
+               goto err_load;
+
+       /* Get initvals */
+       switch (dev->phy.type) {
+       case B43_PHYTYPE_A:
+               if ((rev >= 5) && (rev <= 10)) {
+                       if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+                               filename = "a0g1initvals5";
+                       else
+                               filename = "a0g0initvals5";
+               } else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_G:
                if ((rev >= 5) && (rev <= 10))
-                       filename = "ucode5";
-               else if ((rev >= 11) && (rev <= 12))
-                       filename = "ucode11";
+                       filename = "b0g0initvals5";
                else if (rev >= 13)
-                       filename = "ucode13";
+                       filename = "lp0initvals13";
                else
-                       goto err_no_ucode;
-               err = do_request_fw(dev, filename, &fw->ucode);
-               if (err)
-                       goto err_load;
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_N:
+               if ((rev >= 11) && (rev <= 12))
+                       filename = "n0initvals11";
+               else
+                       goto err_no_initvals;
+               break;
+       default:
+               goto err_no_initvals;
        }
-       if (!fw->pcm) {
+       err = do_request_fw(dev, filename, &fw->initvals);
+       if (err)
+               goto err_load;
+
+       /* Get bandswitch initvals */
+       switch (dev->phy.type) {
+       case B43_PHYTYPE_A:
+               if ((rev >= 5) && (rev <= 10)) {
+                       if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+                               filename = "a0g1bsinitvals5";
+                       else
+                               filename = "a0g0bsinitvals5";
+               } else if (rev >= 11)
+                       filename = NULL;
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_G:
                if ((rev >= 5) && (rev <= 10))
-                       filename = "pcm5";
+                       filename = "b0g0bsinitvals5";
                else if (rev >= 11)
                        filename = NULL;
                else
-                       goto err_no_pcm;
-               err = do_request_fw(dev, filename, &fw->pcm);
-               if (err)
-                       goto err_load;
-       }
-       if (!fw->initvals) {
-               switch (dev->phy.type) {
-               case B43_PHYTYPE_A:
-                       if ((rev >= 5) && (rev <= 10)) {
-                               if (tmshigh & B43_TMSHIGH_GPHY)
-                                       filename = "a0g1initvals5";
-                               else
-                                       filename = "a0g0initvals5";
-                       } else
-                               goto err_no_initvals;
-                       break;
-               case B43_PHYTYPE_G:
-                       if ((rev >= 5) && (rev <= 10))
-                               filename = "b0g0initvals5";
-                       else if (rev >= 13)
-                               filename = "lp0initvals13";
-                       else
-                               goto err_no_initvals;
-                       break;
-               default:
                        goto err_no_initvals;
-               }
-               err = do_request_fw(dev, filename, &fw->initvals);
-               if (err)
-                       goto err_load;
-       }
-       if (!fw->initvals_band) {
-               switch (dev->phy.type) {
-               case B43_PHYTYPE_A:
-                       if ((rev >= 5) && (rev <= 10)) {
-                               if (tmshigh & B43_TMSHIGH_GPHY)
-                                       filename = "a0g1bsinitvals5";
-                               else
-                                       filename = "a0g0bsinitvals5";
-                       } else if (rev >= 11)
-                               filename = NULL;
-                       else
-                               goto err_no_initvals;
-                       break;
-               case B43_PHYTYPE_G:
-                       if ((rev >= 5) && (rev <= 10))
-                               filename = "b0g0bsinitvals5";
-                       else if (rev >= 11)
-                               filename = NULL;
-                       else
-                               goto err_no_initvals;
-                       break;
-               default:
+               break;
+       case B43_PHYTYPE_N:
+               if ((rev >= 11) && (rev <= 12))
+                       filename = "n0bsinitvals11";
+               else
                        goto err_no_initvals;
-               }
-               err = do_request_fw(dev, filename, &fw->initvals_band);
-               if (err)
-                       goto err_load;
+               break;
+       default:
+               goto err_no_initvals;
        }
+       err = do_request_fw(dev, filename, &fw->initvals_band);
+       if (err)
+               goto err_load;
 
        return 0;
 
 err_load:
-       b43_print_fw_helptext(dev->wl);
+       b43_print_fw_helptext(dev->wl, 1);
        goto error;
 
 err_no_ucode:
@@ -1754,22 +1792,33 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        const __be32 *data;
        unsigned int i, len;
        u16 fwrev, fwpatch, fwdate, fwtime;
-       u32 tmp;
+       u32 tmp, macctl;
        int err = 0;
 
+       /* Jump the microcode PSM to offset 0 */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+       /* Zero out all microcode PSM registers and shared memory. */
+       for (i = 0; i < 64; i++)
+               b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+       for (i = 0; i < 4096; i += 2)
+               b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
        /* Upload Microcode. */
-       data = (__be32 *) (dev->fw.ucode->data + hdr_len);
-       len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+       data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+       len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
        b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
        for (i = 0; i < len; i++) {
                b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
                udelay(10);
        }
 
-       if (dev->fw.pcm) {
+       if (dev->fw.pcm.data) {
                /* Upload PCM data. */
-               data = (__be32 *) (dev->fw.pcm->data + hdr_len);
-               len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+               data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+               len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
                b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
                b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
                /* No need for autoinc bit in SHM_HW */
@@ -1781,9 +1830,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        }
 
        b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_RUN |
-                   B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+       /* Start the microcode PSM */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_JMP0;
+       macctl |= B43_MACCTL_PSM_RUN;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        /* Wait for the microcode to load and respond */
        i = 0;
@@ -1792,13 +1844,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                if (tmp == B43_IRQ_MAC_SUSPENDED)
                        break;
                i++;
-               if (i >= 50) {
+               if (i >= 20) {
                        b43err(dev->wl, "Microcode not responding\n");
-                       b43_print_fw_helptext(dev->wl);
+                       b43_print_fw_helptext(dev->wl, 1);
                        err = -ENODEV;
-                       goto out;
+                       goto error;
+               }
+               msleep_interruptible(50);
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       goto error;
                }
-               udelay(10);
        }
        b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);       /* dummy read */
 
@@ -1812,10 +1868,9 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
                       "binary drivers older than version 4.x is unsupported. "
                       "You must upgrade your firmware files.\n");
-               b43_print_fw_helptext(dev->wl);
-               b43_write32(dev, B43_MMIO_MACCTL, 0);
+               b43_print_fw_helptext(dev->wl, 1);
                err = -EOPNOTSUPP;
-               goto out;
+               goto error;
        }
        b43dbg(dev->wl, "Loading firmware version %u.%u "
               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1826,7 +1881,20 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
 
-      out:
+       if (b43_is_old_txhdr_format(dev)) {
+               b43warn(dev->wl, "You are using an old firmware image. "
+                       "Support for old firmware will be removed in July 2008.\n");
+               b43_print_fw_helptext(dev->wl, 0);
+       }
+
+       return 0;
+
+error:
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
        return err;
 }
 
@@ -1886,7 +1954,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
 
 err_format:
        b43err(dev->wl, "Initial Values Firmware file-format error.\n");
-       b43_print_fw_helptext(dev->wl);
+       b43_print_fw_helptext(dev->wl, 1);
 
        return -EPROTO;
 }
@@ -1900,19 +1968,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
        size_t count;
        int err;
 
-       hdr = (const struct b43_fw_header *)(fw->initvals->data);
-       ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+       hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+       ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
        count = be32_to_cpu(hdr->size);
        err = b43_write_initvals(dev, ivals, count,
-                                fw->initvals->size - hdr_len);
+                                fw->initvals.data->size - hdr_len);
        if (err)
                goto out;
-       if (fw->initvals_band) {
-               hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
-               ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+       if (fw->initvals_band.data) {
+               hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+               ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
                count = be32_to_cpu(hdr->size);
                err = b43_write_initvals(dev, ivals, count,
-                                        fw->initvals_band->size - hdr_len);
+                                        fw->initvals_band.data->size - hdr_len);
                if (err)
                        goto out;
        }
@@ -1949,7 +2017,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
@@ -2119,6 +2187,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
        case B43_PHYTYPE_G:
+       case B43_PHYTYPE_N:
                b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -2148,13 +2217,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
        switch (antenna) {
        case B43_ANTENNA0:
-               ant |= B43_TX4_PHY_ANT0;
+               ant |= B43_TXH_PHY_ANT0;
                break;
        case B43_ANTENNA1:
-               ant |= B43_TX4_PHY_ANT1;
+               ant |= B43_TXH_PHY_ANT1;
+               break;
+       case B43_ANTENNA2:
+               ant |= B43_TXH_PHY_ANT2;
+               break;
+       case B43_ANTENNA3:
+               ant |= B43_TXH_PHY_ANT3;
                break;
        case B43_ANTENNA_AUTO:
-               ant |= B43_TX4_PHY_ANTLAST;
+               ant |= B43_TXH_PHY_ANT01AUTO;
                break;
        default:
                B43_WARN_ON(1);
@@ -2164,15 +2239,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
        /* For Beacons */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
        /* For ACK/CTS */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
        /* For Probe Resposes */
        tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
-       tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+       tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
 }
 
@@ -2180,7 +2255,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 static void b43_chip_exit(struct b43_wldev *dev)
 {
        b43_radio_turn_off(dev, 1);
-       b43_leds_exit(dev);
        b43_gpio_cleanup(dev);
        /* firmware is released later */
 }
@@ -2192,11 +2266,15 @@ static int b43_chip_init(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
        int err, tmp;
-       u32 value32;
+       u32 value32, macctl;
        u16 value16;
 
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+       /* Initialize the MAC control */
+       macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+       if (dev->phy.gmode)
+               macctl |= B43_MACCTL_GMODE;
+       macctl |= B43_MACCTL_INFRA;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        err = b43_request_firmware(dev);
        if (err)
@@ -2208,11 +2286,10 @@ static int b43_chip_init(struct b43_wldev *dev)
        err = b43_gpio_init(dev);
        if (err)
                goto out;       /* firmware is released later */
-       b43_leds_init(dev);
 
        err = b43_upload_initvals(dev);
        if (err)
-               goto err_leds_exit;
+               goto err_gpio_clean;
        b43_radio_turn_on(dev);
 
        b43_write16(dev, 0x03E6, 0x0000);
@@ -2242,14 +2319,6 @@ static int b43_chip_init(struct b43_wldev *dev)
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
                    | B43_MACCTL_INFRA);
 
-       if (b43_using_pio(dev)) {
-               b43_write32(dev, 0x0210, 0x00000100);
-               b43_write32(dev, 0x0230, 0x00000100);
-               b43_write32(dev, 0x0250, 0x00000100);
-               b43_write32(dev, 0x0270, 0x00000100);
-               b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
-       }
-
        /* Probe Response Timeout value */
        /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
        b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
@@ -2288,8 +2357,7 @@ out:
 
 err_radio_off:
        b43_radio_turn_off(dev, 1);
-err_leds_exit:
-       b43_leds_exit(dev);
+err_gpio_clean:
        b43_gpio_cleanup(dev);
        return err;
 }
@@ -2312,9 +2380,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
+       if (phy->type != B43_PHYTYPE_G)
+               return;
        if (!b43_has_hardware_pctl(phy))
                b43_lo_g_ctl_mark_all_unused(dev);
-       if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
                b43_mac_suspend(dev);
                b43_calc_nrssi_slope(dev);
                if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
@@ -2366,6 +2436,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
        }
        b43_phy_xmitpower(dev); //FIXME: unless scanning?
        //TODO for APHY (temperature?)
+
+       atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+       wmb();
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -2423,32 +2496,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
        queue_delayed_work(dev->wl->hw->workqueue, work, 0);
 }
 
-/* Validate access to the chip (SHM) */
+/* Check if communication with the device works correctly. */
 static int b43_validate_chipaccess(struct b43_wldev *dev)
 {
-       u32 value;
-       u32 shm_backup;
+       u32 v, backup;
 
-       shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
-       b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
-       if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
-               goto error;
+       backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+
+       /* Check for read/write and endianness problems. */
        b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
        if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
                goto error;
-       b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
-
-       value = b43_read32(dev, B43_MMIO_MACCTL);
-       if ((value | B43_MACCTL_GMODE) !=
-           (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+       b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+       if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
                goto error;
 
-       value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
-       if (value)
+       b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+
+       if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+               /* The 32bit register shadows the two 16bit registers
+                * with update sideeffects. Validate this. */
+               b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
+               b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
+               if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
+                       goto error;
+               if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
+                       goto error;
+       }
+       b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
+
+       v = b43_read32(dev, B43_MMIO_MACCTL);
+       v |= B43_MACCTL_GMODE;
+       if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
                goto error;
 
        return 0;
-      error:
+error:
        b43err(dev->wl, "Failed to validate the chipaccess\n");
        return -ENODEV;
 }
@@ -2511,40 +2594,35 @@ static int b43_rng_init(struct b43_wl *wl)
        return err;
 }
 
-static int b43_tx(struct ieee80211_hw *hw,
-                 struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int b43_op_tx(struct ieee80211_hw *hw,
+                    struct sk_buff *skb,
+                    struct ieee80211_tx_control *ctl)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        int err = -ENODEV;
-       unsigned long flags;
 
        if (unlikely(!dev))
                goto out;
        if (unlikely(b43_status(dev) < B43_STAT_STARTED))
                goto out;
        /* DMA-TX is done without a global lock. */
-       if (b43_using_pio(dev)) {
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               err = b43_pio_tx(dev, skb, ctl);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       } else
-               err = b43_dma_tx(dev, skb, ctl);
-      out:
+       err = b43_dma_tx(dev, skb, ctl);
+out:
        if (unlikely(err))
                return NETDEV_TX_BUSY;
        return NETDEV_TX_OK;
 }
 
-static int b43_conf_tx(struct ieee80211_hw *hw,
-                      int queue,
-                      const struct ieee80211_tx_queue_params *params)
+static int b43_op_conf_tx(struct ieee80211_hw *hw,
+                         int queue,
+                         const struct ieee80211_tx_queue_params *params)
 {
        return 0;
 }
 
-static int b43_get_tx_stats(struct ieee80211_hw *hw,
-                           struct ieee80211_tx_queue_stats *stats)
+static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
+                              struct ieee80211_tx_queue_stats *stats)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2555,19 +2633,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw,
                goto out;
        spin_lock_irqsave(&wl->irq_lock, flags);
        if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
-               if (b43_using_pio(dev))
-                       b43_pio_get_tx_stats(dev, stats);
-               else
-                       b43_dma_get_tx_stats(dev, stats);
+               b43_dma_get_tx_stats(dev, stats);
                err = 0;
        }
        spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out:
+out:
        return err;
 }
 
-static int b43_get_stats(struct ieee80211_hw *hw,
-                        struct ieee80211_low_level_stats *stats)
+static int b43_op_get_stats(struct ieee80211_hw *hw,
+                           struct ieee80211_low_level_stats *stats)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        unsigned long flags;
@@ -2706,8 +2781,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
        return err;
 }
 
-static int b43_antenna_from_ieee80211(u8 antenna)
+/* Check if the use of the antenna that ieee80211 told us to
+ * use is possible. This will fall back to DEFAULT.
+ * "antenna_nr" is the antenna identifier we got from ieee80211. */
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+                                 u8 antenna_nr)
 {
+       u8 antenna_mask;
+
+       if (antenna_nr == 0) {
+               /* Zero means "use default antenna". That's always OK. */
+               return 0;
+       }
+
+       /* Get the mask of available antennas. */
+       if (dev->phy.gmode)
+               antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+       else
+               antenna_mask = dev->dev->bus->sprom.ant_available_a;
+
+       if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
+               /* This antenna is not available. Fall back to default. */
+               return 0;
+       }
+
+       return antenna_nr;
+}
+
+static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
+{
+       antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
        switch (antenna) {
        case 0:         /* default/diversity */
                return B43_ANTENNA_DEFAULT;
@@ -2715,37 +2818,34 @@ static int b43_antenna_from_ieee80211(u8 antenna)
                return B43_ANTENNA0;
        case 2:         /* Antenna 1 */
                return B43_ANTENNA1;
+       case 3:         /* Antenna 2 */
+               return B43_ANTENNA2;
+       case 4:         /* Antenna 3 */
+               return B43_ANTENNA3;
        default:
                return B43_ANTENNA_DEFAULT;
        }
 }
 
-static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
        struct b43_phy *phy;
        unsigned long flags;
        unsigned int new_phymode = 0xFFFF;
-       int antenna_tx;
-       int antenna_rx;
+       int antenna;
        int err = 0;
        u32 savedirqs;
 
-       antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
-       antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
-
        mutex_lock(&wl->mutex);
 
        /* Switch the PHY mode (if necessary). */
-       switch (conf->phymode) {
-       case MODE_IEEE80211A:
+       switch (conf->channel->band) {
+       case IEEE80211_BAND_5GHZ:
                new_phymode = B43_PHYMODE_A;
                break;
-       case MODE_IEEE80211B:
-               new_phymode = B43_PHYMODE_B;
-               break;
-       case MODE_IEEE80211G:
+       case IEEE80211_BAND_2GHZ:
                new_phymode = B43_PHYMODE_G;
                break;
        default:
@@ -2771,8 +2871,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 
        /* Switch to the requested channel.
         * The firmware takes care of races with the TX handler. */
-       if (conf->channel_val != phy->channel)
-               b43_radio_selectchannel(dev, conf->channel_val, 0);
+       if (conf->channel->hw_value != phy->channel)
+               b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
 
        /* Enable/Disable ShortSlot timing. */
        if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
@@ -2784,6 +2884,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
                        b43_short_slot_timing_disable(dev);
        }
 
+       dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
        /* Adjust the desired TX power level. */
        if (conf->power_level != 0) {
                if (conf->power_level != phy->power_level) {
@@ -2793,8 +2895,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
        }
 
        /* Antennas for RX and management frame TX. */
-       b43_mgmtframe_txantenna(dev, antenna_tx);
-       b43_set_rx_antenna(dev, antenna_rx);
+       antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+       b43_mgmtframe_txantenna(dev, antenna);
+       antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+       b43_set_rx_antenna(dev, antenna);
 
        /* Update templates for AP mode. */
        if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
@@ -2825,22 +2929,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
        return err;
 }
 
-static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           const u8 *local_addr, const u8 *addr,
                           struct ieee80211_key_conf *key)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
-       struct b43_wldev *dev = wl->current_dev;
+       struct b43_wldev *dev;
        unsigned long flags;
        u8 algorithm;
        u8 index;
-       int err = -EINVAL;
+       int err;
+       DECLARE_MAC_BUF(mac);
 
        if (modparam_nohwcrypt)
                return -ENOSPC; /* User disabled HW-crypto */
 
-       if (!dev)
-               return -ENODEV;
+       mutex_lock(&wl->mutex);
+       spin_lock_irqsave(&wl->irq_lock, flags);
+
+       dev = wl->current_dev;
+       err = -ENODEV;
+       if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+               goto out_unlock;
+
+       err = -EINVAL;
        switch (key->alg) {
        case ALG_WEP:
                if (key->keylen == 5)
@@ -2856,20 +2968,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        default:
                B43_WARN_ON(1);
-               goto out;
+               goto out_unlock;
        }
-
        index = (u8) (key->keyidx);
        if (index > 3)
-               goto out;
-
-       mutex_lock(&wl->mutex);
-       spin_lock_irqsave(&wl->irq_lock, flags);
-
-       if (b43_status(dev) < B43_STAT_INITIALIZED) {
-               err = -ENODEV;
                goto out_unlock;
-       }
 
        switch (cmd) {
        case SET_KEY:
@@ -2915,19 +3018,18 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 out_unlock:
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        mutex_unlock(&wl->mutex);
-out:
        if (!err) {
                b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
-                      "mac: " MAC_FMT "\n",
+                      "mac: %s\n",
                       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
-                      MAC_ARG(addr));
+                      print_mac(mac, addr));
        }
        return err;
 }
 
-static void b43_configure_filter(struct ieee80211_hw *hw,
-                                unsigned int changed, unsigned int *fflags,
-                                int mc_count, struct dev_addr_list *mc_list)
+static void b43_op_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed, unsigned int *fflags,
+                                   int mc_count, struct dev_addr_list *mc_list)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2962,8 +3064,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw,
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
-static int b43_config_interface(struct ieee80211_hw *hw,
-                               int if_id, struct ieee80211_if_conf *conf)
+static int b43_op_config_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_if_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2973,7 +3076,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
                return -ENODEV;
        mutex_lock(&wl->mutex);
        spin_lock_irqsave(&wl->irq_lock, flags);
-       B43_WARN_ON(wl->if_id != if_id);
+       B43_WARN_ON(wl->vif != vif);
        if (conf->bssid)
                memcpy(wl->bssid, conf->bssid, ETH_ALEN);
        else
@@ -2983,7 +3086,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
                        B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
                        b43_set_ssid(dev, conf->ssid, conf->ssid_len);
                        if (conf->beacon)
-                               b43_refresh_templates(dev, conf->beacon);
+                               b43_update_templates(wl, conf->beacon);
                }
                b43_write_mac_bssid_templates(dev);
        }
@@ -3001,6 +3104,16 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
        if (b43_status(dev) < B43_STAT_STARTED)
                return;
+
+       /* Disable and sync interrupts. We must do this before than
+        * setting the status to INITIALIZED, as the interrupt handler
+        * won't care about IRQs then. */
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+       b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       b43_synchronize_irq(dev);
+
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
        mutex_unlock(&wl->mutex);
@@ -3011,13 +3124,6 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)
 
        ieee80211_stop_queues(wl->hw);  //FIXME this could cause a deadlock, as mac80211 seems buggy.
 
-       /* Disable and sync interrupts. */
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
-       b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-       b43_synchronize_irq(dev);
-
        b43_mac_suspend(dev);
        free_irq(dev->dev->irq, dev);
        b43dbg(wl, "Wireless interface stopped\n");
@@ -3083,9 +3189,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        unsupported = 1;
                break;
        case B43_PHYTYPE_G:
-               if (phy_rev > 8)
+               if (phy_rev > 9)
+                       unsupported = 1;
+               break;
+#ifdef CONFIG_B43_NPHY
+       case B43_PHYTYPE_N:
+               if (phy_rev > 1)
                        unsupported = 1;
                break;
+#endif
        default:
                unsupported = 1;
        };
@@ -3108,14 +3220,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        tmp = 0x5205017F;
        } else {
                b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
-               tmp <<= 16;
+               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
                b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+               tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
        }
        radio_manuf = (tmp & 0x00000FFF);
        radio_ver = (tmp & 0x0FFFF000) >> 12;
        radio_rev = (tmp & 0xF0000000) >> 28;
+       if (radio_manuf != 0x17F /* Broadcom */)
+               unsupported = 1;
        switch (phy_type) {
        case B43_PHYTYPE_A:
                if (radio_ver != 0x2060)
@@ -3133,6 +3246,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (radio_ver != 0x2050)
                        unsupported = 1;
                break;
+       case B43_PHYTYPE_N:
+               if (radio_ver != 0x2055)
+                       unsupported = 1;
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -3165,9 +3282,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
        memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
 
-       /* Flags */
-       phy->locked = 0;
-
        phy->aci_enable = 0;
        phy->aci_wlan_automatic = 0;
        phy->aci_hw_rssi = 0;
@@ -3194,17 +3308,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        phy->lofcal = 0xFFFF;
        phy->initval = 0xFFFF;
 
-       spin_lock_init(&phy->lock);
        phy->interfmode = B43_INTERFMODE_NONE;
        phy->channel = 0xFF;
 
        phy->hardware_power_control = !!modparam_hwpctl;
+
+       /* PHY TX errors counter. */
+       atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+       /* OFDM-table address caching. */
+       phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 {
-       /* Flags */
-       dev->reg124_set_0x4 = 0;
+       dev->dfq_valid = 0;
+
        /* Assume the radio is enabled. If it's not enabled, the state will
         * immediately get fixed on the first periodic work run. */
        dev->radio_hw_enable = 1;
@@ -3230,13 +3349,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
        struct ssb_sprom *sprom = &dev->dev->bus->sprom;
        u32 hf;
 
-       if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+       if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
                return;
        if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
                return;
 
        hf = b43_hf_read(dev);
-       if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+       if (sprom->boardflags_lo & B43_BFL_BTCMOD)
                hf |= B43_HF_BTCOEXALT;
        else
                hf |= B43_HF_BTCOEX;
@@ -3275,23 +3394,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+                                unsigned int short_retry,
+                                unsigned int long_retry)
+{
+       /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+        * the chip-internal counter. */
+       short_retry = min(short_retry, (unsigned int)0xF);
+       long_retry = min(long_retry, (unsigned int)0xF);
+
+       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+                       short_retry);
+       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+                       long_retry);
+}
+
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
+       u32 macctl;
 
        B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
        if (b43_status(dev) != B43_STAT_INITIALIZED)
                return;
        b43_set_status(dev, B43_STAT_UNINIT);
 
-       mutex_unlock(&dev->wl->mutex);
-       b43_rfkill_exit(dev);
-       mutex_lock(&dev->wl->mutex);
+       /* Stop the microcode PSM. */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
+       b43_leds_exit(dev);
        b43_rng_exit(dev->wl);
-       b43_pio_free(dev);
        b43_dma_free(dev);
        b43_chip_exit(dev);
        b43_radio_turn_off(dev, 1);
@@ -3300,6 +3438,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                kfree(phy->tssi2dbm);
        kfree(phy->lo_control);
        phy->lo_control = NULL;
+       if (dev->wl->current_beacon) {
+               dev_kfree_skb_any(dev->wl->current_beacon);
+               dev->wl->current_beacon = NULL;
+       }
+
        ssb_device_disable(dev->dev, 0);
        ssb_bus_may_powerdown(dev->dev->bus);
 }
@@ -3354,7 +3497,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
                hf |= B43_HF_SYMW;
                if (phy->rev == 1)
                        hf |= B43_HF_GDCW;
-               if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+               if (sprom->boardflags_lo & B43_BFL_PACTRL)
                        hf |= B43_HF_OFDMPABOOST;
        } else if (phy->type == B43_PHYTYPE_B) {
                hf |= B43_HF_SYMW;
@@ -3363,15 +3506,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        }
        b43_hf_write(dev, hf);
 
-       /* Short/Long Retry Limit.
-        * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
-        * the chip-internal counter.
-        */
-       tmp = limit_value(modparam_short_retry, 0, 0xF);
-       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
-       tmp = limit_value(modparam_long_retry, 0, 0xF);
-       b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
-
+       b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
+                            B43_DEFAULT_LONG_RETRY_LIMIT);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
 
@@ -3392,17 +3528,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       do {
-               if (b43_using_pio(dev)) {
-                       err = b43_pio_init(dev);
-               } else {
-                       err = b43_dma_init(dev);
-                       if (!err)
-                               b43_qos_init(dev);
-               }
-       } while (err == -EAGAIN);
+       err = b43_dma_init(dev);
        if (err)
                goto err_chip_exit;
+       b43_qos_init(dev);
 
 //FIXME
 #if 1
@@ -3414,16 +3543,14 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_bluetooth_coext_enable(dev);
 
        ssb_bus_powerup(bus, 1);        /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       b43_rfkill_init(dev);
        b43_rng_init(wl);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-      out:
+       b43_leds_init(dev);
+out:
        return err;
 
       err_chip_exit:
@@ -3440,8 +3567,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        return err;
 }
 
-static int b43_add_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_if_init_conf *conf)
+static int b43_op_add_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_if_init_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -3464,7 +3591,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 
        dev = wl->current_dev;
        wl->operating = 1;
-       wl->if_id = conf->if_id;
+       wl->vif = conf->vif;
        wl->if_type = conf->type;
        memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
 
@@ -3480,8 +3607,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
        return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf)
+static void b43_op_remove_interface(struct ieee80211_hw *hw,
+                                   struct ieee80211_if_init_conf *conf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -3492,7 +3619,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
 
        B43_WARN_ON(!wl->operating);
-       B43_WARN_ON(wl->if_id != conf->if_id);
+       B43_WARN_ON(wl->vif != conf->vif);
+       wl->vif = NULL;
 
        wl->operating = 0;
 
@@ -3505,19 +3633,34 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
        mutex_unlock(&wl->mutex);
 }
 
-static int b43_start(struct ieee80211_hw *hw)
+static int b43_op_start(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
+       bool do_rfkill_exit = 0;
+
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+       wl->radiotap_enabled = 0;
+
+       /* First register RFkill.
+        * LEDs that are registered later depend on it. */
+       b43_rfkill_init(dev);
 
        mutex_lock(&wl->mutex);
 
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
-               if (err)
+               if (err) {
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
+               }
                did_init = 1;
        }
 
@@ -3526,6 +3669,7 @@ static int b43_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43_wireless_core_exit(dev);
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
@@ -3533,14 +3677,19 @@ static int b43_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
+       if (do_rfkill_exit)
+               b43_rfkill_exit(dev);
+
        return err;
 }
 
-static void b43_stop(struct ieee80211_hw *hw)
+static void b43_op_stop(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
 
+       b43_rfkill_exit(dev);
+
        mutex_lock(&wl->mutex);
        if (b43_status(dev) >= B43_STAT_STARTED)
                b43_wireless_core_stop(dev);
@@ -3548,19 +3697,76 @@ static void b43_stop(struct ieee80211_hw *hw)
        mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
+                                 u32 short_retry_limit, u32 long_retry_limit)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+       int err = 0;
+
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
+               err = -ENODEV;
+               goto out_unlock;
+       }
+       b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+out_unlock:
+       mutex_unlock(&wl->mutex);
+
+       return err;
+}
+
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct sk_buff *beacon;
+       unsigned long flags;
+
+       /* We could modify the existing beacon and set the aid bit in
+        * the TIM field, but that would probably require resizing and
+        * moving of data within the beacon template.
+        * Simply request a new beacon and let mac80211 do the hard work. */
+       beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+       if (unlikely(!beacon))
+               return -ENOMEM;
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_update_templates(wl, beacon);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       return 0;
+}
+
+static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
+                                    struct sk_buff *beacon,
+                                    struct ieee80211_tx_control *ctl)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_update_templates(wl, beacon);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
-       .tx = b43_tx,
-       .conf_tx = b43_conf_tx,
-       .add_interface = b43_add_interface,
-       .remove_interface = b43_remove_interface,
-       .config = b43_dev_config,
-       .config_interface = b43_config_interface,
-       .configure_filter = b43_configure_filter,
-       .set_key = b43_dev_set_key,
-       .get_stats = b43_get_stats,
-       .get_tx_stats = b43_get_tx_stats,
-       .start = b43_start,
-       .stop = b43_stop,
+       .tx                     = b43_op_tx,
+       .conf_tx                = b43_op_conf_tx,
+       .add_interface          = b43_op_add_interface,
+       .remove_interface       = b43_op_remove_interface,
+       .config                 = b43_op_config,
+       .config_interface       = b43_op_config_interface,
+       .configure_filter       = b43_op_configure_filter,
+       .set_key                = b43_op_set_key,
+       .get_stats              = b43_op_get_stats,
+       .get_tx_stats           = b43_op_get_tx_stats,
+       .start                  = b43_op_start,
+       .stop                   = b43_op_stop,
+       .set_retry_limit        = b43_op_set_retry_limit,
+       .set_tim                = b43_op_beacon_set_tim,
+       .beacon_update          = b43_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3605,79 +3811,26 @@ static void b43_chip_reset(struct work_struct *work)
 }
 
 static int b43_setup_modes(struct b43_wldev *dev,
-                          int have_aphy, int have_bphy, int have_gphy)
+                          bool have_2ghz_phy, bool have_5ghz_phy)
 {
        struct ieee80211_hw *hw = dev->wl->hw;
-       struct ieee80211_hw_mode *mode;
        struct b43_phy *phy = &dev->phy;
-       int cnt = 0;
-       int err;
 
-/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
-       have_aphy = 0;
-
-       phy->possible_phymodes = 0;
-       for (; 1; cnt++) {
-               if (have_aphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211A;
-                       mode->num_channels = b43_a_chantable_size;
-                       mode->channels = b43_a_chantable;
-                       mode->num_rates = b43_a_ratetable_size;
-                       mode->rates = b43_a_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_A;
-                       have_aphy = 0;
-                       continue;
-               }
-               if (have_bphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211B;
-                       mode->num_channels = b43_bg_chantable_size;
-                       mode->channels = b43_bg_chantable;
-                       mode->num_rates = b43_b_ratetable_size;
-                       mode->rates = b43_b_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_B;
-                       have_bphy = 0;
-                       continue;
-               }
-               if (have_gphy) {
-                       B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-                       mode = &phy->hwmodes[cnt];
-
-                       mode->mode = MODE_IEEE80211G;
-                       mode->num_channels = b43_bg_chantable_size;
-                       mode->channels = b43_bg_chantable;
-                       mode->num_rates = b43_g_ratetable_size;
-                       mode->rates = b43_g_ratetable;
-                       err = ieee80211_register_hwmode(hw, mode);
-                       if (err)
-                               return err;
-
-                       phy->possible_phymodes |= B43_PHYMODE_G;
-                       have_gphy = 0;
-                       continue;
-               }
-               break;
-       }
+       /* XXX: This function will go away soon, when mac80211
+        *      band stuff is rewritten. So this is just a hack.
+        *      For now we always claim GPHY mode, as there is no
+        *      support for NPHY and APHY in the device, yet.
+        *      This assumption is OK, as any B, N or A PHY will already
+        *      have died a horrible sanity check death earlier. */
+
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz;
+       phy->possible_phymodes |= B43_PHYMODE_G;
 
        return 0;
 }
 
 static void b43_wireless_core_detach(struct b43_wldev *dev)
 {
-       b43_rfkill_free(dev);
        /* We release firmware that late to not be required to re-request
         * is all the time when we reinit the core. */
        b43_release_firmware(dev);
@@ -3689,7 +3842,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        struct ssb_bus *bus = dev->dev->bus;
        struct pci_dev *pdev = bus->host_pci;
        int err;
-       int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+       bool have_2ghz_phy = 0, have_5ghz_phy = 0;
        u32 tmp;
 
        /* Do NOT do any device initialization here.
@@ -3709,17 +3862,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                u32 tmshigh;
 
                tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-               have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
-               have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
-               if (!have_aphy && !have_gphy)
-                       have_bphy = 1;
-       } else if (dev->dev->id.revision == 4) {
-               have_gphy = 1;
-               have_aphy = 1;
+               have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+               have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
        } else
-               have_bphy = 1;
+               B43_WARN_ON(1);
 
-       dev->phy.gmode = (have_gphy || have_bphy);
+       dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
@@ -3731,31 +3879,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
            (pdev->device != 0x4312 &&
             pdev->device != 0x4319 && pdev->device != 0x4324)) {
                /* No multiband support. */
-               have_aphy = 0;
-               have_bphy = 0;
-               have_gphy = 0;
+               have_2ghz_phy = 0;
+               have_5ghz_phy = 0;
                switch (dev->phy.type) {
                case B43_PHYTYPE_A:
-                       have_aphy = 1;
-                       break;
-               case B43_PHYTYPE_B:
-                       have_bphy = 1;
+                       have_5ghz_phy = 1;
                        break;
                case B43_PHYTYPE_G:
-                       have_gphy = 1;
+               case B43_PHYTYPE_N:
+                       have_2ghz_phy = 1;
                        break;
                default:
                        B43_WARN_ON(1);
                }
        }
-       dev->phy.gmode = (have_gphy || have_bphy);
+       if (dev->phy.type == B43_PHYTYPE_A) {
+               /* FIXME */
+               b43err(wl, "IEEE 802.11a devices are unsupported\n");
+               err = -EOPNOTSUPP;
+               goto err_powerdown;
+       }
+       dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
        err = b43_validate_chipaccess(dev);
        if (err)
                goto err_powerdown;
-       err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+       err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
        if (err)
                goto err_powerdown;
 
@@ -3763,7 +3914,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        if (!wl->current_dev)
                wl->current_dev = dev;
        INIT_WORK(&dev->restart_work, b43_chip_reset);
-       b43_rfkill_alloc(dev);
 
        b43_radio_turn_off(dev, 1);
        b43_switch_analog(dev, 0);
@@ -3827,8 +3977,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
        tasklet_init(&wldev->isr_tasklet,
                     (void (*)(unsigned long))b43_interrupt_tasklet,
                     (unsigned long)wldev);
-       if (modparam_pio)
-               wldev->__using_pio = 1;
        INIT_LIST_HEAD(&wldev->list);
 
        err = b43_wireless_core_attach(wldev);
@@ -3853,20 +4001,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
        /* boardflags workarounds */
        if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
            bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
-               bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+               bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
        if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
            bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
-               bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
-
-       /* Handle case when gain is not set in sprom */
-       if (bus->sprom.r1.antenna_gain_a == 0xFF)
-               bus->sprom.r1.antenna_gain_a = 2;
-       if (bus->sprom.r1.antenna_gain_bg == 0xFF)
-               bus->sprom.r1.antenna_gain_bg = 2;
-
-       /* Convert Antennagain values to Q5.2 */
-       bus->sprom.r1.antenna_gain_a <<= 2;
-       bus->sprom.r1.antenna_gain_bg <<= 2;
+               bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
@@ -3893,16 +4031,17 @@ static int b43_wireless_init(struct ssb_device *dev)
        }
 
        /* fill hw info */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+                   IEEE80211_HW_RX_INCLUDES_FCS;
        hw->max_signal = 100;
        hw->max_rssi = -110;
        hw->max_noise = -110;
        hw->queues = 1;         /* FIXME: hardware has more queues */
        SET_IEEE80211_DEV(hw, dev->dev);
-       if (is_valid_ether_addr(sprom->r1.et1mac))
-               SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+       if (is_valid_ether_addr(sprom->et1mac))
+               SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
        else
-               SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+               SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
        /* Get and initialize struct b43_wl */
        wl = hw_to_b43_wl(hw);
@@ -3910,6 +4049,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        wl->hw = hw;
        spin_lock_init(&wl->irq_lock);
        spin_lock_init(&wl->leds_lock);
+       spin_lock_init(&wl->shm_lock);
        mutex_init(&wl->mutex);
        INIT_LIST_HEAD(&wl->devlist);
 
@@ -4053,16 +4193,6 @@ static struct ssb_driver b43_ssb_driver = {
        .resume         = b43_resume,
 };
 
-inline int b43_pci_ssb_bridge_init(void)
-{
-       return ssb_pcihost_register(&b43_pci_bridge_driver);
-}
-
-inline void b43_pci_ssb_bridge_exit(void)
-{
-       ssb_pcihost_unregister(&b43_pci_bridge_driver);
-}
-
 static int __init b43_init(void)
 {
        int err;
@@ -4071,19 +4201,12 @@ static int __init b43_init(void)
        err = b43_pcmcia_init();
        if (err)
                goto err_dfs_exit;
-
-       err = b43_pci_ssb_bridge_init();
-       if (err)
-               goto err_pcmcia_exit;
-
        err = ssb_driver_register(&b43_ssb_driver);
        if (err)
-               goto err_pci_exit;
+               goto err_pcmcia_exit;
 
        return err;
 
-err_pci_exit:
-       b43_pci_ssb_bridge_exit();
 err_pcmcia_exit:
        b43_pcmcia_exit();
 err_dfs_exit:
@@ -4094,7 +4217,6 @@ err_dfs_exit:
 static void __exit b43_exit(void)
 {
        ssb_driver_unregister(&b43_ssb_driver);
-       b43_pci_ssb_bridge_exit();
        b43_pcmcia_exit();
        b43_debugfs_exit();
 }